当前位置:首页 > > 嵌入式大杂烩
[导读]之前文章介绍了protobuf、protobuf-c在PC平台上的安装及使用,本篇笔记我们来把它用在我们的嵌入式ARM平台。

什么是protobuf-c

之前的文章:《Protobuf:一种更小、更快、更高效的协议》详细介绍了protobuf及protobuf-c。这里再简单提一下:

Protocol Buffers,是Google公司开发的一种数据格式,类似于XML能够将结构化数据序列化,可用于数据存储、通信协议等方面。protobuf支持一些主流的语言,唯独没有支持C,所以诞生了第三方的protobuf-c。

之前文章介绍了protobuf、protobuf-c在PC平台上的安装及使用,本篇笔记我们来把它用在我们的嵌入式ARM平台。

交叉编译protobuf-c

之前的文章中我们已经把protobuf、protobuf-c安装在我们的PC环境中了:


我们简单回顾一下我们上一篇文章的大致内容:


从中我们知道,这里的protobuf的主要作用是生成了protoc工具,而protoc工具的作用是把.proto文件生成对应的C源、头文件,这个过程是与平台无关的,所以这里我们可以接着用。

而protobuf-c生成了编译需要用到的动态库,此处我们需要编译ARM架构的动态库。即我们本篇笔记需要做的事情是:

(1)交叉编译protobuf-c

首先在protobuf-c目录下使用make clean命令清除我们之前编译得到的东西:


输入如下命令生成交叉编译的Makefile文件:

左右滑动查看全部代码>>>

./configure --host=arm-linux-gnueabihf CC=/home/book/ToolChain/gcc-arm-linux-gnueabihf-6.2.1/bin/arm-linux-gnueabihf-gcc CXX=/home/book/ToolChain/gcc-arm-linux-gnueabihf-6.2.1/bin/arm-linux-gnueabihf-g++ --disable-protoc --prefix=$PWD/tmp


这个命令似乎很长,但并不难,只是加了几个配置参数。这些配置参数怎么看?我们可以输入./configure --help命令来查看支持的配置:


下面我们依次来分析上面那个很长的命令:

  • --host=arm-linux-gnueabihf:表明了我们最终可执行文件运行的环境。

  • CC=/home/book/ToolChain/gcc-arm-linux-gnueabihf-6.2.1/bin/arm-linux-gnueabihf-gcc:这是指定我们的交叉编译工具arm-linux-gnueabihf-gcc,这里直接给出绝对路径。

  • CXX=/home/book/ToolChain/gcc-arm-linux-gnueabihf-6.2.1/bin/arm-linux-gnueabihf-g++:这是指定我们的交叉编译工具arm-linux-gnueabihf-g++,这里直接给出绝对路径。

  • --disable-protoc:不使用protoc,前面我们也说了protoc工具把.proto文件生成对应的C源、头文件的过程是与平台无关的,所以这里不需要使用,除非我们想在我们的开发板上使用protoc,但这反而增加麻烦,不推荐直接在开发板上用。

  • --prefix=$PWD/tmp:指定安装的路径。表明安装路径在当前路径下的tmp文件夹中。

执行完这个命令之后就得到了交叉编译的Makefile文件,然后依次输入如下命令进行编译、安装:

make
make install


此时就在当前目录的tmp文件夹下生成了arm版本的相关库文件:


其中我们比较重要的就是libprotobuf-c.so这个动态库了,我们可以使用file或者readelf工具查看其是不是arm格式的:

很显然,这就是我们ARM平台的动态库。关于readelf的使用相关文章:《简单认识认识ELF文件》

下面开始我们的demo演示:

(2)protobuf-c实例演示

我们自定义一个.proto来创建我们的协议数据,然后使用protoc-c工具编译生成C代码,有两个文件:一个头文件、一个源文件。

例如我们创建一个student.proto文件:

syntax = "proto2";
 
message Student
{
    required string name    = 1;
    required uint32 num     = 2;
    required uint32 c_score = 3;
}

使用protoc-c工具工具编译student.proto文件:

protoc --c_out=. student.proto


编写我们的student.c测试demo:

左右滑动查看全部代码>>>

#include 
#include 
#include 
#include "student.pb-c.h"
 
int main(void)
{
    Student pack_stu = {0};
    uint8_t buffer[512] = {0};
    Student *unpack_stu = NULL;
    size_t len = 0;
 
    student__init(&pack_stu);
 
    /* 组包 */
    pack_stu.name = "ZhengN";
    pack_stu.num = 88;
    pack_stu.c_score = 90;
    len = student__pack(&pack_stu, buffer);
    printf("len = %ld\n",len);
 
    /* 解包 */
    unpack_stu = student__unpack(NULL, len, buffer);
    printf("unpack_stu.name = %s\n", unpack_stu->name);
    printf("unpack_stu.num = %d\n", unpack_stu->num);
    printf("unpack_stu.c_score = %d\n", unpack_stu->c_score);
 
    student__free_unpacked(unpack_stu, NULL);
    return 0;
}

demo很简单,组包就是构造一个协议数据结构体,调用pack组包接口往buffer中扔数据;解包正好是反过来,从buffer中拿数据放到结构体里。

此时我们工程的文件有:


交叉编译:

左右滑动查看全部代码>>>

arm-linux-gnueabihf-gcc student.c student.pb-c.c -o student -I /home/book/git_clone/protobuf-c/tmp/include -L /home/book/git_clone/protobuf-c/tmp/lib -lprotobuf-c

这个命令似乎也很长,其实也很简单:

  • arm-linux-gnueabihf-gcc:交叉编译器。
  • student.c student.pb-c.c:输入的源文件。
  • student:生成的可执行文件。
  • -I /home/book/git_clone/protobuf-c/tmp/include:指定头文件路径。
  • -L /home/book/git_clone/protobuf-c/tmp/lib:指定库路径。
  • -lprotobuf-c:链接动态库libprotobuf-c.so。

这里需要重点提的就是我们可以把我们上面编译得到的tmp/include里的文件复制到我们交叉编译器头文件搜索路径下、把tmp/lib里的文件复制到交叉编译器库文件搜索路径下,这样我们就不需要指定这么长的一串路径了。

但是这里我为了保持我的交叉编译器的一个原始性,我就不往里加东西了。关于这些链接、动态库更详细的内容可以阅读往期文章:《静态链接与动态链接补充(Linux)》《什么是动态链接与静态链接?》

编译没问题的话就可以生成我们的可执行文件student:


同样的,我们可以看一下student可执行文件的运行环境:


可见,是可运行在我们的arm开发板的。

下面把student拷贝到我们的开发板上运行,我这里用的是韦东山老师的IMX6ULL开发板。

运行出现如下错误:


这是因为不能找到共享库文件libprotobuf-c.so1,加载失败,这个问题我们已经在《静态链接与动态链接补充(Linux)》一文中做了详细解释。

解决方法有两种:第一种就是把这个库文件拷贝至系统库默认搜索路径下;第一种就是把当前路径增加为动态库的搜索路径。

这里我们选择第二种方法:我们把libprotobuf-c.so、libprotobuf-c.so1也传到板子上,放在student同目录下。然后输入如下命令把当前路径增加为动态库的搜索路径:

export LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH

然后运行:

运行成功!

以上就是咱们介绍的protobuf-c在嵌入式Linux平台上的使用(如果是正在学单片机的朋友,也可以尝试着移植使用。),如有错误,欢迎指出,谢谢。

按照以上两篇文章的步骤,大概率是可以成功的,关键是有耐心。

心得分享:在Linux的学习中,很多时候会被开发环境阻碍我们。常常按照别人的方法、步骤来做,却做不出来,很容易心态崩,这都是很正常的。因为环境不同,有时候还需要各种依赖。但我们要有足够的耐心,见招拆招!

在此之前,我也遇到了很多问题,也搜索了很多博客文章,要么行不通,要么写得太乱。所以趁此学习、写一篇。

这一篇大概是全网第一篇关于protobuf-c在嵌入式Linux平台上的交叉编译、使用步骤最全、解释最多的文章了。如果文章对你有帮助,麻烦帮忙转发,谢谢大家。

最后

以上就是本次的分享,如果觉得文章不错,转发、在看,也是我们继续更新的动力。

猜你喜欢:

2020年精选原创笔记汇总

干货 | 深度剖析C语言的main函数

Linux 的启动流程

1024G 嵌入式资源大放送!包括但不限于C/C++、单片机、Linux等。在公众号聊天界面回复1024,即可免费获取!

免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

随着现代家庭生活方式不断升级,厨房已不再只是功能空间,而逐渐成为融合审美表达、健康管理与智能体验的重要场域。消费者在关注空间整体性的同时,也对食材储存的安全性、洁净度以及使用便利性提出了更高要求。基于对中国家庭真实使用场...

关键字: 冰箱 嵌入式

在嵌入式系统、工业物联网等各类电子设备中,UART与网口是两种应用广泛的通信接口,前者作为经典的串行通信接口,承担着简单设备互联、调试日志传输等基础任务,后者则专注于高速、远距离的数据交互,是设备接入网络、实现大数据量传...

关键字: 嵌入式 通信接口 网口通讯

在软件开发领域,设计模式被誉为“解决特定问题的最佳实践”,但在嵌入式开发中,它却常常处于“边缘地带”。许多嵌入式工程师职业生涯中可能从未刻意使用过设计模式,甚至认为这些“软件工程理论”与单片机、传感器、实时系统等硬件紧密...

关键字: 嵌入式 设计模式

在居住结构持续演进与消费需求不断升级的背景下,中国家庭厨房正经历从“功能集合”向“系统空间”的深层转变。厨房不再只是烹饪的场所,而逐渐成为融合效率、健康、美学与家庭互动的重要生活空间。基于对这一趋势的长期洞察,西门子家电...

关键字: 嵌入式 蒸玲珑

在物联网设备、工业控制系统和智能家居等嵌入式场景中,轻量级WEB服务器扮演着核心角色。它们不仅需要满足资源受限环境下的性能需求,还需兼顾安全性、可扩展性和开发效率。本文从资源占用、功能特性、适用场景三个维度,对比分析六大...

关键字: 嵌入式 WEB服务器

在嵌入式软件开发工具领域,一场悄然的变革正在发生。随着全球软件行业向订阅制转型,嵌入式软件开发工具的授权模式也迎来了重要调整。市场上的嵌入式软件开发工具基本可以分为三类:商用开发工具,开源开发工具和厂商私有开发工具,其中...

关键字: 嵌入式 MCU RISC-V

在资源受限的嵌入式系统中,传统调试工具(如JTAG)往往成本高昂且占用引脚资源。本文介绍一种基于串口的低成本调试方案,通过自定义协议实现内存数据的实时监控,硬件成本可降低80%以上,特别适用于8/16位MCU开发场景。

关键字: 嵌入式 串口 内存数据

随着国家家电以旧换新补贴政策的持续推进,绿色节能、品质升级正成为越来越多家庭的新年焕新关键词。面对消费者在居住空间、生活效率与健康体验上的多元需求,西门子家电围绕新春焕新节点,正式开启“开门红”焕新季,通过国家补贴与企业...

关键字: 嵌入式 咖啡机 嵌饮机

设计人员通过瑞萨远程板场可在新MCU发布首日免费开始编程和编码

关键字: MCU 嵌入式 电路板
关闭