Die Hauptfrage ist: Soll Ihre Konfigurationsdatei in einer vollständigen Turing-Sprache vorliegen (wie Python)? Wenn Sie dies wünschen, können Sie auch eine andere Skriptsprache (Turing complete) wie Guile oder Lua einbetten (da diese als "einfacher" zu verwenden oder einzubetten ist als Python). Lesen Sie das Kapitel zu Erweitern und Python einbinden ). Ich werde darauf nicht weiter eingehen (da andere Antworten - z. B. von Amon - ausführlich darauf eingegangen sind), aber beachten Sie, dass das Einbetten einer Skriptsprache in Ihre Anwendung eine wichtige architektonische Wahl ist , die Sie sehr früh in Betracht ziehen sollten; Ich empfehle wirklich nicht, diese Wahl später zu treffen!
Ein bekanntes Beispiel für ein durch "Skripte" konfigurierbares Programm ist der GNU-Emacs- Editor (oder wahrscheinlich AutoCAD im proprietären Bereich). Beachten Sie daher, dass einige Benutzer, wenn Sie Skripte akzeptieren, diese Funktion möglicherweise ausgiebig verwenden und ein Skript mit mehreren tausend Zeilen erstellen würden. Daher ist die Auswahl einer ausreichend guten Skriptsprache wichtig.
(Zumindest auf POSIX-Systemen) können Sie es jedoch als zweckmäßig erachten, die Konfigurationsdatei zum Zeitpunkt der Initialisierung dynamisch berechnen zu lassen Text, der aus einer Datei oder einem Befehl stammt). Dazu können Sie einfach die Konvention übernehmen (und dokumentieren ), dass ein Konfigurationsdateipfad, der mit a !
oder a beginnt, |
tatsächlich ein Shell- Befehl ist , den Sie als Pipeline lesen würden . Dadurch hat der Benutzer die Wahl, welche "Präprozessor" - oder "Skriptsprache" er am besten kennt.
(Sie müssen Ihrem Benutzer in Bezug auf Sicherheitsprobleme vertrauen, wenn Sie eine dynamisch berechnete Konfiguration akzeptieren.)
In Ihrem Initialisierungscode main
würde Ihr (zum Beispiel) ein --config
Argument akzeptieren confarg
und einiges FILE*configf;
daraus abrufen. Wenn dieses Argument mit !
(dh wenn (confarg[0]=='!')
....) beginnt , würden Sie configf = popen(confarg+1, "r");
diese Pipe mit verwenden und schließen pclose(configf);
. Andernfalls würden Sie configf=fopen(confarg, "r");
diese Datei verwenden und mit schließen fclose(configf);
(Fehlerprüfung nicht vergessen). Siehe Pipe (7) , Popen (3) , Fopen (3) . Eine in Python codierte Anwendung enthält Informationen zu os.popen usw.
(Dokument auch für den seltsamen Benutzer, der eine Konfigurationsdatei mit dem Namen !foo.config
pass übergeben möchte ./!foo.config
, um den popen
obigen Trick zu umgehen )
BTW, wie ein Trick ist nur eine Bequemlichkeit (zu vermeiden , dass die erweiterte Benutzer zB Code erfordern einige Shell - Skript zu generieren eine Konfigurationsdatei ). Wenn der Benutzer einen Fehler melden möchte, sollte er Ihnen die generierte Konfigurationsdatei senden ...
Beachten Sie, dass Sie Ihre Anwendung auch so gestalten können, dass Sie Plugins zum Zeitpunkt der Initialisierung verwenden und laden können , z. B. mit dlopen (3) (und Sie müssen Ihrem Benutzer in Bezug auf dieses Plugin vertrauen). Auch dies ist eine sehr wichtige architektonische Entscheidung (und Sie müssen einige recht stabile APIs und Konventionen für diese Plugins und Ihre Anwendung definieren und bereitstellen ).
Für eine Anwendung, die in einer Skriptsprache wie Python codiert ist, können Sie auch ein Programmargument für eval oder exec oder ähnliche Grundelemente akzeptieren . Wiederum sind die Sicherheitsprobleme das Anliegen des (fortgeschrittenen) Benutzers.
In Bezug auf das Textformat für Ihre Konfigurationsdatei (ob generiert oder nicht) glaube ich, dass Sie es meistens gut dokumentieren müssen (und die Wahl eines bestimmten Formats ist nicht so wichtig, ich empfehle jedoch, dass Ihr Benutzer es setzen kann einige übersprungene Kommentare drin). Sie könnten JSON (vorzugsweise mit einem JSON-Parser, der Kommentare mit der üblichen //
bis-eol-Methode oder /*
... */
... akzeptiert und überspringt ) oder YAML oder XML oder INI oder Ihr eigenes Ding verwenden. Das Parsen einer Konfigurationsdatei ist relativ einfach (und Sie werden viele Bibliotheken finden, die sich auf diese Aufgabe beziehen).