Référence linguistique
Cette page est la référence orientée utilisateur pour le seed Spécification linguistique. Les chapitres complets sur la grammaire et la sémantique opérationnelle se trouvent sous compiler/llvm. Pour connaître les limites actuelles et les demandes de fermeture, voir État actuel.
Codage source et noms
.sd les fichiers sont UTF-8. Les commentaires et le contenu des chaînes peuvent contenir du Unicode. string possède valide UTF-8 et str est un fichier emprunté en lecture seule UTF-8 vue pointeur plus longueur d'octet. La longueur du texte est mesurée en octets ; Les opérations scalaires, graphèmes, de normalisation et de paramètres régionaux Unicode appartiennent aux bibliothèques.
Les identifiants de source utilisent intentionnellement l'ASCII :
| Genre | Règle | Exemple |
|---|---|---|
| variable, fonction, champ, module | [a-z][a-z0-9_]* |
my_document |
| struct, ADT, union, trait, paramètre de type, variante | même boîtier de serpent inférieur | parse_result |
| constante | [A-Z][A-Z0-9_]* |
MAX_DOCUMENT_SIZE |
Le nom du langage formel est seed. Les types ne sont pas en majuscules. _ supprime une liaison ; un trait de soulignement de début peut marquer une liaison privée intentionnellement inutilisée.
Les commentaires de ligne commencent par //. Bloquer les commentaires /* ... */ nid. La grammaire propre n'utilise pas # commentaires.
Le chargeur de source valide l'intégralité du fichier comme UTF-8 avant le lexing et rejette les NUL intégrés ; les littéraux de chaîne décodés sont également validés.
Liaisons, constantes et mutation
let answer = 42
let mut count: usize = 0
let linear ticket = acquire_ticket()
const MAX_COUNT = 100
Le compilateur actuel accepte également les expressions scalaires typées, les tables de constantes fixes privées u32 telles que const TABLE: [4]u32 = [1 as u32, 2 as u32, 3 as u32, 4 as u32], le texte statique, les tuples et les structures. Les lectures indexées et de champ utilisent un stockage statique immuable avec des vérifications de limites ordinaires. Les valeurs agrégées publiques conservent leur représentation récursive dans les versions à source schéma-14.
Les liaisons sont immuables sauf si elles sont déclarées mut. L'affectation à une liaison, un champ ou un index via une liaison nécessite que cette liaison soit modifiable. linear crée une obligation unique.
Pour supprimer une valeur de retour, liez-la à un nom unique commençant par _: let _unused = expression. Les rejets nommés évitent l'erreur de « liaison active en double » qui apparaît clairement let _ = expression produit lorsqu'il est utilisé plusieurs fois dans la même portée. Un trait de soulignement au début de tout identifiant marque la liaison comme intentionnellement inutilisée.
Fonctions, méthodes et retours
fn add(left: i64, right: i64) -> i64 {
left + right
}
fn document.title_size() -> usize {
len(self.title)
}
unsafe fn read_register(address: *mmio mut i64) -> i64 {
raw_volatile_read<i64>(address, 0)
}
L'expression finale d'un bloc est sa valeur. ret expression revient tôt; le compilateur propre n'utilise pas return. Une déclaration de méthode inclut le type nominal avant le point et reçoit des informations implicites self; n'écris pas self dans sa liste de paramètres. fn type_name.drop() est un destructeur dévorant. @borrow sur une méthode ou un trait, la méthode donne self un emprunt lexical partagé. @mut à la place, nécessite un récepteur adressable mutable, détient un prêt exclusif pour l'appel et effectue des mutations vers self visible pour l'appelant. Les deux attributs s’excluent mutuellement.
Utilisation des déclarations publiques pub. Les déclarations étrangères utilisent des extern appeler convention/link métadonnées et il est dangereux de les appeler jusqu'à ce qu'ils soient encapsulés par une fonction sûre auditée. La classification des arguments Platform-C est spécifique à la cible : Windows x86-64 transmet indirectement des paramètres agrégés de plus de huit octets, donc str, les tranches et les structures C équivalentes interagissent avec MinGW/MSVC-style appelés.
Types de base
| Catégorie | Espèces |
|---|---|
| contrôle | void, never, bool |
| entier | i8, i16, i32, i64, u8, u16, u32, u64, isize, usize; byte pseudonymes u8 |
| flotter | f32, f64 |
| text/buffer | str, string, bytes, shared_bytes |
| formatage | format_args (éphémère) |
| aggregate/view | [n]t, []t, mut []t, tuples, nominal structs/ADTs/unions |
| échec | ?t, result<t,e>, alloc_error |
| appelable | non-propriétaire fn(t) -> u, échappant à box fn(t) -> u |
| bas niveau | pointeurs bruts plus user, kernel, physical, mmio, et dma espaces d'adressage |
| exactement une fois | linear t |
alloc_result<t> abrège result<t, alloc_error> sans introduire de nouvelle identité de type, représentation, règle de nettoyage ou ABI.
Hébergé main peut revenir result<i64, e>. ok(status) sort avec ce statut ; alloc_error utilise le diagnostic d'allocation fixe. Un autre e doit être une copie, ne pas avoir de destructeur et implémenter @borrow fn e.display() -> str; sa vue est écrite une fois avant le statut 1, après un nettoyage ordinaire.
@static_view extern fn ... est la déclaration FFI auditée pour un produit retourné str/slice dont le stockage est process/static vie. L'attribut est rejeté de manière ordinaire seed fonctionne et ne sécurise pas l'appel étranger.
Les attributs d'effet peuvent annoter les déclarations fn : @no_alloc, @allocates, @blocking, @panics, @io, @interrupt_safe. Les types de rappel qualifiés utilisent @no_runtime_effects fn(...) -> t pour déclarer un résumé complet des effets vides. Un unsafe struct peut déclarer @unsafe_send pour affirmer la capacité d'envoi, ou @repr("null_niche") pour activer l'optimisation du pointeur nul sur un seul champ de pointeur brut pour ?wrapper.
L’entier add/subtract/multiply s’enroule de manière déterministe à la largeur du type. Division par zéro, minimum signé divisé par -1, décalages non valides, conversions sécurisées non valides et piège d'indexation sécurisée ayant échoué. Les profils de version conservent ces règles. L'élargissement explicite des entiers utilise la signature de la source ; le rétrécissement conserve les bits faibles et les changements de signature de largeur égale préservent les bits. Integer/float et les conversions en largeur flottante suivent la conversion IEEE-754. La conversion en nombre entier nécessite unsafe et une entrée représentable par destination finie.
Les littéraux d'octets utilisent b'A' et sont de type u8. Un octet ASCII brut ou un échappement \\n/\\r/\\t/\\0/\\\\/\\'/\\xNN est accepté. Utilisez b'\\xFF' pour un octet non-ASCII ; seed n'a délibérément aucun type littéral de caractères dépendant des paramètres régionaux.
Structures, ADT et syndicats
struct document {
title: string
}
type parse_result {
parsed(document)
invalid(str)
}
union scalar_bits {
integer: u64
decimal: f64
}
Un littéral de structure est document.{ title: owned_title }. Un constructeur ADT est qualifié, par exemple parse_result.parsed(value), et sa charge utile est inspectée de manière exhaustive match. Un ADT sans charge utile remplace l'héritage enum mot-clé :
type color { red green blue }
L'union brute construction/access n'est pas sûre. Les alternatives sécurisées et étiquetées utilisent des ADT.
Options, résultats et propagation
fn find(enabled: bool) -> ?i64 {
if enabled { some(42) } else { none }
}
fn allocate_name(view: str) -> result<string, alloc_error> {
view.to_string()
}
some(value) et none de type attendu construisent une option. result.ok(value) et result.error(problem) construisent un résultat. ? consomme le conteneur, génère sa charge utile success/present ou renvoie l'échec correspondant de la fonction actuelle. La propagation des résultats peut modifier le type de réussite mais doit conserver le type d'erreur. Il n’effectue aucune allocation ou clonage implicite.
is_some/is_none et is_ok/is_error inspecter par emprunt partagé. unwrap_or(fallback) consomme le conteneur et nettoie la valeur possédée non sélectionnée exactement une fois. or_abort(), expect(message), et principal uniquement or_exit(status) sont des limites d'application explicites ; ils ne se cachent jamais dans l'ordinaire ? propagation.
? ne peut pas franchir une limite spawn alors que la tâche décrite ABI renvoie void.
Contrôler le flux et les modèles
Les formulaires de contrôle implémentés sont orientés expression if/elif/else, while, for, exhaustif match, blocs, break, continue, et ret. elif est l'orthographe requise ; else if n’est pas accepté. Les bras de match n'ont pas de virgules. Couverture de motifs bindings/discards, littéraux, tuples, structures et variantes ADT qualifiées ; les gardes conservent un scrutateur de mouvement uniquement jusqu'à ce que le bras sélectionné le transfère réellement.
for sur les plages, les tableaux fixes et les tranches diminue à un niveau sans allocation index/length boucle. for index, value in enumerate(items) ajoute un usize index sans itérateur de tas. Les éléments de déplacement uniquement nécessitent des indexing/ownership manipulation.
Texte, vues et conversions
- les littéraux ont un type emprunté statique
str; - le
stringdétenu emprunte automatiquement sous le nom destrlorsque prévu ; lenrenvoieusizepour le texte, les tampons, les tranches et les tableaux ;string.view()retoursstr;bytes.view()etshared_bytes.view()retour[]u8;bytes.mutable_view()renvoie unmut []u8exclusif avec la version complète longueur allouée ;bytes.zeroed(length)alloue de manière faillible les octetslengthinitialisés à zéro et sonmutable_view()couvre l'allocation complète ;byte_buffer.mutable_view()renvoie uniquement le préfixe initialisé (longueur 0 pour un nouveau tampon), pas la capacité — utilisezbytes.zeroedlorsqu'une cible d'écriture mutable de pleine longueur est nécessaire ;bytes.zeroed(length)nécessitei64et alloue de manière failliblelengthoctets initialisés à zéro ;- les tableaux fixes dérivent des vues partagées compatibles et les tableaux mutables dérivent vues exclusives;
str.slice(start, count)est vérifié et zéro copie ;- les tranches de texte vérifient également les limites des points de code UTF-8 ;
str.equal(other)etstr.find_ascii(delimiter, start)vérifiés sont sans allocation ;compiler/llvm/libs/textcrée un curseur partagé de source sécurisée à partir des plages d'octets renvoyées ;[]u8.slice(start, count)est une sous-vue vérifiée sans copie et[]u8.equal(other)compare la longueur et le contenu sans allocation ;str.to_string()/string.from(str)retourresult<string, alloc_error>;str.to_bytes()/bytes.from(str)retourresult<bytes, alloc_error>;bytes.to_shared()/shared_bytes.from(bytes)consomme le propriétaire des octets et renvoyerresult<shared_bytes, alloc_error>.bytes.into_prefix(length)consomme le propriétaire, vérifielengthpar rapport au longueur initialisée et renvoie la même allocation avec une longueur logique plus courte. Il n'attribue ni ne copie ; le propriétaire d'origine est déplacé.[n]t.mutable_view() -> mut []tdérive une vue mutable exclusive lorsque le le propriétaire du tableau est mutable.
L'interpolation typée phase-1/2 est sans allocation, sauf si elle est explicitement matérialisée :
write_stdout_format(f"name={name} count={count} braces={{ok}}\n")
let message = f"count={count}".to_string()?
Les expressions sont évaluées une fois de gauche à droite. Les valeurs prises en charge sont str, emprunté string, bool, et des entiers intégrés. L'éphémère format_args le résultat doit être transmis directement ou consommé par .to_string()?; il ne peut pas être attribué avec let, restitués, capturés ou stockés. Integer/text/bool Les spécifications de largeur, de remplissage, d'alignement et de base entière sont implémentées. Utilisation de types personnalisés trait display { @borrow fn display() -> str } avec expédition statique directe. Les flotteurs prennent en charge la sortie générale par défaut plus f/F, e/E, et g/G avec une précision jusqu'à 18. Personnalisé :? le formatage utilise l'analogue emprunté debug.debug() -> str trait.
Génériques et traits
Les paramètres génériques utilisent la casse du serpent inférieure. Les définitions sont vérifiées par rapport à leurs limites, puis les instances concrètes accessibles sont monomorphisées. La répartition des traits est statique et directe : il n'y a pas de tables virtuelles, de boxe, d'allocation ou de clone implicites. L'exhaustivité de l'implément, les signatures, la cohérence et les règles orphelines sont vérifiées. Modèles génériques publics, instances courantes, éphémères format_args les paramètres, la représentation nominale de niche nulle, les récepteurs mutables exclusifs, les rappels qualifiés et les signatures appelables en boîte persistent dans le schéma-16 actuel .sdi. Les instances de méthode matérialisées sont exportées uniquement par une interface qui possède également la définition de méthode générique. Un wrapper autour d'un type générique importé enregistre donc son contrat public sans spécialisation orpheline ; un consommateur élidé par la source obtient le modèle de méthode à partir de l'interface de dépendance du wrapper et y matérialise l'instance concrète.
inline fn demande une inlining limitée. Un pub inline fn publie son corps vérifié et son hachage de corps déterministe dans le schéma 13 .sdi tout en conservant un symbole de secours exporté. Les déclarations en ligne ont un budget source de 4 096 octets ; un changement de corps invalide les artefacts dépendants. Les partitions de tranches mutables utilisent view.split_at_mut(index) et les modèles de tuples peuvent déclarer des liaisons mutables comme (mut left, mut right). Le partage vérifie index <= len, n'attribue rien et maintient le propriétaire commun exclusivement prêté jusqu'au décès des deux frères et sœurs.
Fermetures et rappels
fn apply(values: [3]i64, callback: fn(i64) -> i64) -> i64 {
let mut total = 0
for value in values {
total = total + callback(value)
}
total
}
let base = 40
let total = apply([1, 2, 3], |value: i64| base + value)
let retained = (box |value: i64| base + value).or_abort()
|...| et la position de préfixe || créent des appels anonymes. Les types de paramètres peuvent être omis lorsqu’un fn(...) -> t attendu les fournit. Une fermeture simple utilise le stockage de capture de pile, n'alloue rien et ne peut pas échapper à son propriétaire lexical. Copie de capture capable de copier ; les captures possédées bougent ; les captures sont immuables. Les captures empruntées, mutables, liées à une région, déjà déplacées et autres captures dangereuses à stocker sont rejetées.
box |...| est la forme d'échappement explicite et renvoie result<box fn(...) -> t, alloc_error>. Le propriétaire peut être stocké ou restitué, mais il est uniquement déplacé, non clonable et non envoyable. Drop détruit ses captures exactement une fois et libère son allocation. L'attribution des régions reste lexicale. Il n'y a pas de conversion implicite entre les fermetures en pile et en boîte.
Les rappels Seed fn(...) -> t utilisent un descripteur code/environment à un pointeur. Les pointeurs de fonction C/platform restent fins et acceptent uniquement les fonctions nommées. Les effets de fermeture sont déduits du corps et vérifiés par rapport à des contrats de rappel qualifiés tels que @no_runtime_effects fn() -> void. Les fermetures récursives ne sont pas prises en charge.
Résumé de la propriété
- copie des scalaires et des agrégats en copie uniquement ;
- les ressources se déplacent et rendent le lieu source indisponible ;
.clone()est explicite et capability/effect vérifié ;- les vues empruntées portent la provenance sans syntaxe à vie ;
- le nettoyage structuré s'exécute exactement une fois sur les sorties structurées normales ;
- panic/trap/abort ne déroule ni n'exécute de destructeurs ;
linear tdoit être consommé une seule fois ;- la propriété partielle est suivie à travers les champs, les champs imbriqués, le tableau connu
index, charges utiles ADT actives, unions, génériques, canaux, valeurs de fonction et
.sdi; Les mouvements de ressources à index dynamique restent rejetés.
Voir Ownership pour le modèle opérationnel.
Régions, tâches et bibliothèques
region(capacity) { body } installe un allocateur de bosses lexicales vérifiées. Les valeurs, vues ou pointeurs liés à la région ne peuvent pas échapper. Les tâches structurées capturées dans une région se rejoignent avant que son stockage de sauvegarde ne soit libéré.
spawn { body } est structuré : chaque arête quittant la portée lexicale propriétaire attend son groupe de tâches avant d'être nettoyée. La capture est une copie ou un déplacement par capacité. Les canaux, les jointures tapées, les événements, l'annulation et la synchronisation sont fournis par l'ordinaire. compiler/llvm/libs/task paquet. La grammaire propre n'a pas de chan<t>, send, recv, ou spawn détaché.
Substrat dangereux
raw_try_alloc<t>, raw_null<t>, raw_is_null<t>, raw_read<t>, raw_write<t>, raw_free<t>, raw_slice<t>, atomes, accès volatile, clôtures, conversions d'espace d'adressage, assemblage brut, FFI, appels système et unions brutes nécessitent unsafe. Les applications normales doivent consommer des wrappers sécurisés provenant des bibliothèques.
Lanceur de référentiel
./seed/seed check [--lib] [path|file.sd]
./seed/seed build [path] [-o output] [compiler flags]
./seed/seed run [path] [-- program arguments]
./seed/seed test [path] [compiler flags]
./seed/seed format [--check] [file.sd]
./seed/seed new path [--name package_name]
./seed/seed pkg resolve|add|update|prune ...
./seed/seed install [path|package] [--profile release] [--system] [--prefix path] [--dry-run]
./seed/seed uninstall package [--system] [--prefix path] [--dry-run]
./seed/seed doc [path] [--output file]
./seed/seed lint [--json] [path]
./seed/seed lsp
./seed/seed publish --check [path]
./seed/seed mobile android <setup|build|stage|check|package|run|doctor>
check est une vérification directe à la source. Il résout les importations relatives source/interface et les dépendances du manifeste local path ; il ne compile pas d'abord un package de référentiel nu manquant. Utilisez build ou run lors de la validation de l'intégration de packages qui dépend du transfert automatique de la bibliothèque principale.
build effectue une compilation incrémentielle avec résolution automatique des dépendances. Importations de packages nus (par ex. use "vec") sont mis en scène dans un endroit isolé target/profile magasin. Une deuxième version réutilise la correspondance .sdi/Artefacts natifs. test transmet les indicateurs de fin du compilateur, y compris les répétitions --link-object et --link-library entrées, à chaque binaire de test. Ceci est requis pour les tests de bibliothèque dont la surface Seed sécurisée est soutenue par un natif externe. ABI.
install compile le package en mode release et l'installe à l'échelle du système : exécutables sur ~/.local/bin (ou /usr/local/bin avec --system), générations de dépendance à ~/.local/lib/seed/generations/, et des interfaces avec ~/.local/share/seed/interfaces/. Utiliser --profile debug pour les versions de débogage et --prefix /custom/path pour les emplacements d'installation personnalisés.
uninstall supprime un package précédemment installé et ses générations de dépendances. install et uninstall prennent en charge --dry-run pour l'aperçu. L'enregistrement transactionnel du package installé comprend la cible, le profil, l'identité de génération de dépendance, la somme de contrôle du compilateur, la somme de contrôle de l'artefact installé, la somme de contrôle source et la somme de contrôle du verrouillage afin qu'une application déployée puisse être retracée jusqu'à ses entrées de construction exactes.
La publication à distance est distincte ; seed publish --check valide l'intégrité du package et du verrou localement sans exécuter de scripts sans restriction. Les packages compilés utilisent la qualification cible .sdi plus --install-library/--install-interface. Les monorepos locaux peuvent conserver plusieurs packages versionnés indépendamment connectés par rapport path dépendances. Les sommes de contrôle de leurs arbres entraînent des reconstructions ; le développement local ordinaire ne nécessite pas de référentiel, de balise ou de publication Git pour chaque bibliothèque.
Le lanceur lit [build].profile = "debug" | "release" | "release-small"; héritage release = true cartes à release. Un explicite CLI le profil remplace le manifeste. seed install par défaut, il est publié quel que soit le manifeste, sauf si --profile est explicite. Les applications sont par défaut src/main.sd; un parent sûr facultatif [package].entry sélectionne une autre source dans le package. Les importations de packages nus sont d'abord résolues en fonction des artefacts installés correspondants ; sinon, ils sont compilés avec le profil d'application dans un fichier isolé. target/profile magasin. Les builds hébergés les lient dynamiquement par défaut. Une deuxième version réutilise la correspondance .sdi/artefacts indigènes ; les modifications apportées aux bibliothèques dynamiques privées ne reconstruisent pas les consommateurs, tandis que les modifications apportées aux bibliothèques dynamiques privées ne reconstruisent pas les consommateurs, tandis que les modifications apportées aux bibliothèques dynamiques privées ne reconstruisent pas les consommateurs, tandis .sdi ou ABI les changements le font.
L'installation de l'utilisateur place les exécutables dans ~/.local/bin, générations de dépendance immuables dans ~/.local/lib/seed, et les miroirs d'interface versionnés sous ~/.local/share/seed/interfaces. --system utilise la portée du système de plateforme (/usr/local sous Unix); --prefix remplace la racine. L'installation et la suppression sont enregistrées par la propriété et atomiques, et aucune commande ne modifie silencieusement les fichiers de démarrage du shell ou les variables d'environnement du chargeur.
Opérateurs
Priorité binaire du plus élevé au plus bas :
- multiplicatif (
*,/,%) - additif (
+,-) - changements de vitesse (
<<,>>) - comparaisons (
<,<=,>,>=) - égalité (
==,!=) - ET au niveau du bit (
&), XOR (^), OU (|) - ET logique (
&&) - OU logique (
||)
&& et || court-circuit : a && b évalue b seulement quand a est true, et a || b évalue b seulement quand a est false. Les deux opérandes doivent être bool et le résultat est bool. Le court-circuit s'applique également au pliage constant, donc false && expensive() et true || expensive() sont des expressions constantes valides même lorsque expensive() n'est pas constante.
Compilateur de nettoyage direct
L'exécutable est compiler/llvm/build/seed. Sa liste de drapeaux faisant autorité est seed --help.
# Source processing
seed --check source.sd
seed --format|--format-check|--format-write source.sd
# Code generation
seed --emit-llvm out.ll source.sd
seed --emit-object out.o source.sd
seed --emit-binary out source.sd
seed --emit-shared library.so source.sd
seed --emit-static-library library.a source.sd
seed --emit-raw out.bin source.sd
seed --run source.sd -- arguments
# Interface inspection
seed --interface-print file.sdi
seed --interface-hash file.sdi
seed --emit-interface out.sdi source.sd
# Library management
seed --install-library artifact --install-interface file.sdi --package name [--seed-home path]
# Debug dumps
seed --lex source.sd
seed --ast-print source.sd
seed --types-print source.sd
seed --symbols-print source.sd
seed --hir-print source.sd
seed --safety-print source.sd
seed --mir-print source.sd
seed --layout-print source.sd
seed --abi-print source.sd
seed --low-mir-print source.sd
seed --llvm-print source.sd
# Build options
seed --release source.sd
seed --release-small source.sd
seed --thin-lto source.sd
seed --pgo-generate dir source.sd
seed --pgo-use profile source.sd
seed --profile-print source.sd
seed --target target source.sd
seed --runtime linux-native|linux-libc source.sd
seed --runtime-profile profile source.sd
seed --runtime-feature feature source.sd
seed --static source.sd
seed --static=all source.sd
seed --sysroot path source.sd
seed --soname name source.sd
seed --entry symbol source.sd
seed --linker-script path source.sd
seed --code-model model source.sd
seed --relocation-model model source.sd
seed --no-red-zone source.sd
seed --link-object file.o source.sd
seed --link-library lib.so|lib.a|package source.sd
seed --cache-dir path source.sd
seed --seed-home path source.sd
seed --package name source.sd
# Diagnostics
seed --diagnostics human|json source.sd
seed --version
seed --help
Debug/inspection les modes incluent le jeton, l'AST, les types, les symboles, le HIR, la sécurité, le MIR, la disposition, ABI, faible MIR, et LLVM impression. Target/runtime les options incluent --target, --runtime-profile, --runtime-feature, --runtime, --sysroot, entry/linker-script commandes et séparer object/library lien.
--release utilise seed-safe-o2-v1; --release-small utilise seed-safe-oz-v1. Les deux sont en sécurité. ThinLTO et PGO sont des options explicites réservées à la version ; la liaison statique est indépendante. Il n'y a pas de fonctionnement --unchecked ou --fast-unsafe profil.
Statut cible
La prise en charge des objets et la prise en charge hébergée de bout en bout sont des revendications distinctes. Linux x86-64/AArch64 sont les chemins hébergés fermés. Autonome x86-64/AArch64/RISC-V64 avoir des preuves de démarrage à leurs niveaux déclarés. Windows x86-64 a PE/runtime/DLL/ task/network preuve sous le vin requis. macOS x86-64 et arm64 ont un SDK explicite executable/dylib/static liaison, exécution et planification de pthread. Intel natif x86-64 l'exécution demeure; arm64 est uniquement à liaison croisée. Voir compiler/llvm/tests/GATE14_TARGET_MATRIX.tsv.
Sur un Mac Intel, exécutez SEED_MACOS_RUNNER_POLICY=required make -C seed/compiler/llvm gate14-macos-x86_64-test. Le script découvre le SDK avec xcrun et utilise le ld d'Apple, sauf s'il est explicitement remplacé.