Cmake

cmake 简单配置使用

基本使用

基本使用只需要三行即可,如下示例

1
2
3
cmake_minimum_required(VERSION 3.22)
project(demo)
add_executable(demo main.cpp)
  • cmake_minimum_required:表示编译项目 cmake 最低需要的版本号
  • project:设置项目名称
  • add_executable:生成可执行文件。第一个参数为可执行文件名称,第二个源文件,如果有多个源文件,需要使用空格间隔全都写上。

多个源文件

上面的基本使用,面对很多源文件的时候,需要手动一个一个添加就实在是太反人类了。所以我们需要让 cmake 去处理,如下示例:

首先给出文件目录结构

1
2
3
4
5
6
7
8
9
.
├── CMakeLists.txt
├── lib1
│   ├── lib1.cpp
│   └── lib1.hpp
├── lib2
│   ├── lib2.cpp
│   └── lib2.hpp
└── main.cpp
1
2
3
4
5
6
7
8
9
10
11
# CMakeLists.txt 内容
cmake_minimum_required(VERSION 3.22)
project(demo)

include_directories(lib1 lib2)

aux_source_directory(lib1 SRC_LIST)
aux_source_directory(lib2 SRC_LIST)
aux_source_directory(. SRC_LIST) # . 表示当前目录,因为 main.cpp 不在任何子文件中

add_executable(demo ${SRC_LIST})

这里相比上面的示例新增了两个:include_directoriesaux_source_directory

  • aux_source_directory:表示添加源代码文件夹,并把文件夹内的源代码文件名称路径保存到变量中。第一个参数为项目中的文件夹名称,第二个参数为变量,自定义命名即可
  • include_directories:表示添加头文件搜索位置

最后add_executable中只需要填写变量即可。这个变量是个列表,这样就不需要我们手动输入一堆文件名了。

如果你想排除某些源代码文件,那你只能使用 set 手动来写了,如下示例

1
2
3
4
5
6
set(SRC_LIST lib1/lib1.cpp lib2/lib2.cpp)

# 可以换行,显示更清晰
set(SRC_LIST
lib1/lib1.cpp
lib2/lib2.cpp)

编译的时候,新建 build 目录,然后进入 build 目录执行 cmake ..,然后执行make来生成

设置编译后可执行文件位置

如下示例

1
2
# 设置生成的可执行文件存放位置,这里的 ${PROJECT_SOURCE_DIR} 为 CMakeLists.txt 所在目录
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

库文件编译

先上文件目录结构

1
2
3
4
5
6
7
8
# 目录结构
.
├── CMakeLists.txt
├── inc
│   └── test_func.hpp
├── lib
└── src
└── test_func.cpp

这里我们把源文件和头文件分开放,编译后的库文件放到 lib 中,CMakeLists.txt 内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
cmake_minimum_required(VERSION 3.22)
project(demo_test_lib)

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

// 设置动态库文件生成后存放的位置
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

add_library (test_func_shared SHARED ${SRC_LIST})
add_library (test_func_static STATIC ${SRC_LIST})

set_target_properties (test_func_shared PROPERTIES OUTPUT_NAME "test_func")
set_target_properties (test_func_static PROPERTIES OUTPUT_NAME "test_func")

已经介绍过的参数,就直接略过了,下面介绍新的配置。

  • add_library:表示生成库文件,第一个参数为变量名,第二个为库类型 SHARED(共享/动态),STAIC(静态),第三个参数为源代码文件列表,这里直接使用 set 设置了,也可以手动写,多个使用空格间隔
  • set_target_properties:设置生成的动态库参数,上面的示例为重新设置生成的动态库名称,注意名称和实际文件名是不同的。后面我们会讲。

编译的时候,新建 build 目录,然后进入 build 目录执行 cmake ..,然后执行make来生成

多个库同时编译

准备两个需要编译的库代码,这里简单拷贝一份上面的库代码文件,简单修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.
├── CMakeLists.txt
├── build
├── lib
│   ├── test_func
│   │   ├── CMakeLists.txt
│   │   ├── inc
│   │   │   └── test_func.hpp
│   │   ├── lib
│   │   └── src
│   │   └── test_func.cpp
│   └── test_func2
│   ├── CMakeLists.txt
│   ├── inc
│   │   └── test_func.hpp
│   ├── lib
│   └── src
│   └── test_func.cpp

这里的文件树示例,仅保留 lib 下面的两个库文件

注意这里的两个库文件的,头文件名相同。这是在 c++ 中不允许的。这里演示偷懒就无所谓了

每个库都有一份上面我们演示过的 CMakeLists.txt 文件,也就是库编译配置,生成的 库文件 依然存放在对应库中的 lib 文件夹中

注意顶层有个 CMakeLists.txt 文件,该文件就是编译下面两个库的配置。内容如下

1
2
3
4
5
6
cmake_minimum_required(VERSION 3.22)
project(demo)

# 运行指定目录下的 CMakeLists.txt 文件
add_subdirectory(lib/test_func)
add_subdirectory(lib/test_func2)

只需要使用 add_subdirectory 指明下面两个库的文件夹即可

  • add_subdirectory:运行指定文件夹内部的 CMakeLists.txt

链接库文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 文件树
├── CMakeLists.txt
├── Makefile
├── bin
├── lib
│   ├── test_func
│   │   ├── CMakeLists.txt
│   │   ├── inc
│   │   │   └── test_func.hpp
│   │   ├── lib
│   │   │   ├── libtest_func.a
│   │   │   └── libtest_func.dylib
│   │   └── src
│   │   └── test_func.cpp
└── src
├── CMakeLists.txt
├── lib1
│   ├── lib1.cpp
│   └── lib1.hpp
├── lib2
│   ├── lib2.cpp
│   └── lib2.hpp
└── main.cpp

现在我们需要在 src/CMakeLists.txt 文件中配置链接库的相关操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
cmake_minimum_required(VERSION 3.22)
project(demo)

include_directories(lib1 lib2)

aux_source_directory(lib1 SRC_LIST)
aux_source_directory(lib2 SRC_LIST)
aux_source_directory(. SRC_LIST)

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../bin)

# 库的头文件位置
include_directories(${PROJECT_SOURCE_DIR}/../lib/test_func/inc)
# find_library(TESTFUNC_LIB test_func HINTS ${PROJECT_SOURCE_DIR}/../lib/test_func/lib)
# 不指定搜索库文件位置,简单写法
find_library(TESTFUNC_LIB test_func ${PROJECT_SOURCE_DIR}/../lib/test_func/lib)

# 使用静态链接的方法链接使用下面的方法,直接指定静态库文件名
# find_library(TESTFUNC_LIB libtest_func.a ${PROJECT_SOURCE_DIR}/../lib/test_func/lib)


# 生成可执行文件
add_executable(demo ${SRC_LIST})
# 链接可执行文件
target_link_libraries (demo ${TESTFUNC_LIB})

添加编译参数

比如在终端中我们会添加-std=c++11这种参数,在 cmake 中使用add_definitions来设置参数,如下示例:

1
2
3
# g++ -std=c++11 main.cpp
add_definitions(-std=c++11)
add_executable(main main.cpp)