CMake教程(七):添加系统检查
个人觉得 CMake 官网教程 Step6 对当前我们增加对 CMake 的了解作用不大,所以直接写了教程七。
现在,我们考虑在项目中添加一些代码,这些代码取决于目标平台可能没有的功能。对于这个例子,我们将添加一些代码,这取决于目标平台是否具有log
和 exp
函数。几乎每个平台都具有这两个函数,在这里我们仅是作为例子来说明本节的内容。
本节的目标是根据可用的系统依赖让编译器有选择性编译具体的实现代码。
需要编辑的文件:
MathFunctions/CMakeLists.txt
MathFunctions/mysqrt.cxx
本节使用的源代码是官网 Step7
目录下的文件。一开始我们需要编辑 MathFunctions/CMakeLists.txt
文件,包含 CheckCXXSourceCompiles
模块。之后,使用 check_cxx_source_compiles
确认 cmath
库当中的 log
和 exp
函数是否可用。如果它们可用,使用 target_compile_definitions()
指定 HAVE_LOG
和 HAVE_EXP
作为编译定义。
在 MathFunctions/mysqrt.cxx
文件中,包含 cmath
。之后,如果系统有 log
和 exp
函数,使用它们计算平方根。
首先,修改 MathFunctions/mysqrt.cxx
文件,在其中添加下面的指令:
include(CheckCXXSourceCompiles)
之后,使用 check_cxx_compiles_source
测试 log
和 exp
函数的可用性。此函数允许我们在编译真正的源代码之前,尝试编译具有所需依赖关系的简单代码。结果变量 HAVE_LOG
和 HAVE_EXP
表示这些依赖关系是否可用。继续修改 MathFunctions/CMakeLists.txt
文件,添加以下的内容:
check_cxx_source_compiles("#include <cmath>int main() {std::log(1.0);return 0;}" HAVE_LOG)check_cxx_source_compiles("#include <cmath>int main() {std::exp(1.0);return 0;}" HAVE_EXP)
然后,需要传递这些 CMake 变量到源代码中。这样,源代码就能够分辨出哪些资源是可用的。如果 log
和 exp
函数都可用,使用指令 target_compile_definitions()
指定 HAVE_LOG
和 HAVE_EXP
作为 PRIVATE
的编译定义。继续修改 MathFunctions/CMakeLists.txt
文件,添加以下的内容:
if(HAVE_LOG AND HAVE_EXP)target_compile_definitions(SqrtLibraryPRIVATE "HAVE_LOG" "HAVE_EXP")endif()target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()
接下来,我们需要修改 mysqrt.cxx
文件包含 cmath
。
#include <cmath>
如果 log
和 exp
函数都可用,那么在 mysqrt
函数当中使用它们来计算平方根。修改 MathFunctions/mysqrt.cxx
文件中的 mysqrt
函数:
#if defined(HAVE_LOG) && defined(HAVE_EXP)double result = std::exp(std::log(x) * 0.5);std::cout << "Computing sqrt of " << x << " to be " << result<< " using log and exp" << std::endl;
#elsedouble result = x;// do ten iterationsfor (int i = 0; i < 10; ++i) {if (result <= 0) {result = 0.1;}double delta = x - (result * result);result = result + 0.5 * delta / result;std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;}
#endif
执行结果:
如果想要使用我们自己编写的指数函数和对数函数,需要在 MathFunctions/CMakeLists.txt
当中删除以下的代码:
check_cxx_source_compiles("#include <cmath>int main() {std::log(1.0);return 0;}" HAVE_LOG)check_cxx_source_compiles("#include <cmath>int main() {std::exp(1.0);return 0;}" HAVE_EXP)
再次编译并运行程序:
小结:本节我们利用 CMake 当中的 CheckCXXSourceCompiles
模块,该模块提供了一系列用于检查 C++ 源代码片段是否能够在当前系统上成功编译的宏。接着,使用 CHECK_CXX_SOURCE_COMPILES
指令让 CMake 编译一小段代码,如果编译成功,根据这个结果来设置变量、条件编译选项或者定义特定的特性。
最后,介绍 include(CheckCXXSourceCompiles)
的作用。
include(CheckCXXSourceCompiles)
的作用
在CMake中,include(CheckCXXSourceCompiles)
命令的作用是引入一个 CMake 模块,该模块提供了一系列用于检查 C++ 源代码片段是否能够在当前系统上成功编译的宏。这通常用于在配置(configure)阶段自动检测系统或编译器的特定功能或限制。
具体来说,CheckCXXSourceCompiles
模块定义了一个或多个宏,比如 CHECK_CXX_SOURCE_COMPILES
,你可以使用这些宏来编写一小段 C++ 代码,并让 CMake 尝试编译这段代码。如果编译成功,你可以根据这个结果来设置变量、条件编译选项或者定义特定的特性。
使用 CHECK_CXX_SOURCE_COMPILES
宏时,需要提供至少两个参数:
- 第一个参数是要执行的 C++ 代码;
- 第二个参数是一个自定义的变量,用于存储编译这段代码的结果。
下面是一个简单的例子,展示了如何使用 CheckCXXSourceCompiles
来检测编译器是否支持 C++11 的某些特性(如 auto
关键字):
include(CheckCXXSourceCompiles) # 检查C++11的auto关键字是否可用
CHECK_CXX_SOURCE_COMPILES("
#include <vector> int main() { std::vector<int> v = {1, 2, 3}; auto x = v[0]; return 0;
}
" HAVE_CXX11_AUTO) # 根据检查结果,可以做出不同的配置决策
if(HAVE_CXX11_AUTO) message(STATUS "Compiler supports C++11 auto keyword.")
else() message(FATAL_ERROR "Compiler does not support C++11 auto keyword.")
endif()
各位道友,码字不易,如有收获,记得一键三连啊。
看完觉得有帮助的道友,可以关注我的公众号,里面会分享一些高质量的个人成长类读书笔记、生活随笔以及职场经验等等。