Best Way? Main Function auslagern?
Forumsregeln
Wenn das Problem mit einer Programmiersprache direkt zusammenhängt, bitte HIER posten.
Wenn das Problem mit einer Programmiersprache direkt zusammenhängt, bitte HIER posten.
Best Way? Main Function auslagern?
Hallo zusammen,
ich wollte einmal wissen wie Ihr damit umgeht. Für den Multi-Platform Support, habe ich je nach Platform (Linux, Win32, Android) eine eigene Main-Methode implementiert. Diese ruft Platform spezifisch ein (Pseudo)-Singleton auf, das zur Applikations Initialisierung dient und über virtuelle Methoden die komplette Initialisierung, Start und Stop der Applikation abdeckt. Somit muss der Anwender nur eine Instanz dieses Singletons implementieren und dann startet die Applikation wohldefiniert.
Klapp soweit auch gut. Nur muss ich grundsätzlich die Main-Methode "mitschleppen", da der Linker nur lokal nach einer Main-Methode sucht. Gibt es eine elegante Möglichkeit die Main-Methoden, die nicht mehr implementiert werden müssen, vom Anwender weg zu kapseln und in eine Lib auszulagern?
Wie geht Ihr damit um? Lasst Ihr immer den Anwender noch eine Main-Methode implementieren? Oder schleppt Ihr wie ich aktuell eine fertige Implementation mit, die der Anwender in seiner Applikation direkt linken muss, damit die Executable diese findet?
ich wollte einmal wissen wie Ihr damit umgeht. Für den Multi-Platform Support, habe ich je nach Platform (Linux, Win32, Android) eine eigene Main-Methode implementiert. Diese ruft Platform spezifisch ein (Pseudo)-Singleton auf, das zur Applikations Initialisierung dient und über virtuelle Methoden die komplette Initialisierung, Start und Stop der Applikation abdeckt. Somit muss der Anwender nur eine Instanz dieses Singletons implementieren und dann startet die Applikation wohldefiniert.
Klapp soweit auch gut. Nur muss ich grundsätzlich die Main-Methode "mitschleppen", da der Linker nur lokal nach einer Main-Methode sucht. Gibt es eine elegante Möglichkeit die Main-Methoden, die nicht mehr implementiert werden müssen, vom Anwender weg zu kapseln und in eine Lib auszulagern?
Wie geht Ihr damit um? Lasst Ihr immer den Anwender noch eine Main-Methode implementieren? Oder schleppt Ihr wie ich aktuell eine fertige Implementation mit, die der Anwender in seiner Applikation direkt linken muss, damit die Executable diese findet?
- Schrompf
- Moderator
- Beiträge: 5047
- Registriert: 25.02.2009, 23:44
- Benutzertext: Lernt nur selten dazu
- Echter Name: Thomas
- Wohnort: Dresden
- Kontaktdaten:
Re: Best Way? Main Function auslagern?
Ich habe pro Plattform die passende main() in einer Lib, von der aus die allgemeine Nutzer-Main() aufgerufen wird. Das geht natürlich nur, solange Du nicht dynamisch linkst, aber der Unsinn sollte sich eh langsam rausgewachsen haben.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
- Sternmull
- Establishment
- Beiträge: 264
- Registriert: 27.04.2007, 00:30
- Echter Name: Til
- Wohnort: Dresden
Re: Best Way? Main Function auslagern?
Du könntest es so machen wie die SDL. Die definiert main als SDL_main und ruft diese von einer plattform-abhängigen "echten" main Funktion aus auf die in der einer lib implementiert ist.
Die main-Funktionen anderer Plattformen zu verstecken sollte eigentlich unproblematisch sein: Pro Plattform sollte ja nur eine main-Funktion implementiert sein, die main-Funktionen der anderen Plattformen sollten beim Build für eine bestimmte Plattform nicht gebaut werden (z.B. per Präprozessor ausklammern, oder jede Funktion in einer separaten c/cpp Dateie von denen nur die verwendet wird die für die Plattform relevant ist).
Die ganze Initialisierung sollte meiner Meinung nach in der allgemeinen main-Funktion des Nutzers plattformunabhängig implementiert sein. Wenn man wieder die SDL als Beispiel nimmt würde dort halt (egal für welche Plattform gebaut wird) SDL_Init, SDL_GL_SetAttribute, SDL_SetVideoMode etc. aufgerufen werden. Diese Funktionen sind dann natürlich plattformabhängig implementiert, aber der Nutzer braucht sich in dem Moment keine Gedanken mehr machen unter welcher Plattform er was anders machen muss.
Für Android müsste man das evtl. anders machen weil dort (glaube ich) der gängige Weg so ist das man eine Java-Wrapper Anwendung schreibt die alles initialisiert (OpenGL, Eingabebehandlung etc.) und dann den C/C++-Code aufruft der in einer dynamisch geladenen Bibliothek implementiert ist, dort müsste dann also eine main-Funktion drin sein die diesen Teil der Initialisierung nicht macht (oder der dort durch Dummy Funktionen imlementiert ist).
Aber letzten Endes sollte meiner Meinung nach grundsätzlich das Ziel sein das man die plattformabhängige Initialisierung "wegkapselt" oder sie zumindest so früh wie möglich hinter sich lässt um dann in allgemeinem Code zu landen der für alle Plattformen identisch ist. Der Nutzer sollte nicht durch plattformabhängigen Code belastet werden.
Die main-Funktionen anderer Plattformen zu verstecken sollte eigentlich unproblematisch sein: Pro Plattform sollte ja nur eine main-Funktion implementiert sein, die main-Funktionen der anderen Plattformen sollten beim Build für eine bestimmte Plattform nicht gebaut werden (z.B. per Präprozessor ausklammern, oder jede Funktion in einer separaten c/cpp Dateie von denen nur die verwendet wird die für die Plattform relevant ist).
Die ganze Initialisierung sollte meiner Meinung nach in der allgemeinen main-Funktion des Nutzers plattformunabhängig implementiert sein. Wenn man wieder die SDL als Beispiel nimmt würde dort halt (egal für welche Plattform gebaut wird) SDL_Init, SDL_GL_SetAttribute, SDL_SetVideoMode etc. aufgerufen werden. Diese Funktionen sind dann natürlich plattformabhängig implementiert, aber der Nutzer braucht sich in dem Moment keine Gedanken mehr machen unter welcher Plattform er was anders machen muss.
Für Android müsste man das evtl. anders machen weil dort (glaube ich) der gängige Weg so ist das man eine Java-Wrapper Anwendung schreibt die alles initialisiert (OpenGL, Eingabebehandlung etc.) und dann den C/C++-Code aufruft der in einer dynamisch geladenen Bibliothek implementiert ist, dort müsste dann also eine main-Funktion drin sein die diesen Teil der Initialisierung nicht macht (oder der dort durch Dummy Funktionen imlementiert ist).
Aber letzten Endes sollte meiner Meinung nach grundsätzlich das Ziel sein das man die plattformabhängige Initialisierung "wegkapselt" oder sie zumindest so früh wie möglich hinter sich lässt um dann in allgemeinem Code zu landen der für alle Plattformen identisch ist. Der Nutzer sollte nicht durch plattformabhängigen Code belastet werden.
Re: Best Way? Main Function auslagern?
Danke ersteinmal für Eure ausführlichen Anregungen. Ich sehe, dass wir von der Idee und Meinung her auf der gleichen Schiene fahren 8-) Leider hab ich genau das Problem, dass ich dynamisch gelinkte Bibliotheken verwenden muss um den Objekt-Speicherbereich zwischen den Libs zu teilen. Und soweit ich das gelesen habe, geht dann hier das Auslagern nicht, da dann der Linker nicht mitspielt, weil er nur lokal die Main-Methode sucht ...
Aber dank Eurer Vorschläge habe ich evtl. einen alternativen Ansatz gefunden, den ich mal ausrpobieren will. Ich werde einfach die Main-Methode generieren. Da ich sowieso schon per CMake z.B. für das Android NDK die GNU Make Skripte generiere, werde ich einfach mal versuchen, die Main-Methode auch zu generieren und dann bei Bedarf direkt zu linken. So ist die plattformabhängige Implementation vor dem Anwender weg gekapselt und alles da, wo es sein sollte ;)
Aber dank Eurer Vorschläge habe ich evtl. einen alternativen Ansatz gefunden, den ich mal ausrpobieren will. Ich werde einfach die Main-Methode generieren. Da ich sowieso schon per CMake z.B. für das Android NDK die GNU Make Skripte generiere, werde ich einfach mal versuchen, die Main-Methode auch zu generieren und dann bei Bedarf direkt zu linken. So ist die plattformabhängige Implementation vor dem Anwender weg gekapselt und alles da, wo es sein sollte ;)
Re: Best Way? Main Function auslagern?
Statt sie zu generieren würde ich aber eher eine von n fertigen Dateien mit ins Projekt aufnehmen oder eben nicht. Ich mag es halt, mein Build-Skript dumm zu halten, damit ich nicht zu sehr davon abhängig bin.
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
https://jonathank.de/games/
Re: Best Way? Main Function auslagern?
Ich versteh nicht so ganz wozu man die main-Funktion plattformabhängig implementieren sollte. Die kann doch auf jeder Plattform gleich sein und ruft dann etwas auf, was eine plattformabhängige Implementierung enthält. Dann kann man sich den ganzen Link-Kram sparen und einfach mit einer kleinen Präprozessor-Direktive (z.B. plattformabhängige Includes) arbeiten.
Sofern man dann dem Nutzer noch eine Extra-Funktion spendieren will, die zur Initialisierung verwendet werden kann, kann man ja einfach ein Hook und/oder Signal (im einfachsten Fall ein Funktionspointer) verwenden.
Sofern man dann dem Nutzer noch eine Extra-Funktion spendieren will, die zur Initialisierung verwendet werden kann, kann man ja einfach ein Hook und/oder Signal (im einfachsten Fall ein Funktionspointer) verwenden.
Ohne Input kein Output.
- Sternmull
- Establishment
- Beiträge: 264
- Registriert: 27.04.2007, 00:30
- Echter Name: Til
- Wohnort: Dresden
Re: Best Way? Main Function auslagern?
Unter Windows ergibt sich das Problem das "WinMain" statt "main" verwendet werden muss wenn es sich um eine Nicht-Konsolen-Anwendung handelt (also eine Anwendung die auf das automatische erstlelen eines Konsolenfensters verzichtet). Das dürfte auch der Grund sein warum die SDL da so einen Zauber macht. Auf Linux, FreeBSD etc. sollte es immer ein normales "main" sein. Unter Android muss man sich aber (wie oben bereits erwähnt) ggf. auch etwas verbiegen (vielleicht aber auch nicht: Der Java-Wrapper könnte ja die Main-Funktion aufrufen... oder vielleicht kommt man mittlerweile auch ohne Java aus, hab da bloß vor Jahren mal reingeschnuppert).BeRsErKeR hat geschrieben:Ich versteh nicht so ganz wozu man die main-Funktion plattformabhängig implementieren sollte. Die kann doch auf jeder Plattform gleich sein und ruft dann etwas auf, was eine plattformabhängige Implementierung enthält.
Re: Best Way? Main Function auslagern?
Hm, ist dieses WinMain nicht einfach eine Einstellungssache? Irgendwo in den Projektoptionen kann man meines Wissens nach den Einstiegspunkt einstellen, und auch, ob man ein Konsolenfenster haben möchte oder nicht. (Ich benutze eigentlich nur das, was bei CMake rauskommt, und da funktioniert es immer mit main()).
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
https://jonathank.de/games/
- Sternmull
- Establishment
- Beiträge: 264
- Registriert: 27.04.2007, 00:30
- Echter Name: Til
- Wohnort: Dresden
Re: Best Way? Main Function auslagern?
Stimmt, das Default welches durch das Subsystem gesetzt wird kann man per /ENTRY ändern. Alledings dürfte bei /SUBSYSTEM:WINDOWS immer noch ein Einstiegspunkt mit der Signatur von WinMain erwartet werden. Dementsprechend dürfte es schief gehen wenn man eine "int main(int, char **)" angibt.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Best Way? Main Function auslagern?
Ein manuell gesetzter Einsprungspunkt akzeptiert keine Parameter. Man müsste sich argc und argv also über das Betriebssystem aus seiner Kommandozeile zusammenbauen; damit würde es erst recht plattformabhängig.
Re: Best Way? Main Function auslagern?
Muss man das auf dem anderen Weg für Windows nicht auch tun?Krishty hat geschrieben:Ein manuell gesetzter Einsprungspunkt akzeptiert keine Parameter. Man müsste sich argc und argv also über das Betriebssystem aus seiner Kommandozeile zusammenbauen; damit würde es erst recht plattformabhängig.
Ohne Input kein Output.
Re: Best Way? Main Function auslagern?
Übrigens muss ich euch enttäuschen. Wenn ich als Subsystem WINDOWS nutze und den Entry-Point auf mainCRTStartup stelle, dann läuft das wie geschmiert mit der normalen main-Funktion und auch mit den gültigen Argumenten.
Beispielsweise damit:
Getestet mit Visual Studio 2010. Für gcc usw geht das ja eh ohne den Kram.
Beispielsweise damit:
Code: Alles auswählen
#ifdef _MSC_VER
# pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif
int main(int argc, char **argv)
{
return 0;
}
Ohne Input kein Output.
-
- Beiträge: 75
- Registriert: 24.07.2002, 00:00
- Wohnort: Bremen
- Kontaktdaten:
Re: Best Way? Main Function auslagern?
Ja, das liegt daran, dass mainCRTStartup genau die Funktion ist, die dafür zuständig ist, argc und argv abzuholen und mit denen dann main aufzurufen.
- Krishty
- Establishment
- Beiträge: 8316
- Registriert: 26.02.2009, 11:18
- Benutzertext: state is the enemy
- Kontaktdaten:
Re: Best Way? Main Function auslagern?
Ist aber keine schlechte Lösung – ich hatte nicht bedacht, dass der Linker die Funktion auch auf diese Art anbietet.
Re: Best Way? Main Function auslagern?
Naja ist doch super. Was anderes braucht man doch nicht um das Problem zu lösen. :)Florian Keßeler hat geschrieben:Ja, das liegt daran, dass mainCRTStartup genau die Funktion ist, die dafür zuständig ist, argc und argv abzuholen und mit denen dann main aufzurufen.
Ist ja eh nur eine Sonderlocke vom Visual Studio. Das eine pragma tut nicht weh und erübrigt den ganzen Kram mit plattformabhängiger main-Funktion.
Ohne Input kein Output.
Re: Best Way? Main Function auslagern?
Hab es jetzt per CMake config Import gelöst, d.h. je nach Plattform wird eine entsprechendes cpp Modul mit einer Main Funktion generiert (hier wird nur vorimplementierter Code übernommen) und in den Build-Prozess mit eingebunden ...
Genau das ist der Grund. Linux und Windows stellen an sich kein Problem dar. Die Main-Funktionen waren bisher per Präprozessor-Direktive separiert worden, .d.h. lediglich die Funktionssignatur wurde ensprechend angepasst (platformabhängige Aufrufe, wie Eventhandling waren bereits weggekapselt der Rest der Aufrufe im Programmablauf war daher identisch). Aber Android (reines NDK) hat hier u.A. andere Aufruffolgen, die sich nicht mit Windows und Linux verheiraten lassen, so wird u.A. z.B. das Native Window per Android-Thread zu einem späteren Zeitpunkt initialisiert, wodurch sich Fenster nicht wie in Windows/Linux mal einfach so erzeugen lassen ...
Unter Android muss man sich aber (wie oben bereits erwähnt) ggf. auch etwas verbiegen ...
Genau das ist der Grund. Linux und Windows stellen an sich kein Problem dar. Die Main-Funktionen waren bisher per Präprozessor-Direktive separiert worden, .d.h. lediglich die Funktionssignatur wurde ensprechend angepasst (platformabhängige Aufrufe, wie Eventhandling waren bereits weggekapselt der Rest der Aufrufe im Programmablauf war daher identisch). Aber Android (reines NDK) hat hier u.A. andere Aufruffolgen, die sich nicht mit Windows und Linux verheiraten lassen, so wird u.A. z.B. das Native Window per Android-Thread zu einem späteren Zeitpunkt initialisiert, wodurch sich Fenster nicht wie in Windows/Linux mal einfach so erzeugen lassen ...
- Sternmull
- Establishment
- Beiträge: 264
- Registriert: 27.04.2007, 00:30
- Echter Name: Til
- Wohnort: Dresden
Re: Best Way? Main Function auslagern?
Ich seh grad das SDL auch Android unterstützt. Da solltest du mal einen Blick drauf werfen. Vielleicht kannst du auch direkt SDL verwenden statt diese Abstraktionsschicht selbst zu implmementieren?