std.res — eingebettete Ressourcen
import std.res;
Zugriff auf Dateien, die mit @resource(„name“, „pfad“) ins Erzeugnis eingebettet wurden — über ihren Namen, zur Laufzeit. Das Gegenstück zu Delphis .res: Bilder, Schriften, Vorlagen oder Konfigurationsvorgaben liegen im Programm selbst, nicht daneben im Dateisystem.
→ @resource und @embed · Standard Library · #1961
1. Einbetten und finden
unit main;
@resource("splash", "assets/splash.lyxi");
@resource("hilfe", "assets/hilfe.txt");
import std.res;
import std.io;
import std.string;
fn main(): int64 {
var bild: pchar := ResFind("splash");
var n: int64 := ResLen("splash");
PrintLn(StrConcat("Groesse: ", IntToStr(n)));
PrintLn(StrConcat("Inhalt: ", bild));
return 0;
}
Groesse: 16
Inhalt: SPLASH-BYTES-123
@resource steht auf Unit-Ebene, nicht in einer Funktion. Der Pfad wird relativ zur Quelldatei aufgelöst, nicht zum Arbeitsverzeichnis — ein Programm lässt sich also aus jedem Verzeichnis übersetzen.
2. Funktionen
| Signatur | Zweck |
|---|---|
ResCount(): int64 | Zahl der eingebetteten Ressourcen; 0, wenn keine vorhanden |
ResFind(name: pchar): pchar | Zeiger auf die Bytes, oder 0 bei unbekanntem Namen |
ResLen(name: pchar): int64 | Länge in Byte, oder 0 |
ResIndex(name: pchar): int64 | Position in der Tabelle, oder -1 |
ResName(i: int64): pchar | Name des Eintrags i |
ResBytesAt(i: int64): pchar | Bytes des Eintrags i |
ResSizeAt(i: int64): int64 | Länge des Eintrags i |
Damit lässt sich der Bestand auch durchlaufen — etwa für ein Werkzeug, das zeigt, was in einem Programm steckt:
var i: int64 := 0;
while (i < ResCount()) {
PrintLn(StrConcat(ResName(i), StrConcat(" ", IntToStr(ResSizeAt(i)))));
i := i + 1;
}
3. Aufbau der Tabelle
Die Tabelle liegt im Datensegment und wird über das Builtin GetResTable() erreicht — dasselbe Muster wie GetEnvBlock (#1677): der Codegen kennt die Adresse, std/res.lyx rechnet in Lyx weiter. Damit ist die Bibliotheksseite lesbarer Lyx-Code und kein Compiler-Interna.
[0] Anzahl der Einträge
[1 + i*4 + 0] Zeiger auf den Namen (NUL-terminiert)
[1 + i*4 + 1] Länge des Namens
[1 + i*4 + 2] Zeiger auf die Bytes
[1 + i*4 + 3] Anzahl der Bytes
GetResTable() liefert 0, wenn das Programm keine einzige @resource-Angabe trägt. Jede Funktion dieser Unit fängt diesen Fall ab — ein Programm ohne Ressourcen bekommt ResCount() = 0 und keinen Absturz.
4. Fallstricke
- Binärdaten sind nicht nullterminiert.
ResFindliefert einenpchar, aber die Bytes stammen aus der Datei: enthält sie ein Nullbyte, endet jede Zeichenkettenfunktion dort. Die Länge kommt ausResLen, nicht ausStrLen— gemessen: eine Datei mitA\0B\0Cmeldet korrekt5. - Der Name ist frei wählbar und hat nichts mit dem Dateinamen zu tun. Zwei Ressourcen mit demselben Namen sind nicht sinnvoll; gesucht wird der erste Treffer.
- Fehlt die Datei, bricht die Übersetzung ab:
error: @resource: Datei nicht lesbar: <pfad>. Das ist Absicht — eine fehlende Ressource fällt beim Bauen auf, nicht beim Kunden. @resourcewirkt über Unit-Grenzen. Eine importierte Unit darf eigene Ressourcen mitbringen; sie landen in derselben Tabelle und sind über ihren Namen erreichbar.
<WRAP center round important 90%>
Nur --target=x86_64. Auf dem IR-Weg (lyxos, arm64, riscv, xtensa) bricht die Übersetzung ab:
lyxc: @resource ist bisher nur mit --target=x86_64 umgesetzt.
Die Ressourcentabelle besteht aus Zeigern in den Datenbereich; auf dem
IR-Weg gibt es dafuer bisher nur die nullterminierte
Zeichenkettentabelle (siehe #1968).
Für einzelne Dateien geht dort @embed — bei Textdateien.
</WRAP>
5. Abgrenzung zu @embed
@embed(„pfad“) | @resource(„name“, „pfad“) |
|
|---|---|---|
| Auflösung | zur Übersetzungszeit, der Pfad steht im Quelltext | zur Laufzeit, über den Namen |
| Ergebnis | Zeiger auf die Bytes (@embed_len liefert die Größe) | Eintrag in einer benannten Tabelle |
| Auflisten möglich | nein | ja, über ResCount/ResName |
| Name zur Laufzeit wählbar | nein | ja |
| Zielplattformen | auch IR-Ziele (Textdateien) | nur x86-64 |
@embed ist der kürzere Weg, wenn genau eine Datei an genau einer Stelle gebraucht wird:
var s: pchar := @embed("assets/hilfe.txt");
var n: int64 := @embed_len("assets/hilfe.txt");
[N]uint8-Feld: Lyx legt Felder mit acht Byte je Element ab, auch bei uint8. Ein eingebettetes 1-MB-Bild bräuchte damit 8 MB im Erzeugnis. Die Bytes liegen deshalb gepackt im Datensegment, und @embed liefert die Adresse. Gelesen wird mit peek8, wie bei jedem anderen Bytepuffer.
Letzte Aktualisierung: 2026-09-05 — Seite neu angelegt; erhoben aus std/res.lyx und src/parser.lyx (#1961 Stufe 1 und 2), alle Beispiele gegen lyxc 1.2.2D übersetzt und ausgeführt.
Ressourcen in einer ''.lyu''
Seit #1971 trägt auch das .lyu-Format eingebettete Ressourcen: der Abschnitt steht am Ende der Datei, der Offset im bisher reservierten Feld des Kopfes. Die Version bleibt 2 — ein Leser, der den Abschnitt nicht kennt, hört nach der Symboltabelle auf und liest die Datei unverändert.
--unit-info listet die Ressourcen mit Name und Größe. Das ist die Stelle, an der sich ohne Übersetzen nachsehen lässt, was eine Bibliothek mitbringt.
Die Länge steht ausdrücklich in der Datei und nicht als Nullterminierung: eine Ressource ist eine Binärdatei und darf Nullbytes tragen — genau daran ist die Zeichenkettentabelle des IR-Wegs gescheitert (#1968).
Der Import daraus fehlt noch. Eine.lyuträgt die Ressourcen zwar, aber eine importierende Übersetzung übernimmt sie nicht — das hängt an #2014, solange die.lyueine reine Namensliste ist. Offen sind ebenso die IR-Ziele und das LBF-Format.
