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()
{
}
Author: P Shved, 2010-03-01

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

 38
Author: Dmitry Yudakov,
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
 13
Author: P Shved,
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.

 2
Author: David,
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.

 1
Author: bmargulies,
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