1 cmake简介

1.1 背景知识

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

1.2 特点

  a.开放源代码,使用类 BSD 许可发布。http://cmake.org/HTML/Copyright.html

  b.跨平台,并可生成 native 编译配置文件,在 Linux/Unix 平台,生成 makefile,在苹果平台,可以生成 xcode,在 Windows 平台,可以生成 MSVC 的工程文件。

  c.能够管理大型项目,KDE4 就是最好的证明。

  d.简化编译构建过程和编译过程。Cmake 的工具链非常简单:cmake+make。

  e.高效率,按照 KDE 官方说法,CMake 构建 KDE4 的 kdelibs 要比使用 autotools 来构建 KDE3.5.6 的 kdelibs 快 40%,主要是因为 Cmake 在工具链中没有 libtool。

  d.可扩展,可以为 cmake 编写特定功能的模块,扩充 cmake 功能。

2 安装cmake

cmake 目前已经成为各大 Linux 发行版提供的组件,比如 Ubuntu 直接在系统中包含,所以,需要自己动手安装的可能性很小。如果你使用的操作系统没有提供 cmake 或者包含的版本较旧,有以下两种下载方法。

可以直接在命令行下载cmake:

$ sudo apt-get install cmakek

也可以从官网下载最新版本:

http://www.cmake.org/HTML/Download.html

3 最简单的例子:HelloWorld

下面选择一个最简单的例子 Helloworld 来演练一下 cmake 的完整构建过程,并不

会深入的探讨 cmake,仅仅展示一个简单的例子,并加以粗略的解释。

1,准备工作

首先,在/backup 目录建立一个 cmake 目录,用来放置我们学习过程中的所有练习。

$ mkdir -p /backup/cmake

然后在 cmake 建立第一个练习目录 t1 。

$ cd /backup/cmake
$ mkdir t1
$ cd t1

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

main.c 文件内容:

#include<stdio.h>
int main()
{
printf("Hello world!\n");
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})

2,开始构建 

所有的文件创建完成后,t1 目录中应该存在 main.c 和 CMakeLists.txt 两个文件。接下来我们来构建这个工程,在这个目录运行(注意命令后面的点号,代表本目录):

$ cmake .

输出大概是这个样子:

-- Check for working C compiler: /usr/bin/gcc
-- Check for working C compiler: /usr/bin/gcc -- works
-- Check size of void*
-- Check size of void* - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- This is BINARY dir /backup/cmake/t1
-- This is SOURCE dir /backup/cmake/t1
-- Configuring done
-- Generating done
-- Build files have been written to: /backup/cmake/t1

再让我们看一下目录中的内容,你会发现,系统自动生成了: CMakeFiles, CMakeCache.txt, cmake_install.cmake 等文件,并且生成了Makefile。

现在不需要理会这些文件的作用,以后你也可以不去理会。最关键的是,它自动生成了Makefile.。

然后进行工程的实际构建,在这个目录输入 make 命令,大概会得到如下的彩色输出:

Scanning dependencies of target hello
[100%] Building C object CMakeFiles/hello.dir/main.o
Linking C executable hello
[100%] Built target hello

如果你需要看到 make 构建的详细过程,可以使用 make VERBOSE=1 或者 VERBOSE=1 make 命令来进行构建。

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

$ ./hello

得到输出:

Hello World from Main

恭喜您,到这里为止您已经完全掌握了 cmake 的使用方法。

3,简单的解释 

我们来重新看一下 CMakeLists.txt,这个文件是 cmake 的构建定义文件,文件名是大小写相关的,如果工程存在多个目录,需要确保每个要管理的目录都存在一个CMakeLists.txt。(关于多目录构建,后面我们会提到,这里不作过多解释)。

上面例子中的 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})

PROJECT 指令的语法是 :

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

你可以用这个指令定义工程名称,并可指定工程支持的语言,支持的语言列表是可以忽略的,默认情况表示支持所有语言。

这个指令隐式的定义了两个 cmake 变量:

<projectname>_BINARY_DIR 以及<projectname>_SOURCE_DIR,这里就是HELLO_BINARY_DIRHELLO_SOURCE_DIR(所以 CMakeLists.txt 中两个 MESSAGE指令可以直接使用这两个变量),因为采用的是内部编译,两个变量目前指的都是工程所在路径/backup/cmake/t1,后面我们会讲到外部编译,两者所指代的内容会有所不同。

同时 cmake 系统也帮助我们预定义了 PROJECT_BINARY_DIRPROJECT_SOURCE_DIR变量,他们的值分别跟 HELLO_BINARY_DIRHELLO_SOURCE_DIR 一致。为了统一起见,建议以后直接使用PROJECT_BINARY_DIRPROJECT_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)。


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

将本例改写成一个最简化的 CMakeLists.txt:

PROJECT(HELLO)
ADD_EXECUTABLE(hello main.c)

4 基本语法规则

前面提到过,cmake 其实仍然要使用”cmake 语言和语法”去构建,上面的内容就是所谓的”cmake 语言和语法”,最简单的语法规则是:

  1. 变量使用${}方式取值,但是在 IF 控制语句中是直接使用变量名
  2. 指令(参数 1 参数 2... ) 【参数使用括弧括起,参数之间使用空格或分号分开】
  3. 指令是大小写无关的,参数和变量是大小写相关的。但推荐你全部使用大写指令。

5 关于语法的疑惑

cmake 的语法还是比较灵活而且考虑到各种情况,比如

SET(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 清理工程

运行:

make clean

即可对构建结果进行清理。

7 内部构建与外部构建

上面的例子展示的是“内部构建”,相信看到生成的临时文件比您的代码文件还要多的时候,估计这辈子你都不希望再使用内部构建。

而外部编译的过程如下:

  1. 首先,请清除 t1 目录中除 main.c CmakeLists.txt 之外的所有中间文件,最关键的是 CMakeCache.txt。
  2. 在 t1 目录中建立 build 目录,当然你也可以在任何地方建立 build 目录,不一定必须在工程目录中。
  3. 进入 build 目录,运行 cmake ..(注意,..代表父目录,因为父目录存在我们需要的CMakeLists.txt,如果你在其他地方建立了 build 目录,需要运行 cmake <工程的全路径>),查看一下 build 目录,就会发现了生成了编译需要的 Makefile 以及其他的中间文件。
  4. 运行 make 构建工程,就会在当前目录(build 目录)中获得目标文件 hello。

上述过程就是所谓的 out-of-source 外部编译,一个最大的好处是,对于原有的工程没有任何影响,所有动作全部发生在编译目录。通过这一点,也足以说服我们全部采用外部编译方式构建工程。

8 小结

本小节描述了使用 cmake 构建 Hello World 程序的全部过程,并介绍了三个简单的指令:PROJECT/MESSAGE/ADD_EXECUTABLE 以及变量调用的方法,同时提及了两个隐式变量<projectname>_SOURCE_DIR 及<projectname>_BINARY_DIR,演示了变量调用的方法 。

CMake学习笔记一:初识cmake的更多相关文章

  1. CMake学习笔记三:cmake 常用指令

    1 基本指令 1,ADD_DEFINITIONS 向 C/C++编译器添加-D 定义,比如: DD_DEFINITIONS(-DENABLE_DEBUG -DABC),参数之间用空格分割. 如果你的代 ...

  2. CMake学习笔记二:cmake 常用变量和常用环境变量

    1 cmake 变量引用的方式 使用 ${} 进行变量的引用.在 IF 等语句中,是直接使用变量名而不通过 ${} 取值. 2 cmake 自定义变量的方式 主要有隐式定义和显式定义两种,举一个隐式定 ...

  3. CMake学习笔记六-引用cmake文件

    include(${CMAKE_CURRENT_SOURCE_DIR}/../Share/share.cmake)

  4. cmake 学习笔记(三)

    转自:http://blog.csdn.net/dbzhang800/article/details/6329314 接前面的 Cmake学习笔记(一) 与 Cmake学习笔记(二) 继续学习 cma ...

  5. cmake 学习笔记(三) (转)

    接前面的 Cmake学习笔记(一) 与 Cmake学习笔记(二) 继续学习 cmake 的使用. 学习一下cmake的 finder. finder是神马东西? 当编译一个需要使用第三方库的软件时,我 ...

  6. CMake学习笔记四:usb_cam的CMakeLists解析

    最近在学习cmake,在完整看了<cmake实践>一书后,跟着书上例程敲了跑了一遍,也写了几篇相关读书笔记,算是勉强基本入门了.所以找了usb_cam软件包的CMakeLists.txt来 ...

  7. cmake学习笔记(五)

    在cmake 学习笔记(三) 中简单学习了 find_package 的 model 模式,在cmake 学习笔记(四)中了解一个CMakeCache相关的东西.但靠这些知识还是不能看懂PySide使 ...

  8. cmake 学习笔记(二)

    在 Cmake学习笔记一 中通过一串小例子简单学习了cmake 的使用方式. 这次应该简单看看语法和常用的命令了. 简单的语法 注释 # 我是注释 命令语法 COMMAND(参数1 参数2 ...) ...

  9. LevelDB学习笔记 (1):初识LevelDB

    LevelDB学习笔记 (1):初识LevelDB 1. 写在前面 1.1 什么是levelDB LevelDB就是一个由Google开源的高效的单机Key/Value存储系统,该存储系统提供了Key ...

  10. Storm学习笔记 - Storm初识

    Storm学习笔记 - Storm初识 1. Strom是什么? Storm是一个开源免费的分布式计算框架,可以实时处理大量的数据流. 2. Storm的特点 高性能,低延迟. 分布式:可解决数据量大 ...

随机推荐

  1. 【APUE】信号量、互斥体和自旋锁

    http://www.cnblogs.com/biyeymyhjob/archive/2012/07/21/2602015.html http://blog.chinaunix.net/uid-205 ...

  2. How can we listen for errors that do not trigger window.onerror?

    原文: http://stackoverflow.com/questions/19141195/how-can-we-listen-for-errors-that-do-not-trigger-win ...

  3. Centos 6.x 安装Nagios及WEB管理nagiosql实现windows及linux监控指南

    一.Nagios简介 Nagios是一款开源的电脑系统和网络监视工具,能有效监控Windows.Linux和Unix的主机状态,交换机路由器等网络设置,打印机等.在系统或服务状态异常时发出邮件或短信报 ...

  4. android KE or NE分析

    使用arm-eabi-addr2line工具跟踪Android调用堆栈 在通常的C/C++代码中,可以通过响应对内存操作不当引起的Segmentation Fault错误即信号SIGSEGV(11)做 ...

  5. poj2488--A Knight&#39;s Journey(dfs,骑士问题)

    A Knight's Journey Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 31147   Accepted: 10 ...

  6. Java基础学习之final和多态及类型转换

    finalkeyword: finalkeyword是终于的意思,能够修饰类,成员变量,成员方法. •    修饰类,类不能被继承 •    修饰变量,变量就变成了常量,仅仅能被赋值一次. •    ...

  7. MSMQ消息队列的安装、启用

    最近研究消息队列,先从微软自带的MSMQ开始,百度如何安装,方式如下: 控制面板---程序和功能--启用和关闭windows功能--Microsoft Message Queue(MSMQ)服务器 默 ...

  8. 不等式数列 DP

    度度熊最近对全排列特别感兴趣,对于1到n的一个排列,度度熊发现可以在中间根据大小关系插入合适的大于和小于符号(即 '>' 和 '<' )使其成为一个合法的不等式数列.但是现在度度熊手中只有 ...

  9. HDU 5044 Tree 树链剖分+区间标记

    Tree Problem Description You are given a tree (an acyclic undirected connected graph) with N nodes. ...

  10. Linux的进程优先级NI和PR到底有什么区别

    Linux的进程优先级NI和PR到底有什么区别 - 51CTO.COM http://os.51cto.com/art/201605/511559.htm