Seite 1 von 1
Projekstruktur
Verfasst: 25.11.2024, 10:02
von Matthias Gubisch
Hallo Forum
ich würde gerne mal eure Meinung hören zu folgendem Problem:
Aktuell kompiliere ich meine Engine als statische library.
Das hat den Vorteil dass ich z.B. die Main und damit auch init und shutdown calls zur engine darin gut verstecken kann und damit die Testprojekte einfacher werden, ähnlich wie die SDL das macht.
Das impliziert aber auch dass alle Anwender der Engine alle Abhänigkeiten explizit linken müssen.
Bisher ist mir das nicht aufgefallen weil VS das schön versteckt solange man sich in der gleichen Solution befindet.
Idee deshalb: Man packe die Engine in eine DLL (die API ist dafür vorbereitet und sollte kein Problem machen...)
Aber was mach ich dann mit meiner Main? Das würde ich gerne aus convienience Gründen beibehalten dass die einfach nur reingelinkt wird und sich der User (wenn er das nicht explizit will) sich nicht damit rumschlagen muss.
Idee meinerseits ist jetzt eine statische lib als Engine Loader zu schreiben in der die Main beinhaltet ist und die ansonsten die API einfach nur durchreicht. Aber ich scheue etwas den Warnungsaufwand da ich ja alle API Änderungen dort ebenfalls nachziehen muss.
Hat hier jemand eine Meinung oder gute Idee wie ich
a) das Linker problem gelöst bekomme
b) trotzdem noch die Main zur Verfügung stellen kann?
Re: Projekstruktur
Verfasst: 25.11.2024, 11:59
von antisteo
Bau doch lieber die Engine als Executable und das Spiel ist ein Skript / eine DLL / ein Asset-Ordner.
Re: Projekstruktur
Verfasst: 25.11.2024, 12:27
von Matthias Gubisch
Interessanter Gedanke, muss ich mir mal durch den Kopf gehen lassen.
Re: Projekstruktur
Verfasst: 25.11.2024, 15:41
von Schrompf
Ich würde erstmal die Frage klären, warum Du das Problem überhaupt lösen möchtest, wenn es für Dich doch funktioniert und niemand sonst jemals die Engine in die Hand kriegt? Für mich klingt das nach reinem Sauberkeitsdrang, also ein reines Wohlfühl-Problem. Und ich würde spekulieren, dass es auch echte Probleme gibt, die man stattdessen lösen könnte.
Ansonsten seh ich ehrlich keinen Unterschied, wenn Du das jetzt in ne DLL schiebst. Ist halt alles bissl langsamer als statisch gelinkt, weil jeder Call ne doppelte Indirektion geworden ist, aber sonst ist alles genauso wie beim statischen Linken. So why bother?
Re: Projekstruktur
Verfasst: 25.11.2024, 16:11
von Matthias Gubisch
Schrompf hat geschrieben: ↑25.11.2024, 15:41
Ich würde erstmal die Frage klären, warum Du das Problem überhaupt lösen möchtest, wenn es für Dich doch funktioniert und niemand sonst jemals die Engine in die Hand kriegt? Für mich klingt das nach reinem Sauberkeitsdrang, also ein reines Wohlfühl-Problem. Und ich würde spekulieren, dass es auch echte Probleme gibt, die man stattdessen lösen könnte.
Ansonsten seh ich ehrlich keinen Unterschied, wenn Du das jetzt in ne DLL schiebst. Ist halt alles bissl langsamer als statisch gelinkt, weil jeder Call ne doppelte Indirektion geworden ist, aber sonst ist alles genauso wie beim statischen Linken. So why bother?
Meine Engine besitzt mittlerweile einen Editor (ok, der steckt noch in den Kinderschuhen, aber trotzdem...), und der legt mir beim anlegen einens neuen Projektes auch eine VS Solution nebst Projekt an um Entity verhalten programmiern zu können und so weiter (aktuell mit c++)
Das funktioniert recht gut, aber sobald sich an den Dependencies er Engine was ändert, ist es zwar trivial das für neue Projekte zu berücksichten, für bestehende Projekte allerdings nicht, das müsste ich von Hand machen und das nervt mich.
In der Regal sind das interne Dinge die die API nicht betreffen wie der D3D12Memory Allocator, ShaderCompiler usw., von daher möchte ich auch gar nicht unbedingt das das nach aussen hin sichtbar ist...
Und ja ich will tatsächlich mal ein Game damit machen ;) hoffentlich spätestens zur nächsten ZFX-Action
Re: Projekstruktur
Verfasst: 25.11.2024, 21:45
von Chromanoid
Stumpf ist Trumpf :)
Mach das, was Du am einfachsten findest.
https://grugbrain.dev/
Am Ende ist sowas bei Hobby-Projekten halt Hobby oder Prokrastination der eigentlichen Herausforderung... Also meiner Erfahrung nach...
Re: Projekstruktur
Verfasst: 25.11.2024, 21:52
von Schrompf
Ich kapier's nicht. Du hast eine Lib. Die muss halt neu gebaut werden, wenn sich was ändert. Du packst die Lib mit in die Solution, Du stellst sie als Dependency in Deinem Hauptprojekt ein, fertig.
Falls Dein Editor irgendwie Code generiert, wär's wirklich ne Idee, diesen Code in ne DLL zu packen und die Engine als HostProzess diese DLL laden zu lassen. Ermöglicht Dir auch Hot Reloading in gewissem Maße. Schlug ja auch schon Anti vor.
Re: Projekstruktur
Verfasst: 25.11.2024, 22:11
von Matthias Gubisch
Schrompf hat geschrieben: ↑25.11.2024, 21:52
Ich kapier's nicht. Du hast eine Lib. Die muss halt neu gebaut werden, wenn sich was ändert. Du packst die Lib mit in die Solution, Du stellst sie als Dependency in Deinem Hauptprojekt ein, fertig.
Falls Dein Editor irgendwie Code generiert, wär's wirklich ne Idee, diesen Code in ne DLL zu packen und die Engine als HostProzess diese DLL laden zu lassen. Ermöglicht Dir auch Hot Reloading in gewissem Maße. Schlug ja auch schon Anti vor.
Leider nicht, weil der schrott von VisualStudio die dependencies nicht dazupackt zur .lib, das macht die *** IDE nur für executeables und DLLs...
Was dazu führt das ich die lib nicht einfach zu einer exe dazulinken kann wenn ich eine neue Abhängigkeit bekomme...
Einfach eine DLL nimmt mir halt die Möglichkeit die Main bereitzustellen, was ich einfach praktisch finde...
Denke es wied darauf rauslaufen dass ich die Engine in eine DLL packe, die "main" exportiere und meinen Editor eine echte Main generieren lasse die genau dies eine Methode aufruft, alles andere klingt nervig komplex
Engine als Hostprozess gefällt mir bei genauerem überlegen von der usability in meinem setup nicht so gut.
Hätte lieber ein executeable per Client...
Re: Projekstruktur
Verfasst: 26.11.2024, 12:37
von NytroX
Wenn du die Engine als DLL machst, stellst du dann nicht sowieso einen Header (engine.h oder wieauchimmer) bereit für den "Benutzer" der Engine?
Und wenn du dann darin die main() oder WinMain() machst, ist doch alles bestens, oder nicht?
Du könntest das dann auch so wie SDL machen, dass man dann aussuchen kann, ob die main() von der Engine gemacht wird oder nicht.
https://wiki.libsdl.org/SDL3/SDL_MAIN_USE_CALLBACKS
Re: Projekstruktur
Verfasst: 26.11.2024, 13:34
von Matthias Gubisch
NytroX hat geschrieben: ↑26.11.2024, 12:37
Wenn du die Engine als DLL machst, stellst du dann nicht sowieso einen Header (engine.h oder wieauchimmer) bereit für den "Benutzer" der Engine?
Und wenn du dann darin die main() oder WinMain() machst, ist doch alles bestens, oder nicht?
Du könntest das dann auch so wie SDL machen, dass man dann aussuchen kann, ob die main() von der Engine gemacht wird oder nicht.
https://wiki.libsdl.org/SDL3/SDL_MAIN_USE_CALLBACKS
Die SDL Lösung mit 2 Libs eine für die main() und eine für die Engine könnte tatsächlich auch ganz gut sein.
Die Headerlösung geällt mir irgendwie einfach nicht
Danke schonmal für eure Vorschläge, ein wenig was zum experimentieren hab ich ja jetzt ;)
Re: Projekstruktur
Verfasst: 15.12.2024, 08:41
von Jonathan
Also, meine Erfahrung nach Dekaden des qualvollen Versuchens: C++ kompilieren ist komplett kaputt, war schon immer kaputt, und wird sich niemals bessern. Am glücklichsten wird man, wenn man absolut alles, was sich irgendwie clever anfühlt vergisst und alles so trivial hält wie möglich, damit man sich damit so wenig wie nur irgend möglich beschäftigen muss. Keine defines, keine Makros, keine Compilerflags, gar nichts, einfach nur Code den man zusammenschmeißt und dann direkt mit Standardeinstellungen kompilieren kann.
DLLs machen immer und nur Ärger, die meide ich wie der Teufel das Weihwasser. Ich hab für meine Engine eine Reihe an Spielprojekten und absolut alles ist in einer großen Solution. Es gibt eine minimale CMake-Datei (weil CMake noch kaputter ist, als C++), mit der ich einzelne Spieleprojekte aktivieren, oder deaktivieren kann. Weil alles eine einzige Solution ist, findet CMake dann auch tatsächlich immer alle Pfade sofort. Es würde mir im Traum nicht einfallen, meine Engine als eigene Solution zu haben, getrennt zu kompilieren, das Ergebnis in irgendeinen Ordner zu installieren und ein CMake script für ein anderes Projekt schreiben, dass genau diesen Pfad dann auch tatsächlich findet und korrekt einbindet. Viel zu kompliziert, das geht auf jeden Fall kaputt und dann hat man wieder nur Ärger.
Ich habe sogar alle CMake Suchpfade für externe Abhängigkeiten explizit deaktiviert. Am Ende findet mir das Ding noch irgendeine blöde zlib-dll, weil die von irgendetwas anderem zufällig in PATHS gelandet ist. Und schon ist wieder alles kaputt und tut nicht mehr. Und nahezu alles, was ich nicht vorkompiliert installieren kann, landet auch einfach als Unterprojekt in meinem großen Solution Ordner. Damit es funktioniert und gefunden wird.
Ineffizient scheint mir das nicht. Die Solution ist ja immer noch in Unterprojekte unterteilt, und es werden halt die Unterprojekte neu kompiliert die sich selbst oder deren Abhängigkeiten sich geändert haben. Also genau so oft, als hätte ich es in unterschiedlichen Solutions.
Und will ich doch mal, aus irgendwelchen Gründen, es könnte ja sein, aber ist mir tatsächlich noch kein einzige mal vorgekommen, sollte ich also doch wirklich mal für eines meiner Spieleprojekte eine andere Engine Version verwenden wollen, nun, dafür gibt es dann ja git und git branches. Weil ja sowieso alles ein großer monolithischer Block ist. Da kann es dann also gar nicht passieren, dass ich mit den Versionen zwischen unterschiedlichen Projekten durcheinander komme und wieder nichts kompiliert. Weil alles so dumm und einfach wie möglich ist.
Re: Projekstruktur
Verfasst: 16.12.2024, 10:03
von antisteo
Nach Jahren des Hypes tauchen jetzt endlich mal ein paar Videos auf, die überwuchende Microservices und Altlasten durch eine sinnlose Zerteilung von zusammengehöriger Software in hunderte sich gegenseitig aufrufende REST-APIs aufgeteilt haben.
Mit den DLLs ist es ähnlich: Die sind ein Relikt aus den 90ern, wo Software auf CD-ROM ausgeliefert wurde, sich nicht mehr geändert hat und proprietär war. Da konnte man schön Fremdfunktionalität "reinpluggen". DLLs zentral zu installieren hat mit Ausnahme des OpenGL-Treibers und der .NET-Runtime nie funktioniert und jeder Software-Hersteller hat seine DLLs immer in einer DLL-Hölle mitgeliefert.
Re: Projekstruktur
Verfasst: 16.12.2024, 10:46
von Matthias Gubisch
Ich verstehe die Bedenken und Argumente gegen DLLs durchaus.
Meine Idee war folgende:
Die Engine wird in einer eigenen Solution entwickelt, zusammen mit dem Editor.
Wenn ich jetzt ein Spiel machen will dann erzeugt mir den Editor die komplette Folder Struktur inklusive einer VS Solution die ein Executeable beinhaltet. Das Executeable soll im großen und ganzen nur die Main aufrufen und ein paar Costumization Points bereitstellen.
Der Editor weiß wo die Engine liegt auf dem entsprechenden Rechner und konfiguriert das linken automatisch. Das hat auch erstmal getan.
Bis ich angefangen habe nicht nur ein bischen Framework, sondern tatsächlich meinen Renderer da wieder einzubauen. Seitdem fliegt der Linker in der erzeugten Solution auf die Nase weil VS es nicht gebacken bekommt transitive Abhängigkeiten von statischen Libraries automatisch zu linken.
Da ich keine Lust habe bei jeder neuen externen Abhängkeit alle möglichen Projekte durchzugehen war ich auf der Suche nach einer anderen Lösung.
Die Lösung die ich Mittlerweile gebaut habe und auch ganz gut tut bisher:
- Engine ist eine DLL, alle Abhängigkeiten sind da aktuell statisch reingelinkt
- Die EngineDLL wird zusammen mit der zugehörigen statischen lib kopiert um zum Executeable gelinkt. Das kopieren passiert aktuell automatisch bei jedem laden eines Projektes so dass ich immer die aktuellste Engine Version habe. Später soll hier mal ein intelligenterer Update mechanismus her aber vorerst löst das meine Probleme soweit.
Die Idee mit der Automatisch vorhandenen main die nur reingelinkt wird habe ich aufgegeben, das schien mir einfach den Aufwand nicht wert.
Re: Projekstruktur
Verfasst: 16.12.2024, 11:26
von Schrompf
Und jetzt machst Du aus der Engine-DLL noch ne Static Library und kriegst die selbe Lösung mit 2% mehr Performance :-)
und mit 10% weniger Stress bei Sichtbarkeit von C++-Symbolen, abweichenden Heap-Implementationen und Symbol-Exporten und -Importen
Re: Projekstruktur
Verfasst: 16.12.2024, 12:02
von Matthias Gubisch
Schrompf hat geschrieben: ↑16.12.2024, 11:26
Und jetzt machst Du aus der Engine-DLL noch ne Static Library und kriegst die selbe Lösung mit 2% mehr Performance :-)
und mit 10% weniger Stress bei Sichtbarkeit von C++-Symbolen, abweichenden Heap-Implementationen und Symbol-Exporten und -Importen
Genau das hatte ich, genau damit fliegt Visual Studio auf die schnauze ohne manuelle Nacharbeit
Das nervt mich, deshalb die DLL Lösung...
Also wenn mir einer eine Lösung sagt wie ich das executebele zu allen externen Abhängigkeiten der Engine gelinkt bekomme ohne das von Hand nachzutragen dann bau ich wieder zurück.
Re: Projekstruktur
Verfasst: 16.12.2024, 12:09
von Schrompf
Hm, ok, wundert mich, aber lassen wir es damit bewenden.
Wenn ich mal groß bin, will ich mal die Umgedrehte Lösung ausprobieren: die Engine als Host-Prozess und die komplette Spiellogik als DLL. Damit kann ich dann vielleicht auch Hot Reloading der Spielmechanik machen und schneller iterieren.
Wobei ich das jetzt mit Edit&Continue auch schon kann. Hm.