編譯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使用的是動態庫版本有關