cmake基础知识
Cmake
Cmake变量
Cmake的基本类型只有两种,分别是字符串
和字符串列表
,使用set
命令来设置变量
set(var abc) # abc是字符串,var是值为“abc”的字符串变量
set(var a b c) # var是包含a b c三个元素的字符串列表
set(var a;b;c) # 同上
set(var “a b c”) # var是值为“a b c”的字符串变量
Cmake命令不区分大小写,变量区分大小写
变量取值方法如下:
set(var abc) # abc是字符串,var是变量
message(${var}) # 使用${变量}的形式来取值,并打印
条件语句
(1)if条件语句
if(condition1)
expression1
elseif(condition2)
expression2
endif()
(2)循环语句
foreach(item IN LISTS list_var)
message(${item})
endforeach()
常用命令
(1)版本号要求
指定Cmake最低版本号
cmake_minimum_required(VERSION xx.xx)
(2)指定项目信息
project(PRO_NAME)
(3)设置构建目标Target
- 创建可执行文件
add_executable() # 用于创建一个可执行的Target
- 创建静态库/动态库
add_library(target STATIC/SHARED a.cpp b.cpp)
源文件过多的情况下,可以通过调用aux_source_directory([目录] [变量名])来批量添加
aux_source_directory(./src Clist)
add_library(target STATIC ${Clist})
- 子目录联编
父级CMakeList.txt通过调用add_subdirectory()来实现包含、调用存在CMakeList.txt的子目录或者子工程
add_subdirectory([目录])
- 指定链接选项
- 仅用于可执行文件或者动态库目标(必须先创建target):
add_executable(mymathApp mymathApp.cc)
target_link_options(mymathApp <INTERFACE|PUBLIC|PRIVATE> -wl,-shared,-z,noexecstack)
PUBLIC、PRIVATE和INTERFACE是目标属性的修饰符
- 指定目标的属性
set_target_properties
- 设置链接属性变量LINK_FLAGS
set(LINK_FLAGS "-rdynamic -W1,-z,noexecstack -W1,-z,relro -W1,-z,now")
- 添加源编译选项
1)向源文件编译添加选项,相关选项将添加到COMPILE_OPTIONS目录属性。从当前目录和下一级目录编译target时,将使用这些选项。
add_compile_options(<option> ...)
e.g.
add_compile_options(-DSAMPLE_ADD_VALUE=10)
add_compile_options(-Wall -Wextra -pedantic -Werror)
2)向target添加编译选项
add_executable(main samples/sample_add.cpp)
target_compile_options(main
PRIVATE $<$<CXX_COMPILER_ID:AppleClang,IBMClang,Clang,GNU,LCC>:-DMY_PRIVATE_DEFINE>
PUBLIC $<$<COMPILE_LANG_AND_ID:CXX,GNU,LCC>:-DMY_PUBLIC_DEFINE>
PUBLIC $<$<COMPILE_LANG_AND_ID:CXX,GNU,LCC,Clang,AppleClang,IBMClang>:-
DMY_MUTLI_COMP_PUBLIC_DEFINE>
INTERFACE $<$<CXX_COMPILER_ID:GNU,LCC>:-DMY_INTERFACE_DEFINE>
INTERFACE $<$<CXX_COMPILER_ID:GNU,LCC,Clang,AppleClang,IBMClang>:-
DMY_MULTI_COMP_INTERFACE_DEFINE>
)
- 给顶级目标添加依赖项
使顶级<目标>依赖于其他顶级目标,以确保子一级的目标在<目标>之前构建 ,顶级目标是由add_executable()、 add_library()或add_custom_target()命令创建的
ADD_EXECUTABLE(main main.cpp)
ADD_DEPENDENCIES(main a.so b.so) ## main有一些符号的定义在a.so或者b.so中,提示编译器先生产依赖库,再去生成main
TARGET_LINK_LIBRARIES(main a.so b.so c.so d.so)
- 查找某级目录下的所有源文件,并保存文件列表到变量
aux_source_directory([目录] [变量名])
e.g.
aux_source_directory(../ DIR_SRC)
- 添加子目录进行构建
add_subdirectory(../src)
- 添加头文件搜索目录,如果是相对路径,则是基于当前源文件的路径
include_directories
- 添加链接器寻找库文件的目录
link_directories
注意:该命令只适用于在它被调用后创建target的场景, 如果必须提供库搜索路径,则最好尽可能使用 target_link_directories命令
- 将库文件链接目录添加到target里,指定连接器在链接给定target的时候应该在设置的目录下搜索库文件
target_link_directories(<target> [INTERFACE/PUBLIC/PRIVATE] DIR)
注意:命名中的target必须先由add_excecutable或者add_library等命令创建
- 将库链接到稍后添加的所有目标里
link_libraries("/opt/libeng.so" "/opt/bin/libmx.so")
注意:该命令只适用于在它被调用后创建target的场景
- 指定将要链接到给定target的库
target_link_libraries(<target> [INTERFACE/PUBLIC/INTERFACE] item1 ...)
target_link_libraries(myProject libcomm.so) # 这些库名写法都可以
target_link_libraries(myProject comm)
target_link_libraries(myProject -lcomm)
PUBLIC 在public后面的库会被Link到你的target中,并且里面的符号也会被导出,提供给第三方使用。
PRIVATE在private后面的库仅被link到你的target中,并且终结掉,第三方不能感知你调了啥库 INTERFACE 在 interface后面引入的库不会被链接到你的target中,只会导出符号。
作用域
没有指定作用域的情况
父目录的CMakeList.txt变量作用域会扩展至子目录,但是子目录不能扩展到父亲目录。例如, sub_module_a1/CMakeLists.txt可以访问到module_a和root下的CMakeLists.txt中定义的变量,反之 module_a/CMakeLists.txt访问不到sub_module_a1/CMakeLists.txt中定义的变量。
root
|--CMakeLists.txt
|--module_a
| |--CMakeLists.txt
| |--sub_module_a1
| |--CMakeLists.txt
|
|--module_b
|--CMakeLists.txt
如果子目录变量需要被上一级父目录访问
set(var xxx PARENT_SCOPE)
如果子目录变量作用域需要扩大到全局CMakeList.txt
set(var xxx CACHE INTERNAL "")
常见的内部变量
变量名 | 描述 |
---|---|
CMAKE_C_COMPILER/CMAKE_CXX_COMPILER | C/C++编译器 |
CMAKE_C_FLAGS/CMAKE_CXX_FLAGS | C/C++编译选项 |
CMAKE_BINARY_DIR/PROJECT_BINARY_DIR | 执行cmake命令的dir,即cmake生成件所在dir |
CMAKE_SOURCE_DIR/PROJECT_SOURCE_DIR | 工程顶层目录 |
CMAKE_CURRENT_SOURCE_DIR | 当前CMakeLists.txt所在dir |
CMAKE_INSTALL_PREFIX | 执行make install的发布件安装dir |
CMAKE_TOOLCHAIN_FILE | 指定交叉编译环境的配置文件,在cmake命令中指定 |
CMAKE_CXX_STANDARD | 指定C++的版本号: 11、17等 |