diff --git a/.cargo/config.toml b/.cargo/config.toml index cce0104f8e..5d1a7883f9 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -37,6 +37,11 @@ rustflags = [ #[target.x86_64-unknown-linux-gnu] #rustflags = ["-C", "linker=clang", "-C", "link-arg=-fuse-ld=lld"] +# mold is significantly faster and more memory-efficient than ld on aarch64 +[target.aarch64-unknown-linux-gnu] +linker = "clang" +rustflags = ["-C", "link-arg=-fuse-ld=mold"] + [env] RUST_TEST_THREADS = "40" diff --git a/dev/docker/Dockerfile.build-artifacts-container-aarch64 b/dev/docker/Dockerfile.build-artifacts-container-aarch64 index 1634065bb2..bb37d42ba8 100644 --- a/dev/docker/Dockerfile.build-artifacts-container-aarch64 +++ b/dev/docker/Dockerfile.build-artifacts-container-aarch64 @@ -16,6 +16,11 @@ # FROM arm64v8/rust:1.97.1-slim-bullseye +# Bullseye does not package mold. Keep this image on Bullseye for artifact +# compatibility and install the pinned upstream ARM64 binary instead. +ARG MOLD_VERSION=2.30.0 +ARG MOLD_SHA256=258aaf2b7808ea22fca625480efdf7a13830e9ee311716db0ba9c62af1770c07 + # Set in gitlab-templates/scripts/build-push-container-image.sh ARG CI_COMMIT_SHORT_SHA ENV CI_COMMIT_SHORT_SHA $CI_COMMIT_SHORT_SHA @@ -60,6 +65,21 @@ RUN CACHEKEY=${CI_COMMIT_SHORT_SHA} apt update && \ git \ && rm -rf /var/lib/apt/lists/* +RUN curl -fsSL --retry 5 \ + -o /tmp/mold.tar.gz \ + "https://github.com/rui314/mold/releases/download/v${MOLD_VERSION}/mold-${MOLD_VERSION}-aarch64-linux.tar.gz" && \ + echo "${MOLD_SHA256} /tmp/mold.tar.gz" | sha256sum --check - && \ + tar -C /usr/local --strip-components=1 -xzf /tmp/mold.tar.gz && \ + rm /tmp/mold.tar.gz && \ + mold --version + +# Keep the system linker for non-Rust builds such as iPXE, whose linker script +# is not accepted by mold. Cargo uses this wrapper even outside the repository. +RUN printf '#!/bin/sh\nexec clang -fuse-ld=mold "$@"\n' \ + >/usr/local/bin/clang-mold && \ + chmod 0755 /usr/local/bin/clang-mold +ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=/usr/local/bin/clang-mold + RUN rustup component add rustfmt RUN cargo install cargo-cache cargo-make sccache && \ cargo install mdbook@0.4.52 mdbook-plantuml@0.8.0 mdbook-mermaid@0.16.2 && \ diff --git a/dev/docker/Dockerfile.build-artifacts-container-cross-aarch64 b/dev/docker/Dockerfile.build-artifacts-container-cross-aarch64 index c051a4748b..a1e3a38a7f 100644 --- a/dev/docker/Dockerfile.build-artifacts-container-cross-aarch64 +++ b/dev/docker/Dockerfile.build-artifacts-container-cross-aarch64 @@ -21,7 +21,7 @@ FROM rust:1.97.1-bookworm RUN dpkg --add-architecture arm64 && \ apt-get update && \ apt-get upgrade -y && \ - apt-get -o Dpkg::Options::="--force-overwrite" install --assume-yes unzip libudev-dev:arm64 libssl-dev:arm64 libtss2-dev:arm64 g++-aarch64-linux-gnu libc6-dev-arm64-cross libclang-dev cmake + apt-get -o Dpkg::Options::="--force-overwrite" install --assume-yes unzip libudev-dev:arm64 libssl-dev:arm64 libtss2-dev:arm64 g++-aarch64-linux-gnu libc6-dev-arm64-cross libclang-dev cmake mold # protoc must match the image userspace (FROM rust:… resolves to host arch by default), # not the Rust target (aarch64); see prost-build protoc invocation. @@ -40,5 +40,16 @@ ENV PATH="/protobuf/bin:${PATH}" RUN rustup target add aarch64-unknown-linux-gnu -ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++ PKG_CONFIG_PATH=/lib/aarch64-linux-gnu/pkgconfig PKG_CONFIG_SYSROOT_DIR=/lib/aarch64-linux-gnu +# Keep the cross-GCC driver so it supplies the ARM64 sysroot, but make mold an +# invariant of that driver rather than relying on a mounted checkout's Cargo +# configuration. +RUN printf '#!/bin/sh\nexec aarch64-linux-gnu-gcc -fuse-ld=mold "$@"\n' \ + >/usr/local/bin/aarch64-linux-gnu-gcc-mold && \ + chmod 0755 /usr/local/bin/aarch64-linux-gnu-gcc-mold && \ + printf 'int main(void) { return 0; }\n' | \ + aarch64-linux-gnu-gcc-mold -x c - -o /tmp/mold-smoke && \ + readelf -p .comment /tmp/mold-smoke | grep -q mold && \ + rm /tmp/mold-smoke + +ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc-mold CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++ PKG_CONFIG_PATH=/lib/aarch64-linux-gnu/pkgconfig PKG_CONFIG_SYSROOT_DIR=/lib/aarch64-linux-gnu WORKDIR ./carbide diff --git a/dev/docker/Dockerfile.build-container-aarch64 b/dev/docker/Dockerfile.build-container-aarch64 index 4ef588dac4..5d3ec83f79 100644 --- a/dev/docker/Dockerfile.build-container-aarch64 +++ b/dev/docker/Dockerfile.build-container-aarch64 @@ -54,6 +54,7 @@ RUN CACHEKEY=${CI_COMMIT_SHORT_SHA} apt update && \ libssl-dev \ libtss2-dev \ libudev-dev \ + mold \ pandoc \ pkg-config \ tpm2-tools \ @@ -66,8 +67,12 @@ RUN CACHEKEY=${CI_COMMIT_SHORT_SHA} apt update && \ git \ && rm -rf /var/lib/apt/lists/* -# make LLVM's linker lld the default, because ld crashes using too much memory -RUN update-alternatives --install /usr/bin/ld ld /usr/bin/lld 50 +# Keep the system linker for non-Rust builds such as iPXE, whose linker script +# is not accepted by mold. Cargo uses this wrapper even outside the repository. +RUN printf '#!/bin/sh\nexec clang -fuse-ld=mold "$@"\n' \ + >/usr/local/bin/clang-mold && \ + chmod 0755 /usr/local/bin/clang-mold +ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=/usr/local/bin/clang-mold RUN rustup component add rustfmt RUN cargo install cargo-cache cargo-make sccache --locked && \ diff --git a/dev/docker/Dockerfile.cargo-docker-minimal b/dev/docker/Dockerfile.cargo-docker-minimal index 2f3538f87c..e39132c234 100644 --- a/dev/docker/Dockerfile.cargo-docker-minimal +++ b/dev/docker/Dockerfile.cargo-docker-minimal @@ -17,14 +17,24 @@ RUN apt-get update && \ protobuf-compiler \ libpq-dev \ libssl-dev \ + clang \ pkg-config \ lld \ + mold \ && rm -rf /var/lib/apt/lists/* +RUN printf '#!/bin/sh\nexec clang -fuse-ld=lld "$@"\n' \ + >/usr/local/bin/clang-lld && \ + printf '#!/bin/sh\nexec clang -fuse-ld=mold "$@"\n' \ + >/usr/local/bin/clang-mold && \ + chmod 0755 /usr/local/bin/clang-lld /usr/local/bin/clang-mold + # sccache: reuse compiled artifacts across runs (mount SCCACHE_DIR from host in run) RUN cargo install sccache --locked && rm -rf /usr/local/cargo/registry/src ENV RUSTC_WRAPPER=sccache ENV SCCACHE_DIR=/sccache -# Use lld for linking (uses less RAM than default ld; avoids OOM when linking carbide-api tests). +# Use lld on x86_64 and mold on aarch64 to avoid memory-heavy GNU ld links. # Enable tokio_unstable so tokio::task::Builder is available (used by api-db, api, etc.). -ENV RUSTFLAGS="-C link-arg=-fuse-ld=lld --cfg tokio_unstable" +ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=/usr/local/bin/clang-lld +ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=/usr/local/bin/clang-mold +ENV RUSTFLAGS="--cfg tokio_unstable" diff --git a/docs/development/build-guide.md b/docs/development/build-guide.md index 4b20566194..ee2b9d5a6e 100644 --- a/docs/development/build-guide.md +++ b/docs/development/build-guide.md @@ -1,5 +1,20 @@ # Build Guide +## Native Linux ARM64 Builds + +The repository's [Cargo configuration](../../.cargo/config.toml) selects Clang +with mold when building the `aarch64-unknown-linux-gnu` target. Before running +Cargo directly on a Linux ARM64 host, ensure that the `clang` and `mold` +executables are on `PATH`. On Debian or Ubuntu, install both packages with: + +```bash +sudo apt-get install -y clang mold +``` + +Without either executable, Cargo fails during linking. Containerized ARM64 +builds install both tools in their build images and do not require them on the +host. + ## Updating Pinned Dependencies ### Git submodules