【关于CMake、CMakeLists.txt】相关知识与ORB_SLAM3-ROS-CMakeLists注释

文章目录

  • 前言
  • 一、C/C++程序的GCC编译过程
    • 1. 预处理
    • 2. 编译
    • 3. 汇编
    • 4. 链接
    • 5. 总述
  • 二、GCC优化级别
  • 三、GDB常用指令
  • 四、CMake组织编译文件
  • 五、CMake编译安装的一般流程
  • 六、CMakeLists.txt语法规则汇总
  • 七、ORBSLAM3-ROS-CMakeLists.txt 文件详解
    • 补充
  • 总结
  • Reference


前言

填自己的知识深渊。

一切皆变量,CPU 访问内存时需要的是地址,而不是变量名和函数名!
变量名和函数名只是地址的一种助记符,当源文件被编译和链接成可执行程序后,它们都会被替换成地址。
编译和链接过程的一项重要任务就是找到这些名称所对应的地址。


一、C/C++程序的GCC编译过程

通常分为四个阶段:预处理、编译、汇编、链接,最终生成可执行程序。

1. 预处理

调用cpp对源码进行预处理,对其中的包含(include)、预编译语句(宏定义等)进行分析,根据这些预处理指令修改源文件,生成.i文件。

C/C++提供的预处理指令主要有:
文件包含(include)、
宏定义(macro)、
条件编译等。

C/C++预处理器只做宏替换和文本替换

C/C++预处理是不会做任何语法检查的,不仅是因为它不具备语法检查功能,也因为预处理命令不属于C/C++语句(这也是定义宏时不要加分号的原因),语法检查是编译器的工作。

通过预处理之后,我们得到的是也仅仅是真正的源代码

2. 编译

调用ccl进行编译,通过词法分析和语法分析,在确认所有的指令都符合语法规则之后,将其翻译成等价的中间代码表示或汇编代码,生成.s文件。

3. 汇编

调用as进行汇编,把汇编语言代码翻译成目标机器指令,生成.o文件。

4. 链接

将有关的目标文件彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够诶操作系统装入执行的统一整体。

5. 总述

【关于CMake、CMakeLists.txt】相关知识与ORB_SLAM3-ROS-CMakeLists注释_第1张图片
上图可得:
预编译:将.cpp文件转化成.i文件,使用的gcc命令是:gcc –E,对应于预处理命令cpp

编译:将.cpp/.h文件转换成.s文件,使用的gcc命令是:gcc –S,对应于编译命令cc –S

汇编:将.s文件转化成.o文件,使用的gcc 命令是:gcc –c,对应于汇编命令是as

链接:将.o文件转化成可执行程序,使用的gcc 命令是:gcc,对应于链接命令是ld


二、GCC优化级别

GCC中指定优化级别的参数有:-O0、-O1、-O2、-O3、-Og、-Os、-Ofast。

-Ox这个参数只有在CMake -DCMAKE_BUILD_TYPE=release时有效,因为debug版的项目生成的可执行文件需要有调试信息并且不需要进行优化,而release版的不需要调试信息但需要优化。

说明:
1)在编译时,如果没有指定上面的任何优化参数,则默认为 -O0,即没有优化。

2)参数 -O1、-O2、-O3 中,随着数字变大,代码的优化程度也越高,不过这在某种意义上来说,也是以牺牲程序的可调试性为代价的。

3)参数 -Og 是在 -O1 的基础上,去掉了那些影响调试的优化,所以如果最终是为了调试程序,可以使用这个参数。不过光有这个参数也是不行的,这个参数只是告诉编译器,编译后的代码不要影响调试,但调试信息的生成还是靠 -g 参数的。

4)参数 -Os 是在 -O2 的基础上,去掉了那些会导致最终可执行程序增大的优化,如果想要更小的可执行程序,可选择这个参数。

5)参数 -Ofast 是在 -O3 的基础上,添加了一些非常规优化,这些优化是通过打破一些国际标准(比如一些数学函数的实现标准)来实现的,所以一般不推荐使用该参数

【关于CMake、CMakeLists.txt】相关知识与ORB_SLAM3-ROS-CMakeLists注释_第2张图片
【关于CMake、CMakeLists.txt】相关知识与ORB_SLAM3-ROS-CMakeLists注释_第3张图片


三、GDB常用指令

【关于CMake、CMakeLists.txt】相关知识与ORB_SLAM3-ROS-CMakeLists注释_第4张图片


四、CMake组织编译文件

CMake处理文件之间的关系,是跨平台编译工具,主要编写 CMakeLists.txt 文件,用 cmake 命令将 CMakeLists.txt 文件转化为 make 所需要的Makefiles 文件,然后调用g++来编译程序。
CMakefiles.txt 和用来生成 Makefiles 的文件是一致的,用 make 命令编译源码生成可执行程序或共享库。

gcc 一次编译一个源代码文件
make 一次编译多个源代码文件

cmake 根据 CmakeLists.txt文件生成的makefile
make调用makefile文件中的指令进行编译和链接

【关于CMake、CMakeLists.txt】相关知识与ORB_SLAM3-ROS-CMakeLists注释_第5张图片


五、CMake编译安装的一般流程

cmake -D CMAKE_BUILD_TYPE=RELEASE \ -D CMAKE_INSTALL_PREFIX=/usr/local ..

-D相当于是宏定义, 实际上是给编译器 gcc 传入参数,可以理解为告诉CMake后续要定义一些参数,每定义一个参数就在前边加上"-D"。

CMAKE_BUILD_TYPE 往往是在CMakeList.txt中定义的,代表要编译的类型,如果你要对编译的程序进行调试,就需要设置CMAKE_BUILD_TYP=debug;如果你要对编译的程序只是运行追求性能,要设置CMAKE_BUILD_TYP=release

CMAKE_INSTALL_PREFIX是指定编译好的程序安装的路径,如果不指定的就是默认的安装路径,指定可以安装在任意位置,一般软件多版本切换的时候会用到。

CMAKE_PREFIX_PATH是要编译的文件所在的安装路径。

“…” 表示上层目录,意思是CMakeList.txt文件在编译路径的上一层。

根据CMakeLists.txt文件找到make以及make install所依赖的文件生成Makefile文件。

make
Makefile中读取指令,然后编译源码生成静态库、动态库、可执行程序等。

sudo make install
Makefile中读取指令,将编译好的可执行程序以及文档复制安装到指定的位置


六、CMakeLists.txt语法规则汇总

//声明要求的cmake最低版本,终端输入cmake -version可查看cmake的版本
cmake_minimum_required( VERSION 2.8 )

//声明cmake工程名字
project(slam)

//设置使用g++编译器,这是添加变量的用法set(KEY VALUE)接收两个参数,用来声明变量。在camke语法中使用${KEY}这种写法来取到VALUE
set( CMAKE_CXX_COMPILER "g++")

//设置cmake编译模式有debug和release两种PROJECT_SOURCE_DIR项目根目录也就是是CmakeLists.txt的绝对路径
set( CMAKE_BUILD_TYPE "Release" )

//设定生成的可执行二进制文件存放的存放目录
set( EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

//设定生成的库文件的存放目录
set( LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

//参数CMAKE_CXX_FLAGS含义是: set compiler for c++ language
//添加c++11标准支持,*.CPP文件编译选项,-march=native指定目标程序的cpu架构来进行程序优化
//native就是相当于自检测cpu,-march是gcc优化选项,后面的-O3是用来调节编译时的优化程度的,最高为-O3,最低为-O0即不做优化
//-Ox这个参数只有在CMake -DCMAKE_BUILD_TYPE=release时有效
//因为debug版的项目生成的可执行文件需要有调试信息并且不需要进行优化,而release版的不需要调试信息但需要优化
set( CMAKE_CXX_FLAGS “-std=c++11 -march=native -O3”)

//调试手段message打印信息,类似于echo/printf,主要用于查cmake文件的语法错误
set(use_test ${SOURCES_DIRECTORY}/user_accounts.cpp)
message("use_test : ${use_test}")

//在CMakeLists.txt中指定安装位置, 在编译终端指定安装位置:cmake -DCMAKE_INSTALL_PREFIX=/usr ..
set(CMAKE_INSTALL_PREFIX < install_path >)

//增加子文件夹,也就是进入源代码文件夹继续构建
add_subdirectory(${PROJECT_SOURCE_DIR}/src)

//添加依赖,去寻找该库的头文件位置、库文件位置以及库文件名称,并将其设为变量,返回提供给CMakeLists.txt其他部分使用。
//cmake_modules.cmake文件是把CMakeLists.txt里用来寻找特定库的内容分离出来,如果提示没有找到第三方依赖库可以尝试安装或者暴力指定路径
// 寻找OpenCV库
find_package( OpenCV REQUIRED )

// **在CMakeLists.txt中使用第三方库的三部曲:find_package、include_directories、target_link_libraries
include_directories(${OpenCV_INCLUDE_DIRS})// 去哪里找头文件
link_directories()// 去哪里找库文件(.so/.lib/.ddl等)
target_link_libraries( ${OpenCV_LIBRARIES})// 需要链接的库文件
message("OpenCV_INCLUDE_DIRS: \n" ${OpenCV_INCLUDE_DIRS})
message("OpenCV_LIBS: \n" ${OpenCV_LIBS})

// find_package(Eigen3 REQUIRED), 假如找不到Eigen3库,我们就设置变量来指定Eigen3的头文件位置
set(Eigen3_DIR /usr/lib/cmake/eigen3/Eigen3Config.cmake)
include_directories(/usr/local/include/eigen3)

// include 指令用来载入并运行来自于文件或模块的 CMake 代码
include()

七、ORBSLAM3-ROS-CMakeLists.txt 文件详解

cmake_minimum_required(VERSION 2.4.6)					// 声明要求的cmake最低版本为2.4.6
include($ENV{ROS_ROOT}/core/rosbuild/rosbuild.cmake)	// 用来载入并运行来自于文件或模块的 CMake 代码

rosbuild_init()											// 初始化

IF(NOT ROS_BUILD_TYPE)									// 如果没有设定编译类型,则设置为Release
  SET(ROS_BUILD_TYPE Release)
ENDIF()

MESSAGE("Build type: " ${ROS_BUILD_TYPE})				// 打印信息,类似于echo/printf

// 参数CMAKE_CXX_FLAGS含义是: set compiler for c++ language,建立c++编译器
// -Wall:允许发出Gcc提供的所有有用的报警信息
// -O3优化级别
// native就是相当于自检测cpu,-march是gcc优化选项,即指定使用目标程序gcc的cpu架构来进行程序优化
// -Ox这个参数只有在CMake -DCMAKE_BUILD_TYPE=release时有效
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}  -Wall  -O3 -march=native ")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall  -O3 -march=native")

# Check C++11 or C++0x support	判断编译器是否支持C++11
include(CheckCXXCompilerFlag)							// include 指令用来载入并运行来自于文件或模块的 CMake 代码
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)		// 判断编译器是否支持C++11的标志
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")				// 添加`c++11`标准支持
   add_definitions(-DCOMPILEDWITHC11)								// -D 定义标志添加到源文件的编译中,将定义添加到当前目录及以下目录中的源的编译器命令行
   message(STATUS "Using flag -std=c++11.")							// 打印信息
elseif(COMPILER_SUPPORTS_CXX0X)
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
   add_definitions(-DCOMPILEDWITHC0X)
   message(STATUS "Using flag -std=c++0x.")
else()
   message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()

// Cmake 中定义了一系列的数组操作,使用方法如下
// LIST追加或者删除变量的值,此处是追加CMAKE_MODULE_PATH的值,CMAKE_MODULE_PATH的值是地址
// ${PROJECT_SOURCE_DIR}:项目源文件夹/根目录,为包含PROJECT()的最近一个CMakeLists.txt文件所在的路径。
LIST(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../../../cmake_modules)

// 查找opencv
find_package(OpenCV 3.0 QUIET)
if(NOT OpenCV_FOUND)
   find_package(OpenCV 2.4.3 QUIET)
   if(NOT OpenCV_FOUND)
      message(FATAL_ERROR "OpenCV > 2.4.3 not found.")
   endif()
endif()

find_package(Eigen3 3.1.0 REQUIRED)		// 查找Eigen3
find_package(Pangolin REQUIRED)			// 查找Pangolin

include_directories(					// 所包含(include)头文件的目录
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/../../../
${PROJECT_SOURCE_DIR}/../../../include
${PROJECT_SOURCE_DIR}/../../../include/CameraModels
${Pangolin_INCLUDE_DIRS}
)

set(LIBS 								// 设置依赖库的路径
${OpenCV_LIBS} 
${EIGEN3_LIBS}
${Pangolin_LIBRARIES}
${PROJECT_SOURCE_DIR}/../../../Thirdparty/DBoW2/lib/libDBoW2.so
${PROJECT_SOURCE_DIR}/../../../Thirdparty/g2o/lib/libg2o.so
${PROJECT_SOURCE_DIR}/../../../lib/libORB_SLAM3.so
-lboost_system							// -l 的作用是做链接,链接的库是“boost_system”
)

# Node for monocular camera
rosbuild_add_executable(Mono			// 生成可执行文件
src/ros_mono.cc
)

target_link_libraries(Mono				// 库路径
${LIBS}
)

# Node for monocular camera (Augmented Reality Demo)
rosbuild_add_executable(MonoAR			// 生成可执行文件
src/AR/ros_mono_ar.cc
src/AR/ViewerAR.h
src/AR/ViewerAR.cc
)

target_link_libraries(MonoAR			// 库路径
${LIBS}
)

# Node for stereo camera
rosbuild_add_executable(Stereo
src/ros_stereo.cc
)

target_link_libraries(Stereo
${LIBS}
)

# Node for RGB-D camera
rosbuild_add_executable(RGBD
src/ros_rgbd.cc
)

target_link_libraries(RGBD
${LIBS}
)

# Node for monocular-inertial camera
rosbuild_add_executable(Mono_Inertial
src/ros_mono_inertial.cc
)

target_link_libraries(Mono_Inertial
${LIBS}
)

# Node for stereo-inertial camera
rosbuild_add_executable(Stereo_Inertial
src/ros_stereo_inertial.cc
)

target_link_libraries(Stereo_Inertial
${LIBS}
)

补充

  1. add_definitions()
    【关于CMake、CMakeLists.txt】相关知识与ORB_SLAM3-ROS-CMakeLists注释_第6张图片
  2. find_package()
find_package(<package> [version] [EXACT] [QUIET]
               [[REQUIRED|COMPONENTS] [components...]]
               [NO_POLICY_SCOPE])

查找并加载外来工程的设置。


总结

最近cmake遇到了点困难,直接重温了一下cmake和cmakelists文件的编写。

然后许多知识点都是来自于“小秋SLAM代码实战笔记”,赞一波dalao。


Reference

  1. https://blog.csdn.net/qq_21950671/article/details/94456864(小秋,全)
  2. https://blog.csdn.net/yimingsilence/article/details/52800987(编译过程)
  3. https://www.bilibili.com/video/BV1fy4y1b7TC?from=search&seid=10822750881263437190&spm_id_from=333.337.0.0(B站视频)
  4. http://blog.sina.com.cn/s/blog_628cc2b70102yqwj.html(CMakeLists指令)
  5. https://blog.csdn.net/wyyang2/article/details/104770144(CMAKE_PREFIX_PATH)
  6. https://www.cnblogs.com/coderfenghc/archive/2012/07/15/2592758.html(cmake find_package)

你可能感兴趣的:(ORBSLAM3,自动驾驶,c++,c语言)