protobuf-c 纯C版本的protobuf移植与使用
一、X86 ubuntu平台
1.下载protobuf-c ,下载最新版本就行
下载地址:https://github.com/protobuf-c/protobuf-c/tags
2.编译与安装
安装依赖库
sudo apt-get install autoconf automake libtool curl make g++ unzip pkg-config
安装protobuf3(要先安装protobuf2.6.1以上的版本后,才能正常编译出protobuf-c的bin、lib等)
下载地址:https://github.com/protocolbuffers/protobuf/tags
解压后,进入解压目录,执行以下命令(可以看下src/README.md的说明)
git submodule update --init --recursive(如果不是从git仓库clone下来的源码,可忽略)
./autogen.sh(如果不是从git仓库clone下来的源码,可忽略)
./configure
make
make check
sudo make install
sudo ldconfig # refresh shared library cache.
编译protobuf-c
./autogen.sh (如果不是从git仓库clone下来的源码,可忽略)
./configure --prefix=xxx/xxx/protobuf-c-x86(--prefix选一个自定义的目录,可以不加这选项,默认安装的系统文件夹)
make
make install
至此,protobuf-c安装完成。
3.protobuf-c移植至ARM
./autogen.sh
./configure --host=arm-linux CC=arm-none-linux-gnueabi-gcc CXX=arm-none-linux-gnueabi-g++ --disable-protoc --prefix=/usr/local/protobuf-c-arm
CC=指定gcc编译器,CXX=指定g++编译器,--disable-protoc 不使用protoc(因为它是C++版本,此处只用它生成两个文件,编译处用不到,除非在arm机器上编译protoc代码才会用到),--prefix=指定安装路径
如果arm-gcc编译器不会自动寻找依赖的h和lib,有时还需要指定
CFLAG、LDFLAGS、CPP即$(CC) -E 、CXXCPP即$(CXX) -E 、LD 、AR
可以暴力的将CFLAG、LDFLAGS加到CC="arm-none-linux-gnueabi-gcc $(CFLAGS) $(LDFLAGS)"后面,防止arm-gcc编译器找不到依赖头文件或库文件,导致configure、编译或链接失败
4.protobuf-c的使用
编写.proto文件,如test.proto
syntax="proto2";//标记使用proto V2版本,现在最新已经是V3版本,支持C++、JAVA等主流语言,C还不支持
/*以下为测试数据*/
message TestMessage{
optional uint64 id=1;
repeated uint32 state=2;
required string name=3;
}
message AllMessage{
required bytes data=1;
required uint64 all_id=2;
required uint32 all_state=3;
required TestMessage testmsg=4;
}
字段规则类型:
required:表示后面的数据是必须的。
optional:表示后面数据是可选的。
repeated:表示后面的数据是一个数组。
生成.pb-c.c和.pb-c.h文件
可以将.proto文件复制到安装目录(xxx/xxx/protobuf-c-x86/bin),即proto-c可执行文件所在目录,终端执行
./protoc-c -I=. --c_out=. ./test.proto
可以生成test.pb-c.c和test.pb-c.h文件
如果安装在系统文件夹
可以在test.proto所在的文件夹,终端执行
protoc-c -I=. --c_out=. ./test.proto
使用.pb-c.c和.pb-c.h文件
test.pb-c.c
/* Generated by the protocol buffer compiler. DO NOT EDIT! */ /* Generated from: test.proto */ /* Do not generate deprecated warnings for self */ #ifndef PROTOBUF_C__NO_DEPRECATED #define PROTOBUF_C__NO_DEPRECATED #endif #include "test.pb-c.h" void test_message__init (TestMessage *message) { static const TestMessage init_value = TEST_MESSAGE__INIT; *message = init_value; } size_t test_message__get_packed_size (const TestMessage *message) { assert(message->base.descriptor == &test_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t test_message__pack (const TestMessage *message, uint8_t *out) { assert(message->base.descriptor == &test_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t test_message__pack_to_buffer (const TestMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &test_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } TestMessage * test_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (TestMessage *) protobuf_c_message_unpack (&test_message__descriptor, allocator, len, data); } void test_message__free_unpacked (TestMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &test_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } void all_message__init (AllMessage *message) { static const AllMessage init_value = ALL_MESSAGE__INIT; *message = init_value; } size_t all_message__get_packed_size (const AllMessage *message) { assert(message->base.descriptor == &all_message__descriptor); return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); } size_t all_message__pack (const AllMessage *message, uint8_t *out) { assert(message->base.descriptor == &all_message__descriptor); return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); } size_t all_message__pack_to_buffer (const AllMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &all_message__descriptor); return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); } AllMessage * all_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (AllMessage *) protobuf_c_message_unpack (&all_message__descriptor, allocator, len, data); } void all_message__free_unpacked (AllMessage *message, ProtobufCAllocator *allocator) { if(!message) return; assert(message->base.descriptor == &all_message__descriptor); protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); } static const ProtobufCFieldDescriptor test_message__field_descriptors[3] = { { "id", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_UINT64, offsetof(TestMessage, has_id), offsetof(TestMessage, id), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "state", 2, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_UINT32, offsetof(TestMessage, n_state), offsetof(TestMessage, state), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "name", 3, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_STRING, 0, /* quantifier_offset */ offsetof(TestMessage, name), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned test_message__field_indices_by_name[] = { 0, /* field[0] = id */ 2, /* field[2] = name */ 1, /* field[1] = state */ }; static const ProtobufCIntRange test_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 3 } }; const ProtobufCMessageDescriptor test_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "TestMessage", "TestMessage", "TestMessage", "", sizeof(TestMessage), 3, test_message__field_descriptors, test_message__field_indices_by_name, 1, test_message__number_ranges, (ProtobufCMessageInit) test_message__init, NULL,NULL,NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor all_message__field_descriptors[4] = { { "data", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_BYTES, 0, /* quantifier_offset */ offsetof(AllMessage, data), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "all_id", 2, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_UINT64, 0, /* quantifier_offset */ offsetof(AllMessage, all_id), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "all_state", 3, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_UINT32, 0, /* quantifier_offset */ offsetof(AllMessage, all_state), NULL, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, { "testmsg", 4, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(AllMessage, testmsg), &test_message__descriptor, NULL, 0, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, }; static const unsigned all_message__field_indices_by_name[] = { 1, /* field[1] = all_id */ 2, /* field[2] = all_state */ 0, /* field[0] = data */ 3, /* field[3] = testmsg */ }; static const ProtobufCIntRange all_message__number_ranges[1 + 1] = { { 1, 0 }, { 0, 4 } }; const ProtobufCMessageDescriptor all_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "AllMessage", "AllMessage", "AllMessage", "", sizeof(AllMessage), 4, all_message__field_descriptors, all_message__field_indices_by_name, 1, all_message__number_ranges, (ProtobufCMessageInit) all_message__init, NULL,NULL,NULL /* reserved[123] */ };
test.pb-c.h
/* Generated by the protocol buffer compiler. DO NOT EDIT! */ /* Generated from: test.proto */ #ifndef PROTOBUF_C_test_2eproto__INCLUDED #define PROTOBUF_C_test_2eproto__INCLUDED #include <protobuf-c/protobuf-c.h> PROTOBUF_C__BEGIN_DECLS #if PROTOBUF_C_VERSION_NUMBER < 1000000 # error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. #elif 1004000 < PROTOBUF_C_MIN_COMPILER_VERSION # error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. #endif typedef struct TestMessage TestMessage; typedef struct AllMessage AllMessage; /* --- enums --- */ /* --- messages --- */ /* *以下为测试数据 */ struct TestMessage { ProtobufCMessage base; protobuf_c_boolean has_id; uint64_t id; size_t n_state; uint32_t *state; char *name; }; #define TEST_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&test_message__descriptor) \ , 0, 0, 0,NULL, NULL } struct AllMessage { ProtobufCMessage base; ProtobufCBinaryData data; uint64_t all_id; uint32_t all_state; TestMessage *testmsg; }; #define ALL_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&all_message__descriptor) \ , {0,NULL}, 0, 0, NULL } /* TestMessage methods */ void test_message__init (TestMessage *message); size_t test_message__get_packed_size (const TestMessage *message); size_t test_message__pack (const TestMessage *message, uint8_t *out); size_t test_message__pack_to_buffer (const TestMessage *message, ProtobufCBuffer *buffer); TestMessage * test_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void test_message__free_unpacked (TestMessage *message, ProtobufCAllocator *allocator); /* AllMessage methods */ void all_message__init (AllMessage *message); size_t all_message__get_packed_size (const AllMessage *message); size_t all_message__pack (const AllMessage *message, uint8_t *out); size_t all_message__pack_to_buffer (const AllMessage *message, ProtobufCBuffer *buffer); AllMessage * all_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void all_message__free_unpacked (AllMessage *message, ProtobufCAllocator *allocator); /* --- per-message closures --- */ typedef void (*TestMessage_Closure) (const TestMessage *message, void *closure_data); typedef void (*AllMessage_Closure) (const AllMessage *message, void *closure_data); /* --- services --- */ /* --- descriptors --- */ extern const ProtobufCMessageDescriptor test_message__descriptor; extern const ProtobufCMessageDescriptor all_message__descriptor; PROTOBUF_C__END_DECLS #endif /* PROTOBUF_C_test_2eproto__INCLUDED */
main.c
#include "test.pb-c.h" #include <stdio.h> #include "unistd.h" #include "stdlib.h" #include "string.h" int main(int argc, char **argv) { printf("compile date:%s %s\n", __DATE__, __TIME__); TestMessage test_msg = TEST_MESSAGE__INIT; AllMessage all_msg = ALL_MESSAGE__INIT; test_msg.name = calloc(1, 32); memcpy(test_msg.name,"helloworld",strlen("helloworld")); test_msg.id = 12345678; test_msg.n_state = 8; test_msg.state = calloc(test_msg.n_state,sizeof(uint32_t)); for (int i = 0; i < 8; i++) { test_msg.state[i] = i * i; } all_msg.testmsg = &test_msg; all_msg.data.len = 32; all_msg.data.data = calloc(1, all_msg.data.len); all_msg.all_id = 87654321; all_msg.all_state = 1234; int pack_len = all_message__get_packed_size(&all_msg); char *pack_buf = NULL; pack_buf = (char *)calloc(1, pack_len); if (!pack_len) { printf("calloc error\n"); return -1; } int unpack_len=all_message__pack(&all_msg, pack_buf); printf("get size=%d %d\n", pack_len,unpack_len); AllMessage *all_unpack = all_message__unpack(NULL, pack_len,pack_buf); printf("unpack name:%s\n", all_unpack->testmsg->name); for (int i = 0; i < 8; i++) { printf("all_unpack->testmsg->state[%d]=%d\n",i,all_unpack->testmsg->state[i]); } all_message__free_unpacked(all_unpack, NULL); free(test_msg.name ); free(test_msg.state); free(all_msg.data.data); free(pack_buf); return 0; }
build.sh
gcc main.c test.pb-c.c -o test_proto -I. -L./lib -I./include -lprotobuf-c
运行结果: