1. 背景
按装好protobuf之后,我们简单使用它。
在我的test/protobuf目录下,我创建了main.cc、test.proto,在main.cc和test.proto各写了简单内容(我将例子放在后面了)之后,使用命令protoc对test.proto进行编译:
protoc test.proto --cpp.out=./
执行这条命令之后,会在当前目录下生成test.pb.h和test.pb.cc,test/protobuf/整个目录结构如下:
.
├── main.cc
├── test.pb.cc
├── test.pb.h
└── test.proto
重点来了,我想要编译main.cc,生成可执行程序,我执行如下命令:
g++ main.cc test.pb.cc -o main -lprotobuf
上面的命令中,值得说一下的就是-lprotobuf,它就是说,要使用protobuf的库,名为protobuf的动态库或者静态库,出问题的也是因为这里,我暂且不表,后续会说如何解决。
错误如下:
/usr/bin/ld: /tmp/ccguO4TS.o: in function `google::protobuf::internal::ArenaStringPtr::Set(char const*, google::protobuf::Arena*)':
main.cc:(.text._ZN6google8protobuf8internal14ArenaStringPtr3SetEPKcPNS0_5ArenaE[_ZN6google8protobuf8internal14ArenaStringPtr3SetEPKcPNS0_5ArenaE]+0x5e): undefined reference to `google::protobuf::internal::ArenaStringPtr::Set(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, google::protobuf::Arena*)'
/usr/bin/ld: /tmp/ccZ5dEAo.o: in function `fixbug::ResultCode::ResultCode(fixbug::ResultCode const&)':
test.pb.cc:(.text+0x124): undefined reference to `google::protobuf::internal::ArenaStringPtr::Set(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, google::protobuf::Arena*)'
/usr/bin/ld: /tmp/ccZ5dEAo.o: in function `fixbug::ResultCode::Clear()':
test.pb.cc:(.text+0x24b): undefined reference to `google::protobuf::internal::ArenaStringPtr::ClearToEmpty()'
/usr/bin/ld: /tmp/ccZ5dEAo.o: in function `fixbug::ResultCode::ByteSizeLong() const':
test.pb.cc:(.text+0x5df): undefined reference to `google::protobuf::Message::MaybeComputeUnknownFieldsSize(unsigned long, google::protobuf::internal::CachedSize*) const'
/usr/bin/ld: /tmp/ccZ5dEAo.o: in function `fixbug::ResultCode::MergeFrom(fixbug::ResultCode const&)':
test.pb.cc:(.text+0x711): undefined reference to `google::protobuf::internal::ArenaStringPtr::Set(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, google::protobuf::Arena*)'
..........
/usr/bin/ld: /tmp/ccZ5dEAo.o:(.data.rel.ro+0x10): undefined reference to `google::protobuf::Message::CopyWithSizeCheck(google::protobuf::Message*, google::protobuf::Message const&)'
/usr/bin/ld: /tmp/ccZ5dEAo.o:(.data.rel.ro+0x20): undefined reference to `google::protobuf::Message::CopyWithSizeCheck(google::protobuf::Message*, google::protobuf::Message const&)'
/usr/bin/ld: /tmp/ccZ5dEAo.o: in function `fixbug::LoginRequest::SharedDtor()':
test.pb.cc:(.text._ZN6fixbug12LoginRequest10SharedDtorEv[_ZN6fixbug12LoginRequest10SharedDtorEv]+0x9e): undefined reference to `google::protobuf::internal::ArenaStringPtr::Destroy()'
/usr/bin/ld: test.pb.cc:(.text._ZN6fixbug12LoginRequest10SharedDtorEv[_ZN6fixbug12LoginRequest10SharedDtorEv]+0xae): undefined reference to `google::protobuf::internal::ArenaStringPtr::Destroy()'
collect2: error: ld returned 1 exit status
粗鲁看了一下,上面的错误信息,发现是编译test.proto生成的test.pb.cc中的一些函数没有办法找到protobuf中的定义。换句话说,在我们编译main.cc的时候,没有提供给编译器protobuf的动态库或者静态库的位置,导致-lprotobuf无法找到protobuf的动态库和静态库。
2.寻找protobuf库
我们使用locate命令:
locate libprotobuf
如果之前成功安装protobuf,那么会出现它的库所在目录:
/usr/local/lib/libprotobuf-lite.a
/usr/local/lib/libprotobuf-lite.la
/usr/local/lib/libprotobuf-lite.so
/usr/local/lib/libprotobuf-lite.so.31
/usr/local/lib/libprotobuf-lite.so.31.0.2
/usr/local/lib/libprotobuf.a
/usr/local/lib/libprotobuf.la
/usr/local/lib/libprotobuf.so
/usr/local/lib/libprotobuf.so.31
/usr/local/lib/libprotobuf.so.31.0.2
我们发现动态库和静态库在/usr/local/lib目录下。
3. 重新执行失败命令
我们重新执行失败命令,在原来基础上,添加库的定位信息,使用-L操作,具体如下:
g++ main.cc test.pb.cc -o main -L/usr/local/lib/ -lprotobuf
-L表示库所在目录;
-l表示使用的库名称,会自动忽略lib前缀、.a后缀、.so后缀等,比如说有libxxx.a和libxxx.so库,那么我们只需要使用xxx名字即可,正如这个例子所使用的protobuf一样。
编译成功:
.
├── main
├── main.cc
├── test.pb.cc
├── test.pb.h
└── test.proto
上面的main就是可执行程序,执行效果如下:
lijizhi 123456789
lijizhi
123456789
4. 代码附录
main.cc
#include "test.pb.h"
#include <iostream>
#include <string>
using namespace fixbug;
int main()
{
LoginRequest req;
req.set_name("lujizhi");//用户名
req.set_pwd("123456789");//密码:123456789
//将req数据序列化
std::string send_str;
if (req.SerializeToString(&send_str))
{
std::cout << send_str.c_str() << std::endl;
}
//将req数据反序列化
LoginRequest reqA;
if (reqA.ParseFromString(send_str))
{
std::cout << reqA.name() << std::endl;
std::cout << reqA.pwd() << std::endl;
}
return 0;
}
test.proto
syntax = "proto3";//设置protobuf版本
//声明代码所在包,相当于C++的namespace,在引入由这份文件生成的.cc文件和.h文件时,
//需要using namespace fixbug
package fixbug;
//message相当于C++中的类或结构体
message ResultCode//封装失败消息类
{
int32 errcode = 1;//表示第1字段
bytes errmsg = 2;//表示第2字段,protobuf中bytes相当于C++中的string
}
//定义登录请求
message LoginRequest
{
bytes name = 1;//表示第1字段
bytes pwd = 2;//表示第2字段
}
//定义响应登录请求
message LoginResponse
{
ResultCode result = 1;//表示第1字段
bool success = 2;//表示第2字段
}