• CMake Tutorial 巡礼(6)_添加自定义命令并生成文件


    CMake Tutorial 巡礼(6)_ 添加自定义命令并生成文件

    这是本系列的第七篇。
    上一篇我们学习了如何添加系统自察。这一篇我们来学习如何添加自定义命令并生成文件。

    本章导读

    在这里插入图片描述

    第六步 添加自定义命令并生成文件

    Suppose, for the purpose of this tutorial, we decide that we never want to use the platform log and exp functions and instead would like to generate a table of precomputed values to use in the mysqrt function. In this section, we will create the table as part of the build process, and then compile that table into our application.

    出于本教程的目的,假如我们决定,不使用平台提供的logexp函数,而是生成一个预计算好的表,来用于mysqrt函数的计算。在本篇中,我们将会创建这个表,作为编译过程的一部分,然后将这个表编译进我们的应用中去。

    First, let’s remove the check for the log and exp functions in MathFunctions/CMakeLists.txt. Then remove the check for HAVE_LOG and HAVE_EXP from mysqrt.cxx. At the same time, we can remove #include .

    首先,让我们移除MathFunctions/CMakeLists.txt中的logexp函数。接着移除mysqrt.cxx文件中的HAVE_LOGHAVE_EXP的检查。与此同时,我们也可以移除#include

    小白按:带大家一起看看删除这两部分之后的这两个文件代码如何:
    MathFunctions/CMakeLists.txt

    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}
              )
    
    # install rules
    install(TARGETS MathFunctions DESTINATION lib)
    install(FILES MathFunctions.h DESTINATION include)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    mysqrt.cxx

    #include   
    
    #include "MathFunctions.h" 
    // a hack square root calculation using simple operations
    double mysqrt(double x)
    {
      if (x <= 0) {
        return 0;
      } 
    
      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;
      } 
    
      return result;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    In the MathFunctions subdirectory, a new source file named MakeTable.cxx has been provided to generate the table.

    MathFunctions子目录下,已经新建一个名为MakeTable.cxx的源文件来生成表。

    After reviewing the file, we can see that the table is produced as valid C++ code and that the output filename is passed in as an argument.

    重新审视这个文件,我们可以看到这张表是以合法C++代码的形式生成的,并且输出文件作为一个变量传递。

    小白按:看一下这个MakeTable.cxx文件的内容

    // A simple program that builds a sqrt table
    #include 
    #include 
    #include   
    
    int main(int argc, char* argv[])
    {
      // make sure we have enough arguments
      if (argc < 2) {
        return 1;
      }  
    
      std::ofstream fout(argv[1], std::ios_base::out);
      const bool fileOpen = fout.is_open();
      if (fileOpen) {
        fout << "double sqrtTable[] = {" << std::endl;
        for (int i = 0; i < 10; ++i) {
          fout << sqrt(static_cast<double>(i)) << "," << std::endl;
        }
        // close the table with a zero
        fout << "0};" << std::endl;
        fout.close();
      }
      return fileOpen ? 0 : 1; // return 0 if wrote the file
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    通读代码,我们可以看出它是对[0,10)区间内的整数求取了平方根,当然实际上还是用了系统的sqrt函数。然后将这些值写进了文件名为argv[1]的文件。在MathFunctions/CMakeLists.txt中,将会使用调用语句来执行这个代码对应的可执行文件,并向其传递argv[1],对于本例来说,当然就是MathFunctions二进制目录下的Table.h

    The next step is to add the appropriate commands to the MathFunctions/CMakeLists.txt file to build the MakeTable executable and then run it as part of the build process. A few commands are needed to accomplish this.

    下一步就是向MathFunctions/CMakeLists.txt文件中添加合适的命令来建立MakeTable可执行文件,然后执行它,将这个执行的过程当作编译过程的一部分。需要用几行命令来实现。

    First, at the top of MathFunctions/CMakeLists.txt, the executable for MakeTable is added as any other executable would be added.

    首先,在MathFunctions/CMakeLists.txt的顶部,向添加其他任意的文件一样,添加MakeTable的可执行文件。

    MathFunctions/CMakeLists.txt

    add_executable(MakeTable MakeTable.cxx)
    
    • 1

    Then we add a custom command that specifies how to produce Table.h by running MakeTable.

    然后我们添加一条自定义命令,指定如何通过运行MakeTable的方式生成Table.h

    MathFunctions/CMakeLists.txt

    add_custom_command(
      OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
      COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
      DEPENDS MakeTable
      )
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Next we have to let CMake know that mysqrt.cxx depends on the generated file Table.h. This is done by adding the generated Table.h to the list of sources for the library MathFunctions.

    接下来我们必须让CMake知道mysqrt.cxx是依赖于生成的文件Table.h之上的。这通过向MathFunctions库中的源码列表添加已生成的Table.h来实现。

    MathFunctions/CMakeLists.txt

    add_library(MathFunctions
                mysqrt.cxx
                ${CMAKE_CURRENT_BINARY_DIR}/Table.h
                )
    
    • 1
    • 2
    • 3
    • 4

    We also have to add the current binary directory to the list of include directories so that Table.h can be found and included by mysqrt.cxx.

    我们同时也不得不把当前的二进制目录添加进包含路径中,这样Table.h才能够被mysqrt.cxx所发现并包含。

    MathFunctions/CMakeLists.txt

    target_include_directories(MathFunctions
              INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
              PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
              )
    
    • 1
    • 2
    • 3
    • 4

    小白按:修改完成后,展示一下最终的MathFunctions/CMakeLists.txt

    add_executable(MakeTable MakeTable.cxx)
    add_custom_command(
      OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
      COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
      DEPENDS MakeTable
      )
    
    add_library(MathFunctions
                mysqrt.cxx
                ${CMAKE_CURRENT_BINARY_DIR}/Table.h
                )
    
    # 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}
              PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
              )
    
    # install rules
    install(TARGETS MathFunctions DESTINATION lib)
    install(FILES MathFunctions.h DESTINATION include)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    Now let’s use the generated table. First, modify mysqrt.cxx to include Table.h. Next, we can rewrite the mysqrt function to use the table:

    现在让我们来使用生成的表。首先,修改mysqrt.cxx来包含Table.h。接下来,我们可以重写mysqrt函数来使用表:
    MathFunctions/mysqrt.cxx

    double mysqrt(double x)
    {
      if (x <= 0) {
        return 0;
      }
    
      // use the table to help find an initial value
      double result = x;
      if (x >= 1 && x < 10) {
        std::cout << "Use the table to help find an initial value " << std::endl;
        result = sqrtTable[static_cast<int>(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;
      }
    
      return result;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    小白按: 尽管没什么必要,小白还是展示一下完整的该文件

    #include 
    #include "Table.h"
    #include "MathFunctions.h"  
    
    double mysqrt(double x)
    {
      if (x <= 0) {
        return 0;
      }  
    
      // use the table to help find an initial value
      double result = x;
      if (x >= 1 && x < 10) {
        std::cout << "Use the table to help find an initial value " << std::endl;
        result = sqrtTable[static_cast<int>(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;
      }
    
      return result;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    Run the cmake executable or the cmake-gui to configure the project and then build it with your chosen build tool.

    运行 cmake 可执行文件或 cmake-gui来指定项目,然后用你选定的工具来进行编译。

    When this project is built it will first build the MakeTable executable. It will then run MakeTable to produce Table.h. Finally, it will compile mysqrt.cxx which includes Table.h to produce the MathFunctions library.

    当这个项目编译时,它首先生成MakeTable可执行文件。然后它会运行这个MakeTable来创建Table.h。最后,它将会编译包含了Table.hmysqrt.cxx来生成MathFunctions库。

    Run the Tutorial executable and verify that it is using the table.

    运行Tutorial 可执行文件,验证它使用了这个表。

    小白按:编译过程省略,没有什么坑点。编译完以后你可以在/Step6_build/MathFunctions找到Table.h文件,向大家展示一下这个文件的内容:
    Table.h

    double sqrtTable[] = {
    0,
    1,
    1.41421,
    1.73205,
    2,
    2.23607,
    2.44949,
    2.64575,
    2.82843,
    3,
    0};
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    进入编译好的debug文件夹执行一下看看:

    Tutorial 7.2
    Use the table to help find an initial value
    Computing sqrt of 7.2 to be 2.68355
    Computing sqrt of 7.2 to be 2.68328
    Computing sqrt of 7.2 to be 2.68328
    Computing sqrt of 7.2 to be 2.68328
    Computing sqrt of 7.2 to be 2.68328
    Computing sqrt of 7.2 to be 2.68328
    Computing sqrt of 7.2 to be 2.68328
    Computing sqrt of 7.2 to be 2.68328
    Computing sqrt of 7.2 to be 2.68328
    Computing sqrt of 7.2 to be 2.68328
    The square root of 7.2 is 2.68328
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    其实这个算法还是沿用了之前编写的那个逻辑,只是对于[0,10)范围内的值给定了一个迭代的初始值。作为对比,我们来看一看已经学习过的第2步中的函数运行的结果:

    Tutorial 7.2
    Computing sqrt of 7.2 to be 4.1
    Computing sqrt of 7.2 to be 2.92805
    Computing sqrt of 7.2 to be 2.69351
    Computing sqrt of 7.2 to be 2.6833
    Computing sqrt of 7.2 to be 2.68328
    Computing sqrt of 7.2 to be 2.68328
    Computing sqrt of 7.2 to be 2.68328
    Computing sqrt of 7.2 to be 2.68328
    Computing sqrt of 7.2 to be 2.68328
    Computing sqrt of 7.2 to be 2.68328
    The square root of 7.2 is 2.68328
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    下一篇我们将学习如何打包一个安装文件。

    【水平所限,错漏难免,创作不易,轻喷勿骂】

    在这里插入图片描述

  • 相关阅读:
    Python 全栈打造某宝客微信机器人
    Windows客户端下pycharm配置跳板机连接内网服务器
    Apache DolphinScheduler 入门(一篇就够了)
    用于大规模 MIMO 检测的近似消息传递 (AMP)(Matlab代码实现)
    Day36PHPcookie和session
    CSS 常见属性设置
    Linux0.12内核源码解读(2)-Bootsect.S
    【大数据面试题】024 Spark 3 升级了些什么?
    JAVA计算机毕业设计自行车在线租赁管理系统2021Mybatis+系统+数据库+调试部署
    python实例 - 猜数字游戏
  • 原文地址:https://blog.csdn.net/horsee/article/details/126825960