CMAKE手册
[toc]
## CMake 用法导览
Preface : 本文是CMake官方文档CMake Tutorial ([http://www.cmake.org/cmake/help/cmake_tutorial.html](http://www.cmake.org/cmake/help/cmake_tutorial.html)) 的翻译。通过一个样例工程从简单到复杂的完善过程,文档介绍了CMake主要模块(cmake, ctest, cpack)的功能和使用环境;从中可以一窥cmake的大体形貌。正文如下:
本文下述内容是一个手把手的使用指南;它涵盖了CMake需要解决的公共构建系统的一些问题。这些主题中的许多主题已经在`Mastering CMake一书中以单独的章节被介绍过,但是通过一个样例工程看一看它们如何工作也是非常有帮助的。本指南可以在CMake源码树的Tests/Tutorial路径下找到。每一步都有它自己的子路径,其中包含该步骤的一个完整的指南。
### 1.作为基础的起始点(步骤1)
最基本的工程是一个从源代码文件中构建可执行文件的例子。对于简单工程,只要一个两行的CMakeLists文件就足够了。这将会作为我们指南的起点。这份CMakeLists文件看起来像是这样:
```
cmake_minimum_required (VERSION 2.6)
project (Tutorial)
add_executable(Tutorial tutorial.cxx)
```
注意到这个例子在CMakeLists文件中使用了小写。CMake支持大写、小写、混合大小写的命令。tutorial.cxx中的源代码用来计算一个数的平方根,并且它的第一版非常简单,如下所示:
```
// A simple program that computes the square root of a number
// 计算一个数的平方根的简单程序
#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文件中指定它可以提供更好的灵活性。如下所示,我么可以通过添加一个版本号来修改CMakeLists文件:
```
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)
```
由于配置过的文件将会被写到二进制文件目录下,我们必须把该目录添加到包含文件的搜索路径清单中。然后,以下的代码就可以在源目录下创建一份TotorialConfig.h.in文件:
```
// 与tutorial相关的配置好的选项与设置;
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
```
当CMake配置这份头文件时,@Tutorial_VERSION_MAJOR@和@Tutorial_VERSION_MINOR@的值将会被从CMakeLists文件中传递过来的值替代。下一步,我们要修改tutorial.cxx来包含configured头文件然后使用其中的版本号。修改过的源代码展列于下:
```
// 计算平方根的简单程序。
#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;
}
```
### 2.引入库(步骤2)
现在我们将会在我们的工程中引入一个库。这个库会包含我们自己实现的计算一个数的平方根的函数。可执行文件随后可以使用这个库文件而不是编译器提供的标准开平方函数。在本指南中,我们将会把库文件放到一个子目录MathFunctions中。它包含下述的单行CMakeLists文件:
```
add_library(MathFunctions mysqrt.cxx)
```
源文件mysqrt.cxx有一个叫做mysqrt的函数,它提供了与编译器的sqrt函数类似的功能。为了使用新的库,我们在顶层的CMakeLists中增加一个add_subdirectory调用,这样这个库也会被构建。我们也要向可执行文件中增加另一个头文件路径,这样就可以从MathFunctions/mysqrt.h头文件中找到函数的原型。最后的一点更改是在向可执行文件中引入新的库。顶层CMakeLists文件的最后几行现在看起来像是这样:
```
include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions")
add_subdirectory (MathFunctions)
# 引入可执行文件
add_executable (Tutorial tutorial.cxx)
target_link_libraries (Tutorial MathFunctions)
```
现在,让我们考虑下让MathFunctions库变为可选的。在本指南中,确实没有必要这样画蛇添足;但是对于更大型的库或者依赖于第三方代码的库,你可能需要这种可选择性。第一步是为顶层的CMakeLists文件添加一个选项:
```
# 我们应该使用我们自己的数学函数吗?
option (USE_MYMATH "Use tutorial provided math implementation" ON)
```
这将会在CMake的GUI中显示一个默认的ON值,并且用户可以随需改变这个设置。这个设置会被存储在cache中,那么用户将不需要在cmake该工程时,每次都设置这个选项。第二处改变是,让链接MathFunctions库变为可选的。要实现这一点,我们修改顶层CMakeLists文件的结尾部分:
```
# 添加MathFunctions库吗?
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应该被编译和执行。注意到,要用一个变量(在这里是EXTRA_LIBS)来收集所有以后会被连接到可执行文件中的可选的库。这是保持带有许多可选部件的较大型工程干净清爽的一种通用的方法。源代码对应的改变相当直白,如下所示:
```
// 计算一个数平方根的简单程序
#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。这个宏是由CMake通过TutorialConfig.h.in配置文件中的下述语句行提供给源代码的:
```
#cmakedefine USE_MYMATH
```
### 3.安装与测试(步骤3)
下一步我们会为我们的工程引入安装规则以及测试支持。安装规则相当直白,对于MathFunctions库,我们通过向MathFunctions的CMakeLists文件添加如下两条语句来设置要安装的库以及头文件:
```
install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)
```
对于应用程序,在顶层CMakeLists文件中添加下面几行,它们用来安装可执行文件以及配置头文件:
```
# 添加安装目标
install (TARGETS Tutorial DESTINATION bin)
install (FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
DESTINATION include)
```
这就是要做的全部;现在你应该可以构建tutorial工程了。然后,敲入命令make install(或者从IDE中构建INSTALL目标)然后它就会安装需要的头文件,库以及可执行文件CMake的变量CMAKE_INSTALL_PREFIX用来确定这些文件被安装的根目录。添加测试同样也只需要相当浅显的过程。在顶层CMakeLists文件的的尾部补充许多基本的测试代码来确认应用程序可以正确工作。
```
# 应用程序是否运行?
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")
```
第一个测试用例仅仅用来验证程序可以运行,没有出现段错误或其他的崩溃,并且返回值必须是0。这是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.增加系统内省(步骤4)
下一步,让我们考虑向我们的工程中引入一些依赖于目标平台上可能不具备的特性的代码。在本例中,我们会增加一些依赖于目标平台是否有log或exp函数的代码。当然,几乎每个平台都有这些函数;但是对于tutorial工程,我们假设它们并非如此普遍。如果该平台有log函数,那么我们会在mysqrt函数中使用它去计算平方根。我们首先在顶层CMakeLists文件中使用宏CheckFunctionExists.cmake测试这些函数的可用性:
```
# 该系统提供log和exp函数吗?
include (CheckFunctionExists.cmake)
check_function_exists (log HAVE_LOG)
check_function_exists (exp HAVE_EXP)
```
下一步,如果CMake在对应平台上找到了它们,我们修改TutorialConfig.h.in来定义这些值;如下:
```
// 该平台提供exp和log函数吗?
#cmakedefine HAVE_LOG
#cmakedefine HAVE_EXP
```
这些log和exp函数的测试要在TutorialConfig.h的configure_file命令之前被处理,这一点很重要。最后,在mysqrt函数中,如果log和exp在当前系统上可用的话,我们可以提供一个基于它们的可选的实现:
```
// 如果我们有log和exp两个函数,那么使用它们
#if defined (HAVE_LOG) && defined (HAVE_EXP)
result = exp(log(x)*0.5);
#else // 否则使用替代方法
```
### 5.添加一个生成文件以及生成器(步骤5)
在本节,我们会展示你应该怎样向一个应用程序的构建过程中添加一个生成的源文件。在本范例中,我们会创建一个预先计算出的平方根表作为构建过程的一部分。MathFunctions子路径下,一个新的MakeTable.cxx源文件来做这件事。
```
// 一个简单的用于构建平方根表的程序
#include
#include
#include
int main (int argc, char *argv[]) {
int i;
double result;
// 确保有足够多的参数
if (argc < 2) {
return 1;
}
// 打开输出文件
FILE *fout = fopen(argv[1],"w");
if (!fout) {
return 1;
}
// 创建一个带有平方根表的源文件
fprintf(fout,"double sqrtTable[] = {\n");
for (i = 0; i < 10; ++i) {
result = sqrt(static_cast(i));
fprintf(fout,"%g,\n",result);
}
// 该表以0结尾
fprintf(fout,"0};\n");
fclose(fout);
return 0;
}
```
注意到这个表是由合法的C++代码生成的,并且被写入的输出文件的名字是作为一个参数输入的。下一步是将合适的命令添加到MathFunction的CMakeLists文件中,来构建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_directories( ${CMAKE_CURRENT_BINARY_DIR} )
# 添加main库
add_library(MathFunctions mysqrt.cxx ${CMAKE_CURRENT_BINARY_DIR}/Table.h )
```
首先,MakeTable的可执行文件也和其他被加入的文件一样被加入。然后,我们添加一个自定义命令来指定如何通过运行MakeTable来生成Table.h。这是通过将生成Table.h增加到MathFunctions库的源文件列表中来实现的。我们还必须增加当前的二进制路径到包含路径的清单中,这样Table.h可以被找到并且可以被mysqrt.cxx所包含。当该工程被构建后,它首先会构建MakeTable可执行文件。然后它会运行MakeTable来生成Table.h文件。最后,它会编译mysqrt.cxx(其中包含Table.h)来生成MathFunctions库。到目前为止,拥有我们添加的完整特性的顶层CMakeLists文件看起来像是这样:
```
cmake_minimum_required (VERSION 2.6)
project (Tutorial)
# 版本号
set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 0)
# 本系统是否提供log和exp函数?
include (${CMAKE_ROOT}/Modules/CheckFunctionExists.cmake)
check_function_exists (log HAVE_LOG)
check_function_exists (exp HAVE_EXP)
# 我们应该使用自己的math函数吗?
option(USE_MYMATH
"Use tutorial provided math implementation" ON)
# 配置一个头文件来向源代码传递一些CMake设置。
configure_file (
"${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
"${PROJECT_BINARY_DIR}/TutorialConfig.h"
)
# 为包含文件的搜索路径添加二进制树,这样才能发现TutorialConfig.h头文件。
include_directories ("${PROJECT_BINARY_DIR}")
# 添加MathFunctions库吗?
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})
# 添加安装的目标
install (TARGETS Tutorial DESTINATION bin)
install (FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
DESTINATION include)
# 测试1 :应用程序可以运行吗?
add_test (TutorialRuns Tutorial 25)
# 测试2 : 使用信息可用吗?
add_test (TutorialUsage Tutorial)
set_tests_properties (TutorialUsage
PROPERTIES
PASS_REGULAR_EXPRESSION "Usage:.*number"
)
# 定义一个可以简化引入测试过程的宏
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文件看起来像是这样:
```
// Tutorial的配置选项与设置如下
#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文件看起来像是这样:
```
# 首先,我们添加生成这个表的可执行文件
add_executable(MakeTable MakeTable.cxx)
# 添加生成源代码的命令
add_custom_command (
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
DEPENDS MakeTable
COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
)
# 为包含文件向搜索路径中添加二进制树目录
include_directories( ${CMAKE_CURRENT_BINARY_DIR} )
# 添加main库
add_library(MathFunctions mysqrt.cxx ${CMAKE_CURRENT_BINARY_DIR}/Table.h)
install (TARGETS MathFunctions DESTINATION bin)
install (FILES MathFunctions.h DESTINATION include)
```
### 6.构建一个安装器(步骤6)
下一步假设我们想要向其他人分发我们的工程,这样他们就可以使用它。我们想同时提供在许多不同平台上的源代码和二进制文档发行版。这与之前我们在“安装与测试(步骤3)”做过的安装有一点不同,那里我们仅仅安装我们从源码中构建出来的二进制文件。在本例子中,我们会构建支持二进制安装以及类似于cygwin,debian,RPM等具有包管理特性的安装包。为了完成这个目标,我们会使用CPack来创建Packaging with CPack一章中描述的特定平台的安装器。
```
# 构建一个CPack驱动的安装包
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 -C CPackConfig.cmake
```
为了创建一个源代码发行版,你应该键入:
```
cpack -C CPackSourceConfig.cmake
```
### 7.增加对Dashboard的支持(步骤7)
增加对向一个dashboard提交我们的测试结果的功能的支持非常简单。我们在本指南的先前步骤中已经定义了我们工程中的许多测试样例。我们仅仅需要运行这些测试样例然后将它们提交到dashboard即可。为了包含对dashboards的支持,我们需要在顶层CMakeLists文件中包含CTest模块。
```
# 支持dashboard脚本
include (CTest)
```
我们也可以创建一个CTestConfig.cmake文件,在其中来指定该dashboard的工程名。
```
set (CTEST_PROJECT_NAME "Tutorial")
```
CTest 将会在运行期间读取这个文件。为了创建一个简单的dashboard,你可以在你的工程下运行CMake,然后切换到二进制树,然后运行ctest -DExperimental. 你的dashboard将会被更新到Kitware的公共dashboard.
## cmake指令
```
公司的一个项目使用CMake作为跨平台构建工具;业务有需求,当然要好好研读一下官方的技术手册。目前的计划是先把官方手册翻译一下,了解清楚CMake中的各种命令、属性和变量的用法。同时在工作中也会阅读CMake的真实源码,后续会基于此陆续写一些工程中使用CMake的心得。CMake的版本也在不停更新,有些新的命令和变量会随着版本更新添加进来,这是后事了,暂且不管;现在锁定CMake 2.8.3作为手册翻译的版本。
```
### 命令名称
```
cmake - 跨平台Makefile生成工具。
```
### 用法
```
cmake [选项] <源码路径>
cmake [选项] <现有构建路径>
```
### 描述
cmake可执行程序是CMake的命令行界面。它可以用脚本对工程进行配置。工程配置设置可以在命令行中使用-D选项指定。使用-i选项,cmake将通过提示交互式地完成该设置。
CMake是一个跨平台的构建系统生成工具。它使用平台无关的CMake清单文件CMakeLists.txt,指定工程的构建过程;源码树的每个路径下都有这个文件。CMake产生一个适用于具体平台的构建系统,用户使用这个系统构建自己的工程。
### 选项
---
```
-C : 预加载一个脚本填充缓存文件。
当cmake在一个空的构建树上第一次运行时,它会创建一个CMakeCache.txt文件,然后向其中写入可定制的项目设置数据。-C选项可以用来指定一个文件,在第一次解析这个工程的cmake清单文件时,从这个文件加载缓存的条目(cache entries)信息。被加载的缓存条目比项目默认的值有更高的优先权。参数中给定的那个文件应该是一个CMake脚本,其中包含有使用CACHE选项的SET命令;而不是一个缓存格式的文件。
-D :=: 创建一个CMake的缓存条目。
当cmake第一次运行于一个空的构建数时,它会创建一个CMakeCache.txt文件,并且使用可定制的工程设置来填充这个文件。这个选项可以用来指定优先级高于工程的默认值的工程设置值。这个参数可以被重复多次,用来填充所需要数量的缓存条目(cache entries)。
-U : 从CMake的缓存文件中删除一条匹配的条目。
该选项可以用来删除CMakeCache.txt文件中的一或多个变量。文件名匹配表达式(globbing expression)支持通配符*和?的使用。该选项可以重复多次以删除期望数量的缓存条目。使用它时要小心,你可能因此让自己的CMakeCache.txt罢工。
-G : 指定一个makefile生成工具。
在具体的平台上,CMake可以支持多个原生的构建系统。makefile生成工具的职责是生成特定的构建系统。可能的生成工具的名称将在生成工具一节给出。
-Wno-dev: 抑制开发者警告。
抑制那些为CMakeLists.txt文件的作者准备的警告信息。
-Wdev: 使能开发者警告信息输出功能。
允许那些为CMakeLists.txt文件的作者准备的警告信息。
-E: CMake命令行模式。
为了真正做到与平台无关,CMake提供了一系列可以用于所有系统上的的命令。以-E参数运行CMake会帮助你获得这些命令的用法。可以使用的命令有:chdir, copy, copy_if_different copy_directory, compare_files, echo, echo_append, environment, make_directory, md5sum, remove_directory, remove, tar, time, touch, touch_nocreate, write_regv, delete_regv, comspec, create_symlink。
-i: 以向导模式运行CMake。
向导模式是在没有GUI时,交互式地运行cmake的模式。cmake会弹出一系列的提示,要求用户回答关于工程配置的一行问题。这些答复会被用来设置cmake的缓存值。
-L[A][H]: 列出缓存的变量中的非高级的变量。
-L选项会列出缓存变量会运行CMake,并列出所有CMake的内有被标记为INTERNAL或者ADVANCED的缓存变量。这会显示当前的CMake配置信息,然后你可以用-D选项改变这些选项。修改一些变量可能会引起更多的变量被创建出来。如果指定了A选项,那么命令也会显示高级变量。如果指定了H选项,那么命令会显示每个变量的帮助信息。
--build : 构建由CMake生成的工程的二进制树。(这个选项的含义我不是很清楚—译注)
该选项用以下的选项概括了内置构建工具的命令行界面
= 待创建的工程二进制路径。
--target = 构建,而不是默认目标。
--config = 对于多重配置工具,选择配置。
--clean-first = 首先构建目标的clean伪目标,然后再构建。
(如果仅仅要clean掉,使用--target 'clean'选项。)
-- = 向内置工具(native tools)传递剩余的选项。
运行不带选项的cmake --build来获取快速帮助信息。
-N: 查看模式。
仅仅加载缓存信息,并不实际运行配置和生成步骤。
-P : 处理脚本模式。
将给定的cmake文件按照CMake语言编写的脚本进行处理。不执行配置和生成步骤,不修改缓存信息。如果要使用-D选项定义变量,-D选项必须在-P选项之前。
--graphviz=[file]: 生成依赖的graphviz图。
生成一个graphviz软件的输入文件,其中包括了项目中所有库和可执行文件之间的依赖关系。
--system-information [file]: 输出与该系统相关的信息。
输出范围比较广的、与当前使用的系统有关的信息。如果在一个CMake工程的二进制构建树的顶端运行该命令,它还会打印一些附加信息,例如缓存,日志文件等等。
--debug-trycompile: 不删除“尝试编译”路径。
不删除那些为try_compile调用生成的路径。这在调试失败的try_compile文件时比较有用。不过,因为上一次“尝试编译”生成的旧的垃圾输出文件也许会导致一次不正确通过/不通过,且该结果与上次测试的结果不同,所以该选项可能会改变“尝试编译”的结果。对于某一次“尝试编译”,该选项最好只用一次;并且仅仅在调试时使用。
--debug-output: 将cmake设置为调试模式。
在cmake运行时,打印额外的信息;比如使用message(send_error)调用得到的栈跟踪信息。
--trace: 将cmake设置为跟踪模式。
用message(send_error)调用,打印所有调用生成的跟踪信息,以及这些调用发生的位置。(这句话含义不是很确定—译注。)
--help-command cmd [file]: 打印单个命令cmd的帮助信息,然后退出。
显示给定的命令的完整的文档。如果指定了[file]参数,该文档会写入该文件,其输出格式由该文件的后缀名确定。支持的文件类型有:man page,HTML,DocBook以及纯文本。
--help-command-list [file]: 列出所有可用命令的清单,然后退出。
该选项列出的信息含有所有命令的名字;其中,每个命令的帮助信息可以使用--help-command选项后跟一个命令名字得到。如果指定了[file]参数,帮助信息会写到file中,输出格式依赖于文件名后缀。支持的文件格式包括:man page,HTML,DocBook以及纯文本。
--help-commands [file]: 打印所有命令的帮助文件,然后退出。
显示所有当前版本的命令的完整文档。如果指定了[file]参数,帮助信息会写到file中,输出格式依赖于文件名后缀。支持的文件格式包括:man page,HTML,DocBook以及纯文本。
--help-compatcommands [file]: 打印兼容性命令(过时的命令—译注)的帮助信息。
显示所有关于兼容性命令的完整文档。如果指定了[file]参数,帮助信息会写到file中,输出格式依赖于文件名后缀。支持的文件格式包括:man page,HTML,DocBook以及纯文本。
--help-module module [file]: 打印某单一模块的帮助信息,然后退出。
打印关于给定模块的完整信息。如果指定了[file]参数,帮助信息会写到file中,且输出格式依赖于文件名后缀。支持的文件格式包括:man page,HTML,DocBook以及纯文本。
--help-module-list [file]: 列出所有可用模块名,然后退出。
列出的清单包括所有模块的名字;其中,每个模块的帮助信息可以使用--help-module选项,后跟模块名的方式得到。如果指定了[file]参数,帮助信息会写到file中,且输出格式依赖于文件名后缀。支持的文件格式包括:man page,HTML,DocBook以及纯文本。
--help-modules [file]: 打印所有模块的帮助信息,然后退出。
显示关于所有模块的完整文档。如果指定了[file]参数,帮助信息会写到file中,且输出格式依赖于文件名后缀。支持的文件格式包括:man page,HTML,DocBook以及纯文本。
--help-custom-modules [file]: 打印所有自定义模块名,然后退出。
显示所有自定义模块的完整文档。如果指定了[file]参数,帮助信息会写到file中,且输出格式依赖于文件名后缀。支持的文件格式包括:man page,HTML,DocBook以及纯文本。
--help-policy cmp [file]: 打印单个策略的帮助信息,然后退出。
显示给定的策略的完整文档。如果指定了[file]参数,帮助信息会写到file中,且输出格式依赖于文件名后缀。支持的文件格式包括:man page,HTML,DocBook以及纯文本。
--help-policies [file]: 打印所有策略的帮助信息,然后退出。
显示所有策略的完整文档。如果指定了[file]参数,帮助信息会写到file中,且输出格式依赖于文件名后缀。支持的文件格式包括:man page,HTML,DocBook以及纯文本。
--help-property prop [file]: 打印单个属性的帮助信息,然后退出。
显示指定属性的完整文档。如果指定了[file]参数,帮助信息会写到file中,且输出格式依赖于文件名后缀。支持的文件格式包括:man page,HTML,DocBook以及纯文本。
--help-property-list [file]: 列出所有可用的属性,然后退出。
该命令列出的清单包括所有属性的名字;其中,每个属性的帮助信息都可以通过--help-property选项后跟一个属性名的方式获得。如果指定了[file]参数,帮助信息会写到file中,且输出格式依赖于文件名后缀。支持的文件格式包括:man page,HTML,DocBook以及纯文本。
--help-properties [file]: 打印所有属性的帮助信息,然后退出。
显示所有属性的完整文档。如果指定了[file]参数,帮助信息会写到file中,且输出格式依赖于文件名后缀。支持的文件格式包括:man page,HTML,DocBook以及纯文本。
--help-variable var [file]: 打印单个变量的帮助信息,然后退出。
显示指定变量的完整文档。如果指定了[file]参数,帮助信息会写到file中,且输出格式依赖于文件名后缀。支持的文件格式包括:man page,HTML,DocBook以及纯文本。
--help-variable-list [file]: 列出文档中有记录的变量,然后退出。
该命令列出的清单包括所有变量的名字;其中,每个变量的帮助信息都可以通过--help-variable选项后跟一个变量名的方式获得。如果指定了[file]参数,帮助信息会写到file中,且输出格式依赖于文件名后缀。支持的文件格式包括:man page,HTML,DocBook以及纯文本。
--help-variables [file]: 打印所有变量的帮助信息,然后退出。
显示所有变量的完整帮助文档。如果指定了[file]参数,帮助信息会写到file中,且输出格式依赖于文件名后缀。支持的文件格式包括:man page,HTML,DocBook以及纯文本。
--copyright [file]: 打印CMake的版权信息,然后退出。
如果指定了[file]参数,版权信息会写到这个文件中。
--help: 打印用法信息,然后退出。
用法信息描述了基本的命令行界面及其选项。
--help-full [file]: 打印完整的帮助信息,然后退出。
显示大多数UNIX man page提供的帮助信息。该选项是为非UNIX平台提供的;但是如果man手册页没有安装,它也能提供便利。如果制定了[file]参数,帮助信息会写到这个文件中。
--help-html [file]: 以HTML格式打印完整的帮助信息,然后退出。
CMake的作者使用该选来帮助生成web页面。如果指定了[file]参数,帮助信息会写到这个文件中。
--help-man [file]: 以UNIX的man手册页格式打印完整的帮助信息,然后退出。
cmake使用该选生成UNIX的man手册页。如果指定了[file]参数,帮助信息会写到这个文件中。
--version [file]: 显示程序名/版本信息行,然后退出。
如果指定了[file]参数,版本信息会写到这个文件中。
```
---
对于CMake的语言要素,比如命令,属性和变量,帮助命令选项也是很有规律的,一般是用--help-xxx-list查看所有值的名字,找出感兴趣的项,然后用--help-xxx name查看该名字的详细信息;也可以用--help-xxxs获得相关语言要素的完整帮助信息。
### 生成器
在CMake 2.8.3平台上,CMake支持下列生成器:
---
* Borland Makefiles: 生成Borland makefile。
* MSYS Makefiles: 生成MSYS makefile。
生成的makefile用use /bin/sh作为它的shell。在运行CMake的机器上需要安装msys。
* MinGW Makefiles: 生成供mingw32-make使用的make file。
生成的makefile使用cmd.exe作为它的shell。生成它们不需要msys或者unix shell。
* NMake Makefiles: 生成NMake makefile。
* NMake Makefiles JOM: 生成JOM makefile。
* Unix Makefiles: 生成标准的UNIX makefile。
在构建树上生成分层的UNIX makefile。任何标准的UNIX风格的make程序都可以通过默认的make目标构建工程。生成的makefile也提供了install目标。
* Visual Studio 10: 生成Visual Studio 10 工程文件。
* Visual Studio 10 Win64: 生成Visual Studio 10 Win64 工程文件。
* Visual Studio 6: 生成Visual Studio 6 工程文件。
* Visual Studio 7: 生成Visual Studio .NET 2002 工程文件。
* Visual Studio 7 .NET 2003: 生成Visual Studio .NET 2003工程文件。
* Visual Studio 8 2005: 生成Visual Studio .NET 2005 工程文件。
* Visual Studio 8 2005 Win64: 生成Visual Studio .NET 2005 Win64工程文件。
* Visual Studio 9 2008: 生成Visual Studio 9 2008 工程文件。
* Visual Studio 9 2008 Win64: 生成Visual Studio 9 2008 Win64工程文件。
* Watcom WMake: 生成Watcom WMake makefiles。
* CodeBlocks - MinGW Makefiles: 生成CodeBlock工程文件。
在顶层目录以及每层子目录下为CodeBlocks生成工程文件,生成的CMakeList.txt的特点是都包含一个PROJECT()调用。除此之外还会在构建树上生成一套层次性的makefile。通过默认的make目标,正确的make程序可以构建这个工程。makefile还提供了install目标。
* CodeBlocks - NMake Makefiles: 生成CodeBlocks工程文件。
在顶层目录以及每层子目录下为CodeBlocks生成工程文件,生成的CMakeList.txt的特点是都包含一个PROJECT()调用。除此之外还会在构建树上生成一套层次性的makefile。通过默认的make目标,正确的make程序可以构建这个工程。makefile还提供了install目标。
* CodeBlocks - Unix Makefiles: 生成CodeBlocks工程文件。
在顶层目录以及每层子目录下为CodeBlocks生成工程文件,生成的CMakeList.txt的特点是都包含一个PROJECT()调用。除此之外还会在构建树上生成一套层次性的makefile。通过默认的make目标,正确的make程序可以构建这个工程。makefile还提供了install目标。
* Eclipse CDT4 - MinGW Makefiles: 生成Eclipse CDT 4.0 工程文件。
在顶层目录下为Eclipse生成工程文件。在运行源码外构建时,一个连接到顶层源码路径的资源文件会被创建。除此之外还会在构建树上生成一套层次性的makefile。通过默认的make目标,正确的make程序可以构建这个工程。makefile还提供了install目标。
* Eclipse CDT4 - NMake Makefiles: 生成Eclipse CDT 4.0 工程文件。
在顶层目录下为Eclipse生成工程文件。在运行源码外构建时,一个连接到顶层源码路径的资源文件会被创建。除此之外还会在构建树上生成一套层次性的makefile。通过默认的make目标,正确的make程序可以构建这个工程。makefile还提供了install目标。
* Eclipse CDT4 - Unix Makefiles: 生成Eclipse CDT 4.0 工程文件。
在顶层目录下为Eclipse生成工程文件。在运行源码外构建时,一个连接到顶层源码路径的资源文件会被创建。除此之外还会在构建树上生成一套层次性的makefile。通过默认的make目标,正确的make程序可以构建这个工程。makefile还提供了install目标。
---
## CMake函数
CMake手册的客套话总算说完了,开始进入正题。第一部分是CMake命令。命令就相当于命令行下操作系统提供的各种命令,重要性不言而喻;可以说,这些命令是CMake构建系统的骨架。CMake 2.8.3共有80条命令,分别是:add_custom_command, add_custom_target, add_definitions, add_dependencies, add_executable, add_library, add_subdirectory, add_test, aux_source_directory, break, build_command, cmake_minimum_required, cmake_policy, configure_file, create_test_sourcelist, define_property, else, elseif, enable_language, enable_testing, endforeach, endfunction, endif, endmacro, endwhile, execute_process, export, file, find_file, find_library, find_package, find_path, find_program, fltk_wrap_ui, foreach, function, get_cmake_property, get_directory_property, get_filename_component, get_property, get_source_file_property, get_target_property, get_test_property, if, include, include_directories, include_external_msproject, include_regular_expression, install, link_directories, list, load_cache, load_command, macro, mark_as_advanced, math, message, option, output_required_files, project, qt_wrap_cpp, qt_wrap_ui, remove_definitions, return, separate_arguments, set, set_directory_properties, set_property, set_source_files_properties, set_target_properties, set_tests_properties, site_name, source_group, string, target_link_libraries, try_compile, try_run, unset, variable_watch, while。这些命令在手册中是字典序排列的;为了便于查找,翻译也按照字典序来组织。但是在翻译结束后,会对命令进行小结,与大家讨论一下这些命令的使用方法和使用时机。
## CMD#1 add_custom_command
为生成的构建系统添加一条自定义的构建规则。
add_custom_command命令有两种主要的功能;第一种是为了生成输出文件,添加一条自定义命令。
```
add_custom_command(OUTPUT output1 [output2 ...]
COMMAND command1 [ARGS] [args1...]
[COMMAND command2 [ARGS] [args2...] ...]
[MAIN_DEPENDENCY depend]
[DEPENDS [depends...]]
[IMPLICIT_DEPENDS depend1 ...]
[WORKING_DIRECTORY dir]
[COMMENT comment] [VERBATIM] [APPEND])
```
这种命令格式定义了一条生成指定的文件(文件组)的生成命令。在相同路径下创建的目标(CMakeLists.txt文件)——任何自定义命令的输出都作为它的源文件——被设置了一条规则:在构建的时候,使用指定的命令来生成这些文件。如果一个输出文件名是相对路径,它将被解释成相对于构建树路径的相对路径,并且与当前源码路径是对应的。注意,MAIN_DEPENDENCY完全是可选的,它用来向visual studio建议在何处停止自定义命令。对于各种类型的makefile而言,这条命令创建了一个格式如下的新目标:
```
OUTPUT: MAIN_DEPENDENCY DEPENDS
COMMAND
```
如果指定了多于一条的命令,它们会按顺序执行。ARGS参数是可选的,它的存在是为了保持向后兼容,以后会被忽略掉。
第二种格式为一个目标——比如一个库文件或者可执行文件——添加一条自定义命令。这种格式可以用于目标构建前或构建后的一些操作。这条命令会成为目标的一部分,并且只有目标被构建时才会执行。如果目标已经构建了,该目标将不会执行。
```
add_custom_command(TARGET target
PRE_BUILD | PRE_LINK | POST_BUILD
COMMAND command1 [ARGS] [args1...]
[COMMAND command2 [ARGS] [args2...] ...]
[WORKING_DIRECTORY dir]
[COMMENT comment] [VERBATIM])
```
这条命令定义了一个与指定目标的构建过程相关的新命令。新命令在何时执行,由下述的选项决定:
```
PRE_BUILD - 在所有其它的依赖之前执行;
PRE_LINK - 在所有其它的依赖之后执行;
POST_BUILD - 在目标被构建之后执行;
```
注意,只有Visual Studio 7或更高的版本才支持PRE_BUILD。对于其他的生成器,PRE_BUILD会被当做PRE_LINK来对待。
如果指定了WORKING_DIRECTORY选项,这条命令会在给定的路径下执行。如果设置了COMMENT选项,后跟的参数会在构建时、以构建信息的形式、在命令执行之前显示出来。如果指定了APPEND选项,COMMAND以及DEPENDS选项的值会附加到第一个输出文件的自定义命令上。在此之前,必须有一次以相同的输出文件作为参数的对该命令的调用。在当前版本下,如果指定了APPEND选项,COMMENT, WORKING_DIRECTORY和MAIN_DEPENDENCY选项会被忽略掉,不过未来有可能会用到。
如果指定了VERBATIM选项,所有该命令的参数将会合适地被转义,以便构建工具能够以原汁原味的参数去调用那些构建命令。注意,在add_custom_command能看到这些参数之前,CMake语言处理器会对这些参数做一层转义处理。推荐使用VERBATIM参数,因为它能够保证正确的行为。当VERBATIM未指定时,CMake的行为依赖于平台,因为CMake没有针对某一种工具的特殊字符采取保护措施。
如果自定义命令的输出并不是实际的磁盘文件,应该使用SET_SOURCE_FILES_PROPERTIES命令将该输出的属性标记为SYMBOLIC。
IMPLICIT_DEPENDS选项请求扫描一个输入文件的隐含依赖关系。给定的语言参数(文中的lang1—译注)指定了应该使用哪种编程语言的依赖扫描器。目前为止,仅支持C和CXX语言扫描器。扫描中发现的依赖文件将会在编译时添加到自定义命令中。注意,IMPLICIT_DEPENDS选项目前仅仅直至Makefile生成器,其它的生成器会忽略之。
如果COMMAND选项指定了一个可执行目标(由ADD_EXECUTABLE命令创建的目标),在构建时,它会自动被可执行文件的位置所替换。而且,一个目标级的依赖性将会被添加进去,这样这个可执行目标将会在所有依赖于该自定义命令的结果的目标之前被构建。不过,任何时候重编译这个可执行文件,这种特性并不会引入一个会引起自定义命令重新运行的文件级依赖。
DEPENDS选项指定了该命令依赖的文件。如果依赖的对象是同一目录(CMakeLists.txt文件)下另外一个自定义命令的输出,CMake会自动将其它自定义命令带到这个命令中来。如果DEPENDS指定了任何类型的目标(由ADD_*命令创建),一个目标级的依赖性将会被创建,以保证该目标在任何其它目标使用这个自定义命令的输出之前,该目标已经被创建了。而且,如果该目标是可执行文件或库文件,一个文件级依赖将会被创建,用来引发自定义命令在目标被重编译时的重新运行。
在Unix Makefile中,这条命令相当于增加了一个依赖关系和一条显式生成命令。
## CMD#2 add_custom_target
add_custom_target 添加一个目标,它没有输出;这样它就总是会被构建。
```
add_custom_target(Name [ALL] [command1 [args1...]]
[COMMAND command2 [args2...] ...]
[DEPENDS depend depend depend ... ]
[WORKING_DIRECTORY dir]
[COMMENT comment] [VERBATIM]
[SOURCES src1 [src2...]])
```
用Name选项给定的名字添加一个目标,这个目标会引发给定的那些命令。这个目标没有输出文件,并且总是被认为是过时的,即使那些命令试图去创建一个与该目标同名的文件。使用ADD_CUSTOM_COMMAND命令可以生成一个带有依赖性的文件。默认情况下,没有目标会依赖于自定义目标。使用ADD_DEPENDENCIES命令可以添加依赖于该目标或者被该目标依赖的目标。如果指定了ALL选项,这表明这个目标应该被添加到默认的构建目标中,这样它每次都会被构建(命令的名字不能是ALL)。命令和选项是可选的;如果它们没有被指定,将会产生一个空目标。如果设定了WORKING_DIRECTORY参数,该命令会在它指定的路径下执行。如果指定了COMMENT选项,后跟的参数将会在构件的时候,在命令执行之前,被显示出来。DEPENDS选项后面列出来的依赖目标可以引用add_custom_command命令在相同路径下(CMakeLists.txt)生成的输出和文件。
如果指定了VERBATIM选项,所有传递到该命令的选项将会被合适地转义;这样,该命令调用的构建工具会接收到未经改变的参数。注意,CMake语言处理器会在add_custom_target命令在看到这些参数之前对它们进行一层转义。推荐使用该参数,因为它保证了正确的行为。当未指定该参数时,转义的行为依赖于平台,因为CMake没有针对于特定工具中特殊字符的保护措施。
SOURCES选项指定了会被包含到自定义目标中的附加的源文件。指定的源文件将会被添加到IDE的工程文件中,方便在没有构建规则的情况下能够编辑。
## CMD#3 add_definitions
为源文件的编译添加由-D引入的define flag。
```
add_definitions(-DFOO -DBAR ...)
```
在编译器的命令行上,为当前路径以及下层路径的源文件加入一些define flag。这个命令可以用来引入任何flag,但是它的原意是用来引入预处理器的定义。那些以-D或/D开头的、看起来像预处理器定义的flag,会被自动加到当前路径的COMPILE_DEFINITIONS属性中。为了后向兼容,非简单值(non-trival,指的是什么?——译注)的定义会被留在flags组(flags set)里,而不会被转换。关于在特定的域以及配置中增加预处理器的定义,参考路径、目标以及源文件的COMPILE_DEFINITIONS属性来获取更多的细节。
## CMD#4 add_dependencies
为顶层目标引入一个依赖关系。
```
add_dependencies(target-name depend-target1
depend-target2 ...)
```
让一个顶层目标依赖于其他的顶层目标。一个顶层目标是由命令ADD_EXECUTABLE,ADD_LIBRARY,或者ADD_CUSTOM_TARGET产生的目标。为这些命令的输出引入依赖性可以保证某个目标在其他的目标之前被构建。查看ADD_CUSTOM_TARGET和ADD_CUSTOM_COMMAND命令的DEPENDS选项,可以了解如何根据自定义规则引入文件级的依赖性。查看SET_SOURCE_FILES_PROPERTIES命令的OBJECT_DEPENDS选项,可以了解如何为目标文件引入文件级的依赖性。
## CMD#5 add_executable
使用给定的源文件,为工程引入一个可执行文件。
```
add_executable( [WIN32] [MACOSX_BUNDLE]
[EXCLUDE_FROM_ALL]
source1 source2 ... sourceN)
```
引入一个名为的可执行目标,该目标会由调用该命令时在源文件列表中指定的源文件来构建。对应于逻辑目标名字,并且在工程范围内必须是全局唯一的。被构建的可执行目标的实际文件名将根据具体的本地平台创建出来(比如.exe或者仅仅是)。
默认情况下,可执行文件将会在构建树的路径下被创建,对应于该命令被调用的源文件树的路径。如果要改变这个位置,查看RUNTIME_OUTPUT_DIRECTORY目标属性的相关文档。如果要改变最终文件名的部分,查看OUTPUT_NAME目标属性的相关文档。
如果指定了MACOSX_BUNDLE选项,对应的属性会附加在创建的目标上。查看MACOSX_BUNDLE目标属性的文档可以找到更多的细节。
如果指定了EXCLUDE_FROM_ALL选项,对应的属性将会设置在被创建的目标上。查看EXCLUDE_FROM_ALL目标属性的文档可以找到更多的细节。
使用下述格式,add_executable命令也可以用来创建导入的(IMPORTED)可执行目标:
```
add_executable( IMPORTED)
```
一个导入的可执行目标引用了一个位于工程之外的可执行文件。该格式不会生成构建这个目标的规则。该目标名字的作用域在它被创建的路径以及底层路径有效。它可以像在该工程内的其他任意目标一样被引用。导入可执行文件为类似于add_custom_command之类的命令引用它提供了便利。
关于导入的可执行文件的细节可以通过设置以IMPORTED_开头的属性来指定。这类属性中最重要的是IMPORTED_LOCATION(以及它对应于具体配置的版本IMPORTED_LOCATION_);该属性指定了执行文件主文件在磁盘上的位置。查看IMPORTED_*属性的文档来获得更多信息。
## CMD#6 add_library
使用指定的源文件向工程中添加一个库。
```
add_library( [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
source1 source2 ... sourceN)
```
添加一个名为的库文件,该库文件将会根据调用的命令里列出的源文件来创建。对应于逻辑目标名称,而且在一个工程的全局域内必须是唯一的。待构建的库文件的实际文件名根据对应平台的命名约定来构造(比如lib.a或者.lib)。指定STATIC,SHARED,或者MODULE参数用来指定要创建的库的类型。STATIC库是目标文件的归档文件,在链接其它目标的时候使用。SHARED库会被动态链接,在运行时被加载。MODULE库是不会被链接到其它目标中的插件,但是可能会在运行时使用dlopen-系列的函数动态链接。如果没有类型被显式指定,这个选项将会根据变量BUILD_SHARED_LIBS的当前值是否为真决定是STATIC还是SHARED。
默认状态下,库文件将会在于源文件目录树的构建目录树的位置被创建,该命令也会在这里被调用。查阅ARCHIVE_OUTPUT_DIRECTORY,LIBRARY_OUTPUT_DIRECTORY,和RUNTIME_OUTPUT_DIRECTORY这三个目标属性的文档来改变这一位置。查阅OUTPUT_NAME目标属性的文档来改变最终文件名的部分。
如果指定了EXCLUDE_FROM_ALL属性,对应的一些属性会在目标被创建时被设置。查阅EXCLUDE_FROM_ALL的文档来获取该属性的细节。
使用下述格式,add_library命令也可以用来创建导入的库目标:
```
add_library( IMPORTED)
```
导入的库目标是引用了在工程外的一个库文件的目标。没有生成构建这个库的规则。这个目标名字的作用域在它被创建的路径及以下有效。他可以向任何在该工程内构建的目标一样被引用。导入库为类似于target_link_libraries命令中引用它提供了便利。关于导入库细节可以通过指定那些以IMPORTED_的属性设置来指定。其中最重要的属性是IMPORTED_LOCATION(以及它的具体配置版本,IMPORTED_LOCATION_),它指定了主库文件在磁盘上的位置。查阅IMPORTED_*属性的文档获取更多的信息。
## CMD#7 add_subdirectory 为构建添加一个子路径。
```
add_subdirectory(source_dir [binary_dir]
[EXCLUDE_FROM_ALL])
```
这条命令的作用是为构建添加一个子路径。source_dir选项指定了CMakeLists.txt源文件和代码文件的位置。如果source_dir是一个相对路径,那么source_dir选项会被解释为相对于当前的目录,但是它也可以是一个绝对路径。binary_dir选项指定了输出文件的路径。如果binary_dir是相对路径,它将会被解释为相对于当前输出路径,但是它也可以是一个绝对路径。如果没有指定binary_dir,binary_dir的值将会是没有做任何相对路径展开的source_dir,这也是通常的用法。在source_dir指定路径下的CMakeLists.txt将会在当前输入文件的处理过程执行到该命令之前,立即被CMake处理。
如果指定了EXCLUDE_FROM_ALL选项,在子路径下的目标默认不会被包含到父路径的ALL目标里,并且也会被排除在IDE工程文件之外。用户必须显式构建在子路径下的目标,比如一些示范性的例子工程就是这样。典型地,子路径应该包含它自己的project()命令调用,这样会在子路径下产生一份完整的构建系统(比如VS IDE的solution文件)。注意,目标间的依赖性要高于这种排除行为。如果一个被父工程构建的目标依赖于在这个子路径下的目标,被依赖的目标会被包含到父工程的构建系统中,以满足依赖性的要求。
## CMD#8 add_test
以指定的参数为工程添加一个测试。
```
add_test(testname Exename arg1 arg2 ... )
```
如果已经运行过了ENABLE_TESTING命令,这个命令将为当前路径添加一个测试目标。如果ENABLE_TESTING还没有运行过,该命令啥事都不做。测试是由测试子系统运行的,它会以指定的参数执行Exename文件。Exename或者是由该工程构建的可执行文件,也可以是系统上自带的任意可执行文件(比如tclsh)。该测试会在CMakeList.txt文件的当前工作路径下运行,这个路径与二进制树上的路相对应。
```
add_test(NAME [CONFIGURATIONS [Debug|Release|...]]
COMMAND [arg1 [arg2 ...]])
```
如果COMMAND选项指定了一个可执行目标(用add_executable创建),它会自动被在构建时创建的可执行文件所替换。如果指定了CONFIGURATIONS选项,那么该测试只有在列出的某一个配置下才会运行。
在COMMAND选项后的参数可以使用“生成器表达式”,它的语法是$<...>。这些表达式会在构建系统生成期间,以及构建配置的专有信息的产生期间被评估。合法的表达式是:
```
$ = 配置名称
$ = 主要的二进制文件(.exe, .so.1.2, .a)
$ = 用于链接的文件(.a, .lib, .so)
$ = 带有.so.的文件(.so.3)
```
其中,"tgt"是目标的名称。目标文件表达式TARGET_FILE生成了一个完整的路径,但是它的_DIR和_NAME版本可以生成目录以及文件名部分:
```
$/$
$/$
$/$
```
用例:
```
add_test(NAME mytest
COMMAND testDriver --config $
--exe $)
```
这段代码创建了一个名为mytest的测试,它执行的命令是testDriver工具,传递的参数包括配置名,以及由目标生成的可执行文件myexe的完整路径。
## CMD#9 aux_source_directory
查找在某个路径下的所有源文件。
```
aux_source_directory( )
```
搜集所有在指定路径下的源文件的文件名,将输出结果列表储存在指定的变量中。该命令主要用在那些使用显式模板实例化的工程上。模板实例化文件可以存储在Templates子目录下,然后可以使用这条命令自动收集起来;这样可以避免手工罗列所有的实例。
使用该命令来避免为一个库或可执行目标写源文件的清单,是非常具有吸引力的。但是如果该命令貌似可以发挥作用,那么CMake就不需要生成一个感知新的源文件何时被加进来的构建系统了(也就是说,新文件的加入,并不会导致CMakeLists.txt过时,从而不能引起CMake重新运行。——译注)。正常情况下,生成的构建系统能够感知它何时需要重新运行CMake,因为需要修改CMakeLists.txt来引入一个新的源文件。当源文件仅仅是加到了该路径下,但是没有修改这个CMakeLists.txt文件,使用者只能手动重新运行CMake来产生一个包含这个新文件的构建系统。
## CMD#10 break
从一个包围该命令的foreach或或while循环中跳出。
```
break()
```
从包围它的foreach循环或while循环中跳出。
## CMD#11 build_command
获取构建该工程的命令行。
```
build_command(
[CONFIGURATION ]
[PROJECT_NAME ]
[TARGET ])
```
把给定的变量设置成一个字符串,其中包含使用由变量CMAKE_GENERATOR确定的项目构建工具,去构建某一个工程的某一个目标配置的命令行。
对于多配置生成器,如果忽略CONFIGURATION选项,CMake将会选择一个合理的默认值;而对于单配置生成器,该选项会被忽略。
如果PROJECT_NAME选项被忽略,得到的命令行用来构建当前构建树上的顶层工程。
如果TARGET选项被忽略,得到的命令行可以用来构建所有目标,比较高效的用法是构建目标all或者ALL_BUILD。
```
build_command( )
```
不推荐使用以上的这种格式,但对于后相兼容还是有用的。只要可以,就要使用第一种格式。
这种格式将变量设置为一个字符串,其中包含从构建树的根目录,用指定的构建工具构建这个工程的命令。应该是指向msdev,devenv,nmake,make或者是一种最终用户指定的构建工具的完整路径。
## CMD#12 cmake_minimum_required
设置一个工程所需要的最低CMake版本。
```
cmake_minimum_required(VERSION major[.minor[.patch[.tweak]]]
[FATAL_ERROR])
```
如果CMake的当前版本低于指定的版本,它会停止处理工程文件,并报告错误。当指定的版本高于2.4时,它会隐含调用:
```
cmake_policy(VERSION major[.minor[.patch[.tweak]]])
```
从而将cmale的策略版本级别设置为指定的版本。当指定的版本是2.4或更低时,这条命令隐含调用:
```
cmake_policy(VERSION 2.4)
```
这将会启用对于CMake 2.4及更低版本的兼容性。
FATAL_ERROR选项是可以接受的,但是CMake 2.6及更高的版本会忽略它。如果它被指定,那么CMake 2.4及更低版本将会以错误告终而非仅仅给出个警告。
## CMD#13 cmake_policy
管理CMake的策略设置。
随着CMake的演变,有时为了搞定bug或改善现有特色的实现方法,改变现有的行为是必须的。CMake的策略机制是在新的CMake版本带来行为上的改变时,用来帮助保持现有项目的构建的一种设计。每个新的策略(行为改变)被赋予一个CMP格式的识别符,其中是一个整数索引。每个策略相关的文档都会描述“旧行为”和“新行为”,以及引入该策略的原因。工程可以设置各种策略来选择期望的行为。当CMake需要了解要用哪种行为的时候,它会检查由工程指定的一种设置。如果没有可用的设置,工程假定使用“旧行为”,并且会给出警告要求你设置工程的策略。
cmake_policy是用来设置“新行为”或“旧行为”的命令。如果支持单独设置策略,我们鼓励各项目根据CMake的版本来设置策略。
```
cmake_policy(VERSION major.minor[.patch[.tweak]])
```
上述命令指定当前的CMakeLists.txt是为给定版本的CMake书写的。所有在指定的版本或更早的版本中引入的策略会被设置为使用“新行为”。所有在指定的版本之后引入的策略将会变为无效(unset)。该命令有效地为一个指定的CMake版本请求优先采用的行为,并且告知更新的CMake版本给出关于它们新策略的警告。命令中指定的策略版本必须至少是2.4,否则命令会报告一个错误。为了得到支持早于2.4版本的兼容性特性,查阅策略CMP0001的相关文档。
```
cmake_policy(SET CMP NEW)
cmake_policy(SET CMP OLD)
```
对于某种给定的策略,该命令要求CMake使用新的或者旧的行为。对于一个指定的策略,那些依赖于旧行为的工程,通过设置策略的状态为OLD,可以禁止策略的警告。或者,用户可以让工程采用新行为,并且设置策略的状态为NEW。
```
cmake_policy(GET CMP )
```
该命令检查一个给定的策略是否设置为旧行为或新行为。如果策略被设置,输出的变量值会是“OLD”或“NEW”,否则为空。
CMake将策略设置保存在一个栈结构中,因此,cmake_policy命令产生的改变仅仅影响在栈顶端的元素。在策略栈中的一个新条目由各子路径自动管理,以此保护它的父路径及同层路径的策略设置。CMake也管理通过include()和find_package()命令加载的脚本中新加入的条目,除非调用时指定了NO_POLICY_SCOPE选项(另外可参考CMP0011)。cmake_policy命令提供了一种管理策略栈中自定义条目的接口:
```
cmake_policy(PUSH)
cmake_policy(POP)
```
每个PUSH必须有一个配对的POP来去掉撤销改变。这对于临时改变策略设置比较有用。
函数和宏会在它们被创建的时候记录策略设置,并且在它们被调用的时候使用记录前的策略。如果函数或者宏实现设置了策略,这个变化会通过调用者(caller)一直上传,自动传递到嵌套的最近的策略栈条目。
## CMD#14 configure_file
将一份文件拷贝到另一个位置并修改它的内容。
```
configure_file(