Ubuntu学习心得——翻译篇——CMake教程(官方文档中文版)

Ubuntu学习心得——翻译篇——CMake官方使用手册
FOR THE SIGMA
FOR THE GTINDER
FOR THE ROBOMASTER

简介:

该篇以翻译 https://cmake.org/cmake-tutorial/ 的官网文档为主,该篇配搭 https://blog.csdn.net/whl970831/article/details/97157693 教程食用更加美味。

操作系统版本:Ubuntu16.04
http://www.ubuntu.org.cn/download/desktop 桌面版ubuntu16.04 下载
http://mirror.pnl.gov/releases/xenial/ Ubuntu系列镜像文件下载列表(amd64为64位,i386为32位)

CMake版本 CMake 3.15.0
https://cmake.org/download/ 官网下载地址
https://blog.csdn.net/whl970831/article/details/97143463 安装教程
https://cmake.org/cmake-tutorial/ 文档地址

内容:

下面是一个有步骤的教程,介绍CMAKE帮助解决的常见构建系统用例。在掌握CMAKE时,已经介绍了许多这些主题作为单独的问题,但是看看它们如何在示例项目中一起工作是非常有帮助的。本教程可以在cmake源代码树的tests/tutorial目录中找到。每个步骤都有自己的子目录,其中包含该步骤教程的完整副本。

有关cmake概念和源代码结构的概述,请参阅cmake构建系统(7)和cmake语言(7)手册页的介绍部分。

基本起点(步骤1)
最基本的项目是从源代码文件构建的可执行文件。对于简单项目,只需要两三行写入cmakelists.txt文件中即可。这将是本教程的起点。cmakelists.txt文件如下:

cmake_minimum_required (VERSION 2.6)
project (Tutorial)
add_executable(Tutorial tutorial.cxx)

请注意,此示例在cmakelists.txt文件中使用小写命令。CMAKE支持upper、lower和mixed case命令。tutorial.cxx的源代码将计算一个数字的平方根,它的第一个版本非常简单,如下所示:

// 计算一个数的平方根的简单程序
#include 
#include 
#include 
int main (int argc, char *argv[])
{
  if (argc < 2)
    {
    fprintf(stdout,"Usage: %s number\n",argv[0]);
    return 1;
    }
  double inputValue = atof(argv[1]);
  double outputValue = sqrt(inputValue);
  fprintf(stdout,"The square root of %g is %g\n",
          inputValue, outputValue);
  return 0;
}

添加版本号和配置的头文件

我们将添加的第一个特性是为可执行文件和项目提供一个版本号。虽然您可以在源代码中专门这样做,但在cmakelists.txt文件中这样做可以提供更多的灵活性。要添加版本号,我们修改cmakelists.txt文件,如下所示:

cmake_minimum_required (VERSION 2.6)
project (Tutorial)
#版本号
set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 0)
 
#配置头文件以传递一些cmake设置
#到源代码
configure_file (
  "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
  "${PROJECT_BINARY_DIR}/TutorialConfig.h"
  )
 
#将二进制树添加到包含文件的搜索路径中
#这样我们就能找到tutorialconfig.h
include_directories("${PROJECT_BINARY_DIR}")
 
#添加可执行文件
add_executable(Tutorial tutorial.cxx)

由于配置的文件将写入二进制树,因此我们必须将该目录添加到搜索包含文件的路径列表中。然后,我们在源代码树中创建一个tutorialconfig.h文件,其中包含以下内容:

// 为教程配置的选项和设置
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@

当cmake配置此头文件时,@tutorial_version_major@和@tutorial_version_minor@的值将替换为cmakelists.txt文件中的值。接下来,我们修改tutorial.cxx以包含已配置的头文件并使用版本号。生成的源代码如下所示。

#include 
#include 
#include 
#include "TutorialConfig.h"
 
int main (int argc, char *argv[])
{
  if (argc < 2)
    {
    fprintf(stdout,"%s Version %d.%d\n",
            argv[0],
            Tutorial_VERSION_MAJOR,
            Tutorial_VERSION_MINOR);
    fprintf(stdout,"Usage: %s number\n",argv[0]);
    return 1;
    }
  double inputValue = atof(argv[1]);
  double outputValue = sqrt(inputValue);
  fprintf(stdout,"The square root of %g is %g\n",
          inputValue, outputValue);
  return 0;
}

主要的更改是包含tutorialconfig.h头文件,并将版本号作为使用消息的一部分打印出来。

添加库(步骤2)

现在我们将在项目中添加一个库。这个库将包含我们自己的实现,用于计算一个数的平方根。然后,可执行文件可以使用这个库,而不是编译器提供的标准平方根函数。对于本教程,我们将把库放到一个名为mathfunctions的子目录中。它将具有以下一行cmakelists.txt文件:

add_library(MathFunctions mysqrt.cxx)

源文件mysqrt.cxx有一个称为mysqrt的函数,它提供与编译器的sqrt函数类似的功能。为了利用新的库,我们在顶层cmakelists.txt文件中添加了一个add_子目录调用,以便构建库。我们还添加了另一个include目录,以便可以找到函数原型的mathfunctions/mathfunctions.h头文件。最后一个更改是将新库添加到可执行文件中。顶层cmakelists.txt文件的最后几行现在如下所示:

include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions")
add_subdirectory (MathFunctions) 
 
#添加可执行文件
add_executable (Tutorial tutorial.cxx)
target_link_libraries (Tutorial MathFunctions)

现在让我们考虑让MathFunctions库成为可选的。在本教程中,确实没有任何理由这样做,但是对于大型库或依赖第三方代码的库,您可能希望这样做。第一步是向顶层cmakelists.txt文件添加一个选项。

#我们应该使用我们自己的数学函数吗?
option (USE_MYMATH 
        "Use tutorial provided math implementation" ON) 

这将显示在cmake gui中,默认值为on,用户可以根据需要进行更改。此设置将存储在缓存中,这样用户就不必每次对此项目运行cmake时都进行设置。下一个更改是使MathFunctions库的构建和链接成为条件。为此,我们将顶级cmakelists.txt文件的结尾更改为如下所示:

#add the MathFunctions library?
if (USE_MYMATH)
  include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions")
  add_subdirectory (MathFunctions)
  set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)
 
#add the executable
add_executable (Tutorial tutorial.cxx)
target_link_libraries (Tutorial  ${EXTRA_LIBS})

这将使用“使用MyMath”的设置来确定是否应编译和使用数学函数。请注意,使用变量(在本例中是多余的库)来收集任何可选库,以便稍后链接到可执行文件中。这是一种常用的方法,用于保持具有许多可选组件的大型项目的清洁。对源代码的相应更改是相当直接的,并留给我们:

#include 
#include 
#include 
#include "TutorialConfig.h"
#ifdef USE_MYMATH
#include "MathFunctions.h"
#endif
 
int main (int argc, char *argv[])
{
  if (argc < 2)
    {
    fprintf(stdout,"%s Version %d.%d\n", argv[0],
            Tutorial_VERSION_MAJOR,
            Tutorial_VERSION_MINOR);
    fprintf(stdout,"Usage: %s number\n",argv[0]);
    return 1;
    }
 
  double inputValue = atof(argv[1]);
 
#ifdef USE_MYMATH
  double outputValue = mysqrt(inputValue);
#else
  double outputValue = sqrt(inputValue);
#endif
 
  fprintf(stdout,"The square root of %g is %g\n",
          inputValue, outputValue);
  return 0;
}

在源代码中,我们也使用了USE_MYMATH。通过将以下行添加到配置文件中的tutorialconfig.h里面,从cmake提供给源代码:

#cmakedefine USE_MYMATH

安装和测试(步骤3)

在下一步中,我们将向项目添加安装规则和测试支持。安装规则相当直截了当。对于MathFunctions库,我们通过在MathFunctions的cmakeLists.txt文件中添加以下两行来设置要安装的库和头文件:

install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)

对于应用程序,将以下行添加到顶层cmakelists.txt文件中,以安装可执行文件和配置的头文件:

#add the install targets
install (TARGETS Tutorial DESTINATION bin)
install (FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"        
         DESTINATION include)

这就是一切。此时,您应该能够构建教程,然后键入make install(或从IDE构建安装目标),它将安装适当的头文件、库和可执行文件。cmake变量 CMAKE_INSTALL_PREFIX用于确定安装文件的根目录。添加测试也是一个相当直接的过程。在顶级cmakelists.txt文件的末尾,我们可以添加一些基本测试来验证应用程序是否正常工作。

include(CTest)

#应用程序是否运行
add_test (TutorialRuns Tutorial 25)
#是25码的吗
add_test (TutorialComp25 Tutorial 25)
set_tests_properties (TutorialComp25 PROPERTIES PASS_REGULAR_EXPRESSION "25 is 5")
#它能处理负数吗
add_test (TutorialNegative Tutorial -25)
set_tests_properties (TutorialNegative PROPERTIES PASS_REGULAR_EXPRESSION "-25 is 0")
#它能处理小数字吗
add_test (TutorialSmall Tutorial 0.0001)
set_tests_properties (TutorialSmall PROPERTIES PASS_REGULAR_EXPRESSION "0.0001 is 0.01")
#使用消息有效吗?
add_test (TutorialUsage Tutorial)
set_tests_properties (TutorialUsage PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number")

在构建之后,可以运行“ctest”命令行工具来运行测试。第一个测试只是验证应用程序是否运行,是否出现故障或崩溃,以及返回值是否为零。这是CTEST测试的基本形式。接下来的几个测试都使用PASS_REGULAR_EXPRESSION测试属性来验证测试的输出是否包含某些字符串。在这种情况下,验证计算的平方根是否应该是它应该是什么,以及当提供的参数数量不正确时是否打印了使用消息。如果要添加大量测试来测试不同的输入值,可以考虑创建如下宏:

#定义宏以简化添加测试,然后使用它
macro (do_test arg result)
add_test (TutorialComp${arg} Tutorial ${arg})
set_tests_properties (TutorialComp${arg}
  PROPERTIES PASS_REGULAR_EXPRESSION ${result})
endmacro (do_test)

#做一系列基于结果的测试
do_test (25 "25 is 5")
do_test (-25 "-25 is 0")

对于每次调用do_test,都会向项目添加另一个测试,该测试的名称、输入和结果基于传递的参数。

添加系统自省(步骤4)

接下来,让我们考虑向项目中添加一些依赖于目标平台可能没有的特性的代码。对于这个示例,我们将添加一些代码,这些代码取决于目标平台是否具有日志和exp函数。当然,几乎每个平台都有这些功能,但对于本教程来说,它们并不常见。如果平台有日志,那么我们将使用它来计算mysqrt函数中的平方根。我们首先使用顶级cmakelists.txt文件中的checkfunctionexists.cmake宏测试这些函数的可用性,如下所示:

#这个系统提供日志和exp函数吗?
include (CheckFunctionExists)
check_function_exists (log HAVE_LOG)
check_function_exists (exp HAVE_EXP)

接下来,我们修改tutorialconfig.h中的参数以定义这些值(如果cmake在平台上找到这些值),如下所示:

//平台是否提供exp和log功能?
#cmakedefine HAVE_LOG
#cmakedefine HAVE_EXP

在tutorialconfig.h的configure_file命令之前完成日志和exp的测试是很重要的。configure_file命令使用cmake中的当前设置立即配置文件。最后,在mysqrt函数中,如果使用以下代码在系统上可用,我们可以提供基于log(日志)和exp的替代实现:

// if we have both log and exp then use them
#if defined (HAVE_LOG) && defined (HAVE_EXP)
  result = exp(log(x)*0.5);
#else // otherwise use an iterative approach
  . . .

添加生成的文件和生成器(步骤5)

在本节中,我们将展示如何将生成的源文件添加到应用程序的构建过程中。对于这个例子,我们将创建一个预先计算平方根的表作为构建过程的一部分,然后将该表编译到我们的应用程序中。为了实现这一点,我们首先需要一个生成表的程序。在Mathfunctions子目录中,名为maketable.cxx的新的源文件将执行此操作:

// A simple program that builds a sqrt table 
#include 
#include 
#include 

int main (int argc, char *argv[])
{
 int i;
 double result;

 // make sure we have enough arguments
 if (argc < 2)
   {
   return 1;
   }
 
 // open the output file
 FILE *fout = fopen(argv[1],"w");
 if (!fout)
   {
   return 1;
   }
 
 // create a source file with a table of square roots
 fprintf(fout,"double sqrtTable[] = {\n");
 for (i = 0; i < 10; ++i)
   {
   result = sqrt(static_cast(i));
   fprintf(fout,"%g,\n",result);
   }

 // close the table with a zero
 fprintf(fout,"0};\n");
 fclose(fout);
 return 0;
}

请注意,表是以有效C++代码生成的,并且将输出写入文件的名称作为参数传递。下一步是将适当的命令添加到MathFunctions的cmakeLists.txt文件中,以构建makeTable可执行文件,然后将其作为构建过程的一部分运行。需要一些命令来完成这一点,如下所示。

 # 首先,我们添加生成表的可执行文件
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
 )

#将二进制根目录添加到的搜索路径
#include files
include_directories( ${CMAKE_CURRENT_BINARY_DIR} )

#链接到库
add_library(MathFunctions mysqrt.cxx ${CMAKE_CURRENT_BINARY_DIR}/Table.h  )

首先添加maketable的可执行文件,就像添加其他可执行文件一样。然后我们添加一个自定义命令,指定如何通过运行maketable生成table.h。接下来,我们必须让cmake知道mysqrt.cxx依赖于生成的文件table.h。这是通过将生成的table.h添加到库数学函数的源列表中来完成的。我们还必须将当前的二进制目录添加到include目录列表中,以便mysqrt.cxx可以找到并包含该表.h。构建此项目时,它将首先构建maketable可执行文件。然后运行maketable生成table.h,最后编译mysqrt.cxx,其中包含table.h,生成mathfunctions库。此时,包含我们添加的所有功能的顶层cmakelists.txt文件如下所示:

cmake_minimum_required (VERSION 2.6)
project (Tutorial)
include(CTest)
 
# The version number.
set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 0)
 
# does this system provide the log and exp functions?
include (${CMAKE_ROOT}/Modules/CheckFunctionExists.cmake)
 
check_function_exists (log HAVE_LOG)
check_function_exists (exp HAVE_EXP)
 
# should we use our own math functions
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 (
  "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
  "${PROJECT_BINARY_DIR}/TutorialConfig.h"
  )
 
# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
include_directories ("${PROJECT_BINARY_DIR}")
 
# add the MathFunctions library?
if (USE_MYMATH)
  include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions")
  add_subdirectory (MathFunctions)
  set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)
 
# add the executable
add_executable (Tutorial tutorial.cxx)
target_link_libraries (Tutorial  ${EXTRA_LIBS})
 
# add the install targets
install (TARGETS Tutorial DESTINATION bin)
install (FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"        
         DESTINATION include)
 
# does the application run
add_test (TutorialRuns Tutorial 25)
 
# does the usage message work?
add_test (TutorialUsage Tutorial)
set_tests_properties (TutorialUsage
  PROPERTIES 
  PASS_REGULAR_EXPRESSION "Usage:.*number"
  )
 
 
#define a macro to simplify adding tests
macro (do_test arg result)
  add_test (TutorialComp${arg} Tutorial ${arg})
  set_tests_properties (TutorialComp${arg}
    PROPERTIES PASS_REGULAR_EXPRESSION ${result}
    )
endmacro (do_test)
 
# do a bunch of result based tests
do_test (4 "4 is 2")
do_test (9 "9 is 3")
do_test (5 "5 is 2.236")
do_test (7 "7 is 2.645")
do_test (25 "25 is 5")
do_test (-25 "-25 is 0")
do_test (0.0001 "0.0001 is 0.01")

tutorialconfig.h的内容:

//为教程配置的选项和设置
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
#cmakedefine USE_MYMATH
 
//平台是否提供exp和log功能?
#cmakedefine HAVE_LOG
#cmakedefine HAVE_EXP

MathFunctions的cmakeLists.txt文件的内容如下:

#首先,我们添加生成表的可执行文件
add_executable(MakeTable MakeTable.cxx)
# add the command to generate the source code
add_custom_command (
  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
  DEPENDS MakeTable
  COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
  )
# add the binary tree directory to the search path 
# for include files
include_directories( ${CMAKE_CURRENT_BINARY_DIR} )
 
# add the main library
add_library(MathFunctions mysqrt.cxx ${CMAKE_CURRENT_BINARY_DIR}/Table.h)
 
install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)

构建安装程序(步骤6)

接下来假设我们希望将项目分发给其他人,以便他们可以使用它。我们希望在各种平台上提供二进制和源代码分发。这与我们之前在安装和测试部分(步骤3)中所做的安装稍有不同,我们在这里安装了从源代码构建的二进制文件。在本例中,我们将构建支持二进制安装和包管理功能的安装包,如Cygwin、Debian、RPMS等中所示。为了实现这一点,我们将使用CPack创建平台特定的安装程序,如与CPack打包一章中所述。具体来说,我们需要在顶层cmakelists.txt文件的底部添加几行。

# build a CPack driven installer package
include (InstallRequiredSystemLibraries)
set (CPACK_RESOURCE_FILE_LICENSE  
     "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
set (CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}")
set (CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}")
include (CPack)

这就是一切。我们从包含installRequiredSystemLibraries开始。此模块将包括项目为当前平台所需的任何运行库。接下来,我们将一些cpack变量设置为存储此项目的许可证和版本信息的位置。版本信息使用了我们在本教程前面设置的变量。最后,我们还包括cpack模块,它将使用这些变量和您正在安装的系统的一些其他属性来设置安装程序。

下一步是以通常的方式构建项目,然后在其上运行cpack。要构建二进制分发,您将运行:

cpack --config CPackConfig.cmake

要创建源分布,请输入

cpack --config CPackSourceConfig.cmake

添加对仪表板的支持(步骤7)

添加对将测试结果提交到仪表板的支持非常简单。在本教程的早期步骤中,我们已经为项目定义了许多测试。我们只需要运行这些测试并将它们提交到仪表板。为了包括对仪表盘的支持,我们在顶层cmakelists.txt文件中包含了ctest模块。

# enable dashboard scripting
include (CTest

我们还创建了一个ctestconfig.cmake文件,可以在其中为仪表板指定此项目的名称。

set (CTEST_PROJECT_NAME "Tutorial")

CTest运行时将读取此文件。要创建一个简单的仪表板,您可以在项目上运行cmake,将目录更改为二进制树,然后运行ctest–d experimental。仪表板的结果将上载到Kitware的公共仪表板。

你可能感兴趣的:(Ubuntu,CMake教程,翻译)