cmake使用教程(四)-文件生成器

13,686 阅读3分钟

【cmake系列使用教程】

cmake使用教程(一)-起步

cmake使用教程(二)-添加库

cmake使用教程(三)-安装、测试、系统自检

cmake使用教程(四)-文件生成器

cmake使用教程(五)-cpack生成安装包

cmake使用教程(六)-蛋疼的语法

cmake使用教程(七)-流程和循环

cmake使用教程(八)-macro和function

这个系列的文章翻译自官方cmake教程:cmake tutorial

示例程序地址:github.com/rangaofei/t…

不会仅仅停留在官方教程。本人作为一个安卓开发者,实在是没有linux c程序开发经验,望大佬们海涵。教程是在macos下完成,大部分linux我也测试过,有特殊说明的我会标注出来。本教程基于cmake-3.10.2,同时认为你已经安装好cmake。

有时候我们的文件不是一开始就编写好的,而是通过在编译过程中来生成文件比如某个日志,构建时间等,等文件生成后我们需要将这个文件再添加到应用程序的构建过程中。

下边,我们将创建一个预先计算的平方根表作为构建过程的一部分,程序可以通过查询这个表来输出对应的数值,然后将该表编译到我们的应用程序中。为了实现这一点,我们首先需要一个生成该表的程序。在mathfunction子目录中,新建一个文件,名称为MakeTable.cxx,内容如下:

// A simple program that builds a sqrt table 
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
 
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<double>(i));
    fprintf(fout,"%g,\n",result);
    }
 
  // close the table with a zero
  fprintf(fout,"0};\n");
  fclose(fout);
  return 0;
}

注意,该表是作为有效的c++代码生成的,输出的文件名称是以参数形式传入的。下一步是将合适的命令添加到mathfunction的CMakeLists.txt文件中来构建MakeTable的可执行文件,然后将其作为构建过程的一部分运行。添加如下命令:

# first we add the executable that generates the table
add_executable(MakeTable MakeTable.cxx)
 
# add the command to generate the source code
add_custom_command (
  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
  COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
  DEPENDS MakeTable
  )
 
# 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  )

首先,add_executable(MakeTable MakeTable.cxx)添加了MakeTable这个可执行文件。然后我们添加一个自定义命令来指定通过运行MakeTable来生成平方根表(Table.h),注意add_custom_command的第二个参数COMMAND,相当于执行MakeTable并传入参数${CMAKE_CURRENT_BINARY_DIR}/Table.h。接下来我们要让CMake知道mysqrt.cxx依赖于生成的文件表(Table.h)。这是通过添加生成的Table.h文件到MathFunctions库来实现的。我们还必须将当前的二进制目录添加到包含目录的列表中,因为生成的表在二进制目录中,这样库就可以找到并包含在mysqrt.cxx中。当这个项目被构建时,它将首先构建MakeTable可执行文件。然后它将运行MakeTable命令生成Table.h文件。最后,它将编译mysqrt.cxx和table.h生成mathfunction库。

根目录下的的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.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
 
// does the platform provide exp and log functions?
#cmakedefine HAVE_LOG
#cmakedefine HAVE_EXP

MathFunction文件夹下的CMakeLists.txt文件内容如下:

# first we add the executable that generates the table
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)

完整的文件结构

 ~/Desktop/Tutorial/Step5/ tree -L 2
.
├── CMakeLists.txt
├── MathFunctions
│   ├── CMakeLists.txt
│   ├── MakeTable.cxx
│   ├── MathFunctions.h
│   └── mysqrt.cxx
├── TutorialConfig.h.in
├── build
└── tutorial.cxx

然后执行外部构建命令(第六个教程里有说明如何外部构建):

mkdir build
cd build
cmake ..
make

构建成功后,我们预期会在二进制文件夹中的MathFunction中生成一个Table.h文件,并且文件内容是一个简单的平方根表。

来看一下结果:

 ~/Desktop/Tutorial/Step5/ tree -L 3 -I CMakeFiles
.
├── CMakeLists.txt
├── c
│   ├── CMakeLists.txt
│   ├── MakeTable.cxx
│   ├── MathFunctions.h
│   └── mysqrt.cxx
├── TutorialConfig.h.in
├── build
│   ├── CMakeCache.txt
│   ├── CTestTestfile.cmake
│   ├── Makefile
│   ├── MathFunctions
│   │   ├── MakeTable
│   │   ├── Makefile
│   │   ├── Table.h
│   │   ├── cmake_install.cmake
│   │   └── libMathFunctions.a
│   ├── Tutorial
│   ├── TutorialConfig.h
│   └── cmake_install.cmake
└── tutorial.cxx

可以看到,确实有这个表。 然后看一下表的内容是不是0-9的平方根且最后以0结束,执行命令:

 ~/Desktop/Tutorial/Step5/ cat build/MathFunctions/Table.h 
double sqrtTable[] = {
0,
1,
1.41421,
1.73205,
2,
2.23607,
2.44949,
2.64575,
2.82843,
3,
0};

结果正确。这种构建方式增加了蛋疼的操作,获取用python脚本或者shell脚本更容易生成,但是为了展示cmake系统构建的强大功能,一次编写到处运行,我们忍一忍吧。