阅读 834

CMake从入门到入门

一、概述

1、CMake作用

CMake是一个跨平台、开源的构建系统。它是一个集软件构建、测试、打包于一身的软件。比如它能根据源码和预先配置好的构建配置文件构建出Visual Studio的.sln文件或者Linux中的Makefile、启动编译过程、启动单元测试、打包可执行文件及依赖到指定目录。

2、CMake优点

  1. 跨平台,支持Windows、Linux、Mac、Android系统;
  2. 扩展性好,支持逻辑控制语法、条件编译等;

二、CMake的Helloworld示例

CMake通过CMakeLists.txt文件配置项目构建过程,该文件通常位于项目根目录。其他还有xxx.cmake格式的文件,这种文件的功能类似C++中的头文件,可以被include进CMakeLists.txt中,实现对构建配置的扩展。

1、项目目录、配置CMakeLists.txt

  • 创建src目录,包含hello.cpp文件;
  • 根目录创建CMakeLists.txt;
  • build目录是空目录,执行构建过程(构建过程会产生一些配置文件,为了防止污染源码,在一个独立文件夹中构建);

上图CMakeLists.txt文件解释:

  • project(hello) 配置项目名为hello;
  • add_executable(hello src/hello.cpp) 配置生成可执行文件,可执行文件名为hello,参与链接的文件是src/hello.cpp

2、生成解决方案

通过使用cmake命令,指定根目录的CMakeLists.txt位置,生成项目解决方案。

以上便生成了Visual Studio的解决方案hello.sln和hello项目的工程配置hello.vcxproj

3、构建

上一步只是生成了解决方案,我们想要的hello.exe还没有生成。可以用图形界面打开hello.vcproj生成,也可以直接通过命令行生成。

在build目录执行 cmake --build .:

三、CMake常用关键字

1、工程管理

(1) include_directory

配置头文件路径,可以同时配置多个路径。比如: include_directory(CMAKE_SOURCE_DIR/include1 CMAKE_CURRENT_SOURCE_DIR/../include2)

上面包含了两个变量CMAKE_SOURCE_DIRCMAKE_CURRENT_SOURCE_DIR

  • CMAKE_SOURCE_DIR:最开始的CMakeLists.txt的路径,比如使用cmake ..构建时,指的是项目根目录下的CMakeLists.txt路径;
  • CMAKE_CURRENT_SOURCE_DIR:当前CMakeLists.txt所在路径(CMakeLists.txt可以有多个);

(2) add_executable、add_library

前者配置如何生成可执行文件,后者配置如何生成库文件。如:

add_executable(可执行文件名 源码列表)
add_library(动态链接库名称 SHARED 源码列表)
add_library(静态链接库名称 STATIC 源码列表)
复制代码

在执行链接时,通常要指定其他链接库。CMake通过library_directory指定链接库路径、通过target_link_libraries指定链接库名,相当于Makefile里面的-L-l如:

library_directory(CMAKE_BINARY_DIR/lib)    # CMAKE_BINARY_DIR是执行cmake命令的目录
target_link_libraries(二进制文件名 链接库名列表)
复制代码

(3) add_subdirectory、include

对于上面helloworld的简单使用,你可能觉得写Makefile更简单,但如果整个解决方案像下面这样,你还会写Makefile吗?

单个解决方案项目太大,CMake使用分而治之解决。通过在每个模块单独使用一个CMake配置文件,在根目录引入这些配置文件。

  • add_subdirectory的参数是一个模块目录。CMake会在该目录下查找CMakeLists.txt文件,并执行里面的配置脚本;
  • include的参数是一个文件名,通常是类似xxx.cmake的文件;

2、开关选项

CMake通过执行cmake命令时的-D选项,控制某一个编译选项的开关。比如有以下CMakeLists.txt

project(hello)
option("ENABLE_FEATURE", "whether enable some feature", OFF)    # 定义一个开关,是否开启某一个指定功能,默认关闭

if(ENABLE_FEATURE)
add_executable(hello src/hello.cpp feature.cpp)    # 假设特定功能就是多链接一个文件
else
add_executable(hello src/hello.cpp)
endif
复制代码

构建时使用cmake .. -DENABLE_FEATURE=ON开启指定功能,若没有-D选项或者把ON改为OFF,则关闭指定功能。

option定义的选项只能在CMakeLists.txt中使用如果想在源码中识别是否定义了某一个开关呢? add_definition可以完成该功能。比如:

if(ENABLE_FEATURE)
add_definition(FEATURE)    # 如果ENABLE_FEATURE开启,则定义FEATURE宏
elsec
endif
复制代码

通过增加宏定义,在源码中判断该宏达到同样的开关作用。

3、调试信息

(1) message

打印信息。格式:message(<mode> "debug info: value of arg: ${arg}")。 message函数至少有以下几种模式(mode):STATUSINFOWARNINGFATAL_ERROR。其中FATAL_ERROR模式会停止构建并以失败退出。

4、其他CMake变量

(1) CMAKE_C_FLAGS、CMAKE_CXX_FLAGS

分辨控制C/C++编译选项。比如: set(CMAKE_CXX_FLAGS "std-c++11 ${CMAKE_CXX_FLAGS}") # 扩展CMAKE_CXX_FLAGS的值,增加对C++11的支持。

(2) CMAKE_BUILD_TYPE

指定构建类型,通过在使用cmake命令构建时传入。比如: cmake .. -DCMAKE_BUILD_TYPE=Release