У меня есть общая библиотека, которая связана с другим совместно использованная библиотека (третьего лица). Моя общая библиотека затем загружается с помощью dlopen в моем приложении. Все это хорошо работает (предположение, что файлы находятся в надлежащем пути и т.д.).
Теперь, проблема состоит в том, что я не должен даже указывать для соединения против совместно использованной библиотеки третьего лица, когда я связываю свою библиотеку. GCC принимают его, не сообщая об ошибках о неопределенных ссылках. Так, вопрос; как я могу вынудить GCC уведомить меня о неопределенных ссылках?
Если я изменяю свою библиотеку, чтобы быть (временно) исполняемым файлом, я получаю неопределенные ссылки (если не предоставляющий библиотеку компоновщику). (Хорошо работает, если я указываю его.)
Т.е. следующее сделано:
g++ -fPIC -shared -o libb.so b.o
g++ -fPIC -shared -o liba.so a.o
g++ -o a.exe a.cpp
Где вторая строка НЕ выделяет ошибку, и третья строка жалуется на неопределенную ссылку.
Пример кода:
a.h:
class a
{
public:
void foobar();
};
a.cpp:
#include "a.h"
#include "b.h"
void a::foobar()
{
b myB;
myB.foobar();
}
int main()
{
a myA; myA.foobar();
}
b.h:
class b
{
public:
void foobar();
};
b.cpp:
#include "b.h"
void b::foobar()
{
}
-Wl, - no-undefined параметр компоновщика может использоваться при построении разделяемой библиотеки, неопределенные символы будут отображаться как ошибки компоновщика.
g ++ -shared -Wl, -soname, libmylib.so.5 -Wl, - no-undefined -o libmylib.so.1.1 mylib.o -lthirdpartylib
После дополнительных исследований я понял, как это работает. Есть два варианта компоновщика для управления неопределенными символами разделяемых библиотек:
Первый - - no-undefined
. Он сообщает о неразрешенных символах, которые не разрешаются сразу на этапе связывания. Если символ не найден в совместно используемой библиотеке, с которой связана ссылка, либо вручную (с переключателем -l
), либо автоматически ( libgcc_s
, среда выполнения C ++; libc
, среда выполнения C ; ld-linux - **. So
, утилит динамического компоновщика) выбрано, - no-undefined
сообщает об ошибке. Это ключ, который нужен вопрошающему.
Есть еще один ключ, - no-allow-shlib-undefined
(описание которого также предполагает - no-undefined
). Он проверяет, удовлетворены ли определения в разделяемых библиотеках , с которыми вы связываете вашу разделяемую библиотеку с . В случае, показанном в этом разделе, от этого ключа мало пользы, но он может быть полезен. Однако у него есть свои препятствия.
Справочная страница дает некоторое объяснение, почему это не по умолчанию:
--allow-shlib-undefined
--no-allow-shlib-undefined
Allows (the default) or disallows undefined symbols in shared
libraries (It is meant, in shared libraries _linked_against_, not the
one we're creating!--Pavel Shved). This switch is similar to --no-un-
defined except that it determines the behaviour when the undefined
symbols are in a shared library rather than a regular object file. It
does not affect how undefined symbols in regular object files are
handled.
The reason that --allow-shlib-undefined is the default is that the
shared library being specified at link time may not be the same as
the one that is available at load time, so the symbols might actually
be resolvable at load time. Plus there are some systems, (eg BeOS)
where undefined symbols in shared libraries is normal. (The kernel
patches them at load time to select which function is most appropri-
ate for the current architecture. This is used for example to dynam-
ically select an appropriate memset function). Apparently it is also
normal for HPPA shared libraries to have undefined symbols.
Дело в том, что сказанное выше также верно, например, для систем Linux, где некоторые из внутренних процедур разделяемой библиотеки реализованы в ld-linux.so
, динамический загрузчик (это как исполняемая, так и разделяемая библиотека). Если вы каким-то образом не свяжете его, вы получите что-то вроде этого:
/lib64/libc.so.6: undefined reference to `_dl_argv@GLIBC_PRIVATE'
/lib64/libc.so.6: undefined reference to `_rtld_global_ro@GLIBC_PRIVATE'
/usr/lib64/gcc/x86_64-suse-linux/4.3/libstdc++.so: undefined reference to `__tls_get_addr@GLIBC_2.3'
/lib64/libc.so.6: undefined reference to `_rtld_global@GLIBC_PRIVATE'
/lib64/libc.so.6: undefined reference to `__libc_enable_secure@GLIBC_PRIVATE'
Это неопределенные ссылки из загрузчика, ld-linux.so
. Он зависит от платформы (например, в моей системе правильный загрузчик /lib64/ld-linux-x86-64.so
). Вы можете связать загрузчик со своей библиотекой и проверить даже сложные ссылки, показанные выше:
g++ -fPIC -shared -o liba.so a.o -Wl,--no-allow-shlib-undefined /lib64/ld-linux-x86-64.so.2
Вы не можете заставить ld (это то, что работает gcc) обратить внимание на библиотеку, которая нет в ссылке. Вы можете отключить RTLD_LAZY, чтобы получать агрессивные отчеты, и вы можете добавить модульный тест, который запускается сразу после ссылки, просто чтобы устранить эти проблемы.