RFC: Reduzierung der Präprozessor-Nutzung

Hallo zusammen,

ein m. E. etwas problematisches Muster im aktuellen Code ist die übermäßige Nutzung des Präprozessors für die Implementierung von Konfigurationsoptionen.

Spontan fallen mir drei Nachteile ein:

  • Der Code ist deutlich schwerer lesbar, da Anweisungen an den Präprozessor und den Compiler im Code miteinander verwoben sind.
  • Große Teile vom Code werden selten oder nie dem Compiler zugeführt und sind daher besonders anfällig für Bugs und schwierig zu debuggen.
  • Wenn man Config-Optionen die aktuell zur Compilezeit vorgenommen werden verschiebt, damit sie zur Laufzeit (z. B. in der Weboberfläche) einstellbar sind, entsteht ggf. zusätzlicher Aufwand beim Umbauen des Codes um den Präprozessor zu umgehen.

Es gibt sicherlich noch weitere, aber Fakt ist, dass der Compiler smart genug ist um auch ohne Präprozessor den Code soweit zu optimieren, dass binär am Ende das selbe Ergebnis herauskommt (Dead Code Elimination).

Ein entsprechendes Refactoring des Codes wäre also äußerst sinnvoll und nützlich. Zudem ist die Umsetzung nicht besonders kompliziert und es würde meinem persönlichen, längerfristigen Ziel Kconfig zur Konfiguration zu verwenden dienen (mehr dazu in Konfiguration via Kconfig).

Ein Beispiel wie das Ganze aussieht gibt es hier: Commits · fschrempf/ESPuino · GitHub. Es wurde dort beispielhaft die RfidPn5180.cpp überarbeitet. Das resultierende Binary belegt mit meiner Beispielkonfiguration exakt die selbe Menge an Speicher wie ohne die Änderungen und sollte damit binär und funktional identisch sein.

Ein kleiner Nachteil bzw. eine Stolperfalle könnte sein, dass Boolean Config-Optionen anders definiert werden müssen. Aus #define MDNS_ENABLE wird #define MDNS_ENABLE 1. Wenn man also eine lokale settings-override.h hat ist diese nicht mehr kompatibel.

Wenn es generelle Zustimmung gibt, würde ich das Thema weiter bearbeiten und einen PR erstellen. Sonstiges Feedback, Fragen, Kritik, etc. sind natürlich ebenfalls willkommen.

Viele Grüße
Frieder

1 „Gefällt mir“

Ich finde das generelle Thema wichtig und eine gute Idee.

Bei Kconfig bin ich mir nicht sicher, ob der Mehrwehrt so hoch ist. Ich kenne von einem anderen Projekt, dass mit Github Actions und KConfig jeder sein eigenes image bauen kann, ohne irgendwelche tools bei sich installieren zu müssen.
Das ist ziemlich cool, sollte aber mit settings.h ja auch gehen…

Mein Fokus läge eher darauf, möglichst viele Optionen, die wirklich nicht zur Build-Zeit definiert sein müssen dynamisch ins web-frontend zu holen. Zum Beispiel „PAUSE_WHEN_RFID_REMOVED, DONT_ACCEPT_SAME_RFID_TWICE“. Also Optionen, die die Code-Size auch kaum verändern.

Langfristig fände ich es cool bzw. gut für mehr Reichweite für ESPuino, wenn es ein paar fertige „universal“ builds für gängige Hardware gäbe. Das ist aber noch eine riesige Aufgabe.

2 „Gefällt mir“

Danke für die Rückmeldung!

Sowas in der Art hätte ich langfristig auch gerne und Kconfig würde da helfen. Welches Projekt ist das denn? Würde mir das gerne mal anschauen.

Prinzipiell wahrscheinlich schon, aber Kconfig würde hier schon vieles vereinfachen und noch viel anderen Mehrwert bringen. Aber die Diskussion sollte dann besser im anderen Thread zum Thema stattfinden.

Das ist auch wichtig. Aber es wird immer Compile-Time-Config geben und wenn es nur die verschiedenen Board-Varianten sind. Und die hier vorgestellten Änderungen bieten ja gerade auch eine Vereinfachung/Vorarbeit um Optionen ins Frontend zu bringen.

1 „Gefällt mir“

Das Projekt ist zmk, eine firmware für Bluetooth-Tastaturen. Dort ist der „normale“ bzw. offizielle Weg sich eine eigene Firmware zu erstellen, auf Github zu forken und alles online zu bauen…

Sehe ich ehrlich gesagt anders: Das war alles schön eingerückt. Und zwar genau aus dem Grund. Da haben hier einige die Nase gerümpft und gemeint, dass das unüblich sei, Präprozessor-Anweisungen gleichermaßen einzurücken. Dann musste Clang her und jetzt ist es halt „so halb“ eingerückt.
Also mir ist unklar, wo genau das Problem liegt, wenn einem VSC mit entsprechender Kolorierung sogar anzeigt, was gerade greift und was nicht. Die einzige Stelle, wo es wirklich „haarig“ wird, ist meines Erachtens die SD-Initialisierung. Weil da ergeben sich mit SPI, SDMMC und Single-SPI doch eine Reihe von (verschachtelten) Kombinationsmöglichkeiten, wo schwer nachzuvollziehen ist, was wann und wie greift.

Teil 1: Akzeptiert!
Teil 2: Das Problem ist halt, dass ESPuino inzwischen Unmengen an Kombinationsmöglichkeiten hat, die keiner testet. Ich hab’s ne Weile für eine gute Idee gehalten, sämtliche Feature-Requests zu integrieren. Isoliert betrachtet war das von der Handhabung ok, aber in Kombination und vor allem im Lifecycle ist’s zuweilen schiarch. Inzwischen bin ich davon abgekommen und beäuge jeden Feature-Request erstmal kritisch und hinterfrage, ob das überhaupt nennenswert genutzt wird.

Akzeptiert!

Ich bin von KConfig ja weiterhin nur so bedingt überzeugt. Also nicht, dass ich es für schlecht halte und es für mich nicht funktionieren würde, aber da muss halt wieder zusätzlicher Kram installiert werden, der die initiale Einrichtung noch aufwändiger macht, als sie jetzt eh schon ist. Weil sind wir mal ehrlich: Für nicht wenige Leute ist es schon ein „Akt“, VSC mit Platformio zum Laufen zu bringen und zu verstehen, was git ist.
Mal abgesehen davon, dass ich hier einiges an Doku umschreiben muss, einiges an alten Posts obsolet wird (was nicht zwangsläufig jedem klar ist, der sie liest) und dann wieder zahlreiche Support-Anfragen bei mir als PN landen von Leuten, die schon länger ESPuino verwenden und nach einem Update völlig lost sind, weil alles ganz anders ist. Rechne mal damit, dass nur etwa 1/4 bis 1/3 der Userfragen hier im Forum landen - den Rest beantworte ich privat schon. Die meisten Fragen sind einfacher Natur, aber es kostet halt dennoch Zeit. Mache ich das nicht, dann stehen wahlweise Fragen hier doppelt und dreifach oder User wenden sich entnervt von ESPuino ab. Letztgenanntes stimmt mich unzufrieden, wenn diese Leute zuvor Hardware von mir bezogen haben.

Was ich sagen will: Mitnichten zieht ESPuino nur irgendwelche Nerds an und daher sind viele Änderungen und Notwendigkeiten vielen Usern gar nicht klar. Ihr dürft auf keinen Fall erwarten, dass hier sonderlich viele User ständig am Ball bleiben.

Auch wenn das Handling mit den settings-Files schon irgendwie „raw“ ist, bieten sie ja doch eine halbwegs gute Übersicht (aufgrund der ganzen Kommentare und Beschreibungen) und wenn man ein Jahr später nochmal ein Update macht und sich diese Files aufgehoben hat, dann ist da, finde ich, auch ein gewisses Maß an Nachvollziehbarkeit gegeben.

Das unterschreibe ich VÖLLIG!

Das auf jeden Fall. Und ich glaube es ist auch unklar, ob sowas speichertechnisch auf dem ESP32 auch wirklich funktioniert.

Also ich hoffe, dass ich hier nicht als „der Mahner vom Dienst“ wahrgenommen werde. Aber da ich quasi täglich mit Supportanfragen konfrontiert werde, sehe ich mich genötigt, hier öfter mal auf die Bremse zu treten.

2 „Gefällt mir“

6 Beiträge wurden in ein neues Thema verschoben: Einstiegshürde(n) in ESPuino senken

Das wäre für mich auch der nächste Schritt.

2 „Gefällt mir“

Mal ganz ehrlich, egal wie der Code formatiert ist gibt es durch den Mix aus normalem Code, den der Compiler interpretiert und Präprozessor-Code, den der Präprozessor interpretiert eine erhebliche Verschlechterung der Lesbarkeit.

Mir persönlich fällt es einfach sehr schwer Code zu lesen, der ständig von Blöcken unterbrochen wird, die nur bedingt compiliert werden und ich weiß, dass das anderen auch so geht weshalb es allgemein als schlechter Stil gilt, wenn man unnötig den Präprozessor strapaziert. Wenn das bei dir anders ist, ist das ja schön aber das steht halt einfach im Gegensatz zur allgemein vorherrschenden Meinung unter Entwicklern.

Siehe z. B. auch:

Das Syntax-Highlighting zeigt mir vielleicht welcher Block mit meiner aktuellen Config aktiv ist, aber das verhindert eben nicht, dass man die Auswirkungen von Änderungen auf inaktive Blöcke gerne übersieht bzw. nicht einmal compile-testet.

Genau! Und man kann die Kombinationen in der Config auch kaum testen, weil es eine Vielzahl von Abhängigkeiten zwischen den einzelnen Config-Optionen gibt, die nirgends abgebildet sind. Das heißt man muss im Voraus irgendwoher wissen oder aufwendig recherchieren wie die Optionen zusammenhängen. Genau da kommt Kconfig wieder ins Spiel. Dort werden die Abhängigkeiten zwischen den Optionen abgebildet und berücksichtigt. Das geht theoretisch so weit, dass man Compile-Tests mit einer randomisierten Config machen kann um sicherzustellen, dass alle Kombinationen zumindest korrekt compilieren.

Das ist sicher eine gute und sinnvolle Strategie.

Nein, eben nicht. Wir verwenden mittlerweile das Buildsystem des esp-idf SDKs. Das verwendet bereits Kconfig für die Konfiguration des SDKs und alle Abhängigkeiten sind bereits vorhanden. Dort würden sich die ESPuino-spezifischen Optionen einfach einfügen lassen.

Das sehe ich anders. Ja, wir wollen die Schwelle für nicht Software-affine Leute senken und ja, das Handling der Settings-Header ist sehr „raw“ und m. E. für diesen Personenkreis eben gerade nicht geeignet. Aber diese Diskussion gehört jetzt wieder ganz klar in Konfiguration via Kconfig und hat wenig mit dem eigentlichen Thema hier zu tun.

1 „Gefällt mir“

Mir ist noch aufgefallen, dass ich in meinem Beispiel oben den Rat von @laszloh aus Automatische Code Formatierung - #16 von laszloh vergessen habe. Dort sollte natürlich if constexpr zum Einsatz kommen.

1 „Gefällt mir“

Bin total dafür!
Würde das ganze aber gerne zweiteilen:

  • einige Settings (@biologist hatte da schon eine gute Liste) sollten wir über den Webserver änderbar machen und somit komplett auflösen, dass diese immer mit kompiliert werden und über den Speicher mit einem Neustart wirken.
  • den Rest, der nicht davon betroffen ist sollte meiner Meinung nach genau so umgesetzt und aufgelöst werden

Wenn man die Anleitung hier im Forum für die Konfiguration erstellt sehe ich keine Hindernisse.
Ob ein Neuling die passenden Dateien suchen und mit dem Editor bearbeiten muss (ohne Kontrollmechanismen und Abhängigkeits-Check) oder über vscode Menü-geführt die Einstellungen festlegt sollte wirklich kein Unterschied (wenn nicht sogar einfacher) sein.

Gerade die aktuellen Probleme mit der Audiowiedergabe abhängig von der Konfiguration oder dem Code ist für mich ein Zeichen, dass wir mittelfristig genau diese Schritte brauchen.

1 „Gefällt mir“