Ich schreibe eine ziemlich große C++ - Objektbibliothek und bin auf ein kleines Problem gestoßen, das das Debuggen zu einem Problem macht:
Wenn ich eine Funktion/Methode in einer Header-Datei definiere und vergesse, einen Stub dafür zu erstellen (während der Entwicklung), werden beim Kompilieren keine Fehler angezeigt, die angeben, dass ich eine solche habe, da ich eine gemeinsam genutzte Objektbibliothek anstelle einer ausführbaren Datei erstelle vergessen, diese Funktion zu implementieren. Der einzige Weg, wie ich herausfinde, dass etwas nicht in Ordnung ist, ist die Laufzeit, wenn eine Anwendung, die mit dieser Bibliothek verknüpft ist, mit einem undefinierten Symbolfehler umfällt.
Ich suche nach einer einfachen Möglichkeit, um zu überprüfen, ob ich alle Symbole habe, die ich zum Kompilierzeitpunkt benötige, vielleicht etwas, das ich zu meinem Makefile hinzufügen kann.
Eine Lösung, die ich mir ausgedacht habe, besteht darin, die kompilierte Bibliothek über nm -C -U
, um eine entwirrte Liste aller undefinierten Referenzen zu erhalten. Das Problem ist, dass dies auch mit der Liste aller Referenzen in anderen Bibliotheken wie GLibC einhergeht, die natürlich zusammen mit dieser Bibliothek verknüpft werden, wenn die endgültige Anwendung zusammengestellt wird. Es wäre möglich, die Ausgabe von nm
bis grep
in allen meinen Header-Dateien zu verwenden und zu prüfen, ob die entsprechenden Namen vorhanden sind. Dies scheint jedoch verrückt zu sein. Sicher ist dies kein ungewöhnliches Problem und es gibt einen besseren Weg, es zu lösen?
Überprüfen Sie die Linker-Option -z defs
/--no-undefined
. Wenn Sie ein freigegebenes Objekt erstellen, schlägt die Verknüpfung fehl, wenn nicht aufgelöste Symbole vorhanden sind.
Wenn Sie den Linker mit gcc aufrufen, verwenden Sie den Compiler -Wl
Option, um die Option an den Linker zu übergeben:
gcc -shared ... -Wl,-z,defs
Betrachten Sie als Beispiel die folgende Datei:
#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);
}
}
Wenn Sie dies nun in ein freigegebenes Objekt integrieren, ist dies erfolgreich:
> gcc -shared -fPIC -o libsilly.so silly.c && echo succeeded || echo failed
succeeded
Aber wenn Sie hinzufügen -z defs
, der Link schlägt fehl und informiert Sie über Ihr fehlendes Symbol:
> 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
Unter Linux (das Sie anscheinend verwenden) sollte ldd -r a.out
Genau die Antwort geben, nach der Sie suchen.
UPDATE: Eine einfache Möglichkeit, a.out
Zu erstellen, anhand derer überprüft werden soll:
echo "int main() { return 0; }" | g++ -xc++ - ./libMySharedLib.so
ldd -r ./a.out
Was ist mit einer Testsuite? Sie erstellen nachgebildete ausführbare Dateien, die mit den von Ihnen benötigten Symbolen verknüpft sind. Wenn die Verknüpfung fehlschlägt, bedeutet dies, dass Ihre Bibliotheksschnittstelle unvollständig ist.
Ich hatte einmal das gleiche Problem. Ich habe ein Komponentenmodell in C++ entwickelt, und natürlich sollten Komponenten zur Laufzeit dynamisch geladen werden. Mir fielen drei Lösungen ein, die ich angewendet habe:
Ich hoffe, das hilft.