Создание исполняемого сервера gRPC для Android, использующего буфер протокола (без APK) - PullRequest
0 голосов
/ 06 сентября 2018

Я скомпилировал пример gRPC Android из здесь .

Я хочу запустить программу как исполняемый файл из оболочки adb.

Добавлены эти строки в 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})

Затем я нажал на сгенерированный исполняемый файл и файл libs и попытался запустить его:

LD_LIBRARY_PATH=. ./avocado

Я получил следующую ошибку:

[libprotobuf FATAL /home/buga/grpc/third_party/protobuf/src/google/protobuf/stubs/common.cc:79] Эта программа была скомпилирована против версии 3.0.0 протокола Buffer библиотека времени выполнения, несовместимая с установленной версией (3.5.1). Свяжитесь с автором программы для обновления. Если вы скомпилировали программа сама, убедитесь, что ваши заголовки из того же версия протокола Buffers в качестве библиотеки ссылок. (Версия проверка не удалась в "Выход / Сунг / .intermediates / рамки / AV / ЦУП / libmediadrm / libmediadrm / android_arm64_armv8-a_kryo300_shared_core / ген / прото / рамки / AV / ЦУП / libmediadrm / протос / plugin_metrics.pb.cc".) Прекращение с неперехваченным исключением типа google :: protobuf :: FatalException: это Программа была скомпилирована с версией 3.0.0 буфера протокола библиотека времени выполнения, несовместимая с установленной версией (3.5.1). Свяжитесь с автором программы для обновления. Если вы скомпилировали программа сама, убедитесь, что ваши заголовки из того же версия протокола Buffers в качестве библиотеки ссылок. (Версия проверка не удалась в "Выход / Сунг / .intermediates / рамки / AV / ЦУП / libmediadrm / libmediadrm / android_arm64_armv8-a_kryo300_shared_core / ген / прото / рамки / AV / ЦУП / libmediadrm / протос / plugin_metrics.pb.cc".) Отменено

Что я делаю не так?

Мы поняли, что существует версия библиотеки protobuf с именами libprotobuf-cpp-full.so и libprotobuf-cpp-lite.so, и, похоже, их версия 3.0.0. Это противоречит нашей версии (3.5.1), которая компилируется либо в статическую библиотеку, либо в общую библиотеку.

1 Ответ

0 голосов
/ 06 сентября 2018

Я не совсем уверен, почему это происходит. Кое-что о том, как компоновщик загружает helloworld_proto_lib, он переопределяет все загруженные символы protobuf, и по какой-то причине другая библиотека, к которой вы не имели никакого отношения, приводит к сбою вашей программы. Но это не говорит вам ничего нового.

Вот один из способов решения этой проблемы:

1. Изменения в grpc-helloworld.cc

Сделайте основной extern "C" и измените его имя, может быть. Например:

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

2. Добавить файл 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. Изменить CMakeLists.txt

Поскольку вы будете загружать helloworld_proto_lib динамически, теперь вы можете удалить его из определения исполняемого файла, и нет необходимости в каких-либо прото-заголовках:

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. Удачи с остальной частью вашего проекта!

...