Я не совсем уверен, почему это происходит. Кое-что о том, как компоновщик загружает 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
. Удачи с остальной частью вашего проекта!