GNU开发工具——CMake快速入门
Posted 悦码
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GNU开发工具——CMake快速入门相关的知识,希望对你有一定的参考价值。
一、CMake简介
不同Make工具,如GNU Make、QT的qmake、微软的MS nmake、BSD Make(pmake)等,遵循着不同的规范和标准,所执行的Makefile格式也不同。如果软件想跨平台,必须要保证能够在不同平台编译。而如果使用Make工具,必须为不同的Make工具编写不同的Makefile。
CMake是一个比Make工具更高级的编译配置工具,是一个跨平台的、开源的构建系统(BuildSystem)。CMake允许开发者编写一种平台无关的CMakeList.txt文件来定制整个编译流程,然后再根据目标用户的平台进一步生成所需的本地化Makefile和工程文件,如:为Unix平台生成Makefile文件(使用GCC编译),为Windows MSVC生成projects/workspaces(使用VS IDE编译)或Makefile文件(使用nmake编译)。使用CMake作为项目架构系统的知名开源项目有VTK、ITK、KDE、OpenCV、OSG等。
二、CMake管理工程
在Linux平台下使用CMake生成Makefile并编译的流程如下:
A、编写CMake配置文件CMakeLists.txt
B、执行命令cmake PATH生成Makefile,PATH是CMakeLists.txt所在的目录。
C、使用make命令进行编译。
三、单个源文件工程
1、源文件编写
假设项目test中只有一个main.cpp源文件,程序用途是计算一个数的指数幂。
2、编写CMakeLists.txt
在main.cpp源文件目录test下编写CMakeLists.txt文件。
CMakeLists.txt由命令、注释和空格组成,其中命令是不区分大小写。符号#后的内容被认为是注释。命令由命令名称、小括号和参数组成,参数之间使用空格进行间隔。
本例中CMakeLists.txt文件的命令如下:
cmake_minimum_required:指定运行本配置文件所需的CMake的最低版本;
project:参数值是demo,表示项目的名称是demo。
add_executable:将名为main.cpp的源文件编译成一个名称为demo的可执行文件。
3、编译工程
在源码根目录下创建一个build目录,进入build目录,执行cmake ..,生成Makefile,再使用make命令编译得到demo可执行文件。
通常,建议在源码根目录下创建一个独立的build构建编译目录,将构建过程产生的临时文件等文件与源码隔离,避免源码被污染。
四、单目录多源文件工程
1、源文件编写
假如把power函数单独写进一个名为MathFunctions.cpp的源文件里,使得这个工程变成如下的形式:
MathFunctions.h文件:
MathFunctions.cpp文件:
main.cpp文件:
2、编写CMakeLists.txt
add_executable命令中增加了一个MathFunctions.cpp源文件,但如果源文件很多,可以使用aux_source_directory命令,aux_source_directory命令会查找指定目录下的所有源文件,然后将结果存进指定变量名。其语法如下:
aux_source_directory(dir variable)
修改后CMakeLists.txt如下:
CMake会将当前目录所有源文件的文件名赋值给变量DIR_SRCS ,再指示变量DIR_SRCS中的源文件需要编译成一个名称为demo的可执行文件。
五、多文件多目录工程
1、源码文件编写
创建一个math目录,将MathFunctions.h和MathFunctions.cpp文件移动到math目录下。在工程目录根目录test和子目录math里各编写一个CMakeLists.txt文件,可以先将math目录里的文件编译成静态库再由main函数调用。
math子目录:
MathFunctions.h文件:
MathFunctions.cpp文件:
根目录源文件:
2、CMakeLists.txt文件编写
根目录的CMakeLists.txt文件:
add_subdirectory命令指明本工程包含一个子目录math,math目录下的 CMakeLists.txt文件和源代码也会被处理 。target_link_libraries命令指明可执行文件demo需要连接一个名为MathFunctions的链接库 。
math子目录的CMakeLists.txt文件:
add_library命令将math目录中的源文件编译为静态链接库。
六、自定义编译选项
1、自定义编译选项简介
CMake允许为工程增加编译选项,从而可以根据用户的环境和需求选择最合适的编译方案。
例如,可以将MathFunctions库设为一个可选的库,如果该选项为ON ,就使用MathFunctions库定义的数学函数来进行运算,否则就调用标准库中的数学函数库。
2、CMakeLists 文件编写
在根目录的CMakeLists.txt文件指定自定义编译选项:
configure_file命令用于加入一个配置头文件config.h,config.h文件由CMake从config.h.in生成,通过预定义一些参数和变量来控制代码的生成。
option命令添加了一个USE_MYMATH选项,并且默认值为ON。
根据USE_MYMATH变量的值来决定是否使用自己编写的MathFunctions库。
3、修改源文件的调用
修改main.cpp文件,让其根据USE_MYMATH的预定义值来决定是否调用标准库还是MathFunctions库。
4、编写config.h.in文件
main.cpp文件包含了一个config.h文件,config.h文件预定义了USE_MYMATH 的值。但不会直接编写config.h文件,为了方便从CMakeLists.txt中导入配置,通常编写一个config.h.in文件,内容如下:
#cmakedefine USE_MYMATH
CMake会自动根据CMakeLists.txt配置文件中的设置自动生成config.h文件。
5、编译工程
修改CMakeLists.txt文件,USE_MYMATH为OFF,使用标准库。
# 是否使用自己的MathFunctions库
option (USE_MYMATH
"Use provided math implementation" OFF)
在build目录下cmake ..,make,执行程序:
七、安装和测试
1、定制安装规则
在math/CMakeLists.txt文件指定MathFunctions库的安装规则:
#指定MathFunctions库的安装路径
install(TARGETS MathFunctions DESTINATION bin)
install(FILES MathFunctions.h DESTINATION include)
修改根目录的CMakeLists.txt文件指定目标文件的安装规则:
#指定安装路径
install(TARGETS test DESTINATION bin)
install(FILES "${PROJECT_BINARY_DIR}/config.h"
DESTINATION include)
通过对安装规则的定制,生成的目标文件和MathFunctions函数库 libMathFunctions.o文件将会被拷贝到/usr/local/bin中,而MathFunctions.h和生成的config.h文件则会被复制到/usr/local/include中。
/usr/local是默认安装到的根目录,可以通过修改 CMAKE_INSTALL_PREFIX 变量的值来指定文件应该拷贝到哪个根目录。
2、为工程添加测试
CMake提供了一个CTest测试工具。在项目根目录的CMakeLists.txt文件中调用一系列的add_test 命令。
第一个测试test_run用来测试程序是否成功运行并返回0值。剩下的三个测试分别用来测试 5 的 平方、10 的 5 次方、2 的 10 次方是否都能得到正确的结果。其中PASS_REGULAR_EXPRESSION用来测试输出是否包含后面跟着的字符串。
如果要测试更多的输入数据,可以通过编写宏来实现:
八、GDB支持
让CMake支持gdb的设置只需要指定Debug模式下开启-g选项:
set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
生成的程序可以直接使用gdb来调试。
九、添加环境检查
使用平台相关的特性时,需要对系统环境做检查。检查系统是否自带pow函数,如果有pow函数,就使用;否则使用自定义的power函数。
1、添加 CheckFunctionExists 宏
首先在顶层CMakeLists.txt文件中添加CheckFunctionExists.cmake 宏,并调用check_function_exists命令测试链接器是否能够在链接阶段找到 pow函数。
#检查系统是否支持 pow 函数
include (${CMAKE_ROOT}/Modules/CheckFunctionExists.cmake)
check_function_exists (pow HAVE_POW)
check_function_exists需要放在configure_file命令前。
2、预定义相关宏变量
修改 config.h.in 文件,预定义相关的宏变量。
// does the platform provide pow function?
#cmakedefine HAVE_POW
3、在代码中使用宏和函数
修改 main.cpp文件 ,在代码中使用宏和函数。
十、添加版本号
修改顶层CMakeLists.txt文件,在project命令后分别指定当前的项目的主版本号和副版本号。
分别指定当前的项目的主版本号和副版本号。
为了在代码中获取版本信息,可以修改 config.h.in 文件,添加两个预定义变量:
// the configured options and settings for Tutorial
#define Demo_VERSION_MAJOR @Demo_VERSION_MAJOR@
#define Demo_VERSION_MINOR @Demo_VERSION_MINOR@
// does the platform provide pow function?
#cmakedefine HAVE_POW
直接在源码中使用:
十一、生成安装包
1、增加CPack模块
CMake提供了一个专门用于打包的工具CPack,用于配置生成各种平台上的安装包,包括二进制安装包和源码安装包。
首先在顶层的CMakeLists.txt文件尾部添加下面几行:
导入InstallRequiredSystemLibraries模块,便于导入CPack模块;
设置一些CPack相关变量,包括版权信息和版本信息
导入CPack模块。
在顶层目录下创建License.txt文件内如如下:
2、生成安装包
生成二进制安装包:
cpack -C CPackConfig.cmake
生成源码安装包:
cpack -C CPackSourceConfig.cmake
上述两个命令都会在目录下创建3个不同格式的二进制包文件:
demo-1.0.1-Linux.tar.gz
demo-1.0.1-Linux.tar.Z
demo-1.0.1-Linux.sh
3个二进制包文件所包含的内容是完全相同的。
以上是关于GNU开发工具——CMake快速入门的主要内容,如果未能解决你的问题,请参考以下文章