点击上方“小白学视觉”,选择加"星标"或“置顶

重磅干货,第一时间送达

文章导读

本文从C/C++代码的编译过程入手,弄清楚Make与Makefile,CMake与CMakeLists的关系,最后从CMakeLists的语法规则入手给出示例带大家熟悉如何编写一份简单的编译脚本。

1.C/C++的编译过程

编译过程实际上就是将一种语言(通常为高级语言)翻译为成另一种语言(通常为低级语言)。C/C++程序编译的主要工作流程为:源代码  → 预处理器  → 编译器  → 汇编器 → 链接器  → 可执行程序

(1)预处理

C/C++中,在编译器对源程序进行编译之前,首先要对程序文本进行预处理。预处理器提供了一组预编译处理指令和预处理操作符,形式上以#开头,实际上并不属于C/C++中的语句,不能被编译程序翻译,需要在真正编译之前做一个预处理,最后输出一个“.i”文件。

(2)编译

编译就是把C/C++代码转换成汇编代码。编译程序需要通过词法分析和语法分析,在确认所有的指令都符合语法规则没有语法错误之后,把代码转换成汇编语言,生成汇编代码。

(3)汇编

汇编就是将上一步输出的汇编代码翻译成目标机器指令的过程,生成的目标文件中是与源程序等效的机器语言。

(4)链接

链接就是将汇编生成的目标文件、系统库的目标文件、库文件链接起来,生成可以在某一特定平台运行的可执行程序。

2.Make和Makefile是什么关系?

当源文件比较多时,一般不适合直接通过gcc来编译代码,这时就需要一个自动化的编译工具。

Make(GNU Make)是一个自动化软件,用于将源代码文件编译为可执行的二进制文件从而完成自动化编译。Make工具编译的时候需要Makefile文件提供编译规则,Makefile定义了一系列的编译规则,包括编译的先后顺序,哪些文件需要重新编译等操作。

利用Make工具可以自动完成编译工作,如果修改了某几个源文件,则只重新编译这几个源文件。如果某个头文件被修改了,则重新编译所有包含该头文件的源文件。利用这种自动编译极大地提高了开发效率,避免了不必要的重新编译。

3.CMake与CMakeLists又是什么?

CMake是更加抽象的跨平台的项目管理工具,它能够输出各种Makefile文件或工程文件。例如,在windows下它能生成visual studio的工程,在linux下它会生成Makefile文件。也就是说,cmake能够按照同一个抽象规则为各个编译器生成工程文件,从而忽略不同平台的差异,抽象成为一个一致的环境。

而CMake命令的执行所按照的规则也就是由CMakeLists.txt文件编写的。

对于一个庞大的工程,编写Makefile相当复杂,有了CMake工具之后就可以读入所有源文件,自动生成Makefile。那么使用CMake编写一个跨平台工程的基本流程如下:

  1. 编写源文件

  2. 编写CMakeLists.txt

  3. 由CMake根据CMakeLists.txt生成Makefile

  4. 由Make根据Makefile,调用gcc生成可执行文件

4.如何编写CMakeLists

CMakeLists.txt的编写主要包含以下步骤:

  1. cmake_minimum_required(VERSION 2.8.0):用于指定cmake所需最低版本;

  2. project(Project) :用于指定项目名称;

  3. include_directories() :用于包含头文件目录;

  4. aux_source_directory(src dir_srcs):用于包含源文件目录;

  5. set(TEST_MATH) :用于设置环境变量,编译用到的源文件全部都要放到这里;

  6. add_executable(${PROJECT_NAME} ${TEST_MATH}):用于添加要编译的可执行文件;

  7. target_link_libraries(${PROJECT_NAME} m):用于添加可执行文件所需要的库;

CMake语法中预设了一些常用变量:

  • CMAKE_MAJOR_VERSION:cmake 主版本号;

  • CMAKE_MINOR_VERSION:cmake 次版本号;

  • CMAKE_C_FLAGS:设置 C 编译选项;

  • CMAKE_CXX_FLAGS:设置 C++ 编译选项;

  • PROJECT_SOURCE_DIR:工程的根目录;

  • PROJECT_BINARY_DIR:运行 cmake 命令的目录;

  • CMAKE_CURRENT_SOURCE_DIR:当前CMakeLists.txt 所在路径;

  • CMAKE_CURRENT_BINARY_DIR:目标文件编译目录;

  • EXECUTABLE_OUTPUT_PATH:重新定义目标二进制可执行文件的存放位置

  • LIBRARY_OUTPUT_PATH:重新定义目标链接库文件的存放位置

示例代码如下(cmake语法大小写不敏感)

cmake_minimum_required(VERSION 2.8.12)
option(ARM "Activate the ARM cross-compile" OFF)
if(ARM)message(STATUS "ARM Cross-Compile")set(CMAKE_SYSTEM_NAME Linux)set(CMAKE_C_COMPILER /usr/local/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-gcc)set(CMAKE_CXX_COMPILER /usr/local/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-g++)set(CMAKE_BUILD_TYPE "Release")
else()message(STATUS "Default Compile")
endif()
project("Demo")

上述代码中通过cmake_minimum_required指定cmake的最小版本,if-else语句进行条件判断,因为cmake可以跨平台编译,上述通过宏的方式选择arm下的交叉编译器或者win下的默认编译器。

project()在上面提到是指定当前项目的名称。而message()类似于printf用于答应信息。set()用于显示的定义变量,比如定义CMAKE_C_COMPILER变量保存arm平台C编译器的路径,定义CMAKE_BUILD_TYPE变量指定编译的是Release版本程序。

add_compile_options(-D_DEBUG)
add_compile_options(-D_INTERNALDEBUG)
add_compile_options(-std=c++11)
add_compile_options(-O0)
add_compile_options(-g)
add_compile_options(-Wall)

add_compile_options主要用来设置编译选项,比如例子代码中-std=c++11指定编译c++代码时加上c++11支持选项;-g允许发出gcc能提供的所有有用的警告到生成的二进制文件中;-O0是调节编译优化程度,调到最高需要设置 -O3 ,最低的是 -O0 即不做优化;

# Find requirements
find_package(PCL REQUIRED)
if(NOT PCL_FOUND)message("Not found PCL")
endif()
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})

当在工程中使用第三方库时,需要知道在哪里找头文件;在哪里找库文件;链接库的名称是什么等信息。使用find_package()命令会在模块路径中寻找Find.cmake,其中记录了库的相关信息。如实例代码中,当找到第三方库的配置路径后,就可以通过include_directories包含其头文件;通过link_directories链接其库文件;add_definitions的作用是控制库的源代码开关,保证在更改第三方库代码时,不对其源码进行破坏,并可以添加自己的功能。

file(GLOB_RECURSE SRC_LIST    ${CMAKE_CURRENT_SOURCE_DIR}/modules/src/*.cpp
)aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/modules/common SRC_COMMON_LIST
)add_library(perception STATIC        ${SRC_LIST}${SRC_COMMON_LIST}
)

file()通过自定义搜索规则将文件中的内容存储到变量中,其中参数GLOB 会产生一个由所有匹配globbing表达式的文件组成的列表将其保存到变量SRC_LIST。或者使用参数GLOB_RECURSE遍历匹配目录的所有文件以及子目录下面的文件将其保存到变量SRC_LIST。

aux_source_directory()的作用与file()类似,查找指定目录下的所有源文件,然后将结果存进指定变量名。如上述代码将common路径下的文件保存到变量SRC_COMMON_LIST中。

add_library用于将变量中保存的源文件打成库的形式,可以通过参数选择静态库或动态库。如:

add_library(perception STATIC ${SRC_LIST})

add_library(perception SHARED ${SRC_LIST})

link_directories(${CMAKE_CURRENT_SOURCE_DIR}/modules/lib/
)add_executable(main ${SRC_FILES})target_link_libraries(main libdetect.alibsegment.alibtracker.a
)

最后就是生成可执行文件并链接库文件的环节,add_executable使用指定的源文件来生成目标可执行文件。

目标可执行文件分为三类:

  • 普通可执行目标文件

  • 导入可执行目标文件

  • 别名可执行目标文件

其中link_libraries和target_link_libraries这两个命令长得挺相似,功能却不同:

link_libraries是指定要链接的库文件路径。自己生成的库文件可以用该指令指定目录的路径以便工程能够找到。

target_link_libraries是将目标文件与库文件进行链接,可以指定动态库/静态库,如果只提供库名称,系统会根据链接库目录搜索xxx.so 或者 xxx.a 文件;或者指定给出全路径。

下载1:OpenCV-Contrib扩展模块中文版教程

在「小白学视觉」公众号后台回复:扩展模块中文教程即可下载全网第一份OpenCV扩展模块教程中文版,涵盖扩展模块安装、SFM算法、立体视觉、目标跟踪、生物视觉、超分辨率处理等二十多章内容。

下载2:Python视觉实战项目52讲

在「小白学视觉」公众号后台回复:Python视觉实战项目即可下载包括图像分割、口罩检测、车道线检测、车辆计数、添加眼线、车牌识别、字符识别、情绪检测、文本内容提取、面部识别等31个视觉实战项目,助力快速学校计算机视觉。

下载3:OpenCV实战项目20讲

在「小白学视觉」公众号后台回复:OpenCV实战项目20讲即可下载含有20个基于OpenCV实现20个实战项目,实现OpenCV学习进阶。

交流群

欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器、自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN、算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~

CMake编译工具与项目构建相关推荐

  1. 一文详解CMake编译工具与项目构建

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 文章导读 本文从C/C++代码的编译过程入手,弄清楚Make与Makefile,CMake与CMake ...

  2. 使用CMake编译Caffe的项目

    使用CMake编译Caffe的项目 最近我在编译一个Caffe的项目,在编译时候总会找不到这个依赖,那个依赖,这里总结出几条经验. 1. Caffe必须要使用CMake去编译 我一开始用作者提供的Ma ...

  3. 走进JavaWeb技术世界12:从手动编译打包到项目构建工具Maven

    小李的Build之路(上) 转自: 刘欣 码农翻身 2016-07-10 摘要:手工Build的烦恼要不是为了和女朋友留在一个城市,小李肯定去北上广奋斗去了.现在他只能留在这个2.5线城市,进入这家软 ...

  4. CMakeList--->CMakeList的编写,cmake,平台通用项目构建工具

    视频教程康康这个Bilibili点击跳转,由于本文信息密度大,比较详细,可能略显繁琐,还请耐心阅读

  5. gyp linux,gyp编译工具

    最近用到了 node-gyp 这个工具, 是node 社区对 google gyp 编译工具的一个封装, 使用 node-gyp 工具可以用C++为node 项目编写 addon. 了解了一下 goo ...

  6. python 项目构建工具_GitHub - shjlone/emake: 你见过的最简单的 GCC/CLANG 项目构建工具(python3版本)...

    python3实现版本 Preface GNU Make 太麻烦?Makefile 写起来太臃肿?头文件依赖生成搞不定?多核同时编译太麻烦?Emake 帮你解决这些问题: 使用简单:设定源文件,设定编 ...

  7. c c 语言编程项目实例,实例分享cmake编译一个简单c++项目(demo)

    实例分享cmake编译一个简单c++项目(demo) 发布时间:2020-09-19 21:08:04 来源:脚本之家 阅读:63 作者:mdxy-dxy 下面通过一个小例子来说明cmake编译一个c ...

  8. 使用CMake编译Libigl错误问题解决方法

    所编译环境:win10.VS2015 X64 Libigl,所编译时遇到的问题: error: could not find git for clone of eigen-download 官网下载安 ...

  9. 关于项目编译工具ninja、make、cmake的区别与优劣

    ninja和make都是通过脚本语言指定编译规则,然后调用gcc等编译器实现自动化编译,过程中会通过文件时间戳来进行增量构建. ninja Ninja 是Google的一名程序员推出的注重速度的构建工 ...

最新文章

  1. 京东热点key探测系统发布,单机 QPS 提升至 37 万
  2. CSP认证201412-4 最优灌溉[C++题解]:最小生成树裸题、Kruskal算法求最小生成树
  3. vue学习:v-text,v-html, v-model, {{}}之间的异同
  4. abap mm后台表_【中后台应用】从表单抽象到表单中台
  5. 【Ubuntu16.04-opencv3.4.0-FDDB Evaluation】评测代码使用中遇到对‘cvxxx’未定义的引用问题
  6. GetProcAddress()用法
  7. C ++中的std :: binary_search()
  8. Python 库的使用 —— dis
  9. 使用IDEA创建一个Maven Web工程:无法创建Java Class文件
  10. 「WC 2019」数树
  11. WD西部数据内置硬盘编号说明书
  12. 紫猫安卓按键之其他命令
  13. DataV-组件配置
  14. 【常见网页排版布局】
  15. 云南民族大学计算机网络期末试卷,云南民族大学附中2018届高三上学期期末考试物理试卷【附答案】...
  16. 微信小程序使用Echarts 实现世界地图(其它地图同理)
  17. uint8_t图像数据类型介绍
  18. RTX4070ti-40系列显卡配置pytorch深度学习环境过程
  19. B+树与B树的不同及B+树的特点
  20. 实验一:鸢尾花数据集分类

热门文章

  1. 一站式解决:隐马尔可夫模型(HMM)全过程推导及实现
  2. 媲美Pandas?一文入门Python的Datatable操作
  3. 频频曝出程序员被抓,我们该如何避免面向监狱编程?
  4. 21 款 yyds 的 IDEA插件
  5. SpringBoot集成Quartz实现定时任务的动态创建、启动、暂停、恢复、删除。
  6. 2w字长文,让你瞬间拥有「调用链」开发经验
  7. 2021年自然语言处理学习路线!
  8. Datawhale两岁啦!
  9. 爱可可推荐!关于竞赛思路,方法和代码实践,Datawhale数据竞赛Baseline开源分享!...
  10. GitHub开源项目!一款功能强大的特征选择工具