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)

解決方案:

  1. 根據你編譯的的庫看你Qt編譯debug還是release下
  2. 嘗試在.pro中添加DEFINES += PROTOBUF_USE_DLLS

靜態庫版本的protoc.exe和動態庫版本protoc.exe對.proto處理后生成的文件是相同的。這個是自己做實驗得到的結果。
問題2:windows + Qt 中使用protobuf靜態庫版本遇到的問題:
在這里插入圖片描述
這就是為什么在windows上要編譯動態庫了,靜態庫試了一下總會出現這樣的問題,參考網友在.pro中添加了MTd方式,繼續出現這樣的問題,原因可能是和免費的Qt使用的是動態庫版本有關

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM