CMake用法笔记
CMake使用教程笔记
笔记说明:
整理自苏丙榅的博客,链接: https://subingwen.cn/cmake/CMake-primer/
符号说明:
- “<>”代表要填充的内容
- "[]"代表可追加的内容或选项
目录
1. 使用方法
- 项目目录下新建文件CMakeLists.txt
- 文件必须名为CMakeLists.txt
- 在CMakeLists.txt同级目录下创建build文件夹
- 在build目录下,执行"cmake .."命令构建项目,生成可执行程序或库文件
2. 基础功能
2.1 指定最小CMake版本
cmake_minimum_required(VERSION 3.0.0)
ps:在CMakeLists.txt中可写可不写,若CMake版本小于指定的版本,则build报错
2.2 注释
# 被注释的行
cmake_minimum_required(VERSION 3.0.0)
#[[被注释的块
被注释的块
被注释的块]]
cmake_minimum_required(VERSION 3.0.0)
2.3 定义工程名称
project(<工程名称>)
project:定义工程名称,并可指定工程的版本、工程描述、web主页地址、支持的语言(默认情况支持所有语言),如果不需要这些都是可以忽略的,只需要指定出工程名字即可.
project(<PROJECT-NAME> [<language-name>...])
project(<PROJECT-NAME>
[VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
[DESCRIPTION <project-description-string>]
[HOMEPAGE_URL <url-string>]
[LANGUAGES <language-name>...])
2.4 添加可执行程序
add_executable(<可执行程序名> <源文件名>)
源文件名可以有多个,例:
add_executable(app add.cpp div.cpp main.cpp)
2.5 定义与使用变量
SET(<变量名> [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
例:
set(SRC_LIST add.c;div.c;main.c;mult.c;sub.c)
add_executable(app ${SRC_LIST})
2.6 指定C++标准
-
方法1:在CMakeLists.txt中写入
set(CMAKE_CXX_STANDARD 11) #set(CMAKE_CXX_STANDARD 14) #set(CMAKE_CXX_STANDARD 17) -
方法2:在执行cmake时指定CMAKE_CXX_STANDARD宏的值
cmake CMakeLists.txt文件路径 -DCMAKE_CXX_STANDARD=11
2.7 CMakeLists.txt的路径
有两种宏来获取CMakeLists.txt文件所在目录的路径
PROJECT_SOURCE_DIR
CMAKE_CURRENT_SOURCE_DIR
2.8 指定输出路径
set(HOME /home/zzh/code)
set(EXECUTABLE_OUTPUT_PATH ${HOME}/bin)
- 如果这个路径中的子目录不存在,会自动生成,无需自己手动创建
2.9 搜索文件
-
方法1:aux_source_directory
aux_source_directory(<路径> <变量名>)例:
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src SRC_LIST) add_executable(app ${SRC_LIST}) -
方法2:file
file(GLOB/GLOB_RECURSE <变量名> <要搜索的文件路径和文件类型>)- GLOB: 将指定目录下搜索到的满足条件的所有文件名生成一个列表,并将其存储到变量中。
- GLOB_RECURSE:__递归__搜索指定目录,将搜索到的满足条件的文件名生成一个列表,并将其存储到变量中。
例:
file(GLOB MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp) file(GLOB MAIN_HEAD ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h)- 要搜索的文件路径和文件类型可加双引号,也可不加
file(GLOB MAIN_HEAD "${CMAKE_CURRENT_SOURCE_DIR}/include/*.h")
2.10 包含头文件
include_directories(<头文件路径>)
2.11 制作动态库或静态库
2.11.1 静态库
add_library(<库名称> STATIC <源文件1> [源文件2] ...)
- 在Linux中,静态库名字分为三部分:lib+库名字+.a,此处只需要指定出库的名字就可以了,另外两部分在生成该文件的时候会自动填充。在Windows中虽然库名和Linux格式不同,但也只需指定出名字即可。
例:
cmake_minimum_required(VERSION 3.0)
project(CALC)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
add_library(calc STATIC ${SRC_LIST})
可生成静态库文件libcalc.a
2.11.2 动态库
add_library(<库名称> SHARED <源文件1> [源文件2] ...)
- 在Linux中,动态库名字分为三部分:lib+库名字+.so,此处只需要指定出库的名字就可以了,另外两部分在生成该文件的时候会自动填充。在Windows中虽然库名和Linux格式不同,但也只需指定出名字即可。
例:
cmake_minimum_required(VERSION 3.0)
project(CALC)
include_directories(${PROJECT_SOURCE_DIR}/include)
file(GLOB SRC_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
add_library(calc SHARED ${SRC_LIST})
可生成动态库文件libcalc.so
2.11.3 指定库文件的输出路径
-
适用于动态库
由于在Linux下生成的动态库默认是有执行权限的,所以可以按照生成可执行程序的方式去指定它生成的目录:
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib) -
都适用
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
3. 引入库文件
3.1 指定库目录
如果库不是系统提供的(自己制作或者使用第三方库)可能出现静态/动态库找不到的情况,此时需指定库的路径:
link_directories(<库的路径>)
3.2 链接静态库
link_libraries(<static lib> [<static lib>...])
- 参数1:指定出要链接的静态库的名字
可以是全名 libxxx.a
也可以是掐头(lib)去尾(.a)之后的名字 xxx - 参数2-N:要链接的其它静态库的名字
3.3 链接动态库
target_link_libraries(
<target>
<PRIVATE|PUBLIC|INTERFACE> <item>...
[<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
用于指定一个目标(如可执行文件或库)在编译时需要链接哪些库,编译器会在链接阶段将这些库与目标文件合并,确保目标文件能够正确调用这些库中的函数。它支持指定库的名称、路径以及链接库的顺序。
-
target:指定目标文件的名称
- 该文件可以是一个源文件
- 该文件可以是一个动态库/静态库文件
- 该文件可以是一个可执行文件
-
PRIVATE|PUBLIC|INTERFACE:动态库的访问权限,默认为PUBLIC
-
如果各个动态库之间没有依赖关系,无需做任何设置,三者没有没有区别,一般无需指定,使用默认的 PUBLIC 即可。
-
动态库的链接具有传递性,如果动态库 A 链接了动态库B、C,动态库D链接了动态库A,此时动态库D相当于也链接了动态库B、C,并可以使用动态库B、C中定义的方法。
target_link_libraries(A B C) # A链接B、C target_link_libraries(D A) # D链接A -
PUBLIC:在public后面的库会被Link到前面的target中,并且里面的符号也会被导出,提供给第三方使用。
-
PRIVATE:在private后面的库仅被link到前面的target中,并且终结掉,第三方不能感知你调了啥库
-
INTERFACE:在interface后面引入的库不会被链接到前面的target中,只会导出符号。
-
-
item:库名称
3.4 链接动态库的细节
-
链接语句在生成可执行文件语句之后
动态库的链接和静态库是完全不同的:
- 静态库会在生成可执行程序的链接阶段被打包到可执行程序中,所以可执行程序启动,静态库就被加载到内存中了。
- 动态库在生成可执行程序的链接阶段__不会__被打包到可执行程序中,当可执行程序被启动并且调用了动态库中的函数的时候,动态库才会被加载到内存
因此,在cmake中指定要链接的动态库的时候,应该将命令写到生成了可执行文件之后
add_executable(app ${SRC_LIST}) target_link_libraries(app pthread) -
指定第三方库的路径
在链接第三方库时,而不是链接系统提供的库(如libpthread.so),需要使用 link_directories 单独指定第三方库目录。如果不指定,程序执行就不知道动态库被放在什么位置
cmake_minimum_required(VERSION 3.0) project(TEST) file(GLOB SRC_LIST ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) # 指定源文件或者动态库对应的头文件路径 include_directories(${PROJECT_SOURCE_DIR}/include) # 指定要链接的动态库的路径 link_directories(${PROJECT_SOURCE_DIR}/lib) # 添加并生成一个可执行程序 add_executable(app ${SRC_LIST}) # 指定要链接的动态库 target_link_libraries(app pthread calc)
3.5 引入库文件总结
target_link_libraries 和 link_libraries 是 CMake 中用于链接库的两个命令,都可以用于链接动态库和静态库,但它们的使用场景和功能有所不同。
-
target_link_libraries
用于指定一个目标(如可执行文件或库)在编译时需要链接哪些库。它支持指定库的名称、路径以及链接库的顺序。
优点:
- 更精确地控制目标的链接库。
- 可以指定库的不同链接条件(如调试版本、发布版本)。
- 支持多个目标和多个库之间的复杂关系。
- 更加灵活和易于维护,特别是在大型项目中。
-
link_libraries
用于设置全局链接库,这些库会链接到之后定义的所有目标上。它会影响所有的目标,适用于全局设置,但不如 target_link_libraries 精确。
缺点:
- 缺乏针对具体目标的控制,不适合复杂的项目结构。
- 容易导致意外的依赖关系,因为它对所有目标都生效。
- 一旦设置,全局影响可能导致难以追踪的链接问题。
4. 区分操作系统平台
利用宏CMAKE_SYSTEM_NAME来识别Windows、Linux、Macos
IF (CMAKE_SYSTEM_NAME MATCHES "Linux")
MESSAGE(STATUS "current platform: Linux ")
ELSEIF (CMAKE_SYSTEM_NAME MATCHES "Windows")
MESSAGE(STATUS "current platform: Windows")
ELSEIF (CMAKE_SYSTEM_NAME MATCHES "Darwin")
MESSAGE(STATUS "current platform: Mac OS X")
ELSE ()
MESSAGE(STATUS "other platform: ${CMAKE_SYSTEM_NAME}")
ENDIF (CMAKE_SYSTEM_NAME MATCHES "Linux")
5. 区分release和debug
cmake的默认编译方式是release
单配置生成器下,使用CMAKE_BUILD_TYPE变量就能拿到当前是debug还是release
-
方法1:判断CMAKE_BUILD_TYPE
if(CMAKE_BUILD_TYPE STREQUAL "Debug") # 使用 Debug 库 elseif(CMAKE_BUILD_TYPE STREQUAL "Release") # 使用 Release 库 endif() -
方法2:配置CMAKE_BUILD_TYPE
if("${CMAKE_BUILD_TYPE}" STREQUAL "") set(CMAKE_BUILD_TYPE "Release") endif()

浙公网安备 33010602011771号