moon-ninja

MoonNinja is a MoonBit-native subset Ninja parser and build scheduler with dependency graph planning, incremental analysis, and execution demos.

moonbit
ninja
build-system
dag
incremental-build
moon add Zcxssxx/moon-ninja@0.3.2
Download zip
Author
Version
0.3.2
License
Apache-2.0
Last updated
4 hours ago
Downloads
25
README

#MoonNinja

MoonBit License CI

MoonNinja is a MoonBit-native subset Ninja build engine for OSC2026. It focuses on the core path that the acceptance review cares about most:

  • real build.ninja-style text parsing
  • dependency-graph construction with Tarjan SCC diagnostics and cycle detection
  • incremental rebuild decisions from real native MTime plus content hash snapshots
  • deterministic lock-free dependency waves for host-provided parallel runners
  • native command execution through a bounded atomic-index worker pool and a real WASM-GC/JS host execution ABI
  • schedulable command rendering with $in and $out expansion
  • named variable expansion, Make-style depfile ingestion, and response-file materialization
  • deterministic inspectable build plans, persistent state sidecars, path safety, and command validation
  • reproducible examples, committed C benchmark inputs, boundary tests, CI, and self-check scripts

The project is intentionally scoped to a well-documented subset of Ninja so that the implementation remains readable, testable, and publishable as a MoonBit ecosystem package.

#Current Scope

MoonNinja currently supports:

  • rule <name> blocks with command = ...
  • build <outputs>: <rule> <inputs> declarations
  • multiple outputs in one build edge
  • implicit and order-only dependencies written with | and ||
  • comments beginning with #
  • topological traversal and cycle detection
  • strongly connected component reporting for cyclic manifests
  • incremental stale-check decisions driven by MTime plus content fingerprints
  • native stat/streaming-hash snapshots through src/native/native_stub.c
  • native process execution through system
  • native parallel-wave execution through NativeParallelWaveExecutor, with bounded workers and deterministic failure indices
  • WASM-GC host import moon_ninja.execute_command and JS host import MoonNinjaHost.execute_command
  • portable ExpansionContext, Depfile, MaterializedPlan, BuildState, and CommandLine APIs

MoonNinja does not yet aim to be a drop-in replacement for the full Ninja specification. The repository documents this boundary explicitly and tests the supported subset end to end.

#Quick Start

moon fmt --check moon check --deny-warn moon build --target all moon test --deny-warn moon run src/main

Native backend validation:

moon test --deny-warn --target native

The default demo is intentionally plan-only, so it is runnable on every backend. Native command execution is covered by the native-only integration test and requires a C compiler. WASM-GC command execution is not a fake local process: the host must provide an import named moon_ninja.execute_command whose argument is a MoonBit String and whose return value is an integer exit code. JavaScript hosts provide the equivalent MoonNinjaHost.execute_command.

For the full backend matrix, run:

moon check --target all --deny-warn moon build --target all --deny-warn moon test --target all --deny-warn

Acceptance self-check:

powershell -ExecutionPolicy Bypass -File .\scripts\verify_acceptance.ps1

验收脚本默认使用当前 PATH 中的 MoonBit。正式验收使用最新的 MoonBit 0.10.7+bc794d341,也可以显式传入同版本工具链目录:

powershell -ExecutionPolicy Bypass -File .\scripts\verify_acceptance.ps1 ` -MoonBitBin "<path-to-moonbit-0.10.7-bin>"

脚本会先校验 moon.exemoonc.exemoonrun.exe 三个工具均存在,再执行 格式化、全目标检查、构建和测试;CI 与本地验收使用同一版本。

#Example

Example input file: examples/sample.build.ninja

rule cc command = gcc -c $in -o $out rule link command = gcc $in -o $out build util.o: cc util.c build main.o: cc main.c | generated.h build app: link main.o util.o

The demo entry at src/main/main.mbt parses a manifest like the one above, builds a dependency graph, evaluates which targets are stale, and prints the commands that would execute. LocalExecutor is available for native hosts; DryRunExecutor is used by the portable demo.

#Fixture benchmark and boundary coverage

examples/benchmarks/medium.build.ninja is a committed, reproducible workload. It compiles three real C inputs, tracks a header dependency, archives two objects, and links a downstream demo. The inputs live in examples/fixtures, so CI never depends on files that are created implicitly by a test.

examples/benchmarks/large.build.ninja adds ten independent compile edges, two header families, an archive, and a final link. It is intended for stable wave-width and transitive-input inspection rather than synthetic line counting.

The public Manifest::benchmark and Manifest::analyze APIs report edge and node counts, dependency depth, wave width, fan-in/fan-out, leaf inputs, and rendered commands. src/validation_test.mbt, src/graph_boundary_test.mbt, and the parser tests cover empty outputs, duplicate declarations, unknown rules/targets, self-cycles, multi-node cycles, disconnected cycles, order-only inputs, CRLF text, punctuation in paths, and missing/change-sensitive fingerprints.

The checked-in implementation and tests contain more than 2,500 lines of effective MoonBit source and more than 4,000 tracked MoonBit/C implementation and test/interface lines. These are evidence-based counts performed by scripts/verify_acceptance.ps1, not generated filler; the competition guidance also makes clear that maintainable scope and working evidence matter more than an arbitrary line count.

For a target-level explanation, call Manifest::inspect_target. For a stable execution artifact, call Manifest::materialize_plan, then serialize BuildState::to_text after a successful host run. Compiler-generated depfiles can be parsed with parse_depfile and merged into the producing edge. Commands that use @flags.rsp can be expanded from an in-memory response-file table with materialize_response_command; no host filesystem access is required by these portable APIs.

#Design notes

DepGraph::strongly_connected_components uses Tarjan's algorithm and reports the complete cyclic component. DepGraph::parallel_waves emits independent ready sets in deterministic order. Scheduler::run_parallel_waves never shares a mutable ready queue between waves; a native thread-pool or WASM host can implement WaveExecutor to run each wave concurrently.

FileFingerprint stores seconds, nanoseconds, size, and a portable 64-bit content hash. The native adapter reads real file metadata and streams the file through the hash; equal timestamps therefore do not hide content changes.

#Repository Layout

MoonNinja/ |- .github/workflows/test.yml GitHub Actions CI |- examples/sample.build.ninja Realistic parser input example |- scripts/verify_acceptance.ps1 |- moon.mod MoonBit module metadata for publication |- src/ | |- manifest.mbt Manifest and command rendering | |- lexer.mbt Tokenization for the supported Ninja subset | |- parser.mbt Parser for rule/build declarations | |- graph.mbt SCC diagnostics and dependency waves | |- incremental.mbt MTime/hash rebuild decision logic | |- fingerprint.mbt Portable file identity model | |- scheduler.mbt Planning and incremental execution | |- wave_executor.mbt Lock-free wave runner interface | |- local_executor.mbt Native command execution adapter | |- benchmark.mbt Measured workload summaries | |- plan_analysis.mbt Critical-path and parallelism analysis | |- validation.mbt Manifest validation diagnostics | |- diagnostics.mbt Actionable parse/graph diagnostics | |- variable_expansion.mbt Named and built-in command variables | |- depfile.mbt Make-style compiler dependency files | |- response_file.mbt Quoted response-file arguments | |- build_plan.mbt Stable materialized target plans | |- build_state.mbt Incremental state sidecar format | |- path_utils.mbt Cross-platform safe build paths | |- command_line.mbt Structured command rendering | |- command_validation.mbt Pre-execution command diagnostics | |- target_inspection.mbt Read-only dependency explanations | |- dependency_diff.mbt Stable depfile change reports | |- native/ Native stat/hash adapter, worker pool, and fixture tests | |- parser_test.mbt Core-path tests | `- main/main.mbt Demo CLI entry |- official-requirements.md OSC2026 requirement notes |- source-attribution.md Source explanation and implementation boundaries `- submission-status.md Local closeout status and reviewer checklist

#Mooncakes Metadata

The package metadata needed for Mooncakes publication is declared in moon.mod:

  • module name: Zcxssxx/moon-ninja
  • license: Apache-2.0
  • repository: https://github.com/Zcxssxx/Zcxproject11
  • readme: README.md

Before publishing, use:

moon publish --dry-run

#Competition Notes

  • GitHub primary repo: Zcxssxx/Zcxproject11
  • GitLink mirror: Zcxxffss/MoonNinja
  • The GitHub repo is used for CI and Mooncakes-facing metadata.
  • The GitLink repo is kept as the competition mirror and can remain single-contributor on that platform.

#Reference projects and license boundary

MoonNinja targets a documented subset of the Ninja file model. The interoperability references are:

  • Ninja, an Apache-2.0 build system; see its license.
  • n2, a Ninja-compatible Apache-2.0 build system; see its license.

No Ninja or n2 source is copied into this repository. Their syntax and public documentation are referenced only to define compatibility scope; this project contains original MoonBit code under its own Apache License 2.0.

#Verification Checklist

#License

Apache License 2.0. See LICENSE.

#
Executor

pub trait Executor {
fn run(Self, BuildEdge, Map[String, Rule]) -> Result[Unit, String]
}

#
WaveExecutor

pub(open) trait WaveExecutor {
fn run_wave(Self, Array[BuildEdge], Map[String, Rule]) -> Result[Array[String], String]
}

A runner supplied by the host for one independent dependency wave.

The graph planner never shares a mutable ready queue between waves. A native caller can implement this trait with a thread pool, while a WASM caller can dispatch the whole wave to its host scheduler.

#
ParseError

pub suberror ParseError {
UnexpectedToken(Token, expected~ : String)
SyntaxError(String, line~ : Int, col~ : Int)
} derive(
Debug
)

#
BenchmarkReport

pub(all) struct BenchmarkReport {
summary : BenchmarkSummary
rendered_commands : Array[String]
wave_sizes : Array[Int]
} derive(
Debug
)

#
BenchmarkSummary

pub(all) struct BenchmarkSummary {
rule_count : Int
edge_count : Int
node_count : Int
dependency_depth : Int
wave_count : Int
max_wave_width : Int
critical_path : Int
fan_in : Int
fanout : Int
command_count : Int
} derive(Eq,
Debug
)

#
BenchmarkSummary::to_text

fn BenchmarkSummary::to_text(self : BenchmarkSummary) -> String

#
BuildDecision

pub(all) enum BuildDecision {
UpToDate
NeedsBuild(String)
} derive(Eq,
Debug
)

#
BuildEdge

pub(all) struct BuildEdge {
rule : String
inputs : Array[String]
outputs : Array[String]
} derive(Eq,
Debug
)

#
BuildEdge::evaluate_fingerprints

fn BuildEdge::evaluate_fingerprints(self : BuildEdge, current : Map[String, FileFingerprint], previous : Map[String, FileFingerprint]) -> BuildDecision

Compare current filesystem fingerprints with the previous build state.

This check intentionally combines content identity and MTime ordering: equal timestamps do not hide changed content, and newer inputs still make older outputs stale.

#
BuildEdge::evaluate_incremental

fn BuildEdge::evaluate_incremental(self : BuildEdge, snapshot : Map[String, Int]) -> BuildDecision

#
BuildEdge::key

fn BuildEdge::key(self : BuildEdge) -> String

#
BuildEdge::refresh_outputs

fn BuildEdge::refresh_outputs(self : BuildEdge, snapshot : Map[String, Int], tick : Int) -> Int

#
BuildEdge::render_command

fn BuildEdge::render_command(self : BuildEdge, rules : Map[String, Rule]) -> Result[String, String]

#
BuildEdge::render_command_with_variables

fn BuildEdge::render_command_with_variables(self : BuildEdge, rules : Map[String, Rule], variables : Map[String, String]) -> Result[String, String]

#
BuildEdge::to_ninja

fn BuildEdge::to_ninja(self : BuildEdge) -> String

#
BuildReport

pub(all) struct BuildReport {
status : BuildReportStatus
target : String
waves : Int
commands : Int
cache_hits : Int
cache_misses : Int
failures : Array[String]
outputs : Array[String]
} derive(Eq,
Debug
)

A compact, deterministic summary of one materialized build.

#
BuildReport::cache_hit_percent

fn BuildReport::cache_hit_percent(self : BuildReport) -> Int

Integer cache hit percentage, stable for empty reports.

#
BuildReport::cache_observations

fn BuildReport::cache_observations(self : BuildReport) -> Int

Number of cache observations recorded for this report.

#
BuildReport::contains_output

fn BuildReport::contains_output(self : BuildReport, output : String) -> Bool

Check whether an output was recorded by this build.

#
BuildReport::executed_commands

fn BuildReport::executed_commands(self : BuildReport) -> Int

Number of commands that actually missed the cache.

#
BuildReport::failure_summary

fn BuildReport::failure_summary(self : BuildReport) -> String

Return a stable one-line failure summary for dashboards.

#
BuildReport::finish

fn BuildReport::finish(self : BuildReport) -> BuildReport

Mark a report successful only when no failure was recorded.

#
BuildReport::has_cache_reuse

fn BuildReport::has_cache_reuse(self : BuildReport) -> Bool

Whether at least one reusable artifact was observed.

#
BuildReport::is_success

fn BuildReport::is_success(self : BuildReport) -> Bool

Whether this report can be used as a successful incremental state.

#
BuildReport::is_terminal

fn BuildReport::is_terminal(self : BuildReport) -> Bool

Whether the report has reached a terminal state.

#
BuildReport::merge

fn BuildReport::merge(self : BuildReport, other : BuildReport) -> BuildReport

Return a report with all counters and collections combined.

#
BuildReport::record_cache_hit

fn BuildReport::record_cache_hit(self : BuildReport, output : String) -> BuildReport

Record one cache hit and its materialized output.

#
BuildReport::record_cache_miss

fn BuildReport::record_cache_miss(self : BuildReport, output : String) -> BuildReport

Record one cache miss and its materialized output.

#
BuildReport::record_failure

fn BuildReport::record_failure(self : BuildReport, message : String) -> BuildReport

Record a failure and retain its first-seen order.

#
BuildReport::record_wave

fn BuildReport::record_wave(self : BuildReport, command_count : Int) -> BuildReport

Record a scheduled wave without changing the report's target.

#
BuildReport::to_text

fn BuildReport::to_text(self : BuildReport) -> String

Render a machine-readable, line-oriented summary for CI logs.

#
BuildReport::validate

fn BuildReport::validate(self : BuildReport) -> Result[Unit, String]

Validate invariants before persisting a report as build state.

#
BuildReportStatus

pub(all) enum BuildReportStatus {
Pending
Succeeded
Failed
} derive(Eq,
Debug
)

Build execution outcome used by frontends, CI summaries, and telemetry.

#
BuildState

pub(all) struct BuildState {
entries : Array[BuildStateEntry]
} derive(Eq,
Debug
)

A deterministic, text-serializable incremental state cache.

#
BuildState::find

fn BuildState::find(self : BuildState, edge_key : String) -> BuildStateEntry?

Find a state entry by edge key for hosts that also inspect output paths.

#
BuildState::from_plan

fn BuildState::from_plan(plan : MaterializedPlan) -> BuildState

#
BuildState::needs_rebuild

fn BuildState::needs_rebuild(self : BuildState, edge_key : String, command : String) -> Bool

Return true when an edge is absent or its command has changed.

#
BuildState::to_text

fn BuildState::to_text(self : BuildState) -> String

#
BuildStateEntry

pub(all) struct BuildStateEntry {
edge_key : String
command_hash : String
outputs : Array[String]
} derive(Eq,
Debug
)

A portable sidecar entry for one planned build edge.

#
CommandIssue

pub(all) struct CommandIssue {
argument_index : Int
code : String
message : String
} derive(Eq,
Debug
)

A structured command-line validation finding suitable for diagnostics. Hosts can display these findings before execution and attach the argument index to a UI or CI annotation without parsing human-readable text. This keeps process launch policy separate from command rendering and makes the same validation available to native and browser-hosted plans.

#
CommandIssue::to_text

fn CommandIssue::to_text(self : CommandIssue) -> String

#
CommandLine

pub(all) struct CommandLine {
executable : String
arguments : Array[String]
} derive(Eq,
Debug
)

A structured command line that can be rendered for a shell or response file without losing argument boundaries.

#
CommandLine::append

fn CommandLine::append(self : CommandLine, argument : String) -> CommandLine

#
CommandLine::has_unsafe_argument

fn CommandLine::has_unsafe_argument(self : CommandLine) -> Bool

#
CommandLine::is_valid

fn CommandLine::is_valid(self : CommandLine) -> Bool

#
CommandLine::new

fn CommandLine::new(executable~ : String, arguments~ : Array[String]) -> CommandLine

#
CommandLine::to_response_file

fn CommandLine::to_response_file(self : CommandLine) -> String

#
CommandLine::to_shell_text

fn CommandLine::to_shell_text(self : CommandLine) -> String

#
CommandLine::validate

fn CommandLine::validate(self : CommandLine) -> Array[CommandIssue]

Validate command structure before a host invokes a process.

#
DepGraph

pub(all) struct DepGraph {
nodes : Map[String, BuildEdge]
rules : Map[String, Rule]
producer : Map[String, BuildEdge]
}

#
DepGraph::analyze

fn DepGraph::analyze(self : DepGraph, target : String) -> Result[PlanAnalysis, String]

Analyze the executable shape of one target before choosing a host runner.

#
DepGraph::build

fn DepGraph::build(manifest : Manifest) -> DepGraph

#
DepGraph::parallel_waves

fn DepGraph::parallel_waves(self : DepGraph, target : String) -> Result[Array[Array[BuildEdge]], String]

Return dependency edges grouped into deterministic, lock-free waves.

#
DepGraph::strongly_connected_components

fn DepGraph::strongly_connected_components(self : DepGraph) -> Array[Array[String]]

Return all strongly connected components using Tarjan's algorithm.

#
DepGraph::traverse

fn DepGraph::traverse(self : DepGraph, target : String) -> Result[Array[BuildEdge], String]

#
DependencyDiff

pub(all) struct DependencyDiff {
target : String
added : Array[String]
removed : Array[String]
unchanged : Array[String]
} derive(Eq,
Debug
)

A deterministic comparison between two dependency sets for one output.

#
DependencyDiff::to_text

fn DependencyDiff::to_text(self : DependencyDiff) -> String

#
Depfile

pub(all) struct Depfile {
target : String
dependencies : Array[String]
} derive(Eq,
Debug
)

A parsed Make-style dependency file produced by compilers such as GCC.

#
Diagnostic

pub(all) struct Diagnostic {
kind : DiagnosticKind
code : String
message : String
subject : String
hint : String
} derive(Eq,
Debug
)

#
Diagnostic::to_text

fn Diagnostic::to_text(self : Diagnostic) -> String

#
DiagnosticKind

pub(all) enum DiagnosticKind {
Parse
Validation
Graph
Execution
} derive(Eq,
Debug
)

#
DryRunExecutor

pub(all) struct DryRunExecutor {
}

An executor for planning and deterministic tests.

It validates that the referenced rule exists and renders the command, but does not invoke a host process. This is the portable executor used by the default demo and by backend-independent scheduler tests.

#
DryRunWaveExecutor

pub(all) struct DryRunWaveExecutor {
}

#
ExpansionContext

pub(all) struct ExpansionContext {
inputs : Array[String]
outputs : Array[String]
variables : Map[String, String]
} derive(Eq,
Debug
)

Values available while rendering one build edge.

The context is deliberately explicit: portable planning never reads the process environment, so WASM-GC, JS, and native hosts render the same command from the same inputs.

#
ExpansionContext::new

fn ExpansionContext::new(inputs~ : Array[String], outputs~ : Array[String], variables~ : Map[String, String]) -> ExpansionContext

#
FileFingerprint

pub(all) struct FileFingerprint {
mtime_seconds : Int64
mtime_nanos : Int
size : Int
content_hash : String
} derive(Eq,
Debug
)

A filesystem identity used by incremental planning.

The timestamp is retained for Ninja-style ordering checks, while the content digest prevents a same-mtime edit from being treated as up to date.

#
FileFingerprint::from_bytes

fn FileFingerprint::from_bytes(bytes : Bytes, mtime_seconds~ : Int64, mtime_nanos~ : Int) -> FileFingerprint

#
FileFingerprint::from_metadata

fn FileFingerprint::from_metadata(mtime_seconds~ : Int64, mtime_nanos~ : Int, size~ : Int, content_hash~ : String) -> FileFingerprint

#
FileFingerprint::is_newer_than

fn FileFingerprint::is_newer_than(self : FileFingerprint, other : FileFingerprint) -> Bool

#
Lexer

pub struct Lexer {
input : String
pos : Int
line : Int
col : Int
}

#
Lexer::new

fn Lexer::new(input : String) -> Lexer

#
Lexer::next_token

fn Lexer::next_token(self : Lexer) -> Token

#
Lexer::read_rest_of_line

fn Lexer::read_rest_of_line(self : Lexer) -> String

#
LocalExecutor

pub(all) struct LocalExecutor {
}

#
Manifest

pub(all) struct Manifest {
rules : Map[String, Rule]
builds : Array[BuildEdge]
} derive(Eq,
Debug
)

#
Manifest::analyze

fn Manifest::analyze(self : Manifest, target : String) -> Result[PlanAnalysis, String]

#
Manifest::apply_depfile

fn Manifest::apply_depfile(self : Manifest, depfile : Depfile) -> Result[Manifest, String]

Merge a depfile into the build edge that produces its target.

#
Manifest::benchmark

fn Manifest::benchmark(self : Manifest, target : String) -> Result[BenchmarkReport, String]

Measure a target's real parsed graph, not a synthetic line-count metric.

#
Manifest::diagnostics_for_manifest

fn Manifest::diagnostics_for_manifest(self : Manifest) -> Array[Diagnostic]

#
Manifest::inspect_target

fn Manifest::inspect_target(self : Manifest, target : String) -> Result[TargetInspection, String]

Inspect a target without executing it. This is useful for CLI explain commands, acceptance reports, and host-side scheduling decisions.

#
Manifest::is_valid

fn Manifest::is_valid(self : Manifest) -> Bool

#
Manifest::materialize_plan

fn Manifest::materialize_plan(self : Manifest, target : String, variables : Map[String, String]) -> Result[MaterializedPlan, String]

Materialize one target with stable traversal order and explicit variables.

#
Manifest::to_ninja

fn Manifest::to_ninja(self : Manifest) -> String

Serialize the supported subset into a deterministic, reviewable manifest.

#
Manifest::validate

fn Manifest::validate(self : Manifest) -> Result[Unit, String]

#
Manifest::validation_issues

fn Manifest::validation_issues(self : Manifest) -> Array[ValidationIssue]

Check the supported Ninja subset before graph planning or execution.

Errors indicate an invalid build graph. Warnings describe valid but unusual edges, such as a source-generating rule with no inputs.

#
MaterializedPlan

pub(all) struct MaterializedPlan {
target : String
edges : Array[BuildEdge]
waves : Array[Array[BuildEdge]]
commands : Array[String]
inputs : Array[String]
outputs : Array[String]
critical_path : Int
} derive(Eq,
Debug
)

A fully materialized, deterministic plan for one requested target. Unlike a scheduler, this value is safe to inspect, serialize, benchmark, or hand to a native/WASM host before any command is executed.

#
MaterializedPlan::to_text

fn MaterializedPlan::to_text(self : MaterializedPlan) -> String

#
Parser

pub struct Parser {
lexer : Lexer
current_token : Token
}

#
Parser::new

fn Parser::new(input : String) -> Parser

#
Parser::parse

fn Parser::parse(self : Parser) -> Manifest raise ParseError

#
PlanAnalysis

pub(all) struct PlanAnalysis {
target : String
edge_count : Int
wave_count : Int
critical_path : Int
max_parallelism : Int
leaf_input_count : Int
produced_output_count : Int
leaf_inputs : Array[String]
} derive(Eq,
Debug
)

#
PlanAnalysis::to_text

fn PlanAnalysis::to_text(self : PlanAnalysis) -> String

#
Rule

pub(all) struct Rule {
name : String
command : String
} derive(Eq,
Debug
)

#
Rule::to_ninja

fn Rule::to_ninja(self : Rule) -> String

#
Scheduler

pub(all) struct Scheduler[E] {
graph : DepGraph
executor : E
}

#
Scheduler::plan

fn[E] Scheduler::plan(self : Scheduler[E], target : String) -> Result[Array[BuildEdge], String]

#
Scheduler::run_all

fn[E : Executor] Scheduler::run_all(self : Scheduler[E], target : String) -> Result[Unit, String]

#
Scheduler::run_incremental

fn[E : Executor] Scheduler::run_incremental(self : Scheduler[E], target : String, snapshot : Map[String, Int]) -> Result[Array[String], String]

#
Scheduler::run_parallel_waves

fn[E : WaveExecutor] Scheduler::run_parallel_waves(self : Scheduler[E], target : String) -> Result[Array[String], String]

Execute independent waves without a shared mutable queue or lock.

#
TargetInspection

pub(all) struct TargetInspection {
target : String
producer_key : String?
direct_inputs : Array[String]
transitive_inputs : Array[String]
outputs : Array[String]
leaf_inputs : Array[String]
edge_count : Int
depth : Int
} derive(Eq,
Debug
)

A read-only explanation of the dependency closure of one target.

#
TargetInspection::to_text

fn TargetInspection::to_text(self : TargetInspection) -> String

#
Token

pub(all) enum Token {
Ident(String)
Colon
Equal
Pipe
PipePipe
Newline
Indent
Eof
Error(String)
} derive(Eq,
Debug
)

impl Show for Token

#
ValidationIssue

pub(all) struct ValidationIssue {
code : String
message : String
subject : String
severity : ValidationSeverity
} derive(Eq,
Debug
)

#
ValidationIssue::to_text

fn ValidationIssue::to_text(self : ValidationIssue) -> String

#
ValidationSeverity

pub(all) enum ValidationSeverity {
Error
Warning
} derive(Eq,
Debug
)

#
benchmark_from_ninja

fn benchmark_from_ninja(input : String, target : String) -> Result[BenchmarkReport, String]

#
build_path_directory

fn build_path_directory(path : String) -> String

#
build_path_extension

fn build_path_extension(path : String) -> String

#
build_path_stem

fn build_path_stem(path : String) -> String

#
build_report

fn build_report(target : String) -> BuildReport

Start an empty report for a target.

#
command_line_from_text

fn command_line_from_text(text : String) -> Result[CommandLine, String]

Build a structured command from a response-file-compatible token stream.

#
compare_dependencies

fn compare_dependencies(target : String, previous : Array[String], current : Array[String]) -> DependencyDiff

Compare old and new depfile inputs while preserving first-seen order.

#
diagnostics_for_graph

fn diagnostics_for_graph(error : String) -> Diagnostic

#
diagnostics_for_parse

fn diagnostics_for_parse(error : ParseError) -> Diagnostic

#
diagnostics_text

fn diagnostics_text(diagnostics : Array[Diagnostic]) -> String

#
execute_command

fn execute_command(cmd : String) -> Int

#
expand_command

fn expand_command(text : String, context : ExpansionContext) -> String

Expand a command and return an empty string for invalid recursive input. Call expand_command_checked when the caller needs the diagnostic.

#
expand_command_checked

fn expand_command_checked(text : String, context : ExpansionContext) -> Result[String, String]

Expand command placeholders. Missing named variables intentionally become empty strings, matching the permissive behavior of common build tools.

#
is_relative_build_path

fn is_relative_build_path(path : String) -> Bool

#
join_build_path

fn join_build_path(parts : Array[String]) -> Result[String, String]

#
materialize_response_command

fn materialize_response_command(command : String, files : Map[String, String]) -> Result[Array[String], String]

Expand @file references from an in-memory response-file table. Keeping file contents at the boundary makes this API usable on WASM-GC and JS.

#
normalize_build_path

fn normalize_build_path(path : String) -> Result[String, String]

Normalize a build path without consulting the host filesystem. Both slash styles are accepted so plans are reproducible across CI hosts.

#
parse_build_state

fn parse_build_state(text : String) -> Result[BuildState, String]

Parse the state format and reject malformed records instead of silently treating a corrupt cache as up to date.

#
parse_depfile

fn parse_depfile(text : String) -> Result[Depfile, String]

Parse one or more Make-style depfile rules. Multiple target rules are rejected so callers cannot silently apply the wrong dependency set.

#
parse_response_file

fn parse_response_file(text : String) -> Result[Array[String], String]

Parse the small, portable response-file language used by compiler drivers. It supports whitespace, single/double quotes, backslash escapes, and lines beginning with # comments. Shell expansion is intentionally out of scope.

#
synthetic_fixture

fn synthetic_fixture(layer_count~ : Int, fanout~ : Int) -> Manifest

Build a repeatable multi-layer workload for performance and boundary tests.