Forzar a GCC a notificar sobre referencias indefinidas en bibliotecas compartidas
Tengo una biblioteca compartida que está vinculada con otra biblioteca compartida (de terceros). Mi biblioteca compartida se carga mediante dlopen en mi aplicación. Todo esto funciona bien (suponiendo que los archivos están en la ruta correcta, etc.).
Ahora, el problema es que ni siquiera necesito especificar para vincular con la biblioteca compartida de terceros cuando enlace mi biblioteca. GCC lo acepta sin reportar errores sobre referencias indefinidas. Entonces, la pregunta; ¿cómo puedo obligar a GCC a notificarme sobre undefined referencias?
Si cambio mi biblioteca para que sea (temporalmente) un ejecutable, obtengo referencias indefinidas (cuando no suministro la biblioteca al enlazador). (Funciona bien si lo especifico.)
Es decir, se hace lo siguiente:
g++ -fPIC -shared -o libb.so b.o
g++ -fPIC -shared -o liba.so a.o
g++ -o a.exe a.cpp
Donde la segunda línea NO da un error y la tercera línea se queja de una referencia indefinida.
Código de ejemplo:
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()
{
}
4 answers
-Wl, no no-undefined la opción de enlazador se puede usar cuando se construye una biblioteca compartida, los símbolos indefinidos se mostrarán como errores de enlazador.
G++ -shared-Wl,-soname,libmylib.so.5-Wl, no no-undefined-o libmylib.so.1.1 mylib.o-lthirdpartilib
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-01 15:30:23
Después de más investigación, me di cuenta de cómo funcionan las cosas. Hay dos opciones de enlazador para manipular símbolos indefinidos de bibliotecas compartidas:
El primero es --no-undefined
. Informa de los símbolos sin resolver que no se resuelven inmediatamente, en la etapa de enlace. A menos que el símbolo se encuentre en una biblioteca compartida enlazada, ya sea manualmente (con -l
switch) o automáticamente (libgcc_s
, C++ runtime; libc
, C runtime; ld-linux-**.so
, dynamic linker utils) elegido, --no-undefined
lo informa como error. Esa es la clave que necesitaba el interlocutor.
Hay otra clave, --no-allow-shlib-undefined
(cuya descripción también sugiere --no-undefined
). Comprueba si se cumplen las definiciones de las bibliotecas compartidas con las que vincula su biblioteca compartida. Esta clave es de poca utilidad en el caso que se muestra en este tema, pero puede ser útil. Sin embargo, tiene sus propios obstáculos.
La página de manual proporciona algunas razones sobre por qué no es predeterminada:
--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.
La cosa es que lo que se dice arriba es también es cierto, por ejemplo, para sistemas Linux, donde algunas de las rutinas internas de la biblioteca compartida se implementan en ld-linux.so
, el cargador dinámico (es tanto ejecutable como biblioteca compartida). A menos que lo vincules de alguna manera, obtendrás algo como esto:
/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'
Estas son referencias indefinidas del cargador, ld-linux.so
. Es específico de la plataforma(por ejemplo, en mi sistema el cargador correcto es /lib64/ld-linux-x86-64.so
). Puede vincular el cargador con su biblioteca y verificar incluso las referencias difíciles que se muestran arriba:
g++ -fPIC -shared -o liba.so a.o -Wl,--no-allow-shlib-undefined /lib64/ld-linux-x86-64.so.2
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-01 16:20:47
También hay una buena discusión de esto en la wiki de Mandriva.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-27 13:26:37
No se puede hacer que ld (que es lo que gcc está ejecutando) preste atención a una biblioteca que no está allí en el enlace. Puede desactivar RTLD_LAZY para obtener informes agresivos, y puede agregar una prueba unitaria que se ejecute justo después del enlace para eliminar estos problemas.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-01 13:57:54