Build::Rust
NAME
Build::Rust - build Rust crates at install time and locate their binaries at run time
SYNOPSIS
In your distribution's Build.rakumod:
use Build::Rust;
class Build does Build::Rust {
method crates {
crate 'psshaw', :on-missing<fetch>,
}
}In META6.json, list the binary as a resource and add the build dependency:
"build-depends": ["Build::Rust"],
"depends": ["Build::Rust", ...],
"resources": ["bin/psshaw", ...]At run time, wherever you need the binary:
use Resource::Wrangler;
use Build::Rust::Binary;
my $psshaw = Build::Rust::Binary.new:
:name<psshaw>,
:resources(Resource::Wrangler[-> { %?RESOURCES }].new),
:env<PANG_PSSHAW>;
run $psshaw.path, '--help';DESCRIPTION
Build::Rust lets a Raku distribution ship a binary built from Rust source that lives inside the distribution, typically as a git submodule. It has two halves.
The Build::Rust role is composed into the Build class that zef runs at install time. Each crate you declare is built with cargo and its binaries are copied to resources/bin/, so they install with the distribution. Cargo is the incremental authority: it is always invoked and no-ops when nothing changed.
Build::Rust::Binary finds that binary again at run time. From a checkout the resource is the file in resources/bin/ itself and is used in place. Once installed, a resource lives in the CompUnit store with no execute bit, so it is staged out first to a private per-user directory ā XDG_RUNTIME_DIR or $*TMPDIR when that is a directory we own that nobody else can write to, else $*HOME/.cache/build-rust ā keyed by the resource's size and mtime so a reinstall never reuses a stale copy.
DECLARING CRATES
crate $path, *%opts returns a Build::Rust::Crate. $path is the crate's directory relative to the distribution root; Cargo.toml must be there.
:binsā names of the[[bin]]targets to ship. Defaults to the basename of$path. Nothing is read fromCargo.toml; you say what you mean.:profileārelease(default),dev, or a custom profile name.:featuresā list of cargo features.:on-missingā what to do when the crate's source is absent:die(default) stops with instructions;fetchrunsgit submodule update --init --recursivefor that path, which needs a git checkout with a.gitmodules;skipnotes the absence and carries on, so the installed distribution has no binary andBuild::Rust::Binary.availableisFalse.
To declare several crates, parenthesise each call:
method crates {
crate('psshaw', :on-missing<fetch>),
crate('tools', :bins<fmt lint>),
}cargo is found on PATH, or via $CARGO if that is set. If the built binary is not listed under resources in META6.json, the build warns that it will not ship.
LOCATING BINARIES
Build::Rust::Binary.new(:name, :resources, :env)
:nameā the binary's name, without any.exe.:resourcesā an object withAT-KEYandload-resource-to-path, such asResource::Wrangler[-> { %?RESOURCES }].new. The closure is what carries your distribution's%?RESOURCESacross the module boundary.:envā optional. If this environment variable is set, it must name an executable file, which is used instead of the shipped binary.
.path returns the absolute path of a runnable copy, resolved once per instance (the module-scoped singleton in the SYNOPSIS makes that once per process in practice); it dies with instructions when there is nothing to run. .available answers whether .path would succeed, without staging anything.
AUTHOR
ab5tract [email protected]
COPYRIGHT AND LICENSE
Copyright 2026 ab5tract
This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.