This commit is contained in:
Amaan Qureshi 2026-06-16 00:15:25 -04:00 committed by GitHub
commit c3dc093b85
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 53 additions and 66 deletions

View file

@ -1,16 +1,16 @@
# Use a linker wrapper that invokes mold then strips junk sections with objcopy. # Link the tier-1 Linux arches with the wild linker, driven by clang via the
# mold cannot discard .eh_frame/.dynstr/.comment via linker scripts, so we do # scripts/clang-wild wrapper.
# it as a post-link step.
# See:
# <https://github.com/rui314/mold?tab=readme-ov-file#how-to-use>
# #
# Binary-specific link flags live in microfetch/build.rs via cargo:rustc-link-arg-bin # Binary-specific link flags live in microfetch/build.rs via cargo:rustc-link-arg-bin
# so they only affect the final binary and don't break proc-macro or build-script linking. # so they only affect the final binary and don't break proc-macro or build-script linking.
[target.'cfg(target_os = "linux")'] [target.'cfg(target_os = "linux")']
linker = "scripts/ld-wrapper" # Suppress .eh_frame emission from our own codegen.
rustflags = [ rustflags = ["-C", "force-unwind-tables=no"]
# Suppress .eh_frame emission from our own codegen (does not cover compiler_builtins;
# those remnants are removed by the linker wrapper via objcopy post-link) [target.x86_64-unknown-linux-gnu]
"-C", linker = "scripts/clang-wild"
"force-unwind-tables=no", rustflags = ["-C", "force-unwind-tables=no"]
]
[target.aarch64-unknown-linux-gnu]
linker = "scripts/clang-wild"
rustflags = ["-C", "force-unwind-tables=no"]

View file

@ -19,8 +19,10 @@ jobs:
with: with:
rustflags: "" rustflags: ""
- name: Make Mold the default linker - name: Install the wild linker
uses: rui314/setup-mold@v1 uses: wild-linker/action@0.9.0
- name: Put wild on PATH
run: echo "$RUNNER_TEMP/wild-install" >> "$GITHUB_PATH"
- name: Create metrics directory - name: Create metrics directory
run: mkdir -p /tmp/metrics run: mkdir -p /tmp/metrics

View file

@ -73,8 +73,10 @@ jobs:
if: ${{ !matrix.build_std }} if: ${{ !matrix.build_std }}
run: rustup target add ${{ matrix.target }} run: rustup target add ${{ matrix.target }}
- name: "Make Mold the default linker" - name: "Install the wild linker"
uses: rui314/setup-mold@v1 uses: wild-linker/action@0.9.0
- name: "Put wild on PATH"
run: echo "$RUNNER_TEMP/wild-install" >> "$GITHUB_PATH"
- name: "Setup cross-compilation toolchain" - name: "Setup cross-compilation toolchain"
uses: taiki-e/setup-cross-toolchain-action@v1 uses: taiki-e/setup-cross-toolchain-action@v1

View file

@ -59,7 +59,8 @@ welcome to use it on your system: it is pretty _[fast](#benchmarks)_...
- Respects [`NO_COLOR` spec](https://no-color.org/) - Respects [`NO_COLOR` spec](https://no-color.org/)
- Funny [^1] - Funny [^1]
[^1]: I don't know how else to describe the (unhealthy) amount of handwritten [^1]:
I don't know how else to describe the (unhealthy) amount of handwritten
assembly that was written in order to make Microfetch faster. assembly that was written in order to make Microfetch faster.
## Motivation ## Motivation
@ -234,7 +235,7 @@ interested in Microfetch tailored to their distributions.
## Customizing ## Customizing
You can't* You can't\*
### Really? ### Really?
@ -302,17 +303,19 @@ A Nix flake is provided. You may use `nix develop` to get started. Direnv users
may instead run `direnv allow` to get a complete environment with shell may instead run `direnv allow` to get a complete environment with shell
integration. integration.
Non-Nix user will need `cargo`, `clang` and `mold` installed on their system to Non-Nix users will need `cargo`, `clang` and [`wild`] on their `PATH` to build
build Microfetch. As Mold seems to yield _slightly_ better results than the Microfetch. `wild` is faster than the default linker and emits a tighter binary,
default linker, it has been set as the default in `.cargo/config.toml` for so it is set as the linker (via `clang`) in `.cargo/config.toml` for x86-64 and
x86-64 Linux. You may override those defaults using the `RUSTFLAGS` environment aarch64 Linux. To use a different linker, override it with the `RUSTFLAGS`
variable. For example: environment variable. For example:
```sh ```sh
# Use ld instead of Mold # Use ld instead of wild
$ RUSTFLAGS="-C linker=/path/to/ld.lld" cargo build $ RUSTFLAGS="-C linker=/path/to/ld.lld" cargo build
``` ```
[`wild`]: https://github.com/wild-linker/wild
## Thanks ## Thanks
Huge thanks to everyone who took the time to make pull requests or nag me in Huge thanks to everyone who took the time to make pull requests or nag me in

View file

@ -2,12 +2,20 @@
lib, lib,
rustPlatform, rustPlatform,
llvm, llvm,
clang,
wild,
}: let }: let
pname = "microfetch"; pname = "microfetch";
toml = (lib.importTOML ../Cargo.toml).workspace.package; toml = (lib.importTOML ../Cargo.toml).workspace.package;
inherit (toml) version; inherit (toml) version;
inherit (llvm) stdenv;
# wild + clang are only used on Linux tier-1 arches
hasWild =
stdenv.hostPlatform.isLinux
&& (stdenv.hostPlatform.isx86_64 || stdenv.hostPlatform.isAarch64);
in in
rustPlatform.buildRustPackage.override {inherit (llvm) stdenv;} (finalAttrs: { rustPlatform.buildRustPackage.override {inherit stdenv;} (finalAttrs: {
__structuredAttrs = true; __structuredAttrs = true;
inherit pname version; inherit pname version;
@ -21,12 +29,17 @@ in
(s + /.cargo) (s + /.cargo)
(s + /crates) (s + /crates)
(s + /microfetch) (s + /microfetch)
(s + /scripts/ld-wrapper)
(s + /Cargo.lock) (s + /Cargo.lock)
(s + /Cargo.toml) (s + /Cargo.toml)
]; ];
}; };
nativeBuildInputs = lib.optionals hasWild [wild clang];
env = lib.optionalAttrs hasWild {
RUSTFLAGS = "-Cforce-unwind-tables=no -Clinker=${clang}/bin/clang -Clink-arg=--ld-path=${wild}/bin/wild";
};
cargoLock.lockFile = "${finalAttrs.src}/Cargo.lock"; cargoLock.lockFile = "${finalAttrs.src}/Cargo.lock";
enableParallelBuilding = true; enableParallelBuilding = true;
buildNoDefaultFeatures = true; buildNoDefaultFeatures = true;

View file

@ -2,7 +2,7 @@
mkShell, mkShell,
cargo, cargo,
rustc, rustc,
mold, wild,
clang, clang,
rust-analyzer, rust-analyzer,
rustfmt, rustfmt,
@ -16,7 +16,7 @@ mkShell {
nativeBuildInputs = [ nativeBuildInputs = [
cargo cargo
rustc rustc
mold wild
clang clang
rust-analyzer rust-analyzer

5
scripts/clang-wild Executable file
View file

@ -0,0 +1,5 @@
#!/usr/bin/env sh
# Link via clang+wild. Wild sits behind the linker (not a rustflag) so a
# cross-toolchain that overrides the linker drops it instead of choking on
# --ld-path. Needs clang and wild on PATH.
exec clang --ld-path=wild "$@"

View file

@ -1,38 +0,0 @@
#!/usr/bin/env sh
# Invoke mold, then strip junk sections from the output binary with objcopy.
# This (more or less) removes sections that mold cannot discard itself, such as:
# - .eh_frame / .eh_frame_hdr - unwind tables from compiler_builtins
# - .dynstr - mold emits this, even for fully static binaries
# - .comment - compiler version string
#
# We forward everything to mold via -fuse-ld, then post-process the output in place.
set -eu
# Locate the output file and detect static linking
IS_STATIC=0
OUTPUT=""
prev=""
for arg in "$@"; do
case "$arg" in
-static) IS_STATIC=1 ;;
esac
if [ "$prev" = "-o" ]; then
OUTPUT="$arg"
fi
prev="$arg"
done
# Invoke mold via the cc driver, forward all original arguments
cc -fuse-ld=mold "$@"
# Only strip sections from fully static binaries.
# Dynamic executables (i.e. build scripts, proc-macros) need .dynstr at runtime.
if [ "$IS_STATIC" = 1 ] && [ -n "$OUTPUT" ] && [ -f "$OUTPUT" ]; then
objcopy \
--remove-section=.eh_frame \
--remove-section=.eh_frame_hdr \
--remove-section=.dynstr \
--remove-section=.comment \
"$OUTPUT"
fi