CMake学习

目录

一、介绍

二、构建系统

三、构建步骤

四、CMake源文件

1、目录(CMakeLists.txt)

2、脚本(script.cmake)

3、模块(module.cmake)

五、变量

1、变量范围

2、变量引用

3、自定义变量

4、内置变量

5、环境变量

六、平台相关变量

七、条件表达式

八、循环

九、宏/函数

十、生成二进制目标

1、生成可执行文件

2、生成链接库

3、源文件指定方式 

十一、指定头文件目录

十二、指定链接库 

十三、定义预处理宏

十四、常用命令

1、字符串string

2、列表list

3、信息打印message

4、文件file

5、源文件分组source_group


一、介绍

CMake是一个跨平台的源码构建工具,它使用统一的语法编写CMakeLists.txt文件,可以生成不同平台下的构建系统,然后再使用原生的开发工具(如VS/make等)进行编译安装。CMake可以看作是一门脚本语言,很多大型开源项目都在使用它,广泛用于C/C++项目中。

二、构建系统

构建系统(Buildsystem)就是指原始的项目工程文件,比如VS的.sln .vcxproj,各种Makefile等等

#查看CMake可以生成哪些构建系统
cmake -G

三、构建步骤

  • 通过CMakeLists.txt文件生成构建系统,这里会检查环境配置,比如编译器等,如果出错则直接退出。

        可以使用cmake命令或cmake-gui完成这一步,比如cmake命令: cmake  [选项]  <CMakeLists.txt路径>

  • 生成.vcxproj或Makefile之后就可以使用原生工具VS/nmake/make编译安装

常用选项:

-G:表示生成哪种构建系统

#一般性的构建步骤:
mkdir build    #在项目目录下创建build目录
cd build
cmake -G "Visual Studio 14 2015" ..    #生成VS2015工程文件,..表示CMakeLists.txt在上一级目录中
cmake -G "NMake Makefiles" ..          #生成Windows平台的Makefile
cmake -G "Unix Makefiles"  ..          #生成Linux/Unix平台下标准的Makefile
#根据不同平台选择相应的构建档,在CMake中称之为generator

#接下来使用VS/nmake/make等工具编译安装

-D:定义预处理变量,比如用CMAKE_BUILD_TYPE指定编译类型

cmake -DCMAKE_BUILD_TYPE=Debug|Release .. #生成Debug版或者Release版

-P: 执行CMake语言编写的脚本文件,通常以.cmake为后缀

cmake [{-D <var>=<value>}...] -P <script.cmake>

四、CMake源文件

1、目录(CMakeLists.txt)

当CMake处理工程源码树的时候,入口点是顶层目录的CMakeLists.txt文件,文件中还可能使用add_subdirectory()命令添加子目录,每个子目录也必须有一个CMakeLists.txt

2、脚本(script.cmake)

通常<script>.cmake会使用macro()/function()命令定义一些公共的复用的函数(类似于c语言宏和函数的功能),脚本主要有下面两种执行方式:

  1. 通过cmake -P <script>.cmake单独解释执行,而不会生成构建系统,这种方式可以用来测试脚本文件中是否有语法错误
  2. 在CMakeLists.txt中使用include()命令加载并执行脚本文件中的代码,这样CMakeLists.txt后续的代码就可以直接调用这些宏和函数,通过CMAKE_MODULE_PATH内置变量指定脚本文件的查找路径,如果没找到则会搜索CMake安装目录

3、模块(module.cmake)

find_package命令用来查找项目中的依赖库,有可能是系统库(如OpenGL),也可能是第三方库(如OpenCV)

命令格式:
find_package(<PackageName> [version] [module] [REQUIRED] [[COMPONENTS] [components...]])

该命令首先会在CMAKE_MODULE_PATH指定的路径之中查找,然后在CMake的安装路径中查找并执行Find<PackageName>.cmake文件,在该文件中会搜索PackageName的相关信息,比如.h、.lib、.so的位置等

如果找到PackageName的这些信息,Find<PackageName>.cmake文件就会设置PackageName_FOUND、PackageName_INCLUDE_DIR、PackageName_LIBRARIES等变量,那么在CMakeLists.txt中就可以使用这些变量,比如用target_include_directories、target_link_libraries命令设置依赖库的头文件、库文件。

五、变量

CMake语言的变量都是字符串类型

1、变量范围

  • 函数范围

function()/endfunction()命令会创建一个新的变量范围,在函数中set/unset设定的变量都属于该范围,return之后这些变量就不可见了

  • 目录范围

function()/endfunction()命令之外set/unset的变量属于目录范围,在当前目录及其子目录的CMakeLists.txt都可见

注:add_subdirectory()添加的子目录的CMakeLists.txt会继承父目录CMakeLists.txt的变量

  • 持久缓存

CMake可以持久保存一些变量的值,这些变量每次构建都存在,使用set/unset的CACHE选项设置

2、变量引用

形式:${<variable>}

引用顺序:函数—>目录—>CACHE,如果没找到设置为空字符串

3、自定义变量

通过set/unset命令在函数范围目录范围定义/取消

4、内置变量

以CMAKE_开头的都属于内置变量,但也不限于CMAKE_开头,这里介绍最常用的几个

变量名含义
PROJECT_NAME由project指令设置的工程名
${ProName}_SOURCE_DIR工程(顶层)CMakeLists.txt所在的目录
PROJECT_SOURCE_DIR工程(顶层)CMakeLists.txt所在的目录,等同于${ProName}_SOURCE_DIR,推荐使用这个
${ProName}_BINARY_DIR 工程(顶层)CMakeLists.txt的构建目录,比如上面的build
PROJECT_BINARY_DIR工程(顶层)CMakeLists.txt的构建目录,等同于${ProName}_BINARY_DIR,推荐使用这个
CMAKE_CURRENT_SOURCE_DIR当前CMakeLists.txt所在的目录
CMAKE_CURRENT_BINARY_DIR当前CMakeLists.txt的构建目录
CMAKE_RUNTIME_OUTPUT_DIRECTORY指定exe的生成目录
CMAKE_LIBRARY_OUTPUT_DIRECTORY 指定dll/lib的生成目录

注意:PROJECT_SOURCE_DIR是固定不变的,就是指最顶层的CMakeLists.txt,包含project指令的那个

          CMAKE_CURRENT_SOURCE_DIR是变化的,指当前CMakeLists.txt,通过add_subdirectory()添加的每个子目录都有一个CMakeLists.txt

5、环境变量

环境变量的范围是全局的,每个CMakeLists.txt都可以引用,它不会被缓存。CMake进程启动时进行初始化,可以通过set/unset改变

引用:$ENV{variable}

修改:set(ENV{<variable>} [<value>])

           unset(ENV{<variable>})

六、平台相关变量

WIN32        如果是windows平台则为True

UNIX          如果是unix-like平台则为True

APPLE        如果是apple平台则为True

七、条件表达式

格式:
if(<condition>)
  <commands>
elseif(<condition>)
  <commands>
else()
  <commands>
endif()

条件判断关键字:

关键字意义
AND
OR
NOT
EXISTS文件或目录是否存在
COMMAND是否为命令
DEFINED变量是否定义
TARGET是否为目标,通过add_executable或add_library添加
MATCHES匹配正则表达式
IS_DIRECTORY是否为目录
IS_NEWER_THAN文件1是否比文件2新
EQUAL,LESS,LESS_EQUAL,GREATER,GREATER_EQUAL数字比较

STREQUAL,STRLESS,STRLESS_EQUAL

STRGREATER,STRGREATER_EQUAL

字符串比较

VERSION_EQUAL,VERSION_LESS,VERSION_LESS_EQUAL

VERSION_GREATER,VERSION_GREATER_EQUAL

版本比较

八、循环

  1. while(<condition>) #condition跟if的语法一样
      <commands>
    endwhile()
  2. foreach(<loop_var> <items>) #items是用分号或空格分隔的列表,loop_var每次迭代一个列表项
      <commands>
    endforeach()
  3. foreach(<loop_var> RANGE <start> <stop> [<step>]) #数字范围循环,start和step可以省略
  4. foreach(<loop_var> IN [LISTS [<lists>]] [ITEMS [<items>]]) #列表(项)循环

        注:break()/continue()相当于C语言的break和continue关键字

九、宏/函数

  1. macro(<name> [<arg1> ...])
      <commands>
    endmacro()
  2. function(<name> [<arg1> ...])
      <commands>
    endfunction()

        注:宏和函数一旦定义之后,就可以想普通命令一样去调用

十、生成二进制目标

1、生成可执行文件

命令格式:
add_executable(<name> [WIN32] [source1] [source2 ...])

选项:

WIN32:表示生成win32应用程序,即程序入口点为WinMain

source1 source2 ...指定要编译的源文件(.h,.c,.cpp,.ui,资源文件等)

2、生成链接库

命令格式:
add_library(<name> [STATIC | SHARED] [<source>...])

选项:

 STATIC:生成静态库

SHARED:生成动态库

3、源文件指定方式 

  • 通过set命令把要编译的文件放在变量中
  • 通过file(GLOB ...)命令生成源文件列表
  • add_executable/add_library命令中不指定源文件,通过target_source命令指定
命令格式:
file(GLOB <variable>
     [LIST_DIRECTORIES true|false] [RELATIVE <path>] [<globbing-expr>...])
file(GLOB_RECURSE <variable> 
     [LIST_DIRECTORIES true|false] [RELATIVE <path>] [<globbing-expr>...])

作用: 

根据globbing-expr表达式匹配目录下的文件,globbing-expr类似于正则表达式,常用的通配符有:

*  任意个任意字符

? 一个任意字符

[] 必有一个中括号的字符

示例:*.cpp,*.vt?,f[3-5].txt

选项: 

LIST_DIRECTORIES :是否列出目录,默认为true

RELATIVE:相对路径

GLOB_RECURSE模式会递归查找子目录

#头文件
set(HDR_LIST common.h)
#源文件
set(SRC_LIST main.cpp utils.cpp log.cpp)
#UI文件
set(UI_LIST frame.ui)
#资源文件
set(RC_LIST dolphin.rc)

add_executable(test ${HDR_LIST} ${SRC_LIST} ${UI_LIST} ${RC_LIST})

#通过下面两步设置与上面等价
#add_executable(test)
#target_source(test PRIVATE ${HDR_LIST} ${SRC_LIST} ${UI_LIST} ${RC_LIST})

#================================================================
file (GLOB SRCS LIST_DIRECTORIES false
            "${CMAKE_CURRENT_SOURCE_DIR}/*.h"
            "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp"
            "${CMAKE_CURRENT_SOURCE_DIR}/*.ui"
            "${CMAKE_CURRENT_SOURCE_DIR}/*.rc"
)
add_executable(test ${SRCS})

十一、指定头文件目录

target_include_directories(<target> [SYSTEM] <PUBLIC|PRIVATE> [items1...])

选项: PUBLIC:为当前target及其依赖目标(通过target_link_libraries命令指定)指定包含目录

            PRIVATE:只为当前target指定包含目录

注:老式的指定包含目录的命令为:include_directories([SYSTEM] dir1 [dir2 ...]),它会为当前CMakeLists.txt中的所有target都指定这个包含目录

十二、指定链接库 

target_link_libraries(<target> <PRIVATE|PUBLIC> <item>...)

十三、定义预处理宏

ADD_DEFINITIONS、ADD_COMPILE_DEFINITIONS预处理宏

十四、常用命令

1、字符串string

字符串查找:
string(FIND <string> <substring> <output_variable> [REVERSE])

   说明: 

        查找子字符串首次出现的位置,并把所有保存在output_variable中,若没找到则为-1

        REVERSE表示反向查找,即最后一次出现的位置

字符串替换:
string(REPLACE <match_str> <replace_str> <result_str> <src_str1> [<src_str2>...])

  说明: 

        在源字符串src_str中查找匹配的子字符串match_str,并替换为replace_str,替换后的字符串保存在result_str中,源字符串src_str保持不变

字符串拼接:
string(APPEND <string_variable> [<input>...])
string(PREPEND <string_variable> [<input>...])
string(CONCAT <output_variable> [<input>...])
string(JOIN <glue> <output_variable> [<input>...])

  说明:

APPEND在变量最后添加

PREPEND在变量前面添加

CONCAT把参数字符串直接连接在一起

JOIN把参数字符串用glue连接在一起

string(APPEND str1 "hello " "cmake")     #str1: hello cmake
string(PREPEND str2 "Lists.txt" "CMake") #str2: CMakeLists.txt
string(CONCAT str3 "Build" "System")     #str3: BuildSystem
string(JOIN "+" str4 "1" "2" "3" "4")    #str4: 1+2+3+4
大小写转换:
string(TOLOWER <string> <output_variable>)
string(TOUPPER <string> <output_variable>)
字符串长度:
string(LENGTH <string> <output_variable>)
子字符串提取:
string(SUBSTRING <string> <begin> <length> <output_variable>)
删除首尾空白:
string(STRIP <string> <output_variable>)
字符串比较:
string(COMPARE LESS <string1> <string2> <output_variable>)
string(COMPARE GREATER <string1> <string2> <output_variable>)
string(COMPARE EQUAL <string1> <string2> <output_variable>)
string(COMPARE NOTEQUAL <string1> <string2> <output_variable>)
string(COMPARE LESS_EQUAL <string1> <string2> <output_variable>)
string(COMPARE GREATER_EQUAL <string1> <string2> <output_variable>)

  说明:

        比较结果保存在变量output_variable,其值为true或false

2、列表list

3、信息打印message

message([<mode>] "message text" ...)

常用的mode选项有:

  • FATAL_ERROR:致命错误,终止构建
  • SEND_ERROR:一般错误,继续构建
  • WARNING:警告信息
  • NOTICE:需要注意的信息
  • STATUS:一般输出信息
  • DEBUG:调试信息

4、文件file

5、源文件分组source_group

source_group(<name> [FILES <src>...] [REGULAR_EXPRESSION <regex>])

把源文件、头文件、ui文件等进行分组归类,在IDE中放在一起显示

FILES:要添加的文件

REGULAR_EXPRESSION:正则表达式匹配

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值