该文档是基于CMake的官方教程翻译而来,并稍微添加了自己的理解:
cmake的官方网站为:CMake Tutorial
The CMake tutorial provides a step-by-step guide that covers common build system issues that CMake helps address. Seeing how various topics all work together in an example project can be very helpful.
CMake 教程提供了一个循序渐进的指南,涵盖了 CMake 可帮助解决的常见构建系统问题。在一个示例项目中了解各个主题是如何协同工作的,会非常有帮助。
The tutorial source code examples are available in this archive. Each step has its own subdirectory containing code that may be used as a starting point. The tutorial examples are progressive so that each step provides the complete solution for the previous step.
本文档中提供了教程源代码示例。每个步骤都有自己的子目录,其中包含可用作起点的代码。教程示例是循序渐进的,因此每一步都提供了前一步的完整解决方案。
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 and exp functions. Of course almost every platform has these functions but for this tutorial assume that they are not common.
让我们考虑在项目中添加一些依赖于目标平台可能不具备的功能的代码。在本例中,我们将添加一些取决于目标平台是否具有 log 和 exp 函数的代码。当然,几乎每个平台都有这些函数,但本教程假设它们并不常见。
Change implementation based on available system dependencies.
根据现有的系统依赖关系改变实现方式。
The starting source code is provided in the Step7 directory. In this exercise, complete TODO 1 through TODO 5.
Step7 目录中提供了起始源代码。在本练习中,完成 TODO 1 到 TODO 5。
Start by editing MathFunctions/CMakeLists.txt. Include the CheckCXXSourceCompiles module. Then, use check_cxx_source_compiles to determine whether log and exp are available from cmath. If they are available, use target_compile_definitions() to specify HAVE_LOG and HAVE_EXP as compile definitions.
首先编辑 MathFunctions/CMakeLists.txt
。加入 CheckCXXSourceCompiles
模块。然后,使用 check_cxx_source_compiles
确定 cmath
是否提供 log
和 exp
。如果可用,则使用 target_compile_definitions
() 将 HAVE_LOG
和 HAVE_EXP
指定为编译定义。
In the MathFunctions/mysqrt.cxx, include cmath. Then, if the system has log and exp, use them to compute the square root.
在 MathFunctions/mysqrt.cxx
中,加入 cmath
。然后,如果系统有 log
和 exp
,则使用它们计算平方根。
Make a new directory called Step7_build. Run the cmake executable or the cmake-gui to configure the project and then build it with your chosen build tool and run the Tutorial executable.
新建一个名为 Step7_build
的目录。运行 cmake
可执行文件或 cmake-gui
配置项目,然后使用所选的构建工具构建项目,并运行 Tutorial
可执行文件。
This can look like the following:
如下所示:
mkdir Step7_build
cd Step7_build
cmake ../Step7
cmake --build .
Which function gives better results now, sqrt or mysqrt?
sqrt 和 mysqrt 哪个函数的结果更好?
In this exercise we will use functions from the CheckCXXSourceCompiles module so first we must include it in MathFunctions/CMakeLists.txt.
在本练习中,我们将使用 CheckCXXSourceCompiles
模块中的函数,因此首先必须将其包含在 MathFunctions/CMakeLists.txt
中。
TODO 1: Click to show/hide answer
TODO 1: MathFunctions/CMakeLists.txt
include(CheckCXXSourceCompiles)
Then test for the availability of log and exp using check_cxx_compiles_source. This function lets us try compiling simple code with the required dependency prior to the true source code compilation. The resulting variables HAVE_LOG and HAVE_EXP represent whether those dependencies are available.
然后使用 check_cxx_compiles_source
测试log
志和 exp
是否可用。通过该函数,我们可以在编译真正的源代码之前,尝试使用所需的依赖关系编译简单的代码。结果变量 HAVE_LOG
和 HAVE_EXP
表示这些依赖关系是否可用。
TODO 2: Click to show/hide answer
TODO 2: MathFunctions/CMakeLists.txt
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)
Next, we need to pass these CMake variables to our source code. This way, our source code can tell what resources are available. If both log and exp are available, use target_compile_definitions() to specify HAVE_LOG and HAVE_EXP as PRIVATE compile definitions.
接下来,我们需要将这些 CMake
变量传递给我们的源代码。这样,我们的源代码就能知道哪些资源可用。如果 log
和 exp
都可用,请使用 target_compile_definitions
() 将 HAVE_LOG
和 HAVE_EXP
指定为私有编译定义。
TODO 3: Click to show/hide answer
TODO 3: MathFunctions/CMakeLists.txt
if(HAVE_LOG AND HAVE_EXP)
target_compile_definitions(SqrtLibrary
PRIVATE "HAVE_LOG" "HAVE_EXP"
)
endif()
Since we may be using log and exp, we need to modify mysqrt.cxx to include cmath.
由于我们可能会使用 log
和 exp
,因此需要修改 mysqrt.cxx
以包含 cmath
。
TODO 4: Click to show/hide answer
TODO 4: MathFunctions/mysqrt.cxx
#include
If log and exp are available on the system, then use them to compute the square root in the mysqrt function. The mysqrt function in MathFunctions/mysqrt.cxx will look as follows:
TODO 5: Click to show/hide answer
TODO 5: 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;
// 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
add_library(MathFunctions MathFunctions.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}
)
# should we use our own math functions
option(USE_MYMATH "Use tutorial provided math implementation" ON)
if (USE_MYMATH)
target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
# library that just does sqrt
add_library(SqrtLibrary STATIC
mysqrt.cxx
)
target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
# TODO 1: Include CheckCXXSourceCompiles
include(CheckCXXSourceCompiles)
# TODO 2: Use check_cxx_source_compiles with simple C++ code to verify
# availability of:
# * std::log
# * std::exp
# Store the results in HAVE_LOG and HAVE_EXP respectively.
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)
# Hint: Sample C++ code which uses log:
# #include <cmath>
# int main() {
# std::log(1.0);
# return 0;
# }
# TODO 3: Conditionally on HAVE_LOG and HAVE_EXP, add private compile
# definitions "HAVE_LOG" and "HAVE_EXP" to the SqrtLibrary target.
# Hint: Use target_compile_definitions()
if(HAVE_LOG AND HAVE_EXP)
target_compile_definitions(SqrtLibrary
PRIVATE "HAVE_LOG" "HAVE_EXP"
)
endif()
target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()
# link our compiler flags interface library
target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags)
# install libs
set(installable_libs MathFunctions tutorial_compiler_flags)
if(TARGET SqrtLibrary)
list(APPEND installable_libs SqrtLibrary)
endif()
install(TARGETS ${installable_libs} DESTINATION lib)
# install include headers
install(FILES MathFunctions.h DESTINATION include)
#include "mysqrt.h"
#include
#include
namespace mathfunctions {
namespace detail {
// a hack square root calculation using simple operations
double mysqrt(double x)
{
if (x <= 0) {
return 0;
}
// TODO 5: If both HAVE_LOG and HAVE_EXP are defined, use the following:
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, use the existing logic.
#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;
}
}
}
test@test:~/sda3/work/cmake/Step7_build$ cmake ../Step7
-- Configuring done
-- Generating done
-- Build files have been written to: /home/test/sda3/work/cmake/Step7_build
test@test:~/sda3/work/cmake/Step7_build$ cmake --build .
Consolidate compiler generated dependencies of target SqrtLibrary
[ 16%] Building CXX object MathFunctions/CMakeFiles/SqrtLibrary.dir/mysqrt.cxx.o
[ 33%] Linking CXX static library libSqrtLibrary.a
[ 33%] Built target SqrtLibrary
Consolidate compiler generated dependencies of target MathFunctions
[ 66%] Built target MathFunctions
Consolidate compiler generated dependencies of target Tutorial
[ 83%] Linking CXX executable Tutorial
[100%] Built target Tutorial
test@test:~/sda3/work/cmake/Step7_build$
test@test:~/sda3/work/cmake/Step7_build$
test@test:~/sda3/work/cmake/Step7_build$ ./T
Testing/ Tutorial
test@test:~/sda3/work/cmake/Step7_build$ ./T
Testing/ Tutorial
test@test:~/sda3/work/cmake/Step7_build$ ./T
Testing/ Tutorial
test@test:~/sda3/work/cmake/Step7_build$ ./Tutorial
./Tutorial Version 1.0
Usage: ./Tutorial number
test@test:~/sda3/work/cmake/Step7_build$ ./Tutorial 10
Computing sqrt of 10 to be 3.16228 using log and exp
The square root of 10 is 3.16228
test@test:~/sda3/work/cmake/Step7_build$ ./Tutorial 100
Computing sqrt of 100 to be 10 using log and exp
The square root of 100 is 10
test@test:~/sda3/work/cmake/Step7_build$ ./Tutorial 10000
Computing sqrt of 10000 to be 100 using log and exp
The square root of 10000 is 100
test@test:~/sda3/work/cmake/Step7_build$