本文主要介绍cmake超详细的介绍教程,有需要的朋友可以参考一下。
什么是cmake
你可能听说过几个Make工具,比如GNU Make、QT qmake、微软MSnmake、BSD Make(pmake)、Makepp等等。这些Make工具遵循不同的规范和标准,它们执行的Makefile的格式也大相径庭。这就带来了一个严重的问题:软件要跨平台,就必须在不同的平台上编译。如果您使用上面的Make工具,您必须为每个标准编写一个Makefile,这将是一项令人抓狂的工作。
CMake CMake图1 CMake是针对上述问题设计的工具:它首先允许开发人员编写一个平台无关的CMakeList.txt文件来定制整个编译过程,然后根据目标用户的平台进一步生成所需的本地化Makefile和工程文件,如Unix的Makefile或Windows的Visual Studio项目。从而实现“写一次,到处跑”。很明显,CMake是比上面提到的Make更高级的编译器配置工具。使用CMake作为项目架构系统的知名开源项目有VTK、ITK、KDE、OpenCV、OSG等。
linux平台下使用CMake生成Makefile并编译的过程如下:
编写CMake配置文件CMakeLists.txt.
执行命令cmake PATH或ccmake PATH来生成Makefile。其中PATH是CMakeLists.txt所在的目录。(ccmake和cmake的区别在于前者提供了交互界面)
用make命令编译。
入门案例:单个源文件
本节对应的源代码目录:Demo1。
对于简单的项目,只需编写几行代码。举个例子,假设我们的项目现在只有一个源文件main.cc,这个程序的目的是计算一个数的指数幂。
#包含stdio.h
#包含stdlib.h
/**
*幂——计算数的幂。
* @param base:基本值。
* @param指数:指数值。
*
* @return base的幂指数。
*/
双幂(双基数,整数指数)
{
int result=base
int I;
if(指数==0) {
返回1;
}
for(I=1;I指数;i){
结果=结果*基数;
}
返回结果;
}
int main(int argc,char *argv[])
{
if (argc 3){
printf(用法:%s基本指数n ,argv[0]);
返回1;
}
双基=atof(argv[1]);
int指数=atoi(argv[2]);
double result=power(底数,指数);
printf(%g ^ %d是%gn ,底数,指数,结果);
返回0;
}
编写 CMakeLists.txt
首先,编写CMakeLists.txt文件,并将其保存在与main.cc源文件相同的目录中:
# CMake最低版本号要求
cmake_minimum_required(版本2.8)
#项目信息
项目(演示1)
#指定构建目标
add_executable(Demo main.cc)
CMakeLists.txt语法简单,由命令、注释和空格组成,其中命令不区分大小写。符号#后面的内容被视为注释。命令由命令名、括号和参数组成,用空格分隔。
对于上面的CMakeLists.txt文件,几个命令依次出现:
Cmake_minimum_required:指定运行此配置文件所需的Cmake的最低版本;
项目:参数值为Demo1,表示项目名称为Demo1。
Add_executable:将名为main.cc的源文件编译成名为Demo的可执行文件。
编译项目
之后,执行cmake。在当前目录下获取Makefile,然后用make命令编译它,得到Demo1可执行文件。
[ehome@xman Demo1]$ cmake。
-C编译器标识是GNU 4.8.2
CXX编译器标识是GNU 4.8.2
-检查正在工作的C编译器:/usr/sbin/cc
-检查工作的C编译器:/usr/sbin/cc - works
-检测C编译器ABI信息
-检测C编译器ABI信息-完成
-检查正在工作的CXX编译器:/usr/sbin/c
-检查正在工作的CXX编译器:/usr/sbin/c - works
-检测CXX编译器ABI信息
-检测CXX编译器ABI信息-完成
-配置完成
-生成完成
-构建文件已写入:/home/ehome/Documents/programming/C/power/demo 1
[ehome@xman Demo1]$ make
扫描目标演示的依赖关系
[100%]构建C对象CMakeFiles/Demo.dir/main.cc.o
链接C可执行文件演示
[100%]构建目标演示
[ehome@xman Demo1]$。/演示5 4
5 ^ 4是625
[ehome@xman Demo1]$。/演示7 3
7 ^ 3是343
[ehome@xman Demo1]$。/演示2 10
2 ^ 10是1024
多个源文件
同一个目录,多个源文件
本节对应的源代码目录:Demo2。
上面的例子只有一个源文件。现在,如果将幂函数单独写入名为MathFunctions.c的源文件中,该项目将变成以下形式:/Demo2
|
- main.cc
|
- MathFunctions.cc
|
-数学函数. h
此时,CMakeLists.txt可以更改为以下形式:
# CMake最低版本号要求
cmake_minimum_required(版本2.8)
#项目信息
项目(演示2)
#指定构建目标
add _ executable(Demo main . cc math functions . cc)
唯一的变化是在add_executable命令中添加了一个MathFunctions.cc源文件。这样写当然没有问题,但是如果源文件很多,要把所有源文件的名字都加进去,那就很烦人了。更方便的方法是使用aux_source_directory命令,该命令将查找指定目录中的所有源文件,然后将结果保存在指定的变量名中。其语法如下:
辅助源目录(目录变量)
因此,CMakeLists.txt可以修改如下:
# CMake最低版本号要求
cmake_minimum_required(版本2.8)
#项目信息
项目(演示2)
#在当前目录中查找所有源文件
#并将该名称保存到DIR_SRCS变量中
辅助源目录(。SRCS方向)
#指定构建目标
添加可执行文件(演示{ DIR _ SRCS })
这样,CMake会将当前目录下所有源文件的文件名赋给变量DIR_SRCS,然后指示需要将变量DIR_SRCS中的源文件编译成一个名为Demo的可执行文件。
多个目录,多个源文件
本节对应的源代码目录:Demo3。
现在将mathFunctions.h和MathFunctions.cc文件移动到Math目录中。/演示3
|
- main.cc
|
-数学/
|
- MathFunctions.cc
|
-数学函数. h
在这种情况下,需要在项目根目录Demo3和math目录下分别写一个CMakeLists.txt文件。为了方便,我们可以把math目录下的文件编译成一个静态库,然后由main函数调用。
根目录中的CMakeLists.txt:
# CMake最低版本号要求
cmake_minimum_required(版本2.8)
#项目信息
项目(演示3)
#在当前目录中查找所有源文件
#并将该名称保存到DIR_SRCS变量中
辅助源目录(。SRCS方向)
#添加数学子目录
add _子目录(数学)
#指定构建目标
add_executable(Demo main.cc)
#添加链接库
目标_链接_库(演示数学函数)
这个文件中添加了以下内容:第3行,使用add_subdirectory命令表示这个项目包含一个子目录math,这样math目录下的CMakeLists.txt文件和源代码也会被处理。第6行,使用命令target_link_libraries表示可执行文件main需要连接一个名为MathFunctions的链接库。
子目录中的CMakeLists.txt:
#在当前目录中查找所有源文件
#并将名称保存到DIR_LIB_SRCS变量中
辅助源目录(。自由SRCS)
#生成链接库
add_library(数学函数$ {目录_库_SRCS})
在这个文件中,使用add_library命令将src目录中的源文件编译成静态链接库。
自定义编译选项
本节对应的源代码目录:Demo4。
CMake允许为项目添加编译选项,以便根据用户的环境和需求选择最合适的编译方案。
例如,可以将MathFunctiONs库设置为可选库。如果此选项打开,您可以使用此库定义的数学函数来执行操作。否则调用标准库中的数学函数库。
修改CMakeLists文件
我们要做的第一步是在顶层的CMakeLists.txt文件中添加这个选项:
# CMake最低版本号要求
cmake_minimum_required(版本2.8)
#项目信息
项目(演示4)
#添加一个配置头文件,用于处理CMake的源代码设置。
配置文件(
$ { PROJECT _ SOURCE _ DIR }/config . h . in
${PROJECT_BINARY_DIR}/config.h
)
#你想使用你自己的数学函数库吗?
选项(使用_我的数学
使用提供的数学实现开)
#加入MathFunctions库?
if(使用_我的数学)
include _ directory( $ { PROJECT _ SOURCE _ DIR }/math )
add _子目录(数学)
set (EXTRA_LIBS ${EXTRA_LIBS}数学函数)
endif (USE_MYMATH)
#在当前目录中查找所有源文件
#并将该名称保存到DIR_SRCS变量中
辅助源目录(。SRCS方向)
#指定构建目标
添加可执行文件(演示{ DIR _ SRCS })
目标_链接_库(演示$ {额外_LIBS})
其中包括:
第7行的configure_file命令用于添加一个配置头文件config.h。该文件由CMake从config.h生成。通过这种机制,可以通过预定义的一些参数和变量来控制代码的生成。
第13行的optiON命令添加了一个USE_MYMATH选项,默认值是ON。
第17行根据USE_MYMATH变量的值决定是否使用自己编写的MathFunctions库。
修改 main.cc 文件
然后修改main.cc文件,根据USE_MYMATH的预定义值决定是调用标准库还是MathFunctions库:
#包括
#包括
#include config.h
#ifdef USE_MYMATH
#include math/MathFunctions.h
#否则
#包括
#endif
int main(int argc,char *argv[])
{
if (argc 3){
printf(用法:%s基本指数n ,argv[0]);
返回1;
}
双基=atof(argv[1]);
int指数=atoi(argv[2]);
#ifdef USE_MYMATH
printf(‘现在我们用自己的数学库。 n’);
double result=power(底数,指数);
#否则
printf(现在我们使用标准库。 n’);
double result=power(底数,指数);
#endif
printf(%g ^ %d是%gn ,底数,指数,结果);
返回0;
}
编写 config.h.in 文件
上面的程序在第2行值得注意,这里引用了一个config.h文件,它预定义了USE_MYMATH的值。但是我们不直接写这个文件。为了从CMakeLists.txt导入配置,我们编写一个config.h.in文件,其内容如下:
#cmakedefine USE_MYMATH
这样,CMake将根据CMakeLists配置文件中的设置自动生成config.h文件。
编译项目
现在编译这个项目。为了交互式地选择这个变量的值,您可以使用ccmake命令(或者cmake -i命令,它将提供一个对话式交互式配置界面)。)
可以找到刚刚定义的USE_MYMATH选项。按键盘箭头键在不同的选项窗口之间跳转,按enter键修改该选项。修改后可以按C选项完成配置,然后按G键确认生成Makefile。CC的其他操作可以参考窗口底部给出的指令提示。
我们可以尝试分别将USE_MYMATH设置为ON和OFF所获得的结果:
USE_MYMATH已打开。
运行结果:
[ehome@xman Demo4]$。/演示
现在我们使用自己的数学函数库。
7 ^ 3=343.000000
10 ^ 5=100000.000000
2 ^ 10=1024.000000
此时,config.h的内容是:
#define USE_MYMATH
USE_MYMATH已关闭。
运行结果:
[ehome@xman Demo4]$。/演示
现在我们使用标准库。
7 ^ 3=343.000000
10 ^ 5=100000.000000
2 ^ 10=1024.000000
此时,config.h的内容是:
/* #undef USE_MYMATH */
下面是其他网友的补充
用cmake编译,组织c工程
序
这个博客是我对cmake使用经验的总结,它还是很简单的。如有错误或更好的方案,请指正~
该方法统一在构建目录中执行:
$: cmake.
$:制造
我觉得养成外部编译是个好习惯。
例一
目录结构是:
lzj @ lzj:~/C-Plus-Plus/makefile _ cmake/cmake _ 1 $ tree。
大厦
CMakeLists.txt
src
你好
hello.cc
hello.h
缅因河
世界
世界. cc
世界
src目录中不同的属性类在不同的目录中维护。
main.cpp中使用hello.h和world.h
CMakeLists.txt是:
cmake _ minimum _ required(3.0版)
项目(测试_1)
辅助源目录($ { CMAKE _ CURRENT _ LIST _ DIR }/src/HELLO SOURCE _ HELLO)
辅助源目录($ { CMAKE _ CURRENT _ LIST _ DIR }/src/WORLD SOURCE _ WORLD)
add _ definitions(-g-Wall-STD=c11 )
add_executable(主
$ { CMAKE _ CURRENT _ LIST _ DIR }/src/main。卡片打印处理机(Card Print Processor的缩写)
${SOURCE_HELLO}
${SOURCE_WORLD})
例二
目录结构为:
lzj @ lzj:~/C-Plus-Plus/makefile _ cmake/cmake _ 2 $ tree。
大厦
CMakeLists.txt
包括
person.h
src
缅因河
人。复写的副本
包括目录下统一包含头文件和宏定义之类,源文件放在科学研究委员会目录下维护
人类是一个简单的空类,拥有一个私有成员变量瓦尔,一个公有成员函数来打印该变量,在主页面中调用
CMakeLists.txt为:
cmake _ minimum _ required(3.0版)
项目(测试2)
包含目录($ {项目源目录}/包含)
add _ definitions(-g-Wall-STD=c11 )
add_executable(主
$ { PROJECT _ SOURCE _ DIR }/src/main。CPP #这个路径看这个主页面位于哪里了
$ { PROJECT _ SOURCE _ DIR }/src/person。抄送)
例三
目录结构为:
lzj @ lzj:~/C-Plus-Plus/makefile _ cmake/cmake _ 3 $ tree。
大厦
CMakeLists.txt
缅因河
src
CMakeLists.txt
hello.cc
你好
世界。复写的副本
世界
将编写的代码编译为库,在主页面中使用,编译主页面时链接该库
顶层目录中CMakeLists.txt为:
cmake _ minimum _ required(3.0版)
项目(测试_3)
添加子目录(src)
add _ definitions(-g-Wall-STD=c11 )
add_executable(main main.cpp)
目标_链接_库(主测试3) #自己的库名为测试3
子目录科学研究委员会中的CMakeLists.txt为:
辅助源目录(。自由SRCS)
添加库(测试3 $ {目录库SRCS})
当然如果科学研究委员会目录下为多文件时,每个目录下都要添加该语句的CMakeLists.txt
源代码
这篇文章就介绍到这了,希望大家以后多多支持我们。