TOML-Projekte
Ein Projektmanifest wählt geordnete Gruppen von Erlang-Quellen aus und konfiguriert jedes Ziel unabhängig. Alle CLI-Aktionen akzeptieren Projekte. Siehe das funktionierende Beispiel.
Manifest (Schema 1)
schema_version = 1
[[targets]]
name = "app"
sources = ["main.erl", "src/workers/*.erl", "shared/**/*.erl"]
source_dirs = ["src/support"]
output = "build/app"
entry = "main:main"
build_dir = "build"
[targets.options]
source_search_paths = ["src", "generated"]
include_dirs = ["include", "vendor/include"]
defines = ["DEBUG", "LIMIT=100", 'LABEL="demo"']
enable_features = ["maybe_expr"]
disable_features = ["compr_assign"]
ignore_dirs = ["src/legacy", "deps/*/test"]
ignore_modules = ["telemetry", "*_SUITE"]
keep_exports = false
shell = false
cache_inference_in_dirs = ["deps/*"]
[targets.options.applications]
my_dependency = "vendor/my_dependency"
schema_version = 1und ein nicht leeres Arraytargetssind erforderlich. Unbekannte Schlüssel, falsche Typen, doppelte Zielnamen und leere Zeichenketten werden abgewiesen; keine Typumwandlung. Das gesamte Manifest wird validiert, einschließlich nicht ausgewählter Ziele.- Zielnamen: ASCII mit Beachtung der Groß-/Kleinschreibung
[A-Za-z0-9_][A-Za-z0-9_.-]*, eindeutig. Ein Name ist ein Build-Ziel, kein LLVM-Triple. sources(Dateien und Wildcard-Muster) undsource_dirs(rekursive Suche nach.erlund.abstr) sind optional, aber ein Ziel braucht mindestens einen Eintrag. Explizite Dateien müssen auf.erlenden oder auf.abstrfür Formen im abstrakten Format (Transformationen); Header sind Abhängigkeiten, keine Eingaben.[[targets.asn1]]-Gruppen kompilieren ASN.1-Spezifikationen (sources,options,outdir) zu Modulen, die dem Ziel hinzugefügt werden (ASN.1).parse_transforms(Modulnamen) undtransform_paths(Verzeichnisse oder Muster vorkompilierter.beam-Dateien) inoptionswenden Parse-Transformationen auf die Module des Ziels an (Transformationen).ignore_dirs(Pfade) undignore_modules(Modulnamen), beide mit Wildcards, inoptionslassen Quellen aus dem Build heraus (ignorierte Quellen).keep_exports = trueinoptionshält jeden Export der ausführbaren Datei des Ziels aufrufbar, wie es--keep-exportsfür jedes ausgewählte Ziel tut (Export-Lebendigkeit). Es muss ein Boolean sein.shell = trueinoptionsbindet die interaktive Shell in die ausführbare Datei des Ziels ein, wie es--shelltut (interaktive Shell). Es muss ein Boolean sein.cache_inference_in_dirs(Verzeichnis-Wildcards) inoptionsfügt Verzeichnisse hinzu, deren Module ihre Inferenzergebnisse im Build-Cache behalten (Inferenz-Cache).- Die Felder von
optionssind optionale typisierte Frontend-Optionen.definesverwendenNAME(=true) oderNAME=ERLANG_LITERAL_TERM; Duplikate sind Fehler. Ein Feature darf nicht in beiden Feature-Listen stehen. entry(optional) wählt den Einstieg der ausführbaren DateiMODULE[:FUNCTION[/ARITY]]; siehe ausführbare Dateien. Das CLI---entryüberschreibt es für ein einzelnes ausgewähltes Ziel.build_dir(optional) ist das Build-Verzeichnis des Ziels, Standard<manifest-dir>/build.outputist das Ziel der ausführbaren Datei, Standard<manifest-dir>/build/<target>(.exeunter Windows). Ein Ziel mitoutputoderentryist ein ausführbares Ziel (ausführbare Dateien);--emitund Prüf-/Ausgabemodi ignorieren die Ausgaben beider Schlüssel.- Nicht unterstützt: Standards auf Wurzelebene, Vererbung, Zielabhängigkeiten, Importe, Profile, Pakete, Watch, parallele Builds. Felder werden nur zusammen mit ihrem Verhalten hinzugefügt.
CLI und Zielauswahl
clau [options] <source.erl>...
clau [options] --project <path> [--target <name>]...
clau --new-project <filename>
- Positionale Quellen und
--projectschließen sich gegenseitig aus. Ein--project, beliebig viele--target, in beliebiger Reihenfolge. - Kein
--target: alle Ziele in Manifestreihenfolge. Selektoren behalten ihre Reihenfolge und ihr erstes Vorkommen. Unbekannte Namen schlagen vor jeder Frontend-Arbeit fehl und listen die verfügbaren Namen auf. --project test1lädttest1.toml, wenntest1nicht existiert.- CLI-Frontend-Optionen gelten für jedes ausgewählte Ziel. CLI-relative Pfade behalten ihre Bedeutung relativ zum Aufrufverzeichnis; Manifestpfade sind relativ zum Manifest.
- Ohne
--emitoder eine Prüf-/Ausgabeaktion werden ausführbare Ziele zu ihren Ausgaben gelinkt (ausführbare Dateien); andere Ziele werden im Speicher kompiliert. -o/--outputlinkt das Ziel an diesen Pfad statt an seinoutput(Linken); es erfordert genau ein ausgewähltes Ziel.--verboseprotokolliert[pp]-Dateien/-Includes und[parse]-Quellen auf stderr.--print-inputsführt jedes ausgewählte Ziel bis zur Kompilierung aus: Es verarbeitet und parst die Quellen nach der Suche vor und fügt dann die Module hinzu, die sie aus der Bibliothek undsource_search_pathsbenennen, wie es ein Build tut. Es gibt die Quellen des Ziels (absolute Pfade) aus, eine pro Zeile, dann jede hinzugefügte Quelle als<path> (referenced at <file>:<line>), die früheste Stelle im verweisenden Modul, die sie benennt; hinzugefügte Quellen werden ihrerseits durchsucht. Es wird nichts kompiliert. Bei mehreren Zielen folgt jede Liste auf eine Zeile[target <name>]. Positionale Eingaben werden wie angegeben ausgegeben. Diagnosen gehen nach stderr; ein Parse-Fehler stoppt das Hinzufügen referenzierter Module und endet mit 1. Es ersetzt andere Prüf-/Ausgabeaktionen und kollidiert wie diese mit-o,--entryund Kompilierschaltern.--print-envgibt den gesamten Aufruf als TOML aus: eine Tabelle[[targets]]pro ausgewähltem Ziel mit seinen aufgelösten Quellen, Such-/Include-Verzeichnissen und wirksamen Optionen (Umgebungsbericht).- Exit-Code 2: Verwendungsfehler und unbekannte Ziele. Exit-Code 1: Fehler bei Manifest, Suche, Frontend oder Erstellung. Exit-Code 0: Erfolg (Warnungen erlaubt).
Jedes ausgewählte Ziel ist ein separater Kompilier-Batch mit eigenen
Präprozessor-Sitzungen. Die Planung (Dekodieren, Auswählen, Suchen, Prüfen auf
Ausgabekollisionen) ist abgeschlossen, bevor irgendeine Quelle läuft; die
Ausführung verarbeitet dann Ziele/Dateien der Reihe nach und hält Fehlschläge
fest. Nutzausgaben gehen ohne Banner (außer den Zielzeilen von
--print-inputs) in Ziel-/Dateireihenfolge nach stdout; Kontext und Diagnosen
gehen nach stderr. Ein Ziel mit Diagnosen wird einmal genannt, in einer Zeile
<manifest> [target <name>]: vor seiner ersten; die Diagnosen selbst
(error: file:line:col: message) tragen kein Werkzeug- oder Zielpräfix.
./build/debug/bin/clau --parse-check --project examples/project/project.toml
./build/debug/bin/clau --print-ast --project examples/project/project.toml --target tests --target app
Ausführbare Dateien
clau --project FILE [--target T]... (kein --emit, keine
Prüf-/Ausgabeaktion) linkt jedes ausgewählte Ziel, das einen Schlüssel output
oder entry hat oder das CLI--o/--entry adressiert, zu einer ausführbaren
Datei pro Ziel:
- Zielort: CLI-
-o(relativ zum Aufruf), sonstoutput(relativ zum Manifest), sonst<manifest-dir>/build/<target>. Windows-Ziele hängen.exean einen Namen ohne Endung an. Fehlende Verzeichnisse von Manifestausgaben werden erstellt; ein explizites-o-Verzeichnis muss existieren. - Einstieg: CLI-
--entry, Manifest-entry, sonst Erkennung (Einstiegsauswahl). - Ziele ohne
output,entry,-ound--entrysind Bibliotheken: Sie werden im Speicher kompiliert und schreiben nichts, selbst wenn ein Modulmain/1exportiert. - Die Planung weist ausgewählte Ziele mit demselben Zielort ab; Ausgaben, die
erst nach dem Anhängen von
.exezusammenfallen, werden vor der Veröffentlichung abgewiesen. Eine Ausgabe darf keine ausgewählte Quelle und nicht das Manifest überdecken. - Jedes Ziel wird in sein eigenes Staging-Verzeichnis kompiliert und gelinkt. Ausgaben werden erst ersetzt, nachdem jedes ausgewählte Ziel erfolgreich war, in Zielreihenfolge; jeder Fehlschlag lässt alle vorhandenen Ausgaben unverändert. Ein Fehlschlag beim Ersetzen einer späteren Ausgabe kann frühere bereits ersetzt hinterlassen.
--linkerund--runtime-librarygelten für jedes gelinkte Ziel (Linken).
./build/debug/bin/clau --project tests/fixtures/linking/project/project.toml
Ein Projekt erstellen
--new-project <filename> schreibt ein kommentiertes Manifest und sonst
nichts.
- Hängt
.tomlan, außer der Name endet bereits auf.toml(ASCII, ohne Beachtung der Groß-/Kleinschreibung):demo→demo.toml,demo.config→demo.config.toml. - Weist leere oder verzeichnisartige Namen, Wiederholung und jede Kombination
mit Quellen,
--project,--target,-o, Prüf-/Ausgabemodi oder Frontend-Optionen ab. - Das übergeordnete Verzeichnis muss existieren. Überschreibt nie (exklusive Erstellung); räumt bei einem Schreibfehler die eigene unvollständige Datei auf. Gibt bei Erfolg den erstellten Pfad aus.
- Der Inhalt ist deterministisches UTF-8/LF mit Kommentaren: ein Ziel
app,sources = [],source_dirs = ["src"], leere Optionslisten und die Standardausgabe der Plattform. Er lässt sich sofort dekodieren; Quellen fügt man untersrchinzu.
Build-Verzeichnis
Jedes Projektziel hat ein Build-Verzeichnis, in dem Clause seine eigenen
temporären Dateien und seine Caches ablegt: das build_dir des Ziels, relativ
zum Manifest, Standard <manifest-dir>/build. --build-dir DIR (relativ zum
Aufruf) ersetzt es für jedes ausgewählte Ziel. Positionale Eingaben bekommen
keines, außer --build-dir ist angegeben.
- Temporäre Dateien liegen unter
<build_dir>/tmp: die Arbeitsbereiche des Laders für Parse-Transformationen (Transformationen). Jeder Lauf entfernt seine eigenen; ein leerestmpkann bleiben. Ohne Build-Verzeichnis landen sie im temporären Verzeichnis des Systems. - Das Link-Staging (
.clause-link-*) bleibt neben der Ausgabe der ausführbaren Datei, weil das abschließende Umbenennen auf dem Volume der Ausgabe bleiben muss (Linken). - Prüf- und Ausgabemodi (
--parse-check,--print-ast, ...) schreiben nichts außerhalb des Build-Verzeichnisses; positionale Prüfungen ohne--build-dirschreiben überhaupt keine Datei. --print-envgibt dasbuild_dirjedes Ziels aus ("", wenn es keines gibt).
Build-Caches
Ergebnisse, die es wert sind, zwischen Läufen behalten zu werden, liegen unter
<build_dir>/cache; --no-cache liest und schreibt sie weder. Es sind die
Antworten des Laders für Parse-Transformationen und die Liste der Sticky-Module
des Host-OTP, sodass ein warmer Build kein Host-erl für Module startet, deren
Transformationseingaben sich nicht geändert haben, das
Kompilierergebnis jedes Batches und die
Inferenzergebnisse von Modulen in konfigurierten
Verzeichnissen.
- Schnittstelle. Aufrufer verwenden einen projektinternen Speicher
(
compiler/src/cache/ store.hpp):get/putnach Eingabeverzeichnis, Dateiname, Ergebnisart und Schlüssel, dazuinvalidateundprune; Pfade sehen sie nie. Ein Wert ist die Formatversion des Aufrufers und eine Liste benannter Teile (ein Transformationslauf:replyundoutput; ein Kompilierergebnis:failed, jedediagnosticund mit Ausgabentriple,extensionund ein Teil pro Modulobjekt), sodass kein Aufrufer einen eigenen Codec braucht. Eingetmit einer anderen Formatversion ist ein Fehltreffer. Jede Operation ist von mehreren Threads gleichzeitig sicher. - Layout.
cache/v2/cache.dbist eine SQLite-3.54-Datenbank: Tabelleentries(Eingabeverzeichnis, Datei, Art, Schlüssel, Format, letzte Verwendung; eindeutig über die Adresse) und Tabelleparts(Eintrag, Reihenfolge, Name, Größe, xxh3-64-Prüfsumme und entweder die Bytes oder der Name einer Blob-Datei). Teile größer als 256 KB liegen incache/v2/blobs/<xxh3-128 of the bytes>, sodass gleiche Teile (die identischen Objekte eines unter zwei Optionssätzen gebauten Batches) einmal gespeichert werden; bei 256 KB hören gemessene Lesevorgänge auf, die Datenbank zu begünstigen, und Schreibvorgänge beginnen, Dateien zu begünstigen (cache_store benchintests/compiler/cache). Eine Blob-Datei wird als temporäre Datei geschrieben und umbenannt, bevor die Zeile, die sie benennt, festgeschrieben wird, sodass eine Zeile nie eine unvollständige Datei benennt; ein Absturz dazwischen hinterlässt nur eine verwaiste Datei. - Schlüssel. Ein Schlüssel ist der 128-Bit-Inhaltshash von allem, wovon das
Ergebnis abhängt, nie ein Zeitstempel: die Version und die ausführbare Datei
von
clau(Pfad, Größe, Änderungszeit, sodass ein neu gebautesclaueinen Fehltreffer hat), die Ergebnisart und bei einem Transformationslauf die anerlgesendete Anfrage (die vorverarbeiteten Formen des Moduls und seine Compile-Optionen: Include-Verzeichnisse, Defines, Features), das Host-OTP-Release (erlund die Dateienreleases/*/OTP_VERSIONdaneben), jede für den Lauf kompilierte Transformationsquelle des Projekts mit den Dateien, die sie einbindet, und jede.beamauf den Codepfaden der Transformationen. Die Formatversion des Speichers ist das Verzeichnisv<format>; die eigene Formatversion eines Werts wird in seiner Zeile gehalten. Da der Schlüssel die vorverarbeiteten Formen abdeckt, verfehlen ein geänderter Header, ein geändertes Define oder Feature oder ein neuer Header, der einen eingebundenen überdeckt, genau die Module, deren Formen oder Optionen sich ändern; Defines und Features sind Compile-Optionen, die jede Transformation sieht, daher verfehlen sie jedes transformierte Modul; eine geänderte.beamverfehlt jedes Modul, dessen Transformationen mit diesem Codepfad laufen. - Nebenläufigkeit. Die Datenbank läuft im Write-Ahead-Log-Modus mit
synchronous=NORMAL: Leser laufen neben einem Schreiber, und Schreiber (eine Transaktion proput) warten bis zu 30 s aufeinander. Mehrereclau-Prozesse, die sich ein Build-Verzeichnis teilen, behalten jeden Eintrag. Innerhalb eines Prozesses serialisiert ein Mutex die Threads, die sich einen Speicher teilen. - Beschädigung. Teile tragen Größen und Prüfsummen, und Blob-Dateien werden
gegen ihre Namen geprüft: Ein beschädigter Teil oder eine fehlende Blob-Datei
ist ein Fehltreffer (
damaged entry), und sein Eintrag wird verworfen. Eine unbrauchbare, abgeschnittene oder fremdecache.db(SQLite meldet sie als beschädigt oder als keine Datenbank, oder ihre Anwendungs-ID oder Schemaversion weichen ab) wird incache.db.damagedumbenannt und neu erstellt; ist das unmöglich, läuft der Lauf ohne Cache weiter. Nichts davon ist ein Fehler, und--verbosevermerkt es als[cache] .... - Netzwerkdateisysteme. Write-Ahead-Logging braucht gemeinsamen Speicher
zwischen Prozessen, den Netzwerkdateisysteme nicht bieten. Kann SQLite nicht
in den WAL-Modus wechseln, verwendet der Speicher sein Rollback-Journal (Leser
warten dann auf einen Schreiber), und
--verbosesagt das einmal; funktioniert kein Journalmodus, läuft der Lauf ohne Cache weiter. - Bereinigung. Am Ende eines Laufs, der in einen Speicher geschrieben hat,
werden Einträge gelöscht, die 30 Tage nicht verwendet wurden, dann
Blob-Dateien, die kein Eintrag benennt (sobald sie älter als 10 Minuten sind,
damit die neue Datei eines gleichzeitigen Schreibers überlebt), und die
freigegebenen Seiten werden an das Dateisystem zurückgegeben (inkrementelles
Vacuum). Jeder Lauf entfernt einen übrig gebliebenen Baum
cache/v1des früheren Datei-Backends. - Beobachtbarkeit.
--print-stage-timesmarkiert wiederverwendete Stufen ([time] transform src/a.erl: 7.254 ms (cached));--verbosegibt[cache] hit|miss <kind> <file>mit dem Grund eines Fehltreffers aus (no entry,inputs changed,damaged entry). Diagnosen und Transformationsausgabe sind mit und ohne Treffer gleich: Sie werden mit dem Eintrag gespeichert. - Nicht gecacht: Vorverarbeitung und Parsen (das Laden eines gecachten
Ergebnisses über die abstrakten Formen,
transforms/import, war gemessen langsamer als erneutes Parsen) sowie Verzeichnisdurchläufe: Die Planung wird vom Öffnen und Identifizieren jeder Quelle dominiert, was ein Cache für Durchläufe nicht überspringen kann.
Inferenz-Cache
Bibliotheksmodule (die Quellen von OTPs stdlib, kernel, compiler und
syntax_tools, die über source_search_paths gefunden werden, Clauses eigene
Bibliothek) ändern sich selten, daher behalten Module in
konfigurierten Verzeichnissen ihre Ergebnisse der Typinferenz im Build-Cache,
pro Modul, und spätere Kompilierungen verwenden sie wieder, statt sie erneut zu
inferieren.
- Verzeichnisse: die impliziten OTP-Anwendungsmuster
*/stdlib,*/stdlib-*,*/kernel,*/kernel-*,*/compiler,*/compiler-*,*/syntax_toolsund*/syntax_tools-*, dann dascache_inference_in_dirsdes Ziels, dann jedes--cache-inference-in-dirs PATTERN(wiederholbar; auch positionale Eingaben). Muster verwenden die Wildcards vonsources; Windows-Trennzeichen werden akzeptiert. - Ein Modul ist abgedeckt, wenn ein Verzeichnis, das seine Quelle enthält, auf
ein Muster passt. Ein relatives Muster passt auf die abschließenden
Verzeichnisse eines beliebigen Pfads, nicht auf Pfade unterhalb des
Manifestverzeichnisses:
*/stdlibdeckt/usr/lib/erlang/lib/stdlib/src/lists.erlundreferences/otp/lib/stdlib/src/lists.erlab, während ein installiertes.../lib/stdlib-7.0/src/lists.erl*/stdlib-*braucht. Ein absolutes Muster passt auf den ganzen Verzeichnispfad (C:/Program Files/Erlang OTP/lib/*). Das Matching ist lexikalisch und beachtet die Groß-/Kleinschreibung. Die impliziten Muster decken auch ein eigenes Verzeichnis des Projekts mit einem solchen Namen ab (apps/compiler), was nur mehr Einträge speichert: Die Wiederverwendung ist für jedes Modul korrekt. --print-envgibt die wirksame Liste alscache_inference_in_dirsaus, die impliziten Muster zuerst. Ein nicht unterstütztes Konstrukt ([,{,!) ist ein Manifestfehler oder auf der Befehlszeile ein Verwendungsfehler (Exit-Code 2).- Die Wiederverwendung braucht ein Build-Verzeichnis (jedes Projektziel;
positionale Eingaben mit
--build-dir) und ist mit--no-cacheaus. Sie funktioniert für jede Aktion, die analysiert (Kompilieren, ausführbare Dateien,--print-types, IR-Inspektionen), auch wenn der Kompilier-Cache des Batches einen Fehltreffer hat. - Schlüssel: die Identität von
clau, der Fingerabdruck des Moduls und die jedes Batch-Moduls, das seine Atome benennen, transitiv (entfernte Aufrufe,fun M:F/A,apply, jedes Atom, das ein Modulname ist); siehe Semantik: Inferenz-Cache dazu, warum das alles ist, wovon seine Fakten abhängen. Das Bearbeiten eines Nutzermoduls behält daher die Bibliothekstreffer, außer ein Bibliotheksmodul benennt es; das Bearbeiten eines Bibliotheksmoduls verfehlt es und jedes abgedeckte Modul, das es erreicht. - Einträge werden pro Quellverzeichnis, Datei und Projektziel gehalten (Art
inference@<target>,inference@positional); ein Wert ist ein Teilresults(semantic/types/inference_store: Graphknoten, Zusammenfassungen und lokale Eingaben pro Funktion, Ausdrucksfakten nach Syntaxposition). Ergebnisse, die eine Kompilierung mit mehr lebenden Funktionen behalten hat (zum Beispiel--print-types), bedienen eine ausführbare Datei, die weniger behält. --verbosegibt pro abgedecktem Modul[cache] hit|miss inference <file>aus (Gründe für Fehltreffer:no entry,inputs changed,damaged entry,results do not fitfür behaltene Ergebnisse, denen eine jetzt lebende Funktion fehlt);--print-stage-timesgibt die Phaseninference-cache(mitN of M covered modules reused) undinference-storeaus.
Pfade und Suche
- Der Projektpfad wird gegen das Aufrufverzeichnis aufgelöst; das lexikalische
übergeordnete Verzeichnis des Manifests ist die Basis für alle Manifestpfade
(auch über einen Symlink). Absolute Pfade bleiben absolut;
..ist erlaubt. Keine Shell-, Umgebungs- oder Tilde-Expansion. Für Windows-Pfade/oder literale TOML-Zeichenketten verwenden. - Literale relative Quellen versuchen zuerst die Basis, dann der Reihe nach
source_search_paths. Ein vorhandener, aber nicht lesbarer Kandidat ist ein Fehler. Suchpfade zählen keine Module auf und beeinflussen keine Includes. - Benennen die Quellen des Ziels ein Modul, das keine von ihnen definiert (ein
entfernter Aufruf,
fun M:F/A,applymit literalem Modul,-behaviouroder-import), wird zuerst Clauses Bibliothek und dann der Reihe nach die Suchpfade nachModule.erldurchsucht (ein installiertes OTP ersetzt nie ein Clause-Modul, und ein Modul, das Clause als fehlend verzeichnet, wird nie aus einem Suchpfad genommen: Auflösung); eine gefundene Datei kommt wie eine aufgeführte Quelle zum Ziel, und ihre eigenen Verweise werden auf dieselbe Weise aufgelöst. Eine aufgeführte Quelle mit dem Namen eines Clause-Moduls ersetzt dieses, mit einer Warnung. - Wildcards:
*und?innerhalb einer Komponente,**als ganze Komponente. Eckige und geschweifte Klammern, Negation und Maskierungen werden abgewiesen. Das Matching beachtet die Groß-/Kleinschreibung;?ist ein Unicode-Skalar eines gültigen UTF-8-Namens. - Versteckte Einträge werden eingeschlossen; gefundene Verzeichnis-Symlinks werden übersprungen (explizite Wurzeln dürfen Symlinks sein); Datei-Symlinks wird gefolgt.
- Reihenfolge: Einträge von
sourcesder Reihe nach, die Treffer jedes Musters nach UTF-8-Pfadbytes sortiert, dann jede Expansion vonsource_dirsauf dieselbe Weise sortiert. Fehlende Literale, Muster ohne Treffer und leere Ziele sind Fehler. - Die Deduplizierung innerhalb eines Ziels verwendet die Identität im Dateisystem (Symlinks, Hardlinks, Aliase durch Groß-/Kleinschreibung) und behält die erste Schreibweise. Dieselbe Datei in zwei Zielen wird zweimal kompiliert, da sich die Optionen unterscheiden können.
- Nur ausgewählte Ziele greifen auf das Dateisystem zu.
Verzeichnisindex
Lookups nach Namen sondieren nicht jedes Kandidatenverzeichnis. Ein Index pro
Aufruf von clau, von allen Zielen geteilt, hält die Eintragsnamen jedes
durchsuchten Verzeichnisses: einmal nicht rekursiv aufgelistet, wenn ein Lookup
es zum ersten Mal braucht, oder von den rekursiven Durchläufen verzeichnet, die
** in sources, source_dirs, source_search_paths, include_dirs und
transform_paths expandieren, sodass kein Verzeichnis zweimal aufgelistet
wird. Er beantwortet die Fehltreffer der Modulsuche (die Bibliothek, dann
source_search_paths), Transformationsquellen, literale sources, die über
source_search_paths gefunden werden, und die Include-Auflösung (das
Verzeichnis der einbindenden Datei, das Arbeitsverzeichnis,
Include-Verzeichnisse der Reihe nach, dann include_lib-Anwendungen); ein
Kandidat, den der Index hält, wird weiterhin wie zuvor geöffnet oder geprüft,
sodass sich Vorrang, ignore_dirs und Fehlerberichte nicht ändern.
Include-Namen mit Verzeichnisteilen (sub/x.hrl) werden in dem Verzeichnis
nachgeschlagen, das sie benennen; Namen mit ..-Schritten, absolute Namen,
relative Verzeichnisse und fehlgeschlagene Auflistungen werden wie zuvor
sondiert.
- Dateinamenschlüssel falten unter Windows und macOS, deren Volumes
Groß-/Kleinschreibung standardmäßig ignorieren, die ASCII-Schreibung, sodass
Foo.hrlweiterhinfoo.hrlfindet; anderswo sind Schlüssel exakt. Namen, die das Falten nicht exakt abgleichen kann (dort Nicht-ASCII-Namen sowie unter Windows Namen, die auf.oder ein Leerzeichen enden oder~enthalten, was 8.3-Kurznamen sein können), werden sondiert. - Der Index ist ein Schnappschuss eines Aufrufs: Dateien, die erscheinen,
während
clauläuft (Link-Staging, Ausgaben), sind nie Sucheingaben. --verboseendet mit[index] listed=N walked=N lookups=N misses=N probes=N(bei Bedarf aufgelistete Verzeichnisse, von Durchläufen verzeichnete Auflistungen, vom Index beantwortete Lookups und die Fehltreffer darunter, einer Sondierung überlassene Lookups).
Ignorierte Quellen
ignore_dirs und ignore_modules halten Quellen aus einem Ziel heraus, ohne
sie aus dem Baum zu entfernen, z. B. mitgelieferte Tests, Altcode oder Module,
die nur unter OTP eine Rolle spielen. Eine ignorierte Quelle wird
stillschweigend übersprungen: Sie wird nie gelesen, geparst, kompiliert oder
gelinkt, darf also sogar Syntaxfehler enthalten.
ignore_dirs: manifestrelative (oder absolute) Pfade mit den Wildcards vonsources. Eine Quelle wird ignoriert, wenn ihr Pfad oder ein Verzeichnis, das sie enthält, passt:src/legacy,deps/*/test,**/test(jedes Verzeichnistest),src/*_SUITE.erl. Das Matching ist lexikalisch; ein Muster muss auf nichts passen.ignore_modules: Modulnamen oder Namensmuster mit*und?, gegen den ganzen Namen gematcht (*_SUITE,legacy_*,prim_???). Eine Quelle namens<Module>.erl(oder.abstr) wird ignoriert, wenn ein Eintrag auf<Module>passt, und nach einem referenzierten Modul, das passt, wird nie gesucht. Das schließt Clauses Bibliotheksmodule ein.- Eine Quelle, die
sourcesliteral (ohne Wildcard) aufführt, wird nie ignoriert: Die Regeln wirken nicht auf sie, und der Build warntlisted in sources but matched by ignore_modules or ignore_dirs; ignoring it has no effect. Wildcard-Treffer undsource_dirswerden wie beschrieben ignoriert. - Beide gelten für
sources,source_dirs, literale Quellen, die übersource_search_pathsgefunden werden, die Modulsuche insource_search_pathsund der Bibliothek sowie die Suche nach Quellen von Parse-Transformationen. Eine Suche übergeht eine ignorierteModule.erlund sucht in späteren Verzeichnissen weiter. - Ein Modul ist ignoriert, wenn
ignore_moduleses benennt oder wenn keine Batch-Quelle es definiert und seine einzigen gefundenen Quellen ignoriert wurden (bei der Suche oder nach Dateiname aus den Quellen des Ziels übersprungen). Ein Modul, das eine kompilierte Quelle definiert, ist nie ignoriert. - Verweise auf ein ignoriertes Modul (
M:F(...),-import,fun M:F/A,apply(M, F, [...])mit literalen Namen) erreichen ein erzeugtes PlatzhaltermodulM, das jede so benannte Funktion exportiert; jede davon gibt{module_ignored, M}zurück, statt zu laufen. Eine Funktion, die der Batch nie literal benennt, bleibt für dynamische Aufrufeundef. Ein Typ eines ignorierten Moduls, der in einer Spec oder einem Typ benannt wird (helper:result()), warntattempt to import a type from a module ignored in project settings: helper:resultund wird alsterm()behandelt.-behaviour(M)mit einem ignoriertenMwarntbehaviour M undefined. --print-inputslistet jedes ignorierte referenzierte Modul nach den hinzugefügten Quellen alsignored module <name> (referenced at <file>:<line>)auf;--print-envgibt beide Schlüssel aus.
[targets.options]
source_search_paths = ["deps/**"]
ignore_dirs = ["deps/*/test", "src/legacy"]
ignore_modules = ["telemetry", "*_SUITE"]
Wirksame Optionen
| Einstellung | Kombination aus Manifest und CLI |
|---|---|
include_dirs | Manifestreihenfolge, nach CLI--I (letztes CLI--I wird zuerst durchsucht); ein Eintrag mit Wildcards (deps/*/include, apps/**/include) expandiert an Ort und Stelle zu den vorhandenen Verzeichnissen, auf die er passt, sortiert nach UTF-8-Pfadbytes (** passt auch auf keines, Verzeichnis-Symlinks werden übersprungen); ein Muster ohne Treffer ist ein Fehler |
source_search_paths | Ersatzwurzeln für literale Quellen und die Module, die das Ziel benennt, aber nicht aufführt; Muster expandieren wie bei include_dirs (ohne Treffer: unmatched source search path pattern) |
defines | Zuerst Manifest, dann CLI; Duplikate über beide hinweg sind Fehler |
applications | Manifest-Map; CLI-Einträge ersetzen gleichnamige |
| Feature-Listen | Manifesteinstellungen, dann geordnete CLI-Änderungen; CLI gewinnt |
output | Pro Ziel, nur ausführbare Ziele; CLI--o überschreibt für ein einzelnes ausgewähltes Ziel |
entry | Pro Ziel; CLI---entry überschreibt für ein einzelnes ausgewähltes Ziel |
cache_inference_in_dirs | Implizite OTP-Muster, dann die des Manifests, dann CLI---cache-inference-in-dirs (Inferenz-Cache) |
Build-Abhängigkeit
Compiler-internes toml++ 3.4.0 (MIT), nur Header, mit Ausnahmen, nicht
veröffentlichte Syntax deaktiviert. SHA-256 des Archivs
8517f65938a4faae9ccf8ebb36631a38c1cadfb5efa85d9a72e15b9e97d25155.
- macOS:
brew install tomlplusplus(Formel 3.4.0) wird erkannt. - Windows: CMake lädt das Release nach
thirdparty/herunter und verifiziert es. - Anderswo: installieren, nach
thirdparty/tomlplusplus-3.4.0entpacken oder-DCLAUSE_TOML_ROOT=<path>übergeben (hat Vorrang, deaktiviert den Download). - Reine Runtime-Builds suchen nicht danach.
Der Build-Cache verwendet das SQLite-3.54.0-Amalgamat
(gemeinfrei), nur in die Cache-Bibliothek des Compilers kompiliert
(clause_sqlite, ohne die Warnungsflags des Projekts). CMake lädt
https://www.sqlite.org/2026/sqlite-amalgamation-3540000.zip auf jedem Host
nach thirdparty/ herunter und verifiziert seine SHA-256
68e913b0fe8ec6b4e5f391c594a28872884e80d6cd042a1e50c957be46b5aa4d;
-DCLAUSE_SQLITE_ROOT=<directory with sqlite3.c and sqlite3.h> hat Vorrang und
deaktiviert den Download.
Grenzen
Manifestgröße 1 MiB; höchstens 1.024 Ziele und 100.000 TOML-Knoten. Jede Quellenexpansion erlaubt 100.000 besuchte Einträge, 128 Verzeichnisebenen und 16.000.000 Wildcard-Übergänge. Erschöpfung ist ein expliziter Fehler; dies sind Arbeitsgrenzen, keine I/O-Fristen.
Clause