Неопределенный символ в C , когда функция, объявленная в заголовке, определена пользователем

#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 и все начинает работать нормально.

Я сейчас очень смущен относительно:

  1. Почему eglGetNativeClientBufferANDROID его не забирают у Б. обь?
  2. Что _ДИНАМИЧЕСКОЕ означает в 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) {...}