#c #opengl-es #linker
Вопрос:
Я создаю библиотеку для Android. eglGetNativeClientBufferANDROID
функция доступна для Android .итак, выше 26, но я хочу, чтобы библиотека поддерживала все версии API 23. Поэтому я связываю свой файл с libEGL.so версия 23 и динамическая загрузка .таким образом, во время выполнения и получения функции из файла .so (это позволяет получить файл .so в реальном телефоне, который может быть более поздней версии).
Файл A.cpp:
...
#define EGL_EGLEXT_PROTOTYPES
#include <EGL/egl.h>
#include <EGL/eglext.h> // This provides declaration for eglGetNativeClientBufferANDROID
#include <GLES/gl.h>
...
EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(hardwareBuffer);
...
Файл B.cpp:
// defining my custom function for it
EGLClientBuffer eglGetNativeClientBufferANDROID(const struct AHardwareBuffer *buffer)
{
return doSomething();
}
Я связываю A.cpp и B.cpp то есть оба obj-файла связаны для формирования библиотеки. Однако я получаю следующую ошибку:
ld.lld: error: undefined symbol: eglGetNativeClientBufferANDROID
что не имело бы смысла, потому что оно было четко определено. Этот метод работал для нескольких других API, которые я динамически загружал из libandroid.so. Это вызвало у меня еще большее любопытство разобрать символы и посмотреть, что происходит.
Я вижу это по словам А. обь:
U eglGetNativeClientBufferANDROID
а это значит, что eglGetNativeClientBufferANDROID
это нужно проверить.
От Б. обь:
0000000000000000 T _Z31eglGetNativeClientBufferANDROIDPK15AHardwareBuffer
Таким образом, он четко определен, но он ищет другую таблицу, чтобы получить символы (а не из B. obj). Я был более любопытен и описал, как будут выглядеть другие символы из той же библиотеки:
Для A. символы obj для eglCreateImageKHR объявляются следующим образом:
U eglCreateImageKHR
Который он улавливает из libEGL.so что выглядит примерно так:
0000000000002000 d _DYNAMIC
...
0000000000001018 T eglCreateImageKHR
Ясно libEGL.so не предоставляет дополнительных сведений о типе и т.д. из своего символа.
Я изменил eglGetNativeClientBufferANDROID на eglGetNativeClientBufferANDROIDCustom, объявил об этом в A.cpp и все начинает работать нормально.
Я сейчас очень смущен относительно:
- Почему
eglGetNativeClientBufferANDROID
его не забирают у Б. обь? - Что _ДИНАМИЧЕСКОЕ означает в libEGL.so и почему в символах метода указаны только имена, а никакой другой информации о типе нет? (Я думаю, это потому, что egl загружает функции в fps только динамически, но я не уверен на 100%).
Кроме того, я не хотел менять имя eglGetNativeClientBufferANDROID на что-то другое, чтобы решить эту проблему, так как позже я мог бы удалить всю информацию о динамической загрузке.
Я решил эту проблему, решительно определив функцию в A.cpp как:
EGLClientBuffer eglGetNativeClientBufferANDROID(const struct AHardwareBuffer *buffer)
{
return doSomething();
}
и определение дозировки чего-либо в B.cpp.
Есть ли для этого какой-нибудь другой лучший способ?
Комментарии:
1. Может
extern "C"
быть, отсутствует?
Ответ №1:
Почему eglGetNativeClientBufferANDROID не берется из B. obj?
Поскольку экспортированный метод в B не соответствует объявлению в A.
Что
_DYNAMIC
означает в libEGL.so и почему в символах метода указаны только имена, а никакой другой информации о типе нет? (Я думаю, это потому, что egl загружает функции в fps только динамически, но я не уверен на 100%).
Поскольку «информация о типе» в вашем объекте B является результатом искажения имени C (поскольку C допускает перегрузку функций, когда одно и то же имя функции используется с разными типами аргументов, поэтому фактическое имя символа должно содержать всю подпись, чтобы компоновщик мог найти правильный вариант).
Если вы пишете C и хотите связать C, вы должны использовать extern "C"
квалификатор:
extern "C" EGLClientBuffer eglGetNativeClientBufferANDROID(const struct AHardwareBuffer *buffer) {...}