【译】CMake-Tutorial

By | 2019年1月28日

CMake Tutorial

Step1:起点

在编程中,最简单的项目就是:用几个源代码文件编译出一个可执行文件的项目。本教程就从这里开始。要编译这样的项目,在CMakeLists.txt里面写如下两行就够了:

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

CMake指令大小写均可,这里全用小写。

我们要编译的cxx文件将实现一个计算数字平方根的功能,代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
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;
}

添加版本号、配置头文件

这里将为生成的可执行文件添加版本号。在CMake中添加版本号要比直接写在代码里面更灵活一些。添加版本号后的CMake代码如下:

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

# 将要被include的文件的搜索路径添加进binary tree。这个
# PROJECT_BINARY_DIR 是一个CMake自带的常量,在CMake中,
# 使用${}取变量。 
include_directories("${PROJECT_BINARY_DIR}")

# 设置可执行文件,将使用tutorial.cxx编译出Tutorial
add_executable(Tutorial tutorial.cxx)

Binary tree

(不知道该不该翻译为二叉树,直觉觉得不太合适)

Binary tree是一个目录(有层次结构,即hierarchy),CMake用它来存储CMake生成的文件和本地构建工具(native build tool)产生的临时文件

接下来创建一个上面代码中提到的TutorialConfig.h.in文件,文件内容如下:

// 为Tutorial文件配置的选项和设置
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@

补充:.h.in文件会被autoconf解析并基于该文件的内容生成.h文件。autoconf会将@…@中间的变量替换为真正的值后生成.h文件。

当CMake配置这个头文件的时候,CMake将会用写在CMakekLists.txt中的值替换@Tutorial_VERSION_MAJOR@ 和 @Tutorial_VERSION_MINOR@这两个东西。

现在可以在tutorial.cxx中加几行,把配置的头文件包含进去,加上版本号。改完的代码如下:

// 计算一个数字的平方根,现在这个程序可以在 usage message 后面输出版本号了
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#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;
}

Step2:添加库

此步骤中将添加自定义库,这个库将包含我们自己实现的平方根算法,用于替换编译器提供的标准库函数。

代码位于 {项目目录}/MathFunctions/mysqrt.cxx

要把这个代码作为一个库添加,需要修改CMakeLists.txt,下面是改完的CMakeLists.txt的最上面几行:

include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions") #添加自定义库的目录
add_subdirectory (MathFunctions) 

# 添加可执行文件
add_executable (Tutorial tutorial.cxx)
target_link_libraries (Tutorial MathFunctions)  # 把我们自己的库链接到Tutorial上

显然,想要使用这个程序计算一个数字的平方根,并不一定需要用我们自己的算法实现——也许用户希望用编译器的实现,也许用户想用其他的第三方实现。因此我们需要把这个库设置成“可选”的(optional),首先要在CMakeLists.txt中添加这么一行:

# 是否要用我们自己的数学函数?
option (USE_MYMATH 
        "Use tutorial provided math implementation" ON) 

接下来要为MathFunctions库的编译添加附加条件,将项目根目录中的CMakeLists.txt改成下面这样:

# 是否要用我们自己的数学函数?
#
if (USE_MYMATH)
  include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions")
  add_subdirectory (MathFunctions)
  set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)

# 添加可执行文件
add_executable (Tutorial tutorial.cxx)
target_link_libraries (Tutorial  ${EXTRA_LIBS})

USE_MYMATH用来指明是否需要编译和使用MathFunctions。

// 计算一个数字的平方根
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#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;
}

在C++代码中也使用USE_MYMATH,要通过TutorialConfig.h.in从cmake加入到源代码中。在代码中添加这么一行:

#cmakedefine USE_MYMATH

Step3:安装和测试

设置和安装库以及头文件(添加到MathFunctions的CMakeLists.txt中):

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

根目录的头文件中添加以下几行,以安装可执行文件并配置头文件:

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

至此,可以使用make install来安装程序了。

在代码根目录的CMakeLists.txt文件中,可以加一些测试样例来验证程序是否可以正常工作

include(CTest)

# does the application run
add_test (TutorialRuns Tutorial 25)
# does it sqrt of 25
add_test (TutorialComp25 Tutorial 25)
set_tests_properties (TutorialComp25 PROPERTIES PASS_REGULAR_EXPRESSION "25 is 5")
# does it handle negative numbers
add_test (TutorialNegative Tutorial -25)
set_tests_properties (TutorialNegative PROPERTIES PASS_REGULAR_EXPRESSION "-25 is 0")
# does it handle small numbers
add_test (TutorialSmall Tutorial 0.0001)
set_tests_properties (TutorialSmall PROPERTIES PASS_REGULAR_EXPRESSION "0.0001 is 0.01")
# does the usage message work?
add_test (TutorialUsage Tutorial)
set_tests_properties (TutorialUsage PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number")

完成编译后,可以使用“ctest”命令来进行测试。还可以使用宏来进行更加复杂的测试。

点击量:388

发表评论

邮箱地址不会被公开。 必填项已用*标注