diff --git a/contrib/guix/guix-build b/contrib/guix/guix-build index 9d61133e3..a99c0d584 100755 --- a/contrib/guix/guix-build +++ b/contrib/guix/guix-build @@ -270,6 +270,40 @@ mkdir -p "$OUTDIR_BASE" LOGDIR_BASE="${LOGDIR_BASE:-${VERSION_BASE}/logs}" mkdir -p "$LOGDIR_BASE" +# Download and archive Rust dependencies. +# When Cargo.lock is updated: increment RUST_DEPS_VERSION, update +# RUST_DEPS_HASH with the hash reported below, and update +# contrib/guix/rust/config.toml if the set of git sources changed +RUST_DEPS_VERSION=0 +RUST_DEPS_HASH="gg5izydrra2b1ywgskvlrfrh983gf6b4" +RUST_DEPS_ARCHIVE="rust_deps-${RUST_DEPS_VERSION}.tar.gz" +#UNCOMMENT_IN_10359# RUST_DEPS_STORE_ITEM="/gnu/store/${RUST_DEPS_HASH}-${RUST_DEPS_ARCHIVE}" +#UNCOMMENT_IN_10359# if [ ! -f "${RUST_DEPS_STORE_ITEM}" ]; then +if false; then #REMOVE_IN_10359# + time-machine environment --manifest="${PWD}/contrib/guix/rust/cargo.scm" \ + --container \ + --pure \ + --network \ + --no-cwd \ + --writable-root \ + --share="$PWD"=/monero \ + -- env RUST_DEPS_ARCHIVE="$RUST_DEPS_ARCHIVE" \ + bash /monero/contrib/guix/rust/cargo.sh + + RUST_DEPS_ADDED_ITEM="$(time-machine download "${RUST_DEPS_ARCHIVE}" | grep --max-count=1 '^/gnu/store/')" + rm ${RUST_DEPS_ARCHIVE} + + if [ "${RUST_DEPS_ADDED_ITEM}" != "${RUST_DEPS_STORE_ITEM}" ]; then + cat << EOF +ERR: The vendored Rust dependencies do not hash to the expected store item. + + expected: ${RUST_DEPS_STORE_ITEM} + actual: ${RUST_DEPS_ADDED_ITEM} +EOF + exit 1 + fi +fi + # Download the depends sources now as we won't have internet access in the build # container for host in $HOSTS; do @@ -450,6 +484,7 @@ EOF --share="$DISTSRC_BASE"=/distsrc-base \ --share="$OUTDIR_BASE"=/outdir-base \ --share="$LOGDIR_BASE"=/logdir-base \ + ${RUST_DEPS_STORE_ITEM:+--expose="$RUST_DEPS_STORE_ITEM"=/rust-deps} \ --expose="$(git rev-parse --git-common-dir)" \ ${SOURCES_PATH:+--share="$SOURCES_PATH"} \ ${BASE_CACHE:+--share="$BASE_CACHE"} \ diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh index 5c4f58f15..eb3b86454 100644 --- a/contrib/guix/libexec/build.sh +++ b/contrib/guix/libexec/build.sh @@ -85,6 +85,10 @@ unset OBJCPLUS_INCLUDE_PATH NATIVE_GCC="$(store_path gcc-toolchain)" +NATIVE_GCC_VERSION="${NATIVE_GCC##*-gcc-toolchain-}" +NATIVE_GCC_VERSION="${NATIVE_GCC_VERSION%%-*}" +NATIVE_GCC_LIB="$(find /gnu/store -maxdepth 1 -name "*-gcc-${NATIVE_GCC_VERSION}-lib" | sort | head -n 1)" + export C_INCLUDE_PATH="${NATIVE_GCC}/include" export CPLUS_INCLUDE_PATH="${NATIVE_GCC}/include/c++:${NATIVE_GCC}/include" export OBJC_INCLUDE_PATH="${NATIVE_GCC}/include" @@ -132,7 +136,7 @@ case "$HOST" in # See depends/hosts/darwin.mk for more details. ;; *android*) - export LD_LIBRARY_PATH="$(find /gnu/store -maxdepth 1 -name "*zlib*" | sort | head -n 1)/lib:$(find /gnu/store -maxdepth 1 -name "*gcc-14*-lib" | sort | head -n 1)/lib" + export LD_LIBRARY_PATH="$(find /gnu/store -maxdepth 1 -name "*zlib*" | sort | head -n 1)/lib:${NATIVE_GCC_LIB}/lib" ;; *linux-gnu*) CROSS_GLIBC="$(store_path "glibc-cross-${HOST}")" @@ -301,6 +305,31 @@ case "$HOST" in *mingw*) HOST_LDFLAGS="-Wl,--no-insert-timestamp" ;; esac +LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}${NATIVE_GCC_LIB}/lib" + +RUST_STD="$(store_path rust-std)" + +# error: "/gnu/store/<...>-rust-1.82.0/lib/rustlib/src/rust/library/Cargo.lock" does not exist, +# unable to build with the standard library +# +# The standard library does not exist at the location Cargo expects. +# +# We can override the path to the Rust source by setting the __CARGO_TESTS_ONLY_SRC_ROOT environment variable. +# See: https://github.com/rust-lang/cargo/blob/rust-1.82.0/src/cargo/core/compiler/standard_lib.rs#L183 +export __CARGO_TESTS_ONLY_SRC_ROOT="${RUST_STD}/library" + +# error: the `-Z` flag is only accepted on the nightly channel of Cargo, but this is the `stable` channel +# +# Since we don't have access to the nightly channel, we need to bypass the check with RUSTC_BOOTSTRAP. +# +# We could avoid using `-Z build-std` by cross-compiling the full standard library for each target. This approach +# adds hours to our build time and greatly increases the amount of foreign source code that is compiled as part of +# our build process. +export RUSTC_BOOTSTRAP=1 + +# See: https://rust-lang.github.io/rust-project-goals/2025h1/build-std.html +CARGO_OPTIONS="-Zbuild-std=std,panic_abort;" + export GIT_DISCOVERY_ACROSS_FILESYSTEM=1 # Force Trezor support for release binaries export USE_DEVICE_TREZOR_MANDATORY=1 @@ -338,6 +367,23 @@ mkdir -p "$DISTSRC" # Turn off unused default options CMAKEFLAGS+=" -DCOMPILER_CACHE=none -DBUILD_DOCUMENTATION=OFF" + # Make sure cargo knows where to find the vendored sources. + mkdir -p "${HOME}/.cargo" + cp contrib/guix/rust/config.toml "${HOME}/.cargo/" + + # Unpack rust dependencies + mkdir -p /rust/vendor + #UNCOMMENT_IN_10359# tar xf /rust-deps -C /rust + + # "vendor" rust std + for dir in "${RUST_STD}"/vendor/*/; do + [ -d "$dir" ] || continue + BN=$(basename "$dir") + if [ ! -d "/rust/vendor/$BN" ]; then + ln -s "$dir" "/rust/vendor/$BN" + fi + done + # Configure this DISTSRC for $HOST # shellcheck disable=SC2086 env CFLAGS="${HOST_CFLAGS}" CXXFLAGS="${HOST_CXXFLAGS}" \ @@ -345,9 +391,10 @@ mkdir -p "$DISTSRC" -DCMAKE_INSTALL_PREFIX="${INSTALLPATH}" \ -DCMAKE_EXE_LINKER_FLAGS="${HOST_LDFLAGS}" \ -DCMAKE_SHARED_LINKER_FLAGS="${HOST_LDFLAGS}" \ + -DCARGO_OPTIONS="${CARGO_OPTIONS}" \ ${CMAKEFLAGS} - make -C build --jobs="$JOBS" + LD_LIBRARY_PATH="${LD_LIBRARY_PATH}" make -C build --jobs="$JOBS" # Copy docs cp README.md LICENSE docs/ANONYMITY_NETWORKS.md "${INSTALLPATH}" diff --git a/contrib/guix/manifest.scm b/contrib/guix/manifest.scm index b9b7909d3..2a3baddd3 100644 --- a/contrib/guix/manifest.scm +++ b/contrib/guix/manifest.scm @@ -214,6 +214,36 @@ chain for " target " development.")) (delete "make") (append gnu-make-4.2))))) ;; make >= 4.4 causes an infinite loop (stdio-common) +(define-public rust-std + (package + (name "rust-std") + (version (package-version rust)) + ;; You'd expect (source (package-source (rust)) to work here, + ;; but it refers to the source store item and NOT the .tar.gz archive + (source (origin + (method url-fetch) + (uri (origin-uri (package-source rust))) + (sha256 + (content-hash-value (origin-hash (package-source rust)))))) + (build-system trivial-build-system) + (native-inputs (list tar gzip)) + (arguments + `(#:modules ((guix build utils)) + #:builder + (begin + (use-modules (guix build utils)) + (let ((out (assoc-ref %outputs "out")) + (source (assoc-ref %build-inputs "source")) + (tar (search-input-file %build-inputs "/bin/tar")) + (gzip (search-input-file %build-inputs "/bin/gzip")) + (gzip-path (string-append (assoc-ref %build-inputs "gzip") "/bin"))) + (setenv "PATH" gzip-path) + (mkdir out) + (invoke tar "xvf" source "-C" out "--strip-components=1"))))) + (synopsis (package-synopsis rust)) + (description (package-description rust)) + (home-page (package-home-page rust)) + (license (package-license rust)))) ; This list declares which packages are included in the container environment. It ; should reflect the minimal set of packages we need to build and debug the build @@ -262,6 +292,7 @@ chain for " target " development.")) cmake-minimal rust (list rust "cargo") + rust-std ;; Scripting perl ; required to build openssl in depends diff --git a/contrib/guix/rust/cargo.scm b/contrib/guix/rust/cargo.scm new file mode 100644 index 000000000..a8e62d955 --- /dev/null +++ b/contrib/guix/rust/cargo.scm @@ -0,0 +1,26 @@ +(use-modules ((gnu packages base) #:select (coreutils-minimal diffutils findutils tar)) + ((gnu packages bash) #:select (bash-minimal)) + ((gnu packages compression) #:select (gzip)) + ((gnu packages curl) #:select (curl)) + ((gnu packages nss) #:select (nss-certs)) + ((gnu packages rust) #:select (rust))) + +(packages->manifest + (append + (list + ;; The Basics + bash-minimal + coreutils-minimal + + ;; File(system) inspection + findutils ;; find + diffutils ;; diff + + ;; Cargo + (list rust "cargo") + curl ;; networking + nss-certs ;; idem + + ;; Compression + gzip + tar))) diff --git a/contrib/guix/rust/cargo.sh b/contrib/guix/rust/cargo.sh new file mode 100644 index 000000000..9dc497823 --- /dev/null +++ b/contrib/guix/rust/cargo.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -e -o pipefail + +# Environment variables for determinism +export LC_ALL=C +export SOURCE_DATE_EPOCH=1397818193 +export TAR_OPTIONS="--owner=0 --group=0 --numeric-owner --mtime='@${SOURCE_DATE_EPOCH}' --sort=name" +export TZ="UTC" +umask 0022 + +# Vendor fcmp_pp_rust deps +echo "Fetching rust dependencies.." +cd /monero/src/fcmp_pp/fcmp_pp_rust +cargo vendor --locked /rust/vendor > /tmp/config.toml + +if ! diff --unified /monero/contrib/guix/rust/config.toml /tmp/config.toml; then + echo "" + echo "ERR: contrib/guix/rust/config.toml does not match the configuration" + echo " required by Cargo.lock. Update it as shown in the diff above." + exit 1 +fi + +# Create deterministic archive +cd /rust +find . -print0 \ + | sort --zero-terminated \ + | tar --create --no-recursion --mode='u+rw,go+r-w,a+X' --null --files-from=- \ + | gzip -9n > "/monero/$RUST_DEPS_ARCHIVE" diff --git a/contrib/guix/rust/config.toml b/contrib/guix/rust/config.toml new file mode 100644 index 000000000..53d446d73 --- /dev/null +++ b/contrib/guix/rust/config.toml @@ -0,0 +1,15 @@ +[source.crates-io] +replace-with = "vendored-sources" + +[source."git+https://github.com/kayabaNerve/crypto-bigint?branch=c-repr"] +git = "https://github.com/kayabaNerve/crypto-bigint" +branch = "c-repr" +replace-with = "vendored-sources" + +[source."git+https://github.com/monero-oxide/monero-oxide?rev=71da8f03a87f596db674258cda74553068a57bcd"] +git = "https://github.com/monero-oxide/monero-oxide" +rev = "71da8f03a87f596db674258cda74553068a57bcd" +replace-with = "vendored-sources" + +[source.vendored-sources] +directory = "/rust/vendor"