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

文章讲述了在使用Google的Protobuf库时遇到的两个主要问题:运行时内存溢出和编译时链接库报错。内存溢出问题源于protobuf全局registry的重复注册,解决办法是改为静态库编译。编译时链接库报错则是因为动态库与静态库的兼容性问题,通过添加-fPIC选项重新编译protobuf库可解决此问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

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、运行时内存溢出

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

[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 文件代码段和数据段内存映射的位置。可见,这种方式更消耗内存,但是通常来说它的加载速度会更快。

Using: /home/timi/PX4-Autopilot/Tools/simulation/gazebo-classic/sitl_gazebo-classic/models/iris/iris.sdf Warning [parser.cc:833] XML Attribute[version] in element[sdf] not defined in SDF, ignoring. gzserver: symbol lookup error: /home/timi/PX4-Autopilot/build/px4_sitl_default/build_gazebo-classic/libgazebo_mavlink_interface.so: undefined symbol: _ZN8mav_msgs4msgs17CommandMotorSpeedC1Ev SITL COMMAND: "/home/timi/PX4-Autopilot/build/px4_sitl_default/bin/px4" "/home/timi/PX4-Autopilot/build/px4_sitl_default"/etc ______ __ __ ___ | ___ \ \ \ / / / | | |_/ / \ V / / /| | | __/ / \ / /_| | | | / /^\ \ \___ | \_| \/ \/ |_/ px4 starting. INFO [px4] startup script: /bin/sh etc/init.d-posix/rcS 0 INFO [init] found model autostart file as SYS_AUTOSTART=10015 INFO [param] selected parameter default file parameters.bson INFO [param] selected parameter backup file parameters_backup.bson SYS_AUTOCONFIG: curr: 0 -> new: 1 SYS_AUTOSTART: curr: 0 -> new: 10015 CAL_ACC0_ID: curr: 0 -> new: 1310988 CAL_GYRO0_ID: curr: 0 -> new: 1310988 CAL_ACC1_ID: curr: 0 -> new: 1310996 CAL_GYRO1_ID: curr: 0 -> new: 1310996 CAL_ACC2_ID: curr: 0 -> new: 1311004 CAL_GYRO2_ID: curr: 0 -> new: 1311004 CAL_MAG0_ID: curr: 0 -> new: 197388 CAL_MAG0_PRIO: curr: -1 -> new: 50 CAL_MAG1_ID: curr: 0 -> new: 197644 CAL_MAG1_PRIO: curr: -1 -> new: 50 SENS_BOARD_X_OFF: curr: 0.0000 -> new: 0.0000 SENS_DPRES_OFF: curr: 0.0000 -> new: 0.0010 INFO [dataman] data manager file './dataman' size is 1208528 bytes Gazebo multi-robot simulator, version 11.15.1 Copyright (C) 2012 Open Source Robotics Foundation. Released under the Apache 2 License. http://gazebosim.org # # ####### ####### ### ##### ####### ## # # # # # # # # # # # # # # # # # # # # # # # # # ##### # # # # # # # # # # ## # # # # # # # # # ####### # ### ##### ####### This version of Gazebo, now called Gazebo classic, reaches end-of-life in January 2025. Users are highly encouraged to migrate to the new Gazebo using our migration guides (https://gazebosim.org/docs/latest/gazebo_classic_migration/) [Msg] Waiting for master. INFO [init] PX4_SIM_HOSTNAME: localhost INFO [simulator_mavlink] Waiting for simulator to accept connection on TCP port 4560 [Err] [ConnectionManager.cc:121] Failed to connect to master in 30 seconds. [Err] [gazebo_shared.cc:106] Unable to initialize transport. [Err] [gazebo_client.cc:56] Unable to setup Gazebo
最新发布
08-22
<think>我们正在解决PX4 SITL与Gazebo仿真环境启动失败的问题,特别是关于`undefined symbol`错误。根据错误信息,通常与库文件不匹配或编译环境问题有关。结合引用内容,以下为系统化解决方案: ### 问题定位 错误信息`undefined symbol in libgazebo_mavlink_interface.so`表明: 1. **版本不兼容**:PX4与Gazebo版本不匹配(常见于Ubuntu 20.04默认安装Gazebo 11) 2. **依赖缺失**:编译时缺少关键依赖库(如protobuf, libgazebo-dev等) 3. **编译污染**:之前编译的残留文件导致冲突 ### 解决方案 #### 步骤1: 验证Gazebo版本 ```bash gazebo --version # 若输出为9.x或非11.x,需升级/降级至兼容版本[^1] ``` #### 步骤2: 安装指定版本Gazebo(推荐11.11.0) ```bash # 移除旧版本 sudo apt remove gazebo* libgazebo* # 添加Gazebo官方源 sudo sh -c 'echo "deb http://packages.osrfoundation.org/gazebo/ubuntu-stable `lsb_release -cs` main" > /etc/apt/sources.list.d/gazebo-stable.list' wget https://packages.osrfoundation.org/gazebo.key -O - | sudo apt-key add - # 安装Gazebo 11 sudo apt update sudo apt install gazebo11 libgazebo11-dev ``` #### 步骤3: 修复PX4依赖 ```bash cd ~/PX4-Autopilot # 清理旧编译 make distclean # 重新安装依赖(关键步骤) ./Tools/setup/ubuntu.sh --no-nuttx ``` #### 步骤4: 重新编译PX4 SITL ```bash # 设置环境变量(解决protobuf冲突) export PROTOBUF_PROTOC_EXECUTABLE=/usr/bin/protoc # 开始编译 make px4_sitl_default gazebo ``` #### 步骤5: 处理SSL错误(若出现引用[1]的错误) ```bash # 修复libcurl SSL证书问题 sudo apt install libcurl4-openssl-dev ``` ### 验证方法 1. 启动仿真: ```bash make px4_sitl_default gazebo-classic_iris ``` 2. 检查Gazebo界面是否正常加载Iris无人机模型。 ### 疑难解答 - **若仍出现`undefined symbol`**: ```bash # 检查符号表 nm -D /usr/lib/x86_64-linux-gnu/gazebo-11/plugins/libgazebo_mavlink_interface.so | grep [符号名] ``` 对比PX4编译输出的同名符号,确认是否一致。 - **清理构建缓存**: ```bash rm -rf build/ git submodule update --init --recursive ``` ### 相关问题 1. 如何为PX4仿真配置多个无人机? 2. Gazebo启动时卡在加载模型界面如何解决? 3. PX4编译中`make`命令的`-j`参数如何合理设置? 4. 如何验证PX4与ROS的MAVROS连接? > 提示:定期运行`git pull`更新PX4源码,并重新编译(`make distclean`)可避免版本差异问题[^3]。 [^1]: 参考自"Unable to connect gazebo simulator with px4_sitl" [^2]: 参考自"ubuntu20.04基于ROS的PX4在gazebo仿真下编译错误" [^3]: 参考自"failed to make px4_sitl_default gazebo-classic_iris"</think>### 解决PX4 SITL Gazebo启动失败问题(undefined symbol错误) #### 问题分析 `undefined symbol in libgazebo_mavlink_interface.so`错误通常由以下原因导致: 1. **版本不兼容**:PX4与Gazebo版本不匹配(Ubuntu 20.04默认Gazebo 11与PX4最新版可能存在兼容问题)[^2][^3] 2. **依赖缺失**:编译时缺少关键依赖库(如protobuf, libgazebo-dev等) 3. **编译污染**:之前编译的残留文件导致冲突 4. **符号冲突**:动态库链接时符号解析失败 --- ### 完整解决方案 #### 步骤1:彻底清理编译环境 ```bash cd ~/PX4-Autopilot make distclean # 清除所有编译产物 git submodule update --init --recursive # 重置子模块 ``` #### 步骤2:安装兼容版本依赖 ```bash # 移除冲突版本 sudo apt remove '^gazebo' '^libgazebo' # 安装指定版本(推荐Gazebo 11.11.0) sudo apt install gazebo11 libgazebo11-dev # 安装关键依赖 sudo apt install protobuf-compiler libprotobuf-dev \ libeigen3-dev libopencv-dev \ libgstreamer-plugins-base1.0-dev ``` #### 步骤3:修复环境变量配置 ```bash # 在~/.bashrc末尾添加 export GAZEBO_PLUGIN_PATH=$GAZEBO_PLUGIN_PATH:~/PX4-Autopilot/build/px4_sitl_default/build_gazebo export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/x86_64-linux-gnu/gazebo-11/plugins source ~/.bashrc ``` #### 步骤4:重新编译(关键步骤) ```bash cd ~/PX4-Autopilot DONT_RUN=1 make px4_sitl_default gazebo # 仅编译不运行 # 修复符号链接 cd build/px4_sitl_default/build_gazebo cmake --build . --target install ``` #### 步骤5:验证启动 ```bash # 启动Gazebo仿真 make px4_sitl_default gazebo-classic_iris ``` 预期成功输出: ```plaintext [Msg] Connected to gazebo master... [Msg] Publicized address: 192.168.1.XX INFO [simulator] Waiting for simulator to connect on TCP port 4560 ``` --- ### 疑难解答 1. **若仍出现SSL错误**(引用[1]): ```bash sudo apt install libcurl4-openssl-dev export GIT_SSL_NO_VERIFY=1 # 临时禁用SSL验证 ``` 2. **protobuf版本冲突**: ```bash sudo apt install protobuf-compiler=3.12.3-1ubuntu1 \ libprotobuf-dev=3.12.3-1ubuntu1 ``` 3. **Gazebo模型加载失败**: ```bash cd ~/.gazebo git clone https://gitee.com/PX4/models.git --depth 1 ``` --- ### 相关问题 1. 如何为PX4仿真配置多个无人机? 2. Gazebo启动时卡在加载模型界面如何解决? 3. PX4编译中`make`命令的`-j`参数如何合理设置? 4. 如何验证PX4与ROS的MAVROS连接? > 建议使用官方推荐配置:Ubuntu 20.04 + ROS Noetic + Gazebo 11 + PX4 v1.13,可减少兼容性问题[^3]。定期运行`git pull && git submodule update`保持代码最新。 [^1]: 参考自Gazebo SSL连接问题 [^2]: 参考自Ubuntu 20.04编译错误 [^3]: 参考自PX4官方安装指南
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值