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

本篇博客介绍了如何在CMake中添加自定义命令,生成一个预计算的平方根表格文件,并将其整合到编译过程中。首先移除了对系统log和exp函数的检测,然后通过MakeTable.cxx生成Table.h,这个表格在编译时被用来初始化mysqrt函数的迭代。CMakeLists.txt经过相应修改,添加了生成和使用表格的步骤。最终,编译完成的程序在计算平方根时会利用生成的表格提高效率。
摘要由CSDN通过智能技术生成

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 <cmath>.

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

小白按:带大家一起看看删除这两部分之后的这两个文件代码如何:
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)

mysqrt.cxx

#include <iostream>  

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

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 <cmath>
#include <fstream>
#include <iostream>  

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
}

通读代码,我们可以看出它是对[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)

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
  )

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
            )

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

小白按:修改完成后,展示一下最终的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)

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

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

#include <iostream>
#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;
}

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

进入编译好的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

其实这个算法还是沿用了之前编写的那个逻辑,只是对于[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

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

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

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值