幼敏悟过人,读书辄成诵。这篇文章主要讲述构建使用协议缓冲区的Android可执行gRPC服务器(不使用APK)相关的知识,希望能为你提供帮助。
我从here编译了gRPC android示例。
我想从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})
【构建使用协议缓冲区的Android可执行gRPC服务器(不使用APK)】然后我推送生成的可执行文件和libs文件并尝试运行它:
LD_LIBRARY_PATH=. ./avocado
我收到以下错误:
[libprotobuf FATAL /home/buga/grpc/third_party/protobuf/src/google/protobuf/stubs/common.cc:79]这个程序是针对Protocol Buffer运行时库的3.0.0版编译的,它与安装版本(3.5.1)。请与程序作者联系以获取更新。如果您自己编译了程序,请确保您的标题来自与链接时库相同的Protocol Buffers版本。 (版本验证在“out / soong / .intermediates / frameworks / av / drm / libmediadrm / libmediadrm / android_arm64_armv8-a_kryo300_shared_core / gen / proto / frameworks / av / drm / libmediadrm / protos / plugin_metrics.pb.cc”中失败。)终止与google :: protobuf :: FatalException类型的未捕获异常:此程序是针对协议缓冲区运行时库的3.0.0版编译的,该版本与已安装的版本(3.5.1)不兼容。请与程序作者联系以获取更新。如果您自己编译了程序,请确保您的标题来自与链接时库相同的Protocol Buffers版本。 (版本验证在“out / soong / .intermediates / frameworks / av / drm / libmediadrm / libmediadrm / android_arm64_armv8-a_kryo300_shared_core / gen / proto / frameworks / av / drm / libmediadrm / protos / plugin_metrics.pb.cc”中失败。)中止我究竟做错了什么?
我们意识到有一个名为
libprotobuf-cpp-full.so
和libprotobuf-cpp-lite.so
的protobuf库的版本,它们的版本似乎是3.0.0。这与我们的版本(3.5.1)相冲突,它被编译成静态库或共享库。答案我不太清楚为什么会这样。一旦链接器加载
helloworld_proto_lib
,它会覆盖所有加载的protobuf符号,并且由于某种原因,与你无关的另一个库会崩溃你的程序。但这并没有告诉你任何新的东西。这是解决此问题的一种方法:
1. Changes to grpc-helloworld.cc
制作主要的
extern "C"
,并改变它的名字。例如: extern "C" int my_main() {
std::cout <
<
"qwerty" <
<
std::endl;
return 0;
}
2. Add file grpc-avocado.cc
这将包含可执行文件的实际主要内容,它将动态加载库
helloworld_proto_lib
和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_SONAME,并且某些其他库在其DT_NEEDED列表中具有soname,则第一个库将用于解析任何依赖项。
3. Change CMakeLists.txt
由于您将动态加载
helloworld_proto_lib
,现在可以从可执行文件定义中删除它,并且不需要任何proto头:add_executable(avocado
src/main/cpp/grpc-avocado.cc)target_link_libraries(avocado
android
${log-lib})
Build, push, and run
你现在可以构建,推送可执行文件
avocado
和两个库libgrpc-helloworld.so
,libhelloworld_proto_lib.so
,然后运行。你不需要LD_LIBRARY_PATH
。祝你项目的其余部分好运!推荐阅读
- 在android ndk中使用ubuntu header lib
- Android studio 3.1.3创建新项目,c ++支持同步失败
- 在没有Android Studio的情况下为Android创建(Cmake)C / C ++库
- Android NDK“ndk-build”被识别为内部或外部命令批处理文件
- 将cpp类添加到android项目中
- 如何使用Android.mk为不同的平台指定不同的CFLAGS
- 如何在Android上进行SSL对等验证工作()
- 在android NDK中包含本地头文件时的未定义引用
- 平台android NDK不支持ABIs [armeabi,mips]