A progressively enhanced build orchestrator in Rust. neomake reads a
TOML (or TOMLX) configuration file, builds a dependency DAG, runs tasks
concurrently on a tokio executor, and skips unchanged work via a
SHA-256 content-addressable cache.
- TOML in, TOML out. Your build file starts as plain TOML. When you
need more, opt in to TOMLX — a strict superset adding variables,
value-level conditionals, and a small library of built-ins
(
env,glob,exec). - Parallel by default. Tasks with no dependency run concurrently.
Concurrency is capped with
--concurrency N(default: number of CPUs). - Content-addressable cache. Each task's cache key is a SHA-256 of its command, env, sorted input file hashes, and the cache keys of its upstream dependencies, so a change anywhere in the transitive input closure invalidates every dependent.
- Clear diagnostics. Cycle detection reports the concrete cycle path; every config error carries a file name and line number.
neomake/ CLI binary
neomake-core/ task model, DAG builder, cache, tokio executor
neomake-tomlx/ TOMLX lexer, parser, evaluator
examples/ basic.toml, advanced.tomlx
docs/tomlx-spec.md formal TOMLX spec
Requires a recent stable Rust toolchain (1.75+).
cargo install --path neomakeA cargo build --release at the workspace root produces
target/release/neomake.
neomake is available from the AUR. With yay or paru:
yay -S neomake
# or
paru -S neomakeOther repositories can call the reusable workflow to install neomake
from this repo and run it against the caller’s checkout:
jobs:
ci:
uses: sinisterMage/neomake/.github/workflows/reusable-neomake.yml@main
with:
neomake-ref: main
config-path: neomake.tomlSee .github/workflows/reusable-neomake.yml
for all inputs (working-directory, tasks, concurrency, extra-args, …).
neomake runs on Linux, macOS, and Windows. Task commands are passed
to a shell whose choice depends on the host:
- Unix-likes —
sh -c <command>. - Windows —
pwsh -NoProfile -NoLogo -Command <command>if PowerShell 7+ is onPATH, otherwisepowershell.exe(Windows PowerShell 5.1), otherwisecmd.exe /S /Cas a last-resort fallback.
Set NEOMAKE_SHELL to override; its value is whitespace-tokenized as
argv and the user's command is appended as the final argument:
NEOMAKE_SHELL="bash -c" neomake run # force bash
NEOMAKE_SHELL="cmd /S /C" neomake run # force cmd.exe on WindowsCache compatibility. This release bumps the cache format to
neomake-cache-v2so input paths are hashed with portable/separators. Existing entries written by an older neomake will miss on first run after upgrading; useneomake cache cleanif you want to reclaim the disk space immediately.
Windows PowerShell 5.1 redirection.
>writes UTF-16 + BOM by default in 5.1 (this is fixed in pwsh / PowerShell 7+). For deterministic byte-level output, preferpwshor useSet-Content -Encoding ascii/-Encoding utf8NoBOMinstead.
Create neomake.toml:
[tasks.build]
command = "cargo build --release"
inputs = ["src/**/*.rs", "Cargo.toml"]
outputs = ["target/release/myapp"]
[tasks.test]
command = "cargo test"
deps = ["build"]Then:
neomake run # builds all leaves (test → build)
neomake run build # builds just `build` and its deps
neomake list # shows the DAG in topological order
neomake cache status # prints cache entry count and size
neomake cache clean # empties the cache directoryneomake [OPTIONS] <SUBCOMMAND>
Subcommands:
run [TASK]... Run tasks (defaults to all tasks)
list Print tasks in topological order
cache clean Remove every cache entry
cache status Print cache size and entry count
Options:
-c, --config <FILE> Path to config; auto-detects neomake.toml or neomake.tomlx
--concurrency <N> Max parallel shell commands (default: num_cpus)
--no-cache Treat every task as a cache miss
-q, --quiet Suppress per-task stdout/stderr forwarding
Set NEOMAKE_LOG=debug to turn on tracing diagnostics.
| Feature | Syntax |
|---|---|
| Variable declaration | $profile = "release" |
| Variable reference | ${profile} (in strings) / $profile (in expressions) |
| String interpolation | "target/${profile}/app" |
| String concatenation | "cargo build" + " --release" |
| Conditional value | if ${ci} { "make ci" } else { "make" } |
| Environment access | env("PROFILE", "debug") |
| File globbing | glob("src/**/*.rs") |
| Command execution | exec("git rev-parse HEAD") |
See docs/tomlx-spec.md for the full grammar and
semantics, and examples/advanced.tomlx for
a complete example.
┌───────────────────┐ ┌──────────────────────────┐
│ *.toml / *.tomlx │──────▶│ neomake-tomlx │
└───────────────────┘ │ (lexer / parser / eval) │
└───────────┬──────────────┘
│ toml::Value
▼
┌──────────────────────────┐
│ neomake-core │
│ TaskSet → DAG │
│ │ │
│ ▼ │
│ Executor (tokio) │
│ │ │
│ ▼ │
│ Cache (.neomake/cache) │
└──────────────────────────┘
- DAG construction uses Kahn's algorithm for topological sorting; if
a cycle is detected, an iterative DFS recovers the concrete cycle
path (e.g.
a -> b -> c -> a) and reports it. - Cache keys are SHA-256 over a versioned canonical byte layout
(
neomake-cache-v1) built from the command, env, sorted input file hashes, and upstream dep keys. Seeneomake-core/src/cache.rsfor the exact format. - Parallel execution uses one tokio task per DAG node, a per-task
watchchannel to propagate outcomes to dependents, and aSemaphoreto cap concurrent shell commands. Cache hits bypass the semaphore entirely.
MIT