Step 5: Adding System Introspection(添加系统自察)
为了代码能根据不同平台的特征来check环境中的依赖是否都存在,以check环境平台中是否有 log
和exp
函数为例来check(实际上很多平台都有这俩函数,这里只是简单的以这俩为例,假设他们不是很common的依赖函数):
如果在mysqrt
这个函数的计算过程中要用到log
和exp
这俩个函数,需要先使用CheckSymbolExitst
这个模块来检测是否该功能存在。
0 修改配置文件
在MathFunctions
子目录的CMakeLists.txt
中添加如下字段:
include(CheckSymbolExists)
check_symbol_exists(log "math.h" HAVE_LOG)#检查头文件math.h 中是否有函数 log,若有的则定义HAVE_LOG 缓存变量,固定设置为1
check_symbol_exists(exp "math.h" HAVE_EXP)
if(NOT (HAVE_LOG AND HAVE_EXP#如果最初未找到 log 和 exp,则需要 m 库并重试。
unset(HAVE_LOG CACHE)
unset(HAVE_EXP CACHE)
set(CMAKE_REQUIRED_LIBRARIES "m") #将libm.so 加入CMAKE_REQUEST_LIBRARIES 列表中
check_symbol_exists(log "math.h" HAVE_LOG)
check_symbol_exists(exp "math.h" HAVE_EXP)
if(HAVE_LOG AND HAVE_EXP)
target_link_libraries(MathFunctions PRIVATE m)
endif()
endif()
if(HAVE_LOG AND HAVE_EXP)#如果找到了log 和exp,使用 target_compile_definitions() 将 HAVE_LOG 和 HAVE_EXP 指定为私有编译定义。
target_compile_definitions(MathFunctions
PRIVATE "HAVE_LOG" "HAVE_EXP")
endif()
check_symbol_exists()
语法如下:
check_symbol_exists(<symbol> <files> <variable>)
在包含给定的头文件 <files>
后检查<symbol>
是否可用并将结果存储在 <variable>
中。 将一个参数中的文件列表指定为以分号分隔的列表。 <variable>
将被创建为内部缓存变量。
如果头文件将符号定义为宏,则认为它可用并假定可以工作。 如果头文件将符号声明为函数或变量,则符号也必须可用于链接(因此可能无法检测到内部函数)。 如果符号是类型、枚举值或内部符号,则无法识别(考虑使用 CheckTypeSize 或 CheckCSourceCompiles)。 如果需要在 C++ 中完成检查,请考虑改用 CheckCXXSymbolExists。
unset()
语法如下:
取消设置变量、缓存变量或环境变量。
unset(<variable> [CACHE | PARENT_SCOPE])
如果没有关键字,unset用于从当前作用域删除一个普通变量(normal ariable),使其变为未定义。
如果有CACHE 关键字的话,意味着删除了一个缓存变量。
说明:在CMake语义里,引用${VAR}首先找到具有该名的普通变量,如果没有的话再在缓存中找这个名字。
如果存在 PARENT_SCOPE,则该变量将从当前作用域之上的作用域中移除。
set(CMAKE_REQUIRED_LIBRARIES "m")
加载了libm.so库,看当前本地安装的库可使用如下命令:
dconfig -p | grep lib_name
比如在我的本地就有如下动态库:
1 修改源代码
如果系统上有 log 和 exp,那么我们将使用它们来计算 mysqrt 函数中的平方根。 将以下代码添加到 MathFunctions/mysqrt.cxx 中的 mysqrt 函数中(在返回结果之前不要忘记 #endif!):
#if defined(HAVE_LOG) && defined(HAVE_EXP)
double result = exp(log(x) * 0.5);
std::cout << "Computing sqrt of " << x << " to be " << result
<< " using log and exp" << std::endl;
#else
double result = x;
#endif
同时也需要在mysqrt.cxx 文件内添加头文件包含#include<cmath>
测试:
mkdir build
cd build
cmake ../
cmake --build .
ctest -C DEBUG -VV
结果如下:
执行安装sudo make install
的时候仍然有bug
[ 50%] Built target MathFunctions
[100%] Built target Tutorial
Install the project...
-- Install configuration: ""
-- Installing: /usr/local/bin/Tutorial
CMake Error at cmake_install.cmake:57 (file):
file INSTALL cannot find "//TutorialConfig.h".
Makefile:128: recipe for target 'install' failed
make: *** [install] Error 1