Clause
← Toute la documentation

L'original anglais a changé depuis cette traduction ; certaines parties peuvent donc être obsolètes. Lire en anglais

Traduit de l'original anglais · 1e3a39c8-dirty · 2026-10-26

Projets TOML

Un manifeste de projet sélectionne des groupes ordonnés de sources Erlang et configure chaque cible indépendamment. Toutes les actions de la CLI acceptent les projets. Voir l'exemple fonctionnel.

Manifeste (schéma 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"

CLI et sélection des cibles

clau [options] <source.erl>...
clau [options] --project <path> [--target <name>]...
clau --new-project <filename>

Chaque cible sélectionnée est un lot de compilation séparé avec ses propres sessions de prétraitement. La planification (décodage, sélection, découverte, vérification des collisions de sorties) se termine avant le traitement de toute source ; l'exécution traite ensuite les cibles/fichiers dans l'ordre et mémorise les échecs. La sortie utile va sur stdout dans l'ordre cible/fichier sans bannières (sauf les lignes de cible de --print-inputs) ; le contexte et les diagnostics vont sur stderr. Une cible avec des diagnostics est nommée une fois, sur une ligne <manifest> [target <name>]: avant le premier ; les diagnostics eux-mêmes (error: file:line:col: message) ne portent aucun préfixe d'outil ni de cible.

./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

Exécutables

clau --project FILE [--target T]... (sans --emit, sans action de vérification/affichage) lie chaque cible sélectionnée qui a une clé output ou entry, ou que -o/--entry de la CLI désigne, en un exécutable par cible :

./build/debug/bin/clau --project tests/fixtures/linking/project/project.toml

Créer un projet

--new-project <filename> écrit un manifeste annoté et rien d'autre.

Répertoire de build

Chaque cible de projet a un répertoire de build où Clause garde ses propres fichiers temporaires et ses caches : le build_dir de la cible, relatif au manifeste, par défaut <manifest-dir>/build. --build-dir DIR (relatif à l'invocation) le remplace pour chaque cible sélectionnée. Les entrées positionnelles n'en ont pas, sauf si --build-dir est donné.

Caches de compilation

Les résultats qui valent la peine d'être gardés entre deux exécutions vivent sous <build_dir>/cache ; --no-cache ne les lit ni ne les écrit. Ce sont les réponses du chargeur de parse transforms et la liste des modules collants (sticky) de l'OTP hôte, si bien qu'une compilation à chaud ne démarre aucun erl hôte pour les modules dont les entrées de transformation n'ont pas changé, le résultat de compilation de chaque lot, et les résultats d'inférence des modules des répertoires configurés.

Cache d'inférence

Les modules de bibliothèque (les sources de stdlib, kernel, compiler et syntax_tools d'OTP trouvées via source_search_paths, la bibliothèque propre à Clause) changent rarement, si bien que les modules des répertoires configurés gardent leurs résultats d'inférence de types dans le cache de compilation, par module, et les compilations ultérieures les réutilisent au lieu de les inférer à nouveau.

Chemins et découverte

Index des répertoires

Les recherches par nom ne sondent pas chaque répertoire candidat. Un index par invocation de clau, partagé par toutes les cibles, garde les noms des entrées de chaque répertoire parcouru : listés une fois, de façon non récursive, quand une recherche en a besoin pour la première fois, ou enregistrés par les parcours récursifs qui développent ** dans sources, source_dirs, source_search_paths, include_dirs et transform_paths, si bien qu'aucun répertoire n'est listé deux fois. Il répond aux échecs de la recherche de modules (la bibliothèque, puis source_search_paths), aux sources de transformations, aux sources littérales trouvées via source_search_paths et à la résolution des inclusions (le répertoire du fichier qui inclut, le répertoire de travail, les répertoires d'inclusion dans l'ordre, puis les applications de include_lib) ; un candidat que l'index contient est toujours ouvert ou vérifié comme avant, si bien que la priorité, ignore_dirs et les rapports d'erreur ne changent pas. Les noms d'inclusion avec des parties de répertoire (sub/x.hrl) sont cherchés dans le répertoire qu'ils nomment ; les noms avec des étapes .., les noms absolus, les répertoires relatifs et les listages qui échouent sont sondés comme avant.

Sources ignorées

ignore_dirs et ignore_modules excluent des sources d'une cible sans les retirer de l'arborescence, par exemple des tests embarqués, du code ancien ou des modules qui ne comptent que sous OTP. Une source ignorée est sautée en silence : elle n'est jamais lue, analysée, compilée ni liée, elle peut donc même contenir des erreurs de syntaxe.

[targets.options]
source_search_paths = ["deps/**"]
ignore_dirs = ["deps/*/test", "src/legacy"]
ignore_modules = ["telemetry", "*_SUITE"]

Options effectives

RéglageCombinaison du manifeste et de la CLI
include_dirsOrdre du manifeste, après les -I de la CLI (le dernier -I de la CLI est cherché en premier) ; une entrée avec motifs génériques (deps/*/include, apps/**/include) se développe sur place en les répertoires existants auxquels elle correspond, triés par octets du chemin UTF-8 (** correspond aussi à zéro répertoire, les liens symboliques de répertoire sont sautés) ; un motif sans correspondance est une erreur
source_search_pathsRacines de repli pour les sources littérales et les modules que la cible nomme sans les lister ; les motifs se développent comme pour include_dirs (sans correspondance : unmatched source search path pattern)
definesManifeste d'abord, puis CLI ; les doublons entre les deux sont des erreurs
applicationsMap du manifeste ; les entrées de la CLI remplacent les noms correspondants
Listes de fonctionnalitésRéglages du manifeste, puis modifications ordonnées de la CLI ; la CLI l'emporte
outputPar cible, cibles exécutables uniquement ; -o de la CLI le remplace pour une seule cible sélectionnée
entryPar cible ; --entry de la CLI le remplace pour une seule cible sélectionnée
cache_inference_in_dirsMotifs OTP implicites, puis ceux du manifeste, puis --cache-inference-in-dirs de la CLI (cache d'inférence)

Dépendance de compilation

toml++ 3.4.0 (MIT), privé au compilateur, uniquement en en-têtes avec exceptions, syntaxe non publiée désactivée. SHA-256 de l'archive 8517f65938a4faae9ccf8ebb36631a38c1cadfb5efa85d9a72e15b9e97d25155.

Le cache de compilation utilise l'amalgamation SQLite 3.54.0 (domaine public), compilée uniquement dans la bibliothèque de cache du compilateur (clause_sqlite, sans les options d'avertissement du projet). CMake télécharge https://www.sqlite.org/2026/sqlite-amalgamation-3540000.zip dans thirdparty/ sur tous les hôtes et vérifie son SHA-256 68e913b0fe8ec6b4e5f391c594a28872884e80d6cd042a1e50c957be46b5aa4d ; -DCLAUSE_SQLITE_ROOT=<directory with sqlite3.c and sqlite3.h> est prioritaire et désactive le téléchargement.

Limites

Taille du manifeste 1 Mio ; au plus 1 024 cibles et 100 000 nœuds TOML. Chaque expansion de sources autorise 100 000 entrées visitées, 128 niveaux de répertoires et 16 000 000 transitions de motifs génériques. L'épuisement est une erreur explicite ; ce sont des bornes de travail, pas des délais d'E/S.