这是本系列的第六篇。
上一篇我们学习了如何生成安装包,以及如何使用ctest进行简单的测试。
这一篇我们继续学习,如何添加系统自察。什么是“系统自察”呢?具体到本例,就是对系统是否具有某些函数或功能进行预先的测试,通过判断系统的自身属性,在编译时决定采用不同的分支。

Let us consider adding some code to our project that depends on features the target platform may not have. For this example, we will add some code that depends on whether or not the target platform has the
logandexpfunctions. Of course almost every platform has these functions but for this tutorial assume that they are not common.
让我们考虑向项目中添加一些代码,这些代码依赖于目标平台可能没有的功能。对于此示例,我们将添加一些代码,这些代码将依赖于平台是否具有log和exp函数,当然,几乎每个平台都具有这些功能,但在本Tutorial中,假设它们并不常见。
If the platform has
logandexpthen we will use them to compute the square root in themysqrtfunction. We first test for the availability of these functions using theCheckCXXSourceCompilesmodule inMathFunctions/CMakeLists.txt.
如果平台有log和exp函数,那么我们将使用它们来计算mysqrt函数中的平方根。我们首先使用MathFunctions/CMakeLists.txt中的CheckCXXSourceCompiles模块测试这些函数的可用性。
Add the checks for
logandexptoMathFunctions/CMakeLists.txt, after the call totarget_include_directories():
向MathFunctions/CMakeLists.txt中添加针对log和exp的测试,位于target_include_directories()调用之后。
MathFunctions/CMakeLists.txt
target_include_directories(MathFunctions
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
)
# does this system provide the log and exp functions?
include(CheckCXXSourceCompiles)
check_cxx_source_compiles("
#include
int main() {
std::log(1.0);
return 0;
}
" HAVE_LOG)
check_cxx_source_compiles("
#include
int main() {
std::exp(1.0);
return 0;
}
" HAVE_EXP)
If available, use
target_compile_definitions()to specifyHAVE_LOGandHAVE_EXPasPRIVATEcompile definitions.
如果得到的验证结果是“可行”,使用target_compile_definitions()来指定HAVE_LOG和HAVE_EXP,作为私有,即PRIVATE编译定义。
MathFunctions/CMakeLists.txt
if(HAVE_LOG AND HAVE_EXP)
target_compile_definitions(MathFunctions
PRIVATE "HAVE_LOG" "HAVE_EXP")
endif()
小白按:以上修改完成后,最终修改的结果为
add_library(MathFunctions mysqrt.cxx)
# state that anybody linking to us needs to include the current source dir
# to find MathFunctions.h, while we don't.
target_include_directories(MathFunctions
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
)
# does this system provide the log and exp functions?
include(CheckCXXSourceCompiles)
check_cxx_source_compiles("
#include
int main() {
std::log(1.0);
return 0;
}
" HAVE_LOG)
check_cxx_source_compiles("
#include
int main() {
std::exp(1.0);
return 0;
}
" HAVE_EXP)
if(HAVE_LOG AND HAVE_EXP)
target_compile_definitions(MathFunctions
PRIVATE "HAVE_LOG" "HAVE_EXP")
endif()
# install rules
install(TARGETS MathFunctions DESTINATION lib)
install(FILES MathFunctions.h DESTINATION include)
If
logandexpare available on the system, then we will use them to compute the square root in themysqrtfunction. Add the following code to themysqrtfunction inMathFunctions/mysqrt.cxx(don’t forget the#endifbefore returning the result!):
如果log和exp在系统上可用,那么我们将使用它们来计算mysqrt函数中的平方根。将以下代码添加到MathFunctions/mysqrt.cxx中的mysqrt函数(在返回结果之前不要忘记#endif):
MathFunctions/mysqrt.cxx
#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;
#else
double result = x;
We will also need to modify
mysqrt.cxxto includecmath.
我们也需要修改mysqrt.cxx,使其包含cmath。
MathFunctions/mysqrt.cxx
#include
小白按:以上修改全部完成后,mysqrt.cxx的全貌为
#include
#include
#include "MathFunctions.h"
// a hack square root calculation using simple operations
double mysqrt(double x)
{
if (x <= 0) {
return 0;
}
#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;
#else
double result = x;
// do ten iterations
for (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
return result;
}
Run the
cmakeexecutable or thecmake-guito configure the project and then build it with your chosen build tool and run the Tutorial executable.
执行 cmake 或 cmake-gui,指定项目,并且用你选定的编译工具进行编译,最后运行Tutorial可执行文件。
Which function gives better results now,
sqrtormysqrt?
哪一个函数给出了更优的结果?sqrt还是mysqrt?
小白按:给出所有的编译代码:
mkdir Step5_build
cd Step5_build
cmake ../Step5
cmake --build .
cd Debug
Tutorial 4294967206
cd ..
cmake ../Step5 -DUSE_MYMATH=OFF
cmake --build .
cd Debug
Tutorial 4294967206
两个结果分别是:
Computing sqrt of 4.29497e+09 to be 65536 using log and exp
The square root of 4.29497e+09 is 65536
The square root of 4.29497e+09 is 65536
可以看出,使用了log和exp之后,平方根运算的精度已经和系统自带的sqrt函数不相上下了。
这一小节还算是比较容易+平顺的,下一回合我们将要学习“添加自定义命令和生成文件”。
【水平所限,错漏难免,创作不易,轻喷勿骂】
