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号