所有CMake项目跟目录下都会有个CMakeList.txt文件,它描述里项目编译入口,cmake项目编译建议创建一个额外目录放编译过程产物,比如在项目根目录创建“build”文件夹,然后输入命令:
$: cmake ..
-- The C compiler identification is AppleClang 11.0.0.11000033
-- The CXX compiler identification is AppleClang 11.0.0.11000033
-- Check for working C compiler: /Library/Developer/CommandLineTools/usr/bin/cc
-- Check for working C compiler: /Library/Developer/CommandLineTools/usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /Library/Developer/CommandLineTools/usr/bin/c++
-- Check for working CXX compiler: /Library/Developer/CommandLineTools/usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
-- Found Threads: TRUE
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/xxx/App/build
这一步是通过cmake将项目转为makefile,随后可以再敲入命令编译生成可执行文件或库文件:
$: make
Scanning dependencies of target smt-logger
[ 25%] Building CXX object library/CMakeFiles/App.dir/App.cpp.o
[ 50%] Linking CXX shared library ../lib/App.so
[ 50%] Built target App
Scanning dependencies of target tests
[ 75%] Building CXX object tests/CMakeFiles/tests.dir/testcase.cpp.o
[100%] Linking CXX executable ../bin/tests
[100%] Built target tests
1. 如何用cmake组织项目——最基础模版
项目结构:
├── CMakeLists.txt
└── main.cpp
CMakeList.txt:
# VERSION 没必要设置最高版本,不然得要求所有人跟你用一样的最高版本
cmake_minimum_required(VERSION 3.0.0)
# 设置项目名称
project(App)
# 很多IDE默认c++是11以下,需要支持更高版本需要自行设置
set(CMAKE_CXX_STANDARD 14)
# 将main.cpp编译到App里并生成可执行文件,可执行文件名为App(windows环境为App.exe)
add_executable(App main.cpp)
2. 如何用cmake组织项目——同时编译项目中多个文件
2.1 手动一个一个加入
项目结构:
├── CMakeLists.txt
├── main.cpp
├── main1.cpp
├── main2.cpp
└── main3.cpp
CMakeList.txt:
cmake_minimum_required(VERSION 3.0.0)
project(App)
set(CMAKE_CXX_STANDARD 14)
add_executable(App main.cpp \
main2.cpp \
main3.cpp)
2.2:按目录加入
cmake_minimum_required(VERSION 3.0.0)
project(App)
set(CMAKE_CXX_STANDARD 14)
# 假设所有cpp文件都在当前目录,扫描当前目录
# 下所有cpp文件并存储到变量DIR_SRCS里
aux_source_directory(. DIR_SRCS)
# 编译多个cpp文件为可执行文件,cpp文件名来自DIR_SRCS
add_executable(App ${DIR_SRCS})
当然一个项目有多个目录存放cpp文件情况,最简单办法是使用多个aux_source_directory()
创建多个变量,每个变量对应它目录下都cpp文件集合:
aux_source_directory(. DIR_SRCS1)
aux_source_directory(. DIR_SRCS2)
aux_source_directory(. DIR_SRCS3)
add_executable(App ${DIR_SRCS1} ${DIR_SRCS2} ${DIR_SRCS3})
不过这是一种取巧做法,这种做法会导致项目编译时候会编译所有代码,导致编译时间较长,更好的推荐做法是给每个目录都创建一个
CMakeList.txt
, 其实不用担心创建多个CMakeList.txt
会带来很多额外工作量,当然额外工作量是有的,但是非常少,结构更清晰!
3. 下面以live555(一个开源的rtps server项目)为例介绍如何用cmake组织项目
live555本来并非cmake项目,我将此改为cmake构建的项目,live555本身就以文件划分了模块,因此我只要在每个目录里增加CMakeList.txt并在其中描述编译当前模块的cmake脚本即可,最后在项目的跟目录下也创建一个CMakeList.txt并将所有的模块都汇集起来就能编译整个项目了。
├── CMakeLists.txt
├── BasicUsageEnvironment
│ └── CMakeLists.txt
│ └── BasicHashTable.cpp
│ └── xxx.cpp
│ └── include
│ └── BasicHashTable.hh
│ └── xxx.hh
├── groupsock
│ └── CMakeLists.txt
│ └── GroupEId.cpp
│ └── xxx.cpp
│ └── include
│ └── GroupEId.hh
│ └── xxx.hh
├── liveMedia
│ └── CMakeLists.txt
│ └── AC3AudioRTPSink.cpp
│ └── xxx.cpp
│ └── include
│ └── GroupEId.hh
│ └── xxx.hh
├── mediaServer
│ └── CMakeLists.txt
│ └── DynamicRTSPServer.cpp
│ └── xxx.cpp
└── UsageEnvironment
└── CMakeLists.txt
└── HashTable.cpp
└── xxx.cpp
└── include
└── Boolean.hh
└── xxx.hh
3.1 跟目录下的CMakeList.txt
cmake_minimum_required(VERSION 3.15)
project(live555)
set(CMAKE_CXX_STANDARD 14)
if (UNIX)
add_definitions(-Wall -g -O2 -DSOCKLEN_T=socklen_t -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64)
endif(UNIX)
# add subdirectory means add all sub modules
ADD_SUBDIRECTORY(UsageEnvironment)
ADD_SUBDIRECTORY(BasicUsageEnvironment)
ADD_SUBDIRECTORY(groupsock)
ADD_SUBDIRECTORY(liveMedia)
ADD_SUBDIRECTORY(mediaServer)
3.2 BasicUsageEnvironment 目录下的CMakeList.txt
# 这里指定当前模块名,这里推荐用文件名作为模块名
project(BasicUsageEnvironment)
# 因为当前模块cpp里使用里其他模块的头文件,因此需要把它们include进来
include_directories(../UsageEnvironment/include)
include_directories(../groupsock/include)
# 当前模块的头文件肯定要include进来
include_directories(include)
# 当前模块下的cpp跟CMakeList.txt在同级目录
aux_source_directory(. SRC_LIST)
# 当前只是模块,最终需要把所有的模块合并构建,因此当前需要指定编译对象为STATIC
# ${PROJECT_NAME}的值即为当前模块名,需要注意的是不能用${CMAKE_PROJECT_NAME},因为那是跟目录下CMakeList.txt指定的名字,那是整个项目的名字:live555
add_library(${PROJECT_NAME} STATIC ${SRC_LIST})
注意:add_library()可以指定构建STATIC,还可以指定是SHARED和MODULE,但MODULE只能作用在特定系统,使用不常见。
其他模块除了mediaServer的CMakeList.txt内部组织都如此。
3.3 mediaServer(main模块)目录下的CMakeList.txt
project(mediaServer)
include_directories(../UsageEnvironment/include)
include_directories(../groupsock/include)
include_directories(../liveMedia/include)
include_directories(../BasicUsageEnvironment/include)
aux_source_directory(. SRC_LIST)
# 当前模块是main入口,最终目标是编译出live555的可执行文件,因此不再用add_library()
add_executable(${PROJECT_NAME} ${SRC_LIST})
# 链接所有其他模块到当前模块
target_link_libraries(${PROJECT_NAME} liveMedia groupsock BasicUsageEnvironment UsageEnvironment)
大功告成,所有的模块就这样串起来了,但需要注意的是include_directories()
是一种较老的写法,更新的是用target_include_directories()
, 后面文章再介绍。
网友评论