跨平台编译利器cmake、摆脱makefile苦海利器cmake

上篇给大家介绍了如何在linux下的ubuntu系统搭建C、C++的开发环境,现在已经有了操作系统,有了GCC、G++的编译器,有了vim-plus的编辑器,那么是不是就可以直接编码了呢?理论上是已经具备了编码的环境和条件了,事实上当然仅仅写代码也是没有任何问题的,但是如果需要在写完代码之后,继续进行代码的编译,那么我们还缺少一个环节,那就是本篇将要介绍的一个相对编码而言前置的编译问题。我们在编写完代码之后,需要借助G++来对我们编写的C++代码进行编译,将高级语言编译成机器可识别、执行的机器语言,G++是根据什么来进行代码编译的呢?这中间有一个叫makefile的中间件,这个makefile是一系列的编译规则合集,既可以让G++识别根据内涵的编译规则去进行编译工作,也可以让程序员来编写合适自己项目的编译流程,有了这个中间件之后,程序员通过编写编译规则,形成makefile文件,然后调用G++来进行编译工作,生成可执行文件,这是由代码到可执行文件的必经过程。

知道了这个必经过程之后,那么就有了解决方案,只要去搞定这个makefile文件就成了,但是makefile相对而言比较基础繁杂,需要编写较多的规则才能完成编译任务。而且这个编译过程可能会因为操作系统不同也不通用,那么是不是有能跨平台,又相对简单点更加容易上手的工具来解决这个问题呢,答案是肯定的,这个工具就是cmake。cmake自身并不能调用G++来进行编译工作,它是一款制造makefile的工具,相当于makefile的前端工具。cmake解决了上述的两个重要问题,第一,cmake相对makefile更加友好和高级,没有那么多的繁杂指令和规则,更加容易上手,几条简单的内置函数和变量就可以快速搭建工程项目进行编译生成可执行文件。第二,cmake具有相当的跨平台能力,既可以在linux下生成makefile文件进一步进行具体的编译工作,也能在windows下生成VS的工程项目文件,能比较方便快捷的完成跨平台工作,这是我选择使用cmake的重要原因。

在了解了linux下由代码生成可执行文件的必经过程和相关的高级工具cmake之后,本篇将给出一个简单的cmake小例子来讲述cmake的使用过程,由于本人也是linux下开发新手,例子也不复杂,仅使用了cmake的极少数指令和规则,更加复杂的应用场景,请各位同行自行百度查找资料解决,本篇仅为初学者提供简单范例。步骤如下:

1. cmake也同样需要有类似于makefile一样的文件来进行编译行为的指导约束,一般是放在工程项目的根目录下,文件名固定为:CMakeLists.txt,请注意文件名一定不要出错,笔者例子如图所示。

跨平台编译利器cmake、摆脱makefile苦海利器cmake

2. 在给出CMakeLists文件内容之前,简单介绍下笔者这个工程环境,以便更好的理解cmake内置函数功用。工程目录如上图,主要如下:

a. 有main.cpp一个源文件既项目主函数文件。

b. 有bubbling、list、select三个项目子目录文件夹,三个子目录内有项目源文件。

c. built目录用来存放cmake产生文件和编译时产生各种临时文件,如cmake产生的makefile文件等等,是编译文件夹。

d. bin目录用来存放编译产生的可执行文件,既编译结果文件。

3. CMakeLists文件内容。

#指定cmake使用最低版本
cmake_minimum_required (VERSION 2.8)                                                                  
 
 # 项目信息
 project (test)
 
 # 查找目录下的所有源文件
 # 并将名称保存到变量 
 aux_source_directory(. DIR_SRCS)
 aux_source_directory(./bubbling DIR_SRCS2) 
 aux_source_directory(./select DIR_SRCS3) 
 aux_source_directory(./list DIR_SRCS4)
  
 # 将所有源文件集中到一个变量中  
 SET(CPPDIR ${DIR_SRCS} ${DIR_SRCS2} ${DIR_SRCS3} ${DIR_SRCS4})
 
 #指定生成debug版本,以便于使用gdb进行调试 
 SET(CMAKE_BUILD_TYPE "Debug")
 SET(CMAKE_CXX_FLAGG_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
  
 # 指定生成目标
 add_executable(../bin/${PROJECT_NAME} ${CPPDIR})

如上是笔者测试工程CMakeLists文件内容,注释比较完善,基本都可以明白什么功用,简单说明如下:

a. 本工程是多目录,多源文件结构,并未如其他网文那般采用主目录CMakeLists和各个子目录也有CMakeLists文件形式进行编译测试,同时各个子目录与主目录也不是采用静态库的方式进行连接,而是直接进行源文件编译。两种方式都可以达到目的,网上很多的例子都是采用主从CMakeLists文件和静态库连接方式,本文与大部分例子不一样,请各位同行明晰。

b. cmake_minimum_required (VERSION 2.8)   指定cmake的执行的最低版本,本指令可有可无。

c. project (test) 设置项目名称。将会影响cmake内置的PROJECT_NAME变量,设置后可以直接使用该变量。

d. aux_source_directory(./bubbling DIR_SRCS2) cmake内置函数用于收集指定目录中的源文件至指定变量内,参数./bubbling为目录,DIR_SRCS2为指定变量,两个参数之间以空格间隔。

e. SET(CPPDIR ${DIR_SRCS} ${DIR_SRCS2} ${DIR_SRCS3} ${DIR_SRCS4}) 将所有的源文件集中至一个变量中,方便后续使用。SET是cmake内置函数,用于设置变量,参数之间同样使用空格间隔。

f. SET(CMAKE_BUILD_TYPE "Debug") 设置cmake编译类型为debug,设置本参数后,可在后续使用gdb来调试代码。

g. SET(CMAKE_CXX_FLAGG_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb") 设置debug编译参数,如生成调试信息等等参数选项。

h. add_executable(../bin/${PROJECT_NAME} ${CPPDIR}) 生产可执行文件。../bin/${PROJECT_NAME}可执行文件生成路径和可执行文件名,${CPPDIR}可执行文件的构成源文件合集,${}是参数引用标识符,CPPDIR是变量名。

如上就是测试工程的CMakeLists文件内容及简单解释。如需更加详细说明,各位同行可以自行百度cmake的内置函数,变量说明,以便编写更加适合自身项目的cmake文件。

 

4. cmake的编译工作

在工程根目录下生成CMakeLists文件之后,就可以进行cmake工作,如cmake执行无误之后,就可以直接make生成可执行文件了。具体的工作流程如下:

a. 利用linux命令进入项目根目录下的编译目录内,本例则是进入built目录。

b. 输入命令:cmake . 请注意cmake 之后还有一个 .,这是因为命令执行在built目录,而CMakeLists文件在上级目录中。

c. 查看cmake执行输出信息,确定cmake命令正确执行,之后利用ls命令查看本目录下是否顺利生成makefile文件。如果cmake执行成功,那么makefile文件基本也能顺利生成。

d. 输入命令:make 回车后查看make的执行结果,如果没有错误的话,应该在输出目录生成执行文件。

e. 输入命令:cd ..回到上级目录,然后执行:cd bin命令,进入执行目录。执行:ls命令,查看是否生成可执行文件。

f. 执行:./执行文件名 回车之后就能看到项目的输出信息,如hello world之类。

 

总结:本篇讲述如何利用cmake工具生成makefile文件,并且该工具具有跨平台,及相比直接编写makefile文件要更加简单便利等更有友好的特性。在编写完相应的CMakeLists文件后,利用cmake命令,和后续的make命令,可以简单快捷的完成从代码到编译,到生成可执行文件的过程,完成开发整个流程。下篇将介绍编辑器vim-plus在开发过程中经常使用的指令。欢迎各位初学新手浏览查看。