这是本系列的第六篇。
上一篇我们学习了如何生成安装包,以及如何使用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
log
andexp
functions. 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
log
andexp
then we will use them to compute the square root in themysqrt
function. We first test for the availability of these functions using theCheckCXXSourceCompiles
module inMathFunctions/CMakeLists.txt
.
如果平台有log
和exp
函数,那么我们将使用它们来计算mysqrt
函数中的平方根。我们首先使用MathFunctions/CMakeLists.txt
中的CheckCXXSourceCompiles
模块测试这些函数的可用性。
Add the checks for
log
andexp
toMathFunctions/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_LOG
andHAVE_EXP
asPRIVATE
compile 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
log
andexp
are available on the system, then we will use them to compute the square root in themysqrt
function. Add the following code to themysqrt
function inMathFunctions/mysqrt.cxx
(don’t forget the#endif
before 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.cxx
to 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
cmake
executable or thecmake-gui
to 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,
sqrt
ormysqrt
?
哪一个函数给出了更优的结果?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
函数不相上下了。
这一小节还算是比较容易+平顺的,下一回合我们将要学习“添加自定义命令和生成文件”。
【水平所限,错漏难免,创作不易,轻喷勿骂】