Google Protocol buffer 學習筆記.下篇-動態編譯
一 動態編譯
前文介紹了Protobuf的安裝及編譯方法,不過protobuf不僅提供了使用protoc進行靜態編譯的方法,也提供了動態編譯的方法
動態編譯 也就是說無須編譯
.proto
生成.pb.cc
和.pb.h
-
需要使用protobuf中提供的兩個標頭檔案, protobuf中標頭檔案的位置
/usr/local/include/google/protobuf
google/protobuf/compiler/importer.h
以及google/protobuf/dynamic_message.h
先看程式碼示例
#include <iostream>#include <string>#include <google/protobuf/compiler/importer.h>#include <google/protobuf/dynamic_message.h>class MyErrorCollector: public google::protobuf::compiler::MultiFileErrorCollector { virtual void AddError(const std::string & filename, int line, int column, const std::string & message){ // define import error collector printf("%s, %d, %d, %sn", filename.c_str(), line, column, message.c_str()); } };int main(){ google::protobuf::compiler::DiskSourceTree sourceTree; // source tree sourceTree.MapPath("", "/home/szw/code/protobuf/tmp2"); // initialize source tree MyErrorCollector errorCollector; // dynamic import error collector google::protobuf::compiler::Importer importer(&sourceTree, &errorCollector); // importer importer.Import("test.proto"); // find a message descriptor from message descriptor pool const google::protobuf::Descriptor * descriptor = importer.pool()->FindMessageTypeByName("lm.helloworld"); if (!descriptor){ perror("Message is not found!"); exit(-1); } // create a dynamic message factory google::protobuf::DynamicMessageFactory * factory = new google::protobuf::DynamicMessageFactory(importer.pool()); // create a const message ptr by factory method and message descriptor const google::protobuf::Message * tmp = factory->GetPrototype(descriptor); // create a non-const message object by const message ptr // define import error collector google::protobuf::Message * msg = tmp->New(); return 0; }
標頭檔案
<google/protobuf/compiler/importer.h>
包含了編譯器物件相關標頭檔案
<google/protobuf/dynamic_message.h>
包含了Message_Descriptor
和Factory
相關
首先初始化一個
DiskSourceTree
物件, 指明目標.proto
檔案的根目錄建立一個
MyErrorCollector
物件, 用於收集動態編譯過程中產生的編譯bug, 該物件需要根據proto提供的純虛基類派生, 並需要重寫其中的純虛擬函式, 使之不再是一個抽象類初始化一個
Importer
物件, 用於動態編譯, 將DiskSourceTree
和MyErrorCollector
的地址傳入將目標
.proto
動態編譯, 並加入編譯器池中可以透過
FindMessageTypeName()
和訊息名, 來獲取到目標訊息的Message_Descriptor
建立動態工廠, 並利用工廠方法
GetPrototype
和目標訊息的Message_Descriptor
獲取一個指標const message *
利用訊息例項指標的
New()
方法獲取到non-const message ptr
二 型別反射
型別反射即是根據欄位的名稱獲取到欄位型別的一種機制
protobuf自身便配備了型別反射機制
需要標頭檔案
<google/protobuf/descriptor.h>
與<google/protobuf/message.h>
下面的示例,結合了動態編譯以及型別反射機制
程式碼解析:
首先使用動態編譯機制,將test1.proto與test2.proto兩個檔案動態編譯進編譯池
根據訊息名獲取到目標訊息的descriptor
建立一個動態工廠,並利用訊息的descriptor獲取到
const Message * tmp
利用
const Message * tmp
的方法New()
獲取Message * msg
根據msg獲取反射器
Reflection
物件利用descriptor可以遍歷各個欄位, 並利用descriptor的
cpp_type()
方法獲取到每個欄位的型別, 並藉此進行反射填充
程式碼示例
proto檔案
// @file test1.protosyntax = "proto3"; package lm; message Player { int32 id = 1; string name = 2; repeated string hero = 3; }
// @file test2.protosyntax = "proto3";import "test1.proto"; package lm; message Game{ repeated Player player = 1; string gameName = 2; };
cpp
// @file test.cpp#include <iostream>#include <string>#include <google/protobuf/compiler/importer.h> // Importer DiskSourceTree MultiFileErrorCollector#include <google/protobuf/dynamic_message.h> // DynamicMessageFactory #include <google/protobuf/descriptor.h> // Desctriptor FiledDescriptor ... all descriptor#include <google/protobuf/message.h> // Message Reflection MessageFactoryclass MyErrorCollector: public google::protobuf::compiler::MultiFileErrorCollector { virtual void AddError(const std::string & filename, int line, int column, const std::string & message){ // define import error collector printf("%s, %d, %d, %sn", filename.c_str(), line, column, message.c_str()); } };int main(){ google::protobuf::compiler::DiskSourceTree sourceTree; // source tree sourceTree.MapPath("", "./"); // initialize source tree MyErrorCollector errorCollector; // dynamic import error collector google::protobuf::compiler::Importer importer(&sourceTree, &errorCollector); // importer importer.Import("test1.proto"); importer.Import("test2.proto"); // find a message descriptor from message descriptor pool const google::protobuf::Descriptor * descriptor = importer.pool()->FindMessageTypeByName("lm.Game"); if (!descriptor){ perror("Message is not found!"); exit(-1); } // create a dynamic message factory google::protobuf::DynamicMessageFactory * factory = new google::protobuf::DynamicMessageFactory(importer.pool()); // create a const message ptr by factory method and message descriptor const google::protobuf::Message * tmp = factory->GetPrototype(descriptor); // create a non-const message ptr object by const message ptr // define import error collector google::protobuf::Message * msg = tmp->New(); // get a reflection by msg const google::protobuf::Reflection * reflection = msg->GetReflection(); // travel the message by message_descriptor for (int i=0; i<descriptor->field_count(); ++i){ const google::protobuf::FieldDescriptor * fieldDescriptor = descriptor->field(i); if (fieldDescriptor->is_repeated()){ switch (fieldDescriptor->cpp_type()){ case google::protobuf::FieldDescriptor::CPPTYPE_INT32: { reflection->AddInt32(msg, fieldDescriptor, 10); break; } case google::protobuf::FieldDescriptor::CPPTYPE_STRING: { reflection->AddString(msg, fieldDescriptor, "abc"); } case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: { printf("Here is a repeadted message: %sn", fieldDescriptor->full_name().c_str()); } case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_INT64: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: { break; } } }else{ switch (fieldDescriptor->cpp_type()){ case google::protobuf::FieldDescriptor::CPPTYPE_INT32: { reflection->SetInt32(msg, fieldDescriptor, 10); break; } case google::protobuf::FieldDescriptor::CPPTYPE_STRING: { reflection->SetString(msg, fieldDescriptor, "abc"); } case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: { printf("Here is a message: %sn", fieldDescriptor->full_name().c_str()); } case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_INT64: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: { break; } case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: { break; } } } } printf("nmsgn"); msg->PrintDebugString(); return 0; }
作者:neilzwshen
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4369/viewspace-2821348/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- google protocol buffer——protobuf的編碼原理二GoProtocol
- 【編譯openjdk學習筆記】編譯JDK筆記
- google protocol buffer——protobuf的使用特性及編碼原理GoProtocol
- redis 學習筆記(1)-編譯、啟動、停止Redis筆記編譯
- 《圖解 Google V8》編譯流水篇——學習筆記(二)圖解Go編譯筆記
- (轉)redis 學習筆記(1)-編譯、啟動、停止Redis筆記編譯
- Google Protocol Buffer 的使用和原理GoProtocol
- Node中Buffer學習筆記筆記
- ZYNQ學習筆記(一): uboot 編譯筆記boot編譯
- buffer cache size的學習筆記筆記
- 動態規劃學習筆記動態規劃筆記
- protocol buffer的高效編碼方式Protocol
- Mybatis學習筆記(6)-動態SQLMyBatis筆記SQL
- protocol bufferProtocol
- google protocol buffer——protobuf的基本使用和模型分析GoProtocol模型
- Object C學習筆記15-協議(protocol)Object筆記協議Protocol
- 編譯、連結學習筆記(一)簡述編譯連結過程編譯筆記
- java反射之動態代理學習筆記Java反射筆記
- 彙編學習筆記筆記
- google protocol buffer——protobuf的問題及改進一GoProtocol
- google protocol buffer——protobuf的問題和改進2GoProtocol
- JNI學習筆記之ndk-build手動編譯並整合流程筆記UI編譯
- Solidity語言學習筆記————2、使用編譯器Solid筆記編譯
- GCC/G++學習筆記 - 1 - 執行預編譯GC筆記編譯
- Python學習筆記6——動態型別Python筆記型別
- 【JavaScript學習筆記】呼叫google搜尋JavaScript筆記Go
- 前端後臺以及遊戲中使用Google Protocol Buffer詳解前端遊戲GoProtocol
- Protocol Buffer技術詳解(資料編碼)Protocol
- apache動態編譯/靜態編譯區別Apache編譯
- 動態dp複習筆記筆記
- Protocol Buffer 使用指北Protocol
- TarsGo支援Protocol BufferGoProtocol
- TarsGo 支援 protocol bufferGoProtocol
- 【BUFFER】Oracle buffer cache之 latch 學習記錄Oracle
- java動態編譯Java編譯
- RabbitMQ訊息佇列的小夥伴: ProtoBuf(Google Protocol Buffer) [轉]MQ佇列GoProtocol
- 彙編基礎學習筆記筆記
- React學習筆記-State(狀態)React筆記