ORB-SLAM2在window下的配置 (6)

来源:互联网 发布:mac air搜狗输入法 编辑:程序博客网 时间:2024/06/04 18:13

配置g2o


终于到了配置ORB-SLAM2依赖的最后一个库,g2o配置起来麻烦特别多,也不知为什么,蜜汁问题一大堆,之前在window配过一次ORB-SLAM2,就g2o这个库花了我最多时间,问题一个解决又来一个,但因为没即时记录问题和解决方案,后来忘记了怎么搞的了,这也是让我想要写这一系列博客的原因。

废话不多说。g2o的源码可以从ORB-SLAM2的源码中抽取:https://github.com/raulmur/ORB_SLAM2

首先其根目录下建立build文件夹,使用CMake对其配置,选择vs2017 win64的编译器。

点击Configure按钮,不出意外,应该会出现配置错误,原因是CMake找不到eigen3的库。我们压根不想让CMake去找它,所以我们在CMakeList.txt中,删除以下代码:

# Find Eigen3SET(EIGEN3_INCLUDE_DIR ${G2O_EIGEN3_INCLUDE})FIND_PACKAGE(Eigen3 3.1.0 REQUIRED)IF(EIGEN3_FOUND)  SET(G2O_EIGEN3_INCLUDE ${EIGEN3_INCLUDE_DIR} CACHE PATH "Directory of Eigen3")ELSE(EIGEN3_FOUND)  SET(G2O_EIGEN3_INCLUDE "" CACHE PATH "Directory of Eigen3")ENDIF(EIGEN3_FOUND)

再次点击Configure,这一次配置没多大问题了,中间编译选项可以保持默认,点击Generate,生成vs工程。

注意到,编译选项中有一个使用OpenMP,不知是否需要其他的依赖库,我们暂时先不管。(但使用它或许会使程序更快)

现在打开vs工程,并为其添加在上一篇文章中,制作好了的Eigen3属性表将编译模式设置为Release x64,点击开始编译。此时出现第一个蜜汁问题:cl : 命令行 error D8004: “/W”需要参数。

这个问题不是我们的事,是CMake干的,右键项目->属性->C++->命令行,将“-W”删除(后面那些也可以删掉,不过留着无大碍)。但是记得在之前版本的vs配置时,倒是没这个问题。

OK,再次点击编译,vs进入漫长的编译过程。漫长,是因为Eigen3的模版展开导致的,这也导致了另外一个蜜汁问题:C1001 编译器发生内部错误。

查了官方手册资料,说是优化问题,但我把优化各种关闭都无济于事。最后发现只要把问题代码作如下修改就好了:将matrix_operations.h的49行、67行对应的axpy函数的签名,从axpy(..)改成axpy<Eigen::MatrixXd>(..)。这样做的道理跟vs的提示是一致的,即简化代码,但我当时怎么发现这一点的,现在也记不得了。

点击编译,这时触发下一个蜜汁问题的时间更长了,甚至vs呈现假死的情况。好吧有时候确实实在没耐心就强退,这一次我要观察一下是啥导致了这个问题。我将下方编译的输出栏拉高一点,看更多信息,并将输出内容由“生成”改为“生成顺序”。

好吧,这一次瞬间就完成了,提示两个错误:
1. “max”不是std的成员;
2. “vasprintf”未定义的标识符。

先说第一个错误,这个还比较容易解决,直接在问题文件optimization_algorithm_factory.cpp前面加一条语句#include <algorithm>就好了。

第二个错误,我们跳转到问题语句,对vasprintf函数右键转向定义,竟然可以跳转,但跳过去后就会发现,它的声明和定义均位于非活动预处理器块中,被选项WINDOWS关闭了。知道原因,解决方法自然明朗:右键项目->属性->C++->预处理器->预处理器定义,为其添加一个变量,WINDOWS,保存设定之后,这个错误也就消失了。

再次编译,这次的时间更长了,然后再次卡死,其实vs是已经发现了错误,而陷入中断编译的这个痛苦的过程中。等了好久,无奈又把vs强退重启,再次编译发现居然秒成功了?!害怕会不会缺胳膊少腿,我右键项目让它重新生成看看,这一次顺利结束了,生成了g2o.dll,但是,只有36K?!仔细一看,.lib文件也没有。g2o不是一个纯模版的库,这意味着需要有.lib为其定义实现的API,而这一次生成没有.lib表明根本就没有把API铺设出来。

当下有个解决方案,就是手动地为每个包含声明实现分离的类、结构体,加上API宣言(有没有一键添加的啊),正好可以利用g2o的config.h来放一些东西:

#ifdef G2O_EXPORTS#define G2O_API __declspec(dllexport)#else#define G2O_API __declspec(dllimport)#endif

记得,加的位置要在ifndef-endif的范围内。另外,vs工程中一开始没有包括这个头文件,只要右键项目->添加现有项,在g2o根目录下找到config.h并添加就好了。

接下来,我们要在所有的非模版的实现声明分开的类、结构体,加上G2O_API,具体的做法是,如:class A -> class G2O_API A, struct B -> struct G2O_API B,当然,如果有函数和变量需要导出也需要加的,如:extern int a; -> G2O_API extern int a; void fun(); -> G2O_API void fun();

注意到,G2O_API的值由开关G2O_EXPORTS决定,我们需要的是export的值,因此需要为g2o工程添加该开关定义:右键项目->属性->C++->预处理器->预处理器定义,添加G2O_EXPORTS.

现在开始添加。一直强调的非模版的实现声明分开的类、结构体具体是什么呢?记住一点就好了,我们就给位于没有对应的.hpp且有对应的.cpp的.h文件中的类和结构体加。另外,注意给这个.h文件补上include "../../config.h".

是不是累得够呛?赶紧编译一下。如果卡死出错,应该就是忘加了config.h语句导致的,编译成功了,先生成了.lib,也别高兴得太早,我们将g2o的库部署到XXX/g2o下,为其建立一个属性表,并建立一个新的vs工程测试一下。记得,有dll的也要拷贝过去,头文件可以从g2o根目录下的g2o文件夹拷贝过去,至于要不要删掉里边的.cpp文件,就看各位兴趣了。记得,连同g2o根目录下的config.h也要拷贝过去。

配置好属性表后,将编译模式调为Release x64,配置环境可以右键项目->属性->调试->环境,将其内容改为:path=XXX/g2o/lib/;$(Path);
注意路径需要使用斜杠‘/’,并且以斜杠结尾,‘=’前后不要有空格,多个路径用冒号隔开,最后的$(Path)代表系统环境,不加则不会使用系统环境。

使用以下代码进行测试:

#include <g2o/types/types_seven_dof_expmap.h>int main(){    g2o::VertexSim3Expmap v;    return 0;}

编译一下看看,到了这里,我这边已经没啥问题了。终于可以进入最后的大整合阶段。

原创粉丝点击