Ce document est la reference complete du projet. Il couvre la CLI, les formats, la syntaxe MUF, les regles de resolution, les logs et les conventions en usage dans le code.
Steel est la couche de configuration declarative du build. Il:
Le pipeline est en deux phases: 1) Configuration (steel / build steelconf) -> produit steelconfig.mff. 2) Execution (run) -> interprete steelconf pour executer des outils.
Cette separation garantit la reproductibilite: la configuration figee peut etre relue, versionnee et comparee.
.exec.steel / build steelconf.Steel expose des backends via la crate SteelLib. Exemple d import OCaml:
use SteelLib::ocaml::{OcamlArgs, OcamlDriver, OcamlSpec};
Backends disponibles (liste rapide):
gcc (gcc/clang)ocaml (ocamlc/ocamlopt)cpython (CPython/PyPy/Nuitka)ghc-haskell (GHC)steelconf: fichier de configuration cherche par steel / build steelconf.steelconf: fichier MUF attendu par steel run si --file n est pas fourni (alias: steelconf).Steelfile a ete renomme en steelconf. Renommer vos fichiers existants si besoin.steelconfig.mff: artefact resolu emis par steel / build steelconf (nom par defaut)..steel-cache/: cache de configuration (check, stats, etc.).target/steel_run_<timestamp>.mff: log d execution du runner (par defaut).build/: chemins de build resolus (phase configuration).dist/: sorties pour distribution.target/: sorties du runner et logs.Liste rapide (toutes les commandes):
steel (alias: build steelconf) — ex: steelbuild steelconf (alias: resolve, check, print) — ex: steel build steelconfrun — ex: steel run --file MinConfig.muf --alldoctor — ex: steel doctor --jsoncache — ex: steel cache statusgraph — ex: steel graph --dotfmt — ex: steel fmt --file steelconf --checkversion — ex: steel --versionhelp — ex: steel helpCes flags apparaissent dans plusieurs commandes; ils sont censes rester stables.
--profile <name>debug, release).debug (ou MUFFIN_PROFILE si defini).run.Exemples:
steel run --profile debug --all
--log <path> (et --log-mode)run.target/steel_run_<timestamp>.mff.--log-mode accepte append ou truncate.run.Exemples:
steel run --log target/run.mff --log-mode truncate --all
steel help / steel -h / steel --helpsteel version / steel -V / steel --versionCommande principale (alias steel build steelconf):
steel
Semantique:
steelconfig.mff,steelconf.Aliases:
steel resolve : alias de build steelconf.steel check : emit dans .steel-cache/check/ puis supprime (best effort).steel print : emit + print.steel run [--root <path>] [--file <path>] [--profile <name>]
[--toolchain <path>] [--bake <name>] [--all]
[--print] [--no-cache]
[--log <path>] [--log-mode <append|truncate>] [-v]
Semantique:
steelconf),steel doctor [--root <path>] [--json] [-v]
steel cache <status|clear> [--root <path>] [--json] [-v]
status: taille/nb fichiers de .steel-cache.clear: suppression du cache.steel graph [--root <path>] [--text|--dot] [-v]
steel fmt [--file <path>] [--check] [-v]
0: succes.1: erreur d execution / configuration.2: erreur d usage ou de configuration (runner).3: erreur d execution d outil.4: erreur I/O.steel utilise le repertoire courant.Ordre:
1) steelconf dans la racine.
2) scan DFS deterministe sous la racine, avec tri lexicographique.
Regles de scan (fixes):
.git, .hg, .svn, target, node_modules, dist, build, .steel, .steel-cache.steelconf (workspace + blocs profile/target).CC, CXX, AR, LD, RUSTC.toolchain.python -> PYTHONtoolchain.ocaml -> OCAMLPATHtoolchain.ghc -> GHC_PACKAGE_PATHMUFFIN_TOOLCHAIN_PYTHON, MUFFIN_TOOLCHAIN_OCAML, MUFFIN_TOOLCHAIN_GHCMUFFIN_FINGERPRINT_TIME=1 ajoute un sel temporel (non deterministe).mff 1
project
root "/path/to/root"
steelfile "/path/to/steelconf"
.end
select
profile "debug"
target "x86_64-unknown-linux-gnu"
.end
paths
build "/path/to/root/build"
dist "/path/to/root/dist"
cache "/path/to/root/.steel-cache"
.end
toolchain
cc "gcc"
cxx "g++"
ar "ar"
ld "ld"
rustc "rustc"
python "python3"
ocaml "/opt/ocaml/lib"
ghc "/opt/ghc/pkgdb"
versions
cc "gcc (GCC) 13.2.0"
.end
.end
vars
set "steel.profile" "debug"
set "steel.target" "x86_64-unknown-linux-gnu"
set "steel.offline" "false"
set "steel.root" "/path/to/root"
set "steel.file" "/path/to/steelconf"
.end
fingerprint
value "fnv1a64:..."
.end
Notes:
.end ferme les sections.steel.graph.json/1 (export DAG) : schemas/steel.graph.json.schema.jsonsteel.decompile.report (mff report JSON) : schemas/steel.decompile.report.schema.jsonsteel.fingerprints.json/1 (sidecar fingerprints) : schemas/steel.fingerprints.json.schema.jsonassets/grammar/steel.ebnf#!), BOM optionnel.!muf 4.[tag name?] ... ....op arg1 arg2 ....;; ....[A-Za-z_][A-Za-z0-9_]*"..." avec echappements \n \r \t \0 \xNN \uNNNN.+42, -7, 3.14, 1.2e3.~name/name/....Block = WS0 , BlockHead , WS0 , NL , { BlockItem } , WS0 , BlockClose , WS0 , NL ;
BlockHead = "[" , WS0 , Tag , [ WS1 , Name ] , WS0 , "]" ;
BlockClose = ".." ;
Directive = WS0 , "." , Op , { WS1 , Atom } , WS0 , NL ;
Atom = Ref | String | Number | Name ;
Le runner actuel supporte un sous-ensemble volontairement limite.
.set <key> <value>profile, target_dir)..set <key> <value>.exec <path-or-name>gcc)..make <id> <kind> <pattern>
kind supporte: glob, cglob, file (alias: list)..make <id> <path> == .make <id> file <path>..make..needs <bake>: dependance explicite..output <port> <path>: output final.[run <tool>] obligatoire.Directives supportees:
.takes <port> as "@args"
@args est supporte..emits <port> as "-o"
.set <flag> <value>
1|true|yes -> ajoute le flag seul.0|false|no -> ignore.flag puis value..include <path> -> -I <path>.define <K> [<V>] -> -DK ou -DK=V.libdir <path> -> -L <path>.lib <name> -> -l <name>${key}Exemple:
.set "-O${opt}" 1
.set "-g" "${debug}"
Priorite:
1) --all -> tous les bakes dans l ordre du fichier.
2) --bake <name> (repete).
3) bake app si present.
4) premier bake dans le fichier.
.needs cree des dependances entre bakes.--no-cache force l execution.target/steel_run_<timestamp>.mff.--log <path> surcharge l emplacement.--log-mode truncate recree le fichier avant execution.[log meta]
format "steel-runlog-1"
tool "steel"
version "steel <version>"
ts_iso "<RFC3339>"
..
[bake log "<name>"]
output "<path>"
sources_count <n>
source "<path>" ;; repete
[run log]
ts <epoch>
ts_iso "<RFC3339>"
duration_ms <n>
cmd "gcc ..."
cwd "/path/to/root"
status <code>
ok true|false
stdout_bytes <n>
stderr_bytes <n>
stdout "..." ;; optionnel
stderr "..." ;; optionnel
..
runs <n>
duration_ms <n>
..
[run summary]
ts_iso "<RFC3339>"
..
glob / cglob sont resolus avec un moteur de glob interne.!muf 4
[workspace]
.set name "steel-example-c"
.set root "."
.set target_dir "target"
.set profile "debug"
..
[profile debug]
.set opt 0
.set debug 1
.set ndebug 0
..
[tool gcc]
.exec "gcc"
..
[bake app]
.make c_src cglob "**/*.c"
[run gcc]
.takes c_src as "@args"
.set "-std=c17" 1
.set "-O${opt}" 1
.set "-g" "${debug}"
.set "-DNDEBUG" "${ndebug}"
.set "-Wall" 1
.set "-Wextra" 1
.emits exe as "-o"
..
.output exe "target/out/app"
..
# configuration
steel
steel print
# execution
steel run --root . --file steelconf --bake app
steel run --root . --all --print
!muf 4
[workspace]
.set name "demo-c"
.set root "."
.set target_dir "target"
.set profile "debug"
..
[tool gcc]
.exec "gcc"
..
[bake app_c]
.make c_src cglob "src/**/*.c"
[run gcc]
.takes c_src as "@args"
.set "-std=c17" 1
.set "-O0" 1
.set "-g" 1
.emits exe as "-o"
..
.output exe "target/bin/app_c"
..
!muf 4
[workspace]
.set name "demo-c-lib"
.set root "."
.set target_dir "target"
.set profile "release"
..
[tool gcc]
.exec "gcc"
..
[tool ar]
.exec "ar"
..
[bake lib_c]
.make c_src cglob "lib/**/*.c"
[run gcc]
.takes c_src as "@args"
.set "-std=c17" 1
.set "-O2" 1
.set "-c" 1
.emits obj as "-o"
..
.output obj "target/obj/lib_c.o"
..
[bake app_c]
.make main file "src/main.c"
[run gcc]
.takes main as "@args"
.takes "target/obj/lib_c.o" as "@args"
.set "-O2" 1
.emits exe as "-o"
..
.output exe "target/bin/app_c"
..
!muf 4
[workspace]
.set name "demo-cpp"
.set root "."
.set target_dir "target"
.set profile "debug"
..
[tool gpp]
.exec "g++"
..
[bake app_cpp]
.make cpp_src cglob "src/**/*.cpp"
[run gpp]
.takes cpp_src as "@args"
.set "-std=c++20" 1
.set "-O0" 1
.set "-g" 1
.emits exe as "-o"
..
.output exe "target/bin/app_cpp"
..
!muf 4
[workspace]
.set name "demo-cpp-inc"
.set root "."
.set target_dir "target"
.set profile "release"
..
[tool gpp]
.exec "g++"
..
[bake app_cpp]
.make cpp_src cglob "src/**/*.cpp"
[run gpp]
.takes cpp_src as "@args"
.set "-std=c++20" 1
.set "-O2" 1
.set "-Iinclude" 1
.set "-lpthread" 1
.emits exe as "-o"
..
.output exe "target/bin/app_cpp"
..
!muf 4
[workspace]
.set name "demo-ocaml"
.set root "."
.set target_dir "target"
.set profile "release"
..
[tool ocamlopt]
.exec "ocamlopt"
..
[bake app_ml]
.make ml_src cglob "src/**/*.ml"
[run ocamlopt]
.takes ml_src as "@args"
.set "-O2" 1
.emits exe as "-o"
..
.output exe "target/bin/app_ml"
..
!muf 4
[workspace]
.set name "demo-ocaml-byte"
.set root "."
.set target_dir "target"
.set profile "debug"
..
[tool ocamlc]
.exec "ocamlc"
..
[bake app_ml_byte]
.make ml_src cglob "src/**/*.ml"
[run ocamlc]
.takes ml_src as "@args"
.set "-g" 1
.emits exe as "-o"
..
.output exe "target/bin/app_ml.byte"
..
!muf 4
[workspace]
.set name "demo-multi-bakes"
.set root "."
.set target_dir "target"
.set profile "release"
..
[tool gcc]
.exec "gcc"
..
[bake lib_core]
.make c_src cglob "lib/**/*.c"
[run gcc]
.takes c_src as "@args"
.set "-std=c17" 1
.set "-O2" 1
.set "-c" 1
.emits obj as "-o"
..
.output obj "target/obj/lib_core.o"
..
[bake app]
.make main file "src/main.c"
[run gcc]
.takes main as "@args"
.takes "target/obj/lib_core.o" as "@args"
.set "-O2" 1
.emits exe as "-o"
..
.output exe "target/bin/app"
..
!muf 4
[workspace]
.set name "demo-tests-c"
.set root "."
.set target_dir "target"
.set profile "debug"
..
[tool gcc]
.exec "gcc"
..
[bake tests_c]
.make test_src cglob "tests/**/*.c"
[run gcc]
.takes test_src as "@args"
.set "-std=c17" 1
.set "-g" 1
.set "-O0" 1
.emits exe as "-o"
..
.output exe "target/bin/tests_c"
..
!muf 4
[workspace]
.set name "demo-shared-c"
.set root "."
.set target_dir "target"
.set profile "release"
..
[tool gcc]
.exec "gcc"
..
[bake lib_shared]
.make c_src cglob "src/**/*.c"
[run gcc]
.takes c_src as "@args"
.set "-fPIC" 1
.set "-shared" 1
.set "-O2" 1
.emits so as "-o"
..
.output so "target/lib/libdemo.so"
..
!muf 4
[workspace]
.set name "demo-shared-c-win"
.set root "."
.set target_dir "target"
.set profile "release"
..
[tool gcc]
.exec "gcc"
..
[bake lib_shared_win]
.make c_src cglob "src/**/*.c"
[run gcc]
.takes c_src as "@args"
.set "-shared" 1
.set "-O2" 1
.emits dll as "-o"
..
.output dll "target\\lib\\demo.dll"
..
!muf 4
[workspace]
.set name "demo-shared-c-macos"
.set root "."
.set target_dir "target"
.set profile "release"
..
[tool clang]
.exec "clang"
..
[bake lib_shared_macos]
.make c_src cglob "src/**/*.c"
[run clang]
.takes c_src as "@args"
.set "-shared" 1
.set "-O2" 1
.emits dylib as "-o"
..
.output dylib "target/lib/libdemo.dylib"
..
!muf 4
[workspace]
.set name "demo-shared-cpp"
.set root "."
.set target_dir "target"
.set profile "release"
..
[tool gpp]
.exec "g++"
..
[bake lib_shared_cpp]
.make cpp_src cglob "src/**/*.cpp"
[run gpp]
.takes cpp_src as "@args"
.set "-fPIC" 1
.set "-shared" 1
.set "-std=c++20" 1
.set "-O2" 1
.emits so as "-o"
..
.output so "target/lib/libdemo_cpp.so"
..
!muf 4
[workspace]
.set name "demo-shared-cpp-win"
.set root "."
.set target_dir "target"
.set profile "release"
..
[tool gpp]
.exec "g++"
..
[bake lib_shared_cpp_win]
.make cpp_src cglob "src/**/*.cpp"
[run gpp]
.takes cpp_src as "@args"
.set "-shared" 1
.set "-std=c++20" 1
.set "-O2" 1
.emits dll as "-o"
..
.output dll "target\\lib\\demo_cpp.dll"
..
!muf 4
[workspace]
.set name "demo-shared-cpp-macos"
.set root "."
.set target_dir "target"
.set profile "release"
..
[tool clangpp]
.exec "clang++"
..
[bake lib_shared_cpp_macos]
.make cpp_src cglob "src/**/*.cpp"
[run clangpp]
.takes cpp_src as "@args"
.set "-shared" 1
.set "-std=c++20" 1
.set "-O2" 1
.emits dylib as "-o"
..
.output dylib "target/lib/libdemo_cpp.dylib"
..
!muf 4
[workspace]
.set name "demo-ocaml-lib"
.set root "."
.set target_dir "target"
.set profile "release"
..
[tool ocamlopt]
.exec "ocamlopt"
..
[bake lib_ml]
.make ml_src cglob "lib/**/*.ml"
[run ocamlopt]
.takes ml_src as "@args"
.set "-a" 1
.emits lib as "-o"
..
.output lib "target/lib/libml.cmxa"
..
[bake app_ml]
.make ml_src cglob "src/**/*.ml"
[run ocamlopt]
.takes ml_src as "@args"
.takes "target/lib/libml.cmxa" as "@args"
.set "-O2" 1
.emits exe as "-o"
..
.output exe "target/bin/app_ml"
..
!muf 4
[workspace]
.set name "demo-cpp-tests"
.set root "."
.set target_dir "target"
.set profile "debug"
..
[tool gpp]
.exec "g++"
..
[tool sh]
.exec "sh"
..
[bake tests_cpp]
.make test_src cglob "tests/**/*.cpp"
[run gpp]
.takes test_src as "@args"
.set "-std=c++20" 1
.set "-O0" 1
.set "-g" 1
.emits exe as "-o"
..
.output exe "target/bin/tests_cpp"
..
[bake run_tests]
[run sh]
.set "-c" 1
.set "./target/bin/tests_cpp" 1
..
..
!muf 4
[workspace]
.set name "demo-cpp-tests-win"
.set root "."
.set target_dir "target"
.set profile "debug"
..
[tool gpp]
.exec "g++"
..
[tool pwsh]
.exec "pwsh"
..
[bake tests_cpp]
.make test_src cglob "tests/**/*.cpp"
[run gpp]
.takes test_src as "@args"
.set "-std=c++20" 1
.set "-O0" 1
.set "-g" 1
.emits exe as "-o"
..
.output exe "target\\bin\\tests_cpp.exe"
..
[bake run_tests]
[run pwsh]
.set "-NoProfile" 1
.set "-ExecutionPolicy" 1
.set "Bypass" 1
.set "-Command" 1
.set ".\\target\\bin\\tests_cpp.exe" 1
..
..
!muf 4
[workspace]
.set name "demo-cpp-tests-win-profile"
.set root "."
.set target_dir "target"
.set profile "debug"
..
[profile debug]
.set run_tests 1
..
[profile release]
.set run_tests 0
..
[tool gpp]
.exec "g++"
..
[tool pwsh]
.exec "pwsh"
..
[bake tests_cpp]
.make test_src cglob "tests/**/*.cpp"
[run gpp]
.takes test_src as "@args"
.set "-std=c++20" 1
.set "-O0" 1
.set "-g" 1
.emits exe as "-o"
..
.output exe "target\\bin\\tests_cpp.exe"
..
[bake run_tests]
[run pwsh]
.set "-NoProfile" 1
.set "-ExecutionPolicy" 1
.set "Bypass" 1
.set "-Command" 1
.set "if (${run_tests} -eq 1) { .\\target\\bin\\tests_cpp.exe }" 1
..
..
!muf 4
[workspace]
.set name "demo-cpp-tests-win-profile-skip"
.set root "."
.set target_dir "target"
.set profile "release"
..
[profile debug]
.set run_tests 1
..
[profile release]
.set run_tests 0
..
[tool gpp]
.exec "g++"
..
[tool pwsh]
.exec "pwsh"
..
[bake tests_cpp]
.make test_src cglob "tests/**/*.cpp"
[run gpp]
.takes test_src as "@args"
.set "-std=c++20" 1
.set "-O0" 1
.set "-g" 1
.emits exe as "-o"
..
.output exe "target\\bin\\tests_cpp.exe"
..
[bake run_tests]
[run pwsh]
.set "-NoProfile" 1
.set "-ExecutionPolicy" 1
.set "Bypass" 1
.set "-Command" 1
.set "if (${run_tests} -eq 1) { .\\target\\bin\\tests_cpp.exe } else { Write-Host \"skip tests (run_tests=0)\"; exit 5 }" 1
..
..
!muf 4
[workspace]
.set name "demo-cpp-tests-profile"
.set root "."
.set target_dir "target"
.set profile "debug"
..
[profile debug]
.set run_tests 1
..
[profile release]
.set run_tests 0
..
[tool gpp]
.exec "g++"
..
[tool sh]
.exec "sh"
..
[bake tests_cpp]
.make test_src cglob "tests/**/*.cpp"
[run gpp]
.takes test_src as "@args"
.set "-std=c++20" 1
.set "-O0" 1
.set "-g" 1
.emits exe as "-o"
..
.output exe "target/bin/tests_cpp"
..
[bake run_tests]
[run sh]
.set "-c" 1
.set "test ${run_tests} -eq 1 && ./target/bin/tests_cpp" 1
..
..
!muf 4
[workspace]
.set name "demo-c-tests-profile"
.set root "."
.set target_dir "target"
.set profile "debug"
..
[profile debug]
.set run_tests 1
..
[profile release]
.set run_tests 0
..
[tool gcc]
.exec "gcc"
..
[tool sh]
.exec "sh"
..
[bake tests_c]
.make test_src cglob "tests/**/*.c"
[run gcc]
.takes test_src as "@args"
.set "-std=c17" 1
.set "-O0" 1
.set "-g" 1
.emits exe as "-o"
..
.output exe "target/bin/tests_c"
..
[bake run_tests]
[run sh]
.set "-c" 1
.set "test ${run_tests} -eq 1 && ./target/bin/tests_c" 1
..
..
Petit exemple de test C minimal (pour tests/**/*.c):
#include <stdio.h>
#include <assert.h>
int main(void) {
assert(1 + 1 == 2);
puts("ok");
return 0;
}
Petit exemple de test C++ minimal (pour tests/**/*.cpp):
#include <iostream>
#include <cassert>
int main() {
assert(1 + 1 == 2);
std::cout << "ok\n";
return 0;
}
!muf 4
[workspace]
.set name "demo-c-tests-win-profile"
.set root "."
.set target_dir "target"
.set profile "debug"
..
[profile debug]
.set run_tests 1
..
[profile release]
.set run_tests 0
..
[tool gcc]
.exec "gcc"
..
[tool pwsh]
.exec "pwsh"
..
[bake tests_c]
.make test_src cglob "tests/**/*.c"
[run gcc]
.takes test_src as "@args"
.set "-std=c17" 1
.set "-O0" 1
.set "-g" 1
.emits exe as "-o"
..
.output exe "target\\bin\\tests_c.exe"
..
[bake run_tests]
[run pwsh]
.set "-NoProfile" 1
.set "-ExecutionPolicy" 1
.set "Bypass" 1
.set "-Command" 1
.set "if (${run_tests} -eq 1) { .\\target\\bin\\tests_c.exe }" 1
..
..
| Exemple | Objectif | Toolchain |
|---|---|---|
12.1 |
C minimal, binaire simple | gcc |
12.3 C (binaire) |
Binaire C avec sources multiples | gcc |
12.3 C (lib + link) |
Compilation en deux etapes | gcc, ar |
12.3 C++ (binaire) |
Binaire C++ standard | g++ |
12.3 C++ (include + libs) |
Include + lien lib | g++ |
12.3 OCaml (native) |
Binaire natif OCaml | ocamlopt |
12.3 OCaml (bytecode) |
Binaire bytecode OCaml | ocamlc |
12.4 Multi-bakes |
Lib + app, bakes separes | gcc |
12.4 Tests C |
Bake de tests | gcc |
12.4 Lib dynamique C |
.so partagee |
gcc |
12.4 Lib dynamique C++ |
.so partagee |
g++ |
12.4 OCaml (lib + app) |
Lib OCaml + binaire | ocamlopt |
12.4 Lib dynamique C (Windows) |
.dll Windows |
gcc |
12.4 Lib dynamique C (macOS) |
.dylib macOS |
clang |
12.4 Lib dynamique C++ (Windows) |
.dll Windows |
g++ |
12.4 Lib dynamique C++ (macOS) |
.dylib macOS |
clang++ |
12.4 C++ tests + runner |
Binaire tests + run | g++, sh |
12.4 C++ tests + runner (Windows) |
Binaire tests + run | g++, pwsh |
12.4 C++ tests par profile |
Tests conditionnes | g++, sh |
12.4 C tests par profile |
Tests conditionnes | gcc, sh |
12.4 C++ tests (Windows, conditionnel) |
Tests conditionnes | g++, pwsh |
12.4 C tests (Windows, conditionnel) |
Tests conditionnes | gcc, pwsh |
12.4 C++ tests (Windows, conditionnel, skip) |
Tests conditionnes + skip | g++, pwsh |
error[U001]: commande inconnue ou manquante.error[E001]: echec interne de configuration.error[C001]: erreur de configuration du runner.error[P001]: erreur de parsing MUF.error[X001]: tool a echoue.error[IO01]: erreur I/O.Conseils:
steelconf.workspace.profile.-v pour des diagnostics.steel graph avec export text|dot|json depuis le DAG resolu.steel fmt (normalisation des blocs/directives).build steelconf par un parser MUF complet..mff de run log stable et versionne.M1 - CLI et outputs:
M2 - Configuration complete:
build steelconfsteelconfig.mff basee sur le modele resoluM3 - Runner et outillage:
graph et fmt sont des stubs (placeholder deterministe).build steelconf est minimal (pas de parse MUF complet).build steelconf.Cette section est un guide long format qui suit un projet fictif de A a Z. Elle reutilise les concepts de la reference et les illustre avec un chemin concret: ecrire un steelconf, generer un MFF, puis executer.
Nous allons construire un petit projet C avec une lib statique et un binaire:
src/lib/ contient lib.c + lib.hsrc/app/ contient main.ctarget/out/Plan:
1) creer un workspace minimal
2) declarer les tools
3) declarer les bakes
4) declarer les profiles
5) executer avec steel run
6) utiliser la configuration resolue .mff
myproj/
steelconf
src/
lib/
lib.c
lib.h
app/
main.c
Contenu minimal pour lib.c:
int add(int a, int b) { return a + b; }
Contenu minimal pour main.c:
#include "../lib/lib.h"
int main(void) { return add(1, 2); }
On commence par le header et un workspace:
!muf 4
[workspace]
.set name "myproj"
.set root "."
.set target_dir "target"
.set profile "debug"
..
Ce bloc fixe des variables globales utilisables dans les autres blocs.
[tool cc]
.exec "gcc"
..
Le nom cc est logique, il n est pas lie a la commande systeme.
[bake lib]
.make c_src cglob "src/lib/*.c"
[run cc]
.takes c_src as "@args"
.set "-std=c17" 1
.set "-O0" 1
.emits obj as "-o"
..
.output obj "target/out/lib.o"
..
[bake app]
.make c_src cglob "src/app/*.c"
.needs lib
[run cc]
.takes c_src as "@args"
.include "src/lib"
.set "-std=c17" 1
.set "-O0" 1
.emits exe as "-o"
..
.output exe "target/out/app"
..
steel run --root . --file steelconf --bake app
Le runner va:
applibappsteel
Cela produit steelconfig.mff. C est une photo stable de votre config.
[profile release]
.set opt 2
.set debug 0
.set ndebug 1
..
Et adapter le run:
.set "-O${opt}" 1
.set "-g" "${debug}"
.set "-DNDEBUG" "${ndebug}"
steel run --profile release --bake app
La selection --profile surcharge workspace.profile.
On peut declarer autant de profiles que necessaire:
[profile sanitize]
.set opt 1
.set debug 1
.set asan 1
..
Dans le run:
.set "-fsanitize=address" "${asan}"
[workspace]
.set target "x86_64-unknown-linux-gnu"
..
Vous pouvez utiliser ${target} dans les chemins ou flags.
.set target_dir "target/${target}"
Cela evite les collisions entre builds.
[profile windows]
.set exe_ext ".exe"
..
Puis:
.output exe "target/out/app${exe_ext}"
[tool cc]
.exec "gcc"
..
[tool ar]
.exec "ar"
..
Dans la vraie vie, on veut choisir clang ou gcc.
Une strategie simple:
[workspace]
.set cc "gcc"
..
[tool cc]
.exec "${cc}"
..
Le build steel calcule un fingerprint stable:
Le fingerprint peut etre injecte dans vos sorties ou logs.
Un bake peut emettre plusieurs ports:
[bake compile]
.make c_src cglob "src/**/*.c"
[run cc]
.takes c_src as "@args"
.emits obj as "-o"
..
.output obj "target/out/app.o"
.output dep "target/out/app.d"
..
Un bake peut avoir plusieurs runs, mais ici le runner supporte un seul bloc run.
Dans ce cas, on decoupe en deux bakes:
compile -> objlink -> exeOn peut utiliser des variables dans les glob:
.make c_src cglob "src/${module}/*.c"
Dans une version complete, on relierait un port obj vers link.
Le runner actuel ne resolv pas un wiring complet, mais la logique est:
.needs compile
Conventions conseillees:
src pour inputsobj pour objetsexe pour binaire finallib pour archivesLes ports doivent etre stables et predictibles, car ils sont referencables.
Le run produit un fichier .mff de log dans target/.
Ce log sert a diagnostiquer les commandes et la duree.
steel run --log target/runlog.mff --log-mode truncate
Reperer:
cmdstatusstdout / stderrLe runner compare:
Si output est plus recent, il skip.
steel run --no-cache
steel graph --text
Dans le futur, cette commande montrera les bakes et dependances.
steel graph --dot > graph.dot
Le schema cible est schemas/steel.graph.json.schema.json.
Utiliser ce format pour IDE/CI.
error[P001]: invalid token
at steelconf:12:3
steel print--bake-vDans un pipeline:
1) steel print > steelconfig.mff
2) archiver steelconfig.mff
3) executer steel run
L IDE peut:
steelconfig.mffgraph.jsonUtiliser les schemas pour valider la sortie machine-readable.
Exemple typique:
root/
steelconf
src/
lib/
app/
include/
tests/
target/
dist/
Conseils:
src/ pour les sourcesinclude/ pour les headerstarget/ pour les artefactsdist/ pour les artefacts finauxMUF est la source editable. MFF est un artefact stable et deterministe.
Modifier la valeur de .exec ou utiliser une variable de workspace.
Utiliser --log et inspecter la commande.
MUFFIN_FINGERPRINT_TIME (sel temporel pour debug, non deterministe).MUFFIN_PROFILE, MUFFIN_TARGET, MUFFIN_EMIT sont ignores pour steel.steelconf a la racinesteelconfig.mff en sortietarget/ pour logs runner!muf 4
[workspace]
.set name "myproj"
.set root "."
.set target_dir "target"
.set profile "debug"
..
[profile debug]
.set opt 0
.set debug 1
.set ndebug 0
..
[profile release]
.set opt 3
.set debug 0
.set ndebug 1
..
[tool cc]
.exec "gcc"
..
[bake lib]
.make c_src cglob "src/lib/*.c"
[run cc]
.takes c_src as "@args"
.set "-std=c17" 1
.set "-O${opt}" 1
.set "-g" "${debug}"
.set "-DNDEBUG" "${ndebug}"
.emits obj as "-o"
..
.output obj "target/out/lib.o"
..
[bake app]
.make c_src cglob "src/app/*.c"
.needs lib
[run cc]
.takes c_src as "@args"
.include "src/lib"
.set "-std=c17" 1
.set "-O${opt}" 1
.set "-g" "${debug}"
.set "-DNDEBUG" "${ndebug}"
.emits exe as "-o"
..
.output exe "target/out/app"
..
releasedist/steelconfig.mffObjectif: organiser un projet avec plusieurs libs et un binaire final.
root/
steelconf
src/
core/
core.c
core.h
util/
util.c
util.h
app/
main.c
[bake core]
.make c_src cglob "src/core/*.c"
[run cc]
.takes c_src as "@args"
.include "src/core"
.emits obj as "-o"
..
.output obj "target/out/core.o"
..
[bake util]
.make c_src cglob "src/util/*.c"
[run cc]
.takes c_src as "@args"
.include "src/util"
.emits obj as "-o"
..
.output obj "target/out/util.o"
..
[bake app]
.make c_src cglob "src/app/*.c"
.needs core
.needs util
[run cc]
.takes c_src as "@args"
.include "src/core"
.include "src/util"
.emits exe as "-o"
..
.output exe "target/out/app"
..
Utiliser target/out pour les sorties immediates, puis dist/ pour publier.
Steel ne fait pas la copie automatiquement. On peut ajouter un bake:
[bake dist]
.needs app
[run sh]
.set "cmd" "cp target/out/app dist/app"
..
.output exe "dist/app"
..
Ce pattern est symbolique: il depend du runner et des tools autorises.
Choisir des noms stables pour:
Le JSON est pratique pour:
Le schema cible est steel.graph.json/1.
Le fichier est stable et deterministe.
Valider un JSON via un validateur standard et le schema fourni.
Le header mff 1 fixe la version du format.
steel print > steelconfig.mff
Puis archiver l artefact. Cela permet:
Comme c est deterministe, un diff git est lisible et utile.
Si MUF est invalide, la phase build steelconf renvoie des diagnostics.
Si une commande echoue, le code retour est non zero.
--printEviter les patterns trop larges:
src/**/*
Preferer:
src/**/*.c
Plusieurs bakes permettent d isoler les recompilations.
Le cache est simple mais efficace pour des projets moyens.
[bake test]
.needs app
[run sh]
.set "cmd" "target/out/app --selftest"
..
.output exe "target/out/test.ok"
..
steel run --profile debug --bake test
steel run --profile release --bake test
Automatiser la sequence:
Recommandations:
Avant steel fmt, etablir une convention d equipe.
Valider les changements MUF comme du code:
Le runner actuel ne supporte pas toutes les directives MUF possibles.
Les blocs et directives ont ete concus pour etre etendus sans casser la compatibilite.
Configuration:
Execution:
!muf 4 header[tag name] blocs.op arg directives.. fin de blocVoir CONTRIBUTING.md pour les regles de contribution.
Objectif: montrer un pipeline en deux etapes avec outputs intermediaires.
[bake compile]
.make c_src cglob "src/**/*.c"
[run cc]
.takes c_src as "@args"
.set "-std=c17" 1
.emits obj as "-o"
..
.output obj "target/out/app.o"
..
[bake link]
.needs compile
[run cc]
.set "cmd" "gcc target/out/app.o -o target/out/app"
..
.output exe "target/out/app"
..
[bake ar]
.needs compile
[run ar]
.set "cmd" "ar rcs target/out/lib.a target/out/app.o"
..
.output lib "target/out/lib.a"
..
Steel peut orchestrer plusieurs tools:
ocamlcgcc[bake ocaml]
.make ml_src cglob "src/ocaml/*.ml"
[run ocamlc]
.takes ml_src as "@args"
.emits obj as "-o"
..
.output obj "target/out/ocaml.o"
..
[bake c]
.make c_src cglob "src/c/*.c"
[run cc]
.takes c_src as "@args"
.emits obj as "-o"
..
.output obj "target/out/c.o"
..
[bake link]
.needs ocaml
.needs c
[run cc]
.set "cmd" "gcc target/out/ocaml.o target/out/c.o -o target/out/app"
..
.output exe "target/out/app"
..
Regles conseillees:
Exemples:
compilelinktestdistPorts usuels:
srcobjlibexePreferer cc, cxx, ar, ld pour l intention.
[workspace]
.set cc "gcc"
.set cflags "-Wall -Wextra"
..
.set "${cflags}" 1
Eviter les chaines trop longues.
Preferer plusieurs .set simples.
Exemple: un bake standard C.
[bake c_compile]
.make c_src cglob "src/**/*.c"
[run cc]
.takes c_src as "@args"
.set "-std=c17" 1
.set "-O${opt}" 1
.set "-g" "${debug}"
.emits obj as "-o"
..
.output obj "target/out/app.o"
..
Le but est de garder une structure stable et reconnaissable.
Les outputs intermediaires doivent etre dans target/out.
steel cache clear supprime les caches, pas les outputs.
Utiliser un script externe pour nettoyer target/.
Ne pas melanger sources et outputs.
steel
steel print
steel check
target/diff steelconfig.mff other/steelconfig.mff
Nombre de bakes, nombre de sources, taille du log.
1) lister les commandes actuelles 2) en faire des bakes 3) stabiliser les paths
gcc -c src/main.c -o target/out/main.o
gcc target/out/main.o -o target/out/app
Devient:
[bake compile]
.make c_src cglob "src/main.c"
[run cc]
.takes c_src as "@args"
.emits obj as "-o"
..
.output obj "target/out/main.o"
..
[bake link]
.needs compile
[run cc]
.set "cmd" "gcc target/out/main.o -o target/out/app"
..
.output exe "target/out/app"
..
Steel vise:
Ce guide peut etre etendu en fonction de l evolution du runner et des schemas.
Ajouter un court README:
steelsteel runFournir un exemple minimal qui compile sans configuration externe.
Synchroniser la doc avec les changements du steelconf.
[bake app_one]
.make c_src cglob "src/app1/*.c"
[run cc]
.takes c_src as "@args"
.emits exe as "-o"
..
.output exe "target/out/app_one"
..
[bake app_two]
.make c_src cglob "src/app2/*.c"
[run cc]
.takes c_src as "@args"
.emits exe as "-o"
..
.output exe "target/out/app_two"
..
steel run --bake app_one
steel run --bake app_two
steel run --all
Le root doit contenir:
Si plusieurs projets cohabitent, preferer un steelconf par projet.
Les chemins absolus cassent la portabilite.
[bake assets]
.make data cglob "assets/**/*"
[run sh]
.set "cmd" "cp -R assets target/out/assets"
..
.output dir "target/out/assets"
..
Utiliser une variable:
.set assets_dir "assets/${profile}"
assets/ stable.include "include"
.include "src/lib"
.include "src/util"
Preferer un dossier include/ commun.
Utiliser -v sur la CLI.
Inspecter le log:
cmdstatusCopier la commande et l executer manuellement pour isoler l erreur.
Penser au suffixe .exe et aux paths.
Attention aux differences de toolchain.
Le comportement par defaut est teste sur Linux.
Utiliser target/logs/ si besoin de plusieurs logs.
target/logs/run_debug.mff
target/logs/run_release.mff
Archiver les logs avec les artefacts en CI.
Supprimer target/ avant une release propre.
Archiver dist/ et steelconfig.mff.
root/
steelconf
src/
include/
assets/
target/
dist/
steelsteel runsteel printsteel checkLe format MUF reste la source, MFF est l artefact resolu.
Quand plusieurs bakes se ressemblent, creer un bake modele et le copier.
Renommer les bakes avec prudence:
--bake.needsGarder des ports courts et explicites.
Decouper les globs par dossier pour garder un controle fin.
Eviter les fichiers generes dans les globs sources.
Les listes de fichiers doivent rester stables entre runs.
Toujours utiliser des paths relatifs au root.
Steel normalise les chemins avec /.
Si un sous-projet est un submodule, preferer un steelconf separé.
Considerer le steelconf comme du code critique.
Les diffs sur MUF sont lisibles et utiles.
Executer steel check en CI.
Archiver les logs dans un dossier dedie.
Comparer les logs pour detecter des regressions de commandes.
Associer un log a une version de steelconf.
Nettoyer target/ avant un build de reference.
Utiliser des toolchains versionnees.
Archiver steelconfig.mff avec l artefact final.
sh[tool sh]
.exec "sh"
..
[bake script]
[run sh]
.set "cmd" "echo hello > target/out/hello.txt"
..
.output file "target/out/hello.txt"
..
Limiter les scripts pour conserver la reproductibilite.
steel
steel
Utiliser target/${target} pour separer les artefacts.
Comparer les steelconfig.mff par target.
Mettre a jour les sections MUF/MFF si le format evolue.
Ajouter des sections quand de nouvelles commandes arrivent.
Garder des exemples courts et valides.
Consulter:
doc/manifest.mdschemas/README.mdFin du guide et de la reference.
Toujours committer le steelconf avec le code source.
Archiver steelconfig.mff pour les builds importants.
Associer un tag git a un MFF archivé.
Supprimer les anciens logs et outputs.
Revoir les patterns pour eviter les inclusions accidentelles.
Supprimer les profiles obsoletes.
Documenter:
Ajouter un script ./build.sh si besoin de simplifier.
Fournir un exemple MUF minimal dans le repo.
Verifier que le run correspond a la configuration resolue.
Eviter les divergences entre target/ et dist/.
Utiliser les memes versions de tools en local et CI.
Utiliser --offline pour eviter les acces reseau.
Verifier que tout est present localement.
Archiver les logs pour audit.
Garder un root stable facilite les diffs.
Toujours preferer des paths relatifs au root.
Eviter les separateurs OS dans les fichiers MUF.
Conserver les flags dans les profiles:
[profile debug]
.set cflags "-O0 -g"
..
.set "${cflags}" 1
Eviter des lignes de flags trop longues.
Un bake par responsabilite.
Copier les patterns pour garder une structure uniforme.
Ajouter des bakes sans casser les existants.
Toujours !muf 4 en tete.
Lire la roadmap et adapter les exemples.
Eviter les changements cassants dans les conventions internes.
steelsteel run --bake appsteel printsteelconfig.mfftarget/outSteel privilegie la stabilite et la lisibilite des configurations.