C FPL - eine Einzel-Header Platform Abstraktionsschicht für C/C++

Finalspace

Lt. Junior Grade
Registriert
Sep. 2009
Beiträge
369
Hallo,

ich möchte euch mein aktuelles Projekt an dem ich seit einiger Zeit arbeite vorstellen:
Eine super einfache stressfreie Platform Abstraktionsschicht für C in nur einer einzigen Header-Datei.

Der Hauptfokus ist Spiel -und Simulationsprogrammierung, daher ist das Standardverhalten man bekommt ein Fenster und einen OpenGL Rendering Context - ähnlich wie GLUT.
Die API ist einfach gestrickt und enthält nur gut strukturierte abstrahierte Platformfunktionen, ohne irgendwas zu verstecken.


Was ist eine Platform-Abstraktionsschickt?

Ein Set an Funktionen um Betriebssystemabhängige Dinge zu verarbeiten, z.b. Fenster erstellen, Datei laden, Speicher erzeugen, Pfad auslesen/zusammenbauen, Thread erzeugen, usw.


Warum eine Platform Abstraktionsschicht, obwohl es schon etliche gibt?

- Es gibt keine einzige von den brauchbaren die ohne Libs oder DLL´s auskommen
- Bei vielen muss man peinlich genau aufpassen, das die passende LIB zur C-Runtime mit korrekter Einstellung passt
- Viele sind aufgeblaßen und machen deutlich mehr als nur die Platform zu abstrahieren
- Keine oder schlechte Kontrolle über Speicher
- Es gibt keine brauchbaren Einzel-Datei-Header-Bibliotheken welche die Platform abstrahieren
- Ich habe keine Lust mehr Platformspezifischen Code jedesmal aufs neue zu schreiben
- Debuggen bei Platform spezifischen Problemen ist nur bedingt oder gar nicht möglich


Lösung/Idee:


- Es ist in C/89 geschrieben und 100% C++ kompatibel, daher ist es sehr leicht neue Platformen/Compiler zu integrieren
- Es gibt nur eine Header Datei die man einbinden muss und das wars
- Es ist komplett Open-Source und kann daher beliebig in jedem Projekt verwendet und angepasst werden
- Es wird kein Code versteckt, alles ist erreichbar und gut gekennzeichnet
- Einfache und leicht verständliche API, die keine große Dokumentation brauch
- Erzeugt keinen direkten Speicher (Das ist dem User überlassen)
- Nutzt nur reine Betriebssystemsfunktionen, vermeidet daher C Runtime wo es nur geht
- C-Runtime Bibliothek ist nicht zwingend erforderlich
- Arbeitet gut mit anderen Bibliotheken zusammen, z.b. (ImGUI, Box2D, etc.)
- Features könnnen nach Bedarf komplett deaktiviert werden (Window, OpenGL, etc.)
- Ich möchte ohne große Mühe jede Funktion debuggen können
- Ich möchte mehr über programmierung von Nicht-Windows Betriebssysteme erfahren (X11, Linux, Unix etc.)


Features:

- Erstellung/Konfiguration eines einzelnen optionalen Fensters
- Erstellung eines optionalen OpenGL Rendering Kontext auf dem Fenster
- Speicher erzeugen/freigeben
- Zeit-Operationen
- Threading
- Datei und Pfad Funktionen
- Atomische Operationen
- Dynamische Bibliotheken laden (.dll / .so)
- Konsolen ein/ausgabe


Aktueller Stand / Geplant:

- Im Moment ist das ganze noch nicht wirklich vollständig, aber es ist benutzbar und funktioniert einwandfrei
- Einige API-Aufrufe gefallen mir noch nicht, da muss ich noch ein wenig drüber nachdenken, z.b. bei (fpl_ListFilesBegin, fpl_ListFilesNext, etc.)
- Bisher nur x86 und x64 für Windows

- Support für Direct2D/3D/Vulcan (Nur die reine Initialisierung)
- Audio-Ausgabe (DirectSound, ALSA)
- Automatisiertes Testing
- Dokumentation und mehr Beispiele
- Mehr Unterstützung für Platformen (Linux/Unix, vielleicht Android mal schauen)
- Mehr Pre-Processor Optionen um Features rauszukompilieren (Manche nutzen z.b. lieber C++ STL oder ähnliches)
- Hilfsfunktionen komplett in eigene Bibliothek auslagern, welche keine direkten Platform spezifikationen haben z.b. (fpl_ExtractFileName, fpl_RemoveEmptyDirectory)
- Speicher Management vollständigt dem User überlassen. Im Moment wird noch an einer Stelle (Platform Eingabe Ereignisse Queue) Speicher über fpl_AllocateMemory erzeugt.
- C-Runtime komplett abschaltbar zu machen ist nicht ganz zu einfach, wie ich es mir vorgestellt habe - daher muss ich mir hier noch was überlegen oder den Support dafür komplett fallen lassen


Probleme:

- Die Biliotheken verträgt sich nicht mit anderen Platform-Abstraktions-Bibliotheken wie z.b. (SDL, SFML, GLUT, GLFW, etc.),
da alle Platform Bibliotheken immer magisches Zeug mit Einstiegspunkten machen, sich daher alle in die Quere kommen.


Quellcode:

https://github.com/f1nalspace/final_game_tech


Feedback:

Was haltet ihr davon? Was kann man tun um es noch besser zu machen? Fehlt noch etwas wichtiges?
Gerne sind jegliche konstruktive Kommentare erwünscht, aber nutzlose Hasskommentare werden sofort gemeldet.

Grüße,
Final
 
Zuletzt bearbeitet:
Ist ja erstmal nett gedacht, aber spätestens das wird die Realisierung in einer Header Datei eigentlich nicht sauber möglich machen.
Finalspace schrieb:
Probleme:

- Die Biliotheken verträgt sich nicht mit anderen Platform-Abstraktions-Bibliotheken wie z.b. (SDL, SFML, GLUT, GLFW, etc.),
da alle Platform Bibliotheken immer magisches Zeug mit Einstiegspunkten machen, sich daher alle in die Quere kommen.
Es gibt einige Header Dateien welche nur vor oder nach anderen Header Dateien inkludiert werden könnten/sollten. Du wirst aber zum einen wohl kaum eine 100% Abdeckung aller benötigten Features erreichen. Das bedeutet wenn nun ein Nutzer deine Header Datei nutzen möchte aber für das zusätzliche Feature eine andere benötigt könnte es zu Probleme kommen. Das ist der Grund warum man in anderen solcher Libs das einbinden von Systemspezifischen Sachen möglichst in die Code Dateien verschiebt.
 
Fonce schrieb:
Ist ja erstmal nett gedacht, aber spätestens das wird die Realisierung in einer Header Datei eigentlich nicht sauber möglich machen.

Es gibt einige Header Dateien welche nur vor oder nach anderen Header Dateien inkludiert werden könnten/sollten. Du wirst aber zum einen wohl kaum eine 100% Abdeckung aller benötigten Features erreichen. Das bedeutet wenn nun ein Nutzer deine Header Datei nutzen möchte aber für das zusätzliche Feature eine andere benötigt könnte es zu Probleme kommen. Das ist der Grund warum man in anderen solcher Libs das einbinden von Systemspezifischen Sachen möglichst in die Code Dateien verschiebt.

Es ist nicht nur eine Header-Datei, sondern enthält direkt auch den Code mit getrenntem Implementierungsblock, der in einer Translation-Unit eingebunden werden muss, wo ist egal. Das muss auch pro Executable nur in einer Translation Unit passieren, ansonsten kann man die Header-Datei überall beliebig einbinden. Reihenfolge sollte hier fast egal sein, bzw. sehe ich keine Situation wo das Probleme machen kann.

In C gibt es schließlich kein Konzept für Dateien. Es gibt lediglich Translation-Units, aus welchen die Objekt-Dateien erzeugt werden. Es zwingt einen Niemand API bzw. Definition inkl. Implementierungscode direkt in eine Datei zu packen.

Tatsächlich ist es so, dass die anderen Platform Frameworks/Bibliotheken untereinander auch nicht richtig zusammen funktionieren. Z.b. SDL mit GLUT, oder GLUT mit GLFW, GLFW und SFML, etc.
Andere Bibliotheken sind aber problemlos zu integrieren, z.b. Box2D, PhysX, FMOD, etc.
 
Zuletzt bearbeitet:
- Es ist in C/89 geschrieben und 100% C++ kompatibel, daher ist es sehr leicht neue Platformen/Compiler zu integrieren

C ist bei dynamischen Sachen wie GUIs ein gewaltiger "pain in the ass"

- Es gibt nur eine Header Datei die man einbinden muss und das wars

Sehe hier keinen Vorteil nur eine exorbitante Compilezeit wenn dein Header mal 20 Megabyte groß ist bei den Features die du alle reinpacken willst

- Es ist komplett Open-Source und kann daher beliebig in jedem Projekt verwendet und angepasst werden

Wenn du morgen den support einstellst dann muss ich alles maintainen

- Es wird kein Code versteckt, alles ist erreichbar und gut gekennzeichnet

Librarycode muss man nur äußerst selten inspizieren, somit kein Vorteil

- Einfache und leicht verständliche API, die keine große Dokumentation brauch

Durch C bedingte Eigenschaften wie nullptr, nicht typsichere enums etc. ist die API nie wirklich straight-forward

- Erzeugt keinen direkten Speicher (Das ist dem User überlassen)

Code bloat für händische Speicherverwaltung als Vorteil darzustellen ist auch ähm, interessant.

- Nutzt nur reine Betriebssystemsfunktionen, vermeidet daher C Runtime wo es nur geht
- C-Runtime Bibliothek ist nicht zwingend erforderlich

Der Sinn der C Runtime in Unix ist es z.B. die ABI nach außen stabil zu halten und intern auf entsprechende Kernelfunktionen zu mappen. Unter Unix würdest du dadurch statt mehr Kompatibilität weniger erreichen.

- Arbeitet gut mit anderen Bibliotheken zusammen, z.b. (ImGUI, Box2D, etc.)

Eigentlich sollte man immer weniger 3rd Party Libs benutzen statt mehr

- Features könnnen nach Bedarf komplett deaktiviert werden (Window, OpenGL, etc.)

Das können aber viele existierende Libs

- Ich möchte ohne große Mühe jede Funktion debuggen können

Ich möchte, dass Libraryfunktionen einfach funktionieren und nicht debuggen



Alles in allem ist das Projekt für dich eine tolle Fingerübung, aber letztlich gibt es zwei Arten von Projekten:
1. Uralte Bestandsprojekte, da nimmt man was man hat, weil es zu teuer wäre auf etwas neues umzustellen
2. Man fängt bei Null an und nimmt eine Bibliothek die Lizenztechnisch passt. Viel Komfort und möglichst eine breite Featureabdeckung bietet und deren Support gewährleistet ist.

Bei 1 kommst du nicht zum Zug und bei Punkt 2 auch nicht. Mindestens wegen den zwei letzten Punkten
 
Finalspace schrieb:
Es ist nicht nur eine Header-Datei, sondern enthält direkt auch den Code mit getrenntem Implementierungsblock, der in einer Translation-Unit eingebunden werden muss, wo ist egal. Das muss auch pro Executable nur in einer Translation Unit passieren, ansonsten kann man die Header-Datei überall beliebig einbinden. Reihenfolge sollte hier fast egal sein, bzw. sehe ich keine Situation wo das Probleme machen kann.

In C gibt es schließlich kein Konzept für Dateien. Es gibt lediglich Translation-Units, aus welchen die Objekt-Dateien erzeugt werden. Es zwingt einen Niemand API bzw. Definition inkl. Implementierungscode direkt in eine Datei zu packen.

Tatsächlich ist es so, dass die anderen Platform Frameworks/Bibliotheken untereinander auch nicht richtig zusammen funktionieren. Z.b. SDL mit GLUT, oder GLUT mit GLFW, GLFW und SFML, etc.
Andere Bibliotheken sind aber problemlos zu integrieren, z.b. Box2D, PhysX, FMOD, etc.

Translation-Units schön und gut, aber das ändert nichts an der Problematik der Inkludierungsreihenfolge. :rolleyes:
Ich arbeite z.B. mit einer Bibliothek welche sich nicht funktioniert wenn ich in der gleichen Datei die Windows.h inkludiere, weshalb ich dort sämtlichen Code welcher die Win32 API anspricht in eine extra Datei auslagern muss.

"thirdpart.h" -> inkludiert "foo.h" wo eigene Funktionen für Win32 Zugriff deklariert sind -> "foo.cpp" enthält Definition der Funktionen und inkludiert "Windows.h" um "foo.h" sauber zu halten.

Und solche Szenarien gibt es immer wieder.
 
Fonce schrieb:
Translation-Units schön und gut, aber das ändert nichts an der Problematik der Inkludierungsreihenfolge. :rolleyes:
Ich arbeite z.B. mit einer Bibliothek welche sich nicht funktioniert wenn ich in der gleichen Datei die Windows.h inkludiere, weshalb ich dort sämtlichen Code welcher die Win32 API anspricht in eine extra Datei auslagern muss.

"thirdpart.h" -> inkludiert "foo.h" wo eigene Funktionen für Win32 Zugriff deklariert sind -> "foo.cpp" enthält Definition der Funktionen und inkludiert "Windows.h" um "foo.h" sauber zu halten.

Und solche Szenarien gibt es immer wieder.

Mag sein, das die Reihenfolge eingehalten werden muss - aber dann ist je jeweilige Bibliothek halt nicht sauber definiert, bzw. nicht Platform unabhängig.
Ist bei OpenGL Bilbiotheken auch nicht anderst, da muss glew z.b. als aller erstes rein, bevor gl.h eingebunden werden muss. Da muss ich mir diesbezüglich noch was einfallen lassen, weil glew verwende ich selber ganz gerne.

wayne_757 schrieb:
C ist bei dynamischen Sachen wie GUIs ein gewaltiger "pain in the ass"
Sinnfreies Hating: C vs C++ geblubber

wayne_757 schrieb:
Sehe hier keinen Vorteil nur eine exorbitante Compilezeit wenn dein Header mal 20 Megabyte groß ist bei den Features die du alle reinpacken willst
Die Library wird nicht größer als ~250 KB werden, inkl. Linux/Unix Support. 250 KB ist lachhaft für den Compiler.

wayne_757 schrieb:
Wenn du morgen den support einstellst dann muss ich alles maintainen
Ist das ein Witz?

wayne_757 schrieb:
Librarycode muss man nur äußerst selten inspizieren, somit kein Vorteil
Ist es ein Nachteil?

wayne_757 schrieb:
Durch C bedingte Eigenschaften wie nullptr, nicht typsichere enums etc. ist die API nie wirklich straight-forward
nullptr gibt es nicht in C. C != C++. Und wenn du in den Code geschaut hättest, dann wäre dir vielleicht FPL_NULLPTR aufgefallen... Typsicher sind C-Enums zwar nicht, aber es gibt feste Namenskonventionen, daher passt das schon.
Dazu sind enums in C++ einfach nur traurig. Flags - kannste vergessen mit Enums, das kommt erst mit C++/17.

wayne_757 schrieb:
Code bloat für händische Speicherverwaltung als Vorteil darzustellen ist auch ähm, interessant.
Ich schätze es, wenn nicht mit malloc/new hirnlos umherworfen wird. Du wohl nicht.

wayne_757 schrieb:
Der Sinn der C Runtime in Unix ist es z.B. die ABI nach außen stabil zu halten und intern auf entsprechende Kernelfunktionen zu mappen. Unter Unix würdest du dadurch statt mehr Kompatibilität weniger erreichen.
Klingt plausibel, bin eh nicht sicher ob das bleibt mit dem "No-C-Runtime". Zuviel was man selbst machen muss.

wayne_757 schrieb:
Eigentlich sollte man immer weniger 3rd Party Libs benutzen statt mehr
Ich nutze gar keine, aber es gibt durchaus brauchbare, z.b. was besseres in 2D-Physik bereich als Box2D wirst du nicht finden.

wayne_757 schrieb:
Das können aber viele existierende Libs
Ist doch gut wenn es mehr Auswahl gibt ;-)

wayne_757 schrieb:
ch möchte, dass Libraryfunktionen einfach funktionieren und nicht debuggen
Ist in Ordnung. Ich arbeite selbst beruflich fast nur mit Hochsprachen, aber ich schätze es wenn ich fremden Code auch mal debuggen/reparieren/erweitern kann.

wayne_757 schrieb:
Alles in allem ist das Projekt für dich eine tolle Fingerübung, aber letztlich gibt es zwei Arten von Projekten:...
I dont care. Wers nutzen möchte, nutzt es. Wer nicht, der nutzt es nicht. Fertig. Ich stells kostenlos zur Verfügung und nutze es für mich.
 
Zurück
Oben