Qt for Android explore the use of grpc

Grpc need to use Qt use on Android * .a static library, compiled on Windows lib libraries, and compiled by the linux .a, has been tried, were unable to successfully link. This article attempts to compile using the NDK Android version of grpc static library.

Preface
on Qt for Android to use grpc, need to use the corresponding static library files Android architecture, summarize records in Ubuntu

Preparations
install git: sudo apt install git
install cmake: sudo apt install cmake
install build tools: sudo apt-get install build- essential autoconf libtool
Download Android NDK: android-ndk-r18b-linux-x86_64.zip
installation GRPC:
$ mkdir & cd git git
$ git clone https://github.com/grpc/grpc
$ cd GRPC
$ git submodule Update --init

Compiler
environment: Ubuntu18.04
using the Android NDK cross compiler tool chain:
$ cd ../ & mkdir GRPC-Build
$ vim compile.sh enter the following script content
# / bin / SH!
Cd / Home / yakong / git / GRPC-Build
NDK_ROOT = Export / Home / yakong / Downloads / Android-NDK-R 16b
CMake / Home / yakong / Git / GRPC / \
-DCMAKE_TOOLCHAIN_FILE} = $ {NDK_ROOT /build/cmake/android.toolchain.cmake \
-DANDROID_ABI = armeabi-V7a \
-DANDROID_PLATFORM = Android-24 \
-DANDROID_STL = C ++ static _ \
-DRUN_HAVE_STD_REGEX = 0 \
-DRUN_HAVE_POSIX_REGEX = 0 \
-DRUN_HAVE_STEADY_CLOCK = 0 \
-DCMAKE_BUILD_TYPE = Release
CMake --build. --target GRPC ++

The X-./compile.sh chmod + $
$ ./compile.sh
after successfully built, each generation * .a static library files grpc-build

Qt for Android use
environment: Windows10 + Qt5.12.3 + Android NDK r18b + 9 phone Huawei glory
after the new QtgRPC-Server applications, as well as links to third-party protobuffer good grpc such as static libraries, building appear undefined reference to `rand / stderr / strtof ` link error, please see the Appendix section to solve.
After the program build package generated apk, install and run on an Android device directly collapse quit, suggesting Protocol Buffer version mismatch error, see Appendix solve chapters.
Program can be up and running on Android real machine, but watch log shows like? grpc service does not start up, the application output window has the following red error (read):

Wave just flat after another, wave after wave of really continue Daguai! However, I run directly Console server (QtgRPC-Server), and Qt Widget client (grpc-client), results show that can communicate, ha ha, the red part of the log does not affect the results of the final run:

 

At this point, based on the Qt C ++ cross-platform, Qt for Android calling grpc success!

 

附录
1. /bin/sh: 1: go: not found错误
[ 15%] Generating err_data.c
/bin/sh: 1: go: not found
third_party/boringssl/crypto/err/CMakeFiles/err.dir/build.make:83: recipe for target 'third_party/boringssl/crypto/err/err_data.c' failed
make[3]: *** [third_party/boringssl/crypto/err/err_data.c] Error 127
make[3]: *** Deleting file 'third_party/boringssl/crypto/err/err_data.c'
CMakeFiles/Makefile2:3345: recipe for target 'third_party/boringssl/crypto/err/CMakeFiles/err.dir/all' failed
make[2]: *** [third_party/boringssl/crypto/err/CMakeFiles/err.dir/all] Error 2
CMakeFiles/Makefile2:1016: recipe for target 'CMakeFiles/grpc++.dir/rule' failed
make[1]: *** [CMakeFiles/grpc++.dir/rule] Error 2
Makefile:463: recipe for target 'grpc++' failed
make: *** [grpc++] Error 2

The reason for the lack of go-compiler environment
to solve: sudo APT install golang

2. 查看*.a架构信息
yakong@ubuntu:~/git/grpc-build/third_party/protobuf$ ls
CMakeFiles lib Makefile protobuf.pc
cmake_install.cmake libprotobuf.a protobuf-lite.pc
yakong@ubuntu:~/git/grpc-build/third_party/protobuf$ file libprotobuf.a
libprotobuf.a: current ar archive
yakong@ubuntu:~/git/grpc-build/third_party/protobuf$ lipo -info libprotobuf.a

Command 'lipo' not found, did you mean:

command 'lilo' from deb lilo

Try: sudo apt install <deb name>

yakong@ubuntu:~/git/grpc-build/third_party/protobuf$ readelf -h libprotobuf.a | grep 'Class\|File\|Machine'
File: libprotobuf.a(any_lite.cc.o)
Class: ELF32
Machine: ARM
File: libprotobuf.a(arena.cc.o)
Class: ELF32
Machine: ARM

Reference to undefined `RAND 3. / stderr / strtof`
Android use Qt for grpc link error:

The article pointed out that, after NDK15, standard IO devices: stderr, etc. are not supported by the ~
careful find I'm using r16b version of the compiler grpc, and use it in Qt Creator is r18b version, the version does not match, it may cause influences.

However, I will use Qt ndk version of the Creator replaced r16b, the same error:

 Once again, I use r18b version ndk be grpc compiled on Ubuntu, or similar error occurs:

A position control error, the source grpc modifications:
1) using the rand () to a position of a fixed value, such as 1 (arbitrary random integer value)
2) where the use of comment out stderr, does not affect the function
3) the strtof strtod or modified to use low version ndk
after recompile, reload in Qt, the more fortunate, successfully constructed a ~

Attached: NDK versions Download

4. 运行错误:Protocol Buffer版本不匹配
This program requires version 3.9.0 of the Protocol Buffer runtime library, but the installed version is 3.8.0. Please update your library. If you compiled the program yourself, make sure that your headers are from the same version of Protocol Buffers as your link-time library.

 

 

Analysis: I'm using version ndk protobuf used to compile grpc in Ubuntu 3.8.0, and protoc command I use in qt for android generated in version 3.9.0 * .pb.cc is generated. So, I hope * .pb.cc also be generated by the 3.8.0 version of protobuf compiler.
: Protobuf compiler compiler generated
$ ./grpc/third_party/protobuf
$ / autogen.sh.
$ / The configure.
$ The make     // time-consuming
$ [sudo] make install
error occurred while performing -version Protoc:
Protoc: error loading the while shared libraries: libprotoc.so.19: can not open shared object file: No such file or directory

The article states: protobuf default installation path is / usr / local / lib, and / usr / local / lib is not in the default Ubuntu system in the LD_LIBRARY_PATH, so I can not find the lib

Solution:
1. Create a file in the directory /etc/ld.so.conf.d libprotobuf.conf write to: / usr / local / lib
2. Enter the command to reset the contents of the entry into force: sudo ldconfig
At this time, then run protoc -version you can normally see the version number

Executed in grpc directory:
$ the make
incorrect report: zconf.h not found

Solution: sudo APT-GET install zlib1g-dev
again make, compiling a long, wait ...
$ sudo the make install
Then compile comes cpp example helloworld:

The resulting helloworld.pb.h / cpp and helloworld.grpc.pb.h / cpp copy qt use in the project, and include the header files can also use the same set, otherwise there will be " #error This File Generated by WAS AN older Which of Protoc iS ^ Version "error:

After this success down to build, run, do not run it does not lead to the collapse of the Times protobuf version ~

5. Qt project pro file is set
to increase: DEFINES + = _WIN32_WINNT = 0x0600
increase include paths and link static library path:

INCLUDEPATH += $$PWD/../../include
DEPENDPATH += $$PWD/../../include

unix:!macx: LIBS += -L$$PWD/../../grpc-build-r18b/ -lgrpc++
unix:!macx: PRE_TARGETDEPS += $$PWD/../../grpc-build-r18b/libgrpc++.a

unix:!macx: LIBS += -L$$PWD/../../grpc-build-r18b/ -lgrpc
unix:!macx: PRE_TARGETDEPS += $$PWD/../../grpc-build-r18b/libgrpc.a

unix:!macx: LIBS += -L$$PWD/../../grpc-build-r18b/ -lgpr
unix:!macx: PRE_TARGETDEPS += $$PWD/../../grpc-build-r18b/libgpr.a

unix:!macx: LIBS += -L$$PWD/../../grpc-build-r18b/ -laddress_sorting
unix:!macx: PRE_TARGETDEPS += $$PWD/../../grpc-build-r18b/libaddress_sorting.a

unix:!macx: LIBS += -L$$PWD/../../grpc-build-r18b/third_party/protobuf/ -lprotobuf
unix:!macx: PRE_TARGETDEPS += $$PWD/../../grpc-build-r18b/third_party/protobuf/libprotobuf.a

unix:!macx: LIBS += -L$$PWD/../../grpc-build-r18b/third_party/zlib/ -lz
unix:!macx: PRE_TARGETDEPS += $$PWD/../../grpc-build-r18b/third_party/zlib/libz.a

unix:!macx: LIBS += -L$$PWD/../../grpc-build-r18b/third_party/boringssl/ssl/ -lssl
unix:!macx: PRE_TARGETDEPS += $$PWD/../../grpc-build-r18b/third_party/boringssl/ssl/libssl.a

unix:!macx: LIBS += -L$$PWD/../../grpc-build-r18b/third_party/cares/cares/lib/ -lcares
unix:!macx: PRE_TARGETDEPS += $$PWD/../../grpc-build-r18b/third_party/cares/cares/lib/libcares.a

Note : ./src/google which include paths comprises grpc header file and in the file protobuf

6. Qt test engineering part of the code

Helloworld.proto
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 
syntax =  "proto3" ;

option java_multiple_files = 
true ;
option java_package = 
"io.grpc.examples.helloworld" ;
option java_outer_classname = 
"HelloWorldProto" ;
option objc_class_prefix = 
"HLW" ;

package helloworld;

// The greeting service definition.
service Greeter {
  
// Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 
1 ;
  
float  score =  2 ;
}

// The response message containing the greetings
message HelloReply {
  string message = 
1 ;
  
float  score =  2 ;
}
  • Server QtgRPC-Server
 main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
 
#include  <QCoreApplication>

#include  <iostream>
#include  <memory>
#include  <string>

#include  <grpc++/grpc++.h>
#include   "helloworld.pb.h"
#include   "helloworld.grpc.pb.h"

using  grpc::Server;
using  grpc::ServerBuilder;
using  grpc::ServerContext;
using  grpc::Status;
using  helloworld::HelloRequest;
using  helloworld::HelloReply;
using  helloworld::Greeter;

// Logic and data behind the server's behavior.
class  GreeterServiceImpl final :  public  Greeter::Service {
  Status SayHello(ServerContext* context, 
const  HelloRequest* request,
                  HelloReply* reply) override {
    std::string prefix(
"Hello " );
    reply->set_message(prefix + request->name());
    reply->set_score(request->score());
    
return  Status::OK;
  }
};

void  RunServer() {
  std::cout << 
"RunServer() "  << std::endl;
  std::string server_address(
"0.0.0.0:50051" );
  GreeterServiceImpl service;

  ServerBuilder builder;
  
// Listen on the given address without any authentication mechanism.
  builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
  
// Register "service" as the instance through which we'll communicate with
   // clients. In this case it corresponds to an *synchronous* service.
  builder.RegisterService(&service);
  
// Finally assemble the server.
  std::unique_ptr<Server> server(builder.BuildAndStart());
  std::cout << 
"Server listening on "  << server_address << std::endl;

  
// Wait for the server to shutdown. Note that some other thread must be
   // responsible for shutting down the server for this call to ever return.
  server->Wait();
}

int  main( int  argc,  char  *argv[])
{
    std::cout << 
"main(int argc, char *argv[]) "  << std::endl;
    
//QCoreApplication a(argc, argv);
     //return a.exec();

    RunServer();
    
return   0 ;
}
  • The client grpc-client

 

 Widget.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
 
#ifndef  WIDGET_H
#define  WIDGET_H

#include  <QWidget>

#include  <iostream>
#include  <memory>
#include  <string>

#include  <grpcpp/grpcpp.h>
#include  <limits>

#include   "helloworld.grpc.pb.h"

using  grpc::Channel;
using  grpc::ClientContext;
using  grpc::Status;
using  helloworld::HelloRequest;
using  helloworld::HelloReply;
using  helloworld::Greeter;

class  GreeterClient {
 
public :
  GreeterClient(std::shared_ptr<Channel> channel)
      : stub_(Greeter::NewStub(channel)) {}

  
// Assembles the client's payload, sends it and presents the response back
   // from the server.
  std::string SayHello( const  std::string& user) {
    
// Data we are sending to the server.
    HelloRequest request;
    request.set_name(user);

    
// Container for the data we expect from the server.
    HelloReply reply;

    
// Context for the client. It could be used to convey extra information to
     // the server and/or tweak certain RPC behaviors.
    ClientContext context;

    
// The actual RPC.
    Status status = stub_->SayHello(&context, request, &reply);

    
// Act upon its status.
     if  (status.ok()) {
      
return  reply.message();
    } 
else  {
      std::cout << status.error_code() << 
": "  << status.error_message()
                << std::endl;
      
return   "RPC failed" ;
    }
  }

  
float  SayScore( const   float  score = std::numeric_limits< float >::max()) {
    
// Data we are sending to the server.
    HelloRequest request;
    request.set_score(score);

    
// Container for the data we expect from the server.
    HelloReply reply;

    
// Context for the client. It could be used to convey extra information to
     // the server and/or tweak certain RPC behaviors.
    ClientContext context;

    
// The actual RPC.
    Status status = stub_->SayHello(&context, request, &reply);

    
// Act upon its status.
     if  (status.ok()) {
      
return  reply.score();
    } 
else  {
      std::cout << status.error_code() << 
": "  << status.error_message()
                << std::endl;
      
return   3 .14f;
    }
  }

 
private :
  std::unique_ptr<Greeter::Stub> stub_;
};

class  QTextBrowser;
class  Widget :  public  QWidget
{
    Q_OBJECT

public :
    Widget(QWidget *parent = nullptr);
    ~Widget();

private  slots:
    
void  req();

private :
    QTextBrowser *text;
};

#endif // WIDGET_H

 Widget.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
 
#include   "Widget.h"
#include  <QVBoxLayout>
#include  <QTextBrowser>
#include  <QPushButton>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , text(
new  QTextBrowser())
{
    setWindowTitle(tr(
"grpc-client" ));
    resize(
320 460 );

    QVBoxLayout *layout = 
new  QVBoxLayout( this );
    QPushButton *button = 
new  QPushButton( "req" );
    connect(button, &QPushButton::clicked, 
this , &Widget::req);
    layout->addWidget(text);
    layout->addWidget(button);
    setLayout(layout);
}

Widget::~Widget()
{

}

void  Widget::req()
{
    
// Instantiate the client. It requires a channel, out of which the actual RPCs
     // are created. This channel models a connection to an endpoint (in this case,
     // localhost at port 50051). We indicate that the channel isn't authenticated
     // (use of InsecureChannelCredentials()).
    GreeterClient greeter(grpc::CreateChannel(
                              
"localhost:50051" , grpc::InsecureChannelCredentials()));
    std::string user(
"world" );
    std::string reply = greeter.SayHello(user);

    
float  replyf= greeter.SayScore();
    std::cout << 
"Greeter received: "  << reply << std::endl;
    std::cout << 
"Greeter received: "  << replyf << std::endl;
    
if  (text != nullptr){
        text->append(QString(
"Greeter received: %1" ).arg(reply.c_str()));
        text->append(QString(
"Greeter received: %1" ).arg(replyf));
    }
}

Guess you like

Origin www.cnblogs.com/MakeView660/p/11544496.html