Ist es möglich, Code in einer Bibliothek beim Laden auszuführen?
-
Ich hab für das Programm R eine eigene Bibliothek (in C++) geschrieben. Wenn in der Bibliothek die Standardausgabe benutzt wird, stürzt beim Ausführen des entsprechenden Codes R ab. Um trotzdem cout verwenden zu können, setze ich den Streambuffer entsprechend um, sodass die Ausgabe nach Rprintf() gesendet wird (die Ausgabe-Funktion von R).
Nun mein Problem: Ich möchte, dass sofort bei Laden der Bibliothek (oder sobald das erste mal eine Funktion aus der Bibliothek aufgerufen wird) der folgende Code ausgeführt wird:
Rprintf_buf sb_Rprintf; std::cout.rdbuf( &sb_Rprintf );Dieser Code steht momentan nicht in irgendeiner Funktion, sondern in der "obersten" Ebene. Beim Kompilieren kommt deshalb der Fehler:
RInterface.cpp:23:1: error: 'cout' in namespace 'std' does not name a type make: *** [RInterface.o] Error 1Was gibt es da für Lösungsmöglichkeiten?
Mir fällt gerade eigentlich nur ein, bei jedem Funktionsaufruf zu überprüfen, ob der Streambuffer schon umgesetzt wurde (mit einer globalen bool-Variable) und falls nein, den Streambuffer entpsrechend umzusetzen. Wenn die Bilbiothek viele Funktionen hat, die man von außen aufrufen kann, ist das aber irgendwie recht unschön.
-
Ist es eine statische oder eine dynamische Bibliothek?
Bei einer dynamischen solltest du das in derDllMainmachen.Dieser Code steht momentan nicht in irgendeiner Funktion, sondern in der "obersten" Ebene.
Entweder war das wirklich ein verzweifelter Versuch, oder dir fehlen Grundlagen, denn das klingt, als ob du einfach einen Funktionsaufruf in den globalen Namensraum geschrieben hättest.
Abgesehen klingt das ganz danach, als ob dein Design nicht so das wahre wäre.
-
mh, was du machen könntest, was aber dreckig ist:
erstell dir eine globale variable und weise ihr die rückgabe einer funktion zu, in der funktion machst du deine änderungennamespace { bool foo() { Rprintf_buf sb_Rprintf; // wobei das hier böse wird, da referenz auf lokale variable std::cout.rdbuf( &sb_Rprintf ); } bool dummy = foo(); }; int main() { return 0x0; }ist aber alles böse. hab ich einmal z debugging zwecken gemacht/gebraucht um einen breakpoint in die speicherallokation zu setzen, um eine speicherleck zu finden, was von SFML erzeugt wurde in eienr globalen variable
-
Die Bibliothek ist dynamsich.
Mit der DllMain hört sich erstmal gut an. Wird die nur dann ausgeführt, wenn man die Bibliothek für Windows kompiliert oder auch bei anderen Betriebssystemen?Der Tobi schrieb:
Entweder war das wirklich ein verzweifelter Versuch, oder dir fehlen Grundlagen, denn das klingt, als ob du einfach einen Funktionsaufruf in den globalen Namensraum geschrieben hättest.
Wahrscheinlich ist es eine Mischung aus beidem. Was hat es genau mit den Namensräumen auf sich?
@Skym0sh0:
Dann müsste aber "Rprintf_buf sb_Rprintf;" außerhalb der foo()-Funktion, weil sonst müsste das Objekt eigentlich weg sein, nachdem foo() verlassen wurde.Generell kam mir noch die Idee, "std::cout.rdbuf( &sb_Rprintf );" in einen Konstruktur zu packen, den ich durch Deklaration einer globalen Variablen ausführen lasse. Das hat aber Ähnlichkeit mit der foo()-Variante
-
Wird die nur dann ausgeführt, wenn man die Bibliothek für Windows kompiliert oder auch bei anderen Betriebssystemen?
Die wird dann ausgeführt, wenn du die DLL an einen Prozess attachst, also z.B. per LoadLibrary in den Prozessspeicher lädtst. (zumindest bei Windows, inwieweit es sowas bei Linux/Mac gibt weiß ich nicht)
Wahrscheinlich ist es eine Mischung aus beidem. Was hat es genau mit den Namensräumen auf sich?
Mit welchem Buch/Prof lernst du, dass der/das die Erstellung einer DLL vor den Namensräumen bespricht?
-
Thinking in C++
Die DllMain wird nirendwo erwähnt. Ein wenig googlen ergibt, dass es wohl nur für Windows ist. Linux benutzt "void my_load(void)". Und Mac dann wahrscheinlich noch was anderes. Schön ist das nicht.
Zu namespaces in Bezug auf eigene Bibliotheken finde ich in dem Buch leider nichts. Über namespaces allgemein natürlich schon, aber auch nicht so wirklich viel.
Edit:
Ich hab es jetzt mit meiner Konstruktor-Idee gelöst. Es funktioniert, d.h. man kann es kompilieren, es tut, was es soll, und R stürzt nicht ab. Hier der Code:RInterface.h
class Rprintf_buf : public std::streambuf { protected: virtual int_type overflow( traits_type::int_type m = traits_type::eof()) { if( !traits_type::eq_int_type( m, traits_type::eof() ) ) Rprintf( "%c", traits_type::to_char_type( m ) ); // genau ein Zeichen auf Rprintf ausgeben return traits_type::not_eof( m ); // Ok } }; class SetRprintf_buf { public: SetRprintf_buf(); };RInterface.cpp
Rprintf_buf sb_Rprintf; SetRprintf_buf::SetRprintf_buf() { std::cout.rdbuf( &sb_Rprintf ); } SetRprintf_buf sb_Rprintf_set;Ich hab aber noch ein paar konkrete Fragen zu Namespaces.
- Welche Funktionen sollten in einem Namespace stehen? Alle oder nur die, die nicht von außen aufrufbar sein sollen? (außen = ein Programm, das die Bibliothek benutzt)
- Es gibt Namespaces ohne Namen. Sind die enthaltenen Funktionen nur in der entsprechenden .h/.cpp benutzbar und nicht von anderen Dateien aus?
- Die Funktionen, die von R aus aufrufbar sind, stehen bei mir in einem "extern "C""-Block. Sind die anderen Funktionen gar nicht aufrufbar oder müsste man wissen, wie der Compiler/Linker die Funktionen umbenannt hat?
-
Schreib doch einfach deine eigene main-Funktion und ruf sie beim laden auf...
-
Die normale main()-Funktion wird nicht beim Laden einer Bibliothek ausgeführt.
Und wenn die Bibliothek von R aus geladen wird, habe ich keinen Einfluss darauf, eine bestimmte Funktion auszuführen. Das muss schon automatisch geschehen.In R kann man in einer Konsole Befehle eingeben. Das sieht z.B. so aus:
library(ls2mat) // Laden meiner Bibliothek (namens ls2mat) mat <- matrix(1:9, 3, 3) // Matrix zum Testen erstellen .Call("outtest2_", mat) // Aufruf meiner Funktion "outtest2_" mit dem Parameter mat