diff --git a/Dockerfile b/Dockerfile index b00ead2f4e755..6c35255698951 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,45 +1,86 @@ -FROM --platform=$BUILDPLATFORM ubuntu as build +# syntax=docker/dockerfile:1 + +FROM --platform=${BUILDPLATFORM} ubuntu:24.04 AS builder-base +# Configure the shell to exit early if any command fails, or when referencing unset variables. +# Additionally `-x` outputs each command run, this is helpful for troubleshooting failures. +SHELL ["/bin/bash", "-eux", "-o", "pipefail", "-c"] + +RUN \ + --mount=target=/var/lib/apt/lists,type=cache,sharing=locked \ + --mount=target=/var/cache/apt,type=cache,sharing=locked \ + < /etc/apt/apt.conf.d/keep-cache + + apt update && apt install -y --no-install-recommends \ + build-essential \ + curl \ + python3-venv \ + cmake +HEREDOC + ENV HOME="/root" +ENV PATH="$HOME/.venv/bin:$PATH" WORKDIR $HOME -RUN apt update \ - && apt install -y --no-install-recommends \ - build-essential \ - curl \ - python3-venv \ - cmake \ - && apt clean \ - && rm -rf /var/lib/apt/lists/* - -# Setup zig as cross compiling linker -RUN python3 -m venv $HOME/.venv -RUN .venv/bin/pip install cargo-zigbuild -ENV PATH="$HOME/.venv/bin:$PATH" +# Setup zig as cross compiling linker: +RUN < rust_target.txt ;; \ - "linux/amd64") echo "x86_64-unknown-linux-musl" > rust_target.txt ;; \ - *) exit 1 ;; \ - esac -# Update rustup whenever we bump the rust version -COPY rust-toolchain.toml rust-toolchain.toml -RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --target $(cat rust_target.txt) --profile minimal --default-toolchain none +# Install rust: ENV PATH="$HOME/.cargo/bin:$PATH" -# Installs the correct toolchain version from rust-toolchain.toml and then the musl target -RUN rustup target add $(cat rust_target.txt) - -# Build -COPY crates crates -COPY ./Cargo.toml Cargo.toml -COPY ./Cargo.lock Cargo.lock -RUN cargo zigbuild --bin uv --target $(cat rust_target.txt) --release -RUN cp target/$(cat rust_target.txt)/release/uv /uv -# TODO(konsti): Optimize binary size, with a version that also works when cross compiling -# RUN strip --strip-all /uv +COPY rust-toolchain.toml . +RUN <> rust-toolchain.toml + echo 'targets = [ "aarch64-unknown-linux-musl", "x86_64-unknown-linux-musl" ]' >> rust-toolchain.toml + # Add the relevant musl target triples (for a building binary with static linking): + # Workaround until `ensure` arrives: https://github.com/rust-lang/rustup/issues/2686#issuecomment-788825744 + rustup show +HEREDOC + +# Handle individual images differences for ARM64 / AMD64: +FROM builder-base AS builder-arm64 +ENV CARGO_BUILD_TARGET=aarch64-unknown-linux-musl + +FROM builder-base AS builder-amd64 +ENV CARGO_BUILD_TARGET=x86_64-unknown-linux-musl + +# Build app: +FROM builder-${TARGETARCH} AS builder-app +COPY crates/ crates/ +COPY Cargo.toml Cargo.lock . +ARG APP_NAME=uv +ARG CARGO_HOME=/usr/local/cargo +ARG RUSTFLAGS="-C strip=symbols -C relocation-model=static -C target-feature=+crt-static -C opt-level=z" +ARG TARGETPLATFORM +RUN \ + --mount=type=cache,target="/root/.cache/zig",id="zig-cache" \ + # Cache mounts (dirs for crates cache + build target): + # https://doc.rust-lang.org/cargo/guide/cargo-home.html#caching-the-cargo-home-in-ci + # CAUTION: As cargo uses multiple lock files (eg: `${CARGO_HOME}/{.global-cache,.package-cache,.package-cache-mutate}`), do not mount subdirs individually. + --mount=type=cache,target="${CARGO_HOME}",id="cargo-cache" \ + # This cache mount is specific enough that you may not have any concurrent builds needing to share it, communicate that expectation explicitly: + --mount=type=cache,target="target/",id="cargo-target-${APP_NAME}-${TARGETPLATFORM}",sharing=locked \ + # These are redundant as they're easily reconstructed from cache above. Use TMPFS mounts to exclude from cache mounts: + # TMPFS mount is a better choice than `rm -rf` command (which is risky on a cache mount that is shared across concurrent builds). + --mount=type=tmpfs,target="${CARGO_HOME}/registry/src" \ + --mount=type=tmpfs,target="${CARGO_HOME}/git/checkouts" \ + <