cmake使用方法(详细)

帮助文档

  1. cmake官方新手tutorial
  2. cmake 添加头文件目录,链接动态、静态库
  3. 官方文档
  4. cmake 语法
  5. cmake中的link_directories, LINK_LIBRARIES, target_link_libraries的区别

技巧

  1. cmake命令是不区分大小写的,但是变量区分。

  2. 判断编译器类型

     if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
     MESSAGE("Clang")
     elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
     MESSAGE("GNU")
     elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
     MESSAGE("Intel")
     elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
     MESSAGE("MSVC")
     endif()
    

命令行选项

-D

  1. -D 相当于就是定义, -D 可以理解为告诉cmake 后边我要定义一些参数了, 你每定义一个就在前边加上-D就是了
  2. CMAKE_BUILD_TYPE 这种东西往往是在CMakeList.txt 中定义的, 这个是你要编译的类型, 一般的选择有debug,release, 但是不确定
  3. CMAKE_INSTALL_PREFIX 这个是安装路径.

例子

cmake -DCMAKE_BUILD_TYPE=Debug

编译选项

cmake脚本中,设置编译选项可以通过add_compile_options命令,也可以通过set命令修改CMAKE_CXX_FLAGSCMAKE_C_FLAGS
使用这两种方式在有的情况下效果是一样的,但请注意它们还是有区别的:

  1. add_compile_options命令添加的编译选项是针对所有编译器的(包括c和c++编译器),
  2. 而set命令设置CMAKE_C_FLAGSCMAKE_CXX_FLAGS变量则是分别只针对c和c++编译器的。

例子

#判断编译器类型,如果是gcc编译器,则在编译选项中加入c++11支持
if(CMAKE_COMPILER_IS_GNUCXX)
    set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
    message(STATUS "optional:-std=c++11")
endif(CMAKE_COMPILER_IS_GNUCXX)

指定编译器

set(CMAKE_C_COMPILER "/usr/local/gcc")
set(CMAKE_CXX_COMPILER "/usr/local/g++")

也可以直接在编译的时候指定:

cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_COMPILER="/tools/bin/cc"   -DCMAKE_CXX_COMPILER="/tools/bin/c++"

add_compile_options

语法

add_compile_options(<option> ...)

# 例子

add_compile_options(-Wall -Wextra -pedantic -Werror -g)

add_compile_definition

待补充

option & add_definition

语法

# Provides an option for the user to select as ON or OFF. If no initial <value> is provided, OFF is used. If <variable> is already set as a normal variable then the command does nothing
option(<variable> "<help_text>" [value])

# Add -D define flags to the compilation of source files.
add_definitions(-DFOO -DBAR ...)

使用方法

  1. 首先在CMakeList.txt中增加选项

    option(TEST_DEBUG "option for debug" OFF)
    if (TEST_DEBUG)  # 这一步是cmake接收到这个参数了
    add_definitions(-DTEST_DEBUG)  # 这一步意思是make编译的时候加上TEST_DEBUG这个定义
    endif()
    
  2. 在cmake构造makefile的时候输入想要的参数

    cmake -DTEST_DEBUG=ON ..
    
  3. 源码中使用该定义

    // test.cpp
    #include "test.h"
    
    #ifdef TEST_DEBUG
    ...
    #endif
    

语法说明

列表和字符串

在CMake中基础的数据形式是字符串。CMake也支持字符串列表。

列表通过分号分隔。譬如两个声明给变量VAR设同样的值:

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

字符串列表可以通过foreach命令迭代或直接操控列表命令。

变量

CMake 支持简单的变量可以是字符串也可以是字符串列表。变量参考使用${VAR}语法。多参数可以使用set命令组合到一个列表中。所有其他的命令

通过空白分隔符传递命令来扩展列表,例如

set(Foo a b c)
# 将 变量 Foo 设为 a b c, 并且如果Foo 传递给另一个命令
command(${Foo})
# 等同于
command(a b c)

# 如果要把参数列表传递给一个命令,且它是一个简单的参数只要加一个双引号就可以。例如
command("${Foo}")
# 等价于
command("a b c")

控制流

像大多数语言一样,Cmake 提供了控制流结构。Cmake提供了三中控制流:

  1. 条件控制流 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)
    
  2. 循环结构: foreachwhile

    set(VAR a b c)
    # loop over a, b,c with the variable f
    foreach(f ${VAR})
        message(${f})
    endforeach(f)
    
  3. 过程定义 宏和函数(函数在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)
    

更多控制流信息参见命令 if,while,foreach,macro,function文档。

引号,字符串和转义

在CMake中原义字符串用双引号括起来。字符串可以是多行字符串,并在其中嵌入新的行。例如

set(MY_STRING "this is a string with a

 newline in

it")

也可以在一个字符串中转义字符和使用变量

set(VAR "

  hello

  world

")

message("\${VAR}= ${VAR}")

# prints out

${VAR}=

hello

world

同样支持标准C中的转义

message("\n\thello world")

#prints out

hello world

如果字符在引号之前是空格则原义字符串只是原义字符串。但是引号必须成对,例如

message(hell"o") -> prints hell"o"
message(hell\"o\") -> prints hello"o"

正则表达式

cmake可以使用正则表达式

常用命令

cmake_minimum_required

cmake project 头文件必须存在这行命令, 例如cmake_minimum_required(VERSION 3.10)

project

设置项目名称project(Tutorial)

set

语法

# Set Normal Variable
set(<variable> <value>... [PARENT_SCOPE])

# Set Environment Variable
# 这个环境变量只对当前cmake工程有效,对外界是无效的。
set(ENV{<variable>} [<value>])

例子

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O3 -Wall -Wl,-rpath=/tools/lib64 -Wl,--dynamic-linker=/tools/lib/ld-2.17.so")

message

语法

message([<mode>] "message to display" ...)

mode关键字

The optional <mode> keyword determines the type of message:

mode explaination
FATAL_ERROR CMake Error, stop processing and generation.
SEND_ERROR CMake Error, continue processing, but skip generation.
WARNING CMake Warning, continue processing.
AUTHOR_WARNING CMake Warning (dev), continue processing.
DEPRECATION CMake Deprecation Error or Warning if variable CMAKE_ERROR_DEPRECATED or CMAKE_WARN_DEPRECATED is enabled, respectively, else no message.
(none) or NOTICE Important message printed to stderr to attract user’s attention.
STATUS 一般就用这个,Ideally these should be concise, no more than a single line, but still informative.
VERBOSE Detailed informational messages intended for project users. These messages should provide additional details that won’t be of interest in most cases, but which may be useful to those building the project when they want deeper insight into what’s happening.
DEBUG Detailed informational messages intended for developers working on the project itself as opposed to users who just want to build it. These messages will not typically be of interest to other users building the project and will often be closely related to internal implementation details.
TRACE Fine-grained messages with very low-level implementation details. Messages using this log level would normally only be temporary and would expect to be removed before releasing the project, packaging up the files, etc.

aux_source_directory 查找源文件

# 找到所有dir目录下的源文件(不会递归遍历子文件夹),源文件是.c文件(也就是makefile中可以生成.o的文件)
aux_source_directory(<dir> <variable>)

add_library

将指定的源文件(CPP文件)生成链接文件,然后添加到工程中去。

语法

add_library(<name> [STATIC | SHARED | MODULE]
            [EXCLUDE_FROM_ALL]
            [source1] [source2 ...])

其中<name>表示库文件的名字,该库文件会根据命令里列出的源文件来创建。而STATICSHAREDMODULE的作用是指定生成的库文件的类型。

  1. STATIC库是目标文件的归档文件,在链接其它目标的时候使用。
  2. SHARED库会被动态链接(动态链接库),在运行时会被加载。
  3. MODULE库是一种不会被链接到其它目标中的插件,但是可能会在运行时使用dlopen-系列的函数。
  4. 默认状态下,库文件将会在于源文件目录树的构建目录树的位置被创建(默认static),该命令也会在这里被调用。

例子

add_library(roland_pb CreateUDiskRequest.pb.cc)
add_executable(echo_client echo_client.cc)
target_link_libraries(echo_client uevent event uevent_base pthread roland_pb protobuf)

add_subdirectory

在子文件夹添加了library或者executable之后,在上层目录添加subdirectory, 也可以在同一个CMakeList.txt中使用

include_directories 添加头文件目录

它相当于g++选项中的-I参数的作用,也相当于环境变量中增加路径到CPLUS_INCLUDE_PATH变量的作用。

语法:

include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
# 例子
include_directories(../../../thirdparty/comm/include)

link_directories 添加需要链接的库文件目录

它相当于g++命令的-L选项的作用,也相当于环境变量中增加LD_LIBRARY_PATH的路径的作用。
语法:

`link_directories(directory1 directory2 ...)`
# 例子
`link_directories("/home/server/third/lib")`

find_library 查找库所在目录

语法:

# A short-hand signature is:
find_library (<VAR> name1 [path1 path2 ...])

# The general signature is:
find_library (
          <VAR>
          name | NAMES name1 [name2 ...] [NAMES_PER_DIR]
          [HINTS path1 [path2 ... ENV var]]
          [PATHS path1 [path2 ... ENV var]]
          [PATH_SUFFIXES suffix1 [suffix2 ...]]
          [DOC "cache documentation string"]
          [NO_DEFAULT_PATH]
          [NO_CMAKE_ENVIRONMENT_PATH]
          [NO_CMAKE_PATH]
          [NO_SYSTEM_ENVIRONMENT_PATH]
          [NO_CMAKE_SYSTEM_PATH]
          [CMAKE_FIND_ROOT_PATH_BOTH |
           ONLY_CMAKE_FIND_ROOT_PATH |
           NO_CMAKE_FIND_ROOT_PATH]
         )

# 例子如下
FIND_LIBRARY(RUNTIME_LIB rt /usr/lib  /usr/local/lib NO_DEFAULT_PATH)
cmake会在目录中查找,如果所有目录中都没有,值RUNTIME_LIB就会被赋为NO_DEFAULT_PATH

link_libraries 添加需要链接的库文件路径

该指令的作用主要是指定要链接的库文件的路径,该指令有时候不一定需要。因为find_package和find_library指令可以得到库文件的绝对路径。不过你自己写的动态库文件放在自己新建的目录下时,可以用该指令指定该目录的路径以便工程能够找到。

语法:

link_libraries(library1 <debug | optimized> library2 ...)

# 直接是全路径
link_libraries(“/home/server/third/lib/libcommon.a”)
# 下面的例子,只有库名,cmake会自动去所包含的目录搜索
link_libraries(iconv)

# 传入变量
link_libraries(${RUNTIME_LIB})
# 也可以链接多个
link_libraries("/opt/MATLAB/R2012a/bin/glnxa64/libeng.so" "/opt/MATLAB/R2012a/bin/glnxa64/libmx.so")

可以链接一个,也可以多个,中间使用空格分隔.

target_link_libraries 设置要链接的库文件的名称 具体的动态链接库文件.so

语法:

target_link_libraries(<target> [item1 [item2 [...]]]
                      [[debug|optimized|general] <item>] ...)

# 以下写法都可以:
target_link_libraries(myProject comm)       # 连接libhello.so库,默认优先链接动态库
target_link_libraries(myProject libcomm.a)  # 显示指定链接静态库
target_link_libraries(myProject libcomm.so) # 显示指定链接动态库

# 再如:
target_link_libraries(myProject libcomm.so)  #这些库名写法都可以。
target_link_libraries(myProject comm)
target_link_libraries(myProject -lcomm)

add_executable 为工程生成目标文件

语法:

add_executable(<name> [WIN32] [MACOSX_BUNDLE]
               [EXCLUDE_FROM_ALL]
               source1 [source2 ...])

简单的例子如下:

add_executable(demo main.cpp)
add_executable(echo_client echo_client.cc CreateUDiskRequest.pb.cc)

CMAKE_INSTALL_PREFIX 在install的时候增加路径前缀

一般情况下,make install在不指定prefix默认安装在`/usr/local/bin

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

推荐阅读更多精彩内容