最近在cocos2dx的項目中,需要在LUA腳本層使用protobuf協議。官方已經推出了很多種語言的版本。但唯獨LUA版本不全。於是開始研究protobuf在LUA下的實現,將完整的過程記錄了下來,希望對其它人能有所幫助。
1、下載protoc-gen-lua
可以通過HG從服務器(hg clone https://github.com/sean-lin/protoc-gen-lua)上下載最新的版本。
簡單介紹一下里面的三個目錄:
example 存放的一個示例協議,
plugin 將.proto協議轉爲LUA腳本需要的工具。要注意,這個工具是用PYTHON寫的,所以後面我們需要安裝PYTHON。
rotobuf這裏存放了工程需要的文件。其中pb.c是C碼文件。主要是在工程中引用,也可以編譯成動態文件(.so)供LUA調用。其它LUA文件則需要引入到LUA工程中。
2、安裝PYTHON27。推薦是這個版本。
3、下載protobuf然後編譯出protoc.exe。
可以用SVN從服務器上(http://protobuf.googlecode.com/svn/trunk)下載最新的protobuf。我使用的是protobuf-2.4.1。
進入protobuf-2.4.1/vsprojects利用VS2010進行編譯。生成的protoc.exe放到protobuf-2.4.1/src下。如果不放,後面無法安裝python版的protobuf。
4、編譯python版本的protobuf
在protobuf-2.4.1\python下運行python setup.py build,然後再執行python setup.py install。
注意:如果第3步的protoc.exe沒有放,會出現錯誤找不到google\protobuf\compiler目錄。
5、製作轉換協議的批處理
在protoc-gen-lua/plugin目錄下編寫批處理:protoc-gen-lua.bat,就下面一行代碼。
///////////////////////////////////////////////////////////////////////////////////////
@python "%~dp0protoc-gen-lua"
///////////////////////////////////////////////////////////////////////////////////////
但要確保你的python命令能正常運行。否則將python.exe所在的目錄加到環境變量path中。
接着拷貝一份protoc.exe到protoc-gen-lua目錄。第3步我們已經編譯了出了protoc.exe。在協議轉換中,我們需要使用他。
在protoc-gen-lua目錄編寫批處理:buildproto.bat 來轉換協議。
rem 切換到.proto協議所在的目錄 cd ../luascript rem 將當前文件夾中的所有協議文件轉換爲lua文件 for %%i in (*.proto) do ( echo %%i "..\protobuf\protoc\protoc.exe" --plugin=protoc-gen-lua="..\protobuf\plugin\protoc-gen-lua.bat" --lua_out=. %%i ) echo end pause
請正確指定protoc.exe和protoc-gen-lua.bat相對協議目錄的路徑。
6、轉換協議文件
protoc-gen-lua/example目錄中,有一個協議文件person.proto,可以拿他做一下試驗,會生成一個person_pb.lua
7、編譯pb.c文件
protoc-gen-lua/protobuf目錄中有一個pb.c文件。我們需要用他來協助lua完成protobuf的功能。
用vs2010新建一個控制檯程序。將pb.c加入到工程中。在windows平臺下,要對pb.c做如下修改。
1)將 #include <endian.h>修改爲
#ifndef _WIN32
#include <endian.h>
#endif
避免在windows下缺失文件報錯.
2)調整struct_unpack函數前幾行爲
static int struct_unpack(lua_State *L)
{
uint8_t format = luaL_checkinteger(L, 1);
size_t len;
const uint8_t* buffer = (uint8_t*)luaL_checklstring(L, 2, &len);
size_t pos = luaL_checkinteger(L, 3);
uint8_t out[8];
buffer += pos;
3)在主函數前面申明pb.c的入口。
extern "C" { int luaopen_pb (lua_State *L);} // 注意防在命名空間外的全局聲明
編寫主函數如下:
#include "stdafx.h" extern "C"{ #include <lua.h> #include <lualib.h> #include <lauxlib.h> int luaopen_pb (lua_State *L); } int main(int argc, char* argv[]) { lua_State *L = lua_open(); luaL_openlibs(L); luaopen_pb(L); luaL_dofile(L, "main.lua"); lua_pcall(L, 0, LUA_MULTRET, 0); lua_close(L); return 0; }
工程需要lua5.1.lib的接入。這個請自行編譯。
8、編寫main.lua。
也就是測試文件,可以參考protoc-gen-lua/example中的test.lua。
package.path = package.path .. ';./protobuf/?.lua' require "person_pb" local msg = person_pb.Person() msg.id = 100 msg.name = "foo" msg.email = "bar" local pb_data = msg:SerializeToString() -- Parse Example print("create:", msg.id, msg.name, msg.email, pb_data) local msg = person_pb.Person() msg:ParseFromString(pb_data) print("parser:", msg.id, msg.name, msg.email, pb_data)
10、總結。
這裏實現了,在C++中搭建lua的protobuf環境。但未實現純粹的Lua-protobuf環境。
如果需要在LUA中實現protobuf,那需要自己將pb.c編譯成dll。在linux下需要利用protoc-gen-lua/protobuf中的makefile將pb.c編譯成pb.so。
然後將pb.so或pb.dll導入到lua工程中。然後在main.lua中調用pb.c中的入口,代碼如下:
local a = package.loadlib("pb.dll", "luaopen_pb"); a()
理論上是這樣,我還沒有做詳細的測試。如果有進展,再完善本貼。
轉自:http://blog.csdn.net/sunshine7858/article/details/9260671
-----------------------------------------------------------------------------------------------
下載地址:
http://code.google.com/p/protobuf/downloads/list
安裝命令
tar -xzf protobuf-2.5.0.tar.gz
cd protobuf-2.5.0
./configure --prefix=$INSTALL_DIR
make
make check
make install
然後進入python目錄,
python setup.py install --prefix=$INSTALL_DIR
寫proto文件
package lm;
message Person
{
required int32 id = 1;
required string str = 2;
optional int32 opt = 3;
}
保存爲 testp.testpb.proto
編譯指令
protoc -I=/home/workspace/testprob --python_out=/home/workspace/testprob /home/workspace/testprob/testp.testpb.proto
google
https://developers.google.com/protocol-buffers/docs/pythontutorial
報錯
package directory 'google/protobuf/compiler' does not exist
解決
https://groups.google.com/forum/?fromgroups=#!topic/protobuf/YeT5RW4qCxY
python ./setup.py build
sudo python ./setup.py install
報錯
File "/home/workspace/testprob/testp/testpb_pb2.py", line 6, in <module>
from google.protobuf import reflection as _reflection
File "build/bdist.linux-i686/egg/google/protobuf/reflection.py", line 68, in <module>
File "build/bdist.linux-i686/egg/google/protobuf/internal/python_message.py"
ImportError: cannot import name enum_type_wrapper
解決
http://code.google.com/p/protobuf/issues/detail?id=438
Log message
Fix issue 438 : add missing 'enum_type_wrapper' to setup.py
是安裝包的一個改進文件,copy下來, 重新安裝
根據安裝目錄下的demo 自己改寫了個簡單的, 覺得它那個還是麻煩
write.py
import testpb_pb4
import sys
p = testpb_pb2.Person()
try:
f = open(sys.argv[1], "rb")
p.ParseFromString(f.read())
f.close()
except IOError:
print sys.argv[1] + ": File not found. Creating a new file."
p.id = 32
p.str = "test"
f = open(sys.argv[1], "wb")
f.write(p.SerializeToString())
f.close()
print "write success"
編譯指令 python write.py "test"
read.py
import sys
import testpb_pb2
if len(sys.argv) != 2:
print "Usage:", sys.argv[0], "ADDRESS_BOOK_FILE"
sys.exit(-1)
p = testpb_pb2.Person()
f = open(sys.argv[1], "rb")
p.ParseFromString(f.read())
f.close()
print "p.str = ", p.str
print "p.id=", p.id