FAQs


OV-Programmierung

Wie definiere ich in einer OVM-Datei eine Stringvariable und wie greife ich im C-Quelltext darauf zu?

 

    Definition in der OVM-Datei (Beispiel):

 
myString : STRING;


 

     Lesender Zugriff im C-Quelltext:

  
OV_UINT i;

     /* myString als ganzes ausgeben */

     printf("myString = %s\n", pobj->v_myString);

     /* myString in einzelnen Zeichen ausgeben */

     if(pobj->v_myString) { /* Achtung, Zeiger könnte NULL sein (leerer String)! */

          for(i=0; pc[i]; i++) {

               printf("%ld. Zeichen von myString = ‚%c'\n", pc[i]);

          }

     }



Vergleich mit einem anderen String:


  #include "libov/ov_string.h"

     ...

     OV_INT vgl;

     /* vergleiche Strings */

     vgl = ov_string_compare(pobj->v_myString, "VW Bulli");

     if(vgl == 0) {

          /* identisch */

          ...

     } else if(vgl > 0) {

          /* myString ist "größer" als "VW Bulli", z.B. "VW Kaefer"

          ...

     } else {

          /* myString ist "kleiner" als "VW Bulli", z.B. "Opel Astra"

          ...

     }

  

     Schreibender Zugriff:

   

#include "libov/ov_string.h"

     #include "libov/ov_macros.h"

     ...

     OV_RESULT result;

     result = ov_string_setvalue(&pobj->v_myString, "Mitsubishi");

     if(Ov_Fail(result)) {

          /* konnte String nicht setzen */

          ...

     }


 

Wie definiere ich in einer OVM-Datei eine dynamische Vektorvariable und wie greife ich im C-Quelltext auf dessen Elemente zu?

 

    Definition in der OVM-Datei (Beispiel: Integer und String):

 

dynIntVec[] : INT;
dynStringVec[] : STRING;

 

     Lesender Zugriff im C-Quelltext:

 

OV_UINT i;

/* dynIntVec ausgeben */

for(i=0; i<pobj->v_dynIntVec.veclen; i++) {

     printf("dynIntVec[%ld] = %ld\n", i, pobj->v_dynIntVec.value[i]);
}

/* dynStringVec ausgeben */

for(i=0; i<pobj->v_dynStringVec.veclen; i++) {

     printf("dynStringVec[%ld] = %s\n", i, pobj->v_dynStringVec.value[i]);

}


Schreibender Zugriff im C-Quelltext (Zugriff auf einzelne Elemente):


#include "libov/ov_macros.h"

...

OV_UINT len, i;

OV_RESULT result;

/* dynIntVec einen Vektor mit 13 (unterschiedlichen) Elementen zuweisen */

len = 13;

result = Ov_SetDynamicVectorLength(&pobj->v_dynIntVec, len, INT);

if(Ov_OK(result)) {

     for(i=0; i<len; i++) {

          pobj->v_dynIntVec.value [i] = 3*i+15;

}

} else {

     /* konnte neuen Wert nicht setzen (Speichermangel) */

     ...

}

/* dynStringVec einen Vektor mit 5 (gleichen) Elementen zuweisen */

len = 5;

result = Ov_SetDynamicVectorLength(&pobj->v_dynStringVec, len, STRING);

if(Ov_OK(result)) {

     for(i=0; i<len; i++) {

          Ov_SetStringValue(&pobj->v_dynIntVec.value[i], "Ein String");

}

} else {

     /* konnte neuen Wert nicht setzen (Speichermangel) */

     ...

}

/* dynIntVec und dynStringVec "löschen" (je 0 Elemente) */

Ov_SetDynamicVectorLength(&pobj->v_dynIntVec, 0, INT);

     Ov_SetDynamicVectorLength(&pobj->v_dynStringVec, 0, STRING);


Schreibender Zugriff im C-Quelltext (Vektor als ganzes setzen):

 

    #include "libov/ov_macros.h"

...

OV_INT myIntValue[] = { 0, 8, 15, 4711 };

OV_UINT myIntLen = sizeof(myIntValue)/sizeof(myIntValue[0]); /* = 4 */

OV_STRING myStringValue[] = { "Ich", "mag", "ACPLT/OV" };

OV_UINT myStringLen = sizeof(myStringValue)/sizeof(myStringValue[0]); /* = 3 */

OV_RESULT result;

/* dynIntVec auf Wert in myIntValue setzen */

result = Ov_SetDynamicVectorValue(&pobj->v_dynIntVec, myIntLen, INT);

if(Ov_Fail(result)) {

       /* konnte Wert nicht setzen (Speichermangel) */

...

}

/* dynStringVec auf Wert in myStringValue setzen */

result = Ov_SetDynamicVectorValue(&pobj->v_dynStringVec,

myStringLen, STRING);

if(Ov_Fail(result)) {

       /* konnte Wert nicht setzen (Speichermangel) */

...

}


Ich schreibe einen Get-Accessor für eine Variable, dessen Wert ich dynamisch zusammenbauen muß. Wie bekomme ich den notwendigen Speicher und wer gibt ihn wieder frei?

 

    Der Speicher wird auf einem sog. Memory Stack reserviert. Der Aufrufende des Get-Accessors muß den Stack vorher „blockieren“ und später wieder freigeben. In der Get-Accessor-Routine selbst wird nur der Speicher vom Stack angefordert. Beispiel:

 

#include "libov/ov_memstack.h"

#include "libov/ov_string.h"

...

OV_STRING mylib_myclass_myvariable_get(

OV_INSTPTR_mylib_myclass pobj

) {

OV_STRING pstr = (OV_STRING)ov_memstack_alloc(18);

ov_string_print(&pstr, "x ist gleich %d"; 4711);

return pstr;

}


Ich rufe eine Get-Accessor-Funktion eines Objekts auf. Muß ich irgendetwas beachten?

 

    Ja! Unbedingt vor dem Aufruf den Memory Stack „blockieren“ und hinterher wieder freigeben! Der Memory Stack dient der aufgerufenen Accessor-Routine als Quelle für dynamischen Speicher (vgl. vorherige Frage). Beispiel:

 

#include "libov/ov_memstack.h"

...

/* Stapelspeicher blockieren */

ov_memstack_lock();

/* Wert via get-Accessor holen und ausgeben */

printf("myvariable = %s\n“, mylib_myclass_myvariable_get(pobj));

/* Stapelspeicher wieder freigeben */

ov_memstack_unlock();

 

 

Ich schreibe einen Set-Accessor für eine Variable oder rufe einen solchen auf. Muß ich nun etwas beachten?

 

    So gut wie nicht ist zu beachten. Der evtl. notwendige dynamische Speicher gehört immer dem Aufrufer. Er darf in der Set-Accessor-Funktion nicht verändert, sondern nur gelesen werden. Dies kommt aber eigentlich schon im Funktionsprototyp zum Ausdruck (const):

 

OV_DLLFNCEXPORT OV_RESULT mylib_myclass_myvariable_set(

       OV_INSTPTR_mylib_myclass   ptest,

       const OV_XXX                 value

) {

       ...

}


Wer nicht auf Compiler-Warnungen achtet ist selber schuld!

Ich möchte während der Laufzeit von einer Instanzvariable den Typ, Kommentar etc. bekommen.

 

    Diese Informationen kann man über das entsprechende Klassenobjekt der Instanz erhalten.

Über die Beziehung „instantiation“ erhält man eine Objektreferenz auf das zugehörige Klassenobjekt. Dieses beinhaltet (Beziehung „containment“) wiederum die einzelnen Variablen-Beschreibungsobjekte deren Attribute gerade die Definitionen aus der ovm-Datei widerspiegeln (z.B. vartype oder comment):

 

ovm-Datei:

CLASS Test : CLASS ....

...
VARIABLES


           TestVar:  BOOL  COMMENT = ".....";


END_VARIABLES;

       ...
    END_CLASS;

C-Datei:


OV_DLLFNCEXPORT void myLib_Test_execute(

       OV_INSTPTR_ov_object      pobj

) {

       /*

       *            local variables

       */

OV_INSTPTR_ov_variable pvar;

       OV_INSTPTR_myLib_Test   pgvc;

            OV_INSTPTR_ov_class pclass;

            OV_INSTPTR_ov_object pobj2;

 

pgvc = Ov_StaticPtrCast(myLib_Test, pobj);

pclass = Ov_GetParent(ov_instantiation, pobj);

pobj2 = Ov_GetFirstChild(ov_containment, pclass);

pvar = NULL;

 

            while (pobj2) {

                        if (ov_string_compare(pobj2->v_identifier, "TestVar")==0) {

                                    pvar = Ov_StaticPtrCast (ov_variable, pobj2);

                                    break;

                        }

            pobj2 = Ov_GetNextChild(ov_containment, pobj2);

}

if (pvar) {

            .... pvar->v_vartype ...

                        .... pvar->v_comment ...

       }

 

}


Ist die Datenbasis auf 16 MB beschränkt ? Wie kann die Datenbasis dynamisch vergrößert werden?

 

Seit der libov - Version 1.6.2  beträgt die maximale Datenbasisgröße 2GB. Eine dynamische Vergrößerung soll prinzipiell bei einer OV-Compilierung mit dem Makro OV_DYNAMIC_DATABASE ermöglicht werden, ist aber zum gegenwärtigen Zeitpunkt nicht hinreichend ausgereift. Problem ist hier das Memory-Map-File für die Persistenz der Datenbasis. Eine dynamische Änderung dieses Files wird nicht von allen Betriebssystemen unterstützt.

     

Der ov_builder hat Probleme beim Erzeugen der c-Dateien, wenn die Funktionsdefinitionen ohne Zeilenwechsel in der *.ovf Datei eingetragen sind !

 

     In der ov-builder-Version 1.0.2 (OV-Produktversion 1.6.3) konnte dieser Fehler behoben werden.

 

Der OV-Builder hat noch einen kleinen Fehler. Der destructor muss als void-Funktion erstellt werden, nicht als OV_RESULT

 

     Wird er, zumindest ab der ov-builder Version 1.0.1  (OV-Produktversion 1.6.3).


Können von Strukturen statische bzw. dynamische Vekoren definiert werden?

 

     Bis einschließlich libov-version 1.6.3 ist dies nicht möglich.

 

 

Ich möchte direkt beim Laden meiner OV Lib Objekte erzeugen. Wie kann ich denn die Startup Funktion für eine Library definieren?
 
Da die Definition einer Library in einer ovm-Datei dem Anlegen einer Instanz einer Library-Klasse entspricht, kann deren startup-Methode auch nicht überladen werden. Dennoch ist das Ausführen von Aktionen beim Laden einer Bibliothek über einen Umweg möglich. Dazu muss in der Makedatei generik.mk ein zusätzliches define eingeführt werden:

 

MYLIB_DEFINES = \
               -DOV_DEBUG \
               -DOV_COMPILE_LIBRARY_$(MYLIB_NAME) \
               -Dov_library_open_$(MYLIB_NAME)= ov_library_open_$(MYLIB_NAME)_old


Dadurch wird beim Compilieren der vom Codegenerator erzeugten Datei <libname>.c die Funktion ov_library_open_<libane> in ov_library_open_<libname>_old umbenannt. Anstelle des Platzhalters <libname> muss der jeweilige Name der zu erzeugenden Bibliothek eingesetzt werden. In einer der C-Dateien der Bibliothek muss dann eine eigene ov_library_open_<libname> Funktion geschrieben werden, die das folgende Aussehen hat:
 

 

#undef ov_library_open_$(MYLIB_NAME) 
 
OV_DLLFNCEXPORT OV_LIBRARY_DEF *ov_library_open_<libname>(void) {
 
               static OV_LIBRARY_DEF OV_LIBRARY_DEF_<libname>_new;
 
               OV_LIBRARY_DEF_<libname>_new = *ov_library_open_<libname>_old();
               OV_LIBRARY_DEF_<libname>_new.setglobalvarsfnc = 
                                                      ov_library_setglobalvars_<libname>_new;
               return &OV_LIBRARY_DEF_<libname>_new;
}

Das undefine ist notwendig, damit das global im makefile gesetzte define nicht auch auf die eigene ov_library_open Funktion angewendet wird. In dieser Funktion wird die Initialisierungsfunktion der Bibliothek setglobalvarsfnc umgebogen auf die eigene Funktion ov_library_setglobalvars_<libname>_new. Diese Funktion muss in der gleichen C-Datei vor der ov_library_open_<libname> Funktion definiert sein:

 

OV_RESULT ov_library_setglobalvars_<libname>_new(void) {

            OV_RESULT result;

            result = ov_library_setglobalvars_<libname>(void);

            if(Ov_OK(result)) {  

                        // eigene Aktionen wie z.B. das Erzeugen von default-Objekten

                        ...

            }

            return result;
}

 

In dieser Funktion wird zuerst die eigentliche Intitialisierungsfunktion der Bibliothek ov_library_setglobalvars_<libname> aufgerufen und bei erfolgreicher Durchführung können anschließend eigene Aktionen zur Intitialisierung des Systems nach dem Laden der Bibliothek ausgeführt werden.

OV-Compilieren

Bei dem Erzeugen einer ov-Bibliothek mit dem Cygwin Compiler tritt ein seltsamer Fehler auf. Das Lesen einer OV_TIME_SPAN Variable über das KS liefert völlig falsche Werte, die sich auch nicht ändern lassen.

 

    Dieses Problem taucht dann auf, wenn lediglich die ov-Bibliothek mit dem Cygwin-Compiler erzeugt wurde. Für einen korrekten Ablauf ist es aber erforderlich das gesamte OV (und damit auch die Bibliotheken libplt.a, libks.a, libkscln.a, libkssvr.a und libmpm.a im plt-Verzeichnis) mit dem Cygwin-Compiler zu übersetzen (und linken).

Das erzeugen einer OV-Bibliothek unter Windows mittels „make“ funktioniert nicht.

 

    Verwenden Sie das richtige make? Die Standard-Makefiles von OV sind GNU-

Makefiles und es muss das entsprechende GNU-Make-Programm verwendet werden.

Dieses finden Sie in den OV-Entwicklungstools, die standardmäßig unter c:\tools\bin zu finden sind. Verweist Ihre Path-Umgebungsvariable (Eingeben von „path“ in der Kommandozeile liefert die aktuelle Einstellung) nicht auf c:\tools\bin oder befindet sich diese Pfadangabe in der Reihenfolge hinter dem Borland-Compiler-Pfad (c:\bc5\bin), so wird das make-Programm nicht gefunden bzw. das Borland-make ausgeführt. In beiden Fällen kann dann das OV-Makefile nicht korrekt abgearbeitet werden. Abhilfe schafft entweder das explizite Ausführen des gnu-makes (c:\tools\bin\make) in dem build\nt-Verzeichnis ihrer Bibliothek oder das Eintragen der geänderten Path-Umgebungsvariable über die Systemsteuerung. Eine weitere Alternative stellt das Umbenennen des make-Programms z.B. in gmake (für GNU-make) dar. (Prüfen Sie evtl. auf Ihrem System, ob dies nicht bereits geschehen ist, und Sie deshalb mit make Ihre Bibliothek nicht übersetzen konnten).

 

Der ov_codegen stürzt ab, wenn in einer Assoziationdefinition die referenzierte Klasse nicht exstiert!

 

     Dieser Fehler ist in der codegen- Version 1.6.1 behoben (OV-Produktversion 1.6.3).

OV zur Laufzeit

In einer von mir erstellten OV-Bibliothek verwende ich eine Assoziation zwischen zwei Klassen. Der Compile-Vorgang läuft einwandfrei durch, aber wenn ich zu Laufzeiten einen Link über den Magellan anlegen möchte, stürzt der OV-Server ab.

 

    Dieses Problem kann dadurch verursacht werden, wenn Sie entweder in Ihrem Makefile

oder in den C-Dateien nicht  mit der Compileroption OV_COMPILE_LIBRARY_libname den Quellcode übersetzt haben. Die vom ov-codegen erzeugten Funktionen werden ohne diese Option nicht mit dem „extern“ Attribut versehen, so dass der Verweis auf die entsprechenden Link-Funktionen nicht in der Externsektion der DLL eingetragen ist. Gleiches gilt übrigens auch für sämtliche C-Funktionen einer ov-Bibliothek.

 

Eine OV- Bibliothek lässt sich im OV-Server nicht instantiieren.

 

    Die Ursache hierfür kann unterschiedlicher Art sein. Entweder kann das Betriebssystem die zugehörige dll (Windows) bzw. das Shared-Object .so (Linux) nicht finden oder die Objektverwaltung kann die Bibliothek nicht als eine gültige OV-Bibliothek erkennen. Letzteres kann vorkommen, wenn die Bibliothek mit einer anderen OV-Version erzeugt wurde als der Server (Die Versionsnummern unterscheiden sich dann mindestens in der zweiten Stelle - z.B. wäre eine Bibliothek mit OV-1.3.0 übersetzt in einem OV-Server 1.5.1 nicht ausführbar, aber eine Bibliothek mit OV-1.5.0 durchaus - und kennzeichnet eine Änderung des OV-Datenmodells, was eine Ausführung prinzipiell verbietet). In solchen Inkompatibilitätsfällen muss entweder das OV selbst (also in ov/build/nt bzw. ov/build/linux „make install“ ausführen) oder die eigene Bibliothek neu übersetzt werden. Der Fall, dass das Betriebssystem die dynamische Bibliothek nicht finden kann liegt an der fehlenden oder fehlerhaften Umgebungsvariable OV_LIBRARY_PATH. Die hier eingetragenen Pfade teilt das OV dem Betriebssystem mit, wenn versucht wird, eine Bibliothek zu instantiieren. Ist diese Umgebungsvariable nicht gesetzt, so versucht das Betriebssystem die dynamischen Bibliotheken in dem Verzeichnis zu finden, in dem der OV-Server gestartet wurde oder in den Standard-Pfaden des jeweiligen Betriebssystems (bei WindowsNT z.B. winnt/system32).  Unter Linux können die Standard-Pfade über die Umgebungsvariable LD_LIBRARY_PATH eingestellt werden. Eine Erweiterung der darin eingetragenen Pfade auf das Verzeichnis, das die Dateien libov.so und libovks.so enthält, ist für den Start des OV-Servers ohnehin notwendig.

     Die für die Kompatibilität zu beachtende Version des OVs findet sich in einem laufenden OV-Server in /vendor/libov_version oder in der Headerdatei ov/include/libov/ ov_version.h.

 

Die Assoziationen „instantiation“ und „containment“ sollten auch im KS explizit sichtbar sein !

 

Seit der libov-Version 1.6.3 gibt es ein zusätzliches Compiler-Makro OV_EXPLAIN, das dazu dient zur Veranschaulichung von OV auch die Assoziationen „instantiation“ und „cotainment“ als Links über KS darzustellen. Ab der Version 1.6.4 besteht auch die Möglichkeit die KS Darstellung zur Laufzeit zu verändern. Dazu muss in der Server Variable /vendor/serverconfiguration der zweite Bool-Eintrag auf True bzw. False gesetzt werden.

 

Beim textuellen dumpen einzelner Instanzen mit ov_dbdump werden vorhandene Links nicht wiedergegeben.

    Mit der OV-Version 1.6.5 wurde dieses Problem behoben.


Die startup Methode eines Objektes wird beim Erzeugen zweimal Aufgerufen. Ist dies gewollt?

 

    Normalerweise ist dies nicht der Fall. Beim Erzeugen eines Objektes werden die Methoden constructor, checkinit und startup genau einmal aufgerufen. Allerdings kann dies dann passieren, wenn die Objekterzeugung im constructor eines Objektes durchgeführt wird und das erzeugte Objekt gleichzeitig Kind (containment-Beziehung zwischen domain und object) des erzeugenden Objektes ist (oder in einer tieferen Hierarchieebene zum erzeugenden Objekt in Beziehung steht). Dann wird nämlich die startup Methode einmal direkt bei der Erzeugung ausgeführt und ein zweites Mal, wenn die auf den constructor folgende startup-Methode des erzeugenden Objektes ausgeführt wird, da in der Standardimplementierung ov_object_startup nicht nur die startup-Methoden aller parts (embedment), sonder auch aller childs (containment) ausgeführt werden. Abhilfe schafft hier die Abfrage des objectstate auf OV_OS_STARTED, der in der startup-Methode ov_object_startup gesetzt wird. Denkbar wäre auch, diese Abfrage in den OV-Kern des Objektes zu übernehmen. Dies ist zum Zeitpunkt der Version 1.6.2 nicht der Fall.