From ab1adbd5e344c1877f908f818341f3bdbefecc6e Mon Sep 17 00:00:00 2001 From: Surma Date: Fri, 23 Oct 2026 10:20:39 +0100 Subject: [PATCH] flake: link host code with mold on Linux; DECISIONS: mold, and no LTO mold applies to the host target only, in the dev shell, the crane builds, and the packaged binary (proc macros and build scripts of plugins). A rebuild of the host test binary after a change takes 0.9 s (15 s with GNU ld). Measured LTO: no gain worth 4 more minutes per release build. --- DECISIONS.md | 7 +++++++ flake.nix | 26 +++++++++++++++++++------- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/DECISIONS.md b/DECISIONS.md index 5bcdd6f..f0310ab 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -75,6 +75,13 @@ a plugin, or a change that the agent makes to itself. `sdk//`. A path that depends only on the content of the SDK lets cargo reuse the compiled SDK in every world. Tests run in the release profile, so that they share compiled crates with the release build. +- **mold links host code where Nix provides it.** On Linux, the dev shell, + the Nix builds, and the packaged `sausage` (for the proc macros and build + scripts of plugins) link with mold, much faster than GNU ld. Plugins for + `wasm32-wasip2` link with rust-lld. Without Nix, the default linker stays. +- **No LTO.** Measured: fat LTO makes the binary 28 % smaller, but compiles + plugins and answers calls at most 5–8 % faster, for 4 more minutes per + release build. Thin LTO brings nothing. - **Discovery has a deadline of 10 seconds.** It is an internal call of the core, not a limit on plugins. Without it, one plugin that does not answer would block every activation. diff --git a/flake.nix b/flake.nix index 42d8304..7819a1e 100644 --- a/flake.nix +++ b/flake.nix @@ -25,7 +25,17 @@ # the native linker, even when the host itself is started with a bare # PATH. Keep this same runtime path in the packaged host and exercise # the installed binary below with PATH deliberately empty. - runtimePath = pkgs.lib.makeBinPath [ rust pkgs.stdenv.cc ]; + # mold links host code much faster than GNU ld. Only on Linux, and only + # for the host target: plugins for wasm32-wasip2 link with rust-lld. Nix + # brings mold along, so a build without Nix keeps the default linker. + mold = pkgs.lib.optionals pkgs.stdenv.hostPlatform.isLinux [ pkgs.mold ]; + hostTarget = pkgs.lib.toUpper (builtins.replaceStrings [ "-" ] [ "_" ] + pkgs.stdenv.hostPlatform.rust.rustcTarget); + moldVar = "CARGO_TARGET_${hostTarget}_RUSTFLAGS"; + moldEnv = pkgs.lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux { + ${moldVar} = "-C link-arg=-fuse-ld=mold"; + }; + runtimePath = pkgs.lib.makeBinPath ([ rust pkgs.stdenv.cc ] ++ mold); # A WASI clang with wasi-libc, so that build scripts (the `cc` crate) # can compile C for wasm32-wasip2. Its headers are WASI 0.1: C code # that needs sockets does not build. @@ -39,7 +49,8 @@ pname = "sausage"; version = "0.1.0"; src = ./.; - }; + nativeBuildInputs = mold; + } // moldEnv; # The test packages for `checks.tests`. testPackages = "--workspace"; cargoArtifacts = craneLib.buildDepsOnly (common // { @@ -55,13 +66,14 @@ doNotRemoveReferencesToRustToolchain = true; cargoExtraArgs = "--locked -p sausage"; doCheck = false; - nativeBuildInputs = [ pkgs.makeWrapper ]; + nativeBuildInputs = [ pkgs.makeWrapper ] ++ mold; # The native `cargo` plugin runs cargo at runtime. Build scripts need a C linker, # and C code for WASI needs the WASI clang. postInstall = '' wrapProgram $out/bin/sausage --prefix PATH : ${runtimePath} \ --set-default CC_wasm32_wasip2 ${wasiCcEnv.CC_wasm32_wasip2} \ - --set-default AR_wasm32_wasip2 ${wasiCcEnv.AR_wasm32_wasip2} + --set-default AR_wasm32_wasip2 ${wasiCcEnv.AR_wasm32_wasip2} \ + ${pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isLinux "--set-default ${moldVar} '-C link-arg=-fuse-ld=mold'"} ''; meta.mainProgram = "sausage"; }); @@ -101,7 +113,7 @@ # Nothing builds on the test run's target folder: don't store it. doInstallCargoArtifacts = false; # The SDK tests run sample plugins with the wasmtime CLI. - nativeBuildInputs = [ pkgs.wasmtime ]; + nativeBuildInputs = [ pkgs.wasmtime ] ++ mold; }); # Exercise the installed host exactly as the loop launches it: the # caller has no Cargo on PATH, so only the packaged runtime toolchain @@ -191,8 +203,8 @@ apps.default = { type = "app"; program = "${sausage}/bin/sausage"; }; apps.loop = { type = "app"; program = "${loop}/bin/sausage-loop"; }; - devShells.default = pkgs.mkShell (wasiCcEnv // { - packages = [ rust pkgs.wasmtime pkgs.wasm-tools ]; + devShells.default = pkgs.mkShell (wasiCcEnv // moldEnv // { + packages = [ rust pkgs.wasmtime pkgs.wasm-tools ] ++ mold; shellHook = '' export CARGO_HOME="$PWD/.cargo-home" '';