博客
关于我
CMake自学记录,看完保证你知道CMake怎么玩!!!
阅读量:380 次
发布时间:2019-03-05

本文共 4640 字,大约阅读时间需要 15 分钟。

我不信你看完这个还是不知道啥是CMake!

写在前边(๑•̌.•̑๑)

为啥要学习CMake?(不同环境下Makefile格式是不兼容的)这里我就不说啥是CMake了,因为我相信看到这篇文章的你肯定已经接触过CMake了。

最近开始搞SLAM,要运行视觉SLAM十四讲上的一些实践案例,里边涉及到CMake的相关知识。
本来觉得CMake大概会用就行,照着CSDN上一些教程运行了一些小例程,但是感觉还是走马观花,没搞清楚,决定自己写一个来记录如何使用CMake。
那就开始整活吧!

Ubuntu自己的编译命令

在Ubuntu中,我们比较常见的编译器是gccg++,前者编译.c文件,后者编译.cpp文件

g++编译命令为例,可以在网上查到它命令选项,例如该文章
里边可以查到很多有关编译命令的变化
每本书或教材应该都有相关使用的讲解,这里不再赘述最基本的编译命令的使用
几个基本步骤:预处理–编译–汇编–链接
下图展示了我的一些g++编译命令实践,能看懂就没啥问题(里边有不小心打错的命令哦)
在这里插入图片描述

咱们怎么玩CMake

参照网上入门CMake的一些教程,我们也从最简单的一个.cpp+一个CMakeLists.txt开始

逐步过渡到多个源文件、多个目录,再到自定义选项等略微高级的操作
每个阶段主要说明CMakeLists.txt各行代码的含义

Demo1:一个源文件.cpp,一个CMakeLisits.txt

工程经过cmake和make后,长这个样子:

在这里插入图片描述
CMakeLists.txt中代码及解释如下:

#CMake需要的最低的版本,VERSION是固定的,后边的版本号可以变化#指定运行此配置文件所需的 CMake 的最低版本CMAKE_MINIMUM_REQUIRED(VERSION 3.10)#表示工程的名称是Demo1,貌似小写project也可以PROJECT(Demo1)#将源文件main.cpp添加到可执行文件demo1中ADD_EXECUTABLE(demo1  main.cpp)

有意思的是,参照网上一些博客的说法,CMake的内置指令是不区分大小写的(比如PROJECT?),而其内置参数是区分大小写的,写的时候要注意一下

经过编译,生成了名叫demo1的可执行文件,运行时比较有讲究,举个例子,这里需要用到main函数的直接传入参数,具体内容可以参照该篇博文:
具体的输入指令及结果如下:
在这里插入图片描述
这里程序计算了2^5,结果为32

Demo2:同一目录,多个源文件

因为有了多个源文件,需要把多个源文件都放到可执行文件中,这是该部分的关键

先来看看此时编译后的文件结构,如下图所示:
在这里插入图片描述
原始文件包括两个.cpp,一个.hpp,一个CMakeLists.txt
插一句,这个.hpp文件貌似和.h文件一个性质,都是头文件,另一个.cpp则可以认为是库文件,这个在后边会再次说明
来看一下CMakeLists.txt吧,内容及解释如下:

CMAKE_MINIMUM_REQUIRED(VERSION 3.10)PROJECT(Demo2)#将源文件都放到变量DIR_SRCS里边#查找指定目录下的所有源文件,添加到指定变量中:aux_source_directory(
)#这里是指将当前目录下所有的源文件放到DIR_SRCS#./和.都可以表示当前目录,但二者略有区别,现在还没搞懂AUX_SOURCE_DIRECTORY(./ DIR_SRCS)#将包含源文件的变量添加到可执行文件中,注意使用语法ADD_EXECUTABLE(demo2 ${DIR_SRCS})

由此则可以进行编译运行了,由于仍为一个目录,所以操作方法及结果与Demo1几乎完全相同:

在这里插入图片描述

Demo3:多个目录,多个源文件

我们不能把所有的源文件,或者说库文件,以及头文件都放到一个目录下边,所以要进行分目录管理,这里首先讲一下将库文件放到新的目录下的方法

编译后的文件结构如下图所示:
在这里插入图片描述

mylib目录下放了库文件和头文件,根目录以及库目录各有一个CMakeLists.txt,另外在main.cpp文件下,包含了头文件所在路径,如下所示:

#include 
#include "./mylib/mymath.hpp"using namespace std;

貌似有的方法是不用把路径全部打进去,还不是很清楚这个怎么玩

看一下库目录下的CMakeLists.txt,代码及解释如下:

#将当前目录下的源文件名称放到变量DIR_LIB_SRCS中aux_source_directory(. DIR_LIB_SRCS)#将mylib下的源文件,即刚刚当前目录下的源文件,生成为静态链接库Mylib#此时只是生成了一个静态链接库,还需要在根目录对其进行链接操作#参数分别为[生成的库的名字] [STATIC/SHARED] [包含库的源文件]add_library(Mylib STATIC ${DIR_LIB_SRCS})

这里生成了一个静态库,要把它链接到根目录里,根目录下CMakeLists.txt内容如下:

CMAKE_MINIMUM_REQUIRED(VERSION 3.10)PROJECT(Demo3)#添加mylib子目录(新加的),直接用mylib的目录#add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])ADD_SUBDIRECTORY(./mylib)#查找当前目录下所有的源文件,并将名称保存到 DIR_SRCS变量AUX_SOURCE_DIRECTORY(./ DIR_SRCS)#指定生成目标,这里的DIR_SRCS其实只有demo.cppADD_EXECUTABLE(demo3  ${DIR_SRCS})#添加链接库,将子目录中生成的静态库链接到可执行文件TARGET_LINK_LIBRARIES(demo3 Mylib)

为了满足多目录的需要,这里引入了两条新的代码,一个是ADD_SUBDIRECTORY,一个是TARGET_LINK_LIBRARIES,我的理解是前者将包含库目录的子目录添加到编译里,后者将库链接进可执行文件,具体原理我还不是很清楚,有懂的小伙伴欢迎在评论区补充哈!

这里看到一篇讲指令ADD_SUBDIRECTORY的文章,用来解决子目录和根目录同级如何编译的问题,放到这里应该日后用得到:
执行指令是在根目录,生成的可执行文件也在根目录(后边会把它放到其他地方去),具体步骤及结果如下:
在这里插入图片描述

Demo4:正规的文件结构

终于来到这里了,我们都想要搞一个正规的文件结构,并用CMake对其进行编译

我看到这个正规的结构时,立刻想到了当初编译OpenCV时的文件结构,里边就包括了binsrclib,当时不知道这些是什么含义,现在大概知道是咋回事了,如下表所示

文件名称 文件全名 文件含义
bin binary 可执行(二进制)文件
build build 编译相关文件
include include 头文件
src source 源文件&库文件

看到这个我只想说,原来清晰的文件结构是这么漂亮呀!

在这里插入图片描述
小激动一下哈哈(。◕ฺˇε ˇ◕ฺ。)
虽然不知道是不是还可以把库文件拿出来,放到一个叫lib的文件夹里?
Whatever,来看一下编译之前的文件结构细节:
在这里插入图片描述
可以看到,在文件的根目录以及src各有一个CMakeLists.txt,头文件放到了include文件下,源文件放在了src文件夹下,没有编译文件和可执行文件
先看下源文件src里的CMakeLists.txt

aux_source_directory (. SRC_LIST)#将工程用到的头文件目录添加进来#该命令是用来向工程添加多个指定头文件的搜索路径,路径之间用空格分隔。#命令将当前目录的上一级目录下的include目录添加进去,因为里边有用到的头文件include_directories (../include)add_executable (demo4 ${SRC_LIST})#set命令:将生成的指定文件放到指定目录下#这里设定把生成的可执行文件放到根目录下的bin目录下set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

需要说明一下的是,这里我们为工程添加了头文件的搜索路径,在main.c就不用把头文件的完整路径放进去了,此时main.c如下:

#include "testFunc.h"#include "testFunc1.h"

再把刚刚Demo3中的头文件写法放在下面做一下对比:

#include "./mylib/mymath.hpp"

我个人更加喜欢第一种写法,可能是看习惯了,但感觉第二种写法直接写出路径,是不是会更清晰呢?(⊙o⊙)

现在看看根目录下的CMakeLists.txt

cmake_minimum_required (VERSION 2.8)project (Demo4)#将src目录作为次级目录,因为里边是我们的源文件add_subdirectory (./src)

这里没什么特别的,可以跟Demo3对比一下,因为两者的风格还是有一些不同的,可以对比学到很多有趣的东西

这时在build目录下,进行cmake ..,这样才能将编译用的文件放到build目录下
CMakeFiles会在build目录下生成,然后在build目录下运行make
在这里插入图片描述
这时看一下工程文件夹有何变化:
在这里插入图片描述
可以看出来,在bin文件夹下多出来了可执行文件demo4,在build文件夹下多出了很多编译文件,但源文件和头文件没有被“污染”,结构仍然非常清晰舒服!

结语ღ( ´・ᴗ・` )

至此,希望你已经大概了解了CMake是个什么东西

不看别的也一定要仔细看CMakeLists.txt文件中的注释!
在本篇文章中,主要介绍了CMake最基本的操作
其中也穿插着一些小知识,包括

  • Ubuntu自带的g++等编译命令介绍
  • int main( int argc, char* argv[])是什么东西,怎么用
  • 比较正规的文件结构什么亚子
  • 在main函数引用头文件的两种方式

希望你能在学习CMake知识的同时对这些也能有一些了解~

这就是传说中的递归学习法吗!?😣
哎呀,突然发现CSDN还可以打表情哈哈,表情都在这里哦:
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-
最后列出帮助我的一些资源:
1.B站的一个视频,我的前3个demo是采用他的例程做的,非常清晰,但是demo4我觉得他的格式不是很标准,就采用了另外一个教程
2.B站视频下方提到的一个教程,是up教程的代码,但略有不同
3.CSDN的一篇帖子,讲的很清楚,后边有很多深入的知识,是我demo4的主要参考

👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍

你都看到这了,难道不来个小小的点赞迈?!嘿嘿,与君共勉!
在这里插入图片描述

转载地址:http://opewz.baihongyu.com/

你可能感兴趣的文章
docker基础:容器生命周期管理命令
查看>>
Shell脚本学习指南
查看>>
C#开发BIMFACE系列35 服务端API之模型对比6:获取模型构建对比分类树
查看>>
C# 规范建议
查看>>
C语言+easyX图形库的推箱子实现
查看>>
反汇编-流程控制语句-2-循环控制语句分析
查看>>
调试vs2019代码的流程
查看>>
游戏外挂基础-概述
查看>>
脱壳与加壳-加壳-6-代码实现加密导入表
查看>>
Typora配置PicGo时,提示Failed to fetch
查看>>
ASP.NET CORE MVC 实现减号分隔(Kebab case)样式的 URL
查看>>
SQL优化 MySQL版 -分析explain SQL执行计划与笛卡尔积
查看>>
bcolz的新操作
查看>>
Linux的s、t、i、a权限(转)
查看>>
zmq的send
查看>>
C++中的delete加深认识
查看>>
windows消息机制(转)
查看>>
STL笔试面试题总结(干货)(转)
查看>>
XML 和 HTML 之间的差异
查看>>
qt中moc的作用
查看>>