点击上方“3D视觉工坊”,选择“星标”

干货第一时间送达

文章导读

本文从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 requirementsfind_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.a    libsegment.a    libtracker.a)

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

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

  • 普通可执行目标文件

  • 导入可执行目标文件

  • 别名可执行目标文件

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

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

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

本文仅做学术分享,如有侵权,请联系删文。

下载1

在「3D视觉工坊」公众号后台回复:3D视觉即可下载 3D视觉相关资料干货,涉及相机标定、三维重建、立体视觉、SLAM、深度学习、点云后处理、多视图几何等方向。

下载2

在「3D视觉工坊」公众号后台回复:3D视觉github资源汇总即可下载包括结构光、标定源码、缺陷检测源码、深度估计与深度补全源码、点云处理相关源码、立体匹配源码、单目、双目3D检测、基于点云的3D检测、6D姿态估计源码汇总等。

下载3

在「3D视觉工坊」公众号后台回复:相机标定即可下载独家相机标定学习课件与视频网址;后台回复:立体匹配即可下载独家立体匹配学习课件与视频网址。

重磅!3DCVer-学术论文写作投稿 交流群已成立

扫码添加小助手微信,可申请加入3D视觉工坊-学术论文写作与投稿 微信交流群,旨在交流顶会、顶刊、SCI、EI等写作与投稿事宜。

同时也可申请加入我们的细分方向交流群,目前主要有3D视觉CV&深度学习SLAM三维重建点云后处理自动驾驶、多传感器融合、CV入门、三维测量、VR/AR、3D人脸识别、医疗影像、缺陷检测、行人重识别、目标跟踪、视觉产品落地、视觉竞赛、车牌识别、硬件选型、学术交流、求职交流、ORB-SLAM系列源码交流、深度估计等微信群。

一定要备注:研究方向+学校/公司+昵称,例如:”3D视觉 + 上海交大 + 静静“。请按照格式备注,可快速被通过且邀请进群。原创投稿也请联系。

▲长按加微信群或投稿

▲长按关注公众号

3D视觉从入门到精通知识星球:针对3D视觉领域的知识点汇总、入门进阶学习路线、最新paper分享、疑问解答四个方面进行深耕,更有各类大厂的算法工程人员进行技术指导。与此同时,星球将联合知名企业发布3D视觉相关算法开发岗位以及项目对接信息,打造成集技术与就业为一体的铁杆粉丝聚集区,近3000星球成员为创造更好的AI世界共同进步,知识星球入口:

学习3D视觉核心技术,扫描查看介绍,3天内无条件退款

圈里有高质量教程资料、可答疑解惑、助你高效解决问题

觉得有用,麻烦给个赞和在看~  

一文详解CMake编译工具与项目构建相关推荐

  1. CMake编译工具与项目构建

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 文章导读 本文从C/C++代码的编译过程入手,弄清楚Make与Ma ...

  2. 一文详解宏基因组组装工具Megahit安装及应用

    要点 Megahit简介 Megahit的基本组装原理 Megahit的安装和使用 Megahit实战 hello,大家好,今天为大家带来关于宏基因组组装工具Megahit的超详细安装及应用教程. 我 ...

  3. 「软件项目管理」一文详解软件配置管理计划

    一文详解软件配置管理计划 前言 一.配置管理概述 1. 配置管理(SCM)定义 2. 软件配置项目(SCI) 3. 基线 4. 软件配置控制委员会(SCCB) 二.软件配置管理过程 1. 管理过程 2 ...

  4. 一文详解Pandas

    一文详解Pandas 一.Pandas概述 二.Pandas数据结构 2.1 Series 2.2 DataFrame数据结构 二.数学与统计计算 三.DataFrame的文件操作 3.1 读取文件 ...

  5. 一文详解编程中的随机数

    一文详解编程中的随机数 随机数的类型 真随机数生成器 TRNG - True Random Number Generator 伪随机数生成器 PRNG - Pseudo Random Number G ...

  6. 一文详解 ChatGPT:背后的技术,数据,未来发展

    文章目录 一文详解 ChatGPT ChatGPT背后的技术 基于 Transformer 的预训练语言模型 提示学习与指令精调 思维链(Chain of Thought,COT) 基于人类反馈的强化 ...

  7. 云服务器CentOS8.2安装部署Docker一文详解

    目录 前言 一.Docker简介 二.安装部署以及测试Docker 1.安装Docker 1.1查看系统版本 1.2移除旧依赖 1.3安装方法 1.4设置存储库 ​编辑 1.5安装Docker引擎 1 ...

  8. 一文详解VarScan肿瘤体细胞突变检测的的安装和实践

    ​目录 VarScan 简介 VarScan 安装和使用说明:安装.说明.配置.运行 VarScan 案例实战:数据下载.配置.运行.输出 使用sixbox快速运行 hello,大家好,今天为大家带来 ...

  9. Pandas获取SQL数据库read_sql()函数及参数一文详解+实例代码

    前言 Pandas常用作数据分析工具库以及利用其自带的DataFrame数据类型做一些灵活的数据转换.计算.运算等复杂操作,但都是建立在我们获取数据源的数据之后.因此作为读取数据源信息的接口函数必然拥 ...

最新文章

  1. Java List 更换指定位置的元素
  2. data pump工具
  3. 深度丨全球14家顶尖 AI 产业巨头深度学习实力及战略分析
  4. 软件测试师具备的素质_软件测试工程师有哪些需要具备的能力呢
  5. 【Transformer】Do Vision Transformers See Like Convolutional Neural Networks?
  6. keil3如何放大字体_Word技巧之快速放大字体!快来GET新技能!
  7. was控制台的用户和密码怎样加密使用_Python爬虫进阶 | X咕视频密码与指纹加密分析...
  8. Fragment懒加载预加载
  9. ajax中POST请求与参数(请求体)设置
  10. jQuery.获取子节点
  11. day14内置函数作业详解
  12. bugku 杂项 部分
  13. kindle paperwhite3 拆机越狱
  14. 机器学习——DBN深度信念网络详解
  15. EasyAR4.1平面识别
  16. Photoshop DPI缩放比例问题
  17. java 中国标准时间_JAVA 转Wed Oct 05 2016 00:00:00 GMT+0800 (中国标准时间)
  18. xp系统本地连接服务器,xp系统本地连接受限制或无连接怎么办丨xp本地连接断开无法上网解决办法...
  19. 根据指定的经纬度查询半径为5km的地点
  20. self的用法与意义(一)

热门文章

  1. vs生成解决方案出错
  2. linux下的rabbitmq安装与配置
  3. Docker安装Tomcat、MySQL和Redis
  4. 美团某程序员哀叹:能力很强,却因为不会“向上管理”而惨遭被裁!怎么办?...
  5. 由浅入深C A S,小白也能与BAT面试官对线
  6. 菜鸟实时数仓2.0进阶之路
  7. 面试造飞机系列:面对Redis持久化连环Call,你还顶得住吗?
  8. 银行选型和排坑实战:用开源软件自建分布式数据服务平台
  9. 闲鱼亿级商品结构化背后的思考和演进
  10. 推荐10个windows软件,让你的办公更高效