Protobuf报错CHECK failed: GeneratedDatabase()->Add(encoded_file_descriptor, size):

2023-05-16

前言

Protobuf全称Protocol buffers,是Google研发的一种跨语言、跨平台的序列化结构的数据格式,是一个灵活的、高效的用于序列化数据的协议。使用protobuf时,既可以采用动态链接,也可以采用静态链接。因为protobuf本身有一个globalregistry。每个message type都需要去那里注册一下,而且不能重复注册。所以,假如你在A.DLL中定义了某些message type,那么B.DLL就只能从A.DLL的exported的DLL interface中使用这些message type, 而不能从proto文件中重新生成C/C++代码并包含到B.DLL里去。并且B.DLL也不能私自的去修改、扩展这个message type。

最近在调用tensorRT解析onnx模型的时候使用到了这个库,遇到了一些折磨了很久的坑,记录一下。

目录

      • 前言
      • 1、运行时内存溢出
      • 2、编译时链接库报错
    • 关于`GCC`的编译选项`fpic`/`fPIC`, `fpie`/`fPIE`

1、运行时内存溢出

在代码运行时,出现以下错误

[libprotobuf ERROR google/protobuf/descriptor_database.cc:641] File already exists in database: ais_msg.proto
[libprotobuf FATAL google/protobuf/descriptor.cc:2021] CHECK failed: GeneratedDatabase()->Add(encoded_file_descriptor, size):
terminate called after throwing an instance of ‘google::protobuf::FatalException’
what(): CHECK failed: GeneratedDatabase()->Add(encoded_file_descriptor, size):

原因:

有人说是因为需要通信多个进程模块都集成了相同的 *.pb.cc*.pb.h 文件进行编译(动态库或者执行文件),且在编译时通过动态库 libprotobuf.so 的方式进行链接,导致在运行时报错,通过网上查找得到:**protobuf 本身有一个 global registry。每个 message type 都需要去那里注册一下,而且不能重复注册。上述的 Add 错误就是因为注册失败,原因就是因为这几个中重复注册了(多份 *.pb.cc 实现)。

PS:也有可能是protobuf的版本原因,我这里出现了这个错误之后,尝试了网上说的各种方法都没办法解决,后来把protobuf的版本从11.4.3换成6.1.3就没报这个错误了。

解决办法:静态库编译,使用 libprotobuf.a,即多个编译目标通过静态库的方式链接.

在编译protobuf的时候改 configure 文件再执行 configure

// 改成下面的样子(不同版本位置不对,所以可以搜索 ac_cv_env_CFLAGS_set)
if test "x${ac_cv_env_CFLAGS_set}" = "x"; then
 CFLAGS="-fPIC"
fi
 
if test "x${ac_cv_env_CXXFLAGS_set}" = "x"; then
  CXXFLAGS="-fPIC"
fi
$ ./configure --host=arm-linux --disable-shared CFLAGS="-fPIC -fvisibility=hidden" CXXFLAGS="-fPIC -fvisibility=hidden" --prefix=/home/auto/libSrc/protobuf-3.6.1_install
$ make -j;make install

参考:protobuf 的交叉编译使用

2、编译时链接库报错

image-20230204110551059

**原因:**报错中说我们的工程是一个动态库,但是链接的protobuf是一个静态库,将静态库编译为动态库时,会引起问题,请重新编译protobuf

**解决方法:**加上-fPIC选项重新编译protobuf库即可。

在编译protobuf的时候改 configure 文件再执行 configure

// 改成下面的样子(不同版本位置不对,所以可以搜索 ac_cv_env_CFLAGS_set)
if test "x${ac_cv_env_CFLAGS_set}" = "x"; then
 CFLAGS="-fPIC"
fi
 
if test "x${ac_cv_env_CXXFLAGS_set}" = "x"; then
  CXXFLAGS="-fPIC"
fi
$ ./configure --host=arm-linux --disable-shared CFLAGS="-fPIC -fvisibility=hidden" CXXFLAGS="-fPIC -fvisibility=hidden" --prefix=/home/auto/libSrc/protobuf-3.6.1_install
$ make -j;make install

关于GCC的编译选项fpic/fPIC, fpie/fPIE

fPIC 的全称是 Position Independent Code, 用于编译阶段,告诉编译器产生与位置无关代码,代码在被进程加载到内存时使用相对地址,所有对固定地址的访问都通过全局偏移表(GOT)来实现。

编译共享库时使用:

-fPIC: Generate position-independent code if possible (large mode)
-fpic: Generate position-independent code if possible (small mode)

编译可执行程序时使用:

-fPIE: Generate position-independent code for executables if possible (large mode)
-fpie: Generate position-independent code for executables if possible (small mode)

注:还需要在ld时增加-pie选项才能产生这种代码。即gcc -fpie -pie来编译程序。单独使用哪一个都无法达到效果。

-pie; Create a position independent executable

关于large modesmall mode的说明:small指程序必须位于2GB以下的地址空间;large指对地址空间没有任何限制。

在编译某个库的时候,加 fPIC 选项不加 fPIC 选项能否生成动态链接库没有必然的联系,即使不加 fPIC 也可以生成 .so 文件,只是对于那种库的源文件又调用了其他的地方的代码,而这个段代码在全局内存上只能有一个实例的时候,如果在多个进程中都调用了这个库那么会产生多个实例就发生了冲突,例如:Protobuf库。所以,我们在编译共享库的时候,一般都加上fPIC 编译选项,这样多个进程引用同一个 PIC 动态库时,可以共用内存。这一个库在不同进程中的虚拟地址不同,但操作系统显然会把它们映射到同一块物理内存上,这样就不会发生冲突。

对于对于不加 fPIC,则加载 .so 文件时,需要对代码段引用的数据对象需要重定位,重定位会修改代码段的内容,这就造成每个使用这个 .so 文件代码段的进程在内核里都会生成这个 .so 文件代码段的 copy。每个 copy 都不一样,取决于这个 .so 文件代码段和数据段内存映射的位置。可见,这种方式更消耗内存,但是通常来说它的加载速度会更快。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Protobuf报错CHECK failed: GeneratedDatabase()->Add(encoded_file_descriptor, size): 的相关文章

随机推荐

  • VINS 外参在线标定

    在VINS中相机的外参 R i c R ic R i c 是可以在线动态标定的 xff0c 实现函数为 xff1a 6
  • A-LOAM源码阅读

    LOAM 论文地址 xff1a https www ri cmu edu pub files 2014 7 Ji LidarMapping RSS2014 v8 pdf A LOAM地址 xff1a https github com HKU
  • LeGo-LOAM 跑通与源码学习

    论文链接 xff1a https www researchgate net LeGO LOAM 源码仓库 xff1a https github com RobustFieldAutonomyLab LeGO LOAM 本人注释 xff1a
  • SLAM中evo评估工具(用自己的数据集评估vinsFusion)

    目录 xff1a 配置标题文件修改源码修改第一处第二处第三处重新编译工程 安装evo1 安装命令2 常用指令 运行vinsFusion生成位姿估计文件使用evo评估轨迹 配置标题文件修改 主要根据自己的设备 xff0c 修改自己传感器的RO
  • Ubuntu中USB端口与外设绑定,ROS读取IMU模块数据

    目录 xff1a 1 根据设备ID绑定1 1 查看ID1 2 编写USB规则文件1 3 查看绑定结果 2 根据电脑USB口绑定2 1 找到USB端口名称2 2 编写绑定规则 3 通过ROS读数据 1 根据设备ID绑定 方法原理 xff1a
  • 实现外网Ping通WSL(网卡桥接方式实现)

    目录 xff1a 前言 xff1a 实现原理 xff1a 实现步骤1 开启hyper v2 编写桥接网络powershell脚本3 编写网络配置脚本 实现结果取消桥接最后 前言 xff1a 在我们经常和机器人打交道的这群人中有一个需求 xf
  • 如何在markdown中插入表情包

    我们平时经常使用markdown完成一些诸如博客的文档写作 xff0c 但是有时像我这种语言比较乏力的急需要在文档写作过程中插入表情包来完整的表达我想要表达的意思 xff0c 所以我去网上查了一下 xff0c 还真有 比如我想要表达开心即s
  • ROS多设备组网(WSL+miniPC+Nv Orin)

    目录 xff1a 前言硬件连接组网配置1 获取hostname和IP2 在主机添加从机的host信息3 在从机1中配置4 在从机2中配置 测试test1 话题订阅test2 rqt plot可视化传感器信息 最后 前言 实验室最近购买了两台
  • ZED 2i 双目-IMU标定

    目录 xff1a 前言IMU标定1 编译标定工具2 准备数据集3 标定 Camera IMU标定1 安装依赖2 编译Kaibr3 制作标定板下载标定板生成标定板target yaml文件 4 数据采集5 相机标定标定中遇到的问题问题1 xf
  • gazebo中给机器人添加16线激光雷达跑LIO-SAM

    目录 xff1a 前言1 下载雷达仿真包2 添加雷达支架描述文件3 添加雷达描述文件4 启动仿真5 添加IMU模块6 添加RGB D相机7 LIO SAM仿真安装依赖安装GTSAM编译LIO SAM运行 8 源码 遇到的问题1 error
  • ROS中的多线程使用

    目录 xff1a 单线程多线程订阅多个Topic xff0c 多个Spinner threads订阅一个Topic xff0c 多个Spinner threads订阅多个Topic xff0c 每个Subscriber一个Callback
  • 机器人端的图形界面ssh远程显示方案

    目录 xff1a 前言原理解析实现步骤机器人端 xff08 X client xff09 xff1a 1 安装一些必要的软件2 修改 96 etc ssh sshd config 96 中的四个地方 调试端 xff08 X server x
  • 报错 Key is stored in legacy trusted.gpg keyring

    目录 xff1a 1 找到警告相关源的key2 导出相应key到指定目录3 修改ros2源里指定加载key的路径 最近在安装ROS2的时候遇到一个关于密钥的报错 xff0c 这里记录一下 xff01 在 sudo apt update 的时
  • wsl中使用ROS工具rqt显示界面跑到窗口外面

    问题 xff1a 在WSL中使用ROS时确实会有一些小bug xff0c 比如下面这个 的rqt plot功能包时 xff0c 想通过rqt plot指令查看相应信息 xff0c 但是窗口弹出在窗口是空白的 xff0c 并且rqt那个功能界
  • RS雷达转Velodyne雷达数据Failed to find match for field ‘intensity‘

    目录 xff1a 问题分析解决 问题 因为目前很多SLAM框架支持的激光雷达都是Velodyne型号的 xff0c 对于速腾RS雷达的使用者来说 xff0c 需要对数据进行转换 xff0c 其实现在速腾的雷达已经支持输出XYZI和XYZIR
  • LIO-SAM中的mapOptmization

    前言 最近在学习LIO SAM源码的时候 xff0c 发现LIO SAM这套代码调用了比较多库的内置API xff0c 里面涉及的一些细节也比较多 xff0c 整个工程还是比较清晰的 xff0c 值得学习 xff01 LIO SAM这个框架
  • 使用D435i+Avia跑Fast-LIVO

    前言 最近Fast LIVO开源了 xff0c 之前看它的论文的时候发现效果很优秀 xff0c 于是用实验室现有的设备尝试一下 这里主要记录一下使用不带外触发功能的D435i 43 Avia跑Fast LIVO的过程 xff0c 为了适配代
  • CMakeList 中引用系统环境变量中的 include 文件,以及 lib 文件

    CMakeList 中引用系统环境变量中的 include 文件 xff0c 以及 lib 文件 cmake中对环境变量读写都是通过ENV前缀来访问环境变量 ENV ZLIB DIR 表示系统环境变量ZLIB DIR 所表示的路径 以ZLI
  • GroundTrue和里程计输出的位姿的参考坐标系不一致的情况

    这里写目录标题 前言数据集描述使用TF工具包获取使用Eigen库计算置换输出误差对比没做转换之前转换之后 前言 最近遇到一个数据集的ground true参考坐标和vSLAM输出的位姿的参考坐标不一样的问题 xff0c 记录一下 在之前参加
  • Protobuf报错CHECK failed: GeneratedDatabase()->Add(encoded_file_descriptor, size):

    前言 Protobuf全称Protocol buffers xff0c 是Google研发的一种跨语言 跨平台的序列化结构的数据格式 xff0c 是一个灵活的 高效的用于序列化数据的协议 使用protobuf时 xff0c 既可以采用动态链