翻译:原文参见:cmake-tutorial
实践测试路径: 实践过程
下面是一个 step-by-step
教程,涵盖了CMake能够涉及的通用的编译系统问题。这些内容可能在其它的资料中 (http://www.kitware.com/products/books.php) 已经分别被介绍过。
但是如果能够看到它们在整体是如何在一个实例项目中运作的,将会非常有帮助。这个教程可以在 CMake源代码中的 Tests/Tutorial
目录中找到。每个步骤有它自己的子目录,包含了那个步骤的内容。
第一步,一个基本的开始
最基本的项目是一个只有一个由源代码编译而来的可执行文件。对于一个简单的项目,我们只需要在 CMakeLists
文件中加入两行代码。
最基本的过程
这里是我们这个教程的起点。
CMakeLists.txt
文件内容如下:
cmake_minimum_required (VERSION 2.6)
project (Tutorial)
add_executable(Tutorial tutorial.cxx)
注意,这个例子在 CMakeLists
文件中使用了小写字母的命令。CMake支持大写,小写,混合大小写的命令。
tutorial.cxx
源代码文件 tutorial.cxx
计算一个数字的平方根,这个代码文件的第一个版本非常简单,如下:
// A simple program that computes the square root of a number
#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;
}
详细过程
下面通过实践来回顾一下具体发生了什么。
-
原始文件目录结构
经过上面实践,我们的目录中只有两个文件,如下:
$ls -p tutorial/ $tree tutorial/ tutorial/ ├── CMakeLists.txt └── tutorial.cpp 0 directories, 2 files
当前路径下,总共只有1个目录
tutorial
, 2个文件。 -
cmake
生成Makefile
将项目目录
tutorial
做为参数,传递给cmake
之后,会在当前目录(运行cmake
的目录)生成许多文件,包括Makefile
, 如下:$cmake tutorial/ $ls -p CMakeCache.txt CMakeFiles/ cmake_install.cmake Makefile tutorial/ $tree . . ├── CMakeCache.txt ├── CMakeFiles │ ├── CMakeCCompiler.cmake │ ├── cmake.check_cache │ ├── CMakeCXXCompiler.cmake │ ├── CMakeDetermineCompilerABI_C.bin │ ├── CMakeDetermineCompilerABI_CXX.bin │ ├── CMakeDirectoryInformation.cmake │ ├── CMakeOutput.log │ ├── CMakeSystem.cmake │ ├── CMakeTmp │ │ └── CMakeFiles │ │ └── cmTryCompileExec.dir │ ├── CompilerIdC │ │ ├── a.out │ │ └── CMakeCCompilerId.c │ ├── CompilerIdCXX │ │ ├── a.out │ │ └── CMakeCXXCompilerId.cpp │ ├── Makefile2 │ ├── Makefile.cmake │ ├── progress.marks │ ├── TargetDirectories.txt │ └── Tutorial.dir │ ├── build.make │ ├── cmake_clean.cmake │ ├── DependInfo.cmake │ ├── depend.make │ ├── flags.make │ ├── link.txt │ └── progress.make ├── cmake_install.cmake ├── Makefile └── tutorial ├── CMakeLists.txt └── tutorial.cpp 8 directories, 28 files
cmake
之后,当前目录下多了CMakeCache.txt
,CMakeFiles
,cmake_install.cmake
,Makefile
。当前文件总共是8个目录,28个文件,tutorial
内容不变。其中Makefile
是生成的 makefile。 -
make
编译$make Scanning dependencies of target Tutorial [100%] Building CXX object CMakeFiles/Tutorial.dir/tutorial.cpp.o Linking CXX executable Tutorial [100%] Built target Tutorial $ls -p CMakeCache.txt CMakeFiles/ cmake_install.cmake Makefile tree.txt tutorial/ Tutorial $tree . . ├── CMakeCache.txt ├── CMakeFiles │ ├── CMakeCCompiler.cmake │ ├── cmake.check_cache │ ├── CMakeCXXCompiler.cmake │ ├── CMakeDetermineCompilerABI_C.bin │ ├── CMakeDetermineCompilerABI_CXX.bin │ ├── CMakeDirectoryInformation.cmake │ ├── CMakeOutput.log │ ├── CMakeSystem.cmake │ ├── CMakeTmp │ │ └── CMakeFiles │ │ └── cmTryCompileExec.dir │ ├── CompilerIdC │ │ ├── a.out │ │ └── CMakeCCompilerId.c │ ├── CompilerIdCXX │ │ ├── a.out │ │ └── CMakeCXXCompilerId.cpp │ ├── Makefile2 │ ├── Makefile.cmake │ ├── progress.marks │ ├── TargetDirectories.txt │ └── Tutorial.dir │ ├── build.make │ ├── cmake_clean.cmake │ ├── CXX.includecache │ ├── DependInfo.cmake │ ├── depend.internal │ ├── depend.make │ ├── flags.make │ ├── link.txt │ ├── progress.make │ └── tutorial.cpp.o ├── cmake_install.cmake ├── Makefile ├── tree.txt ├── tutorial │ ├── CMakeLists.txt │ └── tutorial.cpp └── Tutorial 8 directories, 33 files
make
之后当前路径下比之前多了:CMakeFiles/Tutorial.dir/CXX.includecache
,CMakeFiles/Tutorial.dir/depend.internal
,CMakeFiles/Tutorial.dir/tutorial.cpp.o
,Tutorial
,总共8个目录33个文件,tutorial
目录内容仍旧不变。其中,Tutorial
是可执行文件。另外,实践后,
make clean
比make
少了Tutorial
与CMakeFiles/Tutorial.dir/tutorial.cpp.o
。
更多信息
通常过程
代码如下:
$ tree .
.
└── tutorial
├── CMakeLists.txt
└── tutorial.cpp
1 directory, 2 files
命令如下:
$ mkdir build && cd build
$ cmake
$ make
$ ./Tutorial
Usage: ./Tutorial number
$ ./Tutorial 25
The square root of 25 is 5
添加版本号和配置头文件
现在我们将为项目加入的第一个特性,为可执行文件和项目提供一个版本号。你可以在源代码中使用互斥的代码来实现这一点,但是使用 CMakeLists
文件来做这些事情会很灵活。
CMakeLists.txt
为了添加一个版本号,我们需要修改 CMakeLists
文件如下:
cmake_minimum_required (VERSION 2.6)
project (Tutorial)
# The version number.
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)
这里,由于配置文件将会被写入到 binary tree
中(对应后面运行 cmake
的目录 ${PROJECT_BINARY_DIR}
, 也就是生成可执行文件的目录),我们必须添加相应的目录到 paths
列表中(对应 include_directories
),以便能够搜索 include
文件(对应 ${PROJECT_BINARY_DIR}/TutorialConfig.h
)。
TutorialConfig.h.in
之后,我们在 source tree
中(对应 Tutorial
的代码目录 ${PROJECT_SOURCE_DIR}
),创建一个 TutorialConfig.h.in
文件,内容如下:
// the configured options and settings for 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
下一步,我们将修改 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;
}
对源代码主要的修改,其实就是包含了一个 TutorialConfig.h
文件,并且在 tutorial.cxx
中打印使用消息字串时添加版本号的信息。
过程
下面通过时间回顾一下具体发生了什么。
注意,这里为了便于记录和对比,我们首先在编译目录中建立了 tree.origin
, tree.cmakelog
, tree.makelog
, tree.cleanlog
以记录文件的变化。
-
原始文件目录结构
$ls -p tree.cleanlog tree.cmakelog tree.makelog tree.origin tutorial/ $tree . >tree.origin $cat tree.origin . ├── tree.cleanlog ├── tree.cmakelog ├── tree.makelog ├── tree.origin └── tutorial ├── CMakeLists.txt ├── TutorialConfig.h.in └── tutorial.cpp 1 directory, 7 files
-
cmake
生成Makefile
$cmake tutorial $tree . >tree.cmakelog $cat tree.cmakelog . ├── CMakeCache.txt ├── CMakeFiles │ ├── CMakeCCompiler.cmake │ ├── cmake.check_cache │ ├── CMakeCXXCompiler.cmake │ ├── CMakeDetermineCompilerABI_C.bin │ ├── CMakeDetermineCompilerABI_CXX.bin │ ├── CMakeDirectoryInformation.cmake │ ├── CMakeOutput.log │ ├── CMakeSystem.cmake │ ├── CMakeTmp │ │ └── CMakeFiles │ │ └── cmTryCompileExec.dir │ ├── CompilerIdC │ │ ├── a.out │ │ └── CMakeCCompilerId.c │ ├── CompilerIdCXX │ │ ├── a.out │ │ └── CMakeCXXCompilerId.cpp │ ├── Makefile2 │ ├── Makefile.cmake │ ├── progress.marks │ ├── TargetDirectories.txt │ └── Tutorial.dir │ ├── build.make │ ├── cmake_clean.cmake │ ├── DependInfo.cmake │ ├── depend.make │ ├── flags.make │ ├── link.txt │ └── progress.make ├── cmake_install.cmake ├── Makefile ├── tree.cleanlog ├── tree.cmakelog ├── tree.makelog ├── tree.origin ├── tutorial │ ├── CMakeLists.txt │ ├── TutorialConfig.h.in │ └── tutorial.cpp └── TutorialConfig.h 8 directories, 34 files
注意,生成的
TutorialConfig.h
生成路径是当前运行cmake
的路径。tutorial
源码路径内容不变(除非直接在源码路径中运行cmake
)。 -
make
编译$make Scanning dependencies of target Tutorial [100%] Building CXX object CMakeFiles/Tutorial.dir/tutorial.cpp.o Linking CXX executable Tutorial [100%] Built target Tutorial $tree .>tree.makelog $cat tree.makelog . ├── CMakeCache.txt ├── CMakeFiles │ ├── CMakeCCompiler.cmake │ ├── cmake.check_cache │ ├── CMakeCXXCompiler.cmake │ ├── CMakeDetermineCompilerABI_C.bin │ ├── CMakeDetermineCompilerABI_CXX.bin │ ├── CMakeDirectoryInformation.cmake │ ├── CMakeOutput.log │ ├── CMakeSystem.cmake │ ├── CMakeTmp │ │ └── CMakeFiles │ │ └── cmTryCompileExec.dir │ ├── CompilerIdC │ │ ├── a.out │ │ └── CMakeCCompilerId.c │ ├── CompilerIdCXX │ │ ├── a.out │ │ └── CMakeCXXCompilerId.cpp │ ├── Makefile2 │ ├── Makefile.cmake │ ├── progress.marks │ ├── TargetDirectories.txt │ └── Tutorial.dir │ ├── build.make │ ├── cmake_clean.cmake │ ├── CXX.includecache │ ├── DependInfo.cmake │ ├── depend.internal │ ├── depend.make │ ├── flags.make │ ├── link.txt │ ├── progress.make │ └── tutorial.cpp.o ├── cmake_install.cmake ├── Makefile ├── tree.cleanlog ├── tree.cmakelog ├── tree.makelog ├── tree.origin ├── tutorial │ ├── CMakeLists.txt │ ├── TutorialConfig.h.in │ └── tutorial.cpp ├── Tutorial └── TutorialConfig.h 8 directories, 38 files