2020年3月26日,17:37:33
- CMake Reference Documentation — CMake 3.16.4 Documentation
- Welcome to cmake’s documentation! — cmake 实践 1.0.0 documentation
- Cmake 如何入门? - 0xCCCCCCCC的回答 - 知乎 https://www.zhihu.com/question/58949190/answer/999701073
- 【必读】C/C库文件全了解(包含静态库、动态库,包含windows、linux,包含dll、lib、so)_hsqyc的博客-CSDN博客_c库文件
cmake相关知识提纲
cmakecmake特性cmake宏数据结构预处理编译组织源文件aux_source_directoryadd_library MODULEadd_subdirectorycmake组织的包find_package包含源文件include_directories生成add_executable链接链接库target_link_libraries生成安装
安装、卸载和升级
- cmake的安装和卸载/特定版本的安装卸载/源码构建和安装:CMake 安装、卸载(Ubuntu 18.04 LTS) - 代码先锋网
基本概念
- cmake脚本中的过程有几个执行的时间点——1. Configure,比如运行cmake时发生;2. Build,若是Unix Makefile的情况,则是运行make时发生;3. Install,比如运行make install时发生;
- cmake $<…>这样尖括号包裹的具体内容是在Build时才填充的;调试方法见:cmake-generator-expressions(7) — CMake 3.14.7 Documentation
- 关于变量、变量的Scope:看cmake set命令的官方文档即可;子目录继承父目录的变量的值,但子目录中的修改不会传导到父目录,除非使用 PARENT_SCOPE;
- 关于库的scope:cmake:target_** 中的 PUBLIC,PRIVATE,INTERFACE - 知乎
基本命令
- cmake常见命令一言以蔽之 CMake命令之项目命令 - Jason886 - 博客园
- cmake命令不区分大小写
- cmake 命令会默认将当前目录作为build生成目录;(所以不要在代码的根目录执行
cmake .污染源码文件夹);
启动cmake构建命令行示例:
cmake -G "Visual Studio 16 2019" -A x64 \-D CMAKE_INSTALL_PREFIX=C:\WORKSPACE\OPENCL\samples\build \ # Define install dir-S <source-dir> # -- CMAKE_CURRENT_SOURCE_DIR-B <build-dir> # -- CMAKE_BINARY_DIR
用来删除cmake生成的东西的脚本
find . -name "CMakeFiles" -type d -print -exec rm -rf {} \;find . -name "cmake_install.cmake" -type f -print -exec rm {} \;find . -name "Makefile" -type f -print -exec rm {} \;
全局和目标性质
- 设置生成对象的位置:cmake设置生成文件的位置 - 简书
预处理【preprocess】
在CMake脚本中定义宏
• add_definitions(-D宏)
编译【compile】
包含头文件【include】
- 尽量要用target_include_directories而不是include_directories——具体情况具体分析,决定对特定目标包含还是对全局包含;
- target_include_directories和include_directories好像是互斥的,即使用target_include_directories的目标无法感知到include_directories中的目录;【未证实】
- 优化
- 将相关联的一系列包含路径合并为变量,便于模块化引入和复用,提升可读性;
包含源文件【source】
交叉编译
cmake的交叉编译范例:CMake交叉编译_samssm的专栏-CSDN博客
形成库【library】
Object库
优化
target_link_libraries 链接顺序:与gcc/g++链接顺序一致;被依赖的放在后面;cmake target_link_libraries 链接库顺序 - Swack
静态库
动态库
- cmake一个项目中默认链接到目标的静态库都是以绝对路径链接的;无论是移动了目标还是移动了库都会出现找不到库的情况;
- 用ldd命令、或者readelf -d 也可以显示一个目标文件链接了哪些库及以何种方式;
- 搜集了一些资料:
- 通过相对路径搜索动态库:cmake相对路径载入so文件和rpath_skyman满天星的博客-CSDN博客
- 即通过设置set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) 和 set_target_properties,更改ELF的dynamic段中rpath(RUNPATH)的值
- 位置无关代码:动态库的正常运行需要以 -fPIC 选项进行编译,使其内部的地址都以相对地址的形式进行重定位;c++ - unexpected reloc type 0x03 - Stack Overflow
- 为什么(在UBT上)没有使用这个选项动态库也可以使用?gcc 编译参数 -fPIC 的详解和一些问题_阿然的专栏-CSDN博客
- “如果用没有加这个参数的编译后的共享库,也可以使用的话,可能是两个原因:
1:gcc默认开启-fPIC选项
2:loader使你的代码位置无关
嵌套其他库【import】
find
了解cmake加入第三方库的机制
CMake之find_package - 简书
//可以通过set()设置<包名>_DIR这样的值,来设置find_package的默认查找目录
常识使用cmake构建sln项目;
已安装VS2019;
安装CMake;
写源代码;
在项目文件夹创建CmakeLists.txt;其中指定了项目名称,包含的文件;
在当前文件夹执行cmake .;进行内构建;
没有进行任何设置,其自动检测到了VS2019的环境并展开成一个sln项目;
PS C:\WORKSPACE\CMAKE\cmake_tutorial> cmake -S . -B .\build\ # 可以用-S和-B指定Source和Build的路径;-- Building for: Visual Studio 16 2019-- The C compiler identification is MSVC 19.24.28314.0-- The CXX compiler identification is MSVC 19.24.28314.0-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.24.28314/bin/Hostx64/x64/cl.exe-- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.24.28314/bin/Hostx64/x64/cl.exe -- works-- Detecting C compiler ABI info-- Detecting C compiler ABI info - done-- Detecting C compile features-- Detecting C compile features - done-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.24.28314/bin/Hostx64/x64/cl.exe-- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.24.28314/bin/Hostx64/x64/cl.exe -- works-- Detecting CXX compiler ABI info-- Detecting CXX compiler ABI info - done-- Detecting CXX compile features-- Detecting CXX compile features - done-- Configuring done-- Generating done-- Build files have been written to: C:/WORKSPACE/CMAKE/cmake_tutorial/buildPS C:\WORKSPACE\CMAKE\cmake_tutorial>
打开生成的sln项目,一般都具有多个“启动项目”,如ALL_BUILD,ZERO_CHECK等;
运行
若运行时出现“ 无法启动程序 xxx\ALL_BUILD 系统找不到指定文件”,则在解决方案资源管理器中,右击源代码对应的项目,设为启动项目;
Cmake以及在软件工程中的一系列构建项目流程
- LInux ./configure、make、make install 命令_Q563573095的博客-CSDN博客
- ./configure
- cmake
- make
- make install
config
范例
project(subProject1)add_subdirectory(lib11)add_subdirectory(lib12)add_subdirectory(libmain)set(LIB_ALLlib11_objlib12_objlibmain_obj)add_executable(TEST_EXE dummy.cpp)target_link_libraries(TEST_EXE PRIVATE ${LIB_ALL})set_target_properties(TEST_EXE PROPERTIES RUNTIME_OUTPUT_NAME test_exe)# add_dependencies(TEST_EXE# product product_ups# )
变量【variable】
- Cmake入门之——Set方法(六)_PGzxc的专栏-CSDN博客 ```json set(SRC_LIST ./main.cpp )
add_library(libmain_obj OBJECT ${SRC_LIST})
target_include_directories(libmain_obj PUBLIC ${PRODUCT_INCLUDE})
目录
message(“##### in ${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt”) # 当前 CMakeLists.txt所在的目录 message(“CMAKE_CURRENT_SOURCE_DIR = ${CMAKE_CURRENT_SOURCE_DIR}”) # 当前目录对应的源文件目录,如果处在subdirectories中,路径也会加上子目录的前缀 message(“CMAKE_CURRENT_BINARY_DIR = ${CMAKE_CURRENT_BINARY_DIR}”) get_filename_component(CMAKE_CUR_SRC_DIR_ABS “${CMAKE_CURRENT_SOURCE_DIR}” ABSOLUTE) message(“CMAKE_CUR_SRC_DIR_ABS = ${CMAKE_CUR_SRC_DIR_ABS}”) message(“CMAKE_SOURCE_DIR = ${CMAKE_SOURCE_DIR}”) # 运行 cmake 命令对应的源文件目录,(即cmake命令 —source 对应的或比如 cmake .. 则 ‘..’ 对应的目录就是;即使处在嵌套的子项目中也不会被子项目覆盖 message(“PROJECT_SOURCE_DIR = ${PROJECT_SOURCE_DIR}”) # 当前 Project 的源文件目录;如果处在根项目包含的子项目中,则显示的是子项目的源文件目录;如果处在subdirectories中,路径也仍然是project的路径; message(“PROJECT_BINARY_DIR = ${PROJECT_BINARY_DIR}”) # 当前 Project 对应的生成目录,(即cmake命令 —build 对应或默认为运行 cmake .. 所在的目录);如果处在根项目包含的子项目中,则显示的是子项目对应的生成目录 message(“CMAKE_INSTALL_PREFIX = ${CMAKE_INSTALL_PREFIX}”) # 安装目录前缀 message(“CMAKE_PROJECT_NAME = ${CMAKE_PROJECT_NAME}”) message(“CMAKE_PROJECT_INCLUDE = ${CMAKE_PROJECT_INCLUDE}”)
本CMakeList
message(“CMAKE_CURRENT_LIST_FILE = ${CMAKE_CURRENT_LIST_FILE}”) # 当前CMakeLists.txt文件名(带路径) message(“CMAKE_CURRENT_LIST_LINE = ${CMAKE_CURRENT_LIST_LINE}”) # 当前CMakeLists.txt中的当前行号
编译选项
message(“CMAKE_CXX_FLAGS = ${CMAKE_CXX_FLAGS}”) message(“CMAKE_C_FLAGS = ${CMAKE_C_FLAGS}”) message(“CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}”) message(“CMAKE_CXX_FLAGS_DEBUG = ${CMAKE_CXX_FLAGS_DEBUG}”)
将动态库/共享库链接到目标,目标文件本身并非直接添加动态库的内容,而仅添加按照CMake指定的路径依赖(相对or绝对?待查)
若按该路径未找到依赖的动态库,则启动失败;
CMake 打印信息;注意message参数不同打印的时间点不同,所以同一上下文的message不要用不同类型打印;
- 变量的几个种类和作用域:[ CMake 两种变量原理 - 佛系师兄 - 博客园](https://www.cnblogs.com/ncuneugcj/p/9756324.html#2%E3%80%81cache-variables)- 常用变量一览:[CMake常见变量——Project和CMake相关信息_山庄来客的专栏-CSDN博客](https://blog.csdn.net/fuyajun01/article/details/8891749)- 理解CMake变量作用机制:[CMake interpret string as variable - Stack Overflow](https://stackoverflow.com/questions/32631168/cmake-interpret-string-as-variable) 用变量的值索引变量`${${var}}`<a name="81afc658"></a>## 宏和函数【function】/CMake脚本调试【DEBUG】调试CMakeLists脚本:```json# 简单版本macro(DUMP _var)message("[DUMP] in " ${CMAKE_CURRENT_LIST_FILE} ":" " ${_var} = " ${${_var}} )endmacro(DUMP)macro(DUMPLIST _var)message("[DUMPLIST] in " ${CMAKE_CURRENT_LIST_FILE} ":" " ${_var} = ")foreach(next_ITEM ${${_var}} )message("\t${next_ITEM}")endforeach(next_ITEM ${${_var}} )endmacro(DUMPLIST)# 例子DUMP(变量)DUMPLIST(列表变量)# 高级版本function(D)message("[dump] in " ${CMAKE_CURRENT_LIST_FILE} ":" ${ARGV1} " ${ARGV0} = " ${${ARGV0}} )endfunction(D)# 例子# 第二个参数放行号的值,很遗憾cmake暂时(2021)没有能够省去传入行号的值的其他办法D(PROJECT_SOURCE_DIR ${CMAKE_CURRENT_LIST_LINE})# 绝对路径和相对路径macro(DUMP VAR_NAME_STR)get_filename_component(_TEMP_PATH "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE)message("[DUMP] in " ${_TEMP_PATH} ":" " ${VAR_NAME_STR} = " ${${VAR_NAME_STR}} )endmacro(DUMP)
# 函数示例function(test_parse)set( options op1 op2 op3 op4) # 定义选项参数,值为TRUE或者FALSEset( oneValueArgs v1 v2 v3 ) # 单个值的变量set( multiValueArgs m1 m2 ) # 多个值的变量message( STATUS "options = ${options}" )message( STATUS "oneValueArgs = ${oneValueArgs}" )message( STATUS "multiValueArgs = ${multiValueArgs}" )# 按照设定好的顺序解析,并获得指定前缀的变量;cmake_parse_arguments( MYPRE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )message("op1 = ${MYPRE_op1}")message("op2 = ${MYPRE_op2}")message("op3 = ${MYPRE_op3}")message("op4 = ${MYPRE_op4}")message("v1 = ${MYPRE_v1}")message("v2 = ${MYPRE_v2}")message("v3 = ${MYPRE_v3}")message("m1 = ${MYPRE_m1}")message("m2 = ${MYPRE_m2}")endfunction()# 例子test_parse(op1 ONOP2 ONop3op4 hahav1 v1_valv2 haham1 C1 C2 C3 C4m2 emmmmmmmmmm)# 输出:[cmake] -- options = op1;op2;op3;op4[cmake] -- oneValueArgs = v1;v2;v3[cmake] -- multiValueArgs = m1;m2[cmake] op1 = TRUE[cmake] op2 = FALSE[cmake] op3 = TRUE[cmake] op4 = TRUE[cmake] v1 = v1_val[cmake] v2 = haha[cmake] v3 =[cmake] m1 = C1;C2;C3;C4[cmake] m2 = emmmmmmmmmm
ref:CMake中cmake_parse_arguments的使用简介 - 知乎
- Q: cmake的macro和function有什么区别?——简单搜了一下:
- cmake函数、宏和模块 - 莫水千流 - 博客园
- macro不能用cmake_parse_arguments
可变参数
macro(argn_test hello world)MESSAGE(STATUS ARGV=${ARGV})MESSAGE(STATUS ARGN=${ARGN})MESSAGE(STATUS ARGV0=${ARGV0})MESSAGE(STATUS ARGV1=${ARGV1})MESSAGE(STATUS ARGV2=${ARGV2})MESSAGE(STATUS ARGV3=${ARGV3})endmacro()
- cmake使用教程(八)-macro和function_weixin_34121282的博客-CSDN博客
- cmake:macro,function中ARGV,ARGN参数的区别_10km的专栏-CSDN博客
调试宏:
可以让编译器来展开宏,生成预处理后的文件(preprocessed file);
如果使用CMake:用CMake Configure之后,make src.cpp.i即可;
如果直接使用GCC: gcc -C -E input -I header-path -o output
ref:Generating preprocessed sources in CMake projects - antek’s tech blog
