步骤 2:添加库¶
至此,我们已经了解了如何使用 CMake 创建一个基本项目。在本步骤中,我们将学习如何在项目中创建和使用库。我们还将了解如何使库的使用成为可选。
练习 1 - 创建库¶
要在 CMake 中添加库,请使用 add_library()
命令并指定构成库的源文件。
我们可以将所有源文件组织在一个或多个子目录中,而不是将它们都放在一个目录中。在这种情况下,我们将专门为我们的库创建一个子目录。在这里,我们可以添加一个新的 CMakeLists.txt
文件和一个或多个源文件。在顶层 CMakeLists.txt
文件中,我们将使用 add_subdirectory()
命令将子目录添加到构建中。
创建库后,它通过 target_include_directories()
和 target_link_libraries()
连接到我们的可执行目标。
目标¶
添加和使用库。
有用资源¶
要编辑的文件¶
CMakeLists.txt
tutorial.cxx
MathFunctions/CMakeLists.txt
开始¶
在本练习中,我们将向我们的项目添加一个库,其中包含我们自己计算数字平方根的实现。然后,可执行文件可以使用此库,而不是编译器提供的标准平方根函数。
在本教程中,我们将把库放在一个名为 MathFunctions
的子目录中。此目录已经包含头文件 MathFunctions.h
和 mysqrt.h
。它们各自的源文件 MathFunctions.cxx
和 mysqrt.cxx
也已提供。我们不需要修改任何这些文件。mysqrt.cxx
有一个名为 mysqrt
的函数,它提供与编译器的 sqrt
函数类似的功能。MathFunctions.cxx
包含一个函数 sqrt
,用于隐藏 sqrt
的实现细节。
从 Help/guide/tutorial/Step2
目录开始,从 TODO 1
开始,完成到 TODO 6
。
首先,填写 MathFunctions
子目录中的一行 CMakeLists.txt
。
接下来,编辑顶层 CMakeLists.txt
。
最后,在 tutorial.cxx
中使用新创建的 MathFunctions
库。
构建并运行¶
运行 cmake
可执行文件或 cmake-gui
配置项目,然后使用您选择的构建工具构建它。
以下是命令行中它的样子
mkdir Step2_build
cd Step2_build
cmake ../Step2
cmake --build .
尝试使用新构建的 Tutorial
并确保它仍然生成准确的平方根值。
解决方案¶
在 MathFunctions
目录中的 CMakeLists.txt
文件中,我们使用 add_library()
创建一个名为 MathFunctions
的库目标。库的源文件作为参数传递给 add_library()
。它看起来像下面这一行
TODO 1:点击显示/隐藏答案
add_library(MathFunctions MathFunctions.cxx mysqrt.cxx)
为了使用新库,我们将在顶层 CMakeLists.txt
文件中添加一个 add_subdirectory()
调用,以便构建库。
TODO 2:点击显示/隐藏答案
add_subdirectory(MathFunctions)
接下来,使用 target_link_libraries()
将新库目标链接到可执行目标。
TODO 3:点击显示/隐藏答案
target_link_libraries(Tutorial PUBLIC MathFunctions)
最后,我们需要指定库的头文件位置。修改现有的 target_include_directories()
调用,将 MathFunctions
子目录添加为包含目录,以便可以找到 MathFunctions.h
头文件。
TODO 4:点击显示/隐藏答案
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
"${PROJECT_SOURCE_DIR}/MathFunctions"
)
现在让我们使用我们的库。在 tutorial.cxx
中,包含 MathFunctions.h
。
TODO 5:点击显示/隐藏答案
#include "MathFunctions.h"
最后,将 sqrt
替换为包装函数 mathfunctions::sqrt
。
TODO 6:点击显示/隐藏答案
double const outputValue = mathfunctions::sqrt(inputValue);
练习 2 - 添加选项¶
现在让我们在 MathFunctions 库中添加一个选项,允许开发人员选择自定义平方根实现或内置标准实现。虽然对于本教程来说没有必要这样做,但对于大型项目来说,这是一种常见的情况。
CMake 可以使用 option()
命令来完成此操作。这为用户提供了一个变量,他们可以在配置 cmake 构建时更改它。此设置将存储在缓存中,以便用户每次在构建目录上运行 CMake 时无需设置该值。
目标¶
添加不使用 MathFunctions
构建的选项。
有用资源¶
要编辑的文件¶
MathFunctions/CMakeLists.txt
MathFunctions/MathFunctions.cxx
开始¶
从练习 1 的结果文件开始。完成 TODO 7
到 TODO 14
。
首先在 MathFunctions/CMakeLists.txt
中使用 option()
命令创建一个变量 USE_MYMATH
。在同一个文件中,使用该选项将编译定义传递给 MathFunctions
库。
然后,更新 MathFunctions.cxx
以根据 USE_MYMATH
重定向编译。
最后,通过在 MathFunctions/CMakeLists.txt
的 USE_MYMATH
块内将其设为自己的库,防止 mysqrt.cxx
在 USE_MYMATH
开启时被编译。
构建并运行¶
由于我们已经从练习 1 配置了构建目录,因此我们可以通过简单地调用以下命令进行重建
cd ../Step2_build
cmake --build .
接下来,在几个数字上运行 Tutorial
可执行文件,以验证它是否仍然正确。
现在让我们将 USE_MYMATH
的值更新为 OFF
。最简单的方法是使用 cmake-gui
或 ccmake
(如果您在终端中)。或者,如果您想从命令行更改选项,请尝试
cmake ../Step2 -DUSE_MYMATH=OFF
现在,使用以下命令重建代码
cmake --build .
然后,再次运行可执行文件,以确保它在 USE_MYMATH
设置为 OFF
时仍然有效。哪个函数给出更好的结果,sqrt
还是 mysqrt
?
解决方案¶
第一步是向 MathFunctions/CMakeLists.txt
添加一个选项。此选项将显示在 cmake-gui
和 ccmake
中,默认值为 ON
,用户可以更改。
TODO 7:点击显示/隐藏答案
option(USE_MYMATH "Use tutorial provided math implementation" ON)
接下来,使用此新选项使我们与 mysqrt
函数一起构建和链接库成为条件。
创建一个 if()
语句,检查 USE_MYMATH
的值。在 if()
块内,放置 target_compile_definitions()
命令,其中包含编译定义 USE_MYMATH
。
TODO 8:点击显示/隐藏答案
if (USE_MYMATH)
target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
endif()
当 USE_MYMATH
为 ON
时,将设置编译定义 USE_MYMATH
。然后我们可以使用此编译定义来启用或禁用源代码的各个部分。
源代码的相应更改非常简单。在 MathFunctions.cxx
中,我们让 USE_MYMATH
控制使用哪个平方根函数
TODO 9:点击显示/隐藏答案
#ifdef USE_MYMATH
return detail::mysqrt(x);
#else
return std::sqrt(x);
#endif
接下来,如果定义了 USE_MYMATH
,我们需要包含 mysqrt.h
。
TODO 10:点击显示/隐藏答案
#ifdef USE_MYMATH
# include "mysqrt.h"
#endif
最后,既然我们正在使用 std::sqrt
,我们需要包含 cmath
。
TODO 11:点击显示/隐藏答案
#include <cmath>
此时,如果 USE_MYMATH
为 OFF
,则不会使用 mysqrt.cxx
,但它仍将编译,因为 MathFunctions
目标在源中列出了 mysqrt.cxx
。
有几种方法可以解决这个问题。第一个选项是使用 target_sources()
从 USE_MYMATH
块中添加 mysqrt.cxx
。另一个选项是在 USE_MYMATH
块内创建另一个库,该库负责编译 mysqrt.cxx
。为了本教程的目的,我们将创建一个附加库。
首先,在 USE_MYMATH
中创建一个名为 SqrtLibrary
的库,其源文件为 mysqrt.cxx
。
TODO 12:点击显示/隐藏答案
add_library(SqrtLibrary STATIC
mysqrt.cxx
)
# TODO 6: Link SqrtLibrary to tutorial_compiler_flags
target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()
接下来,当启用 USE_MYMATH
时,我们将 SqrtLibrary
链接到 MathFunctions
。
TODO 13:点击显示/隐藏答案
target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
最后,我们可以从 MathFunctions
库源列表中删除 mysqrt.cxx
,因为它将在包含 SqrtLibrary
时被拉入。
TODO 14:点击显示/隐藏答案
add_library(MathFunctions MathFunctions.cxx)
通过这些更改,mysqrt
函数对于构建和使用 MathFunctions
库的人来说现在是完全可选的。用户可以切换 USE_MYMATH
来操作构建中使用的库。