该文档是基于CMake的官方教程翻译而来,并稍微添加了自己的理解:
cmake的官方网站为:CMake Tutorial
The CMake tutorial provides a step-by-step guide that covers common build system issues that CMake helps address. Seeing how various topics all work together in an example project can be very helpful.
CMake 教程提供了一个循序渐进的指南,涵盖了 CMake 可帮助解决的常见构建系统问题。在一个示例项目中了解各个主题是如何协同工作的,会非常有帮助。
The tutorial source code examples are available in this archive. Each step has its own subdirectory containing code that may be used as a starting point. The tutorial examples are progressive so that each step provides the complete solution for the previous step.
本文档中提供了教程源代码示例。每个步骤都有自己的子目录,其中包含可用作起点的代码。教程示例是循序渐进的,因此每一步都提供了前一步的完整解决方案。
Where do I start with CMake? This step will provide an introduction to some of CMake’s basic syntax, commands, and variables. As these concepts are introduced, we will work through three exercises and create a simple CMake project.
如何开始使用 CMake?本步骤将介绍 CMake 的一些基本语法、命令和变量。在介绍这些概念的同时,我们将通过三个练习来创建一个简单的 CMake 项目。
Each exercise in this step will start with some background information. Then, a goal and list of helpful resources are provided. Each file in the Files to Edit section is in the Step1 directory and contains one or more TODO comments. Each TODO represents a line or two of code to change or add. The TODO s are intended to be completed in numerical order, first complete TODO 1 then TODO 2, etc. The Getting Started section will give some helpful hints and guide you through the exercise. Then the Build and Run section will walk step-by-step through how to build and test the exercise. Finally, at the end of each exercise the intended solution is discussed.
本步骤中的每个练习都会先介绍一些背景信息。然后是目标和有用资源列表。要编辑的文件 "部分中的每个文件都位于 Step1 目录中,包含一个或多个 TODO 注释。每个 TODO 都代表需要修改或添加的一两行代码。TODO 按数字顺序完成,首先完成 TODO 1,然后完成 TODO 2 等。入门 "部分将提供一些有用的提示,并指导你完成练习。然后,在 "构建和运行 "部分,将逐步介绍如何构建和测试练习。最后,在每个练习的结尾都会讨论预期的解决方案。
Also note that each step in the tutorial builds on the next. So, for example, the starting code for Step2 is the complete solution to Step1.
还请注意,教程中的每一步都是在下一步的基础上进行的。例如,步骤 2 的起始代码就是步骤 1 的完整解决方案。
The most basic CMake project is an executable built from a single source code file. For simple projects like this, a CMakeLists.txt file with three commands is all that is required.
最基本的 CMake 项目是由单个源代码文件构建的可执行文件。对于像这样的简单项目,只需一个包含三条命令的 CMakeLists.txt 文件即可。
Note: Although upper, lower and mixed case commands are supported by CMake, lower case commands are preferred and will be used throughout the tutorial.
注意:虽然 CMake 支持大写、小写和混合大小写命令,但整个教程都将使用小写命令。
Any project’s top most CMakeLists.txt must start by specifying a minimum CMake version using the cmake_minimum_required() command. This establishes policy settings and ensures that the following CMake functions are run with a compatible version of CMake.
任何项目的 CMakeLists.txt 文件都必须首先使用 cmake_minimum_required()
命令指定 CMake 的最小版本。这将建立策略设置,并确保以下 CMake 功能在兼容的 CMake 版本下运行。
To start a project, we use the project() command to set the project name. This call is required with every project and should be called soon after cmake_minimum_required(). As we will see later, this command can also be used to specify other project level information such as the language or version number.
要启动一个项目,我们需要使用 project() 命令来设置项目名称。每个项目都需要调用该命令,并且应在 cmake_minimum_required() 之后尽快调用。稍后我们将看到,该命令还可用于指定其他项目级信息,如语言或版本号。
Finally, the add_executable() command tells CMake to create an executable using the specified source code files.
最后,add_executable()
命令告诉 CMake 使用指定的源代码文件创建一个可执行文件。
Understand how to create a simple CMake project.
了解如何创建一个简单的 CMake 项目。
The source code for tutorial.cxx is provided in the Help/guide/tutorial/Step1 directory and can be used to compute the square root of a number. This file does not need to be edited in this step.
在 Help/guide/tutorial/Step1 目录中提供了 tutorial.cxx 的源代码,可用于计算一个数字的平方根。本步骤无需编辑该文件。
In the same directory is a CMakeLists.txt file which you will complete. Start with TODO 1 and work through TODO 3.
在同一目录下有一个 CMakeLists.txt 文件,您将完成该文件。从 TODO 1 开始,直到 TODO 3。
Once TODO 1 through TODO 3 have been completed, we are ready to build and run our project! First, run the cmake executable or the cmake-gui to configure the project and then build it with your chosen build tool.
完成 TODO 1 到 TODO 3 后,我们就可以构建和运行我们的项目了!首先,运行 cmake 可执行文件或 cmake-gui 配置项目,然后使用所选的构建工具构建项目。
For example, from the command line we could navigate to the Help/guide/tutorial directory of the CMake source code tree and create a build directory:
例如,我们可以从命令行导航到 CMake 源代码树的 Help/guide/tutorial 目录,并创建一个构建目录:
mkdir Step1_build
Next, navigate to that build directory and run cmake to configure the project and generate a native build system:
接下来,导航到构建目录,运行 cmake 配置项目并生成本地构建系统:
cd Step1_build
cmake ../Step1
Then call that build system to actually compile/link the project:
然后调用构建系统来实际编译/链接项目:
cmake --build .
Finally, try to use the newly built Tutorial with these commands:
最后,尝试用这些命令使用新构建的 Tutorial:
Tutorial 4294967296
Tutorial 10
Tutorial
As mentioned above, a three line CMakeLists.txt is all that we need to get up and running. The first line is to use cmake_minimum_required() to set the CMake version as follows:
如上所述,我们只需三行 CMakeLists.txt 即可开始运行。第一行是使用 cmake_minimum_required()设置 CMake 版本,如下所示:
TODO 1: CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
The next step to make a basic project is to use the project() command as follows to set the project name:
制作基本项目的下一步是使用如下的 project() 命令设置项目名称:
TODO 2: CMakeLists.txt
project(Tutorial)
The last command to call for a basic project is add_executable(). We call it as follows:
基本项目需要调用的最后一条命令是 add_executable()。调用方法如下
TODO 3: CMakeLists.txt
add_executable(Tutorial tutorial.cxx)
# TODO 1: Set the minimum required version of CMake to be 3.10
cmake_minimum_required(VERSION 3.10)
# TODO 2: Create a project named Tutorial
project(Tutorial)
# TODO 3: Add an executable called Tutorial to the project
add_executable(Tutorial tutorial.cxx)
// A simple program that computes the square root of a number
#include
#include // TODO 5: Remove this line
#include
#include
// TODO 11: Include TutorialConfig.h
int main(int argc, char* argv[])
{
if (argc < 2) {
// TODO 12: Create a print statement using Tutorial_VERSION_MAJOR
// and Tutorial_VERSION_MINOR
std::cout << "Usage: " << argv[0] << " number" << std::endl;
return 1;
}
// convert input to double
// TODO 4: Replace atof(argv[1]) with std::stod(argv[1])
const double inputValue = atof(argv[1]);
// calculate square root
const double outputValue = sqrt(inputValue);
std::cout << "The square root of " << inputValue << " is " << outputValue
<< std::endl;
return 0;
}
CMake has some special variables that are either created behind the scenes or have meaning to CMake when set by project code. Many of these variables start with CMAKE_. Avoid this naming convention when creating variables for your projects. Two of these special user settable variables are CMAKE_CXX_STANDARD and CMAKE_CXX_STANDARD_REQUIRED. These may be used together to specify the C++ standard needed to build the project.
CMake 有一些特殊的变量,它们或者是在幕后创建的,或者是在项目代码中设置时对 CMake 有意义的。其中许多变量以 CMAKE_ 开头。在为您的项目创建变量时,请避免使用这种命名约定。其中两个特殊的用户可设置变量是 CMAKE_CXX_STANDARD 和 CMAKE_CXX_STANDARD_REQUIRED。这两个变量可以一起使用,以指定构建项目所需的 C++ 标准。
Add a feature that requires C++11.
添加一项需要 C++11 的功能。
Continue editing files in the Step1 directory. Start with TODO 4 and complete through TODO 6.
继续编辑 Step1 目录中的文件。从 TODO 4 开始,完成 TODO 6。
First, edit tutorial.cxx by adding a feature that requires C++11. Then update CMakeLists.txt to require C++11.
首先,编辑 tutorial.cxx,添加需要 C++11 的功能,然后更新 CMakeLists.txt,使其需要 C++11。
Let’s build our project again. Since we already created a build directory and ran CMake for Exercise 1, we can skip to the build step:
让我们再次构建项目。由于我们已经在练习 1 中创建了构建目录并运行了 CMake,因此可以跳过构建步骤:
cd Step1_build
cmake --build .
Now we can try to use the newly built Tutorial with same commands as before:
现在,我们可以尝试使用新构建的 Tutorial,命令与之前的相同:
Tutorial 4294967296
Tutorial 10
Tutorial
We start by adding some C++11 features to our project by replacing atof with std::stod in tutorial.cxx. This looks like the following:
我们首先在 tutorial.cxx 中将 atof 替换为 std::stod,为项目添加一些 C++11 功能。如下所示:
TODO 4: tutorial.cxx
const double inputValue = std::stod(argv[1]);
To complete TODO 5, simply remove #include .
要完成 TODO 5,只需删除 #include 即可。
We will need to explicitly state in the CMake code that it should use the correct flags. One way to enable support for a specific C++ standard in CMake is by using the CMAKE_CXX_STANDARD variable. For this tutorial, set the CMAKE_CXX_STANDARD variable in the CMakeLists.txt file to 11 and CMAKE_CXX_STANDARD_REQUIRED to True. Make sure to add the CMAKE_CXX_STANDARD declarations above the call to add_executable().
我们需要在 CMake 代码中明确说明它应该使用正确的标志。在 CMake 中启用对特定 C++ 标准的支持的一种方法是使用 CMAKE_CXX_STANDARD 变量。在本教程中,将 CMakeLists.txt 文件中的 CMAKE_CXX_STANDARD 变量设为 11,并将 CMAKE_CXX_STANDARD_REQUIRED 设为 True。确保将 CMAKE_CXX_STANDARD 声明添加到 add_executable() 的调用之上。
TODO 6: CMakeLists.txt
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# TODO 1: Set the minimum required version of CMake to be 3.10
cmake_minimum_required(VERSION 3.10)
# TODO 2: Create a project named Tutorial
project(Tutorial)
# TODO 6: Set the variable CMAKE_CXX_STANDARD to 11
# and the variable CMAKE_CXX_STANDARD_REQUIRED to True
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STAND_REQUIRED True)
# TODO 3: Add an executable called Tutorial to the project
add_executable(Tutorial tutorial.cxx)
// A simple program that computes the square root of a number
#include
// #include // TODO 5: Remove this line
#include
#include
// TODO 11: Include TutorialConfig.h
int main(int argc, char* argv[])
{
if (argc < 2) {
// TODO 12: Create a print statement using Tutorial_VERSION_MAJOR
// and Tutorial_VERSION_MINOR
std::cout << "Usage: " << argv[0] << " number" << std::endl;
return 1;
}
// convert input to double
// TODO 4: Replace atof(argv[1]) with std::stod(argv[1])
//const double inputValue = atof(argv[1]);
const double inputValue = std::stod(argv[1]);
// calculate square root
const double outputValue = sqrt(inputValue);
std::cout << "The square root of " << inputValue << " is " << outputValue
<< std::endl;
return 0;
}
Sometimes it may be useful to have a variable that is defined in your CMakelists.txt file also be available in your source code. In this case, we would like to print the project version.
有时,在 CMakelists.txt 文件中定义的变量也可以在源代码中使用。在这种情况下,我们希望打印项目版本。
One way to accomplish this is by using a configured header file. We create an input file with one or more variables to replace. These variables have special syntax which looks like @VAR@. Then, we use the configure_file() command to copy the input file to a given output file and replace these variables with the current value of VAR in the CMakelists.txt file.
其中一种方法是使用配置头文件。我们创建一个输入文件,其中包含一个或多个要替换的变量。这些变量有特殊的语法,看起来像 @VAR@。然后,我们使用 configure_file() 命令将输入文件复制到给定的输出文件,并用 CMakelists.txt 文件中 VAR 的当前值替换这些变量。
While we could edit the version directly in the source code, using this feature is preferred since it creates a single source of truth and avoids duplication.
虽然我们可以直接在源代码中编辑版本,但我们更倾向于使用这一功能,因为它可以创建一个单一的真相源,并避免重复。
Define and report the project’s version number.
定义和报告项目版本号。
Continue to edit files from Step1. Start on TODO 7 and complete through TODO 12. In this exercise, we start by adding a project version number in CMakeLists.txt. In that same file, use configure_file() to copy a given input file to an output file and substitute some variable values in the input file content.
继续编辑步骤 1 中的文件。从 TODO 7 开始,完成 TODO 12。在本练习中,我们首先在 CMakeLists.txt 中添加项目版本号。在同一文件中,使用 configure_file() 将给定的输入文件复制到输出文件,并在输入文件内容中替换一些变量值。
Next, create an input header file TutorialConfig.h.in defining version numbers which will accept variables passed from configure_file().
接下来,创建一个输入头文件 TutorialConfig.h.in,定义版本号,接受 configure_file() 传递的变量。
Finally, update tutorial.cxx to print out its version number.
最后,更新 tutorial.cxx,打印出版本号。
Let’s build our project again. As before, we already created a build directory and ran CMake so we can skip to the build step:
让我们再次构建项目。和之前一样,我们已经创建了一个构建目录并运行了 CMake,因此可以跳过构建步骤:
cd Step1_build
cmake --build .
Verify that the version number is now reported when running the executable without any arguments.
验证在不带任何参数的情况下运行可执行文件时,是否会报告版本号。
执行可执行程序会输出如下的log:
Tutorial Version 1.0
Usage: ./Tutorial number
In this exercise, we improve our executable by printing a version number. While we could do this exclusively in the source code, using CMakeLists.txt lets us maintain a single source of data for the version number.
在本练习中,我们将通过打印版本号来改进我们的可执行程序。虽然我们可以只在源代码中打印版本号,但使用 CMakeLists.txt 可以让我们保持版本号的单一数据源。
First, we modify the CMakeLists.txt file to use the project() command to set both the project name and version number. When the project() command is called, CMake defines Tutorial_VERSION_MAJOR and Tutorial_VERSION_MINOR behind the scenes.
首先,我们修改 CMakeLists.txt 文件,使用 project() 命令来设置项目名称和版本号。调用 project() 命令时,CMake 会在幕后定义 Tutorial_VERSION_MAJOR 和 Tutorial_VERSION_MINOR。
TODO 7: CMakeLists.txt
project(Tutorial VERSION 1.0)
Then we used configure_file() to copy the input file with the specified CMake variables replaced:
然后,我们使用 configure_file() 复制输入文件,并替换指定的 CMake 变量:
TODO 8: CMakeLists.txt
configure_file(TutorialConfig.h.in TutorialConfig.h)
Since the configured file will be written into the project binary directory, we must add that directory to the list of paths to search for include files.
由于配置文件将写入项目二进制目录,我们必须将该目录添加到搜索包含文件的路径列表中。
Note: Throughout this tutorial, we will refer to the project build and the project binary directory interchangeably. These are the same and are not meant to refer to a bin/ directory.
注意:在本教程中,我们将交替使用项目构建目录和项目二进制目录。它们是相同的,并不是指 bin/ 目录。
We used target_include_directories() to specify where the executable target should look for include files.
我们使用 target_include_directories() 来指定目标可执行文件应在何处查找包含文件。
TODO 9: CMakeLists.txt
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
)
TutorialConfig.h.in is the input header file to be configured. When configure_file() is called from our CMakeLists.txt, the values for @Tutorial_VERSION_MAJOR@ and @Tutorial_VERSION_MINOR@ will be replaced with the corresponding version numbers from the project in TutorialConfig.h.
TutorialConfig.h.in 是要配置的输入头文件。当从 CMakeLists.txt 调用 configure_file() 时,@Tutorial_VERSION_MAJOR@ 和 @Tutorial_VERSION_MINOR@ 的值将被替换为 TutorialConfig.h 中项目的相应版本号。
TODO 10: TutorialConfig.h.in
// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
Next, we need to modify tutorial.cxx to include the configured header file, TutorialConfig.h.
接下来,我们需要修改 tutorial.cxx,以包含配置的头文件 TutorialConfig.h。
TODO 11: tutorial.cxx
#include "TutorialConfig.h"
Finally, we print out the executable name and version number by updating tutorial.cxx as follows:
最后,我们对 tutorial.cxx 进行如下更新,打印出可执行文件的名称和版本号:
TODO 12 : tutorial.cxx
if (argc < 2) {
// report version
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
<< Tutorial_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
return 1;
}
# TODO 1: Set the minimum required version of CMake to be 3.10
cmake_minimum_required(VERSION 3.10)
# TODO 2: Create a project named Tutorial
project(Tutorial)
# TODO 7: Set the project version number as 1.0 in the above project command
project(Tutorial VERSION 1.0)
# TODO 6: Set the variable CMAKE_CXX_STANDARD to 11
# and the variable CMAKE_CXX_STANDARD_REQUIRED to True
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STAND_REQUIRED True)
# TODO 8: Use configure_file to configure and copy TutorialConfig.h.in to
# TutorialConfig.h
configure_file(TutorialConfig.h.in TutorialConfig.h)
# TODO 3: Add an executable called Tutorial to the project
add_executable(Tutorial tutorial.cxx)
# TODO 9: Use target_include_directories to include ${PROJECT_BINARY_DIR}
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
)
// A simple program that computes the square root of a number
#include
// #include // TODO 5: Remove this line
#include
#include
// TODO 11: Include TutorialConfig.h
#include "TutorialConfig.h"
int main(int argc, char* argv[])
{
if (argc < 2) {
// TODO 12: Create a print statement using Tutorial_VERSION_MAJOR
// and Tutorial_VERSION_MINOR
// report version
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
<< Tutorial_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
return 1;
}
// convert input to double
// TODO 4: Replace atof(argv[1]) with std::stod(argv[1])
//const double inputValue = atof(argv[1]);
const double inputValue = std::stod(argv[1]);
// calculate square root
const double outputValue = sqrt(inputValue);
std::cout << "The square root of " << inputValue << " is " << outputValue
<< std::endl;
return 0;
}
// the configured options and settings for Tutorial
// TODO 10: Define Tutorial_VERSION_MAJOR and Tutorial_VERSION_MINOR
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
经过cmake --build .
构建之后生成的TutorialConfig.h
内容如下所示:
// the configured options and settings for Tutorial
// TODO 10: Define Tutorial_VERSION_MAJOR and Tutorial_VERSION_MINOR
#define Tutorial_VERSION_MAJOR 1
#define Tutorial_VERSION_MINOR 0