2009-04-30 3 views
10

I statische globale Variablen Konstrukteuren als Trick verwende, um bequem Funktionen zu registrieren, geht die Idee, etwas wie folgt aus:Prevent Linker aus dem Entfernen Globals

typedef int (*FuncPtr)(int); 

struct RegHelper 
{ 
    RegHelper(const char * Name, FuncPtr Func) 
    { 
     Register(Name, Func); 
    } 
} 

#define REGISTER(func) RegHelper gRegHelper_ ## func (#func, func); 

Jetzt kann ich Funktionen registrieren diese Art und Weise (ich benutze es zu implementieren eine Art Reflexion):

int Foo(int a) 
{ 
    return a * 123; 
} 

REGISTER(Foo) 

int Bar(int a) 
{ 
    return a * 456; 
} 

REGISTER(Bar) 

das Problem ist, dass, wenn ich dies in einer statischen Bibliothek verwenden, manchmal der Linker erkennt, dass die Übersetzungseinheit nicht verwendet wird, und es fällt die ganze Sache. Also die globalen Variablen sind nicht konstruiert, und die Funktionen sind nicht registriert ...

Meine Frage ist: Was kann ich tun, um dies zu umgehen? Das Aufrufen von Dummy-Funktionen in jeder Kompilierungseinheit während der Initialisierung scheint die Konstruktion der globalen Variablen auszulösen, aber das fühlt sich nicht sehr sicher an. Irgendwelche anderen Vorschläge?

Antwort

1

Ja, ich hatte dieses Problem auch. Die einzige sichere Weise um sie herum, die ich gefunden wurden:

  • bewegen die Registrierung Objekte in die ausführbare

:

  • die Bibliothek in eine DLL

oder machen Keine von beiden ist perfekt, obwohl die DLL-Lösung in Ordnung ist, wenn es Ihnen nichts ausmacht, DLLS zu verwenden, und auch ich wäre daran interessiert, von anderen Lösungen zu hören.

3

dies zu lösen:

  • Visual Studio (in der gleichen Lösung): Linkers> Allgemein> Verwenden Bibliothek Abhängigkeit Eingänge = yes
  • Gcc: Link direkt mit .o Dateien

Ich habe keine Lösung gefunden, die mir wirklich gefällt.

+0

Danke! Das ist nicht genau die Lösung, die ich suche, aber das hilft schon sehr viel :) – Drealmer

+0

Ich renne in genau dieses selbe Problem, aber "Bibliotheksabhängigkeitseingaben verwenden" einzuschalten funktioniert nicht für mich. Meine statische Bibliothek wird mit einer DLL verbunden, wenn das irgendeinen Unterschied macht. – BigSandwich

+0

Ich habe eine neue Antwort hinzugefügt, weil ich das anders gemacht habe. – BigSandwich

1

Schauen Sie sich die Antwort auf "Best Way To Build a List of Per Type Data"

Es gibt zwei wichtige wichtige Konzepte drin. Erstens:

(void) register_object; 

verwendet das Objekt, um sicherzustellen, dass die Linke es nicht abzustreifen, und

template<typename D> typename automatic_register<D>::exec_register 
    automatic_register<D>::register_object; 

stellt sicher, dass eine statische globale für jede Instanz zugeordnet ist. Sie sollten Ihre Daten in diesem Objekt aufbewahren. Es ist ein wenig anders, seine pro Objekt und nicht pro Klasse, aber wenn Sie das Makro anpassen

// Global list of objectsh 
struct FpList 
{ 
    FpList(FuncPtr func) : 
     func(func) 
    { 
     head = next; 
     next = this 
    } 
    FpList* next; 
    FuncPtr func; 

    static FpList* head; 
}; 
// In .cxx: 
FpList* FpList::head = 0; 

Dann erstellen ändern Sie Makro registrieren, so dass REGISTER (Foo), so dass es schafft:

struct register_Foo : FpList 
{ 
    register_Foo(FuncPtr fn): FpList(fn) 
    { 
     (void) register_object; 
    } 
    static register_Foo register_object; 
}; 

Ich denke, das ist nicht genug.Sie müssen noch die Vorlage instaniate, übergeben, wenn & Foo und sicherzustellen, dass ein

register_Foo register_Foo::register_object 

Instanz irgendwo erstellt wird. Der Vorlagencode für automatic_register zeigt, wie dies in einer Kopfzeile geschieht. Wenn Sie Ihr Makro in ein .cxx setzen können, deklarieren Sie einfach:

register_Foo register_Foo::register_object(&Foo); 

als Teil Ihres Makros. Ich denke, dass es funktionieren könnte. (alle aus der Erinnerung, also wer weiß).

1

Wenn Sie sich in einer UNIX-Umgebung befinden, würde das Aufrufen von ld mit der Option für das gesamte Archiv dazu führen, dass alle Objektdateien unabhängig von ihrer Verwendung in die statische Bibliothek aufgenommen werden.

1

Eine andere mögliche Lösung für das gleiche Problem. Erhalten Sie den konstanten Wert über einen Funktionsaufruf. Wie folgt aus:

constant.h

const char blah[10]; 

extern const char *get_blah(); 

constant.c

#include "header.h" 

const char *get_blah() 
{ return blah; } 

Das half mir den Trick!

+0

Warum das funktioniert: Wenn der Compiler constant.h sieht, muss die Funktion get_blah mit constant.h in die Übersetzungseinheit eingebunden werden. Da die Funktion in constant.c ist, wird die ganze constant.c.o verwendet, anstatt wie zuvor verworfen zu werden. – xryl669

+0

Der Name 'get_blah' hat hier keinen Einfluss, es ist nur der' externe' Trick, der wichtig ist – xryl669