crates/gunnar-build-thing/Cargo.toml
# gunnar's **build thing**, as the forge must find it: a `cdylib` named
# `gunnar-build-thing`.
#
# ## This crate is a SHIM, and the shim is the fix
#
# The recipe — the atoms, the columns, the variants, the receipt writer, the
# reachability gate — is `gunnar-recipe`. This crate is that crate's `pub use`
# plus one macro line, and it exists for one measured reason.
#
# For a lib target whose `crate-type` contains `cdylib`, cargo emits **no
# `--extra-filename`**: every unit of it writes the same
# `target/<profile>/deps/libgunnar_build_thing.rlib`. The recipe is reached BOTH
# as a `[build-dependencies]` (gunnar-cli's and gunnar-server's `build.rs` call
# `emit::write_receipt`) and as a normal dependency, and resolver 2 keeps those
# two feature resolutions apart — so there were two units, two `-C metadata`
# hashes, and one filename. Whichever finished last won and the build script
# linked the loser:
#
# mold: error: undefined symbol: gunnar_recipe::emit::write_receipt
#
# for a function that is in the source *and* in the rlib on disk — the
# disambiguators differed. MEASURED 2026-09-03: `cargo build
# --workspace` from cold went **red 6 times out of 8**, and a warm re-run was
# always green, which is why it survived so long: two boxes saw
# green on the same sha the same day. Upstream: rust-lang/cargo#6313.
#
# **Nothing build-depends on this crate**, so it has exactly one unit and the
# collision cannot happen. `gunnar-recipe` is a plain rlib, gets an
# `--extra-filename`, and its two units coexist.
#
# ## Why the split rather than dropping `cdylib`
#
# Because dwarves REFUSES a recipe crate that is not a cdylib, by name and by
# reading this very file: `dwarves/crates/dwarves/src/build_thing/code.rs:125-133`
# looks for a package called `<repo>-build-thing` and asserts its `[lib]
# crate-type` array contains `"cdylib"` — a wasm32 build of an rlib emits no
# `.wasm` to load. So the name and the crate-type are a contract with another
# repository, and they are kept exactly. What moved is the code behind them.
#
# ## There is no logic in here, and a guard says so
#
# `tests/no_logic_in_the_shim.rs` asserts that `src/lib.rs` contains nothing but
# the re-export, the macro and comments. That is not tidiness: the receipt's
# `hash` field is computed by `gunnar-recipe`'s `build.rs` over
# `gunnar-recipe/src/**/*.rs`, so anything that ran from *this* crate's sources
# would be outside the hash — provenance the coordinate silently would not
# cover. Keeping the shim empty makes that gap zero by construction instead of
# by attention.
[package]
name = "gunnar-build-thing"
# 0.1.1 with gunnar-recipe 0.1.1 (lane G-BOTH, 2026-10-26): `tests/no_logic_in_the_shim.rs` holds
# the two to one number (the coordinate names this crate built by that recipe).
version = "0.2.1"
edition = "2021"
rust-version = "1.85"
license.workspace = true
publish.workspace = true
authors.workspace = true
repository.workspace = true
description = "gunnar's build thing as the forge loads it: the wasm32 cdylib that exports nornir-build-thing's plugin ABI over gunnar-recipe's declaration. The recipe itself is the gunnar-recipe crate."
# Same version as `gunnar-recipe`, deliberately: a receipt's coordinate is
# `gunnar-build-thing:<version>` (`gunnar_recipe::recipe::KRATE`), so the
# version dwarves resolves and the version the recipe was built from have to be
# the same number or the coordinate names something that cannot be fetched.
[lib]
# The contract with dwarves, quoted in the header. `cdylib` is the wasm32
# module; `rlib` is what this crate's own `[[bin]]` and its tests link.
crate-type = ["cdylib", "rlib"]
[[bin]]
# `cargo run -p gunnar-build-thing -- emit` is the documented door that writes
# `.nornir/build-variants.toml`, and the emitted file's own header names that
# command. It stays spelled exactly that way — the recipe moved, the operator's
# command did not.
name = "gunnar-build-thing"
path = "src/main.rs"
[dependencies]
# The recipe. Everything this crate exports is this crate's, re-exported.
gunnar-recipe = { workspace = true }
# `export_build_thing!` and the `plugin::BuildThing` trait the macro needs in
# scope. Same registry/path entry as `gunnar-recipe`'s, through the workspace,
# so the two cannot resolve to different versions of the ABI — which would be a
# module exporting one contract over a declaration written against another.
nornir-build-thing = { workspace = true }
# `main.rs` reports failures with the `{:#}` chain, as the recipe's own writer
# does.
anyhow = "1"
[dev-dependencies]
# The plugin HOST — wasmtime — for `tests/wasm_plugin.rs`: it loads THIS crate's
# wasm32 build through the generic `PluginHandle` (the forge's situation, no
# gunnar dependency on the host side) and holds its answers equal to the native
# ones. This is the test that proves the split did not fork the answer.
nornir-build-thing = { workspace = true, features = ["plugin-host"] }