CMake教程-第 7 步:添加系统自省功能

CMake教程-第 7 步:添加系统自省功能

该文档是基于CMake的官方教程翻译而来,并稍微添加了自己的理解:

cmake的官方网站为:CMake Tutorial

1 CMake教程介绍

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 可帮助解决的常见构建系统问题。在一个示例项目中了解各个主题是如何协同工作的,会非常有帮助。

2 学习步骤

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.
本文档中提供了教程源代码示例。每个步骤都有自己的子目录,其中包含可用作起点的代码。教程示例是循序渐进的,因此每一步都提供了前一步的完整解决方案。

Step 1: A Basic Starting Point

  • Exercise 1 - Building a Basic Project
  • Exercise 2 - Specifying the C++ Standard
  • Exercise 3 - Adding a Version Number and Configured Header File

Step 2: Adding a Library

  • Exercise 1 - Creating a Library
  • Exercise 2 - Adding an Option

Step 3: Adding Usage Requirements for a Library

  • Exercise 1 - Adding Usage Requirements for a Library
  • Exercise 2 - Setting the C++ Standard with Interface Libraries

Step 4: Adding Generator Expressions

  • Exercise 1 - Adding Compiler Warning Flags with Generator Expressions

Step 5: Installing and Testing

  • Exercise 1 - Install Rules
  • Exercise 2 - Testing Support

Step 6: Adding Support for a Testing Dashboard

  • Exercise 1 - Send Results to a Testing Dashboard

Step 7: Adding System Introspection

  • Exercise 1 - Assessing Dependency Availability

Step 8: Adding a Custom Command and Generated File

Step 9: Packaging an Installer

Step 10: Selecting Static or Shared Libraries

Step 11: Adding Export Configuration

Step 12: Packaging Debug and Release

3 Step 7: Adding System Introspection

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 函数的代码。当然,几乎每个平台都有这些函数,但本教程假设它们并不常见。

3.1 Exercise 1 - Assessing Dependency Availability

3.1.1 目标

Change implementation based on available system dependencies.
根据现有的系统依赖关系改变实现方式。

3.1.2 Helpful Resources(有用的资源)

  • CheckCXXSourceCompiles
  • target_compile_definitions()

3.1.3 Files to Edit(需编辑的文件)

  • MathFunctions/CMakeLists.txt
  • MathFunctions/mysqrt.cxx

3.1.4 Getting Started(入门指南)

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 是否提供 logexp。如果可用,则使用 target_compile_definitions() 将 HAVE_LOGHAVE_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。然后,如果系统有 logexp,则使用它们计算平方根。

3.1.5 Build and Run(构建并运行)

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 哪个函数的结果更好?

3.1.6 解决方案

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_LOGHAVE_EXP 表示这些依赖关系是否可用。

TODO 2: Click to show/hide answer

TODO 2: 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)

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 变量传递给我们的源代码。这样,我们的源代码就能知道哪些资源可用。如果 logexp 都可用,请使用 target_compile_definitions() 将 HAVE_LOGHAVE_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.
由于我们可能会使用 logexp,因此需要修改 mysqrt.cxx 以包含 cmath

TODO 4: Click to show/hide answer

TODO 4: MathFunctions/mysqrt.cxx
#include <cmath>
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

3.1.7 MathFunctions/CMakeLists.txt

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 <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)

  # 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)

3.1.8 MathFunctions/mysqrt.cxx

#include "mysqrt.h"

#include <iostream>
#include <cmath>

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;
}
}
}

3.1.9 编译和运行结果

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$
  • 43
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 74
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 74
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值