CMake简介及使用实例
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”构建工具是分开的,而且更为高阶。
在 linux平台下使用CMake生成 Makefile并编译的流程如下:
(1)编写CmakeLists.txt。
(2)执行命令“cmake PATH”或者“ccmake PATH”生成 Makefile( PATH是 CMakeLists.txt所在的目录 )。
(3)使用make命令进行编译。
2.CMake相关语法规则
CMake 可以通过 CMakeLists.txt文件来产生特定平台的标准的构建文件,编写的CMakeLists.txt需要符合一定的语法规则。一个 CMakeLists.txt文件主要由 CMake命令组成。
(1)在 CMake中,注释由 #字符开始到此行的结束。
(2)命令名不区分大小写,参数需区分大小写。
(3)命令由命令名、参数列表组成。参数间使用空格进行分隔。使用一对双引号包裹的被认为是一个参数。我们的命令可以是一个内置命令(如project),也可以是一个用户定义的宏(macro)或者函数(function)。
2.1数据类型
CMake 的基本数据类型是字符串,一组字符串在一起被叫做一个list(列表),例如:
# 通过 set命令构建一个list VARset(VAR a b c)
使用语法 ${VariableName}来访问名字为 VariableName的变量的值(变量名区分大小写)。需要注意的是,即使在字符串中也可以使用 ${VariableName}来访问变量的值:
set(VAR ab c)# 输出 VAR = a;b;cmessage("VAR= ${VAR}")
使用语法 $ENV{VariableName}来访问环境变量的值(ENV{VariableName}则表示环境变量本身):
# 输出环境变量 PATH的值message($ENV{PATH})
2.2条件控制
条件控制命令为 if命令:
if(expression)# ...elseif(expression2)# ...else()# ...endif()
对于 if(string)来说:
如果 string为(不区分大小写)1、ON、YES、TRUE、Y、非 0的数则表示真
如果 string为(不区分大小写)0、OFF、NO、FALSE、N、IGNORE、空字符串、以 -NOTFOUND结尾的字符串则表示假
如果 string不符合上面两种情况,则 string被认为是一个变量的名字。变量的值为第二条所述的各值则表示假,否则表示真。
来看一个例子:
# 此策略(Policy)在CMake 2.8.0才被引入
# 因此这里需要指定最低CMake版本为 2.8
cmake_minimum_required(VERSION2.8)
set(YES0)
# 输出 True
if(YES)message(True)
else()message(False)
endif()
# 输出 False
if(${YES})message(True)
else()message(False)
endif()
表达式中可以包含操作符,操作符包括:
(1)一元操作符,例如:EXISTS、COMMAND、DEFINED等
(2)二元操作符,例如:EQUAL、LESS、GREATER、STRLESS、STRGREATER等
(3)NOT(非操作符)、AND(与操作符)、OR(或操作符)
操作符优先级:一元操作符 >二元操作符 > NOT > AND、OR
常用操作符介绍:
if(NOT expression)
为真的前提是 expression为假
if(expr1 AND expr2)
为真的前提是expr1和 expr2都为真
if(expr1 OR expr2)
为真的前提是expr1或者 expr2为真
if(COMMAND command-name)
为真的前提是存在 command-name命令、宏或函数且能够被调用
if(EXISTS name)
为真的前提是存在 name的文件或者目录(应该使用绝对路径)
if(file1 IS_NEWER_THAN file2)
为真的前提是file1比 file2新或者 file1、file2中有一个文件不存在(应该使用绝对路径)
if(IS_DIRECTORY directory-name)
为真的前提是directory-name表示的是一个目录(应该使用绝对路径)
if(variable|string MATCHES regex)
为真的前提是变量值或者字符串匹配 regex正则表达式
if(variable|stringLESS variable|string)
if(variable|string GREATER variable|string)
if(variable|string EQUAL variable|string)
为真的前提是变量值或者字符串为有效的数字且满足小于(大于、等于)的条件
if(variable|string STRLESS variable|string)
if(variable|string STRGREATER variable|string)
if(variable|string STREQUAL variable|string)
为真的前提是变量值或者字符串以字典序满足小于(大于、等于)的条件
if(DEFINED variable)
为真的前提是variable表示的变量被定义了
2.3循环结构
foreach 循环范例:set(VAR ab c)foreach(f${VAR})message(${f})endforeach()while 循环范例:set(VAR5)while(${VAR}GREATER 0)message(${VAR})math(EXPR VAR "${VAR} - 1")endwhile()
2.4函数和宏的定义
函数会为变量创建一个局部作用域,而宏则使用全局作用域。范例:
# 定义一个宏 hellomacro(helloMESSAGE)message(${MESSAGE})endmacro()# 调用宏 hellohello("helloworld")# 定义一个函数 hellofunction(helloMESSAGE)message(${MESSAGE})endfunction()
函数和宏可以通过命令 return()返回,但是函数和宏的返回值必须通过参数传递出去。例如:
cmake_minimum_required(VERSION2.8)function(get_funcRESULT)# RESULT 的值为实参的值,因此需要使用 ${RESULT}#这里使用 PARENT_SCOPE是因为函数会构建一个局部作用域set(${RESULT} "Hello Function"PARENT_SCOPE)endfunction()macro(get_macroRESULT)set(${RESULT} "Hello Macro")endmacro()get_func(V1)# 输出 Hello Functionmessage(${V1})get_macro(V2)# 输出 Hello Macromessage(${V2})
2.5字符串的一些问题
字符串可跨行且支持转义字符,例如:
set(VAR"helloworld")# 输出结果为:# ${VAR}= hello# worldmessage("\${VAR}= ${VAR}")
3. CMake常用命令
这里介绍一下常用的命令:
project命令
命令语法:project(<projectname>[languageName1 languageName2 … ] )
命令简述:用于指定项目的名称
使用范例:project(Main)
cmake_minimum_required命令
命令语法:cmake_minimum_required(VERSIONmajor[.minor[.patch[.tweak]]] [FATAL_ERROR])
命令简述:用于指定需要的 CMake 的最低版本
使用范例:cmake_minimum_required(VERSION 2.8)
aux_source_directory命令
命令语法:aux_source_directory(<dir><variable>)
命令简述:用于将 dir 目录下的所有源文件的名字保存在变量variable中
使用范例:aux_source_directory(. DIR_SRCS)
add_executable命令
命令语法:add_executable(<name> [WIN32][MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] source1 source2 … sourceN)
命令简述:用于指定从一组源文件 source1 source2 … sourceN 编译出一个可执行文件且命名为 name
使用范例:add_executable(Main ${DIR_SRCS})
add_library命令
命令语法:add_library([STATIC | SHARED |MODULE] [EXCLUDE_FROM_ALL] source1 source2 … sourceN)
命令简述:用于指定从一组源文件 source1 source2 … sourceN 编译出一个库文件且命名为 name
使用范例:add_library(Lib ${DIR_SRCS})
add_dependencies命令
命令语法:add_dependencies(target-namedepend-target1 depend-target2 …)
命令简述:用于指定某个目标(可执行文件或者库文件)依赖于其他的目标。这里的目标必须是add_executable、add_library、add_custom_target命令创建的目标
add_subdirectory命令
命令语法:add_subdirectory(source_dir[binary_dir] [EXCLUDE_FROM_ALL])
命令简述:用于添加一个需要进行构建的子目录
使用范例:add_subdirectory(Lib)
target_link_libraries命令
命令语法:target_link_libraries(<target>[item1 [item2 […]]] [[debug|optimized|general] ] …)
命令简述:用于指定 target 需要链接 item1item2 …。这里 target必须已经被创建,链接的item可以是已经存在的 target(依赖关系会自动添加)
使用范例:target_link_libraries(Main Lib)
set命令
命令语法:set(<variable><value> [[CACHE <type> <docstring> [FORCE]] | PARENT_SCOPE])
命令简述:用于设定变量 variable 的值为 value。如果指定了 CACHE变量将被放入 Cache(缓存)中。
使用范例:set(ProjectName Main)
unset命令
命令语法:unset(<variable>[CACHE])
命令简述:用于移除变量 variable。如果指定了CACHE变量将被从 Cache中移除。
使用范例:unset(VAR CACHE)
message命令
命令语法:message([STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR]“message to display” …)
命令简述:用于输出信息
使用范例:message(“Hello World”)
include_directories命令
命令语法:include_directories([AFTER|BEFORE][SYSTEM] dir1 dir2 …)
命令简述:用于设定目录,这些设定的目录将被编译器用来查找 include 文件
使用范例:include_directories(${PROJECT_SOURCE_DIR}/lib)
find_path命令
命令语法:find_path(<VAR>name1 [path1 path2 …])
命令简述:用于查找包含文件 name1 的路径,如果找到则将路径保存在 VAR中(此路径为一个绝对路径),如果没有找到则结果为<VAR>-NOTFOUND。默认的情况下,VAR会被保存在 Cache中,这时候我们需要清除 VAR 才可以进行下一次查询(使用 unset命令)。
使用范例:
find_path(LUA_INCLUDE_PATHlua.h ${LUA_INCLUDE_FIND_PATH})if(NOT LUA_INCLUDE_PATH)message(SEND_ERROR "Header file lua.hnot found")endif()
find_library命令
命令语法:find_library(<VAR>name1 [path1 path2 …])
命令简述:用于查找库文件 name1 的路径,如果找到则将路径保存在 VAR中(此路径为一个绝对路径),如果没有找到则结果为<VAR>-NOTFOUND。一个类似的命令link_directories已经不太建议使用了
add_definitions命令
命令语法:add_definitions(-DFOO-DBAR …)
命令简述:用于添加编译器命令行标志(选项),通常的情况下我们使用其来添加预处理器定义
使用范例:add_definitions(-D_UNICODE -DUNICODE)
execute_process命令
命令语法:
execute_process(COMMAND<cmd1> [args1...]][COMMAND <cmd2>[args2...] [...]][WORKING_DIRECTORY<directory>][TIMEOUT <seconds>][RESULT_VARIABLE<variable>][OUTPUT_VARIABLE<variable>][ERROR_VARIABLE<variable>][INPUT_FILE <file>][OUTPUT_FILE <file>][ERROR_FILE <file>][OUTPUT_QUIET][ERROR_QUIET][OUTPUT_STRIP_TRAILING_WHITESPACE][ERROR_STRIP_TRAILING_WHITESPACE])
命令简述:用于执行一个或者多个外部命令。每一个命令的标准输出通过管道转为下一个命令的标准输入。WORKING_DIRECTORY用于指定外部命令的工作目录,RESULT_VARIABLE用于指定一个变量保存外部命令执行的结果,这个结果可能是最后一个执行的外部命令的退出码或者是一个描述错误条件的字符串,OUTPUT_VARIABLE或者 ERROR_VARIABLE 用于指定一个变量保存标准输出或者标准错误,OUTPUT_QUIET或者 ERROR_QUIET用于忽略标准输出和标准错误。
使用范例:execute_process(COMMAND ls)
file命令
命令简述:此命令提供了丰富的文件和目录的相关操作(这里仅说一下比较常用的)
使用范例:
#目录的遍历# GLOB用于产生一个文件(目录)路径列表并保存在 variable中#文件路径列表中的每个文件的文件名都能匹配 globbing expressions(非正则表达式,但是类似)#如果指定了 RELATIVE路径,那么返回的文件路径列表中的路径为相对于 RELATIVE 的路径# file(GLOB variable [RELATIVE path] [globbingexpressions]...)#获取当前目录下的所有的文件(目录)的路径并保存到 ALL_FILE_PATH变量中file(GLOB ALL_FILE_PATH ./*)#获取当前目录下的 .h文件的文件名并保存到 ALL_H_FILE 变量中#这里的变量 CMAKE_CURRENT_LIST_DIR表示正在处理的CMakeLists.txt文件的所在的目录的绝对路径(2.8.3以及以后版本才支持)file(GLOB ALL_H_FILE RELATIVE${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/*.h)
4.CMake常用环境变量
- UNIX 如果为真,表示为 UNIX-like的系统,包括 Apple OS X和 CygWin
- WIN32 如果为真,表示为 Windows系统,包括 CygWin
- APPLE 如果为真,表示为 Apple系统
- 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++语言项目的编译器。
4.1构建类型
CMake为我们提供了四种构建类型:
(1)Debug
(2)Release
(3)MinSizeRel
(4)RelWithDebInfo
如果使用 CMake为Windows MSVC生成 projects/workspaces那么我们将得到上述的 4种解决方案配置。
如果使用 CMake生成 Makefile时,我们需要做一些不同的工作。CMake中存在一个变量CMAKE_BUILD_TYPE用于指定构建类型,此变量只用于基于 make的生成器。我们可以这样指定构建类型:
$ CMake -DCMAKE_BUILD_TYPE=Debug
这里的 CMAKE_BUILD_TYPE的值为上述的 4种构建类型中的一种。
4.2编译和链接标志(选项)
C编译标志相关变量:
CMAKE_C_FLAGS
CMAKE_C_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
C++编译标志相关变量:
CMAKE_CXX_FLAGS
CMAKE_CXX_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
CMAKE_C_FLAGS或 CMAKE_CXX_FLAGS可以指定编译标志
CMAKE_C_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO] 或 CMAKE_CXX_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]则指定特定构建类型的编译标志,这些编译标志将被加入到 CMAKE_C_FLAGS或 CMAKE_CXX_FLAGS中去,例如,如果构建类型为 DEBUG,那么 CMAKE_CXX_FLAGS_DEBUG将被加入到 CMAKE_CXX_FLAGS中去。
链接标志相关变量:
CMAKE_EXE_LINKER_FLAGS
CMAKE_EXE_LINKER_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
CMAKE_MODULE_LINKER_FLAGS
CMAKE_MODULE_LINKER_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
CMAKE_SHARED_LINKER_FLAGS
CMAKE_SHARED_LINKER_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
它们类似于编译标志相关变量。
4.3编译 32位和 64 位程序
对于 Windows MSVC,我们可以设定 CMake Generator来确定生成 Win32还是 Win64 工程文件,例如:
#用于生成Visual Studio 10 Win64工程文件CMake -G "Visual Studio 10 Win64"#用于生成Visual Studio 10 Win32工程文件CMake -G "Visual Studio 10"
我们可以通过 CMake –help来查看当前平台可用的 Generator
对于 UNIX和类 UNIX平台,我们可以通过编译器标志(选项)来控制进行 32位还是 64位构建。
5.CMake使用实例
一般我们的项目结构都是多源文件,多目录。面对此种项目结构,我们需要在每一个源码目录中都会放置一个 CMakeLists.txt文件。我们现在假定有这么一个工程:
HelloWorld|+------- Main.cpp|+------- CMakeLists.txt|+------- Lib|+------- Lib.cpp|+------- Lib.h|+------- CMakeLists.txt
这里 Lib目录下的文件将被编译为一个库。首先,我们看一下 Lib目录下的 CMakeLists.txt文件:
aux_source_directory(. DIR_SRCS)add_library(Lib ${DIR_SRCS})然后,看一下 HelloWorld目录下的 CMakeLists.txt文件:project(Main)cmake_minimum_required(VERSION 2.8)set(EXECUTABLE_OUTPUT_PATH ./)set(CMAKE_CXX_COMPILER“g++”)add_definitions(“std=c++0x -g”)add_subdirectory(Lib)aux_source_directory(. DIR_SRCS)add_executable(Main ${DIR_SRCS})target_link_libraries(Main Lib)
这里设置了可执行文件Main的输出目录,编译器,编译选项。使用了 add_subdirectory指定了需要进行构建的子目录,并且使用了target_link_libraries命令,表示 Main可执行文件需要链接 Lib 库。我们执行 CMake .命令,首先会执行 HelloWorld目录下的 CMakeLists.txt中的命令,当执行到 add_subdirectory(Lib)命令的时候会进入 Lib子目录并执行其中的 CMakeLists.txt文件,产生静态链接库Lib。
5.1外部构建(out of sourcebuilds)
我们在 CMakeLists.txt所在目录下执行 CMake .会生成大量的文件,这些文件和我们的源文件混在一起不好管理,我们采用外部构建的方式来解决这个问题。以上面的 HelloWorld工程来做解释:
在 HelloWorld目录下建立一个 Build目录(Build目录可以建立在任何地方)
进入 Build目录并进行外部构建 CMake ..(语法为 CMake <CMakeLists.txt的路径>,这里使用 CMake .. 表明了 CMakeLists.txt在 Build目录的父目录中)。这样 CMake将在 Build目录下生成文件。
CMake简介及使用实例相关推荐
- 【Android NDK 开发】Android Studio 使用 CMake 导入静态库 ( CMake 简介 | 构建脚本路径配置 | 引入静态库 | 指定静态库路径 | 链接动态库 )
文章目录 I . CMake 简介 II . Android Studio 中 CMake 引入静态库流程 III . 指定 CMake 最小版本号 IV . 导入函数库 ( 静态库 / 动态库 ) ...
- 【转载】CMake 简介和 CMake 模板
转载自我的博客: CMake 简介和 CMake 模板 . 如果你用 Linux 操作系统,使用 cmake 会简单很多,可以参考一个很好的教程: CMake 入门实战 | HaHack .如果你用 ...
- apache madlib 教程_Apache顶级开源项目——机器学习库MADlib简介与应用实例
原标题:Apache顶级开源项目--机器学习库MADlib简介与应用实例 Apache MADlib是Pivotal与UCBerkeley合作的一个开源机器学习库,提供了精确的数据并行实现.统计和机器 ...
- CMake快速入门01:CMake简介与安装
目录 1 CMake简介 2 CMake安装 3 CMake基本使用 3.1 实验源文件 3.2 实验CMakeLists.txt 3.2.1 CMakeList.txt命令概述 3.2.2 add_ ...
- php中getenv函数,PHP函数getenv简介和使用实例
这篇文章主要介绍了PHP函数getenv简介和使用实例,getenv函数主要用来获取一个环境变量的值,常见的PHP探针程序都是使用的getenv函数,需要的朋友可以参考下 getenv(PHP 4, ...
- SoapUI简介和入门实例解析
SoapUI简介 SoapUI是一个开源测试工具,通过soap/http来检查.调用.实现Web Service的功能/负载/符合性测试.该工具既可作为一个单独的测试软件使用,也可利用插件集成到Ecl ...
- Android NDK开发一 NDK环境搭建及cmake简介
1 前言 关于NDK的介绍可以查看官方的介绍: https://developer.android.com/ndk/guides/index.html 一句话总结NDK:NDK(Native Deve ...
- MVC框架简介与JavaSE实例
MVC框架简介 MVC全名是Model View Controller,是模型(Model)-视图(View)-控制器(Controller)的缩写,一种软件设计典范,用一种业务逻辑.数据.界面显示分 ...
- FLUENT中MRF模型简介及应用实例
本文主要介绍了FLUENT中的多重参考系(MRF)模型,并运用此模型以离心泵内部的流场为例,进行了数值模拟,得到了其压力分布.速度分布情况. 1.多重参考系(MRF)模型简介 FLUENT 可以进行整 ...
最新文章
- Android studio ocr初级app开发问题汇总(含工程代码)
- 不间断电源ups标准_什么是ups不间断电源,ups电源的重要性。
- 视频云峰会|“超视频化时代的全景创新” 是什么?
- 如何删除第一张单页_如何用PowerBI导入网页数据
- cloudstack centOS安装(二)
- 项目管理图书泄露章节-----关于项目内容中的其他
- 动态规划---01背包问题--Dp(详解附代码)
- 路由接口无法配时钟频率
- MongoDB 基础(六)安全性(权限操作)
- 深度学习CUDA最新最佳安装教程
- 2022年美容师(初级)考试题库模拟考试平台操作
- Python爬虫:新浪新闻详情页的数据抓取(函数版)
- ada:世界上第一位程序员
- Windows 软件定义存储S2D 测试
- 干货解答:如何设置Facebook Messenger 自动回复?
- 【微信开放平台】微信第三方扫码登录(亲测可用)
- Matlab 矩阵运算(1)
- 2019中国开源年会总结
- 网站关键词挖掘外链发布工具
- 这些年我们还在使用的国内国外域名注册商