zoukankan      html  css  js  c++  java
  • 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使用的是动态库版本有关

    参考

  • 相关阅读:
    第三周作业
    2016-03-22 OneZero团队 Daily Scrum Meeting
    OneZero第一次随感
    软件项目管理(6)
    软件项目管理(5)
    软件项目管理(4)
    软件项目管理(3)
    软件项目管理(2)
    Personal Software Process (PSP)
    软件项目管理(1)
  • 原文地址:https://www.cnblogs.com/WindSun/p/12594801.html
Copyright © 2011-2022 走看看