//查看目录结构命令,1表示只看一层结构
tree -L 1
1.cmake 基础构成
//cmake最小版本
cmake_minimum_required (VERSION 2.6)
//工程名
project (Tutorial)
//生成可执行文件
add_executable(Tutorial tutorial.cxx)
2.添加子项目
//生成库文件
add_library(MathFunctions mysqrt.cxx)
//添加目录
include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions")
//添加子项目
add_subdirectory (MathFunctions)
add_executable (Tutorial tutorial.cxx)
//连接子项目
target_link_libraries (Tutorial MathFunctions)
.
├── CMakeLists.txt
├── MathFunctions
│ ├── CMakeLists.txt
│ ├── MathFunctions.h
│ └── mysqrt.cxx
├── TutorialConfig.h.in
└── tutorial.cxx
3.添加开关
根目录下CMakeLists.txt文件中添加
# should we use our own math functions?
option (USE_MYMATH "Use tutorial provided math implementation" ON)
子目录下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})
这将使用USE_MYMATH的设置来确定是否应该编译和使用mathfunction库。注意,使用一个变量(在本例中是EXTRA_LIBS)来设置可选的库,然后将它们链接到可执行文件中。这是一种常见的方法,用于保持较大的项目具有许多可选组件。
首先在Configure.h.in文件中添加以下内容:
#cmakedefine USE_MYMATH
然后我们就可以使用USE_MYMATH这个变量了,最后修改Tutorial.cxx源代码如下:
// A simple program that computes the square root of a number
#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;
}
3.安装
对于mathfunction库,我们添加了这个库,通过将以下两行添加到mathfunction的CMakeLists.txt中来安装头文件和静态库:
install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)
然后根目录下的CMakeLusts.txt文件中添加如下行,用来安装可执行文件和配置文件:
# add the install targets
install (TARGETS Tutorial DESTINATION bin)
install (FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h DESTINATION include)
//编译安装
cmake .
make
make install
注意上边install的第一个参数和第三个参数。
TARGETS包含六种形式:ARCHIVE, LIBRARY, RUNTIME, OBJECTS, FRAMEWORK, BUNDLE。注意Mathfunction安装的是LIBRARY,而根目录下的可执行文件是RUNTIME类型。
FILE 将给定的文件复制到指定目录。如果没有给定权限参数,则由该表单安装的文件默认为OWNER_WRITE、OWNER_READ、GROUP_READ和WORLD_READ。
TARGETS和FILE可指定为相对目录和绝对目录。
DESTINATION在这里是一个相对路径,取默认值。在unix系统中指向 /usr/local 在windows上c:/Program Files/${PROJECT_NAME}。
也可以通过设置CMAKE_INSTALL_PREFIX这个变量来设置安装的路径,那么安装位置不指向/usr/local,而指向你所指定的目录。
文件/库 | 安装位置 |
---|---|
MathFunctions | /usr/local/bin/ |
MathFunctions.h | /usr/local/include/ |
Tutorial | /usr/local/bin/ |
TutorialConfig.h | /usr/local/include |
4.测试
# 启用测试
enable_testing()
# 测试程序是否成功运行
add_test (test_run Demo 5 2)
# 测试帮助信息是否可以正常提示
add_test (test_usage Demo)
set_tests_properties (test_usage
PROPERTIES PASS_REGULAR_EXPRESSION "Usage: .* base exponent")
# 测试 5 的平方
add_test (test_5_2 Demo 5 2)
set_tests_properties (test_5_2
PROPERTIES PASS_REGULAR_EXPRESSION "is 25")
# 测试 10 的 5 次方
add_test (test_10_5 Demo 10 5)
set_tests_properties (test_10_5
PROPERTIES PASS_REGULAR_EXPRESSION "is 100000")
# 测试 2 的 10 次方
add_test (test_2_10 Demo 2 10)
set_tests_properties (test_2_10
PROPERTIES PASS_REGULAR_EXPRESSION "is 1024")
5.文件生成器
5.1文件生成代码MakeTable.c
// 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;
}
5.2
add_custom_command的第二个参数COMMAND,相当于执行MakeTable并传入参数${CMAKE_CURRENT_BINARY_DIR}/Table.h。
首先构建MakeTable可执行文件。然后它将运行MakeTable命令生成Table.h文件。最后,它将编译mysqrt.cxx和table.h生成mathfunction库。
# 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)
6.程序中使用Cmake的配置信息
6.1添加版本配置
# The version number.
# 添加配置key,value
set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 0)
# 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 executable
add_executable(Tutorial tutorial.cxx)
配置文件将会被写入到可执行文件目录下,所以我们的项目必须包含这个文件夹来使用这些配置头文件。我们需要在工程目录下新建一个TutorialConfig.h.in,内容如下:
// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
上面的代码中的@Tutorial_VERSION_MAJOR@和@Tutorial_VERSION_MINOR@将会被替换为CmakeLists.txt中的1和0。 然后修改Tutorial.cxx文件如下,用来在不输入额外参数的情况下输出版本信息:
// A simple program that computes the square root of a number
#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;
}
6.2测试这些函数的是否存在
# does this system provide the log and exp functions?
include (CheckFunctionExists)
check_function_exists (log HAVE_LOG)
check_function_exists (exp HAVE_EXP)
然后在TutorialConfig.h.in中添加使用上边定义的变量的代码:
// does the platform provide exp and log functions?
#cmakedefine HAVE_LOG
#cmakedefine HAVE_EXP
log和exp的测试代码一定要在TutorialConfig.h的configure_file命令之前。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
...
7.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模块,它将使用刚才定义的变量变量和系统的一些其他属性来设置安装程序。
两个生成的文件CPackConfig.cmake,CPackSourceConfig.cmake。
//CPackConfig.cmake生成二进制版本
cpack --config CPackConfig.cmake
//CPackSourceConfig.cmake生成源码版本
cpack --config CPackSourceConfig.cmake
网友评论