CMake基本操作

CMake安装和版本

1
2
sudo apt install cmake  
cmake --version

编译单个文件

例如编译源文件main.c, 在相同目录下编写CMakeLists.txt文件,内容为:

1
2
3
4
5
cmake_minimum_required (VERSION 2.8)

project (demo)

add_executable(main main.cpp)

第一行表示CMake最低版本为2.8;第二行表示项目名为demo;第三行add_executable()第一个参数为最终生成的elf文件名称为main
使用的源文件为main.c
在main.c目录下输入以下命令运行CMake:
cmake .

alt cmake结果
alt cmake结果

可以看到目录下生成了MakeFile
最后再运行make命令,完成编译,其中main文件为可执行文件。

alt make结果

编译同一目录下的多个文件

alt 树状文件

CMakeLists文件编写如下:

1
2
3
4
5
cmake_minimum_required (VERSION 2.8)

project (demo)

add_executable(main main.cpp, te.cpp)

其实就是add_executable()中后面的参数将所有源文件添加进去。
当目录中的源文件过多的时候,上述写法就不可行了。可以使用以下命令将某个目录下所有源文件存入一个变量中:

1
aux_source_directory(dir var)

其中dir参数为指定目录,var参数为存储源文件的变量名称。对于编译上述同一目录中多个文件的CMakeLists.txt可以编写为:

1
2
3
4
5
6
7
cmake_minimum_required (VERSION 2.8)

project (demo)

aux_source_directory(. SRC_LIST)

add_executable(main ${SRC_LIST})

有时不想将目录中的所有源文件都添加进来,这时可以使用set()命令来新建变量,该命令可以指定添加的文件。

1
2
3
4
5
6
7
8
9
cmake_minimum_required (VERSION 2.8)

project (demo)

set(SRC_LIST
./main.cpp
./te.cpp)

add_executable(main ${SRC_LIST})

编译不同目录下的多个源文件

程序源文件较多时,可能会放在多个子目录下,如:

alt 树状文件

此时CMakeLists.txt写法可以为:

1
2
3
4
5
6
7
8
9
10
cmake_minimum_required (VERSION 2.8)

project (demo)

include_directories (test1 test2)

aux_source_directory (test1 SRC_LIST1)
aux_source_directory (test2 SRC_LIST2)

add_executable(main main.cpp ${SRC_LIST1} ${SRC_LIST2})

一般项目结构下的编译

通常,将源文件放到src目录中,头文件放到include目录中,生成的对象文件放到build目录下,最终输出的elf文件放到bin目录下。结构为:

alt 树状文件

其中有两个CMakelists.txt文件,工程根目录下CMakeLists.txt文件的内容为:

1
2
3
4
5
cmake_minimum_required (VERSION 2.8)

project (demo)

add_subdirectory (src)

其中add_subdirectory()命令添加一个子目录并构建该子目录,第一个参数为子目录,该目录下包含了CMakeLists.txt文件和源文件。可以是绝对路径或者相对路径。当执行cmake时,会进入src目录下找CMakeLists.txt文件。
内层的CMakeLists.txt文件的内容为:

1
2
3
4
5
6
7
aux_source_directory (. SRC_LIST)

include_directories (../include)

add_executable (main ${SRC_LIST})

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

其中命令set()中的参数为CMake预定义的变量,含义为:

  • EXECUTABLE_OUTPUT_PATH:目标二进制可执行文件的存放位置
  • PROJECT_SOURCE_DIR:工程根目录
    因此,上述set()命令含义是将存放elf文件的位置设置为工程根目录下的bin目录。

编写完成之后切换至build目录,执行cmake ..然后在build目录下执行make完成编译,可以看到在bin目录下产生了可执行文件main。

alt cmake结果
alt make结果

build目录下执行cmake的原因是:使cmake运行时产生的编译文件存放于build目录,免得其与程序其它部分混在一起造成污染。
使用一个CMakeLists.txt
前面的方法外部CMakeLists.txt使用add_subdirectory()命令来引导其它目录中的CMakeLists.txt,实际上也可以整个使用一个CMakeLists.txt来组织编译过程。其写法为:

1
2
3
4
5
6
7
8
9
10
11
cmake_minimum_required (VERSION 2.8)

project (demo)

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

aux_source_directory (src SRC_LIST)

include_directories (include)

add_executable (main ${SRC_LIST})

动态库和静态库编译

有时只编译动态库和静态库,此时项目结构如下:
alt 结构

编写CMakeLists.txt文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cmake_minimum_required (VERSION 3.5)

project (demo)

set (SRC_LIST ${PROJECT_SOURCE_DIR}/testFun/te.cpp)

add_library (testFun_shared SHARED ${SRC_LIST})
add_library (testFun_static STATIC ${SRC_LIST})

set_target_properties (testFun_shared PROPERTIES OUTPUT_NAME "testFun")
set_target_properties (testFun_static PROPERTIES OUTPUT_NAME "testFun")

set (LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

其中:
add_library()命令用于生成动态库或者静态库,第一个参数为生成库的名字,第二个参数指定生成动态库还是静态库,第三个参数指定生成库所用到的源文件。
set_target_properties()命令用于为一个目标设置属性,上面将两个库的输出名称属性设置为“testFun”,使用该命令能使两者输出名称相同,只是后缀不同(.a和.so)。
最后的LIBRARY_OUTPUT_PATH为库文件的默认输出路径,这里设置为lib目录。
之后进入build目录下分别执行cmake ..make命令,可以看到在lib目录下生成了.a和.so静态和动态库。
alt cmake结果

使用动态库和静态库

若需要使用生成的库或别人的库,即以下项目中lib下的库:
alt 结构
其中main.cpp使用了#include "te.h"工程目录下的CMakeLists.txt内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cmake_minimum_required (VERSION 3.5)

project (demo)

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

set (SRC_LIST ${PROJECT_SOURCE_DIR}/src/main.cpp)

# find te.h
include_directories (${PROJECT_SOURCE_DIR}/testFun/inc)

find_library (TESTFUN_LIB testFun HINTS ${PROJECT_SOURCE_DIR}/testFun/lib)

add_executable (main ${SRC_LIST})

target_link_libraries (main ${TESTFUN_LIB})

共有两个新命令:
find_library():在指定的目录下查找库,第一个参数为变量名称,第二个参数是库名称,第三个参数为HINTS,第四个参数为库路径。
target_link_libraries():把目标文件和库文件进行链接。
使用find_library能够提前发现错误,不必等到链接时报错。 在build目录下执行cmake ..make,在bin目录中可以看到最后生成的可执行main文件。
注:在lib目录下有testFun的静态库和动态库,find_library默认查找动态库,若需要指定使用动态库还是静态库,可以直接指定:find_library(TESTFUN_LIB, libtestFun.so ...)

添加编译选项

添加编译选项可以使用add_compile_options来进行操作。例如:

1
2
3
4
5
6
7
8
9
cmake_munimum_required (VERSION 2.8)

project (demo)

set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

add_compile_options(-std=c++11 -Wall)

add_executable(main main.cpp)

相关链接

  1. CMake 入门实战