Skip to content

Building and Deployment

Sam Green edited this page Aug 26, 2026 · 2 revisions

Building and Deployment

Building

cargo build --release
cargo test
cargo clippy -- -D warnings

Cross-compile for Linux (from macOS)

brew install filosottile/musl-cross/musl-cross
rustup target add x86_64-unknown-linux-musl
./build-linux.sh

Produces a ~1.1 MB fully static binary that runs on any Linux x86_64 host regardless of the target's glibc.

The binary builds and runs on macOS for development, but with no cgroups available it runs in stub mode and collects nothing.

Dependencies

Runtime: Linux with cgroup v1 or v2; glibc 2.31+ or musl; nvidia-smi optional for GPU metrics.

Build: Rust 1.87+, declared as rust-version in Cargo.toml and enforced by a CI job pinned to that exact toolchain. clippy.toml carries the same number so clippy will not suggest APIs newer than the crate supports.

Only the build machine's toolchain matters — deployment is a static musl binary with no Rust runtime dependency.


Cutting a release

Tag a version and the release workflow does the rest:

# Bump the version in Cargo.toml and examples/modulefile first.
git tag -a v0.3.0 -m "logger-rs 0.3.0"
git push origin v0.3.0

The tag must match Cargo.toml exactly or the workflow fails — a binary whose --version contradicts the release it came from makes it impossible to tell what is actually deployed.

It publishes one tarball plus a SHA256:

logger-rs-<version>-x86_64-linux-musl.tar.gz
  logger-rs-<version>/
    bin/logger-rs        (755, static musl)
    bin/logger-rs.sh     (644, sourced)
    examples/gadi-job.pbs
    examples/modulefile
    README.md

The binary and the shell library ship together because they are a matched pair: the library invokes the binary by name from PATH, so a prefix holding one but not the other loads cleanly through module load and then fails at job start with a confusing "not found".

Before publishing, the workflow runs the full test suite and the schema contract test, verifies the binary is statically linked and self-reports the right version, shellchecks the library, and install-tests the tarball by unpacking it into a clean prefix and sourcing it exactly as the docs tell a user to.

workflow_dispatch runs everything except the publish step, so packaging can be rehearsed without cutting a release.

Publishing the module

Users install nothing. The tool lives in a shared project directory as a module, so a colleague needs only the two module lines from Quick Start. Handing people a binary to copy into ~/bin does not scale past a handful of users and leaves everyone on a different version.

VERSION=0.3.0
PREFIX=/g/data/gb02/logger-rs/$VERSION

mkdir -p "$PREFIX"
tar -xzf logger-rs-$VERSION-x86_64-linux-musl.tar.gz \
    -C "$PREFIX" --strip-components=1

That gives $PREFIX/bin/logger-rs and $PREFIX/bin/logger-rs.sh — the layout examples/modulefile expects. Verify the transfer with sha256sum -c.

Then point the modulefile at the new version. Users pick the change up on their next module load, with nothing to reinstall.

The install prefix must be on shared storage that every compute node can read, and jobs must request it with -l storage=. Remote loggers are exec'd by absolute path, so a binary the other nodes cannot see means a multi-node job measures only its head node.

The dashboard watcher picks up the output files automatically.

Deploying without a release

For a quick iteration you can skip the tarball, but stage both files together:

./build-linux.sh

scp target/x86_64-unknown-linux-musl/release/logger-rs \
    logger-rs.sh \
    gadi.nci.org.au:/g/data/gb02/logger-rs/<version>/bin/

Clone this wiki locally