找回密码
 立即注册
查看: 396|回复: 3

被protobuf 3折磨的经历(一)

[复制链接]
发表于 2022-1-30 11:15 | 显示全部楼层 |阅读模式
使用protobuf的初衷
Apollo为了解决ROS 1原生数据类型的后向兼容性问题,使用了Google开源的protobuf(实际上Apollo非常喜欢Google全家桶...除了protobuf还有gfalgs、gtest、glog等等)。原本我以为ROS 2会对这个问题做出一定改进,但实际上它根本没改...当然也有可能是我还没发现。总之,不管是为了提前解决数据后向兼容性问题,还是为了学习Apollo的框架,学习并使用protobuf都是很有必要的。
我是怎么被protobuf折磨的

按照Protocal Buffers在Github上的步骤,我安装了protobuf 3,简单写了个.proto文件之后,顺利编译通过了。然后,我创建了一个新的CLion项目,在cpp文件里引用编译之后生成的头文件也没问题。本来我以为会很顺利地完成protobuf 3的入门使用,但是我很快就发现编译cpp文件的时候报错了,错误信息里出现的关键词是undefined reference to google protobuf等等。
一开始我把问题锁定在CMakeLists的编写上,在茫茫的帖子中我找到了下面这个帖子。
在git了他的源码之后,我发现我没法编译他的.proto文件,因为他用的protobuf 2,而我安装的是protobuf 3。因此,我自己写了个很简单的.proto文件,准备按照他的CMakeLists的写法进行编译。值得一提的是,这个帖子的CMake写法解开了我一直以来的困惑,就是一个cpp文件去调用一个.h文件和一个.cpp时CMake应该怎么写。当这些文件位于同一个文件夹时,是比较容易写的。但是,为了代码整洁有序,通常会按照功能将代码放在不同的文件夹下面(Apollo就是这么干的!)。那么,这篇帖子就讲述了在这种情况下应该怎么写CMakeLists:写2个CMakeLists,一个负责将下层目录编译成静态库文件,让上层目录直接读取和调用,而另一个则负责直接生成一个可执行文件。关键语句为:
add_subdirectory()书归正传,在按照如上的CMakeLists写法操作之后,我依然没法正常编译我的cpp文件。在观察了刚才git的源码结构之后,我认为可能是因为CLion没有正确链接到我安装的protobuf上面。经过一顿摸索,我得知在安装protobuf时,如果在键入./configure时不加后缀,则protobuf会默认分成三部分,分别安装在/usr/local/bin、/usr/local/include/google/protobuf、/usr/local/lib中。在我认真地读了一遍官方安装教程后,我发现有这么一句话:
By default, the package will be installed to /usr/local. However, on many platforms, /usr/local/lib is not part of LD_LIBRARY_PATH. You can add it, but it may be easier to just install to /usr instead.
我猜测可能就是我的Ubuntu虚拟机没有正确识别protobuf的安装路径。为了解决问题,我决定重新安装protobuf,这次把它装在同一个文件夹下面。卸载教程见下贴:
我以为这回能成功,实际上我又失败了...因为我既没有安装在/usr/local/下面,也没有直接安装在/usr/下面,系统根本找不到protoc...当然,这种方法肯定可以通过手动配置来解决,但是我不会...
不过,我似乎已经找到问题所在了。在/etc/下面有个ld.so.conf文件,这里面包含的是系统动态库路径。在Ubuntu中,这个文件里默认不带有/usr/local/lib,这可能就是protobuf说的However吧。执行以下命令:
cd /etc/
sudo gedit ld.so.conf
//在文件末尾添加/usr/local/lib
//保存退出
sudo ldconfigps:好像还可以在/etc/ld.so.conf.d/这个路径下创建*.conf文件来完成配置。
所以!我又重新装了一次,这回还是默认安装在/usr/local/下,不过结果还是error。我又去stack overflow上查了一下,下面这个问答解决了我的问题。
代码运行结果如下:
/home/lizh/CLionProjects/protobuf_test/pb3_c++/cmake-build-debug/pb3_c++
Zhang San 1 Bei Jing

进程已结束,退出代码为 0主要原理就是使用CMake中的FindProtobuf模块来寻找系统中的protobuf,这样看来应该是之前手写的绝对路径存在问题。上层CMakeLists的代码如下:
cmake_minimum_required(VERSION 3.20)
project(pb3_c++)

# 如果代码需要支持C++14,就直接加上这句
set(CMAKE_CXX_STANDARD 14)
# 如果想要生成的可执行文件拥有符号表,可以gdb调试,就直接加上这句
add_definitions("-Wall -g")

# 设置变量,下面的代码都可以用到
set(PROTO_PB_DIR ${PROJECT_SOURCE_DIR}/proto_pb3)


# 编译子文件夹的CMakeLists.txt
add_subdirectory(proto_pb3)

# 规定.h头文件路径
include_directories(${PROJECT_SOURCE_DIR}
        ${PROTO_PB_DIR}
        )

# 生成可执行文件
add_executable(${PROJECT_NAME}
        pb3_test.cpp )

# 链接操作
target_link_libraries<span class="o">${PROJECT_NAME}
        general_pb3)

install(TARGETS ${PROJECT_NAME}
        RUNTIME DESTINATION ${PROJECT_SOURCE_DIR})下层CMakeLists的代码如下:
project(general_pb3)

# Collects the names of all the source files in the specified directory
# and stores the list in the <variable> provided
aux_source_directory(${PROJECT_SOURCE_DIR}
        PB_FILES)

add_library(${PROJECT_NAME}
        STATIC ${PB_FILES})
        
# FindProtobuf module
include(FindProtobuf)
find_package(Protobuf REQUIRED)
include_directories(${PROJECT_SOURCE_DIR}
        ${PROTOBUF_INCLUDE_DIR}
        )

link_directories(${PROTOBUF_LIBRARY})
target_link_libraries(${PROJECT_NAME}
        ${PROTOBUF_LIBRARY}
        )总结

这点东西折磨了我有两三天,代码已经上传gitee,欢迎讨论。
发表于 2022-1-30 11:18 | 显示全部楼层
如果当前文件夹下的proto文件里 import其他文件夹里的proto文件,这个情况怎么写cmakelists呢,
发表于 2022-1-30 11:28 | 显示全部楼层
介个还没研究到[doge]
发表于 2022-1-30 11:37 | 显示全部楼层
哦霍
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2025-6-1 16:46 , Processed in 0.275039 second(s), 22 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表