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 .
构建运行即可.