如今CMake使用的人数越来越多,包括我项目组里,很多大牛们在写Qt程序的时候都不用自带的qmake,貌似会出现很多问题,他们往往都用自己写的CMake来编译系统,今天我也和大家一起来学学这个高大上的工具--CMake。

首先,一个CMake要想运行,必须在同目录下有CMake脚本,说说是脚本,其实并没什么可怕,说白了就是一串CMake作者自己写的token语法分析文件--CMakeLists.txt。

这个文件比如你的项目有很多文件夹,必须在每个源代码文件夹下都有一个CMakeLists.txt.它会根据CMake命令中的add_subdirectory自动的递归分析。

讲完脚本的大致概念,让我们现在开始学写我们自己的脚本,在这里我引用CMake官网的相关Sample我们一起学习。注:在CMake中命令是不区分大小写的,而变量跟C一样是区分大小写的,这一点需要注意,我的默认习惯是命令用小写,比较顺手。

[1] cmake_minium_required(VERSION 2.6),版本号VERSION后面的数字根据你所决定的CMake最低版本号来决定,在这里我们用了官网sample的2.6。

[2] project(HELLO), 这代表你整个工程的工程名,同时CMake会根据这个工程名生成两个变量一个是${HELLO_SOURCE_DIR}一个 是${HELLO_BINARY_DIR},前者是当前source源文件所在路径,后者是生成的二进制文件锁在路径,如果你选用的CMake官方推荐的 外部编译模式(建立build,在build生成中间文件和目标文件,和源文件分离)这个时候两者的变量值是不同的,否则相同。

[3] add_subdirectory(Hello) add_subdirectory(Demo),在这里官方例子给出了本目录下有两个sub目录,所以你在顶层写完CMakeLists之后同时也必须在 你add_sub的目录下写相应的CMake脚本,CMake程序并不会再创建额外的进程来进行遍历,它会一层一层的逐步递归下去,其实这也是UNIX设 计的经典哲学--分而治之。

[4] 在Hello目录中: add_library(Hello hello.cxx),表明在这个sub中是生成一个Hello的库,第一个参数是库名,之后的源文件名(可以有多个)。

[5] 在Demo目录中:include_directories(${HELLO_SOURCE_DIR}/Hello)表明当前工程需要去include头 文件的路径为当前源代码所在路径下的Hello目录下,相当于GCC中的-I.另外要注意你如果依次往下写,比如include_directories 之后又来一句include_directories,这个是个追加过程而不是覆盖过程,同学看到可以不用担心自己之前的目录是否被覆盖了。

[6] link_directories(${HELLO_SOURCE_DIR}/Hello)表明当前工程所需要链接的库的路径所在地址,相当于GCC中的-L.

[7] add_executable(helloDemo demo.cxx demo_b.cxx),表明在当前Demo目录下会生成一个可执行文件,可执行文件的后缀名你不需要担心,CMake会自动判断当前环境合理加上。

[8] target_link_libraries(helloDemo Hello)表明可执行文件的生成必须需要库Hello的支持(包括前者include Hello的头文件)。

这个简单的sample讲完,接下来我们来看一下CMake的语法方面的注意点。

首先讲一下添加给GCC预处理宏的几种用法,有的同学一开始肯定想当然的给cmake .. -DMY_FLAG这样来用,其实这样是不对的,这样其实只是给CMake赋予的MY_FLAG的变量,而最终GCC是根本没有感知到该宏有没有定义的, 所以一般用法是两种,一种是在cmake ..的时候加一把CMAKE_CXX_COMPILE_FLAGS=xxx,另外一种是在CMake脚本内部手动加上一句 add_definitions(-DMY_FLAG)这两种方法都可以传给GCC相关的预处理宏,但是还是有区别的,前者针对的有效目录是所有目录,而 后者针对的目录是当前目录乃至当前目录以下的所有子目录,所以在这里需要特别注意。

command (args ...),arg之间可以用空格分离,如果arg中有空格需要用双引号括起来。

其次,CMake中对于字符串支持list格式,即一个变量可以支持字符串数组,比如set(VAR a b c)和set(VAR
a;b;c)两种形式都可以支持${VAR}为a b
c,这种格式时候foreach()进行循环遍历。但是这个时候要注意command(${VAR})表明同时执行了三次command(command
a; command b; command
c;)而command("${VAR}")注意其中的双引号表明只进行了一次遍历(command("a b c"))这个是需要我们注意的。

CMake也提供了流程控制,比如对于C中的if,CMake的写法也是如此if(var) command endif(var)(其中endif中的var可以写成空),判断语句可以有多重形式,可以验证变量是否为true,也可以是否FOUND,(empty, 0, N, NO, OFF, FALSE, NOTFOUND, or -NOTFOUND)等。

CMake同样提供了迭代结构,类似于Qt中的foreach,比如你设置了一个列表字符串var,这个时候你就可以简单的foreach(temp
${var}) command(${temp})
endforeach(${temp})来对var中的变量进行循环迭代处理,这个时候要注意有没有双引号的问题。

CMake也支持自定义编写宏和函数,函数可以像C语言一样内部定义局部变量,宏:macro(var VALUE)
command({var}) endmacro(var)和function(var VALUE) command(${var})
enfunciton(hello)等。

CMake支持include其他.cmake控制,类似于Qt中的pri可以写一些全局的通用脚本。同时CMake的add_definitions也
要重点理解一下,在CMake中,默认的变量命名是name:type=value,所以在cmake命令进行编译的时候可以动态的增加一些你自己的
CMake变量,比如cmake ..
-DMY_VALUE=ON,这个时候你的${MY_VALUE}就被定义了,在CMake脚本里面你可以用if({MY_VALUE})来进行判断当前
时候这个变量被指定,如果被指定了,你可以通过脚本里的add_definitons给gcc添加命令比如
add_definitons(-DMY_VALUE),这个时候的MY_VALUE才真正到了你的编译环境中,前者的MY_VALUE其实是给
CMake脚本用的,这里需要注意。

另外CMake中的set_target_properties也很强大,可以用他来做很多事情,我目前用到的就是给Qt自动
moc,set_target_properties(${target} PROPERTIES AUTOMOC
ON)这个时候你的target就会被自动moc不需要自己手动去添加了。

到这里,我们差不多简单的学习了一下CMake的相关语法,不得不说CMake是一个管理项目很棒的高级工具,要学会利用好这个工具,我们还需要投入更多
的精力来学习,所以一起努力来迎接CMake的美好吧,enjoy! 同时也希望志同道合的朋友可以互相交流,给我留言或者私信,谢谢!

跟我一起学CMake的更多相关文章

  1. c++通过CMake实现debug开关

    刚学cmake,很多东西还不是很懂,不过今天刚刚实现了通过CMake控制debug的开关,兴奋之余记录一下. 背景介绍: 最近参与到了一个大的C++项目,很多代码已经非常成熟,我来添加一些辅助功能,但 ...

  2. 学习用CMake来编写Qt程序

    最近开始学习CMake,因为项目需求需要用到Qt,自带的qmake会出现许多问题(比如文件修改之后有时候qmake不会侦测到不会重新编译,需要手动去编译等),于是开始尝试使用CMake来编写Qt程序, ...

  3. cmake 简学

    https://www.cnblogs.com/cv-pr/p/6206921.html

  4. 使用cmake自动构建工程

    公司引擎是用cmake根据目标平台来构建工程的,刚接触的时候深深体会到cmake的方便:如果目标平台是windows,它可以帮你自动构建出vs工程:如果是安卓,自动构建出eclipse工程,如果是IO ...

  5. CMake入门以及学习笔记

    使用cef3替代chromium内核开发产品过程中,第一次接触到系统构建,使用了最常见的CMake.CMake虽然在构建系统中用的比较多,但是使用到的程序员还是很少的.现在在国内能找到的相关资料和博客 ...

  6. 一起学习CMake – 03

    这一节我们就一起来看看如何用CMake来链接自己写的lib库,如何进行这些库文件的管理. 一个团队共同开发软件时,一般都是分模块进行作业的,每个人负责整个软件中的一部分,然后再整合成一个完整的软件系统 ...

  7. CMake初步(1)

    转自:<你所不知的OSG>第一章:CMake初步(1)http://bbs.osgchina.org/forum.php?mod=viewthread&tid=1189&f ...

  8. 使用 cmake 进行交叉编译

    cmake 因为“又”要额外学一门语言而被诟病,但这并不妨碍越来越多私人项目用 cmake 来管理:autoconfig 确实是更好的发行工具,但用 cmake 管理项目显然更加的容易.如果要应用这些 ...

  9. 从零开始一起学习SLAM | 学习SLAM到底需要学什么?

    SLAM涉及的知识面很广,我简单总结了 “SLAM知识树” 如下所示: (公众号菜单栏回复 “树” 可获得清晰版) 可以看到涉及的知识面还是比较广的.这里放出一张SLAM圈子里喜闻乐见的表达悲喜交加心 ...

随机推荐

  1. 动态规划(模型转换):uvaoj 1625 Color Length

    [PDF Link]题目点这里 这道题一眼就是动态规划,然而貌似并不好做. 如果不转换模型,状态是难以处理的. 巧妙地转化:不直接求一种字母头尾距离,而是拆开放到状态中. #include <i ...

  2. 【单调队列】Vijos P1771 瑞士轮 (NOIP2011普及组第三题)

    题目链接: https://vijos.org/p/1771 题目大意: 给定2N个人(N<=100 000)和其初始分数.能力值(能力两两不同),比赛M次(M<=50),每次PK都是按分 ...

  3. H-Index ——Leetcode

    Given an array of citations (each citation is a non-negative integer) of a researcher, write a funct ...

  4. 通过web修改svn用户密码

    使用方法: 将文件changePasswd.cgi和changePasswd.ini 放到apche安装目录下的cgi-bin下(cgi-bin的目录可以通过/etc/httpd/conf/httpd ...

  5. JSTL和select标签的组合使用

    1.用于根据不同的值显示对应的内容,不能选择 <select name="grade"> <c:choose> <c:when test=" ...

  6. Linux 输出重定向>和>>的区别是什么

    > 是定向输出到文件,如果文件不存在,就创建文件:如果文件存在,就将其清空:一般我们备份清理日志文件的时候,就是这种方法:先备份日志,再用`>`,将日志文件清空(文件大小变成0字节): & ...

  7. foxmail客户端总是提示接收密码错误

    如上图所示. 我知道的一个原因是 发送太多邮件所致,导致发件服务器触发规则限制登录. 如果之前发的不是很多的话,可以在设置的帐号选项里删除这个账户,再重新建一个.

  8. Python随机生成验证码的两种方法

    Python随机生成验证码的方法有很多,今天给大家列举两种,大家也可以在这个基础上进行改造,设计出适合自己的验证码方法方法一:利用range Python随机生成验证码的方法有很多,今天给大家列举两种 ...

  9. PHP数据结构预热:PHP的迭代器(转)

    迭代器有时又称光标(cursor)是程式设计的软件设计模式,可在容器物件(container,例如list或vector)上遍访的接口,设计人员无需关心容器物件的内容. 各种语言实作Iterator的 ...

  10. [转] C++虚函数与虚函数表

    http://www.cnblogs.com/Ripper-Y/archive/2012/05/15/2501930.html http://blog.csdn.net/haoel/article/d ...