当前位置: 首页 > news >正文

CMake Tutorial 巡礼(2)_添加库

CMake Tutorial 巡礼(2)_ 添加库

这是本系列的第三篇。
上一篇,我们学习了CMake的一些基本操作,包括如何搭建编译系统、如何添加版本号及头文件、如何指定C++标准等等。
我们在日常构建项目的过程中,用于项目组织的代码可能不止一个,这就引入了库的概念,本篇就来学习一下如何在CMake中添加库。

本章导读

在这里插入图片描述

第二步:添加库

Now we will add a library to our project. This library will contain our own implementation for computing the square root of a number. The executable can then use this library instead of the standard square root function provided by the compiler.

现在我们将会在项目中添加一个库。这个库将包含我们自己对计算一个数的平方根的实现。可执行文件将可以调用这个库,而不是由编译器提供的标准平方根函数。

For this tutorial we will put the library into a subdirectory called MathFunctions. This directory already contains a header file, MathFunctions.h, and a source file mysqrt.cxx. The source file has one function called mysqrt that provides similar functionality to the compiler’s sqrt function.

在tutorial中我们将会把这个库放到一个名为MathFunctions的子路径下。这个路径已经包含有一个头文件,即MathFunctions.h,以及一个源文件mysqrt.cxx。这个源文件包含一个名为mysqrt的函数,提供了和编译器的sqrt函数类似的功能。

小白按:原始的MathFunctions.hmysqrt.cxx文件内容如下所示:

MathFunctions.h

double mysqrt(double x);

mysqrt.cxx

#include <iostream> 

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

Add the following one line CMakeLists.txt file to the MathFunctions directory:

添加以下行到MathFunctions路径下的CMakeLists.txt文件中:

MathFunctions/CMakeLists.txt

add_library(MathFunctions mysqrt.cxx)

To make use of the new library we will add an add_subdirectory() call in the top-level CMakeLists.txt file so that the library will get built. We add the new library to the executable, and add MathFunctions as an include directory so that the MathFunctions.h header file can be found. The last few lines of the top-level CMakeLists.txt file should now look like:

为了使用新的库,我们将会在顶层的CMakeLists.txt文件中添加一个add_subdirectory()调用, 这样库就可以被编译。我们将新库添加到可执行中去,并且添加MathFunctions为一个包含目录,于是MathFunctions.h头文件就可以被找到。顶层路径的CMakeLists.txt文件的最后几行应该被改成如下形式:

CMakeLists.txt

# add the MathFunctions library 添加数学函数库
add_subdirectory(MathFunctions)

# add the executable 添加可执行文件
add_executable(Tutorial tutorial.cxx)

target_link_libraries(Tutorial PUBLIC MathFunctions)

# add the binary tree to the search path for include files 为包含文件向搜索路径中添加二进制树
# so that we will find TutorialConfig.h 这样我们才能找得到TutorialConfig.h头文件
target_include_directories(Tutorial PUBLIC
                          "${PROJECT_BINARY_DIR}"
                          "${PROJECT_SOURCE_DIR}/MathFunctions"
                          )

Now let us make the MathFunctions library optional. While for the tutorial there really isn’t any need to do so, for larger projects this is a common occurrence. The first step is to add an option to the top-level CMakeLists.txt file.

现在让我们把MathFunctions目录变成可选。尽管对于tutorial来说没有任何必要这样做,但对于大型项目来说这是一个常规操作。第一步就是在顶层的CMakeLists.txt文件中添加一个选项。

CMakeLists.txt

option(USE_MYMATH "Use tutorial provided math implementation" ON)

# configure a header file to pass some of the CMake settings 指定一个头文件来向源代码中传递一些CMake设置
# to the source code
configure_file(TutorialConfig.h.in TutorialConfig.h)

This option will be displayed in the cmake-gui and ccmake with a default value of ON that can be changed by the user. This setting will be stored in the cache so that the user does not need to set the value each time they run CMake on a build directory.

这个选项将会显示在 cmake-gui以及 ccmake 中,以一个默认值为ON、可以由用户进行修改的形式出现。这个设置将会保存在缓存中,这样当用户在编译目录下运行CMake时,不需要每次都对它进行设置。

The next change is to make building and linking the MathFunctions library conditional. To do this, we will create an if statement which checks the value of the option. Inside the if block, put the add_subdirectory() command from above with some additional list commands to store information needed to link to the library and add the subdirectory as an include directory in the Tutorial target. The end of the top-level CMakeLists.txt file will now look like the following:

另一处修改是让编译和链接到MathFunctions库的操作变成有条件的。为了实现这个目标,我们将会创建一个检查这个选项的if声明。在if块之内,需要将上面提到的add_subdirectory()命令移动到此,并且追加一些添加信息的命令,这些命令需要链接到库,并且在Tutorial目标中添加一个子目录到包含目录中去。顶层的CMakeLists.txt文件末尾将会看起来如下所示:

CMakeLists.txt

if(USE_MYMATH)
  add_subdirectory(MathFunctions)
  list(APPEND EXTRA_LIBS MathFunctions)
  list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
endif()

# add the executable 添加可执行文件
add_executable(Tutorial tutorial.cxx)

target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})

# add the binary tree to the search path for include files 为包含文件向搜索路径中添加二进制树
# so that we will find TutorialConfig.h 这样我们才能找得到TutorialConfig.h头文件。
target_include_directories(Tutorial PUBLIC
                           "${PROJECT_BINARY_DIR}"
                           ${EXTRA_INCLUDES}
                           )

Note the use of the variable EXTRA_LIBS to collect up any optional libraries to later be linked into the executable. The variable EXTRA_INCLUDES is used similarly for optional header files. This is a classic approach when dealing with many optional components, we will cover the modern approach in the next step.

请注意,使用变量EXTRA_LIBS收集任何的可选库,以便稍后链接到可执行文件中。变量EXTRA_INCLUDES类似地用于可选头文件。这是处理许多可选组件时的经典方法,我们将在下一步中介绍现代方法。

The corresponding changes to the source code are fairly straightforward. First, in tutorial.cxx, include the MathFunctions.h header if we need it:

对源代码的相应修改相当直接。首先,在tutorial.cxx中,如果需要的话,请包含MathFunction.h头文件:

tutorial.cxx

#ifdef USE_MYMATH
#  include "MathFunctions.h"
#endif

接着,在同一个文件里,设置USE_MYMATH控制什么情况下会使用什么版本的平方根函数:

tutorial.cxx

#ifdef USE_MYMATH
  const double outputValue = mysqrt(inputValue);
#else
  const double outputValue = sqrt(inputValue);
#endif

Since the source code now requires USE_MYMATH we can add it to TutorialConfig.h.in with the following line:

由于源代码现在需要USE_MYMATH,我们可以使用以下行将其添加到TutorialConfig.h.in文件中去:

TutorialConfig.h.in

#cmakedefine USE_MYMATH

小白按:最终改造后,各个文件的内容分别是:
CMakeLists.txt

cmake_minimum_required(VERSION 3.10)

# set the project name and version
project(Tutorial VERSION 1.0)

# specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

option(USE_MYMATH "Use tutorial provided math implementation" ON)

# configure a header file to pass some of the CMake settings
# to the source code
configure_file(TutorialConfig.h.in TutorialConfig.h)

if (USE_MYMATH)
    #add the MathFunctions library
    add_subdirectory(MathFunctions)
    list(APPEND EXTRA_LIBS MathFunctions)
    list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
endif()

# add the executable
add_executable(Tutorial tutorial.cxx)

target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})

# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
target_include_directories(Tutorial PUBLIC
                           "${PROJECT_BINARY_DIR}"
                           ${EXTRA_INCLUDES}
                           )

tutorial.cxx

// A simple program that computes the square root of a number
#include <cmath>
#include <iostream>
#include <string>  

#include "TutorialConfig.h"
#ifdef USE_MYMATH
#    include "MathFunctions.h"
#endif
 
int main(int argc, char* argv[])
{
  if (argc < 2) {
    // report version
    std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
              << Tutorial_VERSION_MINOR << std::endl;
    std::cout << "Usage: " << argv[0] << " number" << std::endl;
    return 1;
  }
  
  // convert input to double
  const double inputValue = std::stod(argv[1]);
 
  // calculate square root
#ifdef USE_MYMATH
  const double outputValue = mysqrt(inputValue);
#else
  const double outputValue = sqrt(inputValue);
#endif
  std::cout << "The square root of " << inputValue << " is " << outputValue
            << std::endl;
  return 0;
}

TutorialConfig.h.in

// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
#cmakedefine USE_MYMATH

Exercise: Why is it important that we configure TutorialConfig.h.in after the option for USE_MYMATH? What would happen if we inverted the two?

【练习】为什么在USE_MYMATH选项之后再配置TutorialConfig.h.in是很重要的?如果把这二者的顺序对调,会发生什么?

小白按:因为TutorialConfg.h.in中使用了USE_MYMATH变量,如果对调二者顺序,则会出现未定义错误。

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

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

Now let’s update the value of USE_MYMATH. The easiest way is to use the cmake-gui or ccmake if you’re in the terminal. Or, alternatively, if you want to change the option from the command-line, try:

现在让我们来更新USE_MYMATH的值,最简单的办法是使用 cmake-gui ,或者如果你使用终端环境的话可以直接使用cmake。也或者,如果你想要在命令行中修改这个选项,尝试:

cmake ../Step2 -DUSE_MYMATH=OFF

Rebuild and run the tutorial again.

重新编译并运行tutorial.exe。

Which function gives better results, sqrt or mysqrt?

哪种函数给出了更好的结果,sqrt还是mysqrt

小白按:与上一篇中采用相同的测试数,得到的结果为:

Computing sqrt of 4.29497e+09 to be 2.14748e+09
Computing sqrt of 4.29497e+09 to be 1.07374e+09
Computing sqrt of 4.29497e+09 to be 5.36871e+08
Computing sqrt of 4.29497e+09 to be 2.68435e+08
Computing sqrt of 4.29497e+09 to be 1.34218e+08
Computing sqrt of 4.29497e+09 to be 6.71089e+07
Computing sqrt of 4.29497e+09 to be 3.35545e+07
Computing sqrt of 4.29497e+09 to be 1.67773e+07
Computing sqrt of 4.29497e+09 to be 8.38878e+06
Computing sqrt of 4.29497e+09 to be 4.19465e+06
The square root of 4.29497e+09 is 4.19465e+06
Computing sqrt of 10 to be 5.5
Computing sqrt of 10 to be 3.65909
Computing sqrt of 10 to be 3.19601
Computing sqrt of 10 to be 3.16246
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
Computing sqrt of 10 to be 3.16228
The square root of 10 is 3.16228
Tutorial Version 1.0
Usage: Tutorial number

显然,sqrt得到了更高精度的结果,对于大数的开方运算,甚至得到了错误的答案,这是因为mysqrt中使用的方法只迭代了10次,远远达不到需要的精度。

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

在这里插入图片描述

相关文章:

  • java毕业设计蛋糕店会员系统Mybatis+系统+数据库+调试部署
  • IntelliJ IDEA中构建Spring Boot的项目
  • 计算机视觉项目-实时目标追踪
  • 初始数据结构
  • Qt5开发从入门到精通——第六篇一节( 图像与图片——位置相关函数 )
  • 最新版校园招聘进大厂系列----------(5)百度篇 -----未完待续
  • 计算机网络——物理层(互联网接入技术)
  • IntegralUI Web 22.3组件
  • 细说卷积神经网络(CNN)中所谓的“感受野”(Receptive Field)
  • Python 自动化教程(5) : 自动生成Word文件
  • 2022 9.8 模拟
  • Python 页面解析:Beautiful Soup库的使用
  • 请你设计一个LRU(最近最少使用)缓存约束的数据结构
  • 国内低代码平台“定制化开发”能力较强的有哪些?
  • Python 自动化教程(4) : 自动生成PPT文件 Part 2 (干货)
  • 《Java编程思想》读书笔记-对象导论
  • css布局,左右固定中间自适应实现
  • download使用浅析
  • GitUp, 你不可错过的秀外慧中的git工具
  • js算法-归并排序(merge_sort)
  • node-glob通配符
  • Vue UI框架库开发介绍
  • webpack+react项目初体验——记录我的webpack环境配置
  • 半理解系列--Promise的进化史
  • 纯 javascript 半自动式下滑一定高度,导航栏固定
  • 从零开始在ubuntu上搭建node开发环境
  • 码农张的Bug人生 - 初来乍到
  • 前端每日实战:61# 视频演示如何用纯 CSS 创作一只咖啡壶
  • 如何胜任知名企业的商业数据分析师?
  • 通过几道题目学习二叉搜索树
  • 鱼骨图 - 如何绘制?
  • Oracle Portal 11g Diagnostics using Remote Diagnostic Agent (RDA) [ID 1059805.
  • 关于Android全面屏虚拟导航栏的适配总结
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • 直播平台建设千万不要忘记流媒体服务器的存在 ...
  • ​iOS实时查看App运行日志
  • ​ubuntu下安装kvm虚拟机
  • ​Z时代时尚SUV新宠:起亚赛图斯值不值得年轻人买?
  • #Z0458. 树的中心2
  • (14)目标检测_SSD训练代码基于pytorch搭建代码
  • (27)4.8 习题课
  • (C语言)fgets与fputs函数详解
  • (function(){})()的分步解析
  • (二)fiber的基本认识
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • (转载)PyTorch代码规范最佳实践和样式指南
  • *Django中的Ajax 纯js的书写样式1
  • .【机器学习】隐马尔可夫模型(Hidden Markov Model,HMM)
  • .net MVC中使用angularJs刷新页面数据列表
  • .Net+SQL Server企业应用性能优化笔记4——精确查找瓶颈
  • .NET设计模式(2):单件模式(Singleton Pattern)
  • .net通用权限框架B/S (三)--MODEL层(2)
  • .Net下使用 Geb.Video.FFMPEG 操作视频文件
  • /usr/bin/perl:bad interpreter:No such file or directory 的解决办法
  • /usr/local/nginx/logs/nginx.pid failed (2: No such file or directory)