2010-12-08 1 views
9

Meine Frage an diesen ähnlich ist, aber scheint nicht genau zu korrelieren:Wie zu zwingen, Aufnahme von „nicht verwenden“ Objektdefinitionen in einer Bibliothek

How to force inclusion of an object file in a static library when linking into executable?

Forcing symbol export with MSVC

Was ich habe, so etwas wie ist so:

struct thingy; 
struct container 
{ 
    static container& instance(); // singleton 

    int register_thingy(thingy*); 
}; 

struct thingy 
{ 
    virtual ~thingy() {} 
    virtual int id() const = 0; 
}; 

//template trick to force registration. 
template < typename Derived > 
struct registered_thingy : thingy 
{ 
    registered_thingy() : my_id(my_static_id) {} 

    int id() const { return my_id; } 
private: 
    int my_id; 
    static int my_static_id; 
} 
template < typename Derived > 
int registered_thingy<Derived>::my_static_id = 
    container::instance().register_thingy(new Derived); 

nun in einer concrete_thingy.cpp Datei ich habe:

struct my_concrete_thingy : registered_thingy<my_concrete_thingy> 
{ 
    my_concrete_thingy() {} // registered_thingy's constructor not called otherwise 
}; 

Natürlich ist das Obige völlig nutzlos, aber hier wird echtes Verhalten abstrahiert.

Dies funktioniert wunderbar, wenn es in einer Anwendung verwendet wird, die als Ganzes kompiliert wird. Das Problem ist jetzt, dass ich bisher nicht in der Lage bin, diese Technik zu verwenden, während ich das Verhalten hinter collection in einer Bibliothek abfülle. Mit anderen Worten, ich habe eine thingys.lib Datei, die concrete_thingy.cpp enthält, aber die Registrierung tritt nicht auf, wenn das mit einer ausführbaren Datei verknüpft ist. Die collection endet oben vorhanden und funktioniert gut, aber es ist leer.

Jetzt ist dies eine statische Bibliothek, keine DLL. Das kann das Thema ein wenig verändern und die Techniken, die in den obigen Links erwähnt werden, scheinen nicht zu gelten. Das eine ist natürlich über Funktionen und ich sehe nicht, wie ich es auf diese C++ - Strukturen anwenden könnte.

Ich habe versucht, die #pragma comment Verfahren mit den folgenden drei Zeilen zu verwenden (einzeln natürlich) in concrete_thingy.cpp, von denen keines gearbeitet:

#pragma comment (linker, "/export:concrete_thingy") 
#pragma comment (linker, "/export:concrete_thingy::my_static_id") 
#pragma comment (linker, "/export:registered_thingy<concrete_thingy>::my_static_id") 

Wenn concrete_thingy.cpp in der ausführbaren Datei ist, anstatt die Bibliothek alles funktioniert fein.

Also dann, hier ist meine Fragen:

1) Ist es möglich, zu tun, was ich versuche zu tun, um? Ich denke ja, aber ich weiß nicht wie.

2) Wenn es möglich ist, wie würde ich MSVC++ 2010 dazu bekommen?

3) Wenn es möglich ist, wie kann ich es auf eine tragbare Weise tun?

Kurz gesagt, was ich versuche, wäre vergleichbar mit dem Erstellen einer abstrakten Fabrik, die Implementierungen einer Abstraktion erstellt. Es weiß nichts über diese Implementierungen, die unter Verwendung von globalen Initialisierungstricks registriert werden. Dies sollte alles in einer statischen Bibliothek sein, mit der eine Anwendung verknüpft werden kann, und diese Implementierungen sollten über diese Factory verfügbar sein. Niemand weiß etwas über diese Implementierungen, außer sich selbst, und daher führt eine normale Verknüpfung dazu, dass diese und ihre Registrierungs-Globals verschwinden.

Es ist nicht genau das, was ich vorhabe, aber es ist nahe genug.

Bearbeiten: ============================================= ========

Sieht aus wie dieses Verhalten "nach Entwurf" ist.MS erkennt, dass der Bau von Objekten, die Nebenwirkungen verursachen auftreten sollte, ob ihre verwendet wird, sie eine Lücke im Standard verwenden, die sie Einheiten nicht enthalten Übersetzung ermöglicht es, in der nichts verwendet wird: \

https://connect.microsoft.com/feedback/viewfeedback.aspx?FeedbackID=244410&wa=wsignin1.0&siteid=210

Die/OPT: Die NOREF-Option soll in diesem Fall scheinbar nichts tun.

+0

"registered_thingys Konstruktor nicht anders genannt" -> es gibt eine andere Möglichkeit, das Problem zu lösen. Sie brauchen ein 'template struct refit;' und dann können Sie anstelle eines Konstruktors 'typedef refit user;' nach der statischen int-Deklaration angeben. Dies wird auch die Instanziierung der Statik erzwingen. Siehe [diese Antwort] (http://stackoverflow.com/questions/401621/best-way-to-build-a-list-of-per-type-data/401801#401801) für weitere Ausführungen. –

+0

Anscheinend wird wieder einmal gezeigt, dass der Unterschied zwischen einem Fehler und einem Feature darin besteht, dass das Feature dokumentiert ist. Übrigens ... ist wirklich die Template-Trickerei nötig? würde das Folgende nicht besser funktionieren? 'struct concrete: abstract {konkreter (...) {}} concrete_instance (...);' – 6502

Antwort

4

Nun, die anderen Antworten, wo gute Versuche, aber letztlich fruchtlos. Ich werde den Überarbeitungstrick verwenden, aber der Rest scheint ein Ablenkungsmanöver gewesen zu sein; es macht einen Sinn, da die betreffende Vorlage nirgendwo anders verwendet wird, so dass die Tatsache, dass sie nicht explizit instanziiert wird, keinen Unterschied machen sollte ... die Deklaration des Globalen geschieht immer noch in einer Übersetzungseinheit, sie hat Nebenwirkungen ... Ich glaube nicht, dass der Standard es erlaubt, es weg zu optimieren.

Das unglückliche bisschen über den Standard, nicht zu sagen, ob es erforderlich ist, eine Übersetzungseinheit überhaupt zu enthalten, ist das entscheidende Problem. Ich denke, C++ 0x tut etwas dagegen, aber vielleicht nicht ... Jedenfalls fühlt sich MS frei, die Einheit überhaupt nicht einzubeziehen, und da es nicht global ist, wird es letztlich nicht in die ausführbare Datei aufgenommen keiner der anderen Mist passiert.

Was ich beschlossen habe, und es gibt natürlich viele andere Möglichkeiten, ist eine Datei 'Tag' Variable zu erstellen. Diese Variable wird dann in einer Funktion zugewiesen, die global zugänglich ist (sie muss zugewiesen oder zugewiesen werden oder die Referenz ist wegoptimiert). Dann muss diese Funktion von der ausführbaren Datei aufgerufen werden.

Ich entschied mich, es so zu machen, weil dann der Rest immer noch so funktioniert wie immer. Letztendlich ändere ich mein Verhalten nicht so, wie ich es könnte, wenn ich einfach eine Registrierungsfunktion schreiben würde, die die Typen von Hand registriert. Außerdem kann ich auf diese Weise andere Dinge tun ... Ich muss nur sicherstellen, dass alles, was in diese Klassifizierung von Fucktardery fallen könnte, ein Tag hat und auf dieses Tag zugegriffen wird.

Ich werde eine Reihe von Hilfsmakros schreiben, um dies größtenteils schmerzlos zu machen.

1

Es gibt die Linker-Option/OPT: REF und/OPT: NOREF, Zugriff über Linker-> Optimierung-> Referenzen.

+0

@Noah: Ich benutze 2010. Ich bearbeite einen Screenie, wenn du ihn nicht finden kannst. – Puppy

+0

Ich sehe, du sprachst in der EXE, nicht in der Bibliothek. Das Argument wurde angepasst, es wurde akzeptiert, aber es behob das Problem nicht :(Ich bezweifle, dass ich das trotzdem gemacht hätte, weil es andere Bibliotheken gibt, auf die ich verlinke, die ich nicht komplett ziehen möchte. –

Verwandte Themen