2013-10-16 5 views
7

Ich habe Probleme mit dem Linker beim Portieren einer C-Bibliothek von Linux (Ubuntu) nach OS X. Der C-Code wird automatisch von Matlab generiert Idealerweise möchte ich den Code nicht selbst ändern.OS X-Linker kann keine Symbole aus einer C-Datei finden, die nur Variablen enthält

Das Problem scheint in einer C-Datei zu sein, die NUR nicht initialisierte Variablendeklarationen enthält, die dann von anderen C-Dateien EXTERNed werden, um die Matlab-Algorithmen zu implementieren. Der OS X-Linker kann scheinbar keine Symbole aus dieser Datei erkennen. Derselbe Quellcode funktioniert unter Linux gut, daher möchte ich verstehen, wie sich der OS X-Linker anders verhält und ob es eine Markierung gibt, die ich übergeben kann, um das Verhalten zu ändern.

Die statische Bibliothek wird ohne Fehler/Warnungen erstellt. Aber beim Erstellen von Anwendungen, die die statische Bibliothek verweist, wird die folgende Fehlermeldung (auf OS X) geworfen:

Undefined symbols for architecture x86_64: 
    "_my_var", referenced from: 
     _algorithm in libtestlibrary.a(algorithm.o) 
ld: symbol(s) not found for architecture x86_64 
collect2: ld returned 1 exit status 

Ein ‚nm‘ zeigt, dass in der Tat libtestlibrary.a Symbol _my_var enthält.

Eine viel vereinfachte Version des Codes von Matlab folgt unten.

Bibliothek Code:

// DATA.C : declaration of data 
#include "data.h" 
int my_var; 

// DATA.H - extern declaration of data 
#ifndef H_DATA 
#define H_DATA 
extern int my_var; 
#endif 

// ALGORITHM.C - performs the calculation 
#include "data.h" 
int algorithm(int x) { 
    my_var += x; 
    return my_var; 
} 

//ALGORITHM.H - declaration of library API 
#ifndef H_ALGORITHM 
#define H_ALGORITHM 
int algorithm(int x); 
#endif 

Bibliothek bauen Befehle:

gcc -c algorithm.c 
gcc -c data.c 
ar rcs libtestlibrary.a data.o algorithm.o 

Code Anwendung:

// MAIN.C : Code which calls into the static library 
#include "algorithm.h" 
int main() { 
    int x = 1; 
    x = algorithm(x); 
    return 0; 
} 

Anwendung bauen Befehle:

gcc -c main.c 
gcc -o testapp main.o -ltestlibrary 

Wenn ich die Definition in dat.c in 'int my_var = 0' ändere, so dass die Variable initialisiert wird, dann bauen die Bibliothek und die Anwendung sowohl unter Linux als auch unter OS X korrekt auf. Wie ich oben sagte, tue ich das nicht Ich möchte den Code nicht ändern, da er automatisch von Matlab generiert wird.

Vielen Dank im Voraus für Ihre Hilfe!

Antwort

6

Ihr Problem ist, dass Sie may_var nicht initialisieren.

Wenn Sie ein Datensymbol nicht initialisieren und es in eine statische Bibliothek einfügen, wird es als gemeinsames Symbol erstellt. Diese werden beim Verknüpfen von statischen Bibliotheken meines OS X-Linkers nicht erkannt.

Wenn Sie es initialisieren (data.c):

#include "data.h" 
int my_var = 0; 

Dann wird der Compiler es in einem anderen Abschnitt setzen und es wird in einer statischen Bibliothek richtig verknüpfen.

Edit:

Alternativ können Sie die -fno-common Option passieren

gcc -c data.c -fno-common 

gcc Dann wird diese gcc anweisen, gemeinsame Symbole für uninitialised Variablen zu erzeugen, und dann können Sie diese in Bibliotheken verknüpfen.

Dies ist ein Problem mit dem ausführbaren Mach-O-Format unter OS X und wird beschrieben here.

+0

Danke dafür; Ich hatte bereits bemerkt, dass wenn ich my_var initialisiere, es OK funktioniert. Was ich nicht verstehe ist, warum sich das Verhalten unter OS X und Linux unterscheidet. Ist das ein Fehler im OS X Linker? – geekydel

+0

@geekydel Es ist kein Fehler, es ist die Tatsache, dass ausführbare Formate für Linux (die ELF verwendet) und OS X, das Mach-O verwendet, unterschiedlich sind. Letzteres scheint Datensymbole nicht als allgemeine Symbole in statischen Bibliotheken zu mögen. –

+0

@geekydel Ich habe es gefunden. Schau meine Bearbeitung an. –

2

Die Antwort von @Sergey L. ist ausgezeichnet und wird das Problem lösen. Es erfasst jedoch nicht die Essenz dessen, was vor sich geht. Das Verhalten befindet sich tatsächlich in dem OS X-Archivierer ar, der allgemeine Symbole in dem Inhaltsverzeichnis (TOC) eines Archivs nicht auflistet. Ich habe die Dateien wie oben, und hier ist eine Sitzung mit dem Archivierungs (OS X 10.9.4, Xcode 5.1.1):

$ gcc -c algorithm.c 
$ gcc -c data.c 
$ ar rcs libtestlibrary.a data.o algorithm.o 
$ ar x libtestlibrary.a '__.SYMDEF SORTED' 
$ od -c __.SYMDEF\ SORTED 
0000000 \b \0 \0 \0 \0 \0 \0 \0 \0 002 \0 \0 020 \0 \0 \0 
0000020 _ a l g o r i t h m \0 \0 \0 \0 \0 240 
0000040 

Der TOC im Archiv erscheint als ein Eintrag mit dem Namen __.SYMDEF SORTED. Wie Sie sehen können, enthält das Inhaltsverzeichnis keine my_var. Dies ist die Essenz des Problems.

Sie können dem Inhaltsverzeichnis allgemeine Symbole hinzufügen, indem Sie ranlib -c verwenden. Hier ist, wie das funktioniert:

$ ranlib -c libtestlibrary.a 
$ ar x libtestlibrary.a '__.SYMDEF SORTED' 
$ od -c __.SYMDEF\ SORTED 
0000000 020 \0 \0 \0 \b \0 \0 \0 020 002 \0 \0 \0 \0 \0 \0 
0000020 210 \0 \0 \0 030 \0 \0 \0 _ m y _ v a r \0 
0000040 _ a l g o r i t h m \0 Ѓ ** 177 \0 \0 
0000060 

Wie Sie sehen können, hinzugefügt ranlib -cmy_var zum TOC.

Nun wird der Link Schritt arbeiten:

$ gcc -L . -o testapp main.o -ltestlibrary 
$ 

So ist es nicht unbedingt notwendig ist, um den Code neu kompilieren die Verbindung zur Arbeit zu kommen.

Die Manpage ranlib sagt dies:

-c  Include common symbols as definitions with respect to the table 
      of contents. This is seldom the intended behavior for linking 
      from a library, as it forces the linking of a library member 
      just because it uses an uninitialized global that is undefined 
      at that point in the linking. This option is included only 
      because this was the original behavior of ranlib. This option 
      is not the default. 

Also, das eine gewollte Abweichung von den traditionellen Verhalten ist, nicht benötigte Module in den Ausgang zu vermeiden, verbinden. Ich werde wahrscheinlich -fno-common in meiner eigenen Entwicklung verwenden.

Verwandte Themen