1步:一个基本出发点
最基础项目是基于源码的一个可执行构建.对简单项目.三行CMakeLists.txt就满足了.
在步1路径下创建如下CMakeLists.txt文件:
cmake_minimum_required(VERSION 3.10)
//设置项目名
project(Tutorial)
//添加可执行文件
add_executable(Tutorial tutorial.cxx)
注意,在CMakeLists.txt文件中,命令都使用小写.CMake命令支持大小写混用.tutorial.cxx的源码在步1目录下,可用它计算平方根.
添加版本号&配置头文件
先给项目和可执行文件提供版本号.尽管可在源码中添加版本号,但使用CMakeLists.txt更灵活.
首先,修改CMakeLists.txt,用project()命令来设置项目名和版本号.
cmake_minimum_required(VERSION 3.10)
//设置项目名和版本
project(Tutorial VERSION 1.0)
然后制定头文件来传递版本号到源码里:
configure_file(TutorialConfig.h.in TutorialConfig.h)
因为会把指定文件写入二进制结构中,必须添加这一目录到搜索include文件的列表中.在CMakeLists.txt文件尾写入:
target_include_directories(Tutorial PUBLIC"${PROJECT_BINARY_DIR}"
)
使用喜欢的IDE,在源路径下创建TutorialConfig.h.in,并写入:
//教程的`配置选项和设置`
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
CMake生成该头文件时,会自动替换@Tutorial_VERSION_MAJOR@和@Tutorial_VERSION_MINOR@的值.
接着调整tutorial.cxx来包含TutorialConfig.h头文件.
最后,如下更新tutorial.cxx来打印可执行文件名和版本号:
if (argc < 2) {
//报告版本
std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."<< Tutorial_VERSION_MINOR << std::endl;
std::cout << "Usage: " << argv[0] << " number" << std::endl;
return 1;
}
指定C++标准
接着,在tutorial.cxx中,替换atof为std::stod来给项目增加一些C++11特性.同时,移除#include.
const double inputValue = std::stod(argv[1]);
要在CMake代码中显式声明,以使用正确配置.最简单方式是,在CMake中用CMAKE_CXX_STANDARD以启用支持指定C++版本标准.
这里.将CMakeLists.txt中的CMAKE_CXX_STANDARD设为11,CMAKE_CXX_STANDARD_REQUIRED设为True.并在add_executable前声明CMAKE_CXX_STANDARD.
cmake_minimum_required(VERSION 3.10)
//设置项目名和版本
project(Tutorial VERSION 1.0)
//指定`C++`标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
构建与测试
运行cmake可执行文件,或cmake-gui来配置项目,然后用所选构建工具构建它.
如,从命令行中,要进入Help/guide/tutorial目录下,并创建一个build目录:
mkdir 步1构建
之后,进入build目录,然后运行CMake来配置项目,并生成原生构建系统:
cd 步1构建
cmake ../步1
然后调用该构建系统来实际编译/链接项目:
cmake --build .
最后,试用下述命令来使用新构建的Tutorial:
Tutorial 4294967296
Tutorial 10
Tutorial
步2:添加库
现在给项目添加一个包含计算数字平方根的实现库.可执行文件就可用库而非编译器提供的平方根函数.
这里,在MathFunctions子目录下放置库.该目录已包含了一个MathFunctions.h头文件,也包含了一个mysqrt.cxx源文件.
源文件中包含提供了编译器中sqrt相近功能的叫mysqrt的函数.
在MathFunctions目录中,新增下面单行CMakeLists.txt文件:
add_library(MathFunctions mysqrt.cxx)
为了使用新库,在顶级的CMakeLists.txt中加入add_subdirectory()来构建库.
给可执行文件加入新库,并按包含目录添加MathFunctions,这样就可查询得到mqsqrt.h头文件了.顶级CMakeLists.txt的最后几行应该如下:
//添加`MathFunctions`库
add_subdirectory(MathFunctions)
//添加可执行文件
add_executable(Tutorial tutorial.cxx)
target_link_libraries(Tutorial PUBLIC MathFunctions)
//在`包含文件`的`搜索路径`中添加`二叉树`,以便找到`TutorialConfig.h`
target_include_directories(Tutorial PUBLIC"${PROJECT_BINARY_DIR}""${PROJECT_SOURCE_DIR}/MathFunctions"
)
接着让MathFunctions库可作为可选项.在大型项目中这很常见.第一步,是在顶层CMakeLists.txt中增加选项:
option(USE_MYMATH "用这里实现" ON)
//配置头文件以把某些`CMake`设置传递到源码
configure_file(TutorialConfig.h.in TutorialConfig.h)
会在cmake-gui或ccmake中显示这一选项,默认值为ON,用户也可修改它.会在缓存中存储这一选项,用户无需每次都设置.
下一项更改是,把MathFunctions库的构建和链接设置成可选.在顶级CMakeLists.txt尾,如下修改:
if(USE_MYMATH)add_subdirectory(MathFunctions)list(APPEND EXTRA_LIBS MathFunctions)list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")
endif()
//添加可执行文件
add_executable(Tutorial tutorial.cxx)
target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})
//在包含文件的搜索路径中添加二叉树,以便找到`TutorialConfig.h`
target_include_directories(Tutorial PUBLIC"${PROJECT_BINARY_DIR}"${EXTRA_INCLUDES}
)
EXTRA_LIBS变量,收集了之后可在可执行文件中链接的可选库.EXTRA_INCLUDES变量也相应的收集可选头文件.
处理很多可选项时,这是经典处理方式.下一步会用新方式来做.
相应源码改动就比较直接了.首先,在tutorial.cxx中,如果需要则包含MathFunctions.h:
#ifdef USE_MYMATH
//包括`"MathFunctions.h"`
#endif
然后在同一个文件中,让USE_MYMATH变量控制函数的选择:
#ifdef USE_MYMATHconst double outputValue = mysqrt(inputValue);
#elseconst double outputValue = sqrt(inputValue);
#endif
因为现在源码中需要USE_MYMATH变量,可在TutorialConfig.h.in文件中加入:
#cmakedefine USE_MYMATH
为什么在USE_MYMATH选项后,配置TutorialConfig.h.in.如果交换这两行会怎样?
运行cmake或cmake-gui配置项目,然后构建,再运行构建出的可执行文件.
现在更新USE_MYMATH的值.最好是使用cmake-gui或终端中的ccmake.或如果想在命令行中修改这一选项:
cmake ../步2 -DUSE_MYMATH=OFF
重构然后运行.
哪个函数结果更好,sqrt还是mysqrt?
步3:对库添加使用依赖
使用依赖可更好控制库或可执行程序使用的链接和包含.CMake也提供了更充分控制可及属性.控制依赖的重要命令包括:
target_compile_definitions
target_compile_options
target_include_directories
target_link_libraries
用现代CMake的方式重构步2中的依赖部分.
首先除了MathFunctions自身,明确链接到MathFunctions的对象都需要包含当前源目录.
所以它可作为一个INTERFACE使用依赖.
记住INTERFACE指的是那些消费者需要而生产者不需要的东西.在MathFunctions/CMakeLists.txt尾加入:
target_include_directories(MathFunctionsINTERFACE${CMAKE_CURRENT_SOURCE_DIR}
)
现在已指定了MathFunctions的使用依赖,就可安全地移除顶级CMakeLists.txt文件中的EXTRA_INCLUDES变量:
if(USE_MYMATH)add_subdirectory(MathFunctions)list(APPEND EXTRA_LIBS MathFunctions)
endif()
及:
target_include_directories(Tutorial PUBLIC"${PROJECT_BINARY_DIR}"
)
完成后,运行cmake或cmake-gui来配置项目,并在build目录下cmake --build .构建运行即可.