CMake简单语法

  • Post author:
  • Post category:其他


CMake官方文档

https://cmake.org/cmake/help/v3.15/index.html



基本命令方法





cmake_minimum_required


为工程设置CMake最低需求版本

cmake_minimum_required(VERSION 3.5)  #检查cmake的版本,至少为3.5





project


设置工程的名称

project (hello_cmake) # 设置当前工程名为 hello_cmake

使用该指令之后系统会自动创建两个变量:

message(${PROJECT_NAME})
message(${${PROJECT_NAME}_BINARY_DIR})
message(${${PROJECT_NAME}_SOURCE_DIR})
# <projectname>_BINARY_DIR:二进制文件保存路径
# <projectname>_SOURCE_DIR:源代码路径
# 输出:
# TestDemo
# /home/leacock/CLionProjects/TestDemo/cmake-build-debug
# /home/leacock/CLionProjects/TestDemo




add_executable(exename srcname)

exename:生成的可执行文件的名字

srcname:依赖的源文件

指定生成可执行文件的名字以及指出需要依赖的源文件的文件名

add_executable(hello_cmake main.cpp)	#生产可执行文件hello_cmake 依赖源文件main.cpp




set

Set a normal, cache, or environment variable to a given value.

设置局部变量、缓存变量(相当于全局变量)、环境变量

#设置局部变量:
set(MY_VARIABLE "value")
#变量的名称通常大写
#访问变量:${MY_VARIABLE}

#设置缓存变量:
set(MY_CACHE_VALUE "cache_value" CACHE INTERNAL "THIS IS MY CACHE VALUE")	
#THIS IS MY CACHE VALUE,这个字符串相当于对变量的描述说明,不能省略,但可以自己随便定义

#设置环境变量:
set(ENV{variable_name} value)
#获取环境变量:$ENV{variable_name}
#缓存就是CMakeCache文件




target_include_directories

指定在编译给定目标时需要使用的文件目录

target_include_directories(<target> [SYSTEM] [BEFORE]
  <INTERFACE|PUBLIC|PRIVATE> [items1...]
  [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
# <target> 必须被add_executable() 或 add_library() 创建
# <INTERFACE|PUBLIC|PRIVATE> 用于指定后面参数的范围

# eg:
target_include_directories(hello_library
    PUBLIC 
        ${PROJECT_SOURCE_DIR}/include
)




include_directories

将给定的目录添加到编译器用于搜索包含文件的目录中。指定的目录被解释成当前源码路径的相对路径。

include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
# eg:
include_directories(sub) 
include_directories(sub2) #默认将sub2添加到列表最后
include_directories(BEFORE sub3) #可以临时改变行为,添加到列表最前面

默认情况下,

include_directories

命令会将目录添加到列表最后,可以通过命令设置

CMAKE_INCLUDE_DIRECTORIES_BEFORE

变量为

ON

来改变它默认行为,将目录添加到列表前面。也可以在每次调用

include_directories

命令时使用

AFTER



BEFORE

选项来指定是添加到列表的前面或者后面。


注:

官方文档更推荐使用

target_include_directories



target_include_directories

命令将包含目录添加到各个指定目标。相对来说

include_directories

影响范围更大。




add_library

生成lib库

add_library(<name> [STATIC | SHARED | MODULE]
            [EXCLUDE_FROM_ALL]
            [source1] [source2 ...])
# libname:生成的库文件的名字
# [SHARED|STATIC|MODULE]:生成库文件的类型(动态库|静态库|模块)
# [EXCLUDE_FROM_ALL]:有这个参数表示该库不会被默认构建
# [source1] [source2 ...]:生成库依赖的源文件,如果源文件比较多,可以使用aux_sourcr_directory命令获取路径下所有源文件

# eg:
#Generate the static library from the library sources
add_library(hello_library STATIC 
    src/Hello.cpp
)

add_library(hello::library ALIAS hello_library)
# ALIAS 创建动态库别名 hello::library




target_link_libraries

为给定的目标设置链接时使用的库(设置要链接的库文件的名称)

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

# eg:
target_link_libraries(MyProject a b.a c.so)   # 将若干库文件链接到MyProject中,target_link_libraries里的库文件的顺序符合gcc/g++链接顺序规则,即:被依赖的库放在依赖他的库的后面,如果顺序有错,链接将会报错
# 关键字:debug对应于调试配置
# 关键字:optimized对应于所有其他的配置类型
# 关键字:general对应于所有的配置(该属性是默认值)




find_package

如果编译的过程使用了外部的库,事先并不知道其头文件和链接库的位置,得在编译命令中加上包含外部库的查找路径,CMake中使用find_package方法




find_package()

原理解读


find_package()

有Module模式(基本用法,basic signature)和Config模式(full signature,完全用法),其中Module模式是基础,Config模式则更复杂高级些。

只有这3种情况下才是Config模式:


  • find_package()

    中指定

    CONFIG

    关键字
  • `
  • find_package()

    中指定

    NO_MODULE`关键字

  • find_package()

    中使用了不在”basic signature”(也就是Module模式下所有支持的配置)关键字


find_package()

区别是Module模式还是Config模式,如果是Module模式,在查找失败时会继续采用Config模式查找



Module模式下

find_package()

的用法

find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE]
         [REQUIRED] [[COMPONENTS] [components...]]
         [OPTIONAL_COMPONENTS components...]
         [NO_POLICY_SCOPE])


version



EXACT

: 都是可选的,

version

指定的是版本,如果指定就必须检查找到的包的版本是否和

version

兼容。如果指定

EXACT

则表示必须完全匹配的版本而不是兼容版本就可以。


QUIET

可选字段,表示如果查找失败,不会在屏幕进行输出(但是如果指定了

REQUIRED

字段,则

QUIET

无效,仍然会输出查找失败提示语)。


MODULE

可选字段。前面提到说“如果Module模式查找失败则回退到Config模式进行查找”,但是假如设定了

MODULE

选项,那么就只在Module模式查找,如果Module模式下查找失败并不回落到Config模式查找。


REQUIRED

可选字段。表示一定要找到包,找不到的话就立即停掉整个cmake。而如果不指定

REQUIRED

则cmake会继续执行。


COMPONENTS



components

:可选字段,表示查找的包中必须要找到的组件(components),如果有任何一个找不到就算失败,类似于

REQUIRED

,导致cmake停止执行。


OPTIONAL_COMPONENTS



components

:可选的模块,找不到也不会让cmake停止执行。


Module模式查找顺序

Module模式下是要查找到名为

Find.cmake

的文件;先在

CMAKE_MODULE_PATH

变量对应的路径中查找。如果路径为空,或者路径中查找失败,则在cmake module directory(cmake安装时的Modules目录,比如

/usr/local/share/cmake/Modules

)查找。



Config模式下

find_package()

的用法

参见

https://www.jianshu.com/p/39fc5e548310




aux_source_directory

查找目录中的所有源文件

aux_source_directory(<dir> <variable>)

搜集所有在指定路径下的源文件的文件名,将输出结果列表储存在指定的变量中。




add_subdirectory

将指定的文件夹加到build任务列表中

add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
# eg:
add_subdirectory(src)




message


为用户显示一条消息

 message( [STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR]
  "message to display" ...)
#  (无) = 重要消息;
# STATUS = 非重要消息;
# WARNING = CMake 警告, 会继续执行;
# AUTHOR_WARNING = CMake 警告 (dev), 会继续执行;
# SEND_ERROR = CMake 错误, 继续执行,但是会跳过生成的步骤;
# FATAL_ERROR = CMake 错误, 终止所有处理过程;
# 可以打印变量
message("PROJECT_SOURCE_DIR = ${PROJECT_SOURCE_DIR}")




list

列表操作,参见

list

list(LENGTH <list><output variable>)
list(GET <list> <elementindex> [<element index> ...]<output variable>)
list(APPEND <list><element> [<element> ...])
list(FIND <list> <value><output variable>)
list(INSERT <list><element_index> <element> [<element> ...])
list(REMOVE_ITEM <list> <value>[<value> ...])
list(REMOVE_AT <list><index> [<index> ...])
list(REMOVE_DUPLICATES <list>)
list(REVERSE <list>)
list(SORT <list>)

#LENGTH            返回list的长度
#GET              返回list中index的element到value中
#APPEND            添加新element到list中
#FIND             返回list中element的index,没有找到返回-1
#INSERT           将新element插入到list中index的位置
#REMOVE_ITEM      从list中删除某个element
#REMOVE_AT       从list中删除指定index的element
#REMOVE_DUPLICATES       从list中删除重复的element
#REVERSE         将list的内容反转
#SORT           将list按字母顺序排序
# eg:
list(APPEND libraries log4cplus zmq)




install

make install的时候,是需要我们定义一个install的目标,命令install用于指定在安装时运行的规则。

参见

【CMake】cmake的install指令

参见

install官方文档

参数中的

TARGET

可以是很多种目标文件,最常见的是

通过ADD_EXECUTABLE或者ADD_LIBRARY定义的目标文件,即可执行二进制、动态库、静态库


DESTINATION

参数:定要将文件安装到磁盘上的目录。 推荐配置在安装目录变量下的文件夹。

install(TARGETS <target>... [...])
install({FILES | PROGRAMS} <file>... [...])
install(DIRECTORY <dir>... [...])
install(SCRIPT <file> [...])
install(CODE <code> [...])
install(EXPORT <export-name> [...])

# 安装 Binaries 
install (TARGETS cmake_examples_inst_bin
    DESTINATION bin) # 将 cmake_examples_inst_bin 安装到 ${CMAKE_INSTALL_PREFIX}/bin 目录

# 安装 Library
# Note: may not work on windows
install (TARGETS cmake_examples_inst
    LIBRARY DESTINATION lib) # 将 cmake_examples_inst 安装到 ${CMAKE_INSTALL_PREFIX}/lib 目录

# 安装 Header files
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/ 
    DESTINATION include)	# 将 指定文件夹 安装到 ${CMAKE_INSTALL_PREFIX}/include 目录

# 安装 Config
install (FILES cmake-examples.conf
    DESTINATION etc)	# 将 指定文件 安装到 ${CMAKE_INSTALL_PREFIX}/etc 目录


CMAKE_INSTALL_PREFIX



用于指定cmake install时的相对地址前缀

。用法如:

cmake -DCMAKE_INSTALL_PREFIX=/usr ..

DESTINATION定义了安装的路径,如果路径以/开头,那么指的是绝对路径,这时候CMAKE_INSTALL_PREFIX其实就无效了。如果你希望使用CMAKE_INSTALL_PREFIX来定义安装路径,就要写成相对路径,即不要以/开头,那么安装后的路径就是${CMAKE_INSTALL_PREFIX}/<DESTINATION定义的路径>



基本控制语法




if

if (expression)
    COMMAND1(ARGS ...)
    COMMAND2(ARGS ...)
    ...
else (expression)
    COMMAND1(ARGS ...)
    COMMAND2(ARGS ...)
    ...
endif (expression)
# 注意:endif要和if对应

if(not exp)	# 非
if(var1 AND var2) # 与
if(var1 OR var2) # 或
if(COMMAND cmd)  # 如果cmd确实是命令并可调用 为真;
if(EXISTS dir) # 如果目录存在 为真
if(EXISTS file) # 如果文件存在 为真
if(file1 IS_NEWER_THAN file2) # 当file1比file2新 或file1/file2中有一个不存在时为真 文件名需使用全路径
if(IS_DIRECTORY dir) # 当dir是目录时 为真
if(DEFINED var) # 如果变量被定义 为真
if(string MATCHES regex) # 当给定变量或字符串能匹配正则表达式regex时 为真

if(var LESS number) # var小于number为真
if(var GREATER number) # var大于number为真
if(var EQUAL number) # var等于number为真

if(var1 STRLESS var2) # var1字母顺序小于var2为真
if(var1 STRGREATER var2) # var1字母顺序大于var2为真
if(var1 STREQUAL var2) # var1和var2字母顺序相等为真




while

while(<condition>)
  <commands>
endwhile()
# <condition>  使用同 if
# 命令  break() 和 continue() 用于跳出和继续循环




foreach

foreach有四种使用形式的语法,且每个foreach都需要一个endforeach()与之匹配



1. 第一种形式 列表循环

foreach(loop_var arg1 arg2 ...)
  COMMAND1(ARGS ...)
  COMMAND2(ARGS ...)
  ...
endforeach(loop_var)
# eg:
foreach(i 0 1 2 3)
    message(STATUS "current is ${i}")
endforeach(i)

注意

endforeach(loop_var)

的变量最好不要省略,因为foreach循环是依靠变量来跳出循环的。



foreach

和匹配

endforeach

之间的所有命令都会被系统记录而不被调用。 一旦找到了了

endforeach

,则会执行原来记录的命令。在循环的每次迭代之前,

${loop_var}

将被设置为具有列表中当前值的变量。



2. 第二种形式 范围循环

foreach(loop_var RANGE total)

# eg: 范围将会是0-3
foreach(i RANGE 3)
    message(STATUS "current is ${i}")
endforeach(i)



3. 第三种形式 范围步进循环

foreach(loop_var RANGE start stop [step])
# eg:
foreach(i RANGE 0 3 1)
message(STATUS "current is ${i}")
endforeach(i)

从start开始直到stop结束之间的值,可以设置步进值step



4. 第四种形式 LISTS范围循环

foreach(loop_var IN [LISTS [list1 [...]]]
                    [ITEMS [item1 [...]]])

# eg:
set(A 0;1)
set(B 2 3)
set(C "4 5")
set(D 6;7 8)
set(E "")
foreach(X IN LISTS A B C D E)
    message(STATUS "X=${X}")
endforeach()



基本参数


PROJECT_SOURCE_DIR

当前项目的顶层源目录


PROJECT_BINARY_DIR

项目的编译目录完整路径。


CMAKE_INSTALL_PREFIX


用于指定cmake install时的相对地址前缀

,参见

install


CMAKE_ARCHIVE_OUTPUT_DIRECTORY

指定在编译时将所有归档目标文件放在哪里,用于初始化所有目标上的

ARCHIVE_OUTPUT_TRISTORY

属性。


CMAKE_LIBRARY_OUTPUT_DIRECTORY

指定在编译时将所有库文件放在哪里,用于初始化所有目标上的

Library_Output_Directory

属性。


CMAKE_RUNTIME_OUTPUT_DIRECTORY

指定所有运行时目标文件放在哪里,于初始化所有目标上的

RUNTIME_OUTPUT_DIRECTORY

属性。

# 输出目录,${PROJECT_BINARY_DIR}为Cmake命令执行的位置
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)



版权声明:本文为leacock1991原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。