J'écris une bibliothèque d'objets partagés C++ assez grande et j'ai rencontré un petit problème qui rend le débogage difficile:
Si je définis une fonction/méthode dans un fichier d'en-tête, et oublie de créer un stub pour lui (pendant le développement), puisque je construis en tant que bibliothèque d'objets partagée plutôt qu'en tant qu'exécutable, aucune erreur n'apparaît au moment de la compilation me disant que j'ai oublié de mettre en œuvre cette fonction. La seule façon dont je découvre que quelque chose ne va pas est au moment de l'exécution, quand finalement une application se liant à cette bibliothèque tombe avec une erreur de "symbole non défini".
Je cherche un moyen facile de vérifier si j'ai tous les symboles dont j'ai besoin au moment de la compilation, peut-être quelque chose que je peux ajouter à mon Makefile.
Une solution que j'ai trouvée consiste à exécuter la bibliothèque compilée via nm -C -U
pour obtenir une liste démêlée de toutes les références non définies. Le problème est que cela revient également à la liste de toutes les références qui se trouvent dans d'autres bibliothèques, telles que GLibC, qui seront bien sûr liées avec cette bibliothèque lorsque l'application finale sera mise en place. Il serait possible d'utiliser la sortie de nm
vers grep
dans tous mes fichiers d'en-tête et de voir si l'un des noms correspond .. mais cela semble insensé. Ce n'est sûrement pas un problème rare et il existe une meilleure façon de le résoudre?
Découvrez l'option de l'éditeur de liens -z defs
/--no-undefined
. Lors de la création d'un objet partagé, le lien échouera s'il existe des symboles non résolus.
Si vous utilisez gcc pour appeler l'éditeur de liens, vous utiliserez le compilateur -Wl
option pour passer l'option à l'éditeur de liens:
gcc -shared ... -Wl,-z,defs
À titre d'exemple, considérons le fichier suivant:
#include <stdio.h>
void forgot_to_define(FILE *fp);
void doit(const char *filename)
{
FILE *fp = fopen(filename, "r");
if (fp != NULL)
{
forgot_to_define(fp);
fclose(fp);
}
}
Maintenant, si vous construisez cela dans un objet partagé, cela réussira:
> gcc -shared -fPIC -o libsilly.so silly.c && echo succeeded || echo failed
succeeded
Mais si vous ajoutez -z defs
, le lien échouera et vous indiquera votre symbole manquant:
> gcc -shared -fPIC -o libsilly.so silly.c -Wl,-z,defs && echo succeeded || echo failed
/tmp/cccIwwbn.o: In function `doit':
silly.c:(.text+0x2c): undefined reference to `forgot_to_define'
collect2: ld returned 1 exit status
failed
Sous Linux (que vous semblez utiliser) ldd -r a.out
devrait vous donner exactement la réponse que vous recherchez.
MISE À JOUR: une façon triviale de créer a.out
par rapport auquel vérifier:
echo "int main() { return 0; }" | g++ -xc++ - ./libMySharedLib.so
ldd -r ./a.out
Et une suite de tests? Vous créez de faux exécutables qui pointent vers les symboles dont vous avez besoin. Si la liaison échoue, cela signifie que votre interface de bibliothèque est incomplète.
J'ai eu le même problème une fois. Je développais un modèle de composant en C++ et, bien sûr, les composants devraient se charger dynamiquement lors de l'exécution. Trois solutions me viennent à l'esprit, celles que j'ai appliquées:
J'espère que ça t'as aidé.