web-dev-qa-db-fra.com

Forcer GCC à notifier les références non définies dans les bibliothèques partagées

J'ai une bibliothèque partagée liée à une autre bibliothèque partagée (tierce). Ma bibliothèque partagée est ensuite chargée à l'aide de dlopen dans mon application. Tout cela fonctionne bien (en supposant que les fichiers sont dans le bon chemin, etc.).

Maintenant, le problème est que je n'ai même pas besoin de spécifier un lien avec la bibliothèque partagée tierce lorsque je lie ma bibliothèque. GCC l'accepte sans signaler d'erreurs concernant les références non définies. Donc, la question; comment puis-je forcer GCC à me notifier les références non définies?

Si je change ma bibliothèque pour qu'elle soit (temporairement) un exécutable, j'obtiens des références non définies (lorsque je ne fournis pas la bibliothèque à l'éditeur de liens). (Fonctionne bien si je le spécifie.)

C'est-à-dire que ce qui suit est effectué:

g++ -fPIC -shared -o libb.so b.o 
g++ -fPIC -shared -o liba.so a.o
g++ -o a.exe a.cpp 

Où la deuxième ligne ne donne PAS d'erreur et la troisième ligne se plaint d'une référence non définie.

Exemple de code:

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()
{
}
48
Fredrik Ullner

- Wl, - no-undefined L'option de l'éditeur de liens peut être utilisée lors de la construction d'une bibliothèque partagée, les symboles non définis seront affichés comme des erreurs de l'éditeur de liens.

g ++ -shared -Wl, -soname, libmylib.so.5 -Wl, - no-undefined -o libmylib.so.1.1 mylib.o -lthirdpartylib

49
Dmitry Yudakov

Après plus de recherches, j'ai réalisé comment les choses fonctionnaient. Il existe deux options de l'éditeur de liens pour manipuler les symboles non définis des bibliothèques partagées:

Le premier est --no-undefined. Il signale les symboles non résolus qui ne sont pas résolus immédiatement, au stade de la liaison. Sauf si le symbole se trouve dans une bibliothèque partagée liée, soit manuellement (avec -l switch) ou automatiquement (libgcc_s, Runtime C++; libc, runtime C; ld-linux-**.so, utilitaires de l'éditeur de liens dynamiques) sélectionnés, --no-undefined le signale comme une erreur. C'est la clé dont l'intervenant avait besoin.

Il y a une autre clé, --no-allow-shlib-undefined (dont la description suggère également --no-undefined). Il vérifie si les définitions dans les bibliothèques partagées auxquelles vous liez votre bibliothèque partagée sont satisfaites. Cette clé est peu utile dans le cas présenté dans cette rubrique, mais elle peut être utile. Cependant, il a ses propres obstacles.

La page de manuel explique pourquoi ce n'est pas le cas par défaut:

   --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.

Le fait est que ce qui est dit ci-dessus est également vrai, par exemple, pour les systèmes Linux, où certaines des routines internes de la bibliothèque partagée sont implémentées dans ld-linux.so, le chargeur dynamique (c'est à la fois une bibliothèque exécutable et partagée). À moins que vous ne le liez d'une manière ou d'une autre, vous obtiendrez quelque chose comme ceci:

/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'

Ce sont des références indéfinies du chargeur, ld-linux.so. Il est spécifique à la plate-forme (par exemple, sur mon système, le chargeur correct est /lib64/ld-linux-x86-64.so). Vous pouvez lier le chargeur à votre bibliothèque et vérifier même les références délicates indiquées ci-dessus:

g++ -fPIC -shared -o liba.so a.o -Wl,--no-allow-shlib-undefined  /lib64/ld-linux-x86-64.so.2
17
P Shved

Vous ne pouvez pas faire ld (qui est ce que gcc exécute) faire attention à une bibliothèque qui n'est pas là dans le lien. Vous pouvez désactiver RTLD_LAZY pour obtenir des rapports agressifs, et vous pouvez ajouter un test unitaire qui s'exécute juste après le lien juste pour éliminer ces problèmes.

1
bmargulies