cmake 常用指令入门指南


本博客记录:在使用cmake进行构建工程时,写CMakeLists.txt 文件时,常使用到的命令与变量, 不断补充更新中。

相关链接

官方地址: https://cmake.org/cmake/help/
git上很好实践教程: https://github.com/ttroy50/cmake-examples

CMKAE中脚本相关的命令

cmake_minimum_required 命令

语法与参数介绍

语法: cmake_minimum_required(VERSION min[...policy_max] [FATAL_ERROR])

  • min 指定了编译当前的cmake需要的最old的版本号,如果cmake版本号小于指定的版本号时,运行cmake 就报错。

    举例:当前有cmake版本号为3.10.2, 运行如下的CMakeLists.txt 文件时, 就会报错:

    cmake_minimum_required(VERSION 3.12)
    

    运行cmake命令,报错如下:提示运行版本小于要求的最小版本。

    CMake Error at CMakeLists.txt:1 (cmake_minimum_required):
    CMake 3.10.3 or higher is required.  You are running version 3.10.2
    
    
    -- Configuring incomplete, errors occurred!
    
  • ... 表示min或max版本号之间的连接符。

  • policy_max 参数与cmake的policy setting相关,当指定了【policy_max】参数(要大于等于min版本号)时, 所有【小于等于 policy_max版本 或者 小于等于当前运行版本(谁小取谁)】中的已经的policy都设置为NEW.

    policy 可以理解为版本之间的变更,例如语法新增加、约束变严等, policy使用CMPXXXX格式的编号,例如:CMP0000表示cmake文件中必须指定要求的最低版本号,CMP0002表示....等。
    在新的版本中,如果要指定policy的新的规定, 语法为: cmake_policy(SET CMPXXXX NEW), 有时候为了新版本兼容之前写的CMakeLists.txt文件, 则可以使用原来的policy, 语法为:cmake_policy(SET CMPXXXX OLD).
    可以使用cmake_policy(VERSION min[...max])指定policy的要求min与max版本号:
    - 当不指定max版本号时,cmake会把min版本以及之前的版本引入的所有policy设置为NEW, 大于min版本号引入的policy默认不设置。
    - 当指定max版本号时, cmake会把 【max版本或者当前运行的版本号(谁小取谁)】以及之前的版本号引入的的所有polixy设置为NEW, 超过的版本引入的policy默认不设置。
    当使用cmake_minimum_required(VERSION)命令时,会隐式地调用cmake_policy(VERSION)命令用于设置policy相关的版本要求。

举例: 下面的cmake命令:

cmake_mini_mum_required(VERSION 3.12...3.15)

# 上面命令会隐示地调用下面这条命令
cmake_policy(VERSION 3.12...3.15)
  • FATAL_ERROR
    该选项在2.6涉及2.6版本以下有用, 当指定该选项时,如果当前支行的版本号小于要求的版本号,就会报错;如果不指定该选项时,只会报warning. 2.6版本之后,都是报错了,所以用不着该选项了。

引入的变量

  • CMAKE_MINIMUM_REQUIRED_VERSION : 设置该变量的值为 min.

file 命令

file 命令专门用于访问文件系统对文件与路径进行操作的。

读相关

写相关

文件系统相关

file(GLOB variable 通配符表达式)

语法与参数

使用语法为: file(GLOB <variable> [LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS] [<globbing-expressions>...])
含义: GLOB, 就是globbing的缩写, 该命令查找所有在当前目录(CMakeLists.txt所在目录,即CMAKE_CURRENT_SOURCE_DIR变量)下所有满足匹配通配符表达式的文件,并保存到给定的变量中。

  • GLOB: 是关键字。
  • variable: 保存文件名的变量
  • LIST_DIRECTORIES true| false : 表示是否要保存文件的路径,默认保存。 (试了一下,置为false为什么不管用呢?)
  • RELATIVE path: 给定该参数时,保存的路径中是相对于给定path的路径名。
  • globbing-expressions: 通配符表达式。

使用举例

file(GLOB source_list "src/*.cpp")

注意事项

不建议使用该命令搜索源文件名,原因是:如果CMakeLists.txt文件没有变化,但是你增加了源文件, 此时给的结果不一样正确。(我试了一下,ubuntu下可以给出正确结果)

路径转换相关

set命令

设置普通的命令

使用语法:set(<variable> <value>... [PARENT_SCOPE]), 设置一个变量的值。 如果不给定值,就表示取消该变量的设置。

  • PARENT_SCOPE: 表示在上层作用域内设置变量的值。

使用举例

set(SOURCE_LIST 1.c 2.c 3.c)

设置cache 变量

使用语法与参数含义

语法:set(<variable> <value>... CACHE <type> <docstring> [FORCE]), 该命令会设置的cache变量会被保存到CMakeCache.txt 文档中, 可以打开看看的。

  • CACHE 是关键字。
  • type 表示变量的类型, 包含: BOOL、FILEPATH、PATH、STRING、INTERNAL。
  • docstring: 类型注释,表明该参数的含义。
  • FORCE: 默认情况下,如果该cache 变量已经设置过了,再次执行该变量就不会被写入,如果使用了FORCE关键字的话,只要命令被执行,就会对变量进行写入的。

使用举例

set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)

set_property 命令

使用语法与参数含义

该命令用于设置一个对象的属性信息, 它的使用语法如下所示:

set_property(<GLOBAL                      |
              DIRECTORY [<dir>]           |
              TARGET    [<target1> ...]   |
              SOURCE    [<src1> ...]
                        [DIRECTORY <dirs> ...] |
                        [TARGET_DIRECTORY <targets> ...]
              INSTALL   [<file1> ...]     |
              TEST      [<test1> ...]     |
              CACHE     [<entry1> ...]    >
             [APPEND] [APPEND_STRING]
             PROPERTY <name> [<value1> ...])
  • [对象类型] [对象名称]: 指定了对象的类型以及要设置的对象名称, 包含: GLOBAL, DIRECTORY, TARGET, SOURCE 等。例如TARGET hello_main.
  • PROPERTY 属性名: 指定了要设置的属性名以及属性值。

使用举例

cmake_minimum_required(VERSION 3.10.2)
project(hello_main)
add_executable(hello_main main.cpp)
set_property(TARGET hello_main PROPERTY CXX_STANDARD 11)

include 命令

** 语法与参数说明**

该命令用于导入文件或模块中的CMAKE代码, 类似于c语言中的include 功能。 使用语法为:

include(<file|module> [OPTIONAL] [RESULT_VARIABLE <var>]
                      [NO_POLICY_SCOPE])
  • file | module: 指定的包含CMKE指定的文件 或者 模块名。模块名其实就是安装cmake时已经提供的***.cmake文件(例如/usr/share/cmake-3.10/Modules/目录下好多模块)
  • OPTIONAL: 如果指定了该选项,当cmake查找不到指定文件时,不会报错, 因为它是可选的嘛。
  • RESULT_VARIABLE var: 用于保存查找到的文件路径(查找成功时) 或者保存失败结果NOTFOUND(失败时)

举例说明

cmake_minimum_required(VERSION 2.8)
project (hello_cpp11)

#这里导入CheckCXXCompilerFlag模块, 并运行该模块内的CHECK_CXX_COMPILER_FLAG命令。
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)

message 命令

该命令是用于记录log消息的,使用语法为:message([<mode>] "message text" ...)。 其中,mode 关键字用于表示要记录的log的类型,常用的有:

  • FATAL_ERROR: cmake errer, 遇到该错误,cmake 直接停止处理。
  • WARNING: 警告信息, 但是cmake会继续执行下去的。
  • STATUS: 用于记录一些cmake 运行过程中的有用的信息。

例如:

message(STATUS "hello, world.")
set(NAME xiaoming)
messaeg(STATUS "hello, ${NAME}")

CMAKE中project相关命令

project 命令

语法与参数

使用语法为:project(项目名字, [VERSION 版本号] [DESCRIPTION 描述字符串] ), 例如:

project(myproject, VERSION 1.0.0 DESCRIPTION "my first project" )
  • 项目名字, 即指定一个项目名字
  • VERSION, 指定项目的版本号, 可选字段, 一般不用不着它,不学习,不介绍
  • DESCRIPTION, 项目的描述, 可选字段,一般也不需要用它,不学习,不介绍
  • 还有其它的可选参数,例如HOMEPAGE_URL, LANGUAGES, 用不着,不介绍

隐式引入的变量

  • PROJECT_NAME: 它的值为 最近调用的project()命令设置的项目名, 例如你的子目录中调用了project()命令,那么该变量名在子目录中的值就是新设置的项目名。
  • CMAKE_PROJECT_NAME: 它的值为 最top 层的 project 设置的项目名
  • PROJECT_SOURCE_DIR: 最近 调用project() 命令定义的项目所在的源文件的绝对路径。
    例如:在根目录中定义的CMakeLists.txt文件中调用了project()命令, 在该作用域内, 该变量的值就是定义该CMakeLists.txt的绝对路径。
    如果在子目录中定义的CMakeLists.txt文件中也调用了project()命令, 在子目录中CMakeLists.txt的作用域内,该变量的值就是子目录的绝对路径。
  • PROJECT_BINARY_DIR: 最近调用project()命令定义的项目的binary的绝对路径。 与调用cmake命令的位置有关, 通常会在build 目录下调用cmake, 所以该binary目录都在build 目录内。
  • <PROJECT-NAME>_SOURCE_DIR: 首先不推荐使用它,如果你修改的项目名字,该变量名也需要适配。 它的值与PROJECT_SOURCE_DIR变量的值相同。
  • <PROJECT-NAME>_BINARY_DIR: 不推荐使用, 与PROJECT_BINARY_DIR的值相同。

add _executable 命令

普通的可执行文件

语法与参数说明

使用语法为:add_executable(name [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] [source1] [source2] ...). 例如:

cmake_minimum_required(VERSION 3.12)
add_executable(myMain 1.c 2.c)
  • name : 即可执行文件的名字。windows平台下实际产生的可执行文件名为name.exe, linux平台下产生的可执行文件名就是name.

  • WIN32关键字: 用不着,不学习,跳过。

  • MACOSX_BUNDLE: 用不着,不学习,跳过。

  • source1: 源文件列表, 多个源文件使用空格分开,说明如下:

    1. 从3.1版本开始, 可以使用“generator expressions"语法表示($<...>)依赖的源文件列表。
    2. 在该命令中可以暂时不写依赖的源文件列表, 后续由target_sources() 再添加源文件列表。
  • EXCLUDE_FROM_ALL:当指定该参数时,要构建的target 就会被排除在all target 列表之外, 这样当执行makemake all时, 该target 不会被编译。

相关变量

  • CMAKE_RUNTIME_OUTPUT_DIRECTORY: 该变量指定了生成的可执行文件的保存路径.

import可执行文件

用到的时候补。

alias可执行文件

使用语法:add_library(<name> ALIAS <target>), 为给定的target添加一个别名name. 例如:

add_library(other_name ALIAS mylib)

add_library 命令

Normal Libraries

语法与参数说明

使用语法:add_library(<name> [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] [<source>...]) , 该命令用于添加一个库文件的target, 包含静态库、动态库等。

  • name: target的名字。
  • [STATIC | SHARED | MODULE]: STATIC 表示静态库,SHARED 表示动态库,MODULE表示模块库,可以在运行时使用 dlopen 之类的命令动态加载的插件。
  • EXCLUDE_FROM_ALL: 与add_executable命令中的参数相同,当指定该参数时,要构建的target 就会被排除在all target 列表之外。
  • source: 源文件列表。

例如举例

add_library(hello_library STATIC src/Hello.cpp)

相关变量

  • ARCHIVE_OUTPUT_DIRECTORY: 修改静态库的输出路径。
  • LIBRARY_OUTPUT_DIRECTORY: 修改动态库的输出路径。
  • ARCHIVE_OUTPUT_NAME: 修改静态库的输出路径。
  • LIBRARY_OUTPUT_NAME: 修改动态库的输出路径。

target_include_directories 命令

语法与参数说明

语法:target_include_directories(<target> [SYSTEM] [AFTER|BEFORE] <INTERFACE|PUBLIC|PRIVATE> [items1...] [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])

当编译给定target时,该命令用于指令要包含的路径名。 当使用 gcc 编译器编译目标时,就会使用-I选项指定该命令添加的路径, 使用-I directory/include.

  • target: 要编译的目标文件
  • SYSTEM: 感觉用不到,跳过。
  • AFTER 或 BEFORE: 控制把需要添加的路径append 还是 prepend 到已有的路径列表中。
  • INTERFACE/PUBLIC/PRIVATE: 这几个关键字很有用。
    • 从内部实现上讲: 当使用PRIVATEPUBLIC 指定路径名时, 会把路径名添加到target的INCLUDE_DIRECTORIES属性中; 当使用PUBLICINTERFACE指定路径名时, 会把路径名添加到target的INTERFACE_INCLUDE_DIRECTORIES的属性中。
    • 从外部表现上讲:使用PRIVATE关键字时,添加的路径只会在编译当前target时使用到。 当使用INTERFACE关键字时,添加的路径只会在编译任何链接到当前target的目标文件时使用到。 使用PUBLIC关键字时,会包含以两种使用。 因此,通常情况下,如果target是可执行文件,建议使用PRIVATE, 如果target是动态或静态库, 建议使用PUBLIC,比较方便。

命令举例

target_include_directories(mylib PUBLIC include/1.h PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_include_directories(mytarget PRIVATE ${PROJECT_SOURCE_DIR}/include)

语法及参数含义

使用语法: target_link_libraries(<target> <PRIVATE|PUBLIC|INTERFACE> <item>...[<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
该命令的用于指定一个target的链接阶段的依赖库。 它还可以 propagate any include directories with PUBLIC or INTERFACE scope from the linked library target.

PRIVATE|PUBLIC|INTERFACE的作用

暂时不太明白。

使用举例

target_link_libraries( hello_binary PRIVATE hello_library)

install 命令

Installing Target

语法与参数

该命令用于安装指定的target到指定目录内。 全量的使用语法为:

install(TARGETS targets ... [EXPORT <export-name>]
        [RUNTIME_DEPENDENCIES args...|RUNTIME_DEPENDENCY_SET <set-name>]
        [[ARCHIVE|LIBRARY|RUNTIME|OBJECTS|FRAMEWORK|BUNDLE|
          PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE]
         [DESTINATION <dir>]
         [PERMISSIONS permissions...]
         [CONFIGURATIONS [Debug|Release|...]]
         [COMPONENT <component>]
         [NAMELINK_COMPONENT <component>]
         [OPTIONAL] [EXCLUDE_FROM_ALL]
         [NAMELINK_ONLY|NAMELINK_SKIP]
        ] [...]
        [INCLUDES DESTINATION [<dir> ...]]
        )
  • TARGET targets: 指明了要安装的target.
  • ARCHIVE|LIBRARY|RUNTIME等: 指明了target的类型。
  • DESTINATION dir: 指明了要安装到的路径。当使用相对路径时,是相对于变量CMAKE_INSTALL_PREFIX的, 该变量默认为/usr/local/, 也可以在CMakeLists.txt文件中指定,也可以在运行CMAKE命令时指定,例如:cmake .. -DCMAKE_INSTALL_PREFIX=/install/location

使用举例

install(TARGETS mylib LIBRARY DESTINATION lib)
install(TARGETS mybin RUNTIME DESTINATION bin)

Installing Directories

该命令用于安装指定的目录(包含目录内的文件)到指定目录。

使用语法与参数说明

install(DIRECTORY dirs...
        TYPE <type> | DESTINATION <dir>
        [FILE_PERMISSIONS permissions...]
        [DIRECTORY_PERMISSIONS permissions...]
        [USE_SOURCE_PERMISSIONS] [OPTIONAL] [MESSAGE_NEVER]
        [CONFIGURATIONS [Debug|Release|...]]
        [COMPONENT <component>] [EXCLUDE_FROM_ALL]
        [FILES_MATCHING]
        [[PATTERN <pattern> | REGEX <regex>]
         [EXCLUDE] [PERMISSIONS permissions...]] [...])
  • DIRECTORY dirs: 要安装的头文件的目录路径,默认为相对于当前的路径。 注意:如果路径以/结尾时, 会把路径里面的内容复制到给定路径,如果没有以/结尾,则也会复制该层目录的。
  • DESTINATION: 要安装到的目录路径。

使用举例

install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/ DESTINATION include)

Installing Files

使用语法与参数介绍

该命令用于安装指定的文件到指定目录:

install(<FILES|PROGRAMS> files...
        TYPE <type> | DESTINATION <dir>
        [PERMISSIONS permissions...]
        [CONFIGURATIONS [Debug|Release|...]]
        [COMPONENT <component>]
        [RENAME <name>] [OPTIONAL] [EXCLUDE_FROM_ALL])
  • FILES files: 指定要安装的文件。
  • DESTINATION dir: 指定要安装的路径。

使用举例

install(FILES cmake.config DESTINATION etc)

target_compile_definitions

使用语法与参数定义

该命令用于指定指定编译给定的target时,要定义的宏名称:

target_compile_definitions(<target>
  <INTERFACE|PUBLIC|PRIVATE> [items1...]
  [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])

  • target: 要指定编译的target。
  • INTERFACE/PUBLIC/PRIVATE: 与之前介绍的类似, 从内部实现是讲: 当使用INTERFACEPUBLIC时,会把宏定义指定赋值给INTERFACE_COMPILE_DEFINITIONS变量, 当使用PUBLICPRIVATE时,会把宏定义内容赋值给COMPILE_DEFINITIONS变量。从外部表现上讲, 当使用INTERFACEPUBLIC时,表示编译任何链接到该target(当target是一个库时)的目标文件时,都增加了该宏定义。当使用PUBLICPRIVATE时,表示编译当前target时,才使用该宏定义。
  • items1: 表示要定义的宏名字。

其它方法:1. 修改变量CMAKE_CXX_FLAGS(c++) 或者CMAKE_C_FLAGS(C代码),也可以实现该效果,但是建议使用target_compile_definitions命令。
2. 在执行cmake 命令时,也可以通过参数指定,例如:cmake .. -DCMAKE_CXX_FLAGS="-DCHINA", 它就会定义一个CHINA的宏定义。

使用举例

main函数定义如下:

#include <iostream>
int main() {
#ifdef CHINA
	std::cout << "I Love CHINA" << std::endl;
#endif
	return 0;
}
cmake_minimum_required(VERSION 3.10.2)
add_executable(myTarget main.c)
target_compile_definations(myTarget PRIVATE CHINA)

add_subdirectory 命令

该命令用于增加一个构建的子目录。 注意执行的数据流: cmake 命令会执行完子目录中的CmakeLists.txt文件之后,再执行后面的命令。

使用语法与参数说明

使用语法为: add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

  • source_dir: 要添加的子目录, 建议使用相对路径啊(相对于当前位置)。
  • binary_dir: 用于保存输出文件位置。 一般都不写。
  • EXCLUDE_FROM_ALL: 该参数很熟悉了,就是编译的时候(make 或 make all),默认不被编译。如果想要编译它,显示自己执行。

举例

cmake_minimum_required(VERSION 3.10.2)
project(example)
add_subdirectory(subdir1)
add_subdirectory(subdir2)

set_target_properties 命令

该命令用于设置给定target的一些属性值,类似于类对象的成员变量的值。 它们会影响到该target如何被构建的。

使用语法与参数说明

使用语法为:

set_target_properties(target1 target2 ...
                      PROPERTIES prop1 value1
                      prop2 value2 ...)
  • target1... : 要设置的target的名字。
  • PROPERTIES: 后面跟要设置的属性的名字以及它们的值。

使用举例

cmake_minimum_required(VERSION 3.10.2)
project(hello_main)
add_executable(hello_main main.cpp)
set_target_properties(hello_main PROPERTIES CXX_STANDARD 11)

target_compile_features 命令

该命令用于 Specifies compiler features required when compiling a given target.

使用语法与参数说明

使用语法为:target_compile_features(<target> <PRIVATE|PUBLIC|INTERFACE> <feature> [...]).

  • target: 要编译的目标文件的名称。
  • PRIVATE | PUBLIC | INTERFACE : 这个关键字已经介绍过N次了,它指明了什么场景下生效该设置。
  • feature: 就是支持的一些feature了,例如:cxx_std_98cxx_std_11cxx_rvalue_references等。

使用举例

cmake_minimum_required(VERSION 3.10.2)
project(hello_main)
add_executable(hello_main main.cpp)
target_compile_features(hello_main PRIVATE cxx_std_11)

cmake中的常用变量

CMAKE_SOURCE_DIR

表示:源码的根目录,也就是最top层 CMakeLists.txt文件存在的目录。

CMAKE_BINARY_DIR

表示:为编译的binary的根目录,也就是运行CMake时的目录,一般就是build目录。

CMAKE_CURRENT_SOURCE_DIR

表示:当前正在运行的CMakeLists.txt文件的目录

CMAKE_CURRENT_BINARY_DIR

表示:当前正处于的编译目录,例如如果正在运行src目录下的CMakeLists.txt, 该变量通常为build/src目录。

CMAKE_CXX_FLAGS 和 CMAKE_C_FLAGS

表示:当使用g++(或gcc)编译文件时,用于设置compiler flags, 也就是宏定义。

CMAKE_CXX_STANDARD

表示:该变量用于编译target时,使用的c++标准,支持98, 11, 14, 17, 20, 23. 该变量的作用原理是:用于初始化target的CXX_STANDARD属性。

C++编译器相关的宏命令

check_cxx_compiler_flag 命令

该宏定义在CheckCXXCompilerFlag.cmake模块中, 可以打开该文件看它的实现的。 它的功能是用于检测c++编译器是否支持给定的编译选项,并把检测结果写的给定变量中。

使用语法为:check_cxx_compiler_flag(<flag> <var>),

  • flag: 要检测的c++编译选项
  • var: 保存检测结果的cache 变量。

使用举例

posted @ 2021-07-04 11:07  殷大侠  阅读(9827)  评论(1编辑  收藏  举报