Cmake
Cmake
环境
WSL+cmake3.16.3
教程
CMake Tutorial — CMake 3.28.0-rc2 Documentation
Step1
cmake_minimum_required
任何项目的 CMakeLists.txt 文件都必须首先使用 cmake_minimum_required()
命令指定 CMake 的最小版本。这将建立策略设置,并确保以下 CMake 功能在兼容的 CMake 版本下运行。
1 | cmake_minimum_required(VERSION <min>[...<policy_max>] [FATAL_ERROR]) |
project
要启动一个项目,我们需要使用 project()
命令来设置项目名称。每个项目都需要调用该命令,并且应在 cmake_minimum_required()
之后尽快调用。
1 | project(<PROJECT-NAME> [<language-name>...]) |
add_executable
告诉 CMake 使用指定的源代码文件创建可执行文件。
1 | add_executable(<name> [WIN32] [MACOSX_BUNDLE] |
编译
1 | mkdir Step1_build |
CMAKE_CXX_STANDARD
CMAKE_CXX_STANDARD_REQUIRED
CMAKE_CXX_STANDARD_REQUIRED — CMake 3.28.0-rc2 Documentation
设置以下变量来增添对C++11的支持。
1 | set(CMAKE_CXX_STANDARD 11) |
configure_file
1 | configure_file(TutorialConfig.h.in TutorialConfig.h) |
将.in
文件写入.h
里面。
这个.h
会生成在最后的build文件夹内,即PROJECT_BINARY_DIR
(注意和PROJECT_SOURCE_DIR
作出区分)
在这里面可以设置版本,当导入到头文件后也能在项目里面打印了。
target_include_directories
我们使用 target_include_directories() 来指定目标可执行文件应在何处查找包含文件。
1 | target_include_directories(Tutorial PUBLIC |
因为TutorialConfig.h
会生成在build主文件夹下,所以只要把主目录include即可,通过PROJECT_BINARY_DIR变量。
TutorialConfig.h.in
1 | // the configured options and settings for Tutorial |
@<proj_name>_VERSION_MAJOR@
这样的变量会在cmake的时候首先被cmake的设置进行替换(在project函数里面指定了版本),然后再将整个文件复制进TutorialConfig.h.in
里面。
然后在cpp文件里面include:
1 | #include "TutorialConfig.h" |
就可以打印这两个变量了。
总结
Step1教了以下事情:
- 初始化一个项目,项目名及版本
- 编译单文件成可执行文件
- 增加对C++11的支持
- 生成并包括头文件,从而能在源码内打印版本号
Step2
1 | ├── CMakeLists.txt |
目标是在主项目中编译生成并使用一个叫做MathFunctions的库。
add_library
1 | add_library(MathFunctions MathFunctions.cxx mysqrt.cxx) |
首先在MathFunctions里的CMakeLists.txt进行配置。
add_subdirectory
然后在主项目里面添加子项目。
1 | add_subdirectory(MathFunctions) |
target_link_libraries
1 | target_link_libraries(Tutorial PUBLIC MathFunctions) |
将lib连接到主项目上。
target_include_directories
修改这个来添加路径,使得cmake能找到MathFunctions的头文件。
1 | target_include_directories(Tutorial PUBLIC |
PROJECT_BINARY_DIR
和PROJECT_SOURCE_DIR
注意作出区分
option
在MathFunctions里面添加:
1 | option(USE_MYMATH "Use self-defined math implementation" ON) |
if
1 | if(<condition>) |
比如:
1 | if(USE_MYMATH) |
target_compile_definitions
1 | Add compile definitions to a target. |
target
直接是整个子项目/主项目,不需要加文件后缀。
1 | target_compile_definitions(MathFunctions |
修改MathFunctions.cxx
1 |
|
现在添加了基于USE_MYMATH宏的逻辑。
优化编译逻辑
即使USE_MYMATH被设置成OFF,上面的代码还是会编译mysqrt
。
为了进行优化,一种方法是将mysqrt当作一个独立的库,然后在需要的时候再链接到MathFunctions库上。
在if块中:
1 | add_library(SqrtLibrary STATIC |
然后删除
1 | add_library(MathFunctions MathFunctions.cxx mysqrt.cxx) |
改成:
1 | add_library(MathFunctions MathFunctions.cxx) |
编译
1 | cmake ../Step2 -DUSE_MYMATH=OFF |
总结
- 编译库
- if,option
- 将compile flag传入源码中作为宏变量
Step3
简化文件包含
[Step 3: Adding Usage Requirements for a Library — CMake 3.28.0-rc3 Documentation](https://cmake.org/cmake/help/latest/guide/tutorial/Adding Usage Requirements for a Library.html)
在子项目中添加如下的INTERFACE代码,能够省去在主项目中明确包括子项目文件的麻烦。Cmake会自动通过INTERFACE接口来寻找到子项目文件。
1 | target_include_directories(MathFunctions |
这种情况下,只要
1 | target_link_libraries(Tutorial PUBLIC MathFunctions) |
即可。
设置C++标准
用INTERFACE来为每个项目设置C++标准。
先删除
1 | set(CMAKE_CXX_STANDARD 11) |
然后
在主项目中添加一个INTERFACE library:(一个抽象的接口库,这个库只用于设置编译器标准等其他配置)
1 | add_library(tutorial_compiler_flags INTERFACE) |
然后在每一个子项目的CMakeLists.txt中添加:(只要子项目需要C++特性就要加)
1 | target_link_libraries(Tutorial PUBLIC MathFunctions tutorial_compiler_flags) |
Step4
Generator Expressions⭐
cmake-generator-expressions(7) — CMake 3.28.0-rc3 Documentation
一个挺复杂的概念。
一个$<>
包裹的一个表达式。
根据下面的代码,可以笼统理解为:$<某个条件:满足某个条件后会干啥/需要满足哪些条件>
下面就是通过这个来设置布尔变量,进而添加编译器设置。
1 | cmake_minimum_required(VERSION 3.15) |
Step5
安装
用install函数来实现cmake install功能。
1 | set(installable_libs MathFunctions tutorial_compiler_flags) |
1 | install(TARGETS Tutorial DESTINATION bin) |
总结一下:
${}
是用来将变量解析的,转化成变量所表示的值。否则这个变量就当成一个字符串来看了。- install中TARGETS用于指向每个项目(表示其生成的可执行文件),FILES表示一般文件(这里用于头文件),默认路径是源码路径(PROJECT_SOURCE_DIR);DESTINATION表示安装的文件夹
- list APPEND用于为变量(实际上是一个列表)添加元素
- if TARGET意思是如果生成了SqrtLibrary这个可执行文件,则
最后执行命令
1 | cmake --install . --prefix "path/to/installDir" |
测试
1 | # TODO 5: Enable testing |
重新cmake编译
然后
1 | ctest -N |
对于多种配置的生成器(比如VisualStudio),需要指定build:
1 | ctest -C Debug -VV |
Step6
跳过
Step7
检查依赖完整性
这里通过检查log
和exp
函数是否存在作为例子。
1 | include(CheckCXXSourceCompiles) |
mymath.cxx
里面:
1 |
|
Step8
[Step 8: Adding a Custom Command and Generated File — CMake 3.28.0-rc3 Documentation](https://cmake.org/cmake/help/latest/guide/tutorial/Adding a Custom Command and Generated File.html)
Step9
[Step 9: Packaging an Installer — CMake 3.28.0-rc3 Documentation](https://cmake.org/cmake/help/latest/guide/tutorial/Packaging an Installer.html)
Step10
[Step 10: Selecting Static or Shared Libraries — CMake 3.28.0-rc3 Documentation](https://cmake.org/cmake/help/latest/guide/tutorial/Selecting Static or Shared Libraries.html)
Step11
[Step 11: Adding Export Configuration — CMake 3.28.0-rc3 Documentation](https://cmake.org/cmake/help/latest/guide/tutorial/Adding Export Configuration.html)
Step12
[Step 12: Packaging Debug and Release — CMake 3.28.0-rc3 Documentation](https://cmake.org/cmake/help/latest/guide/tutorial/Packaging Debug and Release.html)
- 本文作者: Taardis
- 本文链接: https://taardisaa.github.io/2023/10/24/Cmake/
- 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!