第一篇:最详尽,最初心的的CMake技术文档

CMake简述

CMake旨在成为一个跨平台的构建流程管理器,因此它定义了它自己的脚本语言,具有一定的语法和内置功能。 CMake本身是一个软件程序,因此应该使用脚本文件调用它来解释和生成实际的构建文件。
开发人员可以使用CMake语言为项目编写简单或复杂的构建脚本。

使用CMake语言构建逻辑和定义可以在CMakeLists.txt中编写,也可以使用<project_name> .cmake编写。 但作为最佳实践,主脚本命名为CMakeLists.txt而不是cmake。

  • CMakeLists.txt文件位于要构建的项目的源文件。
  • CMakeLists.txt一般放置在整个工程项目文件夹的根目录下。
  • 如果有多个模块,并且每个模块可以单独编译和构建,则可以将CMakeLists.txt插入到子文件夹中(本文仅提及单个CMakeLists.txt的示例)。
  • cmake文件可以用作脚本,它运行cmake命令来准备环境预处理或拆分任务,这些任务可以在CMakeLists.txt之外编写
  • cmake文件还可以为项目定义模块 ,这些项目可以和库程序文件分离构建,也可以是复杂的多模块项目的额外方法。

编写Makefile可能比编写CMake脚本更难。 通过语法和逻辑的CMake脚本与高级语言具有相似性,因此开发人员可以更轻松地创建他们的cmake脚本,而不会在Makefile中迷失。

常用的命令:

下文的示例会尽量用到这些命令

  • message:打印给定消息
  • cmake_minimum_required:设置要使用的最低的cmake版本
  • add_executable:添加具有给定名称的可执行目标
  • add_library:从列出的源文件中添加要构建的库目标
  • add_subdirectory:添加一个子目录来构建

还有一些命令可以让开发人员编写条件语句,循环,迭代列表,分配:

  • if, endif
  • elif, endif
  • while, endwhile
  • foreach, endforeach
  • list
  • return
  • set_property(分配值给变量)

缩写不是强制性的,但在编写CMake脚本时建议使用。 CMake不使用';'来理解陈述的结尾。所有条件语句都应该以相应的结束命令结束(endif,endwhile,endforeach)CMake的所有这些属性可帮助开发人员编写复杂的构建过程,包括多个模块,库和平台。

CMake环境变量

环境变量用于配置编译器标志,链接器标志,常规构建过程的测试配置。 必须引导编译器搜索库的给定目录。
从以下URL可以看到环境变量的详细列表,可以参见一下链接:
https://cmake.org/cmake/help/latest/manual/cmake-env-variables.7.html

某些环境变量被预定义的CMake变量覆盖。 例如 定义CMAKE_CXX_FLAGS时,CXXFLAGS将被覆盖。

下面是一个示例用例,当您想在编译过程中启用所有警告时,您可以编写-Wall to build命令。 如果使用CMake构建代码,可以使用set命令添加-Wall标志。

set(CMAKE_CXX_FLAGS,"-Wall")
defined flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")

CMake变量

CMake包括预定义变量,这些变量默认设置为源树和系统组件的位置。
变量区分大小写,而不是命令。 在变量的定义中,您只能使用字母数字字符和下划线,短划线(_, - )。
您可以在以下URL中找到有关CMake变量的更多详细信息
https://cmake.org/cmake/help/v3.5/manual/cmake-language.7.html#variables

一些变量是根据根文件夹预定义的:

  • CMAKE_BINARY_DIR:构建树和二进制输出文件夹顶级的完整路径,默认情况下,它定义为构建树的顶级。
  • CMAKE_HOME_DIRECTORY:HOME目录顶部的路径
  • CMAKE_SOURCE_DIR:源文件目录顶级的完整路径。
  • CMAKE_INCLUDE_PATH:用于查找文件,路径的路径

可以使用$ {<variable_name>}访问变量值

message("CXX Standard: ${CMAKE_CXX_STANDARD}")
set(CMAKE_CXX_STANDARD 14)

就像上面的变量一样,您可以定义自己的变量。 您可以调用set命令将值设置为新变量或更改现有变量的值,如下所示:

set("APP_VERSION","1.0.1")
message("${APP_VERSION}")

CMake 列表

CMake中的所有值都存储为字符串,但在某些上下文中可以将字符串视为列表。

通过连接由半列';'分隔的元素表示为字符串的元素列表

set(files a.txt b.txt c.txt)
# sets files to "a.txt;b.txt;c.txt"

要访问值列表,您可以使用CMake的foreach命令,如下所示:

foreach(file ${files})
    message("Filename: ${file}")
endforeach()

完整的表达式列表可以看这里
https://cmake.org/cmake/help/v3.8/manual/cmake-generator-expressions.7.html

使用CMake构建C ++项目

在前面的部分中,我们介绍了编写CMake脚本的核心原则。 现在,我们可以构建一个基本的链表为示例。

如图所示:


vs-code示例

很明显,对于这样一个小项目来说,使用CMake是多余的,但是当事情变得复杂时,它会有很大帮助。

为了构建main.cpp,在项目的根目录下创建一个CMakeLists.txt,并且写入如下代,然后执行cmake命令

/**/
cmake_minimum_required(VERSION 3.9.1)
/*设定项目的名称*/
project(cmake_tor)
/*我们编译的目标文件*/
add_executable(cmake_tor main.cpp)

然后在vscode终端中使用运行cmake命令,CMake会生成如下文件和目录

  • Makefile脚本,这个是我们执行对编译后的程序,执行tarball安装方式的 时候需要用到make脚本。
  • CMakeCache.txt:这个是CMake会根据你的开发环境自动生成一些脚本的预设配置。如果当前的预设配置不符合你的要求,从该文件拷贝相关的配置条目到CMakeLists.txt,修改配置选项后,重新执行一次cmake即可生成符合你需求的配置。
  • CMakeFiles目录:里面包含日志文件和一些临时的二进制文件,一般我们是不用理会的.


问题导入

我们的目的是生成一个二进制文件,但我们这里首先看一下刚才配置有哪些不足之处?

  • 首先,我们希望cmake生成的文件放到一个指定的目录里面,这样我们的项目不至于杂乱无章。
  • 其次,我希望能够使用自己指定的C/C++编译器,而不是cmake预定义的操作系统默认的编译器。
  • 最后,希望执行make命令的时候,编译后的可执行程序和库文件存放到一个有别于其他cmake文件夹的特殊目录。

下面先看看我们之后改进的项目目录结构,如下图,这是更符合我们实际开发工作中的一个目录结构。


屏幕快照 2019-08-24 上午11.53.59.png

那么,我们带着这三个问题定制自己的CMake配置方案吧!

首先,我们在项目的根目录先手动创建一个build的文件夹,在VSCode的终端重定向到build目录之下.

$ mkdir build
$ cd build

然后,在CMakeLists.txt使用以下cmake脚本,每个脚本的语句,代码中有注解

cmake_minimum_required(VERSION 3.1.0)
#设定c编译器和c++编译器,必须放在整个脚本的开头
set(CMAKE_C_COMPILER /usr/local/bin/gcc)
set(CMAKE_CXX_COMPILER /usr/local/bin/g++)

#工程项目的名称
project(cmake_tor)

#包含headers和source目录
include_directories(
    "${PROJECT_SOURCE_DIR}/headers"
    "${PROJECT_SOURCE_DIR}/source"
)

# 修正在macOS下CMAKE_CXX_STANDARD判断C++编译器标准的
#出错的bug,如果你用到是Windows/Linux系统,可以忽略这条语句
if (POLICY CMP0025)
  cmake_policy(SET CMP0025 NEW)
endif ()

#让CMake自动检测gcc的支持的c++标准,
#根据CMake的版本号判断它所支持c++标准
if(CMAKE_VERSION VERSION_LESS "3.8")
    set(CMAKE_CXX_STANDARD 14)
    message("The compile ${CMAKE_CXX_COMPILER} use C++14 standard!!")
elseif(CMAKE_VERSION VERSION_LESS "3.11")
    set(CMAKE_CXX_STANDARD 17)
    message("The compile ${CMAKE_CXX_COMPILER} use C++17 standard!!")
else()
    set(CMAKE_CXX_STANDARD 20)
    message("The compile ${CMAKE_CXX_COMPILER} use C++20 standard!!")
endif()
set(CMAKE_CXX_EXTENSIONS OFF)

#构建自己的软件系统
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/app)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/libs)

add_executable(main "${PROJECT_SOURCE_DIR}/source/main.cpp")
add_library(shape SHARED "${PROJECT_SOURCE_DIR}/source/shape.c")

最后执行cmake和make,我们会发现如下图,正如我们所愿在指定的目录下生成了一个可执行文件和共享对象文件

$ cmake
$ make

结束语:
第一次接触CMake的同学,可能觉得无从入手,单独花上一段时间去完全掌握它得不偿失,本文是对以前遇到的一些典型问题做成一个易懂的教程。

带着问题去stackflow寻找一些相关问题的答案是很好的学习方法之一,至少你在碰壁的时候,不会为了某个方面迷失了自我,然后自己去根据前人提供的建议去实践并归纳到一个文件里,这样就变成你自己已经掌握的技能了。

技术文~~分享至此,希望你喜欢。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容

  • 注:首发地址 1. 前言 当在做 Android NDK 开发时,如果不熟悉用 CMake 来构建,读不懂 CMa...
    cfanr阅读 23,657评论 1 53
  • CMake学习 本篇分享一下有关CMake的一些学习心得以及相关使用。 本文目录如下: [1、CMake介绍] [...
    AlphaGL阅读 12,152评论 11 79
  • 向您的项目添加 C 和 C++ 代码 本文内容 下载 NDK 和构建工具 创建支持 C/C++ 的新项目 构建和运...
    会飞的大象_阅读 3,648评论 0 3
  • 参考 CMake入门实战cmake缓存清理 什么是CMake CMake允许开发者编写一种平台无关的CMakeLi...
    GeminiGirl0604阅读 3,264评论 0 3
  • 搬运自本人 CSDN 博客:https://blog.csdn.net/ajianyingxiaoqinghan/...
    琦小虾阅读 14,932评论 0 11