对于源代码包,咱们只有编译才能在系统上运行。ios
在一个 C++ 工程中,并非全部代码都会编译成可执行文件。只有带有 main 函数的文件才会生成可执行程序。而另外一些代码,咱们只想把它们打包成一个东西,供其余程序调用。这个东西叫作库。 一个库每每是许多算法、程序的集合,咱们会在以后的练习中,接触到许多库。例如,OpenCV 库提供了许多计算机视觉相关的算法,而 Eigen 库提供了矩阵代数的计算。 Linux下的编译器有gcc、g++,随着源文件的增长,直接用gcc/g++命令的方式显得效率低下,人们开始用Makefile来进行编译。然而随着工程体量的增大,Makefile也不能知足需求,因而便出现了Cmake工具。CMake是对make工具的生成器,是更高层的工具,它简化了编译构建过程,可以管理大型项目,具备良好的扩展性。对于ROS这样大致量的平台来讲,就采用的是CMake,而且ROS对CMake进行了扩展,因而便有了Catkin编译系统。c++
咱们用编译器 g++ (g++ 是一个 C++ 编译器)把.cpp
文件编译成一个可执行文件 。算法
g++ helloSLAM.cpp
刚才这条编译命令把 helloSLAM.cpp 这个文本文件编译成了一个可执行程序。咱们检查当前目录,会发现多了一个 a.out 文件,并且它具备执行权限(终端里颜色不一样)。咱们输入./a.out 便可运行此程序编辑器
单个C++文件能够用g++来编译成一个可执行文件。可是一个大工程使用 cmake 来管理源代码 。函数
理论上说,任意一个 C++ 程序均可以用 g++ 来编译。但当程序规模愈来愈大时,一个工程可能有许多个文件夹和里边的源文件,这时输入的编译命令将愈来愈长。一般一个小型 c++ 项目含有十几个类,各种间还存在着复杂的依赖关系。 可能原文件中其中一部分要编译成可执行文件,另外一部分编译成库文件。 若是仅靠 g++ 命令,咱们须要输入大量的编译指令,整个编译过程会变得异常繁琐。工具
在一个 cmake 工程中,咱们会用 cmake 命令生成一个 makefle 文件,而后,用 make命令 ,根据这个 makefle 文件的内容,编译整个工程。 cmake 过程处理了工程文件之间的关系,而 make 过程实际调用了 g++ 来编译程序 。ui
cmake的操做对象其实是CMakeLists.txt 文件,所以须要开发者先编写一个CMakeLists.txt 文件CMakeLists.txt 文件告诉 cmake 咱们要对这个目录下的文件作什么事情。CMakeLists.txt 文件内容须要遵照 cmake 的语法。spa
好比:code
# 声明要求的 cmake 最低版本 cmake_minimum_required( VERSION 2.8 ) # 声明一个 cmake 工程 project( HelloSLAM ) # 添加一个可执行程序 # 语法: add_executable( 自定义程序名 源代码文件 ) add_executable( helloSLAM helloSLAM.cpp )
演示了最基本的工程:指定一个工程名和一个可执行程序(这也是如何使用cmake生成可执行文件的示例)。对象
过程:
在当前目录下 ,首先用cmake对该工程进行分析,再用make指令对工程进行编译。
第一步
cmake .
注意加这个.
说明要编译的源文件以及CMakeLists.txt 文件应当都在打当前目录下。
第二步:
make
cmake 会输出一些编译器等信息,而后在当前目录下生成一些中间文件,其中最重要的就是 MakeFile。MakeFile 是一个自动化编译的脚本,能够将它理解成一系统自动生成的编译指令。
效果:
cmake 过程处理了工程文件之间的关系,而 make 过程实际调用了 g++ 来编译程序。虽然这个过程当中多了调用cmake 和 make 的步骤,但咱们对项目的编译管理工做,从输入一串 g++ 命令,变成了维护若干个比较直观的 CMakeLists.txt 文件,这将明显下降维护整个工程的难度。好比,当我想新增一个可执行文件时,只需在 CMakeLists.txt 中添加一行“add_executable”命令便可,然后续的步骤都是不变的。 cmake 会帮咱们解决代码的依赖关系,无需咱们输入一大串 g++ 命令。
删除中间文件:
如今这个过程当中,惟一让咱们不满的是, cmake 生成的中间文件还留在咱们代码文件当中。当咱们想要发布代码时,并不但愿把这些中间文件一同发布出去。这时咱们还需把它们一个个删除,这十分的不便。一种更好的作法是让这些中间文件都放在一个中间目录中,在编译成功后,把这个中间目录删除便可。因此,更常见的编译 cmake 工程的作法就是这样 :
mkdir build cd build cmake .. make
咱们新建了一个中间文件夹“build”,而后进入 build 文件夹,经过 cmake .. 命令,对上一层文件夹,也就是代码所在的文件夹进行编译。这样, cmake 产生的中间文件就会生成在 build 文件夹中,与源代码分开。当咱们发布源代码时,只要把 build 文件夹删掉便可。 下次编译的时候再像这样新建。
只有带有 main 函数的文件才会生成可执行程序。而另外一些代码,咱们只想把它们打包成一个东西,供其余程序调用。这个东西叫作库。
一个库每每是许多算法、程序的集合(由不含main函数的源文件编译而成),咱们会在以后的练习中,接触到许多库。例如,OpenCV 库提供了许多计算机视觉相关的算法,而 Eigen 库提供了矩阵代数的计算。
好比对于一个libHelloSLAM.cpp 文件 。这个库提供了一个 printHello 函数,调用此函数将输出一个信息。可是它没有 main函数,这意味着这个库中没有可执行文件。
//这是一个库文件 #include <iostream> using namespace std; void printHello() { cout<<"Hello SLAM"<<endl; }
这个库提供了一个 printHello 函数,调用此函数将输出一个信息。可是它没有 main函数,这意味着这个库中没有可执行文件。为了libHelloSLAM.cpp
编译成库文件,咱们在 CMakeLists.txt 里加一句:
add_library( hello libHelloSLAM.cpp )
这条命令告诉 cmake,我想把这个文件编译成一个叫作“hello”的库。以后即可以使用 cmake 和make编译整个工程:
cd build cmake .. make
这时,在 build 文件夹中会生成一个 libhello.a 文件,这就是咱们获得的库(静态库),以.a 做为后缀名。
在 Linux 中,库文件分红静态库和共享库两种。静态库以.a 做为后缀名,共享库以.so结尾。全部库都是一些函数打包后的集合,差异在于静态库每次被调用都会生成一个副本,而共享库则只有一个副本,更省空间。若是咱们想生成共享库而不是静态库,只需用:
add_library( hello_shared SHARED libHelloSLAM.cpp )
就能够编译成一个共享库。此时获得的文件是 libhello_shared.so 了。
库文件是一个压缩包,里头带有编译好的二进制函数。不过,仅有.a 或.so 库文件的话,咱们并不知道它里头的函数究竟是什么,调用的形式又是什么样的。为了让别人(或者本身)使用这个库,咱们须要提供一个头文件,说明这些库里都有些什么。所以,对于库的使用者, 只要拿到了头文件和库文件,就能够调用这个库了。
编写一个库文件对应的头文件:
libHelloSLAM.h
#ifndef LIBHELLOSLAM_H_ #define LIBHELLOSLAM_H_ void printHello();// 对库文件中的函数进行声明,以让别人知道库文件里有什么 #endif
这样,根据这个文件和咱们刚才编译获得的库文件,就可使用这个函数了。下面我
们写一个可执行程序,调用这个简单的函数void printHello()
:
useHello.cpp
#include "libHelloSLAM.h" int main( int argc, char** argv ) { printHello(); return 0; }
而后,在 CMakeLists.txt 中添加一个可执行程序的生成命令,连接到刚才咱们使用的库上:
add_executable( useHello useHello.cpp ) //编译刚编写的可执行文件 target_link_libraries( useHello hello_shared )//将共享库连接到某个头文件
经过这两句话, useHello 程序就能顺利使用 hello_shared 库中的代码了。
对于他人提供的库,咱们也可用一样的方式对它们进行调用,整合到本身的程序中。
使用g++或者cmake本质是使用文本开发环境,即便用文本编辑器编辑代码,再对编辑好的代码进行编译等生成文件。除此以外,还可使用集成开发环境。