CMake使用总结

1.安装

 $sudo apt-get install cmake


2.示例:简单的文件目录

    sample |——Demo  (盛放可执行程序binary directory)

                            |——CMakeLists.txt (内容为:include_directories                                                                                                      (${HELLO_SOURCE_DIR}/Hello                                                                                                    #确认compiler能在Hello 库中找到它include的库

                                                             link_directories (${HELLO_BINARY_DIR}/Hello)                                                                          #确认一旦built时,linker能找到Hello库

                                                            add_executable (helloDemo demo.cxx demo_b.cxx)                                                                  #可执行文件叫做helloDemo,它的源码文件是"demo.cxx"                                                              #和"demo_b.cxx"

                                                           target_link_libraries (helloDemo Hello)                                                                                          #link可执行文件helloDemo 到Hello lib       )

                | ——Hello  (盛放源代码source directory)

                            |——CMakeLists.txt (内容为:add_library (Hello hello.cxx)                                                                                              #创建Hello 库,源文件为hello.cxx)                      

                |——CMakeLists.txt  (内容为:project (HELLO) #工程名

                                                                  add_subdirectory (Hello) # 子目录,路径为                                                                                   ${HELLO_SOURCE_DIR})

                                                                  add_subdirectory (Demo) #子目录 ,路径为                                                                                 ${HELLO_BINARY_DIR}   )


3.CMake 执行过程

      CMake在主目录执行时,会处理该目录下CMakeLists.txt文件,然后进入到子目录,处理子目录下的CMakeLists.txt.

      从字面上看,我们差不多可以理解这三个文件的涵义。第一个CMakeLists.txt文件指定包含Hello和Demo两个子目录。第二个Hello中的CMakeLists.txt文件则指定生成Hello库文件,第三个Demo中的CMakeLists.txt文件则是生成一个可执行文件helloDemo,另外两个附加语句则用来指明头文件路径以及所要链接的库。虽然要写三个CMakeLists文件,但每个文件都非常简单,总共算起来,并不比一个Makefile文件多多少。更重要的是,这其中隐含着linux哲学:分而治之。每个模块自行编写配置文件,只负责自己份内的事务,所以可扩展性好。在进行大型项目开发,就可以体现出优势了。

      CMakeLists.txt相当于定义了一套生成Makefile文件的规则,下面就可以生成Makefile文件了,命令如下:

$cmake .

表示当前目录,如果CMakeLists.txt不在当前目录,请在cmake后面指定。命令执行后,在主目录下和Demo、Hello子目录下均会生成一个Makefile文件,有了这个文件,我们就可以敲入make编译目标程序了。


4.项目文件组织

      我们从一个sample入手,了解了CMake的基本用法和语法。但这个例子与实际开发还有一段距离,主要存在以下几点问题:                                                                                                        1.生成的二进制程序和源程序混在一起                                                                                           2.使用gcc进程程序编译,而不是使用交叉编译工具                                                                       3.为指定编译选项,通常会生成debug版本供调试用,release版本用于发布

      一个项目,通常包含若干子模块。比如上一篇的sample,我们可以认为它包含两个子模块,Hello为程序库,Demo为主程序。很少有项目会把目标二进制文件和源程序放在一起的,通常会建立一个bin目录,存放生成的二进制文件,发布程序则放在release。根据我在项目开发中的习惯,将目录结构修改如下:

CMakeSample

|--- release  (存放程序发布相关文件,包括程序文件、脚本、参数等。)

|--- doc(项目开发中的相关文档,如设计说明以及通过doxgen等工具从代码中生成的文档。)

|--- lib(存放项目中使用的第三方库)

|--- source(自己编写的库不放在lib,应该作为项目的一个模块放在source目录下。)

|--- include (包含整个项目中使用的公共头文件,若子模块中的头文件仅被它使用,不放)

|--- bin (bin目录存放编译后的调试版本代码。)

|--- Hello

|--- Demo

其它的子目录则为各模块的代码及头文件。

按照以上目录结构,将Hello下的hello.h移到include目录,因为这个头文件被Demo模块包含。这个sample中未使用第三方库,所以暂时为空。


5.CMake的内置变量

从上文中我们知道,通过set语句可以自定义变量,然而,CMake还包含大量的内置变量,这些变量和自定义变量的用法没有区别,下面就列出一些常用的变量:

CMAKE_C_COMPILER

指定C编译器,通常,CMake运行时能够自动检测C语言编译器。进行嵌入式系统开发时,通常需要设置此变量,指定交叉编译器。

CMAKE_CXX_COMPILER

指定C++编译器

CMAKE_C_FLAGS

指定编译C文件时编译选项,比如-g指定产生调试信息。也可以通过add_definitions命令添加编译选项。

EXECUTABLE_OUTPUT_PATH

指定可执行文件存放的路径

LIBRARY_OUTPUT_PATH

指定库文件放置的路径

CMAKE_BUILD_TYPE     build 类型(Debug, Release),-DCMAKE_BUILD_TYPE=Debug

BUILD_SHARED_LIBS     Switch between shared and static libraries

内置变量的使用:

>> 在CMakeLists.txt中指定,使用set

>> cmake命令中使用,如cmake -DBUILD_SHARED_LIBS=OFF


6.CMake的常用命令

除了内置变量,我们还可以通过命令来修改编译选项,现将一些常用的命令列出来:

include_directories

指定头文件的搜索路径,相当于指定gcc编译器的-I参数

link_directories

动态链接库或静态链接库的搜索路径,相当于指定gcc的-L参数

add_subdirectory

包含子目录,当工程包含多个子目录时,此命令有用

add_definitions

添加编译参数,比如add_definitions(-DDEBUG)将在gcc命令行添加DEBUG宏定义

add_executable

编译可执行程序

target_link_libraries

指定链接库,相同于指定-l参数

7.CMake语法介绍

CMake语法非常简单,包含注释、命令和空格。以#开头的行为注释行,命令则由命令名、括号及以空格进行分隔的参数组成。命令可以是诸如add_library这样的内置命令,也可以是子定义的宏或者函数。CMake的输入是主目录下的CMakeLists.txt文件,该文件可以使用include或者add_directory命令添加其它的输入文件。

命令的形式如下:

command (args ...)

其中command为命令名,args为空格分隔的参数列表,如果参数中包含空格,使用双引号引起来。命令不区分大小写。

lists and strings. CMake的基本数据类型为字符串,字符串又可以组成list类型,有两种方式:一种通过分号分隔,一种通过空格分隔。比如以下例子给VAR赋了同样的值:

set(VAR a;b;c)    set(VAR a b c)

字符串列表主要用于foreach进行迭代,有些命令也用于对list进行处理。

CMake支持字符串和list类型的简单变量,变量以${VAR}形式引用。多个参数可以用set命令组成一个list,命令将展开list,例如:

set(Foo a b c)

command(${Foo})

等价于

command(a b c)

如果你希望将list当作一个参数传递给命令,就应该用双引号把list引起来,如command("${Foo}")等价于command("a b c")

流程控制

写CMakeLists.txt文件就象写一个简单的程序,CMake提供了三种流程控制结构:

条件语句if

# some_command will be called if the variable's value is not:

# empty, 0, N, NO, OFF, FALSE, NOTFOUND, or -NOTFOUND.

if(var)

some_command(...)

endif(var)

循环结构

set(VAR a b c)

# loop over a, b,c with the variable f

foreach(f ${VAR})

some_command(${f})

endforeach(f)

宏和函数,函数在2.6及以上版本才支持,函数和宏的区别在于函数中可定义局部变量,而宏定义的变量都是全局变量。

# define a macro hello

macro(hello MESSAGE)

message(${MESSAGE})

endmacro(hello)

# call the macro with the string "hello world"

hello("hello world")

# define a function hello

function(hello MESSAGE)

message(${MESSAGE})

endfunction(hello)

project(HELLO)  #指定项目名称,生成的VC项目的名称;

>>使用${HELLO_SOURCE_DIR}表示项目根目录

include_directories:指定头文件的搜索路径,相当于指定gcc的-I参数

>> include_directories (${HELLO_SOURCE_DIR}/Hello)  #增加Hello为include目录

link_directories:动态链接库或静态链接库的搜索路径,相当于gcc的-L参数

>> link_directories (${HELLO_BINARY_DIR}/Hello)     #增加Hello为link目录

add_subdirectory:包含子目录

>> add_subdirectory (Hello)

add_executable:编译可执行程序,指定编译,好像也可以添加.o文件

>> add_executable (helloDemo demo.cxx demo_b.cxx)   #将cxx编译成可执行文件——

add_definitions:添加编译参数

>> add_definitions(-DDEBUG)将在gcc命令行添加DEBUG宏定义;

>> add_definitions( “-Wall -ansi –pedantic –g”)

target_link_libraries:添加链接库,相同于指定-l参数

>> target_link_libraries(demo Hello) #将可执行文件与Hello连接成最终文件demo

add_library:

>> add_library(Hello hello.cxx)  #将hello.cxx编译成静态库如libHello.a

add_custom_target:

message( status|fatal_error, “message”):

set_target_properties( ... ): lots of properties... OUTPUT_NAME, VERSION, ....

link_libraries( lib1 lib2 ...): All targets link with the same set of libs

8. FAQ

1)  怎样获得一个目录下的所有源文件

>> aux_source_directory( )

>> 将dir中所有源文件(不包括头文件)保存到变量variable中,然后可以add_executable (ss7gw ${variable})这样使用。

2)  怎样指定项目编译目标

>>  project命令指定

3)  怎样添加动态库和静态库

>> target_link_libraries命令添加即可

4)  怎样在执行CMAKE时打印消息

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

>> 注意大小写

5)  怎样指定头文件与库文件路径

>> include_directories与link_directories

>>可以多次调用以设置多个路径

>> link_directories仅对其后面的targets起作用

6)  怎样区分debug、release版本

>>建立debug/release两目录,分别在其中执行cmake -DCMAKE_BUILD_TYPE=Debug(或Release),需要编译不同版本时进入不同目录执行make即可;

Debug版会使用参数-g;Release版使用-O3 –DNDEBUG

>> 另一种设置方法——例如DEBUG版设置编译参数DDEBUG

IF(DEBUG_mode)

add_definitions(-DDEBUG)

ENDIF()

在执行cmake时增加参数即可,例如cmake -D DEBUG_mode=ON

7)  怎样设置条件编译

例如debug版设置编译选项DEBUG,并且更改不应改变CMakelist.txt

>> 使用option command,eg:

option(DEBUG_mode "ON for debug or OFF for release" ON)

IF(DEBUG_mode)

add_definitions(-DDEBUG)

ENDIF()

>> 使其生效的方法:首先cmake生成makefile,然后make edit_cache编辑编译选项;Linux下会打开一个文本框,可以更改,该完后再make生成目标文件——emacs不支持make edit_cache;

>> 局限:这种方法不能直接设置生成的makefile,而是必须使用命令在make前设置参数;对于debug、release版本,相当于需要两个目录,分别先cmake一次,然后分别make edit_cache一次;

>> 期望的效果:在执行cmake时直接通过参数指定一个开关项,生成相应的makefile——可以这样做,例如cmake –DDEBUGVERSION=ON

8)  怎样添加编译宏定义

>> 使用add_definitions命令,见命令部分说明

9)  怎样添加编译依赖项

用于确保编译目标项目前依赖项必须先构建好

>>add_dependencies

10)        怎样指定目标文件目录

>> 建立一个新的目录,在该目录中执行cmake生成Makefile文件,这样编译结果会保存在该目录——类似

>> SET_TARGET_PROPERTIES(ss7gw PROPERTIES

RUNTIME_OUTPUT_DIRECTORY "${BIN_DIR}")

11)        很多文件夹,难道需要把每个文件夹编译成一个库文件?

>> 可以不在子目录中使用CMakeList.txt,直接在上层目录中指定子目录

12)        怎样设定依赖的cmake版本

>>cmake_minimum_required(VERSION 2.6)

13)        相对路径怎么指定

>> ${projectname_SOURCE_DIR}表示根源文件目录,${ projectname _BINARY_DIR}表示根二进制文件目录?

14)        怎样设置编译中间文件的目录

>> TBD

15)        怎样在IF语句中使用字串或数字比较

>>数字比较LESS、GREATER、EQUAL,字串比STRLESS、STRGREATER、STREQUAL,

>> Eg:

set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON)

set(AAA abc)

IF(AAA STREQUAL abc)

message(STATUS "true")   #应该打印true

ENDIF()

16)        更改h文件时是否只编译必须的cpp文件

>> 是

17)        机器上安装了VC7和VC8,CMAKE会自动搜索编译器,但是怎样指定某个版本?

>> TBD

18)        怎样根据OS指定编译选项

>> IF( APPLE ); IF( UNIX ); IF( WIN32 )

19)        能否自动执行某些编译前、后命令?

>> 可以,TBD

20)        怎样打印make的输出

make VERBOSE=1

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • CMake学习 本篇分享一下有关CMake的一些学习心得以及相关使用。 本文目录如下: [1、CMake介绍] [...
    AlphaGL阅读 12,219评论 11 79
  • 注:首发地址 1. 前言 当在做 Android NDK 开发时,如果不熟悉用 CMake 来构建,读不懂 CMa...
    cfanr阅读 24,222评论 1 53
  • Cmake 入门 前言 CMake是一个比make更高级的编译配置工具,它可以根据不同平台、不同的编译器,生成相应...
    渝潼不肖生阅读 2,052评论 1 5
  • 果真是大师级的电影人,吴天明导演的《百鸟朝凤》整部我是含着眼泪看完的。影片中焦三爷有句话“唢呐匠人就是要把唢呐吹到...
    川外晴天阅读 210评论 0 0
  • 来深的第三个月,误打误撞的进入了互联网行业,从事着自己喜欢的工作。第一次有勇气将自己打翻重塑,挑战自己并不擅长的东...
    小小惞阅读 259评论 0 0