以下内容为本人的著作,如需要转载,请声明原文链接微信公众号「englyf」https://www.cnblogs.com/englyf/p/16667896.html


1. cmake 是什么?

这些年大型 C/C++ 工程都纷纷转到了 cmake 环境下,那么这个工具到底有什么魅力吸引着大家呢?无它,软件工程崇尚实用主义,而 cmake 的功能强悍而灵活,趁手的工具用起来!为了从 makefile 下解放大伙的双手,cmake 在设计之初的目标就是奔着用于对程序构建过程进行管理,它会自动对工程生成相应的 makefile 和其它辅助构建信息。

注意:cmake 不是编译器,仅是构建管理工具,比如调度编译器/链接器等等

2. cmake 的配置文件 CMakeLists.txt

使用 cmake 来构建工程成功输出目标文件,这个过程需要依赖于配置的设定。而这个设定存放在文件 CMakeLists.txt 中,每个构建工程都至少有一个这样的文件(如果工程有子工程,那么每个子工程又会有对应的配置文件),该文件可按需定制。一般会在工程的根目录下创建这个文件 CMakeLists.txt。举个栗子,这里有个最简单的配置示例(假设本工程不包含子工程,只有一个源文件 main.cpp 而且存放于工程根目录下):

# 指定最低要求的 cmake 版本 3.10
cmake_minimum_required(VERSION 3.10) # 设置工程名 test
project(test) # 指定编译输出可执行结果文件 test, 指定编译源文件 main.cpp
add_executable(test main.cpp)

当然,除了把配置内容写在配置文件 CMakeLists.txt 中,还可以在执行 cmake 指令时传入多样化的参数,不过通过传参的方式用起来不灵活而且不利于持续输出的开发理念。同一套产品输出给不同的客户时,可以将不同客户的需求转化为不同的配置文件,分别调用于构建目标结果文件。

3. CMakeLists.txt 变量

CMakeLists.txt 文件内部同样支持变量,包括变量定义和引用等。

eg. 定义变量 USE_CUSTOM_SRC,并设置默认值 OFF (如果引用该变量前,没有赋值,那么当前值为默认值):

option (USE_CUSTOM_SRC "something you want to mark" OFF)

或者只是定义变量 USE_CUSTOM_SRC,并赋值 true

SET(USE_CUSTOM_SRC true)

或者通过调用其它程序并接收输出值,跳过定义,如在调用变量 CMAKE_CURRENT_SOURCE_DIR 代表的目录下执行程序 git 带上参数 "log --format='%h' -1" 以获取 SHA1 值并且保存到变量 GIT_SHA1 中。

exec_program(
        "git"
        ${CMAKE_CURRENT_SOURCE_DIR}
        ARGS "log --format='%h' -1"
        OUTPUT_VARIABLE GIT_SHA1
    )

在调用 cmake 时同样可以在传入的参数中指定变量 USE_CUSTOM_SRC 并赋值,变量前加 -D,如:

cmake -DUSE_CUSTOM_SRC=ON

CMakeLists.txt 中,已定义的变量可直接引用:

if(USE_CUSTOM_SRC)
    xxx
else()
    xxx
endif()

4. CMakeLists.txt 定义源码相关的宏定义

如果需要为源码编译器添加宏定义呢?

如下:

add_definitions(-DUSE_CUSTOM_SRC)

这段语句定义了适用于源代码中的预编译宏 USE_CUSTOM_SRC, 以 -D 为前缀。

注意:这里的 USE_CUSTOM_SRC (适用范围是被 cmake 管理的工程源代码) 与上面的 CMakeLists.txt 变量 USE_CUSTOM_SRC (适用范围是 cmake 读取的 CMakeLists.txt 文件内容内) 不一样

5. 执行方法

先说一下我的环境:

WIN10 + WSL Ubuntu 18.4

wsl 环境下要求安装有cmake、gcc、g++ 等基本工具。

首先进入 wsl 环境,看一下当前的工作目录内容:

admin@DESKTOP:/mnt/g/test$ ls -l
total 0
-rwxrwxrwx 1 root root 89 Jun 26 16:12 CMakeLists.txt
-rwxrwxrwx 1 root root 354 Jun 26 17:13 main.cpp

源文件 main.cpp 实现了执行指令 ls -l . 的功能,下面是文件内容

#include <unistd.h>
#include <stdio.h> int main()
{
pid_t pid = fork();
if (pid == -1) {
perror("fork error");
} if (pid == 0) {
execl("/bin/ls", "ls", "-l", ".", (char *)NULL);
} return 0;
}

创建构建输出目录 build,然后导航到输出目录

mkdir build
cd build

执行 cmake,输入参数是存放 CMakeLists.txt 文件的相对目录,目的是配置构建工程和生成用于原生构建的必需信息并保存到当前目录文件中,也就是所谓的配置构建系统

admin@DESKTOP:/mnt/g/test/build$ cmake ../
-- The C compiler identification is GNU 7.5.0
-- The CXX compiler identification is GNU 7.5.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /mnt/g/test/build

再次执行 cmake,调用当前目录的构建系统实现项目构建,包括编译/链接和输出二进制目标文件。

admin@DESKTOP:/mnt/g/test/build$ cmake --build .
Scanning dependencies of target test
[ 50%] Building CXX object CMakeFiles/test.dir/main.cpp.o
[100%] Linking CXX executable test
[100%] Built target test

这一步的操作其实也可以直接调用make实现,比如需要用到加速的选项-j等就比较推荐这样子调用

make -jn

看一下输出的二进制目标文件是否存在

admin@DESKTOP:/mnt/g/test/build$ ls -l
total 40
-rwxrwxrwx 1 root root 12704 Jul 12 21:34 CMakeCache.txt
drwxrwxrwx 1 root root 512 Jul 12 21:39 CMakeFiles
-rwxrwxrwx 1 root root 4847 Jul 12 21:34 Makefile
-rwxrwxrwx 1 root root 1552 Jul 12 21:34 cmake_install.cmake
-rwxrwxrwx 1 root root 8392 Jul 12 21:39 test

最后执行一下目标文件,看看实际执行结果和代码的意图是否一致

admin@DESKTOP:/mnt/g/test/build$ ./test
total 40
-rwxrwxrwx 1 root root 12704 Jul 12 21:34 CMakeCache.txt
drwxrwxrwx 1 root root 512 Jul 12 21:39 CMakeFiles
-rwxrwxrwx 1 root root 4847 Jul 12 21:34 Makefile
-rwxrwxrwx 1 root root 1552 Jul 12 21:34 cmake_install.cmake
-rwxrwxrwx 1 root root 8392 Jul 12 21:39 test

好了,简简单单介绍到这里,欢迎留言交流_

cmake 入门笔记的更多相关文章

  1. MySQL入门笔记

    MySQL入门笔记 版本选择: 5.x.20 以上版本比较稳定 一.MySQL的三种安装方式: 安装MySQL的方式常见的有三种: ·          rpm包形式 ·          通用二进制 ...

  2. CMake学习笔记四:usb_cam的CMakeLists解析

    最近在学习cmake,在完整看了<cmake实践>一书后,跟着书上例程敲了跑了一遍,也写了几篇相关读书笔记,算是勉强基本入门了.所以找了usb_cam软件包的CMakeLists.txt来 ...

  3. Android NDK JNI 入门笔记-day04-NDK实现Hash算法

    * Android NDK JNI 入门笔记目录 * 开头 前面的学习,我们已经掌握了 NDK 开发的必备知识. 下一步就要多实践,通过创造问题并解决问题,来增加熟练度,提升经验. 日常开发中,经常会 ...

  4. 每天成长一点---WEB前端学习入门笔记

    WEB前端学习入门笔记 从今天开始,本人就要学习WEB前端了. 经过老师的建议,说到他每天都会记录下来新的知识点,每天都是在围绕着这些问题来度过,很有必要每天抽出半个小时来写一个知识总结,及时对一天工 ...

  5. ES6入门笔记

    ES6入门笔记 02 Let&Const.md 增加了块级作用域. 常量 避免了变量提升 03 变量的解构赋值.md var [a, b, c] = [1, 2, 3]; var [[a,d] ...

  6. [Java入门笔记] 面向对象编程基础(二):方法详解

    什么是方法? 简介 在上一篇的blog中,我们知道了方法是类中的一个组成部分,是类或对象的行为特征的抽象. 无论是从语法和功能上来看,方法都有点类似与函数.但是,方法与传统的函数还是有着不同之处: 在 ...

  7. React.js入门笔记

    # React.js入门笔记 核心提示 这是本人学习react.js的第一篇入门笔记,估计也会是该系列涵盖内容最多的笔记,主要内容来自英文官方文档的快速上手部分和阮一峰博客教程.当然,还有我自己尝试的 ...

  8. redis入门笔记(2)

    redis入门笔记(2) 上篇文章介绍了redis的基本情况和支持的数据类型,本篇文章将介绍redis持久化.主从复制.简单的事务支持及发布订阅功能. 持久化 •redis是一个支持持久化的内存数据库 ...

  9. redis入门笔记(1)

    redis入门笔记(1) 1. Redis 简介 •Redis是一款开源的.高性能的键-值存储(key-value store).它常被称作是一款数据结构服务器(data structure serv ...

随机推荐

  1. IDEA中Maven Project所在位置

    难免有小伙伴找不着这个在哪. 一.首先就是可以在下面这个位置查询到: 二.如果找不着,那么在这里找: 三.如果还找不到,那就没有是你刚导入的项目没有Add Maven, 下面这个图是我Add  Mav ...

  2. Git下载(快速快速快速下载!!)

    在安装Git环境的时候,需要下载Git的安装包,但是官网的下载网速实在是太慢的(几十M的安装包,下载速度只有几十K) (所以可以在镜像中下载,速度超快) Git镜像下载链接-------------- ...

  3. Contest

    Contest 题目 链接 题目描述 \(n\) 支队伍一共参加了三场比赛. 一支队伍 \(x\) 认为自己比另一支队伍 \(y\) 强当且仅当 \(x\) 在至少一场比赛中比 \(y\) 的排名高. ...

  4. 搭建企业级实时数据融合平台难吗?Tapdata + ES + MongoDB 就能搞定

      摘要:如何打造一套企业级的实时数据融合平台?Tapdata 已经找到了最佳实践,下文将以 Tapdata 的零售行业客户为例,与您分享:基于 ES 和 MongoDB 来快速构建一套企业级的实时数 ...

  5. Tapdata 实时数据中台在智慧教育中的实践

      摘要:随着教育信息化的推进,智慧校园建设兴起,但在实施过程中面临数据孤岛.应用繁多.数据再利用等方面挑战,而 Tapdata 的实时数据中台解决方案,能够高效地解决智慧校园实施中的基础数据问题. ...

  6. 攻防世界进阶区MISC ——56-60

    56.low 得到一张bmp,世纪之吻,扔进kali中,binwalk,zsteg,无果,再放进stegsolve中,虽然发现小的数据块,但是过滤通道得不到任何信息,猜测是要用脚本进行 # lsb隐写 ...

  7. Java.稀疏数组

    package array; public class demo06 { public static void main(String[] args) { //创建一个二维数组 11*11 int[] ...

  8. 开发实践丨昇腾CANN的推理应用开发体验

    摘要:这是关于一次 Ascend 在线实验的记录,主要内容是通过网络模型加载.推理.结果输出的部署全流程展示,从而快速熟悉并掌握 ACL(Ascend Computing Language)基本开发流 ...

  9. Java学习_常见异常

    JAVA常见异常 Java.io.NullPointerException null 空的,不存在的 NullPointer 空指针 空指针异常,该异常出现在我们操作某个对象的属性或方法时,如果该对象 ...

  10. 深入剖析(JDK)ArrayQueue源码

    深入剖析(JDK)ArrayQueue源码 前言 在本篇文章当中主要给大家介绍一个比较简单的JDK为我们提供的容器ArrayQueue,这个容器主要是用数组实现的一个单向队列,整体的结构相对其他容器来 ...