
今日是2025年的1月2日,是2025年的第一個做工日,在開始學習之前呢,先要祝大家新年快樂,學有所成嘍。
Intro
先来复习一下吧~
add_library(): ?add_subdirectory(): ?target_link_libraries(): ?PROJECT_SOURCE_DIR: ?if()endif(): ?list(),APPEND: ?option(): ?target_compile_definitions(): ?cmake -D[OPTION_NAME]=: ?
add_library(): 设定一个程式为Lib库。add_subdirectory(): 为项目增加一个子目录。target_link_libraries(): 将一个或多个库链接到指定的目标(如可执行文件或另一个库)。PROJECT_SOURCE_DIR: 程式源码的目录。if()endif(): 条件判断。list(),APPEND: 扫描和追加。option(): 设定选项。target_compile_definitions(): 向程式添加预处理器宏。cmake -D[OPTION_NAME]=: 为 CMakeLists.txt 中的option填充值。
那么今天我们来学习一下CMake如何为Lib添加使用要求和自动配置一些参数的?
涉及到的函式(函数 / API) 如下:
target_include_directories()target_link_libraries()INTERFACE
那学习本节内容还需要一些前提条件:
- 你可以直接使用上节内容中的代码。
- 也可以从Code获取初始代码哦。
Tips: 根据代码提示完成步骤,我们可以在上面的链接中查看
MathFuntions/CMakeLists.txt文本档案中的内容,其中包含对代码的解释说明# TODO 1: State that anybody linking to MathFunctions needs to include the,# TODO 6: Link SqrtLibrary to tutorial_compiler_flags,# TODO 7: Link MathFunctions to tutorial_compiler_flags我们也可以根据这些提示自行查找资料完成CMake的编写来自己学习呦。 A菌也是跟随官方实例来学习的,所以哪里有疑惑也可以自行对照校对,如果文章有出入或者A菌有解释不清或错误,请留言帮助A菌改正啦。
开始
Setp1: 第三方Lib自己处理包含目录,减少使用者负担
MathFunctions指定所需的包含目录。- 在
MathFunctions/CMakeLists.txt末尾,将target_include_directories()与INTERFACE关键字一起使用。
- 在
# TODO 1: State that anybody linking to MathFunctions needs to include the
#
# 这句代码的意思是将 `MathFunctions` 目标的当前源目录(`${CMAKE_CURRENT_SOURCE_DIR}`)添加到 #`MathFunctions` 目标的包含目录中,并且这个包含目录是以 `INTERFACE` 的形式添加的。
#
#`INTERFACE` 的意思是这个包含目录信息将会传播给所有链接到 `MathFunctions` 的目标。
# 也就是说,任何链接到 #`MathFunctions` 的目标(例如 `Tutorial`)都会自动包含 `MathFunctions` 的当前源目录作为它们的包含目录。
target_include_directories(MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
Tutorial只需链接到MathFunctions而不必担心任何其他包含目录。- 从顶级
CMakeLists.txt中删除对EXTRA_INCLUDES变量的使用。
- 从顶级
# TODO 2: Remove EXTRA_INCLUDES list
# add the MathFunctions library
add_subdirectory(MathFunctions)
# 这里注释掉了,不用包含了,因为链接的时候库会自己处理包含目录了
# list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
- 删除顶级
CMakeLists.txt中的target_include_directories中的EXTRA_INCLUDES变量
# TODO 3: Remove use of EXTRA_INCLUDES
# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
#
# target_include_directories(Tutorial PUBLIC
# "${PROJECT_BINARY_DIR}"
# ${EXTRA_INCLUDES}
# )
# 这里删除了 ${EXTRA_INCLUDES} 变量,因为list追加的已经没了,库也自包含了只需要链接就可以了。
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
)
step2: 一对多的Lib配置
- 顶级CMakeLists.txt
- 创建一个新的
lib使用INTERFACE修饰,这样所有的其他代码库链接到它的时候,就都被cxx_std_11约束啦。 - 删除掉
set中依靠环境变量对版本的约束。
# TODO 4: Replace the following code by:
# * Creating an interface library called tutorial_compiler_flags
# Hint: use add_library() with the INTERFACE signature
# * Add compiler feature cxx_std_11 to tutorial_compiler_flags
# Hint: Use target_compile_features()
# specify the C++ standard
# 注释掉之前用set设置的环境变量的约束
# set(CMAKE_CXX_STANDARD 11)
# set(CMAKE_CXX_STANDARD_REQUIRED True)
# 创建一个新的 Lib 名为`tutorial_compiler_flags`亦或是其他
add_library(tutorial_compiler_flags INTERFACE)
# `target_compile_features` 是 CMake 中用于指定目标所需的编译特性的命
# 令。它允许你为目标设置特定的编译器特性,例如 C++ 标准版本。
# 这行代码的意思是为 `tutorial_compiler_flags` 接口库添加 `cxx_std_11`
# 编译特性,这意味着任何链接到 `tutorial_compiler_flags` 的目标都需要支
# 持 C++11 标准。
# `target_compile_features` 的常见用法包括:
# * `PRIVATE`:仅当前目标需要这些编译特性。
# * `PUBLIC`:当前目标和所有链接到它的目标都需要这些编译特性。
# * `INTERFACE`:仅链接到当前目标的目标需要这些编译特性。
target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11)
- 顶级CMakeLists.txt
- 将我们的通用约束库链接到程式中,以传播设置。
# TODO 5: Link Tutorial to tutorial_compiler_flags
#
# 这行代码的意思是将 `MathFunctions` 和 `tutorial_compiler_flags` 库链
# 接到 `Tutorial` 可执行文件,并且这些链接是以 `PUBLIC` 的形式添加的。
#
# `PUBLIC` 的意思是:
# * 任何链接到 `Tutorial` 的目标也会继承这些链接库。
target_link_libraries(Tutorial PUBLIC MathFunctions tutorial_compiler_flags)
- MathFunctions/CMakeLists.txt
- 链接一下
# 从这里开的if然后省略了写内容
if (USE_MYMATH)...
# TODO 6: Link SqrtLibrary to tutorial_compiler_flags
# 链接`tutorial_compiler_flags`到`SqrtLibrary`
# `target_link_libraries` 命令用于指定目标需要链接的库。
# 这里使用 `PUBLIC` 关键字的原因是为了确保依赖关系能够传播到任何链接到 `SqrtLibrary` 的目标。
# * `PRIVATE`:依赖关系仅用于目标本身。
# * `INTERFACE`:依赖关系仅用于链接到该目标的其他目标。
# * `PUBLIC`:依赖关系既用于目标本身,也用于链接到该目标的其他目标。
target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
# 链接`SqrtLibrary`到`MathFunctions`并且被`tutorial_compiler_flags`传播了
target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()
# TODO 7: Link MathFunctions to tutorial_compiler_flags
# 这一行的作用是将 `tutorial_compiler_flags` 的设置传播到任何链接到 `MathFunctions` 的目标。
# 这是因为 `PUBLIC` 关键字会将依赖关系传播到所有依赖 `MathFunctions` 的目标。
target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags)
如此一来,我们想更改编译设置的时候,只需要修改tutorial_compiler_flags即可。
复习
target_include_directories(x option ${CMAKE_CURRENT_SOURCE_DIR}): 指定任何链接到x的目标需要包含当前源目录 (${CMAKE_CURRENT_SOURCE_DIR}) 作为头文件搜索路径。- option: 可选 INTERFACE,PRIVATE,PUBLIC
target_link_libraries(x option y): 将y链接到x- option: 可选 INTERFACE,PRIVATE,PUBLIC
論壇的錯誤真的有夠多誒。