iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++中protobuf的交叉编译如何使用
  • 428
分享到

C++中protobuf的交叉编译如何使用

2023-07-02 16:07:12 428人浏览 独家记忆
摘要

这篇文章主要介绍“c++中protobuf的交叉编译如何使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C++中protobuf的交叉编译如何使用”文章能帮助大家解决问题。简介官方文档给出的定义和

这篇文章主要介绍“c++中protobuf的交叉编译如何使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C++中protobuf的交叉编译如何使用”文章能帮助大家解决问题。

简介

官方文档给出的定义和描述:

protocol buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据) 通信协议 、数据存储等。

Protocol Buffers 是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML,但是比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。

你可以定义数据的结构,然后使用特殊生成的源代码轻松的在各种数据流中使用各种语言进行编写和读取结构数据。你甚至可以更新数据结构,而不破坏由旧数据结构编译的已部署程序。

简单来说:

  • 和平台无关,和开发语言无关(支持多种语言和多个平台)

  • 高效:数据量小,因此更快

  • 扩展性和兼容性较好

使用方式

编译安装

以下仅介绍在嵌入式设备软件中使用,即交叉编译开发环境,以 protobuf-3.19.3为例

$ tar -xzvf protobuf-cpp-3.19.3.tar.gz$ cd protobuf-3.19.3/$ ./autogen.sh

配置交叉编译环境和编译安装后的路径,并编译

$ ./configure --host=arm-linux CC=aarch74-linux-gnu-GCc CXX=aarch74-linux-gnu-g++ --prefix=/home/protobuf/linux$ make -j;make install

此时会在 /home/protobuf/linux 生成三个文件夹

bin:可执行文件 protoc,可以将对应的 proto 文件生成代码的工具(在 ARM 下使用,所以这个不用)lib:对应的库,包含静态库和动态库等。还有对应裁剪版功能的lite库include:集成时需要包含的头文件

重新配置编译环境和安装后的路径,并编译(ubuntu系统)

$ ./configure --prefix=/home/protobuf/ubuntu$ make -j;make install

此时会在 /home/protobuf/ubuntu 生成三个文件夹,和上述一样(Ubuntu 的编译环境),但是这个我们只需要bin文件即可(我们使用的开发环境是 Ubuntu,所以通常都是在 Ubuntu 上执行protoc,用来生成对应的代码)

使用步骤

创建 .proto 文件,定义数据结构,如:

// 指定版本 (默认)使用protobuf2 syntax = "proto2"; // 指定命名空间 package ExampleNC; // 例1: 在 xxx.proto 文件中定义 CExample message message CExample {     optional string stringDesc = 1;     optional bytes bytesVal = 2; }

通过可执行文件 protoc 将 .proto 文件生成对应的代码文件

$ protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/xxx.proto

$SRC_DIR是.proto文件所在的路径,$DST_DIR是生成代码的路径,--cpp_out 是表示生成 C++代码;

生成对应的 xxx.pb.h 和 xxx.pb.cc 两个文件,可将这两个文件放入需要集成的代码中(包括交叉编译生成的头文件include)

通过生成的类 CExample 定义变量,设置对应的值,如:

CExample *pInfo = new CExample();pInfo->set_stringdesc("test");  // 赋值printf("info: %s\n", pInfo->DebugString().c_str());// 打印设置的值(文本格式,lite版本不支持)int length = pInfo->ByteSize();char *pBuf = (char *)malloc(length);pInfo->SerializeToArray(pBuf, length);// 序列化为hexprintf_hexdump("HEX:", pBuf, length);// 打印序列化后的hex数据CExample *pOutInfo = new CExample();pOutInfo->ParseFromArray(pBuf, length);//反序列化printf("OUTinfo: %s\n", pOutInfo->DebugString().c_str());// 打印设置的值(文本格式,lite版本不支持)free(pBuf);

其中,定义新的类后,若没有进行赋值操作的变量,序列化中则没有该数据内容

常见问题

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

[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):

网上提供的解决办法

【转自 https://m.newsmth.net/article/Programming/single/5862/3】Protobuf是Google的一个开源项目,它的大部分代码是用C++写的。当别的程序想要使用protobuf时,既可以采用动态链接,也可以采用静态链接。Google内部主要是采用静态链接为主。而在Linux的世界里,大部分发行版都把Protobuf编译成了动态库。 最佳实践如果你的Project本身是一个动态库,那么你应该避免在它的公开接口中用到任何protobuf的符号,并且采用静态链接到protobuf的方式。同时你应该在dllmain中调用google::protobuf::ShutdownProtobufLibrary()来清理protobuf使用过内存。如果你的Project本身是一个静态库,那么决定权不在你手里,而且最终把你的静态库编译成PE/ELF文件的那个人手里。但是你需要在你的build system中留出接口让他可以告知你这个信息。如果你的Project本身是一个动态库,并且你公开接口中用到了protobuf的符号,那么你必须动态链接到protobuf。 否则当你跨DLL传送protobuf的对象时,如果这个对象在A.DLL中创建,但是在B.DLL中被销毁,那么就会导致程序崩溃。因为当你采用静态链接到Protobuf时,每个DLL内部都有一个protobuf的副本,并且protobuf内部有自己的内存池。跨DLL传输对象就会导致该对象可能在不属于自己的内存池中被释放。 动态链接的注意事项首先,不推荐在windows上这么做。 因为protobuf本身是基于C++的,而Windows上DLL的导出符号应该都是C风格的,不应含有任何STL、std::string这样的东西。 如果你一定要这么做,那么你就会收到C4251警告。这是一个level 1的警告,属于最高严重等级。如果你决定动态链接到protobuf,并且目标平台是Windows操作系统,那么你应该在编译你的project的源代码的时候"#define PROTOBUF_USE_DLLS"。 这样链接器才知道应该使用dllimport的方式去寻找protobuf的符号。 Linux不需要这么做。但是Linux需要注意把code编译成PIC的。 同时,在Windows上需要注意所有代码必须采用动态链接到CRT,而不能采用静态链接。 这条适用于libprotobuf.dll自身以及它的所有使用者。 无论是Windows还是Linux,动态链接带来的另一个问题是:从.proto生成的那些C/C++代码可能也需要被编译成动态库共享。因为protobuf本身有一个global的reGIStry。每个message type都需要去那里注册一下,而且不能重复注册。所以,假如你在A.DLL中定义了某些message type,那么B.DLL就只能从A.DLL的exported的DLL interface中使用这些message type, 而不能从proto文件中重新生成C/C++代码并包含到B.DLL里去。并且B.DLL也不能私自的去修改、扩展这个message type。据说换成protobuf-lite就能避免这个问题,但是Google官方并没有对此表态。 另外,protobuf动态库自身不能被unload然后reload。 这个限制让我很意外,但是Google自己说他们在设计的时候从来没考虑过这样的使用场景。不过,在Linux上这其实是很常见的事情,GLIB自身都不支持unload。 糟糕的用例:Tensorflow首先,tensorflow作为一个python的plugin,它必须是动态库,不能是静态库。Tensorflow选择了静态链接到protobuf。Tensorflow想要支持动态加载plugin。每个plugin是一个动态库。plugin本身需要访问Tensorflow的接口,而这些接口常常又含有protobuf的符号。Tensorflow会暴露(provide) libprotobuf 的部分符号。如果这个plugin需要的符号恰好在tensorflow中都能找到,那么很好。 但事情并非总是如此, 因为Tensorflow它只有一个partial的libprotobuf,它只包含它自己所必须的那部分protobuf的code。当这个plugin想要的超出了tensorflow所能提供的范畴,写plugin的人就会尝试把protobuf加到link command中。这样就会变得非常非常危险,程序随时会崩溃。因为它会在两个不同的protobuf副本之间传送protobuf的对象。 所以,不要看到“unresolved external symbol”就不动脑子的把缺的库加上,有时候这个错误代表的是更深层次的问题。 糟糕的用例: cmakecmake 3.16做了一个火上浇油的事情:当你使用find_package(Protobuf)的时候,你需要提前知道你找到的究竟是动态库还是静态库,如果是静态库那么你需要设置Protobuf_USE_STATIC_LIBS成OFF,否则在Windows上链接会失败。请注意: 不是cmake告诉你它找到的是什么,而是你要主动告诉它,它找到的会是什么。

首先说明错误的具体原因: 因为需要通信多个进程模块都集成了相同的 *.pb.cc 和 *.pb.h 文件进行编译(动态库或者执行文件),且在编译时通过动态库 libprotobuf.so 的方式进行链接 。

因为这个,导致在运行时报错,通过网上查找得到: protobuf 本身有一个 global 的 registry。每个 message type 都需要去那里注册一下,而且不能重复注册 。上述的 Add 错误就是因为注册失败,原因就是因为这几个中重复注册了(多份 *.pb.cc 实现)。

解决方案

根据网上的解决方案,我自己也实验了,归纳如下:

静态库编译,使用 libprotobuf.a,即多个编译目标通过静态库的方式链接,但是这种方式势必会导致程序编译后的目标大小增大,不太适合 ARM 容量小的设备。如果编译目标是动态库,则需要在交叉编译 protobuf 加上-fPIC。

$ ./configure --host=arm-linux --disable-shared CFLAGS="-fPIC -fvisibility=hidden" CXXFLAGS="-fPIC -fvisibility=hidden" CC=aarch74-linux-gnu-gcc CXX=aarch74-linux-gnu-g++ --prefix=/home/protobuf/linux$ make -j;make install

或者改 configure 文件再执行 configure

// 改成下面的样子(不同版本位置不对,所以可以搜索 ac_cv_env_CFLAGS_set)if test "x${ac_cv_env_CFLAGS_set}" = "x"; then CFLAGS="-fPIC"fiif test "x${ac_cv_env_CXXFLAGS_set}" = "x"; then  CXXFLAGS="-fPIC"fi
$ ./configure --host=arm-linux --disable-shared CC=aarch74-linux-gnu-gcc CXX=aarch74-linux-gnu-g++ --prefix=/home/protobuf/linux$ make -j;make install

使用 protobuf-lite 版本,可以通过动态库 libprotobuf-lite.so 链接,但这个版本裁剪了很多功能,只保留了基本功能,这个需要修改 *.proto 文件,增加 option optimize_for  选项,重新生成 *.pb.cc 和 *.pb.h 文件,然后各模块集成编译即可。

// 指定版本 (默认)使用protobuf2 syntax = "proto2"; // 使用 lite 版本option optimize_for = LITE_RUNTIME;// 指定命名空间 package ExampleNC; // 例1: 在 xxx.proto 文件中定义 CExample message message CExample {     optional string stringDesc = 1;     optional bytes bytesVal = 2; }

将生成的 *.pb.cc 和 *.pb.h 和 libprotobuf.a 编译成一个新的动态库 libprotobuf-new.so,其他模块包含 *.pb.h 文件并通过动态库的方式链接这个新的动态库即可。

这种方式解决了上述问题,也保留了全部功能,但是对于后续的维护存在一定问题,如果更新 *.proto 文件,重新生成并编译了 libprotobuf-new.so,那么其他使用的模块也必须都更新*.pb.h 文件重新编译,否则在使用中会遇到:

  • 程序包只替换了 libprotobuf-new.so ,程序运行时可能存在踩踏数据的情况,引发系统异常

  • 程序包只替换了其他模块的库,并没有替换 libprotobuf-new.so ,就会导致进程崩了

所以,在多人合作开发的程序实现数据通信时,这种方式并不好,兼容性太差,因为需要替换所有涉及的模块动态库或者执行文件

以上三种解决方案各有利弊,可以根据实际情况选择

关于“C++中protobuf的交叉编译如何使用”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网其他教程频道,小编每天都会为大家更新不同的知识点。

--结束END--

本文标题: C++中protobuf的交叉编译如何使用

本文链接: https://www.lsjlt.com/news/343176.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++中protobuf的交叉编译如何使用
    这篇文章主要介绍“C++中protobuf的交叉编译如何使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C++中protobuf的交叉编译如何使用”文章能帮助大家解决问题。简介官方文档给出的定义和...
    99+
    2023-07-02
  • C++中protobuf 的交叉编译使用详解
    目录前言简介使用方式编译安装使用步骤常见问题解决方案前言 为了提高通信效率,可以采用 protobuf 替代 XML 和 Json 数据交互格式,protobuf 相对来说数据量小,...
    99+
    2024-04-02
  • Golang交叉编译(跨平台编译)的使用
    目录一、何为交叉编译二、交叉编译前的准备安装TDM-GCC三、简述交叉编译四、实练1. 默认编译2.交叉编译一个Arm+Linux小总结一、何为交叉编译 简单地说,就是在一个平台上生...
    99+
    2024-04-02
  • ubuntu如何交叉编译环境
    12ubuntu交叉编译环境的搭建示例:打开终端命令行。输入以下命令安装交叉编译环境。sudo apt-get install gcc g++ libcc1 libg++ make gdb再输入以下命令安装交叉编译器。wget ftp://...
    99+
    2024-04-02
  • 如何交叉编译Python到ARM-Lin
    前言 我需要在Arm9的s3c2410 CPU上运行python,以下是我的编译过程。 host编译环境: ubuntu 7.04, gcc 4.2.1, arm-linux-gcc 3.3.2 要cross compil...
    99+
    2023-01-31
    Python ARM Lin
  • 如何查看ubuntu交叉编译器
    要查看Ubuntu交叉编译器,请按照以下步骤操作:1. 打开终端。2. 运行以下命令来安装交叉编译器:```sudo apt-get...
    99+
    2023-08-26
    ubuntu
  • Golang交叉编译之跨平台编译使用详解
    目录在CMD命令行中编译设置Linux编译环境powershell命令行中一、CGO_ENABLED二、GOOS三、GOARCH四、GOHOSTOS五、GOHOSTARCH六、go ...
    99+
    2024-04-02
  • ubuntu交叉编译工具如何安装
    要安装Ubuntu的交叉编译工具,您可以按照以下步骤进行操作:1. 打开终端窗口。2. 更新软件包列表,运行以下命令:sudo ap...
    99+
    2023-09-20
    ubuntu
  • Fedora SkyEye如何安装交叉编译器
    这篇文章给大家分享的是有关Fedora SkyEye如何安装交叉编译器的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。Fedora SkyEye是一个可以运行嵌入式操作系统的硬件仿真工具,这样就可以在没有硬件条件下...
    99+
    2023-06-16
  • linux交叉编译环境如何搭建
    搭建Linux交叉编译环境需要以下步骤:1. 安装交叉编译工具链:交叉编译工具链是为了在一种操作系统上生成另一种操作系统的可执行文件。可以通过以下几种方式安装交叉编译工具链:- 使用发行版提供的交叉编译工具链:有些Linux发行版提供了...
    99+
    2023-08-11
    linux
  • linux如何配置arm交叉编译器
    要配置ARM交叉编译器,可以按照以下步骤进行操作:1. 安装ARM交叉编译器工具链:ARM交叉编译器工具链是专门用于ARM架构的编译...
    99+
    2023-08-11
    linux
  • c++编译器如何使用
    要使用C++编译器,你需要按照以下步骤进行操作:1. 安装编译器:首先,你需要安装一个C++编译器。常见的C++编译器包括GCC、C...
    99+
    2023-09-08
    c++
  • Cmake学习记录(九)--使用Cmake交叉编译Android .so库
    文章目录 一、前言二、使用NDK进行编译的相关代码四、使用交叉工具链进行编译五、参考链接 一、前言 注意:本教程没有关于JNI接口的写法,只是把C代码编译成适合android平台的so库,...
    99+
    2023-09-12
    学习 android android studio
  • 关于python中第三方库交叉编译的问题
    目录一、前言:二、交叉编译介绍:三、python及其第三方库的交叉编译背景四、交叉编译的准备工作五、交叉编译python及其第三方的思路六、准备交叉编译工具七、准备openssl-b...
    99+
    2024-04-02
  • TypeScript如何使用交叉类型
    这篇文章主要为大家展示了“TypeScript如何使用交叉类型”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“TypeScript如何使用交叉类型”这篇文章吧。交...
    99+
    2024-04-02
  • Qt中QZXing如何编译使用
    小编给大家分享一下Qt中QZXing如何编译使用,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1.编译下载源码后可以用 CMake 或者直接打开 pro 进行构建...
    99+
    2023-06-26
  • php中如何操作使用protobuf
    这篇文章主要介绍“php中如何操作使用protobuf”,在日常操作中,相信很多人在php中如何操作使用protobuf问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”php中如何操作使用protobuf”的疑...
    99+
    2023-06-25
  • ubuntu中如何编译c++程序
    ubuntu中编译c++程序的方法:打开终端使用vim编辑c++代码。vim hello.cpp输入如下代码:#include using namespace std;int main(){cout...
    99+
    2024-04-02
  • 如何使用java编译器进行编译
    使用Java编译器进行编译可以通过以下步骤:1. 确保已经安装了Java Development Kit (JDK)。可以通过在命令...
    99+
    2023-09-06
    java
  • 从交叉编译的二进制文件 Go 应用 tarball 构建 RPM 包
    对于一个Golang开发者来说,牢固扎实的基础是十分重要的,编程网就来带大家一点点的掌握基础知识点。今天本篇文章带大家了解《从交叉编译的二进制文件 Go 应用 tarball 构建 RPM 包》,主...
    99+
    2024-04-05
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作