CMake教程——基础使用

2020-04-12  本文已影响0人  生活简单些

  所有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(), 后面文章再介绍。

上一篇下一篇

猜你喜欢

热点阅读