Vega — Portabel bauen
Ein Quelltext, drei Ziele: X11 unter Linux, Win32 unter Windows, Ring-3 unter Lyx OS. Der Unterschied steht nicht im Programm, sondern im Include-Pfad des Übersetzungsaufrufs.
→ Vega-Guides · Backends · Bauen und Testen · Cross-Compilation
Der Trick: eine Unit, dreimal vorhanden
Vega.BackendAuto liegt je einmal unter platform/linux, platform/win64 und platform/lyxos. Alle drei exportieren dieselbe Funktion:
pub fn NewPlatformBackend(): IVegaBackend
Welche gebunden wird, entscheidet die letzte -I-Angabe — deshalb steht der Plattformpfad hinter dem Projektpfad.
lyxc app.lyx -I . -I platform/linux -o app # X11
lyxc app.lyx -I . -I platform/win64 --target=win64 --format=pe -o app.exe # Win32
lyxc app.lyx -I . -I platform/lyxos -o app.elf # Lyx OS
Für Lyx OS wird derzeit ohne--target=lyxosgebaut — als Übergang, nicht als Dauerzustand.
Das native Zielformat von Lyx OS istLYX!, der Maschinencode-Container des LX-34-Loaders;--target=lyxoserzeugt ihn (Magic4C 59 58 21, nachgemessen mitlyxc 1.1.4B), undPrintLnarbeitet dort inzwischen — allerdings nur mit einem Zeichenketten-Literal (#1716). ELF wird von Lyx OS nur weiterhin mitgeladen.
Was Vega an diesem Ziel bislang hindert:allocundfreefehlen (#1718 — deshalb die eigeneplatform/lyxos/Vega/Mem.lyxübermmap), und die stdlib-Importe brechen an fehlenden Builtin-Namen (#1717:std.fsschon beiFileExists,std.iobeiStrNew); im Backend selbst fehlen die Builtin-IDs 3 und 6–15 (#1715). Solange das so ist, ist der ELF-Weg der einzige, der wirklich läuft. Sobald die Lücken zu sind, ist--target=lyxosder richtige Weg.
Warum keine Fallunterscheidung im Code
TARGET_OS gibt es (1 = Linux, 3 = Windows), und es ändert sich mit –target. Für die Backendwahl reicht es trotzdem nicht: Beide Zweige müssten übersetzt und gebunden werden, und extern-Deklarationen sind harte Abhängigkeiten — auch in einem Zweig, der nie läuft. Eine Linux-Binary mit eingebundenem Win32-Backend verlangt beim Start kernel32.dll und startet gar nicht erst.
Deshalb die Trennung über den Pfad. Es ist dasselbe Verfahren, mit dem Lazarus seine Widgetsets auswählt.
Beispiel
Dieses Programm ist unverändert für alle drei Ziele übersetzbar:
unit Main;
import std.io;
import Vega.Types;
import Vega.Events;
import Vega.Canvas;
import Vega.Theme;
import Vega.Control;
import Vega.Font;
import Vega.Strings;
import Vega.Lists;
import Vega.Style;
import Vega.StdCtrls;
import Vega.Backend;
// Diese Unit gibt es dreimal — unter platform/linux, platform/win64 und
// platform/lyxos. Welche gilt, entscheidet der Include-Pfad, nicht der Code.
import Vega.BackendAuto;
import Vega.Forms;
var g_app: TApplication;
var g_stand: TLabel;
var g_zaehler: int64;
fn OnZaehl(sender: TControl): void {
g_zaehler := g_zaehler + 1;
g_stand.SetCaption(StrConcat("Geklickt: ", IntToStr(g_zaehler)));
}
fn OnBeenden(sender: TControl): void { g_app.Terminate(); }
fn main(): int64 {
g_app := new TApplication(NewPlatformBackend());
if (!g_app.Ready) { PrintLn("Kein Fenstersystem erreichbar."); return 1; }
var f: TForm := new TForm(320, 160, "Portabel");
g_zaehler := 0;
g_stand := new TLabel("Geklickt: 0");
g_stand.SetBounds(16, 16, 280, 18);
g_stand.SetParent(f);
var b1: TButton := new TButton("Zaehlen");
b1.SetBounds(16, 56, 130, 28);
b1.OnClick := OnZaehl;
b1.SetParent(f);
var b2: TButton := new TButton("Beenden");
b2.SetBounds(166, 56, 130, 28);
b2.OnClick := OnBeenden;
b2.SetParent(f);
if (!g_app.ShowForm(f)) { return 2; }
g_app.Run();
g_app.Shutdown();
return 0;
}
Nachgemessen mit lyxc 1.1.3I — dieselbe Datei, drei Aufrufe:
| Ziel | Aufruf | Ergebnis |
|---|---|---|
| Linux/X11 | -I . -I platform/linux | ELF 64-bit, 787 KB |
| Windows | -I . -I platform/win64 --target=win64 --format=pe | PE32+ x86-64, 803 KB |
| Lyx OS | -I . -I platform/lyxos | ELF 64-bit statisch, 764 KB |
Die PE-Datei wurde zusätzlich unter Wine gestartet und zeigt ihr Fenster.
Was portabel ist und was nicht
| Portabel | Nicht portabel |
|---|---|
Alles aus Vega.* — Controls, Layout, Themes, LFM | Direkte extern-Aufrufe in Systembibliotheken |
| Zeichnen, Schriften, Ereignisse | Pfade mit / oder \\ fest im Code |
std-Units ohne Systembezug | Annahmen über Zeilenenden oder Dateirechte |
Die HAL ist bewusst klein — 21 Methoden. Alles darüber ist geteilter Code und läuft überall gleich; genau deshalb ist sie ein Interface.
Bauen mit Skript
Im Repository nimmt build.sh die Unterscheidung über den Dateinamen ab: ein Beispiel name_win wird als PE gebaut, name_lyxos für Lyx OS, alles andere für X11. Für ein eigenes Projekt genügt dasselbe Muster — drei Aufrufe, ein Quelltext.
Fallstricke
- Plattformpfad vor dem Projektpfad. Die letzte
-I-Angabe gewinnt; stehtplatform/linuxzuerst, greift sie nicht. –target=win64ohneplatform/win64. Dann wird das X11-Backend in eine PE-Datei gebunden — sie startet, findet aber kein Fenstersystem.–target=lyxosbenutzt, solange die Builtins fehlen. Der Bau bricht bei der erstenalloc- oderstd.fs-Stelle ab; siehe Kasten. Es ist das künftige, noch nicht das gangbare Ziel.- Backend direkt importiert.
import Vega.Backend.X11bindet fest an X11; portable Programme nehmenVega.BackendAuto.
Letzte Aktualisierung: 2026-08-20 — drei Ziele mit lyxc 1.1.3I aus derselben Datei gebaut und mit file geprüft; der Lyx-OS-Abschnitt am 2026-08-20 gegen lyxc 1.1.4B nachgemessen (LYX!-Container, fehlende Builtins alloc und readlink).
