Der Compiler unterstützt als Voreinstellung in den Sprachmodi C++ V3, C++ 2017 und C++ 2020 die automatische Instanziierung (INSTANTIATION=*AUTO). Dadurch können Sie Quellcode übersetzen und die erzeugten Module binden, ohne sich um die notwendigen Instanziierungen kümmern zu müssen.
Im Folgenden beziehen sich die Erläuterungen zur automatischen Instanziierung auf Template-Einheiten, für die es keine explizite Instanziierungsanforderung (template declaration) und kein instantiate-Pragma gibt.
Voraussetzungen
Der Compiler erwartet dabei für jede Instanziierung eine Quelldatei, die sowohl eine Referenz auf die benötigte Instanz enthält als auch die Definition der Template-Einheit und aller für die Instanziierung der Template-Einheit benötigten Typen. Um die letzten beiden Anforderungen zu erfüllen, haben Sie folgende Möglichkeiten:
Jede
.h
-Datei, in der eine Template-Einheit deklariert ist, enthält entweder auch die Definition der Template-Einheit oder inkludiert eine Datei, die diese Definition enthält.Implizites Inkludieren
Wenn der Compiler eine Template-Deklaration in einer.h
-Datei findet und auf eine Instanziierungsanforderung stößt, sucht er nach einer Quelldatei mit dem Basisnamen der.h
-Datei und einem Standard-Suffix für C++-Quelldateien (.C
,.CPP
,.CXX
oder.CC
). Diese Datei wird beim Instanziieren ohne Meldung am Ende der jeweiligen Übersetzungseinheit inkludiert. Weitere Einzelheiten siehe Abschnitt „Implizites Inkludieren“.Der Programmierer stellt sicher, dass die Dateien, die Template-Einheiten definieren, auch die Definitionen der benötigten Typen enthalten, und fügt in diese Dateien C++-Code oder Instanziierungs-Pragmas ein, mit denen die Instanziierung der dortigen Template-Einheiten angefordert wird.
Erste Instanziierung ohne Definitionsliste
Alternativ zu dem folgenden Verfahren kann auch das Definitionslisten-Verfahren angewandt werden (siehe "Erste Instanziierung mithilfe der Definitionsliste (temporäres Repository)").
Bei der automatischen Instanziierung werden intern folgende Schritte durchgeführt:
Instanziierungs-Informationsdateien erzeugen
Wenn eine oder mehrere Quelldateien zum ersten Mal mit der COMPILE-Anweisung übersetzt werden, werden noch keine Template-Einheiten instanziiert. Für jede Quelldatei, die ein Template benutzt, wird, falls noch nicht vorhanden, eine Instanziierungs-Informationsdatei erzeugt. Diese Instanziierungs-Informationsdatei wird in die PLAM-Bibliothek des zu erzeugenden Moduls abgelegt. Der Name entspricht dem um das Suffix.II
erweiterten Namen des Moduls (siehe Abschnitt „Bildung von Modulnamen“). Bei der Übersetzung eines QuellprogrammsABC.CC
(ohne explizite Angabe eines Modulnamens) würde z.B. die DateiABC.II
erzeugt werden. Die Instanziierungs-Informationsdatei darf vom Benutzer nicht verändert werden.Module erzeugen
Die erzeugten Module enthalten Informationen darüber, welche Instanzen bei der Übersetzung einer Quelldatei erzeugt werden könnten und ggf. benötigt werden.Template-Instanziierungen zuweisen
Wenn die Module mit der BIND-Anweisung gebunden werden, wird vor dem eigentlichen Binden der Prälinker aufgerufen. Dieser durchsucht die Module nach Referenzen und Definitionen von Template-Einheiten und nach zusätzlichen Informationen über erzeugbare Instanzen. Wenn er keine Definition einer benötigten Template-Einheit findet, sucht er nach einem Modul, in dem angegeben ist, dass es die Template-Einheit instanziieren könnte. Wenn er ein solches Modul findet, weist er die Instanziierung diesem Modul zu.Instanziierungs-Informationsdatei aktualisieren
Für alle Instanziierungen, die einem Modul zugewiesen wurden, werden in der zugehörigen Instanziierungs-Informationsdatei die Namen der entsprechenden Instanzen geschrieben.Nachübersetzen
Der Compiler wird intern erneut aufgerufen, um alle Dateien nachzuübersetzen, deren Instanziierungs-Informationsdatei verändert wurde.Neue Module erzeugen
Wenn der Compiler eine Datei übersetzt, liest er die Instanziierungs-Informationsdatei für diese Übersetzungseinheit und erzeugt ein neues Modul mit den benötigten Instanzen.Wiederholung
Die Schritte 3 bis 6 werden solange wiederholt, bis alle benötigten und generierbaren Instanzen erzeugt sind.Binden
Die Module werden gebunden.
Erste Instanziierung mithilfe der Definitionsliste (temporäres Repository)
Da das obige Verfahren (siehe "Erste Instanziierung ohne Definitionsliste") einige Dateien mehr als einmal nachübersetzt (rekompiliert), wurde eine Option hinzugefügt, die den gesamten Prozess beschleunigen soll.
Dabei werden die Dateien in der Regel nur einmal nachübersetzt. Durch das Verfahren wird der Hauptanteil der Instanziierungen den ersten nachzuübersetzenden Dateien zugeordnet. Dies hat in einigen Fällen Nachteile, da dadurch ihre Objektgröße ansteigt (als Ausgleich werden andere Objekte kleiner).
Die obigen Schritte 3-5 werden modifiziert. Damit sieht der Algorithmus folgendermaßen aus:
Instanziierungs-Informationsdateien erzeugen
Wenn eine oder mehrere Quelldateien zum ersten Mal mit der COMPILE-Anweisung übersetzt werden, werden noch keine Template-Einheiten instanziiert. Für jede Quelldatei, die ein Template benutzt, wird, falls noch nicht vorhanden, eine Instanziierungs-Informationsdatei erzeugt. Diese Instanziierungs-Informationsdatei wird in die PLAM-Bibliothek des zu erzeugenden Moduls abgelegt. Der Name entspricht dem um das Suffix.II
erweiterten Namen des Moduls (siehe Abschnitt „Bildung von Modulnamen“). Bei der Übersetzung eines QuellprogrammsABC.CC
(ohne explizite Angabe eines Modulnamens) würde z.B. die DateiABC.II
erzeugt werden. Die Instanziierungs-Informationsdatei darf vom Benutzer nicht verändert werden.Module erzeugen
Die erzeugten Module enthalten Informationen darüber, welche Instanzen bei der Übersetzung einer Quelldatei erzeugt werden könnten und ggf. benötigt werden.Template-Instanzen einer Sourcedatei zuordnen
Falls es Referenzen für Template-Einheiten gibt, für die es keine Definitionen im Satz der Module gibt, so wird eine Datei ausgewählt, die eine der Template-Einheiten instanziieren könnte. Alle Template-Einheiten, die in dieser Datei instanziiert werden können, werden dieser zugeordnet.Instanziierungs-Informationsdatei aktualisieren
Der Satz an Instanziierungen, der dieser Datei zugeordnet ist, wird in der assoziierten Instanziierungs-Datei aufgezeichnet.Speichern der Definitionsliste
Intern wird eine Definitionsliste im Speicher gehalten. Sie enthält eine Liste aller Template-bezogenen Definitionen, die in allen Modulen gefunden wurden. Diese Liste kann während des Nachübersetzens gelesen und verändert werden.Hinweis
Diese Liste wird nicht in einer Datei abgelegt.Nachübersetzen
Der Compiler wird intern erneut aufgerufen, um die korrespondierende Quelldatei nachzuübersetzen.Neue Module erzeugen
Wenn der Compiler eine Datei nachübersetzt, liest er die Instanziierungs-Informationsdatei für diese Übersetzungseinheit und erzeugt ein neues Modul mit den benötigten Instanzen. Wenn der Compiler während der Übersetzung die Gelegenheit erhält, weitere referenzierte Template-Einheiten zu instanziieren, die nicht in der Definitionsliste erwähnt sind und in den aufgelösten Bibliotheken nicht gefunden wurden, führt er auch diese Instanziierungen durch (z. B. bei Templates, die in Templates enthalten sind). Er führt dem Prälinker eine Liste der Instanziierungen zu, die er auf seinem Weg erhalten hat, so dass der Prälinker sie der Datei zuordnen kann.
Dieser Prozess erlaubt schnellere Instanziierung. Zudem reduziert sich die Notwendigkeit, eine bestehende Datei während des Prälink-Prozesses mehr als einmal nachzuübersetzen.- Wiederholung
Die Schritte 3 - 7 werden solange wiederholt, bis alle benötigten und generierbaren Instanzen erzeugt sind. Binden
Die Module werden gebunden.
Weiterentwicklung
Wenn ein Programm korrekt gebunden wurde, enthalten die zugehörigen Instanziierungs-Informationsdateien alle Namen der definierten und benötigten Instanzen. Von da an zieht der Compiler, wenn eine Quelldatei erneut übersetzt wird, die Instanziierungs-Informationsdatei zu Rate und instanziiert wie bei einem normalen Übersetzungslauf. Das heißt, außer in Fällen, in denen Veränderungen an den Instanzen gemacht werden, sind alle für den Prälinker nötigen Instanziierungen in den Modulen gespeichert und keine Instanziierungsanpassungen mehr nötig. Das ist auch der Fall, wenn das Programm vollständig neu übersetzt wird.
Eine irgendwo im Programm bereitgestellte Spezialisierung einer Template-Einheit betrachtet der Prälinker als Definition. Da diese Definition beliebig auftretende Referenzen auf diese Template-Einheit befriedigt, sieht der Prälinker keine Notwendigkeit, eine Instanz für die Template-Einheit anzufordern. Wenn eine Spezialisierung zu einem Programm hinzugefügt wird, das vorher schon einmal übersetzt wurde, löscht der Prälinker die Instanziierungszuweisung aus der entprechenden Instanziierungs-Informationsdatei.
Bis auf folgende Ausnahme darf die Instanziierungs-Informationsdatei vom Benutzer nicht verändert, z.B. umbenannt oder gelöscht werden: Im selben Compilerlauf wird zuerst eine Quelldatei übersetzt, in der eine Definition verändert wurde und anschließend eine Quelldatei, in die eine Spezialisierung eingefügt wurde. Wenn nun die Übersetzung der ersten Datei (mit der geänderten Definition) mit Fehler abgebrochen wird, muss die zugehörige Instanziierungs-Informationsdatei von Hand gelöscht werden, damit sie vom Prälinker neu generiert werden kann.
Zusammenspiel der Übersetzungs- und Prälinkerläufe
Da bei der automatischen Template-Instanziierung durch den Prälinker u.a. Nachübersetzungen stattfinden, spielen die Bedingungen, unter denen die Übersetzung (COMPILE) stattfindet, auch beim Prälinkerlauf (BIND ACTION=*PRELINK,...) eine wichtige Rolle. Technisch gesehen werden alle für die Übersetzung, Code-Generierung und Compilerausgaben relevanten Optionen in die entsprechenden Instanziierungs-Informationsdateien eingetragen und bei der automatischen Template-Instanziierung ausgewertet. Damit die Nachübersetzungen und andere Aktualisierungen beim Instanziieren funktionieren, sind insbesondere folgende Punkte zu beachten:
Quellprogrammeingaben über SYSDTA sowie Listenausgaben auf SYSLST und SYSOUT werden nicht unterstützt und mit einer entsprechenden Fehlermeldung abgewiesen.
Sämtliche Ein-/Ausgabe-Dateien und -Bibliotheken des Übersetzungslaufs müssen auch für den Prälinkerlauf auffindbar und zugreifbar sein und dürfen demzufolge weder namentlich geändert noch gelöscht werden. Wenn der Prälinkerlauf in einer anderen Umgebung (z.B. Benutzerkennung) stattfindet, müssen bei der Übersetzung vollqualifizierte Dateinamen verwendet werden, d.h. bei BS2000-Dateien und PLAM-Bibliotheken Namen inklusive <cat-id> und <user-id>, bei POSIX-Dateien absolute Pfadnamen (beginnend mit /).
Die Option *INCREMENT ist nicht erlaubt für alle folgenden Ausgabedateien:
module element name
cif element name
listing element name
Achtung: Die Kompilierung wird in diesem Fall abgebrochen.
Wenn man einen expliziten Versionsstring für ’module name’ eingibt, wird eine ii-Element-Datei mit demselben Versionsstring gesucht, gelesen und geschrieben. (Sofern ein existierendes ii-Element mit einem anderen Versionsstring benutzt werden soll, muss dieses Element kopiert und unter neuem Namen abgelegt werden, bevor es gebunden wird bzw. die Template-Instanziierung beginnt.) Dieses Verhalten ist inkompatibel zum C++-Compiler V3.0.
Vorbinden und dynamisches Binden
Der Prälinker führt die automatische Instanziierung nur in den vom Compiler generierten Einzelmodulen durch, da er hierzu die eindeutige Zuordnung von Modul und Instanziierungs-Informationsdatei (.II
-Datei) benötigt. Der Prälinker wird ausschließlich mit der BIND-Anweisung des Compilers aktiviert (ACTION=*PRELINK). Wenn in der BIND-Anweisung nur ACTION=*MODULE-GENERATION angegeben wird, wird keine Template-Instanziierung durchgeführt.
Mit der BIND-Anweisung vorgebundene „Großmodule“ oder dynamisch zu bindende Module, die Instanzen von Template-Einheiten benötigen, müssen beim Erstellen des fertigen Programms (durch statisches oder dynamisches Binden)
entweder diese Instanzen bereits enthalten; dies kann durch explizite Instanziierung und/oder das Vorinstanziieren der Module mit der BIND-Anweisung
(ACTION=*PRELINK) erreicht werdenoder entsprechende Include-Dateien mit
can_instantiate
-Pragmas bereitstellen.
Beim Vorinstanziieren mit der BIND-Anweisung ist unbedingt darauf zu achten, dass die C++-Bibliotheken und C++-Laufzeitsysteme des CRTE (Standard-C++-Bibliothek, C++-Laufzeitsystems, Tools.h++-Bibliothek) vom Prälinker mitbetrachtet werden, da sonst Duplikat-Definitionen entstehen können. Die Bibliotheken werden automatisch berücksichtigt, wenn in der MODIFY-BIND-PROPERTIES-Anweisung die STDLIB-Option auf *DYNAMIC oder *STATIC gesetzt ist und die TOOLSLIB-Option auf *YES. Wenn die CRTE-Bibliotheken selbst dynamisch gebunden werden sollen, können Duplikat-Definitionen folgendermaßen vermieden werden:
In einem ersten Schritt die Module unter Berücksichtigung der verwendetet CRTE-Bibliotheken vorinstanziieren
//MODIFY-BIND-PROPERTIES STDLIB=*DYNAMIC / *STATIC [,TOOLSLIB=*YES], ... //BIND ACTION=*PRELINK, ...
In einem zweiten Schritt die Module mit offenen Externverweisen auf die verwendeten CRTE-Bibliotheken binden
//MODIFY-BIND-PROPERTIES STDLIB=*NONE [,TOOLSLIB=*NO], ... //BIND ACTION=*MODULE-GENERATION, ...
Wenn der Prälinker- und Bindelauf nicht getrennt erfolgen sollen, muss die ADD-PRELINK-FILES-Option verwendet werden. Diese Methode hat den Nachteil, dass die Namen der CRTE-Bibliotheken dann explizit angegeben werden müssen.
Bei einer Standardinstallation des CRTE und im C++ V3-Modus z.B. mit:
//MODIFY-BIND-PROPERTIES ADD-PRELINK-FILES=(*LIB(LIB=$.SYSLNK.CRTE.STDCPP),- *LIB(LIB=$.SYSLNK.CRTE.RTSCPP) [,*LIB(LIB=$.SYSLNK.CRTE.TOOLS)] ),- STDLIB=*NONE, ... //BIND ACTION=(*PRELINK,*MODULE-GENERATION), ...