Qt中使用Protobuf简单案例(Windows + msvc)
编译protobuf
首先下载protobuf源代码
使用cmake,配置相关路径和配置
注意选择生成动态链接库,在windows上最好勾选动态链接库,否则会出现很多麻烦
点Generate,生成VS的工程文件。
然后打开vs,选择release或debug
点击解决方案直接右键选择生成解决方案即可。
注意:debug生成的库在Qt中只能在debug下使用,release生成的库只能在release下使用
Qt中使用Protobuf
编写.proto文件,使用protoc.exe编译成.h和.cc文件
将生成的.h和.cc文件复制到项目目录下
在项目根目录下新建protobuf目录,然后进入protobuf下创建include和lib目录,include目录包括protobuf源代码下的src下的google整个文件夹,lib下包括你VS编译后生成的.lib和.dll文件,在你的cmake设置的输出目录下的Debug或者release目录下,如下:
现在,创建一个Qt的widget项目,右键点击添加库
将你lib下的libprotobuf加入,include下位头文件声明
可以看到在.pro中加入了以下配置
# ==========protobuf==========
win32: LIBS += -L$$PWD/protobuf/lib/ -llibprotobuf
INCLUDEPATH += $$PWD/protobuf/include
DEPENDPATH += $$PWD/protobuf/include
然后编译时候根据你的库是release还是debug选择性编译
简单的案例
.proto 文件
syntax = "proto3";
package tutorial;
message Person {
required int32 id = 1;
required string name = 2;
optional string email = 3;
}
.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = protoTest
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
CONFIG += c++11
SOURCES += \
main.cpp \
person.pb.cc \
widget.cpp
HEADERS += \
person.pb.h \
widget.h
FORMS += \
widget.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
# ==========protobuf==========
DEFINES += PROTOBUF_USE_DLLS
win32: LIBS += -L$$PWD/protobuf/lib/ -llibprotobuf
INCLUDEPATH += $$PWD/protobuf/include
DEPENDPATH += $$PWD/protobuf/include
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include "person.pb.h"
#include <sstream>
#include <QFile>
#include <QDebug>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
GOOGLE_PROTOBUF_VERIFY_VERSION;
tutorial::Person person;
person.set_id(123456);
person.set_name("Mark");
person.set_email("137782866@qq.com");
//write
QFile file_out(QCoreApplication::applicationDirPath() + "/person.pb");
if(!file_out.open(QIODevice::WriteOnly)) {
qDebug() << "can not open file";
}
std::ostringstream streamOut;
person.SerializeToOstream(&streamOut);
QByteArray byteArray(streamOut.str().c_str());
QDataStream out(&file_out);
out << byteArray.length();
out.writeRawData(byteArray.data(), byteArray.length());
file_out.close();
//read
QFile file_in(QCoreApplication::applicationDirPath() + "/person.pb");
if(!file_in.open(QIODevice::ReadOnly)) {
qDebug() << "can not open file";
}
QDataStream in(&file_in);
int dataLength = 0;
in >> dataLength;
QByteArray byteArray2;
byteArray2.resize(dataLength);
in.readRawData(byteArray2.data(), dataLength);
tutorial::Person person2;
if (!person2.ParseFromArray(byteArray2.data(), byteArray2.size())) {
qDebug() << "Failed to parse person.pb.";
}
qDebug() << "ID: " << person.id();
qDebug() << "name: " << QString::fromStdString(person.name());
if (person.has_email()) {
qDebug() << "e-mail: " << QString::fromStdString(person.email());
}
file_in.close();
}
Widget::~Widget()
{
delete ui;
}
运行结果:
ID: 123456
name: "Mark"
e-mail: "137782866@qq.com"
遇到的问题
记录一下自己遇到的问题:
问题1:动态库版本和静态库版本使用一样,都是添加libprotobufd.lib,但动态库版本在Qt中编译会爆出这样的错误:
error: 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" (?fixed_address_empty_string@internal@protobuf@google@@3V?$ExplicitlyConstructed@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@123@A)
解决方案:
- 根据你编译的的库看你Qt编译debug还是release下
- 尝试在.pro中添加
DEFINES += PROTOBUF_USE_DLLS
静态库版本的protoc.exe和动态库版本protoc.exe对.proto处理后生成的文件是相同的。这个是自己做实验得到的结果。
问题2:windows + Qt 中使用protobuf静态库版本遇到的问题:
这就是为什么在windows上要编译动态库了,静态库试了一下总会出现这样的问题,参考网友在.pro中添加了MTd方式,继续出现这样的问题,原因可能是和免费的Qt使用的是动态库版本有关