Ich schreibe eine ziemlich große C ++ - Bibliothek für gemeinsam genutzte Objekte 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, da ich als gemeinsam genutzte Objektbibliothek und nicht als ausführbare Datei baue vergessen, diese Funktion zu implementieren. Der einzige Weg, um herauszufinden, dass etwas nicht stimmt, ist zur Laufzeit, wenn eine Anwendung, die mit dieser Bibliothek verknüpft ist, schließlich mit einem Fehler "undefiniertes Symbol" umkippt.
Ich suche nach einer einfachen Möglichkeit, um zu überprüfen, ob ich alle Symbole habe, die ich zum Zeitpunkt der Kompilierung benötige, vielleicht etwas, das ich meinem Makefile hinzufügen kann.
Eine Lösung, die ich mir nm -C -U
ausgedacht habe, besteht darin, die kompilierte Bibliothek zu durchlaufen , um eine entwirrte Liste aller undefinierten Referenzen zu erhalten. Das Problem ist, dass auch die Liste aller Referenzen in anderen Bibliotheken wie GLibC angezeigt wird, mit denen natürlich zusammen mit dieser Bibliothek verknüpft wird, wenn die endgültige Anwendung zusammengestellt wird. Es wäre möglich, die Ausgabe von nm
to grep
durch alle meine Header-Dateien zu verwenden und zu prüfen, ob einer der Namen übereinstimmt. Dies scheint jedoch verrückt zu sein. Sicher ist dies kein ungewöhnliches Problem und es gibt einen besseren Weg, es zu lösen?
quelle
nm -C -u
hat mich mehrfach gerettet! (Beachten Sie die Kleinbuchstaben-u
auf meinem System.) Lassen Sie diesen Kommentar hier, damit ich ihn beim nächsten Mal finden kann, wenn ich ihn brauche.Antworten:
Ü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 die Compiler-
-Wl
Option, um die Option an den Linker zu übergeben: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 in ein freigegebenes Objekt einbauen, ist dies erfolgreich:
Wenn Sie jedoch hinzufügen
-z defs
, schlägt der Link 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
quelle
-Bsymbolic
sie der Linker-Befehlszeile hinzufügen . Selbst wennforgot_to_define
es dank der-z
Prüfung jetzt in der Bibliothek vorhanden ist , kann die ausführbare Datei diese mit ihrer eigenen Definition überschreiben, und die eigenen Definitionen der Bibliothek werden zu dieser Überschreibung verschoben.-Bsymbolic
erzwingt Dinge, so dass die eigenen Definitionen der Bibliothek zu ihren Funktionen zu ihren Funktionen gehen.// forgot_to_define(fp);
es tue , meldet es keinen FehlerUnter Linux (das Sie anscheinend verwenden)
ldd -r a.out
sollten Sie genau die Antwort erhalten, nach der Sie suchen.UPDATE: Eine einfache Methode zum Erstellen
a.out
, anhand derer überprüft werden kann:echo "int main() { return 0; }" | g++ -xc++ - ./libMySharedLib.so ldd -r ./a.out
quelle
Was ist mit einer Testsuite? Sie erstellen nachgebildete Scheindateien, die mit den benötigten Symbolen verknüpft sind. Wenn die Verknüpfung fehlschlägt, bedeutet dies, dass Ihre Bibliotheksschnittstelle unvollständig ist.
quelle
Ich hatte einmal das gleiche Problem. Ich habe ein Komponentenmodell in C ++ entwickelt, und natürlich sollten Komponenten zur Laufzeit dynamisch geladen werden. Mir fallen drei Lösungen ein, die ich angewendet habe:
Hoffentlich hilft das.
quelle