====================简介 与 前置说明=================

CMake是一个跨平台的建构系统的工具,可以用简单的语句来描述所有平台的安装(编译过程)。他能够输出各种各样的构建文档makefile或者project文件,描述系统建构的过程。还能测试编译器所支持的C++特性,类似UNIX下的automake。只是 CMake 的组态档取名为 CmakeLists.txt。CMake并不直接建构出最终的软件,而是产生标准的建构档(如 Unix的 Makefile或 Windows Visual C++的 projects/workspaces),然后再依一般的构建方式使用。

CMake 可以编译源代码、制作程式库、产生适配器(wrapper)、还可以用任意的顺序建构执行档。CMake支持 in-place建构(二进档和源代码在同一个目录树中)和 out-of-place建构(二进档在别的目录里),因此可以很容易从同一个源代码目录树中建构出多个二进档。CMake也支持静态与动态程式库的建构。

“CMake”这个名字是“cross platform make”的缩写。虽然名字中含有“make”,但是CMake和Unix上常见的“make”构建工具是分开的,它会根据CMakeLists.txt 文件生成适合当前平台的makefile,然后使用makefile 对源码编译;

它包含下面一些特点:

  1. 开放源代码,使用类 BSD 许可发布。
  2. 跨平台。
  3. 能够管理大型项目,KDE4 就是最好的证明。
  4. 简化编译构建过程和编译过程。Cmake 的工具链非常简单:cmake+make。
  5. 可扩展,可以为 cmake 编写特定功能的模块,扩充 cmake 功能。

更多细节可以参考 CMAKE 官网

====================基本操作=================

Cross-platform build automation system, that generates recipes for native build systems.More information: https://cmake.org/cmake/help/latest/manual/cmake.1.html.

 - Generate a build recipe in the current directory with CMakeLists.txt from a project directory:
   cmake {{path/to/project_directory}}

 - Generate a build recipe, with build type set to Release with CMake variable:
   cmake {{path/to/project_directory}} -D {{CMAKE_BUILD_TYPE=Release}}

 - Use a generated recipe in a given directory to build artifacts:
   cmake --build {{path/to/build_directory}}

 - Install the build artifacts into /usr/local/ and strip debugging symbols:
   cmake --install {{path/to/build_directory}} --strip

 - Install the build artifacts using the custom prefix for paths:
   cmake --install {{path/to/build_directory}} --strip --prefix {{path/to/directory}}

 - Run a custom build target:
   cmake --build {{path/to/build_directory}} --target {{target_name}}

cmake [选项] <源码路径> : 内部编译,直接在当前目录进行编译(cmake . / make) ,所有生成的文件 和 源码 混在一起; 而且cmake生成的makefile无法跟踪所有的中间文件,即无法使用”make distclean”命令将所有的中间文件删除。

cmake [选项] <现有构建路径> : 外部编译,可以建立一个build 文件夹进行编译,所有中间文件都会在build 文件夹(如下图所示),需要删除时候,直接清空该目录即可;

====================基础语法=================

  • 注释:在 CMakeLists.txt 文件中,使用“#”号进行单行注释, 类似shell 脚本语言都是使用“#”号进行注释。
  • 命令 (command):基本的语法格式:command(参数1 参数2 参数3 ...) 不同的命令所需的参数不同
    • 参数可以分为必要参数和可选参数(通常称为选项)很多命令都提供了这两类参数,必要参数使用<参数>表示,而可选参数使用[参数]表示;示例如下;
set(<variable> <value> [[CACHE <type> <docstring> [FORCE]] | PARENT_SCOPE])  
    • 多个参数使用空格分隔而不是逗号“,”,这是与函数不同的地方。
    • 在 CMakeLists.txt 中,命令名不区分大小写,可以使用大写字母或小写字母书写命令名;
#下面两种写法是等价的,不过因为cmake 的内置变量都是大写字符组成的,所以命令可以考虑用小写来区分;
project(HELLO) #小写 PROJECT(HELLO) #大写 
  •  变量:但是变量名是区分大小写的,并且 “” 使用会改变变量存储方式;
message("==========DEBUG MESSAGE START==========")
set(VAR0 v1 v2 v3) # 这里会把各个元素作为一个数组看待
set(var0 "v1 v2 v3") #注意这里的 "" 使用, 表示这是一整个元素
message(${VAR0}) #这里定义的是两个变量
message(${var0})
message("==========DEBUG MESSAGE END==========")

还有if/foreach/while/break/macro操作,具体细节可以在官网中查看;

====================简单demon=================

 本文学习的代码地址: https://github.com/guigym/MAKEFILE_Learn(branches:cmake_learn)

 

  • 首先我们做一个简单的demon

  基本的文件结构如下,header 文件都在include 文件夹下,source 文件都在src 文件夹下,使用外部编译方式,将所有的中间文件都放在build 文件夹下;

  然后在build 文件夹下执行, 就可以得到如下结果;

  

cmake_minimum_required(VERSION 2.8.9)
project(cmake_learn)
include_directories(include)

aux_source_directory(src SOURCES) #这与下一步的操作目的类似
#file(GLOB SOURCES "src/*.cpp")
add_executable(CMAKE_RESULT ${SOURCES})

   

  Tips:  代码tag: cmake_demon1 , 涉及到的命令参考下面基础命令部分;

  • 如果我们想要将加入自己的库文件;

   文件结构如下图,新建my_lib 文件夹保存个人lib src 文件;并在其中增加对应的cmakelists.txt 文件处理库文件编译;

   

    ./CMakeLists.txt 文件需要在最外层增加lib 相关信息;

cmake_minimum_required(VERSION 2.8.9)
project(cmake_learn)
set(OUT CMAKE_RESULT)
include_directories(include)

add_subdirectory(my_lib) #增加子文件夹,并在这里处理lib 相关的src 文件;

aux_source_directory(src SOURCES)
#file(GLOB SOURCES "src/*.cpp")


add_executable(${OUT} ${SOURCES})
target_link_libraries(${OUT} my_lib)  #增加库文件链接

  ./my_lib/CMakeLists.txt 要增加lib 处理的cmakelists.txt 文件;

aux_source_directory(. LIB_SRC)
#add_library(my_lib STATIC ${LIB_SRC})  ##static lib
add_library(my_lib SHARED ${LIB_SRC})   ##dynamic lib

install(TARGETS my_lib DESTINATION /usr/lib) #将个人lib 放入

  然后进行正常编译过程如下;

   

  如果想要将个人库文件放入默认库搜索路径下,可以通过下面命令实现;

  

   Tips:  代码tag: cmake_demon2 , 涉及到的命令参考下面基础命令部分;

  • 在实际开发中,我们会用到一些外部的函数库,而这些库文件在不同的系统下对应的位置可能是不同的,我们编译时要找到这些软件包以及链接库所在目录;

   下面例子中把module1.cpp 作为一个外部动态库链接作为简单示例;

   

cmake_minimum_required(VERSION 2.8.9)
project(cmake_learn)

set(OUT CMAKE_RESULT)

include_directories(include)
add_subdirectory(my_lib)

aux_source_directory(src SOURCES)
#file(GLOB SOURCES "src/*.cpp")

add_executable(${OUT} ${SOURCES})
target_link_libraries(${OUT} my_lib)

##寻找并链接  外部链接库 与 头文件 位置
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/module1_lib)
FIND_PACKAGE(libmodule1 REQUIRED)

MARK_AS_ADVANCED(
   LIBMODULE1_INCLUDE_DIR
   LIBMODULE1_LIBRARY
   )

IF ( LIBMODULE1_INCLUDE_DIR AND LIBMODULE1_LIBRARY )
   message(STATUS "FOND THE MODULE1 LIB")
   include_directories(${LIBMODULE1_INCLUDE_DIR})
   target_link_libraries(${OUT} ${LIBMODULE1_LIBRARY})
ENDIF ( LIBMODULE1_INCLUDE_DIR AND LIBMODULE1_LIBRARY )

在module1_lib 文件夹下,要新建findlibmodule1.cmake 文件,注意这个文件名字中findlibXXXX.cmake 中XXXXX部分就是函数库的名字,这个文件的语法与cmakelists.txt 语法一样;

具体执行结果如下:

  Tips:  代码tag: cmake_demon3, 涉及到的命令参考下面基础命令部分;

  • 如果我们想要区分不同的编译条件; cmake 中有一个变量CMAKE_BUILD_TYPE,可以的取值是Debug/Release/RelWithDebinfo/MinSizeRel。

  当这个该变量为Debug 的时候,CMake 会调用变量 CMAKE_CXX_FLAGS_DEBUG 和 CMAKE_C_FLAGS_DEBUG 中的内容作为编译选项生成Makefile;当该变量为Release 的时候,会使用CMAKE_CXX_FLAGS_RELEASE 和 CMAKE_C_FLAGS_RELEASE 的选项生成Makefile.

  在CMakeLists.txt 文件中对上面的变量进行赋值,然后在使用cmake 时候提供不同的选项:

set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")

  通过执行命令时候,给不同的参数,实现不同版本要求;

  

   代码: tag: cmake_demon4

 

  • 在一些工程中,有时候一些信息(如版本信息)为了提供更好的灵活性高,可以通过将版本信息放在CMakeList.txt 文件中控制;
    主要通过将一个配置文件内的内容 copy 到一个新的文件内;如下图就是将.in 文件添加进新的文件中;
##demon6: 配置头文件信息
configure_file (
   "${PROJECT_SOURCE_DIR}/projectConfig.h.in"
   "${PROJECT_BINARY_DIR}/projectConfig.h"
   )
include_directories(${PROJECT_BINARY_DIR})

  

  代码: tag: cmake_demon5

   这里举一个简单的例子示意下, 在CMakeLists.txt 文件的末尾增加测试用例的部分,如下;

enable_testing()

add_test(TC_Pass CMAKE_RESULT 25 0)
set_tests_properties(TC_Pass PROPERTIES
   PASS_REGULAR_EXPRESSION "25 is 5")

add_test(TC_Fail CMAKE_RESULT 9 0)
set_tests_properties(TC_Fail PROPERTIES
   PASS_REGULAR_EXPRESSION "9 is 5")

在cmake -> make 之后,可以通过 ctest / make test 方式执行测试用例;如果fail 的话会有fail 的信息打印出来;

 代码: tag: cmake_demon6

  • 其他还可以通过cpack  创建一个源代码的发行版本...

====================基础命令=================

+++++++++demon 1 涉及到命令+++++++++++++++

  • set:将一个CMAKE变量设置为给定值。
set(<variable> <value> [[CACHE <type> <docstring> [FORCE]] | PARENT_SCOPE])
  将变量<variable>的值设置为<value>。在<variable>被设置之前,<value>会被展开。
  如果有CACHE选项,那么<variable>就会添加到cache中;
  这时<type>和<docstring>是必需的。<type>被CMake GUI用来选择一个窗口,让用户设置值。<type>可以是下述值中的一个:

  FILEPATH = 文件选择对话框。
  PATH = 路径选择对话框。
  STRING = 任意的字符串。
  BOOL = 布尔值选择复选框。
  INTERNAL = 不需要GUI输入端。(适用于永久保存的变量)。

  如果<type>是内部的(INTERNAL),那么<value>总是会被写入到cache中,并替换任何已经存在于cache中的值。
  如果它不是一个cache变量,那么这个变量总是会写入到当前的makefile中。FORCE选项将覆盖cache值,从而去掉任何用户带来的改变。
  如果指定了PARENT_SCOPE选项,变量<variable>将会被设置为当前作用域之上的作用域中。
  每一个新的路径或者函数都可以创建一个新作用域。该命令将会把一个变量的值设置到父路径或者调用函数中(或者任何类似的可用的情形中。)
  如果没有指定<value>,那么这个变量就会被撤销而不是被设置。另见:unset()命令。
    set(<variable> <value1> ... <valueN>)
  在这种情形下,<variable>被设置为一个各个值之间由分号分隔的list。
  <variable>可以是环境变量,比如:
    set( ENV{PATH} /home/martink )
  在这种情形下,环境变量将会被设置。 
set
  • 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 错误, 终止所有处理过程;
CMake的命令行工具会在stdout上显示STATUS消息,在stderr上显示其他所有消息。
CMake的GUI会在它的log区域显示所有消息。
交互式的对话框(ccmake和CMakeSetup)将会在状态行上一次显示一条STATUS消息。
而其他格式的消息会出现在交互式的弹出式对话框中。
CMake警告和错误消息的文本显示使用的是一种简单的标记语言。
文本没有缩进,超过长度的行会回卷,段落之间以新行做为分隔符。
message
  • project  为整个工程设置一个工程名。
project(<projectname> [languageName1 languageName2 ... ] )
  为本工程设置一个工程名。而且,该命令还将变量<projectName>_BINARY_DIR和<projectName>_SOURCE_DIR设置为对应值。
后面的可选项还可以让你指定你的工程可以支持的语言。比如CXX(即C++),C,Fortran,等等。
在默认条件下,支持C和CXX语言。例如,如果你没有C++编译器,你可以通过列出你想要支持的语言,例如C,来明确地禁止对它的检查。
使用特殊语言"NONE",针对任何语言的检查都会被禁止
project
  • add_executable: 使用给定的源文件,为工程引入一个可执行文件
add_executable(<name> [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] source1 source2 ... sourceN)
  引入一个名为<name>的可执行目标,该目标会由调用该命令时在源文件列表中指定的源文件来构建。<name>对应于逻辑目标名字。
并且在工程范围内必须是全局唯一的。被构建的可执行目标的实际文件名将根据具体的本地平台创建出来(比如<name>.exe或者仅仅是<name>)。
    默认情况下,可执行文件将会在构建树的路径下被创建。
    对应于该命令被调用的源文件树的路径。如果要改变这个位置,查看RUNTIME_OUTPUT_DIRECTORY目标属性的相关文档。
    如果要改变最终文件名的<name>部分,查看OUTPUT_NAME目标属性的相关文档。
  如果指定了MACOSX_BUNDLE选项,对应的属性会附加在创建的目标上。查看MACOSX_BUNDLE目标属性的文档可以找到更多的细节。
  如果指定了EXCLUDE_FROM_ALL选项,对应的属性将会设置在被创建的目标上。查看EXCLUDE_FROM_ALL目标属性的文档可以找到更多的细节。
  使用下述格式,add_executable命令也可以用来创建导入的(IMPORTED)可执行目标:
  add_executable(<name> IMPORTED) 一个导入的可执行目标引用了一个位于工程之外的可执行文件。
    该格式不会生成构建这个目标的规则。该目标名字的作用域在它被创建的路径以及底层路径有效。
    它可以像在该工程内的其他任意目标一样被引用。导入可执行文件为类似于add_custom_command之类的命令引用它提供了便利。

  关于导入的可执行文件的细节可以通过设置以IMPORTED_开头的属性来指定。这类属性中最重要的是IMPORTED_LOCATION(以及它对应于具体配置的版本IMPORTED_LOCATION_<CONFIG>);该属性指定了执行文件主文件在磁盘上的位置。查看IMPORTED_*属性的文档来获得更多信息。

add_executable
add_executable
  • include_directories 为构建树添加包含路径。
  include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2 ...)
  将给定的路径添加到编译器搜索包含文件(.h文件)的路径列表中。缺省情况下,该路径会被附加在当前路径列表的后面。
这种缺省行为可以通过设置CMAKE_include_directories_BEFORE变量为ON被改变。
通过将该变量改变为BEFORE或AFTER,你可以在追加和附加在前端这两种方式中选择,而不用理会缺省设置。
如果指定了SYSTEM选项,编译器将会认为该路径是某种平台上的系统包含路径
include_directories
  • add_subdirectory 为构建添加一个子路径。
  add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
  这条命令的作用是为构建添加一个子路径。
    source_dir选项指定了CMakeLists.txt源文件和代码文件的位置。
    如果source_dir是一个相对路径,那么source_dir选项会被解释为相对于当前的目录,但是它也可以是一个绝对路径。
    binary_dir选项指定了输出文件的路径。如果binary_dir是相对路径,它将会被解释为相对于当前输出路径,但是它也可以是一个绝对路径。
    如果没有指定binary_dir,binary_dir的值将会是没有做任何相对路径展开的source_dir,这也是通常的用法。在source_dir指定路径下的CMakeLists.txt将会在当前输入文件的处理过程执行到该命令之前,立即被CMake处理。

  如果指定了EXCLUDE_FROM_ALL选项,在子路径下的目标默认不会被包含到父路径的ALL目标里,并且也会被排除在IDE工程文件之外。
    用户必须显式构建在子路径下的目标,比如一些示范性的例子工程就是这样。
    典型地,子路径应该包含它自己的project()命令调用,这样会在子路径下产生一份完整的构建系统(比如VS IDE的solution文件)。注意,目标间的依赖性要高于这种排除行为。
    如果一个被父工程构建的目标依赖于在这个子路径下的目标,被依赖的目标会被包含到父工程的构建系统中,以满足依赖性的要求。

 
add_subdirectory
  •  aux_source_directory  查找在某个路径下的所有源文件。
  aux_source_directory(<dir> <variable>)
  搜集所有在指定路径下的源文件的文件名,将输出结果列表储存在指定的<variable>变量中。
    该命令主要用在那些使用显式模板实例化的工程上。模板实例化文件可以存储在Templates子目录下,然后可以使用这条命令自动收集起来;这样可以避免手工罗列所有的实例。
  使用该命令来避免为一个库或可执行目标写源文件的清单,是非常具有吸引力的。
    但是如果该命令貌似可以发挥作用,那么CMake就不需要生成一个感知新的源文件何时被加进来的构建系统了(也就是说,新文件的加入,并不会导致CMakeLists.txt过时,从而不能引起CMake重新运行。——译注)。
    正常情况下,生成的构建系统能够感知它何时需要重新运行CMake,因为需要修改CMakeLists.txt来引入一个新的源文件。
    当源文件仅仅是加到了该路径下,但是没有修改这个CMakeLists.txt文件,
    使用者只能手动重新运行CMake来产生一个包含这个新文件的构建系统。
aux_source_directory

 

+++++++++demon 2 涉及到命令+++++++++++++++

  • add_library 使用指定的源文件向工程中添加一个库。
 add_library(<name> [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] source1 source2 ... sourceN)
  添加一个名为<name>的库文件,该库文件将会根据调用的命令里列出的源文件来创建。
    <name>对应于逻辑目标名称,而且在一个工程的全局域内必须是唯一的。
    待构建的库文件的实际文件名根据对应平台的命名约定来构造(比如lib<name>.a或者<name>.lib)。
    指定STATIC,SHARED,或者MODULE参数用来指定要创建的库的类型。
        STATIC库是目标文件的归档文件,在链接其它目标的时候使用。
        SHARED库会被动态链接,在运行时被加载。
        MODULE库是不会被链接到其它目标中的插件,但是可能会在运行时使用dlopen-系列的函数动态链接。
如果没有类型被显式指定,这个选项将会根据变量BUILD_SHARED_LIBS的当前值是否为真决定是STATIC还是SHARED。
  默认状态下,库文件将会在于源文件目录树的构建目录树的位置被创建,该命令也会在这里被调用。
    查阅ARCHIVE_OUTPUT_DIRECTORY,LIBRARY_OUTPUT_DIRECTORY,和RUNTIME_OUTPUT_DIRECTORY这三个目标属性的文档来改变这一位置。
    查阅OUTPUT_NAME目标属性的文档来改变最终文件名的<name>部分。
  如果指定了EXCLUDE_FROM_ALL属性,对应的一些属性会在目标被创建时被设置。查阅EXCLUDE_FROM_ALL的文档来获取该属性的细节。

  使用下述格式,add_library命令也可以用来创建导入的库目标:
    add_library(<name> <SHARED|STATIC|MODULE|UNKNOWN> IMPORTED)
  导入的库目标是引用了在工程外的一个库文件的目标。没有生成构建这个库的规则。
    这个目标名字的作用域在它被创建的路径及以下有效。他可以向任何在该工程内构建的目标一样被引用。
    导入库为类似于target_link_libraries命令中引用它提供了便利。
    关于导入库细节可以通过指定那些以IMPORTED_的属性设置来指定。其中最重要的属性是IMPORTED_LOCATION(以及它的具体配置版本,IMPORTED_LOCATION_<CONFIG>),
    它指定了主库文件在磁盘上的位置。查阅IMPORTED_*属性的文档获取更多的信息。            
add_library
  • install 指定在安装时要运行的规则。
该命令为一个工程生成安装规则。在某一源文件路径中,调用这条命令所指定的规则会在安装时按顺序执行。在不同路径之间的顺序未定义。
  该命令有诸多版本。其中的一些版本定义了文件以及目标的安装属性。这多个版本的公共属性都有所涉及,但是只有在指定它们的版本中,这些属性才是合法的(下面的DESTIONATION到OPTIONAL的选项列表是公共属性。——译注)。
  DESTINATION选项指定了一个文件会安装到磁盘的哪个路径下。若果给出的是全路径(以反斜杠或者驱动器名开头),它会被直接使用。如果给出的是相对路径,它会被解释为相对于CMAKE_INSTALL_PREFIX的值的相对路径。
  PERMISSIONS选项制定了安装文件需要的权限。合法的权限有:OWNER_READ,OWNER_WRITE,OWNER_EXECUTE,GROUP_READ,GROUP_WRITE,GROUP_EXECUTE,WORLD_READ,WORLD_WRITE,WORLD_EXECUTE,SETUID和SETGID。对于在某些特定的平台上没有意义的权限,在这些平台上会忽略这些选项
  CONFIGURATIONS选项指定了该安装规则将会加诸之上的一系列的构建配置(Debug,Release,等等)。
  COMPONENT选项指定了该安装规则相关的一个安装部件的名字,比如“runtime”或“development”。对于那些指定安装部件的安装过程来说,在安装时只有与给定的部件名相关的安装规则会被执行。对于完整安装,所有部件都会被安装。
  RENAME选项为一个可能不同于原始文件的已经安装的文件指定另一个名字。重命名只有在该命令正在安装一个单一文件时才被允许(猜测是为了防止文件名冲突时覆盖掉旧文件。——译注)。
  OPTIONAL选项表示要安装的文件不存在不会导致错误。

  TARGETS版本的install命令
  install(TARGETS targets... [EXPORT <export-name>]
          [[ARCHIVE|LIBRARY|RUNTIME|FRAMEWORK|BUNDLE|
            PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE]
           [DESTINATION <dir>]
           [PERMISSIONS permissions...]
           [CONFIGURATIONS [Debug|Release|...]]
           [COMPONENT <component>]
           [OPTIONAL] [NAMELINK_ONLY|NAMELINK_SKIP]
          ] [...])
  TARGETS格式的install命令规定了安装工程中的目标(targets)的规则。有5中可以被安装的目标文件:ARCHIVE,LIBRARY,RUNTIME,FRAMEWORK,和BUNDLE。除了被标记为MACOSX_BUNDLE属性的可执行文件被当做OS X上的BUNDLE目标外,其他的可执行文件都被当做RUNTIME目标。
静态链接的库文件总是被当做ARCHIVE目标。
模块库总是被当做LIBRARY目标。
对于动态库不是DLL格式的平台来说,动态库会被当做LIBRARY目标来对待,被标记为FRAMEWORK的动态库是例外,它们被当做OS X上的FRAMEWORK目标。
对于DLL平台而言,动态库的DLL部分被当做一个RUNTIME目标而对应的导出库被当做是一个ARCHIVE目标。所有基于Windows的系统,包括Cygwin,都是DLL平台。ARCHIVE,LIBRARY,RUNTIME和FRAMEWORK参数改变了后续属性会加诸之上的目标的类型。如果只给出了一种类型,那么只有那种类型的目标会被安装(这样通常只会安装一个DLL或者一个导出库。)
  PRIVATE_HEADER,PUBLIC_HEADER,和RESOURCE选项的功能是,在非苹果平台上,将后续的属性应用在待安装的一个FRAMEWORK共享库目标的相关文件上。
这些选项定义的规则在苹果系统上会被忽略掉,因为相关的文件将会被安装到framework文件夹内的合适位置。
参见PRIVATE_HEADER,PUBLIC_HEADER和RESOURCE目标属性中更为详细的解释。
  可以指定NAMELINK_ONLY或者NAMELINK_SKIP选项作为LIBRARY选项。在一些平台上,版本化的共享库有一个符号链接,比如lib<name>.so -> lib<name>.so.1,其中“lib<name>.so.1”是so库文件名(soname)而“lib<name>.so”是一个符号链接,当指定“-l<name>”选项时,链接器将会查找这个符号链接。如果一个库目标已经被安装,NAMELINK_ONLY选项表示仅仅安装符号链接;而NAME_SKIP选项则表示仅仅安装库文件而不是符号链接。当两种选项都没有给出时,动态库的两个部分都会被安装。在那些版本化的共享库没有符号链接或者库没有被版本化的平台,选项NAMELINK_SKIP安装这个库,而NAMELINK_ONLY选项什么都不会安装。参见VERSION和SOVERSION目标属性,获取关于创建版本化共享库的更多细节。

  在该命令的TARGETS版本的一次调用中,可以一次性指定一个或多个属性组。一个目标也可以被多次安装到不同的位置。假设有三个目标myExe,mySharedLib和myStaticLib,下面的代码
    install(TARGETS myExe mySharedLib myStaticLib
            RUNTIME DESTINATION bin
            LIBRARY DESTINATION lib
            ARCHIVE DESTINATION lib/static)
    install(TARGETS mySharedLib DESTINATION /some/full/path)
将会把myExe安装到<prefix>/bin目录下,把myStaticLib安装到<prefix>/lib/static目录下。在非-DLL平台上,mySharedLib将会被安装到<prefix>/lib和/some/full/path下。在DLL平台上,mySharedLib DLL将会被安装到<prefix>/bin和/some/full/path路径下,它的导出库会被安装到<prefix>/lib/static和/some/full/path路径下。
  EXPORT选项将已经安装的目标文件和一个名为<export-name>的导出文件关联起来。它必须出现在所有RUNTIME,LIBRARY或者ARCHIVE选项之前。为了实际安装导出文件本身(export file),调用install(EXPORT)。参见下述install命令EXPORT版本的文档获取更多的细节。
  将EXCLUDE_FROM_ALL设置为true时,安装一个目标会造成未定义的行为。
  FILES版本的install命令
  install(FILES files... DESTINATION <dir>
          [PERMISSIONS permissions...]
          [CONFIGURATIONS [Debug|Release|...]]
          [COMPONENT <component>]
          [RENAME <name>] [OPTIONAL])
  FILES版本的install命令指定了为一个工程安装文件的规则。在命令中,以相对路径方式给出的文件名是相对于当前源代码路径而言的。以这个版本安装的文件,如果没有指定PERMISSIONS选项,默认会具有OWNER_WRITE,OWNER_READ,GROUP_READ,和WORLD_READ的权限。

  PROGRAMS版本的install命令
  install(PROGRAMS files... DESTINATION <dir>
          [PERMISSIONS permissions...]
          [CONFIGURATIONS [Debug|Release|...]]
          [COMPONENT <component>]
          [RENAME <name>] [OPTIONAL])
  PROGRAMS版本与FILES版本一样,只在默认权限上有所不同:它还包括了OWNER_EXECUTE,GROUP_EXECUTE和WORLD_EXECUTE选项。INSTALL的这个版本用来安装不是目标的程序,比如shell脚本。使用TARGETS格式安装该工程内部构建的目标。

  DIRECTORY版本的install命令
  install(DIRECTORY dirs... DESTINATION <dir>
          [FILE_PERMISSIONS permissions...]
          [DIRECTORY_PERMISSIONS permissions...]
          [USE_SOURCE_PERMISSIONS] [OPTIONAL]
          [CONFIGURATIONS [Debug|Release|...]]
          [COMPONENT <component>] [FILES_MATCHING]
          [[PATTERN <pattern> | REGEX <regex>]
           [EXCLUDE] [PERMISSIONS permissions...]] [...])
  INSTALL的DIRECTORY版本将一个或者多个路径下的内容安装到指定的目标地址下。目录结构会原封不动地(verbatim)拷贝到目标地址。每个路径名的最后一部分会追加到目标路径下,但是结尾反斜杠(trailing slash)可以用来避免这一点,因为这样最后一部分就是空的。给定的相对路径名被解释成相对于当前源路径的路径。如果没有指定输入目录名字,目标目录会被创建,但是不会安装任何东西。FILE_PERMISSIONS和DIRECTORY_PERMISSIONS选项指定了赋予目标路径和目标文件的权限。如果指定了USE_SOURCE_PERMISSIONS选项,但没有指定FILE_PERMISSIONS选项,文件权限将沿袭源目录结构的权限,而且这个路径会被赋予PAROGRAMS版本中指定的默认权限。

  通过使用PATTERN或REGEX选项可以对路径安装做出细粒度的控制。这些用于匹配的选项指定了一个查询模式或正则表达式来匹配输入路径内的路径或文件。它们可以用来将特定的选项(见下文)加诸于遇到的文件和路径的一个子集上。每个输入文件或路径的完整路径(反斜杠/开头的路径)将用来匹配该表达式。PATTERN仅仅用来匹配完全文件名:匹配该模式的全路径的那部分必须出现在文件名的结尾,并且必须以一个反斜杠开始。

  正则表达式会用来匹配一个完全路径的任何部分,但是它也可以使用'/'和'$'模仿PATTERN的行为。默认情况下,所有文件和路径不管是否匹配都会被安装。可以在第一个匹配选项之前指定FILE_MATCHING选项,这样就能禁止安装那些不与任何表达式匹配的文件。比如,代码

  install(DIRECTORY src/ DESTINATION include/myproj
          FILES_MATCHING PATTERN "*.h")
将会精确匹配并安装从源码树上得到的头文件。

  有些选项后面可以跟在PATTERN或者REGEX表达式的后面,这样这些选项只能加诸于匹配PATTERN/REGEX的文件或路径上。EXCLUDE选项将会指示安装过程跳过那些匹配的文件或者路径。PERMISSIONS选项可以覆盖那些匹配PATTERN/REGEX的文件的权限设定。例如,代码

  install(DIRECTORY icons scripts/ DESTINATION share/myproj
          PATTERN "CVS" EXCLUDE
          PATTERN "scripts/*"
          PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ
                      GROUP_EXECUTE GROUP_READ)
会将icons路径安装到share/myproject/icons下,同时把scripts目录安装到share/myproj路径下。icons将具备默认的文件权限,scripts将会被给与指定的权限,但是所有CVS路径排除在外。

  SCRIPT和CODE版本的install命令
  install([[SCRIPT <file>] [CODE <code>]] [...])
  SCRIPT格式将会在安装期调用给定的脚本文件。如果脚本文件名是一个相对路径,它会被解释为相对于当前的源路径。CODE格式将会在安装期调用给定的CMake代码。code被指定为一个双引号括起来的单独的参数。例如,代码
  install(CODE "MESSAGE(\"Sample install message.\")")
会在安装时打印一条消息。

  EXPORT版本的install命令
  install(EXPORT <export-name> DESTINATION <dir>
          [NAMESPACE <namespace>] [FILE <name>.cmake]
          [PERMISSIONS permissions...]
          [CONFIGURATIONS [Debug|Release|...]]
          [COMPONENT <component>])
  EXPORT格式的install命令生成并安装一个包含将安装过程的安装树导入到另一个工程中的CMake文件。Target格式的安装过程与上文提及的使用EXPORT选项的install(TARGET ...)格式的命令中的EXPORT <export-name>选项是相关的。NAMESPACE选项会在它们被写入到导入文件时加到目标名字之前。缺省时,生成的文件就是<export-name>.cmake;但是FILE选项可以用来指定不同于次的文件名。FILE选项后面的参数必须是一“.cmake”为扩展名的文件。如果指定了CONFIGURATIONS选项,那么只有那些具名的配置中的一个被安装时,这个文件才会被安装。而且,生成的导入文件只能涉及到匹配的目标配置版本。如果指定了一个COMPONENT选项,并且<component>与那个<export-name>相关的目标指定的部件不匹配,那么行为是未定义的。如果一个库目标被包含在export之中,但是与之关联的库却没有背包含,那么结果是未指定的。

  EXPORT格式可以协助外部工程使用当前工程构建出来并安装的目标。例如,代码
  install(TARGETS myexe EXPORT myproj DESTINATION bin)
  install(EXPORT myproj NAMESPACE mp_ DESTINATION lib/myproj)
将会把可执行文件myexe安装到<prefix>/bin下,并且将导入它的代码写到文件"<prefix>/lib/myproj/myproj.cmake"中。一个外部工程可以用include命令加载这个文件,并且可以在安装树上使用导入的目标名mp_myexe(前缀_目标名——译注)引用myexe可执行文件,如同这个目标是它自身的构建树的内置目标一样。
  注意:这个命令会取代INSTALL_TARGETS命令以及PRE_INSTALL_SCRIPT和POST_INSTALL_SCRIPT两个目标属性。它也可以取代FILES格式的INSTALL_FILES命令和INSTALL_PROGRAMS命令。由INSTALL命令生成的安装规则相对于那些由INSTALL_TARGETS,INSTALL_FILES和INSTALL_PROGRAMS命令生成的安装规则处理顺序是未定义的。
install

 +++++++++demon 3涉及到命令+++++++++++++++

  • find_(file/library/path/program/package) 在指定的选项中,将包含指定文件的路径保存在VAR 中
FIND_FILE(<VAR> name path1 path2 …)    #VAR变量代表找到的文件全路径,包含文件名

FIND_LIBRARY(<VAR> name path1 path2 …)   #VAR变量代表找到的库全路径,包含库文件名
EXAM:
    FIND_LIBRARY(libX X11 /usr/lib)
    IF (NOT libx)
    MESSAGE(FATAL_ERROR "libX not found")
    ENDIF(NOT libX)

FIND_PATH(<VAR> name path1 path2 …)    #VAR变量代表包含这个文件的路径

FIND_PROGRAM(<VAR> name path1 path2 …)    #VAR变量代表包含这个程序的全路径

FIND_PACKAGE(<name> [major.minor] [QUIET] [NO_MODULE] [[REQUIRED | COMPONENTS] [componets …]]) #用来调用预定义在CMAKE_MODULE_PATH下的Find<name>.cmake模块,你也可以自己定义Find<name>模块,通过SET(CMAKE_MODULE_PATH dir)将其放入工程的某个目录供工程使用
find_xxx

+++++++++demon 5涉及到命令+++++++++++++++

  • configure_file : 配置文件,复制(并修改)文件到其他地方;
configure_file(<input> <output>
               [COPYONLY] [ESCAPE_QUOTES] [@ONLY]
               [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])
Copies a file <input> to file <output> and substitutes variable values referenced in the file content. If <input> is a relative path it is evaluated with respect to the current source directory. The <input> must be a file, not a directory. If <output> is a relative path it is evaluated with respect to the current binary directory. If <output> names an existing directory the input file is placed in that directory with its original name.

If the <input> file is modified the build system will re-run CMake to re-configure the file and generate the build system again.

This command replaces any variables in the input file referenced as ${VAR} or @VAR@ with their values as determined by CMake. If a variable is not defined, it will be replaced with nothing. If COPYONLY is specified, then no variable expansion will take place. If ESCAPE_QUOTES is specified then any substituted quotes will be C-style escaped. The file will be configured with the current values of CMake variables. If @ONLY is specified, only variables of the form @VAR@ will be replaced and ${VAR} will be ignored. This is useful for configuring scripts that use ${VAR}.

Input file lines of the form “#cmakedefine VAR …” will be replaced with either “#define VAR …” or /* #undef VAR */ depending on whether VAR is set in CMake to any value not considered a false constant by the if() command. (Content of “…”, if any, is processed as above.) Input file lines of the form “#cmakedefine01 VAR” will be replaced with either “#define VAR 1” or “#define VAR 0” similarly.

With NEWLINE_STYLE the line ending could be adjusted:

'UNIX' or 'LF' for \n, 'DOS', 'WIN32' or 'CRLF' for \r\n.
COPYONLY must not be used with NEWLINE_STYLE.
configure_file

 +++++++++demon 6涉及到命令+++++++++++++++

  •  add_test: 在cmake 中增加测试用例
Add a test to the project to be run by ctest(1).

add_test(NAME <name> COMMAND <command> [<arg>...]
         [CONFIGURATIONS <config>...]
         [WORKING_DIRECTORY <dir>])
Add a test called <name>. The test name may not contain spaces, quotes, or other characters special in CMake syntax. The options are:

COMMAND
Specify the test command-line. If <command> specifies an executable target (created by add_executable()) it will automatically be replaced by the location of the executable created at build time.

CONFIGURATIONS
Restrict execution of the test only to the named configurations.

WORKING_DIRECTORY
Set the WORKING_DIRECTORY test property to specify the working directory in which to execute the test. If not specified the test will be run with the current working directory set to the build directory corresponding to the current source directory.

The COMMAND and WORKING_DIRECTORY options may use “generator expressions” with the syntax $<...>. See the cmake-generator-expressions(7) manual for available expressions.

Example usage:

add_test(NAME mytest
         COMMAND testDriver --config $<CONFIGURATION>
                            --exe $<TARGET_FILE:myexe>)
This creates a test mytest whose command runs a testDriver tool passing the configuration name and the full path to the executable file produced by target myexe.

Note CMake will generate tests only if the enable_testing() command has been invoked. The CTest module invokes the command automatically when the BUILD_TESTING option is ON.
add_test(<name> <command> [<arg>...])
Add a test called <name> with the given command-line. Unlike the above NAME signature no transformation is performed on the command-line to support target names or generator expressions.
add_test
  • enable_testing() : 打开测试功能
Enables testing for this directory and below. See also the add_test command. Note that ctest expects to find a test file in the build directory root. Therefore, this command should be in the source directory root.
enable_testing
  • set_test_properties : 测试用例判断pass/fail 条件;
set_tests_properties(test1 [test2...] PROPERTIES prop1 value1 prop2 value2)
Set a property for the tests. If the test is not found, CMake will report an error. Generator expressions will be expanded the same as supported by the test’s add_test call. The properties include:

WILL_FAIL: If set to true, this will invert the pass/fail flag of the test.

PASS_REGULAR_EXPRESSION: If set, the test output will be checked against the specified regular expressions and at least one of the regular expressions has to match, otherwise the test will fail.

Example: PASS_REGULAR_EXPRESSION "TestPassed;All ok"
FAIL_REGULAR_EXPRESSION: If set, if the output will match to one of specified regular expressions, the test will fail.

Example: FAIL_REGULAR_EXPRESSION "[^a-z]Error;ERROR;Failed"
Both PASS_REGULAR_EXPRESSION and FAIL_REGULAR_EXPRESSION expect a list of regular expressions.

TIMEOUT: Setting this will limit the test runtime to the number of seconds specified.
set_tests_properties

 

CMake 中有很多的变量定义,下面列出一些,更多的可以去官网查看;

CMAKE_SIZEOF_VOID_P 表示 void* 的大小(例如为 4 或者 8),可以使用其来判断当前构建为 32位还是 64位
CMAKE_CURRENT_LIST_DIR表示正在处理的 CMakeLists.txt文件的所在的目录的绝对路径(2.8.3以及以后版本才支持)
CMAKE_ARCHIVE_OUTPUT_DIRECTORY用于设置 ARCHIVE目标的输出路径
CMAKE_LIBRARY_OUTPUT_DIRECTORY用于设置 LIBRARY目标的输出路径
CMAKE_RUNTIME_OUTPUT_DIRECTORY用于设置 RUNTIME目标的输出路径
EXECUTABLE_OUTPUT_PATH用于输出可执行文件输出路径
CMAKE_C_COMPILER 指定C语言项目的编译器
CMAKE_CXX_COMPILER指定C++语言项目的编译器。
EXECUTABLE_OUTPUT_PATH 变量控制可执行文件的输出路径
LIBRARY_OUTPUT_PATH 变量控制库文件的输出路径。

 

参考文章: 

  cmake快速入门

  cmake 从放弃到入门 - 醍醐灌顶

  CMake 用法导览 (上面命令细节大部分从这里摘录);

posted on 2022-08-17 21:46  学海一扁舟  阅读(413)  评论(0编辑  收藏  举报