小言_互联网的博客

视觉SLAM笔记(5) 编程基础

218人阅读  评论(0)

视觉SLAM笔记(5) 编程基础


1. 操作系统

程序将主要以 Linux 上的 C++ 程序为主
会以 Ubuntu 16.04 为例,且主要使用 Ubuntu 下的命令


2. Hello SLAM

从最基本的程序开始
在 C++ 编程时,用编译器,把一个文本文件编译成可执行程序

例如:
创建 VSLAM_note/005/helloSLAM.cpp

#include <iostream>
using namespace std; 

int main( int argc, char** argv )
{
    cout<<"Hello SLAM!"<<endl;
    return 0;
}

这个程序只是把一个字符串输出到屏幕上而已
现在可以用文本编辑器 gedit 输入这些代码,并保存在上面列出的路径下

现在,用编译器 g++ (g++ 是一个 C++ 编译器)把它编译成一个可执行文件
输入:

$ g++ helloSLAM.cpp

刚才这条编译命令把 helloSLAM.cpp 这个文本文件编译成了一个可执行程序
检查当前目录,会发现多了一个 a.out 文件,而且它具有执行权限
运行此程序很简单:

$ ./a.out


这个程序输出“Hello SLAM!”,它在正确运行

在这个例子中,用编辑器输入了 helloSLAM.cpp 的源代码,然后调用 g++ 编译器对它进行编译,得到了可执行文件
g++ 默认把源文件编译成 a.out 这个名字的程序
这是一个极其简单的例子,使用了大量的默认参数,几乎省略了所有中间步骤,是为了有一个简洁的印象


3. cmake

理论上说,任意一个 C++ 程序都可以用 g++ 来编译
但当程序规模越来越大时,一个工程可能有许多个文件夹和里边的源文件
这时输入的编译命令将越来越长
通常一个小型 c++ 项目含有十几个类,各类间还存在着复杂的依赖关系
其中一部分要编译成可执行文件,另一部分编译成库文件
如果仅靠 g++ 命令,需要输入大量的编译指令,整个编译过程会变得异常繁琐

因此,对于 C++ 项目,使用一些工程管理工具会更加高效
在历史上工程师们曾使用 makefile 进行自动编译,但下面要谈的 cmake 比它更加方便
并且,会看到后面提到的大多数库都使用 cmake 来管理源代码

在一个 cmake 工程中,会用 cmake 命令生成一个 makefile 文件
然后用 make 命令,根据这个 makefile 文件的内容,编译整个工程

仍然以 helloSLAM.cpp 为例,这次不是直接使用 g++,而是用 cmake 来制作一个工程,然后再编译它
VSLAM_note/005/ 中新建一个 CMakeLists.txt 文件,输入:

# 声明要求的 cmake 最低版本
cmake_minimum_required( VERSION 2.8 )

# 声明一个 cmake 工程
project( HelloSLAM )

# 添加一个可执行程序
# 语法:add_executable( 程序名 源代码文件 )
add_executable( helloSLAM helloSLAM.cpp )

告诉 cmake 要对这个目录下的文件做什么事情
这个示例中,演示了最基本的工程:指定一个工程名和一个可执行程序

现在,在当前目录下,调用 cmake 对该工程进行分析

$ cmake .

cmake 会输出一些编译器等信息,然后在当前目录下生成一些中间文件,其中最重要的就是 MakeFile
由于 MakeFile 是自动生成的,不必修改它
现在,用 make 命令对工程进行编译:

$ make


编译过程中会输出一个编译进度
如果顺利通过,就得到在 CMakeLists.txt 声明的那个可执行程序 helloSLAM
执行它:

$ ./helloSLAM


因为并没有修改源代码,得到的结果和之前是一样的

但这种做法和之前直接使用 g++ 编译有着较大的区别
这次用 cmake-make 的做法, cmake 过程处理了工程文件之间的关系,而 make 过程实际调用了 g++ 来编译程序
虽然这个过程中多了调用cmake 和 make 的步骤
但对项目的编译管理工作,从输入一串 g++ 命令,变成了维护若干个比较直观的 CMakeLists.txt 文件
这将明显降低维护整个工程的难度

比如,想新增一个可执行文件时
只需在 CMakeLists.txt 中添加一行add_executable命令即可,而后续的步骤都是不变的
cmake 会解决代码的依赖关系,无需输入一大串 g++ 命令

现在这个过程中,唯一让不满的是, cmake 生成的中间文件还留在代码文件当中
当想要发布代码时,并不希望把这些中间文件一同发布出去
这时还需把它们一个个删除,这十分的不便
一种更好的做法是让这些中间文件都放在一个中间目录中,在编译成功后,把这个中间目录删除即可
所以,更常见的编译 cmake 工程的做法就是这样:

$ mkdir build
$ cd build
$ cmake ..
$ make

新建了一个中间文件夹build,然后进入文件夹,再编译
这样, cmake 产生的中间文件就会生成在 build 文件夹中,与源代码分开
当发布源代码时,只要把 build 文件夹删掉即可


4. 库

在一个 C++ 工程中,并不是所有代码都会编译成可执行文件
只有带有 main 函数的文件才会生成可执行程序

而另一些代码,只想把它们打包成一个东西,供其他程序调用,这个东西叫做
一个库往往是许多算法、程序的集合,之后会接触到许多库
例如,OpenCV 库提供了许多计算机视觉相关的算法,而 Eigen 库提供了矩阵代数的计算
因此,要学习如何用 cmake 生成库,并且使用库中的函数

现在创建一个 libHelloSLAM.cpp 文件

#include <iostream>
using namespace std;

void printHello()
{
    cout<<"Hello SLAM"<<endl;
}

这个库提供了一个 printHello 函数,调用此函数将输出一个信息
但是它没有 main 函数,这意味着这个库中没有可执行文件

CMakeLists.txt 里添加:

# 添加一个库
add_library( hello libHelloSLAM.cpp )

使用 cmake 编译整个工程

$ cd build
$ cmake ..
$ make

这时,在 build 文件夹中会生成一个 libhello.a 文件,这就是得到的库

在 Linux 中,库文件分成两种:

  • 静态库,以.a 作为后缀名
  • 共享库,以.so 作为后缀名

所有库都是一些函数打包后的集合,差别在于:
静态库每次被调用都会生成一个副本,而共享库则只有一个副本,更省空间

如果想生成共享库而不是静态库,只需用:

# 添加共享库
add_library( hello_shared SHARED libHelloSLAM.cpp )

就可以编译成一个共享库。此时得到的文件是 libhello_shared.so

库文件是一个压缩包,里头带有编译好的二进制函数
不过,仅有.a 或.so 库文件的话,并不知道它里头的函数到底是什么,调用的形式又是什么样的
为了让别人(或者自己)使用这个库,需要提供一个头文件,说明这些库里都有些什么
因此,对于库的使用者, 只要拿到了头文件和库文件,就可以调用这个库

下面来写 libhello 的头文件libHelloSLAM.h

#ifndef LIBHELLOSLAM_H_
#define LIBHELLOSLAM_H_
// 上面的宏定义是为了防止重复引用这个头文件而引起的重定义错误

void printHello();

#endif

这样,根据这个文件和刚才编译得到的库文件,就可以使用这个函数了
下面写一个可执行程序 useHello.cpp,调用这个简单的函数:

#include "libHelloSLAM.h"

int main( int argc, char** argv )
{
    // 使用 libHelloSLAM.h 中的 printHello() 函数
    printHello();
    return 0;
}

然后,在 CMakeLists.txt 中添加一个可执行程序的生成命令,链接到刚才使用的库上

# 添加一个可执行程序
add_executable( useHello useHello.cpp )

# 将库文件链接到可执行程序上
target_link_libraries( useHello hello_shared )

通过这两句话, useHello 程序就能顺利使用 hello_shared 库中的代码了


参考:

《视觉SLAM十四讲》


相关推荐:

视觉SLAM笔记(4) SLAM的数学表述
视觉SLAM笔记(3) 视觉SLAM框架
视觉SLAM笔记(2) 相机
视觉SLAM笔记(1) 初识SLAM


谢谢!


转载:https://blog.csdn.net/qq_32618327/article/details/101022916
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场