CMake Tutorial 巡礼(1)_ 基础的起点
这是本系列的第二篇。
从这篇开始我们将进入CMake的实际学习操作。
本章导读
第一步:一个基础的起点
The most basic project is an executable built from source code files. For simple projects, a three line
CMakeLists.txt
file is all that is required. This will be the starting point for our tutorial. Create aCMakeLists.txt
file in theStep1
directory that looks like:
最基本的项目是从源代码文件构建可执行文件。对最简单的项目,一个三行的CMakeLists.txt
文件就足够了。这也是我们Tutorial的起点。如下这样在Step1
文件夹中新建一个CMakeLists.txt
文件:
cmake_minimum_required(VERSION 3.10)
# set the project name 设置项目名称
project(Tutorial)
# add the executable 添加可执行文件
add_executable(Tutorial tutorial.cxx)
小白按:在CMakeLists.txt中,组织语句有点类似于命令行,而注释部分则由#
符号开头。
Note that this example uses lower case commands in the
CMakeLists.txt
file. Upper, lower, and mixed case commands are supported by CMake. The source code fortutorial.cxx
is provided in theStep1
directory and can be used to compute the square root of a number.
注意到此例中在CMakeLists.txt
文件中使用小写字母命令。CMake支持大写、小写、大小写混用的命令。tutorial.cxx
源码在Step1
路径中提供,可以用来计算一个数的平方根。
// A simple program that computes the square root of a number
// 一个计算平方根的简单程序
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <string>
int main(int argc, char* argv[])
{
if (argc < 2) {
std::cout << "Usage: " << argv[0] << " number" << std::endl;
return 1;
}
// convert input to double 将输入转换成double类型
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;
}
编译运行
That’s all that is needed - we can build and run our project now! First, run the
cmake
executable or thecmake-gui
to configure the project and then build it with your chosen build tool.
所有的所需如上,接着,我们可以编译和运行我们的项目了。首先,运行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
路径下,新建一个build路径:
mkdir Step1_build
小白按:读到这里的时候小白一头雾水:什么叫“CMake源代码树”?哪里去找这个路径?后来从字面意思上,找了一下github上CMake的源码托管仓库才明白:这句话所指的位置可以参考Help/guide/tutorial。其实这句话就是指CMake在github上的托管仓库中的源代码文件路径。
Next, navigate to the build directory and run CMake to configure the project and generate a native build system:
然后,切换到build路径,运行CMake来指定项目,生成一个本地的编译系统:
cd Step1_build
cmake ../Step1
Then call that build system to actually compile/link the project:
然后,调用编译系统来实际编译/链接这个项目:
cmake --build .
小白按: build后面空一格,然后是一个点,意思为编译当前路径。
Finally, try to use the newly built Tutorial with these commands:
最后,通过以下命令尝试使用新编译的Tutorial:
Tutorial 4294967296
Tutorial 10
Tutorial
小白按:关于这一段,小白也进行了实操,这可以说是CMake里的Hello world了。注意生成的可执行文件在Step1_build/Debug
目录下。
对以上的三条命令的执行结果,小白这边的结果为:
The square root of 4.29497e+09 is 65536
The square root of 10 is 3.16228
Usage: Tutorial number
添加版本号并指定头文件
The first feature we will add is to provide our executable and project with a version number. While we could do this exclusively in the source code, using
CMakeLists.txt
provides more flexibility.
我们将要添加的第一个特征是为可执行文件和项目添加一个版本号。尽管我们可以专门地在源代码中实现,使用CMakeLists.txt
提供了更大的灵活性。
First, modify the
CMakeLists.txt
file to use theproject()
command to set the project name and version number.
首先,修改CMakeLists.txt
,使用project()
命令来指定项目名称和版本号。
cmake_minimum_required(VERSION 3.10)
# set the project name and version
project(Tutorial VERSION 1.0)
Then, configure a header file to pass the version number to the source code:
接着,指定一个头文件,把版本号传递到源代码中:
configure_file(TutorialConfig.h.in TutorialConfig.h)
小白按: TutorialConfig.h.in文件可能是一个中间文件,可以连接起CMakeLists.txt和头文件。
Since the configured file will be written into the binary tree, we must add that directory to the list of paths to search for include files. Add the following lines to the end of the
CMakeLists.txt
file:
由于指定的文件将会被写入二进制树,我们必须将包含文件的路径添加进去以便检索。在CMakeLists.txt
文件的末尾添加以下行:
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
)
Using your favorite editor, create
TutorialConfig.h.in
in the source directory with the following contents:
使用你最喜欢的编辑器,在源代码路径中新建TutorialConfig.h.in
文件,在文件中填写以下内容:
// the configured options and settings for Tutorial
// Tutorial中指定选项和设置
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
小白按:果不其然,TutorialConfig.h.in
文件通过define
宏定义将版本号传递出去。
When CMake configures this header file the values for
@Tutorial_VERSION_MAJOR@
and@Tutorial_VERSION_MINOR@
will be replaced.
当CMake指定头文件,则@Tutorial_VERSION_MAJOR@
和@Tutorial_VERSION_MINOR@
就会被替换。
Next modify
tutorial.cxx
to include the configured header file,TutorialConfig.h
.
接下来修改tutorial.cxx
来包含指定的头文件,即TutorialConfig.h
。
Finally, let’s print out the executable name and version number by updating
tutorial.cxx
as follows:
最后,让我们打印出可执行文件的名称和版本号,像下面这样更新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;
}
小白按:小白按照说明的方式进行修改,以下呈现修改后的文件全貌
CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
# set the project name
project(Tutorial VERSION 1.0)
configure_file(TutorialConfig.h.in TutorialConfig.h)
# add the executable
add_executable(Tutorial tutorial.cxx)
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
)
tutorial.cxx
// A simple program that computes the square root of a number
// 一个计算平方根的简单程序
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <string>
#include "TutorialConfig.h"
int main(int argc, char* argv[])
{
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;
}
// convert input to double 转换成double类型
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;
}
指定C++标准
小白按:C++是一种古老而仍然活跃的语言,随着时代的进步,它也在不断地自我更新,C++委员会为它制定了很多标准,目前已有的C++98 C++11 C++14 C++17 C++20 等标准,不同的C++编译器对标准的支持不同,例如VS2013的MSVC编译器就只有部分支持C++11的标准,而VS2015开始的MSVC编译器则开始全面支持C++11标准。
Next let’s add some C++11 features to our project by replacing
atof
withstd::stod
intutorial.cxx
. At the same time, remove#include <cstdlib>
.
接下来让我们向项目中添加一些C++11的特性,通过把tutorial.cxx
中的atof
替换成std::stod
。与此同时,移除#include <cstdlib>
。
const double inputValue = std::stod(argv[1]);
We will need to explicitly state in the CMake code that it should use the correct flags. The easiest way to enable support for a specific C++ standard in CMake is by using the
CMAKE_CXX_STANDARD
variable. For this tutorial, set theCMAKE_CXX_STANDARD
variable in theCMakeLists.txt
file to11
andCMAKE_CXX_STANDARD_REQUIRED
toTrue
. Make sure to add theCMAKE_CXX_STANDARD
declarations above the call toadd_executable
.
我们需要在CMake源码中显式地声明,从而让他使用正确的标志位。在CMake中指定一个特别的C++标准的最简单方法是使用CMAKE_CXX_STANDARD
变量。对于本tutorial,将CMakeLists.txt
文件中的CMAKE_CXX_STANDARD
变量指定为11
,将CMAKE_CXX_STANDARD_REQUIRED
指定为True
。确保在调用add_executable
之前添加CMAKE_CXX_STANDARD
的声明。
cmake_minimum_required(VERSION 3.10)
# set the project name and version 设置项目名称和版本号
project(Tutorial VERSION 1.0)
# specify the C++ standard 指定C++标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
小白按:小白按照tutorial所述的方式来进行修改,以下给出修改后的文件全貌
CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
# set the project name 指定项目的名称
project(Tutorial VERSION 1.0)
configure_file(TutorialConfig.h.in TutorialConfig.h)
# specify the C++ standard 指定C++标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# add the executable 添加可执行文件
add_executable(Tutorial tutorial.cxx)
target_include_directories(Tutorial PUBLIC
"${PROJECT_BINARY_DIR}"
)
tutorial.cxx
// A simple program that computes the square root of a number
// 一个计算平方根的简单程序
#include <cmath>
#include <iostream>
#include <string>
#include "TutorialConfig.h"
int main(int argc, char* argv[])
{
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;
}
// convert input to double 转换成double类型
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;
}
重新编译
Let’s build our project again. We already created a build directory and ran CMake, so we can skip to the build step
让我们重新编译项目,我们已经建立了一个编译路径来运行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
Check that the version number is now reported when running the executable without any arguments.
在最后一句不带参数的可执行文件调用时,看看现在输出的版本号。
小白按:小白按步骤实现并测试的结果为:
The square root of 4.29497e+09 is 65536
The square root of 10 is 3.16228
Tutorial Version 1.0
Usage: Tutorial number
我们来看一下编译后Step1_build路径下的文件情况:
可以看到TutorialConfig.h
文件,这是由Cmake生成的,我们只提供了TutorialConfig.h.in
文件。
至此,我们完成了CMake Tutorial的第一个章节的学习,内容还是挺多的,但确实也不复杂。下一个章节我们将开始学习如何为项目添加一个第三方库。
【水平所限,错漏难免,创作不易,轻喷勿骂】