CMake实践(一) CMake介绍

CMake介绍

cmake 是 kitware 公司以及一些开源开发者在开发几个工具套件(VTK)的过程中衍生品,最终形成体系,成为一个独立的开放源代码项目。项目的诞生时间是 2001 年。其官方网站是 www.cmake.org,可以通过访问官方网站获得更多关于 cmake 的信息。cmake的流行其实要归功于 KDE4 的开发(似乎跟当年的 svn 一样,KDE 将代码仓库从 CVS 迁移到SVN,同时证明了 SVN 管理大型项目的可用性),在 KDE 开发者使用了近 10 年 autotools之后,他们终于决定为 KDE4 选择一个新的工程构建工具,其根本原因用 KDE 开发者的话来说就是:只有少数几个 “ 编译专家 ” 能够掌握 KDE 现在的构建体系(admin/Makefile.common),在经历了 unsermake, scons 以及 cmake 的选型和尝试之后,KDE4 决定使用 cmake 作为自己的构建系统。在迁移过程中,进展异常的顺利,并获得了 cmake 开发者的支持。所以,目前的 KDE4 开发版本已经完全使用 cmake 来进行构建。像 kdesvn,rosegarden 等项目也开始使用 cmake,这也注定了 cmake 必然会成为一个主流的构建体系。

cmake 的特点:

1,开放源代码,使用类 BSD 许可发布。http://cmake.org/HTML/Copyright.html
2,跨平台,并可生成 native 编译配置文件,在 Linux/Unix 平台,生成 makefile,在
苹果平台,可以生成 xcode,在 Windows 平台,可以生成 MSVC 的工程文件。
3,能够管理大型项目,KDE4 就是最好的证明。
4,简化编译构建过程和编译过程。Cmake 的工具链非常简单:cmake+make。
5,高效虑,按照 KDE 官方说法,CMake 构建 KDE4 的 kdelibs 要比使用 autotools 来
构建 KDE3.5.6 的 kdelibs 快 40% ,主要是因为 Cmake 在工具链中没有 libtool。
6,可扩展,可以为 cmake 编写特定功能的模块,扩充 cmake 功能。

问题

1,cmake 很简单,但绝对没有听起来或者想象中那么简单。
2,cmake 编写的过程实际上是编程的过程,跟以前使用 autotools 一样,不过你需要编写的是 CMakeLists.txt(每个目录一个) ,使用的是 ” cmake 语言和语法 ” 。
3,cmake 跟已有体系的配合并不是特别理想,比如 pkgconfig,在实际使用中会有所体会,虽然有一些扩展可以使用,但并不理想。

建议:

1,如果你没有实际的项目需求,那么看到这里就可以停下来了,因为 cmake 的学习过程就是实践过程,没有实践,读的再多几天后也会忘记。
2,如果你的工程只有几个文件,直接编写 Makefile 是最好的选择。
3,如果使用的是 C/C++/Java 之外的语言,请不要使用 cmake(至少目前是这样)
4,如果你使用的语言有非常完备的构建体系,比如 java 的 ant,也不需要学习 cmake,虽然有成功的例子,比如 QT4.3 的 csharp 绑定 qyoto。
5,如果项目已经采用了非常完备的工程管理工具,并且不存在维护问题,没有必要迁移到cmake
4,如果仅仅使用 qt 编程,没有必要使用 cmake,因为 qmake 管理 Qt 工程的专业性和自动化程度比 cmake 要高很多。

安装 cmake

cmake 目前已经成为各大 Linux 发行版提供的组件,比如 Everest 直接在系统中包含,Fedora 在 extra 仓库中提供,所以,需要自己动手安装的可能性很小。如果你使用的操作系统(比如 Windows 或者某些 Linux 版本)没有提供 cmake 或者包含的版本较旧,建议你直接从 cmake 官方网站下载安装。
http://www.cmake.org/HTML/Download.html
在这个页面,提供了源代码的下载以及针对各种不同操作系统的二进制下载,可以选择适合
自己操作系统的版本下载安装。

初试 cmake – cmake 的 helloworld

准备工作:

首先,在/backup 目录建立一个 cmake 目录,用来放置所有练习。
mkdir -p /backup/cmake
以后我所有的 cmake 练习都会放在/backup/cmake 的子目录下(你也可以自行安排目录)
然后在 cmake 建立第一个练习目录 t1:

cd /backup/cmake
mkdir t1
cd t1

在 t1 目录建立 main.c 和 CMakeLists.txt(注意文件名大小写):

touch main.c
touch CMakeLists.txt

main.c 文件内容:

#include<stdio.h>
int main()
{
	printf("hello world");
	return 0;
}

CMakeLists.txt文件内容:

PROJECT(HELLO)
SET(SRC_LIST main.c)
MESSAGE(STATUS "This is BINARY dir" ${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir" ${HELLO_SOURCE_DIR})
ADD_EXECUTABLE(hello ${SRC_LIST})
//或者ADD_EXECUTABLE(hello main.c)
mkdir build
cd build
cmake ..
make

cmake : 系统自动生成了:CMakeFiles, CMakeCache.txt, cmake_install.cmake 等文件,并且生成了
Makefile.现在不需要理会这些文件的作用,以后你也可以不去理会。最关键的是,它自动生成了
Makefile.
在这里插入图片描述如果需要看到 make 构建的详细过程,可以使用 make VERBOSE=1 或者 VERBOSE=1
make 命令来进行构建。

这时候,我们需要的目标文件 hello 已经构建完成,位于当前目录,尝试运行一下:

./hello

得到输出:
hello world
在这里插入图片描述

简单的解释:

CMakeLists.txt是 cmake 的构建定义文件,如果工程存在多个目录,需要确保每个要管理的目录都存在一个CMakeLists.txt。

PROJECT 指令的语法是:

PROJECT(projectname [CXX] [C] [Java])

定义工程名称,并可指定工程支持的语言,支持的语言列表是可以忽略的(默认表示支持所有语言),
隐式的定义了两个cmake变量:
_BINARY_DIR 和 _SOURCE_DIR,这里就是
HELLO_BINARY_DIR 和 HELLO_SOURCE_DIR(所以 CMakeLists.txt 中两个 MESSAGE
指令可以直接使用了这两个变量),因为采用的是内部编译,两个变量目前指的都是工程所
在路径/backup/cmake/t1。

同时cmake系统也预定义了PROJECT_BINARY_DIR 和 PROJECT_SOURCE_DIR
变量,他们的值分别跟 HELLO_BINARY_DIR 与 HELLO_SOURCE_DIR 一致(建议以后直接使用 PROJECT_BINARY_DIR,PROJECT_SOURCE_DIR,即使修改了工程名称,也不会影响这两个变量。如果使用了_SOURCE_DIR ,修改工程名称后,需要同时修改这些变量)。

SET 指令的语法是:

SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])

SET 指令可以用来显式的定义变量。
若我们用到的是 SET(SRC_LIST main.c),如果有多个源文件,也可以定义成:SET(SRC_LIST main.c t1.c t2.c)。

MESSAGE 指令的语法是:

MESSAGE([SEND_ERROR | STATUS | FATAL_ERROR] "message to display"...)

用于向终端输出用户定义的信息,包含了三种类型:
SEND_ERROR,产生错误,生成过程被跳过。
SATUS ,输出前缀为 — 的信息。
FATAL_ERROR,立即终止所有 cmake 过程.

例程使用的是 STATUS 信息输出,演示了由 PROJECT 指令定义的两个隐式变量HELLO_BINARY_DIR 和 HELLO_SOURCE_DIR。

ADD_EXECUTABLE :

ADD_EXECUTABLE(hello ${SRC_LIST})

定义了这个工程会生成一个文件名为 hello 的可执行文件,相关的源文件是 SRC_LIST 中
定义的源文件列表,(也可以直接写成 ADD_EXECUTABLE(hello main.c))。

在本例我们使用 SRC_LIST 来引用变量,这是 cmake 的变量应用方式,但是,有一些例外,比
如在 IF 控制语句,变量是直接使用变量名引用,而不用 SRC_LIST 。如果使用了 SRC_LIST 去应用变
量,其实 IF 会去判断名为${}所代表的值的变量,那当然是不存在的了。

基本语法规则

使用cmake语言和语法去构建:

  1. 变量使用${}方式取值,但在IF控制语句中直接使用变量名
  2. 指令(参数1 参数2) 参数使用()括起,参数之间使用空格或逗号分开
    以上面的 ADD_EXECUTABLE 指令为例,如果存在另外一个 func.c 源文件,就要写成:
    ADD_EXECUTABLE(hello main.c func.c)或者
    ADD_EXECUTABLE(hello main.c;func.c)
  3. 指令与大小写无关,参数和变量与大小写有关(推荐全部大写指令)
    例如 MESSAGE(STATUS “This is BINARY dir” ${HELLO_BINARY_DIR})
    也可以写成: message(STATUS “This is BINARY dir ${HELLO_BINARY_DIR}”)
  4. 工程名 HELLO 和生成的可执行文件 hello 是没有关系的,hello 定义了可执行文件的文件名
    若写成ADD_EXECUTABLE(t1 main.c),编译后会生成一个 t1 可执行文件。
  5. ET(SRC_LIST main.c)也可以写成 SET(SRC_LIST “main.c”)是没有区别的,但是如果一个源文件的文件名是 fu nc.c(文件名中间包含了空格),就必须使用双引号,如果写成了 SET(SRC_LIST fu nc.c),就会出现错误,提示你找不到 fu 文件和 nc.c 文件,必须写成:SET(SRC_LIST “fu nc.c”)。
  6. source列表中的源文件后缀可以忽略,比如可以写成ADD_EXECUTABLE(t1,main),cmake 会自动的在本目录查找 main.c 或者 main.cpp等(最好不要偷这个懒,以免这个目录确实存在一个 main.c 一个 main.cpp)。
  7. 参数也可以使用分号来进行分割。例如ADD_EXECUTABLE(t1 main.c t1.c)可以写成 ADD_EXECUTABLE(t1 main.c;t1.c)

清理工程:

和经典的 autotools 系列工具一样,运行:

make clean	#对构建结果进行清理。

cmake中没有清理中间文件的 make disclean

内部构建与外部构建:

上例是 “ 外部构建 ” ,生成的临时文件比您的代码文件还要多(cmake 强烈推荐的是外部构建(out-of-source build)),内部构建时不建立build文件(in-source-build)(-D)。

举个简单的例子来说明外部构建,以编译 wxGTK 动态库和静态库为例,在 Everest 中打包
方式是这样的:
解开 wxGTK 后。
在其中建立 static 和 shared 目录。
进入 static 目录,运行…/configure –enable-static;make 会在 static 目录生
成 wxGTK 的静态库。
进入 shared 目录,运行…/configure –enable-shared;make 就会在 shared 目录
生成动态库。
这就是外部编译的一个简单例子。

外部编译对于原有的工程没有任何影响,所有动作全部发生在编译目录。通过外部编译进行工程构建,HELLO_SOURCE_DIR 仍然指代工程路径,即/backup/cmake/t1, HELLO_BINARY_DIR 指代编译路径,即/backup/cmake/t1/build

参考:Cmake Practice --Cjacker

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值