Hallo,
innerhalb eines "großen" Programms möchte ich zu Laufzeit nur einen kleinen Bestandteil ändern.
z.B. int calculate (int a; int b)
soll einmal als return(a+b) und später irgendwie anders, z.B. return (a-b) realisiert sein.
Ich will nun nicht das ganze Ding neu kompilieren und starten müssen (Maschinensteuerung!), sondern nur zu einem geeigneten Augenblick diese Änderung einbringen können.
Hat da irgendwer Erfahrung? Was entspricht bei Debian libdl.so? (Irgendwie in libc enthalten?)
TIA
Bernhard
Am Samstag, den 18.04.2009, 10:09 +0200 schrieb Bernhard Schiffner:
innerhalb eines "großen" Programms möchte ich zu Laufzeit nur einen kleinen Bestandteil ändern.
z.B. int calculate (int a; int b)
soll einmal als return(a+b) und später irgendwie anders, z.B. return (a-b) realisiert sein.
2 Vorschläge: Definiere dir doch eine (globale) Variable, die du zur Laufzeit ändern kannst (via GUI oder ähnlichem) und mach in calculate() ein switch(variable) oder werte eine Umgebungsvariable aus, die du zur Laufzeit ändern kannst.
[..]
Hat da irgendwer Erfahrung? Was entspricht bei Debian libdl.so? (Irgendwie in libc enthalten?)
libc6-dev (apt-file libdl.so)
MfG Daniel
On Saturday 18 April 2009, Daniel Leidert wrote:
werte eine Umgebungsvariable aus, die du zur Laufzeit ändern kannst.
Nur vorsichtshalber: Umgebungsvariablen sind Prozess-lokal, nicht System-global. Du kannst in der Shell die Variable ändern so viel Du willst, es interessierte einen laufenden Prozess nicht.
Konrad
Am 18. April 2009 11:18 schrieb Daniel Leidert daniel.leidert.spam@gmx.net:
2 Vorschläge: Definiere dir doch eine (globale) Variable, die du zur Laufzeit ändern kannst (via GUI oder ähnlichem) und mach in calculate() ein switch(variable) oder werte eine Umgebungsvariable aus, die du zur Laufzeit ändern kannst.
Den späteren Algorithmus kennt er ja offensichtlich noch nicht. Was soll dann also in dem entsprechendem case-Zweig stehen?
Eric
Am Samstag, den 18.04.2009, 14:06 +0200 schrieb Eric Schaefer:
Am 18. April 2009 11:18 schrieb Daniel Leidert daniel.leidert.spam@gmx.net:
2 Vorschläge: Definiere dir doch eine (globale) Variable, die du zur Laufzeit ändern kannst (via GUI oder ähnlichem) und mach in calculate() ein switch(variable) oder werte eine Umgebungsvariable aus, die du zur Laufzeit ändern kannst.
Den späteren Algorithmus kennt er ja offensichtlich noch nicht.
So hatte ich das OP nicht verstanden.
MfG Daniel
On Saturday 18 April 2009 11:18:54 Daniel Leidert wrote:
Am Samstag, den 18.04.2009, 10:09 +0200 schrieb Bernhard Schiffner:
innerhalb eines "großen" Programms möchte ich zu Laufzeit nur einen kleinen Bestandteil ändern.
...
2 Vorschläge: Definiere dir doch eine (globale) Variable, die du zur Laufzeit ändern kannst (via GUI oder ähnlichem) und mach in calculate() ein switch(variable) oder werte eine Umgebungsvariable aus, die du zur Laufzeit ändern kannst.
...
MfG Daniel
OK, die Möglichkeit über globale Variable und set ist vielleicht nutzbar. Trotzdem, ich will ja nicht umschalten sondern ersetzen.
Ich glaube mit dlopen() etc. komme ich weiter.
Bernhard
Hi,
On Saturday 18 April 2009, Bernhard Schiffner wrote:
innerhalb eines "großen" Programms möchte ich zu Laufzeit nur einen kleinen Bestandteil ändern.
Ich will nun nicht das ganze Ding neu kompilieren und starten müssen (Maschinensteuerung!), sondern nur zu einem geeigneten Augenblick diese Änderung einbringen können.
Sind die Änderungen wirklich so begrenzt? Sprich: kannst Du es als Plugin bezeichnen?
Hat da irgendwer Erfahrung? Was entspricht bei Debian libdl.so? (Irgendwie in libc enthalten?)
Es gibt libdl.so in /lib (Paket: libc6) und in /usr/lib (Paket: libc6-dev). (Debian Lenny)
Benutzt Du ANSI C oder C++? Bei ersterem musst Du sehr vorsichtig vorgehen, bei letzterem kann man das C++-Typsystem ausnutzen, um es sicher zu gestalten.
C++: Du brauchst ein Interface, z.B.: extern "C" { MyPluginClass* initPlugin(); bool canUnloadPlugin(); }
Der eigentliche Plugin-Code ist dann in einer von MyPluginClass abgeleiteten Klasse, deren Instanz von initPlugin zurückgeliefert wird. Ausserdem sollte diese Klasse einen Instanzen-Counter implementieren, so dass canUnloadPlugin dir sagen kann ob Du das Plugin entladen darfst.
Laden musst Du natürlich mit RTLD_LOCAL - es sei denn Deine Interface-Funktionen enthalten einen eindeutigen Teil (Tcl hängt z.B. immer den Bibliotheksnamen dran - ein "require Tk" lädt libtk.so und initialisiert mit TkInit()). Die Funktionspointer bekommst Du via dlsym - daher auch extern "C", sonst musst Du das Name-Mangling vom C++-Compiler kennen.
Falls Du Qt verwendest schau Dir stattdessen mal QPluginLoader genauer an.
ANSI-C: das Interface wird entsprechend größer und Du musst Dir Gedanken machen, wie Du absicherst dass es keine Abhängigkeiten gibt während Du entlädst (dlclose).
Ein paar Tips zum Thema Plugin mit ANSI-C:
Handles als void* herumreichen - das Handle darf damit beliebig komplex werden, das Plugin weiß worum es geht (cast auf interne Struktur), für die benutzenden Funktionen ist das Handle nur als Identifikator interessant (entsprechende Funktionen: newMyHandle, freeMyHandle, doSomethingMyHandle).
Komplexere Objekte, die bei jedem Plugin gleich strukturiert sind bekommen pseudo-Objektorientierte Strukturen
Nicht jede Funktion einzeln auflösen, sondern von der Interface Funktion eine Struktur mit Funktionspointern geben lassen: -- globale plugin.h -- typedef void* MyHandle; typedef int bool; struct MyStreamStruct { int (*read)(MyStreamStruct*self,int length,void*buffer); int (*write)(MyStreamStruct*self,int length,void*buffer); void (*closeAndFree)(MyStreamStruct*self); //internal: MyHandle _internalhandle; }; struct MyPluginStruct { //Plugin-Maintenance: void (*initPlugin)(); bool canUnload(); //Handle-orientiertes Interface: MyHandle (*newHandle)(); void (*freeHandle)(MyHandle); void (*dosomethingHandle)(MyHandle); //Objektorientiertes Interface: struct MyStreamStruct* (*newStream)(const char*filename); }; -- Plugin-locale interface.h -- #include "global/plugin.h" #ifdef __cplusplus extern "C" #endif MyPluginStruct* initPluginMyExtensionX(); -- Plugin-lokale interface.c -- #include "interface.h" static void myInitFunction(){ /* ... */ } /* ... viel Code ...*/ static struct MyPluginStruct myiface = { myInitFunction, myCanUnloadFunction, myNewHandle, myFreeHandle, myDoSomething, NULL /*z.B. wenn das Plugin keine Streams implementiert*/ }; MyPluginStruct* initPluginMyExtensionX(){return &myiface;} ----
Konrad
On Saturday 18 April 2009 12:03:16 Konrad Rosenbaum wrote:
Hi,
On Saturday 18 April 2009, Bernhard Schiffner wrote:
innerhalb eines "großen" Programms möchte ich zu Laufzeit nur einen kleinen Bestandteil ändern.
Ich will nun nicht das ganze Ding neu kompilieren und starten müssen (Maschinensteuerung!), sondern nur zu einem geeigneten Augenblick diese Änderung einbringen können.
Sind die Änderungen wirklich so begrenzt? Sprich: kannst Du es als Plugin bezeichnen?
Mit entsprechender Vorsicht: ja.
(Ich muß mir das, wenn ich weiß, daß es möglich ist, noch genau überlegen.) Da es sich um eine Maschinensteuerung handelt, sollte das kein Problem sein. "Normale" (d.h. bekannte) Variablen laufen da eh über eine shm-area. Wahrscheinlich muß man ein "last ressort"-shm definieren, in dem ein paar Standard-Typen (int, float, string[255] ...) zur Verfügung stehen, bis mal richtig komplett kompiliert wird.
Hat da irgendwer Erfahrung? Was entspricht bei Debian libdl.so? (Irgendwie in libc enthalten?)
Es gibt libdl.so in /lib (Paket: libc6) und in /usr/lib (Paket: libc6-dev). (Debian Lenny)
In Debian als dlopen() etc. "getrant" (eben nicht ldopen() )
Benutzt Du ANSI C oder C++? Bei ersterem musst Du sehr vorsichtig vorgehen, bei letzterem kann man das C++-Typsystem ausnutzen, um es sicher zu gestalten.
Weiß ich noch nicht. (C)
... (Danke für das Kochbuch.) ...
Konrad
Bernhard
On Saturday 18 April 2009, Bernhard Schiffner wrote:
Es gibt libdl.so in /lib (Paket: libc6) und in /usr/lib (Paket: libc6-dev). (Debian Lenny)
In Debian als dlopen() etc. "getrant" (eben nicht ldopen() )
Das heißt aber schon immer und auf allen POSIX-Systemen dlopen.
Konrad
On Sunday 19 April 2009 09:46:22 Konrad Rosenbaum wrote:
On Saturday 18 April 2009, Bernhard Schiffner wrote:
Es gibt libdl.so in /lib (Paket: libc6) und in /usr/lib (Paket: libc6-dev). (Debian Lenny)
In Debian als dlopen() etc. "getrant" (eben nicht ldopen() )
Das heißt aber schon immer und auf allen POSIX-Systemen dlopen.
Konrad
Beim googlen nach diesem Thema bin ich zuerst (Ehrenwort!) bei ldopen gelandet und habe mich dann dort weitergehangelt.
Ein interessantes Problem: die (wegen Falschschreibung) wenigen Einträge haben zum besseren Trefferbild geführt, wenn die anderen Fragekomponeten "richtig" waren.
Inzwischen weiß ich selber von der Sackgasse ldopen() und Co. Rechtschreibfehler tauchen bei Google zwar auf, führen aber nicht wirklich weiter. Deshalb dann die Frage an menschliche Experten (lug-dd).
Wie so oft, kam mir eine Minute nach Abschicken selbst die richtige Idee. Dann ging's weiter und Dein Kochbuch ergänzt sich gut mit anderen.
Böse?
Bernhard
Am 19. April 2009 11:47 schrieb Bernhard Schiffner bernhard@schiffner-limbach.de:
Wie so oft, kam mir eine Minute nach Abschicken selbst die richtige Idee. Dann ging's weiter und Dein Kochbuch ergänzt sich gut mit anderen.
Böse?
So lange wie Du Deine eigenen Erkenntnisse hier wieder präsentierst haben alle dabei etwas gelernt. Was kann daran böse sein? Es passiert mir auch recht häufig, dass ich die Lösung dann sehen, wenn ich die Frage danach formuliere. Das setzt die richtigen Denkprozesse in Gang.
Eric
lug-dd@mailman.schlittermann.de