Ein beträchtlicher Teil der wirklich vorzeigbaren ST-Software entstammt dem Bereich »Public Domain« und verwandten Quellen (»Freeware«, »Shareware«). Zu den beeindruckendsten dieser Softwarepakete gehören Programme, die bereits früher auf meist größeren Computern entwickelt wurden und nun in Fassungen für den ST vorliegen — man denke an »MicroEmacs«, »TeX«, »Metafont«, »Little Smalltalk« oder »XLISP«.
Die kreativste Crew von Programmierern solcher Juwelen ist zweifellos die »Free Software Foundation«, die sich auf das Betriebssystem UNIX auf 32-Bit-Computern konzentriert. Programme der Free Software Foundation sind nicht Public Domain, denn damit würden die Programmierer freiwillig alle Rechte an ihren Programmen abgeben. Statt dessen stimmt der Anwender einem Lizenzvertrag zu,
Ihre Produkte nennen die Programmierer »GNU software«, wobei »GNU« als Akronym für »GNU is Not Unix« steht — mithin die einzige mir bisher bekannte rekursive Abkürzung. GNU software soll sich zwar durch ähnliche oder größere Leistungsfähigkeit auszeichnen, im Gegensatz zu den kommerziellen Gegenstücken aber gratis sein.
Von GNU software sind zur Zeit komplette Entwicklungssysteme für »C« und »C++« (objektorientiertes C) erhältlich. Zum Umfeld dieser Pakete gehören »Bison« (ein Generator für Parser), »GNU-Make«, »GNU-AR« (Bibliotheksmanager), »LD« (Linker) und »GAS« (der Assembler).
Als erster Vorgeschmack auf die Dinge, die hoffentlich noch folgen, erhielten wir die Atari-Portierung von »GNU-CC«, dem C-Entwicklungssystem. Es waren in unserem System alle ausführbaren Programme (GCC, GNU-CPP, GNU-CC1, GNU-AS, GNU-LD, GNU-AR) enthalten sowie die Runtime-Bibliothek mit den meisten Routinen im Quelltext. Bis zum Redaktionsschluß erhielten wir leider noch nicht die Quellcodes von Compiler und Assembler (wozu man die unter Umständen benötigt, sehen Sie noch...). Daher ist dieser Artikel weniger als Compilertest, sondern mehr als Zusammenfassung der wichtigsten Aspekte von GNU-CC zu verstehen — gerade am Compilerbau interessierte Leser sollten gut aufpassen.
Eine Shell wird nicht mitgeliefert — der Autor der ST-Portierung empfiehlt dazu die PD-Kommando-Shell »Guläm« (von Prabhaker Mateti), die man auch von »Jefferson Modula« und »Aztec C« her kennt. Jede andere Shell, die Environment-Variablen beherrscht, ist aber genausogut einsetzbar (»PCOMMAND«, »Master«, »MSH«, »Mupfel« und wie sie alle heißen).
Aufgrund seiner Herkunft arbeitete GNU-CC erst nach Lösen eines kleinen Rätsels: Zunächst erschienen nämlich partout keine Meldungen des Compilers auf dem Bildschirm. Woran lag’s? UNIX verwendet Standardkanal 2 als »stderr« (also als Ausgabekanal für Fehlermeldungen). Normalerweise landen alle Ausgaben auf »stderr« auf dem Bildschirm — nur eben nicht beim ST, bei dem Standardkanal 2 die serielle Schnittstelle bedient... (Abhilfe: I/O-Redirection).
Wie es sich für eine UNIX-Entwicklung geziemt, steuert man alle Programme ausschließlich über die Kommandozeile. Die Schaltzentrale ist GCC, das je nach Bedarf den Präprozessor, den Compiler, den Assembler und den Linker startet. Wer mit UNIX-Compilern oder beispielsweise »Mark Williams C« vertraut ist, fühlt sich sofort heimisch. Man sieht: GNU-CC ist ein Entwicklungssystem altbewährter Art. C-Präprozessor und Compiler sind zwei separate Programme, die gemeinsam zunächst einmal Assembler-Sourcecode erzeugen. Der Assembler übersetzt diesen in Maschinencode und ruft den Linker zur Arbeit.
GNU-CC ist im Grunde genommen der erste C-Compiler für den ST, der den vollen ANSI-Standard erfüllt (man erinnere sich: Bei Turbo-C hat man die — zugegebenermaßen nicht sehr wichtigen — Trigraphen [1] nicht implementiert).
Nicht unumstritten sind Spracherweiterungen [2], durch die die eigenen Sourcecodes inkompatibel mit anderen Compilern werden. Bei GNU-CC steht man natürlich gut da — besitzt man doch die gesamten Quelltexte des Compilers und kann diesen damit auch auf eine neue Hardware übertragen. Hinzu kommt, daß alle Erweiterungen meiner Meinung nach gut durchdacht sind und die Fähigkeiten von C noch weiter steigern (vielleicht sollte sich das ANSI-Komitee mal GNU-CC ansehen):
Zusammengesetzte Ausdrücke dürfen innerhalb eines C-Ausdrucks auftauchen. Damit hat man die Möglichkeit, »Blöcke« anzulegen und darin lokale Variablen zu deklarieren. Gerade beim Schreiben von Makros ergeben sich dadurch große Vorteile, weil es erlaubt ist, Makro-interne Variablen anzulegen.
Bei »typedef« sind auch Ausdrücke der Form »typedef name = exp;« erlaubt, wobei »exp« irgendein beliebiger C-Ausdruck ist. Damit läßt sich der Typ eines C-Ausdrucks bestimmen und weiterverwenden.
Analog zu »sizeof« gibt es »typeof«, das den Typen eines Ausdrucks liefert.
Für Experten: Zusammengesetzte Anweisungen, bedingte Anweisungen und Type-Casts sind auf der linken Seite von Zuweisungen erlaubt.
Der mittlere Operand in einer bedingten Anweisung darf wegfallen, »x ? : y« ist erlaubt und leistet dasselbe wie »x ? x : y«, mit dem Unterschied, daß der Ausdruck »x« nur einmal ausgewertet wird.
Man kann Arrays mit Länge Null deklarieren, was die Benutzung variabel großer Arrays innerhalb einer Struktur stark vereinfacht.
Innerhalb von Funktionen lassen sich variabel große Felder deklarieren. Damit ist endlich folgendes zulässig:
void foo ( int a ) { char feld [a]; … }
— Addition und Subtraktion auf »void« und Funktionspointer ist erlaubt, da für ihre Größe 1 angenommen wird (durch »sizeof«).
Direkte Zuweisungen von durch geschweifte Klammern konstruierte Strukturen sind erlaubt. Beispiel:
rec = ((struct greet) { x, y, x+ 100, y+100 ) );
Zur Wahrung der Kompatibilität mit anderen Compilern gibt es drei Compiler-Switches:
— »ansi« schaltet die meisten Erweiterungen des ANSI-Standards ab. — »pedantic« sorgt dafür, daß wirklich nur noch Programme ohne Warnung compiliert werden, die hundertprozentig der ANSI-Norm entsprechen.
Aber nicht nur diese Erweiterungen des Sprachumfangs machen diesen Compiler interessant. Auch der für ST-Verhältnisse neuartige Codegenerator dürfte in der nächsten Zeit den anderen Compilerbauern erhebliche Kopfschmerzen verursachen.
Der Compiler baut für jede C-Funktion zunächst einen kompletten Syntaxbaum im Speicher auf (zum Speicherbereich kommen wir später). Er optimiert ihn noch bevor er den eigentlichen Code erzeugt. Folgende Optimierungen sind im Manual beschrieben:
Praktischerweise lassen sich die meisten dieser Optimierungen separat ein-und ausschalten.
Wie schlägt sich dieser Wundercompiler nun in unseren AG-Benchmarks? Zunächst fällt auf, daß er in den Integer-Benchmarks besonders schlecht abschneidet, weil er zur Division nicht den DIV-Befehl des MC 68000 benutzt. In allen anderen Tests (die Trigonometrie-Tests konnten wir wegen der noch lückenhaften Library bisher nicht durchführen) gab es passable bis sehr gute Ergebnisse. Eine Analyse des erzeugten Codes zeigt aber deutlich, daß die verschiedenen Optimierungsmaßnahmen nicht nur auf dem Papier erfolgen. So vereinfacht GNU-CC die Hauptschleife in »IntMath« radikal. Man kann sich allerdings weitere Optimierungen gut vorstellen, auf jeden Fall Arbeit für unsere Benchmark-Autoren, die sich bemühen, daß die Testschleifen nicht optimiert werden können. Es stellt sich allerdings die Frage, ob wir nicht auch einen speziellen Optimierungsbenchmark einführen, um diese erfreuliche Eigenschaft eines Compilers zu erfassen.
Wegen der schlechten Ergebnisse in den Integer-Benchmarks ist man leicht versucht, diesen Compiler als unbrauchbar einzustufen. Als Besitzer der Compiler-Sourcen ändert man jedoch leicht alle Aspekte des Codegenerators und beseitigt damit auch die oben erwähnten Schwächen. Anpassungen an spezielle Arithmetik-Coprozessoren sind so auch sehr leicht vorzunehmen. In einer eigenen Assembler-Beschreibungssprache gibt man alle Aspekte des Zielprozessors an und programmiert sogar noch Peephole-Optimierungen. Damit entwickelt GNU-CC in der Praxis auch zum selbstgebastelten Expertensystem in Sachen Assembler-Programmierung — bisher noch nicht von ihrer Assembler-Manie geheilte Programmierer sollten sich ernsthaft überlegen, was sinnvoller ist: einmal dem Compiler einen guten Kniff beizubringen, oder die Routine immer wieder als Assembler-Code ausformulieren zu müssen.
Soviel zum Compiler. Der Linker wartet mit keinen besonderen Fähigkeiten auf — daß er statt des Formats von Digital Research das von UNIX vorzieht, ist aufgrund seiner Herkunft einzusehen. Die Standardbibliotheken scheinen weitgehend komplett zu sein und sind zum Teil, aus den »dLibs« von Dale Schumacher (wir berichteten) übernommen. GEM-Bibliotheken fehlen bislang.
Kommen wir nun zu einem etwas düsteren Kapitel: den Hardwareanforderungen. Ohne Festplatte und 2 MByte Speicher läuft gar nichts — schon deshalb, weil der Compiler in der vorliegenden Version einen Stack von 512 KByte anlegt (eine Patchanweisung liegt allerdings bei). Auch in Sachen Turnaround-Zeit sollte man nicht auf ähnlich gute Ergebnisse wie bei »Laser-C« oder »Turbo-C« hoffen.
GNU-CC ist bereits in dieser vorliegenden Version ein absoluter Leckerbissen. Jeder Compilerbauer sollte den Sourcecode von GNU-CC genau studieren. Wir berichten erneut, sobald uns eine vollständige, auch für den Durchschnittsprogrammierer verwendbare Version vorliegt — noch ist man bei der Konkurrenz besser aufgehoben. Das Thema C-Compiler bleibt auf jeden Fall spannend. (uh)
Literaturhinweise:
[1] Gereon Steffens: »Der Stand des Standards«, ST-Magazin, 9/1988
[2] Richard M. Stallman: »Internals of GNU CC«
Benchmark AG Version 1.2 für C
Test | Zeit |
---|---|
Intmath short | 10.07 |
Intmath long | 9.60 |
Realmath short | 11.52 |
Realmath long | 12.80 |
Triglog short | — |
Triglog long | — |
For | 0.77 |
Loop | 0.77 |
Repeat | 0.77 |
While | 0.77 |
ArrayAccess | 1.28 |
RecordAccess | 0.41 |
RecordArray | 0.39 |
WriteToFile | 14.27 |
ReadFromFile | 5.51 |
Pass Parameters | 4.39 |
Pass Structures | 1.52 |
Conversions | 29.45 |
Strings | 0.97 |