Unter FreePascal habe ich ein paar recht große Projekte laufen, die sowohl für Windows als auch Linux kompiliert werden. In allen zusammen genommen findet sich genau zwei IFDEFs, und zwar zur Festlegung des Pfadtrenners (Slash/Backslash) und zur Ermittlung der Systemsprache. Es ist also halb so wild.
Das geht und weist auf eine von zwei Möglichkeiten (oder beide) hin: 1.) die grundlegenden Bibliotheken von FreePascal sind saugut konzipiert und/oder 2.) dein Projekt benutzt überhaupt nur wenige systemspezifische Konstrukte.
Vergessen darf man auch nicht, daß du
den gleichen Compiler benutzt, möglicherweise sogar denselben, falls du cross-kompilierst. Wenn du jeweils GCC auf Windows, Linux, AIX und Solaris benutzt können dir viele Probleme anderer Leute mit ifdefs auch wumpe sein. Sobald aber schon ein Strauß verschiedener GCC-Versionen benutzt wird, kommste u.U. in unruhige Gewässer. Wenn dann dein Code auch noch gewisse Anforderungen an den Compiler hat (Speicherausrichtung auf 64-bit SPARC [1], bspw.) und der GCC in seiner vorhandenen Version genau dort schwächelt, kommste um eine Alternative für GCC schon nicht mehr herum (SunC/Sun Studio). Wenn du aber bspw. auf Windows auch sinnvoll post-mortem Debugging mit Minidumps machen willst, brauchste DbgHelp-kompatible Symbole, welche der GCC (bzw. der benutzte Linker) nicht erstellt. Also stellste in Windows auf MSVC um. Und so weiter und so fort. Dann sind wir bei vier Systemen schon bei drei Compilern (jeweils gleiche Sprache C/C++), wobei die Versionsunterschiede noch nicht mitgerechnet sind. Da lassen sich #if und #ifdef selten vermeiden. Bei der Software für die ich beruflich verantwortlich zeichne, habe ich es, je nach Paket, mit bis zu 14 Plattform/Prozessorarchitektur-Paaren zu tun. Und da sind dann die
OS-Versionen noch nicht mitgerechnet, sei es wegen glibc oder wegen einer inkompatiblen ABI-Änderung.
Aber ich hoffe daß hier die Konkurrenz (FPC vs. Delphi) die treibende Kraft ist und sich die Entwickler von Delphi ein Beispiel an der tollen Umsetzung bei FPC nehmen. Bei Clang vs. GCC hat es ja geklappt. Die hilfreichen Fehlermeldungen gibt es nun schon eine Weile auch mit dem GCC und die Sanitizer wurden auf GCC portiert.
Also kommt man ggf. doch in die IFDEF-Hölle, wenn man nicht aufpasst.
Der Nachsatz ist wichtig: wenn man nicht aufpaßt, ja. Und selbst wenn man aufpaßt, sollte das Aufpassen so sorgfältig geschehen, daß man sich keine eigenen Probleme schafft (bspw. statt mit den IFDEFs Unterschiede zu betonen, lieber Gemeinsamkeiten der jeweiligen Varianten betonen).
Ich versuche meistens immer eher einen Grundsatz von Funktionen zu verwenden, und Spezialitäten erstmal wegzulassen.
Also z.B. strcpy, memcpy, etc. solche Funktionen die es schon seit den 60ern unverändert geben sollte.
Sollte doch möglich so einen Satz Grundfunktionen zu finden wo die
API nicht komplett verrückt spielt,
und ich gehe für mich jetzt mal vom aktuellsten Linux aus.
Muss ja bei Neuprojekten nicht 20 Jahre rückwärtskompatibel sein.
Der Witz ist, daß es mit SUS/POSIX vermutlich in vielen Fällen dennoch (quelltext-)rückwärtskompatibel ist. Es sei denn du machst eklige Sachen wie eigene Typen in Fällen einzusetzen wo eingebaute und Bibliothekstypen benutzt werden sollten (bspw. direkt irgendwelche Integer statt ptrdiff_t, off_t).
Und viele der
API-Funktionen die spezifisch nur für ein System entwickelt wurden (vfork, wait3, wait4), haben es auch schon in andere Systeme geschafft (bei Linux/FreeBSD mehrfach), bei anderen gibt es gute Alternativen. Aber in vielen Fällen wird das erst dann relevant wenn du deinen Code auf Geschwindigkeit trimmst oder ähnliches. Solange du ein 08/15-Programm schreibst (also keinen Datenbank- oder Webserver) und mit der Geschwindigkeit zufrieden bist, tun es auch jene Funktionen für Speicherverwaltung, Stringverarbeitung und E/A, welche auf allen unixartigen Systemen quelltextkompatibel implementiert sind.
Ich warte mal ab wie das im neuen Delphi umgesetzt wird, da bin ich schonmal gespannt.
Ich auch. Hoffe auf Rückmeldungen in diesem Thema. Da werd' ich dann ja benachrichtigt.
[1] Speicherausrichtung wird relevant wenn du bspw. auf Integer zugreifst die nicht korrekt ausgerichtet sind. Zwar geht auch das bspw. in SunC und GCC, aber es führt zu einer Geschwindigkeitsreduktion, weil die Ausrichtung auf Prozessorebene erwartet wird. Sind Daten falsch ausgerichtet, kommt es zu einem Fehler ähnlich wie bei einer Division durch Null. Dieser Fehler kann abgefangen und behandelt werden, aber diese Behandlung führt eben zu Performanceverlusten.