Google的probobuf是一个非常好用的序列化和反序列化库,而且它是跨平台的。如果应用需要在linux和windows下跨平台运行, protobuf是一个不错的选择。
这里介绍一下Protobuf linux和windows下编译与使用。
1 Download and build
Download from:
https://github.com/protocolbuffers/protobuf/releases
./configure
make
make check
sudo make install
sudo ldconfig # refresh shared library cache.
/usr/local/bin/protoc
/usr/local/include/google/protobuf
/usr/local/lib/
-rwxr-xr-x 1 root root 5518672 8月 4 16:17 libprotobuf-lite.so.23.0.4
lrwxrwxrwx 1 root root 26 8月 4 16:17 libprotobuf-lite.so.23 -> libprotobuf-lite.so.23.0.4
lrwxrwxrwx 1 root root 26 8月 4 16:17 libprotobuf-lite.so -> libprotobuf-lite.so.23.0.4
-rwxr-xr-x 1 root root 1012 8月 4 16:17 libprotobuf-lite.la
-rwxr-xr-x 1 root root 35029840 8月 4 16:17 libprotobuf.so.23.0.4
lrwxrwxrwx 1 root root 21 8月 4 16:17 libprotobuf.so.23 -> libprotobuf.so.23.0.4
lrwxrwxrwx 1 root root 21 8月 4 16:17 libprotobuf.so -> libprotobuf.so.23.0.4
-rwxr-xr-x 1 root root 977 8月 4 16:17 libprotobuf.la
-rwxr-xr-x 1 root root 47564640 8月 4 16:17 libprotoc.so.23.0.4
lrwxrwxrwx 1 root root 19 8月 4 16:17 libprotoc.so.23 -> libprotoc.so.23.0.4
lrwxrwxrwx 1 root root 19 8月 4 16:17 libprotoc.so -> libprotoc.so.23.0.4
-rwxr-xr-x 1 root root 993 8月 4 16:17 libprotoc.la
-rw-r--r-- 1 root root 14213702 8月 4 16:17 libprotobuf-lite.a
-rw-r--r-- 1 root root 92705362 8月 4 16:17 libprotobuf.a
-rw-r--r-- 1 root root 144112782 8月 4 16:17 libprotoc.a
2 Windows build
这里介绍的方式是使用Visual Studio编译。
2.1安装cmake
首先需要在windows 上安装cmake。
2.2生成sln工程
解压protobuf-3.12.4包后,进入protobuf-3.12.4\cmake目录,创建
子目录: build\debug
启动powershell, 进入protobuf-3.12.4\cmake\build\debug目录,运行如下命令:
cmake -G "Visual Studio 15 2017" -DCMAKE_BUILD_TYPE=Debug
-Dprotobuf_BUILD_SHARED_LIBS=ON
-Dprotobuf_BUILD_TESTS=OFF
-Dprotobuf_MSVC_STATIC_RUNTIME=OFF
-DCMAKE_INSTALL_PREFIX=../../../install
-T host=x64 -A x64 ../..
几个参数说明:
protobuf_BUILD_SHARED_LIBS=ON : 编译成动态库DLL, 如果是需要静态库,不需要加此参数
-T host=x64 -A x64 :指定为windows x86_64 处理器,如果是32位的系统不需要加此参数。
命令运行完毕,会在protobuf-3.12.4\cmake\build\debug目录生成vs 工程文件,如下:
2.3 编译
使用Visual Studio 2017打开工程文件protobuf.sln
因为我们只需要libprotobuf库,所以,只需要编译此库文件即可,其他的项目在编译时会报错,但是可以忽略,如下图所示:
编译完成后,生成的库文件位于:protobuf-3.12.4\cmake\build\debug\Debug
3 usage使用
2.1 编写proto文件
例如:
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}
2.2 generate c++ code
protoc -I=./ --cpp_out=./ person.proto
[email protected]:/local/test$ ls
person.pb.cc person.pb.h person.proto
所幸的是, 在Linux下和在windows下生成的文件是一样的(当然要除去回车和换行的区别),这样,只需要生成一次就可以跨平台使用了。
2.3 write to file
write.cc
#include <iostream>
#include <fstream>
#include <person.pb.h>
using namespace std;
int main()
{
Person person;
person.set_name("John Doe");
person.set_id(1234);
person.set_email("[email protected]");
fstream output("./myfile", ios::out | ios::binary);
person.SerializeToOstream(&output);
return 0;
}
Compile:
g++ -o write person.pb.cc write.cc -I/usr/local/include -I./ -L/usr/local/lib -lprotobuf
2.4 read from file
Read.cc
#include <iostream>
#include <fstream>
#include <person.pb.h>
using namespace std;
int main()
{
fstream input("myfile", ios::in | ios::binary);
Person person;
person.ParseFromIstream(&input);
cout << "Name: " << person.name() << endl;
cout << "E-mail: " << person.email() << endl;
return 0;
}
g++ -o read person.pb.cc read.cc -I/usr/local/include -I./ -L/usr/local/lib -lprotobuf
4 trouble shooting
在windows使用protobuf库时,会报如下错误:
错误 LNK2001 无法解析的外部符号 "class google::protobuf::internal::ExplicitlyConstructed<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > google::protobuf::internal::fixed_address_empty_string" ([email protected]@[email protected]@@[email protected][email protected]?
这时,可以使用如下方法:
1 在protobuf的头文件中inc\google\protobuf\port_def.inc
加上#define PROTOBUF_USE_DLLS
如下所示:
2 如此改动之后,又会报其他的错误: 不允许 dllimport 函数 的定义
parse_context.h文件中的PackedEnumParser, PackedEnumParserArg函数实现不需要import。
需要把函数前面的PROTOBUF_EXPORT_TEMPLATE_DEFINE删除