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

2018-02-03 10:18:51来源:https://juejin.im/post/5a72775d6fb9a01cac187e96作者:稀土掘金人点击

分享

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



下边,我们将创建一个预先计算的平方根表作为构建过程的一部分,程序可以通过查询这个表来输出对应的数值,然后将该表编译到我们的应用程序中。为了实现这一点,我们首先需要一个生成该表的程序。在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系统构建的强大功能,一次编写到处运行,我们忍一忍吧。


最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台