CMake学习笔记一:初识cmake
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_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
,即使修改了工程名称,也不会影响这两个变量。
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 语言和语法”,最简单的语法规则是:
- 变量使用${}方式取值,但是在 IF 控制语句中是直接使用变量名
- 指令(参数 1 参数 2... ) 【参数使用括弧括起,参数之间使用空格或分号分开】
- 指令是大小写无关的,参数和变量是大小写相关的。但推荐你全部使用大写指令。
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 内部构建与外部构建
上面的例子展示的是“内部构建”,相信看到生成的临时文件比您的代码文件还要多的时候,估计这辈子你都不希望再使用内部构建。
而外部编译的过程如下:
- 首先,请清除 t1 目录中除 main.c CmakeLists.txt 之外的所有中间文件,最关键的是 CMakeCache.txt。
- 在 t1 目录中建立 build 目录,当然你也可以在任何地方建立 build 目录,不一定必须在工程目录中。
- 进入 build 目录,运行 cmake ..(注意,..代表父目录,因为父目录存在我们需要的CMakeLists.txt,如果你在其他地方建立了 build 目录,需要运行 cmake <工程的全路径>),查看一下 build 目录,就会发现了生成了编译需要的 Makefile 以及其他的中间文件。
- 运行 make 构建工程,就会在当前目录(build 目录)中获得目标文件 hello。
上述过程就是所谓的 out-of-source 外部编译,一个最大的好处是,对于原有的工程没有任何影响,所有动作全部发生在编译目录。通过这一点,也足以说服我们全部采用外部编译方式构建工程。
8 小结
本小节描述了使用 cmake 构建 Hello World 程序的全部过程,并介绍了三个简单的指令:PROJECT/MESSAGE/ADD_EXECUTABLE 以及变量调用的方法,同时提及了两个隐式变量<projectname>_SOURCE_DIR 及<projectname>_BINARY_DIR,演示了变量调用的方法 。
CMake学习笔记一:初识cmake的更多相关文章
- CMake学习笔记三:cmake 常用指令
1 基本指令 1,ADD_DEFINITIONS 向 C/C++编译器添加-D 定义,比如: DD_DEFINITIONS(-DENABLE_DEBUG -DABC),参数之间用空格分割. 如果你的代 ...
- CMake学习笔记二:cmake 常用变量和常用环境变量
1 cmake 变量引用的方式 使用 ${} 进行变量的引用.在 IF 等语句中,是直接使用变量名而不通过 ${} 取值. 2 cmake 自定义变量的方式 主要有隐式定义和显式定义两种,举一个隐式定 ...
- CMake学习笔记六-引用cmake文件
include(${CMAKE_CURRENT_SOURCE_DIR}/../Share/share.cmake)
- cmake 学习笔记(三)
转自:http://blog.csdn.net/dbzhang800/article/details/6329314 接前面的 Cmake学习笔记(一) 与 Cmake学习笔记(二) 继续学习 cma ...
- cmake 学习笔记(三) (转)
接前面的 Cmake学习笔记(一) 与 Cmake学习笔记(二) 继续学习 cmake 的使用. 学习一下cmake的 finder. finder是神马东西? 当编译一个需要使用第三方库的软件时,我 ...
- CMake学习笔记四:usb_cam的CMakeLists解析
最近在学习cmake,在完整看了<cmake实践>一书后,跟着书上例程敲了跑了一遍,也写了几篇相关读书笔记,算是勉强基本入门了.所以找了usb_cam软件包的CMakeLists.txt来 ...
- cmake学习笔记(五)
在cmake 学习笔记(三) 中简单学习了 find_package 的 model 模式,在cmake 学习笔记(四)中了解一个CMakeCache相关的东西.但靠这些知识还是不能看懂PySide使 ...
- cmake 学习笔记(二)
在 Cmake学习笔记一 中通过一串小例子简单学习了cmake 的使用方式. 这次应该简单看看语法和常用的命令了. 简单的语法 注释 # 我是注释 命令语法 COMMAND(参数1 参数2 ...) ...
- LevelDB学习笔记 (1):初识LevelDB
LevelDB学习笔记 (1):初识LevelDB 1. 写在前面 1.1 什么是levelDB LevelDB就是一个由Google开源的高效的单机Key/Value存储系统,该存储系统提供了Key ...
- Storm学习笔记 - Storm初识
Storm学习笔记 - Storm初识 1. Strom是什么? Storm是一个开源免费的分布式计算框架,可以实时处理大量的数据流. 2. Storm的特点 高性能,低延迟. 分布式:可解决数据量大 ...
随机推荐
- 【APUE】信号量、互斥体和自旋锁
http://www.cnblogs.com/biyeymyhjob/archive/2012/07/21/2602015.html http://blog.chinaunix.net/uid-205 ...
- 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 ...
- Centos 6.x 安装Nagios及WEB管理nagiosql实现windows及linux监控指南
一.Nagios简介 Nagios是一款开源的电脑系统和网络监视工具,能有效监控Windows.Linux和Unix的主机状态,交换机路由器等网络设置,打印机等.在系统或服务状态异常时发出邮件或短信报 ...
- android KE or NE分析
使用arm-eabi-addr2line工具跟踪Android调用堆栈 在通常的C/C++代码中,可以通过响应对内存操作不当引起的Segmentation Fault错误即信号SIGSEGV(11)做 ...
- poj2488--A Knight's Journey(dfs,骑士问题)
A Knight's Journey Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 31147 Accepted: 10 ...
- Java基础学习之final和多态及类型转换
finalkeyword: finalkeyword是终于的意思,能够修饰类,成员变量,成员方法. • 修饰类,类不能被继承 • 修饰变量,变量就变成了常量,仅仅能被赋值一次. • ...
- MSMQ消息队列的安装、启用
最近研究消息队列,先从微软自带的MSMQ开始,百度如何安装,方式如下: 控制面板---程序和功能--启用和关闭windows功能--Microsoft Message Queue(MSMQ)服务器 默 ...
- 不等式数列 DP
度度熊最近对全排列特别感兴趣,对于1到n的一个排列,度度熊发现可以在中间根据大小关系插入合适的大于和小于符号(即 '>' 和 '<' )使其成为一个合法的不等式数列.但是现在度度熊手中只有 ...
- HDU 5044 Tree 树链剖分+区间标记
Tree Problem Description You are given a tree (an acyclic undirected connected graph) with N nodes. ...
- Linux的进程优先级NI和PR到底有什么区别
Linux的进程优先级NI和PR到底有什么区别 - 51CTO.COM http://os.51cto.com/art/201605/511559.htm