代码之家  ›  专栏  ›  技术社区  ›  Michael Litvin chris mcelroy

构建使用协议缓冲区(无APK)的Android可执行gRPC服务器

  •  2
  • Michael Litvin chris mcelroy  · 技术社区  · 6 年前

    here .

    我想从adb shell以可执行文件的形式运行程序。

    将这些行添加到 grpc-helloworld.cc

    #include <iostream>
    
    int main() {
      std::cout << "qwerty" << std::endl;
      return 0;
    }
    

    这些线条 CMakeLists.txt :

    add_executable(avocado
        src/main/cpp/grpc-helloworld.cc)
    
    target_include_directories(avocado
      PRIVATE ${HELLOWORLD_PROTO_HEADERS})
    
    target_link_libraries(avocado
      helloworld_proto_lib
      android
      ${log-lib})
    

    LD_LIBRARY_PATH=. ./avocado

    我得到以下错误:

    [libprotobuf致命 这个程序是根据3.0.0版本的协议缓冲区编译的 运行时库,与安装的版本不兼容 (3.5.1). 请与程序作者联系以获取更新。如果你编译 “out/soong/.intermediates/frameworks/av/drm/libmediadrm/libmediadrm/android\u arm64\u armv8-a\u kryo300\u shared\u core/gen/proto/frameworks/av/drm/libmediadrm/protos/plugin_度量.pb.cc“)终止 类型为google::protobuf::FatalException的未捕获异常:This 程序是根据3.0.0版本的协议缓冲区编译的 (3.5.1). 请与程序作者联系以获取更新。如果你编译 中的验证失败 “out/soong/.intermediates/frameworks/av/drm/libmediadrm/libmediadrm/android\u arm64\u armv8-a\u kryo300\u shared\u core/gen/proto/frameworks/av/drm/libmediadrm/protos/plugin_度量.pb.cc".) 中止

    我们意识到protobuf库的一个版本叫做 libprotobuf-cpp-full.so libprotobuf-cpp-lite.so ,看起来他们的版本是3.0.0。这与我们的版本(3.5.1)相冲突,该版本被编译为静态库或共享库。

    1 回复  |  直到 6 年前
        1
  •  1
  •   Dror Speiser    6 年前

    我不太清楚为什么会这样。一旦链接器加载 helloworld_proto_lib ,它会覆盖所有加载的protobuf符号,并且由于某种原因,与您无关的另一个库会使您的程序崩溃。但这并没有告诉你什么新鲜事。

    有一种方法可以解决这个问题:

    1grpc变更-你好世界.cc

    extern "C" ,并可能更改其名称。例如:

     extern "C" int my_main() {
      std::cout << "qwerty" << std::endl;
      return 0;
    }
    

    这将包含可执行文件的实际main,它将动态加载库 helloworld\u协议库 grpc-helloworld . 以下是操作方法:

    #include <iostream>
    #include <android/dlext.h>
    #include <dlfcn.h>
    
    int main() {
      android_dlextinfo extinfo;
      extinfo.flags = ANDROID_DLEXT_FORCE_LOAD;
    
      void* proto_lib = android_dlopen_ext("/path/to/libhelloworld_proto_lib.so", RTLD_LAZY, &extinfo);
      void* helloworld = dlopen("/path/to/libgrpc-helloworld.so", RTLD_LAZY);
      int (*my_main)() = (int (*)())dlsym(helloworld, "my_main");
    
      return my_main();
    }
    

    函数 android_dlopen_ext #include <android/dlext.h> ,及其标志参数如下所述: https://developer.android.com/ndk/reference/group/libdl . 在上面的代码中,我们传递标志 ANDROID_DLEXT_FORCE_LOAD

    设置后,不要使用stat(2)检查库是否已加载。

    当由于某种原因多个ELF文件共享同一文件名时(例如,因为已加载的库已被删除和覆盖),此标志允许强制加载库。

    请注意,如果库与旧库具有相同的DT\u SONAME,而其他库在其DT\u NEEDED列表中具有该SONAME, .

    三。改变CMakeLists.txt文件

    既然你要装 动态地,您现在可以将其从可执行文件定义中删除,并且不需要任何proto头文件:

    add_executable(avocado
        src/main/cpp/grpc-avocado.cc)
    
    target_link_libraries(avocado
      android
      ${log-lib})
    

    构建、推送和运行

    现在可以构建、推送可执行文件 avocado 两个图书馆 libgrpc-helloworld.so , libhelloworld_proto_lib.so LD_LIBRARY_PATH