Modern CMake 简单使用
Modern CMake 简单使用
目录结构
├── CMakeLists.txt
├── main.cpp
└── threadpool
├── CMakeLists.txt
├── threadpool.cpp
└── threadpool.h
第1个CMakeLists.txt
#设置cmake最小版本
cmake_minimum_required(VERSION 3.21)
#设置工程名 版本
project(test_tp VERSION 0.0.1)
message("PROJECT_NAME: ${PROJECT_NAME}")
message("PROJECT_VERSION: ${PROJECT_VERSION}")
message("PROJECT_SOURCE_DIR: ${PROJECT_SOURCE_DIR}")
message("PROJECT_BINARY_DIR: ${PROJECT_BINARY_DIR}")
message("test_tp_VERSION:${test_tp_VERSION}")
message("test_tp_SOURCE_DIR: ${test_tp_SOURCE_DIR}")
message("test_tp_BINARY_DIR:${test_tp_BINARY_DIR}")
if (PROJECT_BINARY_DIR STREQUAL PROJECT_SOURCE_DIR)
message(MARNING "The binary directory of CMake cannot be the same as source directory.")
endif ()
#设置成Release模式
set(CMAKE_BUILD_TYPE Release)
#设置C++标准版本--C++20
set(CMAKE_CXX_STANDARD 20)
#CMAKE_CXX_STANDARD_REQUIRED--默认OFF。表示是否一定要支持你指定的 C++ 标准
#如果为OFF则CMake检测到编译器不支持C++20时不报错,会使用上一版本;为ON则发现不支持报错,更安全。
set(CMAKE_CXX_STANDARD_REQUIRED ON)
#CMAKE_CXX_EXTENSIONS默认为ON。设为ON表示启用GCC特有的一些扩展功能;OFF则关闭GCC的扩展功能,只使用标准的C++。
#要兼容其他编译器(如 MSVC)的项目,都会设为OFF防止不小心用了GCC才有的特性。
set(CMAKE_CXX_EXTENSIONS OFF)
#添加子目录
add_subdirectory(threadpool)
#设置目标编译成二进制可执行文件,文件名为test_tp
add_executable(test_tp)
#链接源文件
#CMAKE_CURRENT_SOURCE_DIR表示当前CMakeLists.txt所在的目录
#target_sources(test_tp PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
#或者
#aux_source_directory(< dir > < variable >) 查找在某个路径下的所有源文件
aux_source_directory(. SRC_LIST) # 搜索当前目录下的所有.cpp文件
target_sources(test_tp PRIVATE ${SRC_LIST})
#链接库
target_link_libraries(test_tp PRIVATE ThreadPool)
第2个CMakeLists.txt
message("threadpool CMAKE_CURRENT_SOURCE_DIR: ${CMAKE_CURRENT_SOURCE_DIR}")
#设置作为对象库(OBJECT)--对象库类似于静态库,但不生成 .a 文件,只由 CMake 记住该库生成了哪些对象文件对象库是 CMake 自创的,绕开了编译器和操作系统的各种繁琐规则,保证了跨平台统一性。
#SHARED--编译动态库--add_library(ThreadPool SHARED)
#STATIC--编译静态库--add_library(ThreadPool STATIC)
add_library(ThreadPool OBJECT)
#查找依赖库
find_package(Threads REQUIRED)
#链接源文件
#CMAKE_CURRENT_SOURCE_DIR表示当前CMakeLists.txt所在的目录
target_sources(ThreadPool PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/threadpool.cpp)
#链接库
target_link_libraries(ThreadPool PRIVATE Threads::Threads)
#设置让引用或者依赖ThreadPool的能自动包含当前目录
#主要是设置当前库的头文件对依赖它的生效,让其他依赖这个库的,能找到相关头文件
#INTERFACE意味着消费者需要但生产者不需要的东西
target_include_directories(ThreadPool INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
常用命令:
cmake -B build
在源码目录用 -B 直接创建 build 目录并生成 build/Makefilecmake --build build -j4
自动调用本地的构建系统在 build 里构建,即:make -C build -j4sudo cmake --build build --target install
调用本地的构建系统执行 install 这个目标,即安装
CMAKE_BUILD_TYPE 构建的类型,调试模式还是发布模式
- CMAKE_BUILD_TYPE 是 CMake 中一个特殊的变量,用于控制构建类型,他的值可以是:
- Debug 调试模式,完全不优化,生成调试信息,方便调试程序
- Release 发布模式,优化程度最高,性能最佳,但是编译比 Debug 慢
- MinSizeRel 最小体积发布,生成的文件比 Release 更小,不完全优化,减少二进制体积
- RelWithDebInfo 带调试信息发布,生成的文件比 Release 更大,因为带有调试的符号信息
- 默认情况下 CMAKE_BUILD_TYPE 为空字符串,这时相当于 Debug。
操作:
- 在配置build时,
cmake -B build -DCMAKE_BUILD_TYPE=Release
. 注意:在配置阶段可以通过 -D 设置缓存变量。第二次配置时,之前的 -D 添加仍然会被保留。也就是如果设置了Release后,要变回Debug,需要再次执行cmake -B build -DCMAKE_BUILD_TYPE=Debug
- 在CMakeLists.txt中设置
set(CMAKE_BUILD_TYPE Release)
PUBLIC,PRIVATE,INTERFACE,定义了Target属性的传递范围
- PUBLIC 对于可执行文件而言意义不大,对于库来说,它让 CMake 知道链接这个目标的目标也需要这个。也就是 “我自己要用,其他链接我的也要用”,具有传递性
- PRIVATE 表示 “我自己用,其他人不用”
- INTERFACE 表示 “我自己不用,其他链接我的要用”
其他小操作:
FetchContent
使用FetchContent的步骤总结起来就是:
- 在cmake文件写入 include(FetchContent)
- 使用FetchContent_Declare(三方库) 获取项目。可以是一个URL也可以是一个Git仓库。
- 使用FetchContent_MakeAvailable(三方库) 获取我们需要库,然后引入项目。
- 使用 target_link_libraries(targetName PRIVATE 库名)
列子
include(FetchContent)
FetchContent_Declare(
doctest
GIT_REPOSITORY https://github.com/doctest/doctest.git
GIT_TAG v2.4.9
GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(doctest)
add_executable(Test01 test_01.cpp)
target_link_libraries(Test01 PRIVATE doctest_with_main)