====== Lyx OS – Anwendungen entwickeln ======
Diese Seite richtet sich an Entwickler, die Programme für Lyx OS schreiben möchten. Voraussetzung: Grundkenntnisse der [[lyx_-_programmiersprache:start|Lyx-Sprache]] und ein laufendes LyxOS-System (→ [[lyxos:erste-schritte|Erste Schritte]]).
→ [[lyxos:syscalls|Syscall-Referenz]] · [[lyxos:architektur|Architektur]] · [[lyxos:start|Übersicht]]
----
===== 1. Zielplattform: --target=lyxos =====
Jedes Lyx-Programm für LyxOS wird mit dem Flag ''--target=lyxos'' kompiliert. Dieses Target unterscheidet sich wesentlich vom Standard-Linux-Target:
^ Eigenschaft ^ Linux-Target (default) ^ LyxOS-Target (''--target=lyxos'') ^
| Laufzeitbibliothek | libc (glibc / musl) | ''lyxrt_lyxos.lyu'' (keine libc) |
| Ausgabe ''PrintLn(s)'' | ''write(1, ...)'' via libc | ''sys_write(FD_STDOUT, ...)'' direkt |
| Speicher ''mmap(...)'' | ''mmap()'' via libc | ''sys_mmap(...)'' direkt |
| Binärformat | ELF64 (Linux ABI) | ELF64 (LyxOS ABI) |
| Einstiegspunkt | ''main()'' via libc-Initialisierung | ''main()'' direkt (kein CRT0) |
| Syscall-Nummern | Linux-Tabelle | LyxOS-Tabelle (''doku/syscalls.md'') |
# Kompilieren für LyxOS
lyxc --target=lyxos meinprogramm.lyx -o meinprogramm.elf
Das Resultat ist ein ELF64-Binary ohne externe Shared-Library-Abhängigkeiten.
----
===== 2. Basis-Programm =====
Das einfachste lauffähige LyxOS-Programm:
fn main(): int64 {
PrintLn("Lyx OS — Ring-3 aktiv!");
return 0;
}
''PrintLn'' wird vom Compiler auf ''sys_write(FD_STDOUT, ...)'' abgebildet. ''return 0'' ruft ''sys_exit(0)'' auf. Kein ''import'' nötig.
----
===== 3. Ausgabe und Eingabe =====
==== Ausgabe ====
// Einzeiliger String (mit Newline)
PrintLn("Hello LyxOS");
// Ohne Newline
Print("Zähler: ");
PrintLn(IntToStr(42));
// Fehlerausgabe (FD_STDERR)
EPrintLn("Fehler: Ressource nicht verfügbar");
// Formatierte Ausgabe
import std.io;
PrintfSI("User %s hat ID %d", "admin", 1001);
==== Tastatureingabe (ab M5) ====
// Zeichen einlesen via sys_read(FD_STDIN, buf, 1)
var buf: [4]uint8 := [];
var n: int64 := 0;
// (n, err) := syscall(SYS_READ, FD_STDIN, ^buf[0] as int64, 1);
----
===== 4. Dateisystem =====
Die FAT32-Partition wird als ''/ '' gemountet. Alle Pfad-Syscalls nehmen einen ''dir_fd'' als erstes Argument. ''AT_CWD = -1'' verweist auf das aktuelle Arbeitsverzeichnis.
// Datei öffnen (sys_open, Gruppe 0x0200)
// var fd: int64 := 0;
// var err: int64 := 0;
// (err, fd) := syscall(SYS_OPEN, AT_CWD, "/data/config.txt", O_RDONLY, 0);
// Konventionell über Lyx-Builtins (werden intern gemappt):
import std.fs;
var fd: int64 := open("/data/config.txt", O_RDONLY, 0);
if (fd < 0) {
EPrintLn("Datei nicht gefunden");
return 1;
}
var buf: [512]uint8 := [];
var n: int64 := read(fd, ^buf[0] as pchar, 512);
close(fd);
> **Pfad-Konventionen:**
> LyxOS verwendet Forward-Slashes. Die Wurzel des FAT32-Volumes ist ''/'' im VFS. Verzeichnisnamen unterscheiden keine Groß-/Kleinschreibung (FAT32-Einschränkung).
----
===== 5. Speicherverwaltung =====
Ring-3 erhält Speicher über ''sys_mmap''. Das Lyx-Builtin ''mmap'' wird auf diesen Syscall gemappt:
con PROT_READ: int64 := 1;
con PROT_WRITE: int64 := 2;
con MAP_PRIVATE: int64 := 2;
con MAP_ANONYMOUS: int64 := 32;
// 4096 Byte anonymes Mapping
var buf: int64 := mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (buf = 0) {
EPrintLn("mmap fehlgeschlagen");
return 1;
}
poke8(buf, 42u8); // schreiben
var val: uint8 := peek8(buf); // lesen
munmap(buf, 4096);
Statische Arrays ''[N]T'' und lokale Variablen liegen im **Stack** (kein explizites Freigeben). ''mmap''/''munmap'' für dynamischen Heap-Speicher.
----
===== 6. Prozesse und Tasks =====
==== Prozess starten (ab M5) ====
// sys_spawn: neuer Prozess aus ELF-Binary
// Kein fork() — Prozesse werden immer frisch erzeugt
con SYS_SPAWN: int64 := 0x0003;
con AT_CWD: int64 := -1;
// var err, proc_fd := syscall(SYS_SPAWN, AT_CWD, "/bin/editor", argv, envp, 0);
==== Task (leichtgewichtig, automatisch parallelisiert) ====
// sys_task_group: Tasks laufen auf freien Cores ohne Programmierer-Eingriff
con SYS_TASK_GROUP_CREATE: int64 := 0x0B00;
con SYS_TASK_GROUP_ADD: int64 := 0x0B01;
con SYS_TASK_GROUP_AWAIT: int64 := 0x0B02;
// var err, group := syscall(SYS_TASK_GROUP_CREATE, 0);
// for i in range 0..8 { syscall(SYS_TASK_GROUP_ADD, group, worker_fn, args[i], 8); }
// syscall(SYS_TASK_GROUP_AWAIT, group, -1);
''@parallel''-Annotation im Lyx-Code lässt den Compiler dieses Muster automatisch generieren.
----
===== 7. Fehlerbehandlung =====
Jeder Syscall gibt ''rax'' (Fehlercode) und ''rdx'' (Nutzwert) zurück. In Lyx --target=lyxos übersetzt der Compiler diese Zwei-Register-Rückgabe in Tupel-Syntax:
// Zwei-Register-Rückgabe als Lyx-Tupel (ab M5 vollständig unterstützt):
// var (err, fd) := sys_open(AT_CWD, "/config.txt", O_RDONLY, 0);
// if (err != 0) {
// EPrintLn("Fehler: " + IntToStr(err)); // ERR_NOENT = 2 usw.
// return err;
// }
// Bis M5: Fehlercheck via Rückgabewert
var fd: int64 := open("/config.txt", O_RDONLY, 0);
if (fd < 0) {
EPrintLn("open fehlgeschlagen");
return 1;
}
Vollständige Fehlercode-Tabelle: [[lyxos:syscalls#fehlercodes|Syscall-Referenz — Fehlercodes]]
----
===== 8. Programm in die Disk-Image integrieren =====
Bis M5 die Shell fertig ist, muss ein Programm manuell in den Kernel-Startvorgang eingebunden werden. Möglichkeit: direkt in ''kernel.lyx'' aufrufen.
// kernel.lyx (nach allen Initialisierungen):
import meinprogramm;
pub fn main(boot_info_ptr: int64): int64 {
// ... Kernel-Init ...
return meinprogramm.main();
}
Oder: Binary auf FAT32 kopieren und im Build-Skript hinzufügen:
lyxc --target=lyxos hello.lyx -o hello.elf
mcopy -i bootloader/lyx_boot.img@@1048576 hello.elf ::/hello.elf
Letzte Aktualisierung: 2026-06-09