about summary refs log tree commit diff
path: root/pkgs/build-support/rust
diff options
context:
space:
mode:
authorGeorges Dubus <georges.dubus@numergy.com>2014-10-10 16:59:37 +0200
committerRicardo M. Correia <rcorreia@wizy.org>2015-04-21 19:46:29 +0200
commit7d67efa3f23f7d5c494c90b79a63756a3917be6e (patch)
treefc8e6121cc18c9d26bba5107a903a8a499501e2a /pkgs/build-support/rust
parentc55c7e1c1e09dfa57e1a44d08c777f995493d2c9 (diff)
downloadnixlib-7d67efa3f23f7d5c494c90b79a63756a3917be6e.tar
nixlib-7d67efa3f23f7d5c494c90b79a63756a3917be6e.tar.gz
nixlib-7d67efa3f23f7d5c494c90b79a63756a3917be6e.tar.bz2
nixlib-7d67efa3f23f7d5c494c90b79a63756a3917be6e.tar.lz
nixlib-7d67efa3f23f7d5c494c90b79a63756a3917be6e.tar.xz
nixlib-7d67efa3f23f7d5c494c90b79a63756a3917be6e.tar.zst
nixlib-7d67efa3f23f7d5c494c90b79a63756a3917be6e.zip
Add support for building cargo'ed Rust programs
Diffstat (limited to 'pkgs/build-support/rust')
-rw-r--r--pkgs/build-support/rust/default.nix52
-rw-r--r--pkgs/build-support/rust/fetch-builder.sh17
-rwxr-xr-xpkgs/build-support/rust/fetch-cargo-deps119
-rw-r--r--pkgs/build-support/rust/fetchcargo.nix19
4 files changed, 207 insertions, 0 deletions
diff --git a/pkgs/build-support/rust/default.nix b/pkgs/build-support/rust/default.nix
new file mode 100644
index 000000000000..a02163f73faf
--- /dev/null
+++ b/pkgs/build-support/rust/default.nix
@@ -0,0 +1,52 @@
+{ stdenv, cacert, git, rustc, cargo, rustRegistry }:
+{ name, src, depsSha256, buildInputs ? [], ... } @ args:
+
+let
+  fetchDeps = import ./fetchcargo.nix {
+    inherit stdenv cacert git rustc cargo rustRegistry;
+  };
+
+  cargoDeps = fetchDeps {
+    inherit name src;
+    sha256 = depsSha256;
+  };
+
+in stdenv.mkDerivation (args // {
+  inherit cargoDeps rustRegistry;
+
+  buildInputs = [ git cargo rustc ] ++ buildInputs;
+
+  configurePhase = args.configurePhase or "true";
+
+  postUnpack = ''
+    echo "Using rust registry from $rustRegistry"
+    (
+        cd $sourceRoot
+        ln -s $rustRegistry ./cargo-rust-registry
+        cargo clean
+        cargo fetch
+    )
+  '' + (args.postUnpack or "");
+
+  # TODO: Probably not the best way to do this, but it should work for now
+  prePatch = ''
+    for dir in ../deps/registry/src/*/pkg-config-*; do
+        [ -d "$dir" ] || continue
+
+        substituteInPlace "$dir/src/lib.rs" \
+            --replace '"/usr"' '"/nix/store/"'
+    done
+  '' + (args.prePatch or "");
+
+  buildPhase = args.buildPhase or ''
+    echo "Running cargo build"
+    cargo build --release
+  '';
+
+  installPhase = args.installPhase or ''
+    mkdir -p $out/bin
+    for f in $(find target/release -maxdepth 1 -type f); do
+      cp $f $out/bin
+    done;
+  '';
+})
diff --git a/pkgs/build-support/rust/fetch-builder.sh b/pkgs/build-support/rust/fetch-builder.sh
new file mode 100644
index 000000000000..faa17e653289
--- /dev/null
+++ b/pkgs/build-support/rust/fetch-builder.sh
@@ -0,0 +1,17 @@
+source $stdenv/setup
+
+# cargo-fetch needs to write to Cargo.lock, even to do nothing. We
+# create a fake checkout with symlinks and and editable Cargo.lock.
+mkdir copy
+cd copy
+for f in $(ls $src); do
+  ln -s $src/"$f" .
+done
+rm Cargo.lock
+cp $src/Cargo.lock .
+chmod +w Cargo.lock
+
+$fetcher . $out
+
+cd ..
+rm -rf copy
diff --git a/pkgs/build-support/rust/fetch-cargo-deps b/pkgs/build-support/rust/fetch-cargo-deps
new file mode 100755
index 000000000000..d6579fe94bda
--- /dev/null
+++ b/pkgs/build-support/rust/fetch-cargo-deps
@@ -0,0 +1,119 @@
+#! /bin/sh -eu
+
+set -o pipefail
+
+src=$(realpath $1)
+out=$(realpath $2)
+
+echo "Fetching $src to $out"
+
+mkdir $out
+
+# Configure cargo to fetch from a local copy of the crates.io registry
+#
+# Unfortunately, `cargo fetch` will create an output directory named after a
+# hash of the registry index URL.
+#
+# This makes things difficult for us because we don't want our output to change
+# just because the path to the registry changed, otherwise we'd have to update
+# all deps' SHA256 hashes whenever we simply update the registry to a newer
+# commit.
+#
+# Also, since cargo doesn't seem to support relative URLs in the format
+# file://../path, we use a hack to make sure the registry index path/URL is
+# always the same: we'll create a symlink in the current working directory to
+# the real registry path, while pointing cargo to the following fixed absolute
+# path:
+#
+# file:///proc/self/cwd/symlink-name
+
+ln -s $rustRegistry $src/cargo-rust-registry
+
+# TODO: replace /proc/self/cwd hack with normal relative path. Probably
+# needs cargo fix.
+cat <<EOF > $out/config
+[registry]
+index = "file:///proc/self/cwd/cargo-rust-registry"
+EOF
+
+export CARGO_HOME=$out
+cd $src
+cargo fetch --verbose
+
+# TODO: check that Cargo.lock exists, and hasn't changed
+# TODO: this should be done by cargo itself
+
+# Make it deterministic
+
+# The registry index changes all the time, so it's not deterministic
+rm -rf $out/registry/index
+
+# Make git DBs deterministic
+# TODO: test with git submodules
+[[ ! -d $out/git/checkouts ]] || (cd $out/git/checkouts && for name in *; do
+    cd "$out/git/checkouts/$name"
+    revs=""
+    for branch in *; do
+        cd "$branch"
+        rev="$(git rev-parse HEAD)"
+        revs="$revs $rev"
+        cd ..
+    done
+
+    (
+        # The following code was adapted from nix-prefetch-git
+
+        cd "$out/git/db/$name"
+
+        export GIT_DIR=.
+
+        # Remove all remote branches
+        git branch -r | while read branch; do
+            git branch -rD "$branch" >&2
+        done
+
+        # Remove tags that don't point to any HEAD
+        git tag | while read tag; do
+            rev="$(git rev-parse $tag)"
+            if [[ $revs != *" $rev"* ]]; then
+                git tag -d "$tag" >&2
+            fi
+        done
+
+        # Remove branches that don't point to any HEAD
+        branchrefs=()
+        eval "$(git for-each-ref --shell --format='branchrefs+=(%(refname))' refs/heads/)"
+
+        for branchref in "${branchrefs[@]}"; do
+            echo "Examining $branchref"
+            rev="$(git rev-parse "$branchref")"
+            echo "Has rev $rev"
+            echo "List of revs: $revs"
+            if [[ $revs != *" $rev"* ]]; then
+                echo "Deleting $branchref"
+                git update-ref -d "$branchref" >&2
+            fi
+        done
+
+        echo "$revs" | while read rev; do
+            echo "git branch b_$rev $rev"
+            git branch b_$rev $rev
+        done
+
+        # Remove files that have timestamps or otherwise have non-deterministic
+        # properties.
+        rm -rf logs/ hooks/ index FETCH_HEAD ORIG_HEAD refs/remotes/origin/HEAD config
+
+        # Do a full repack. Must run single-threaded, or else we lose determinism.
+        git config pack.threads 1
+        git repack -A -d -f
+        rm -f config
+
+        # Garbage collect unreferenced objects.
+        git gc --prune=all
+    )
+done)
+
+# Remove unneeded outputs
+[[ ! -d $out/registry/src ]] || rm -rf $out/registry/src
+[[ ! -d $out/git/checkouts ]] || rm -rf $out/git/checkouts
diff --git a/pkgs/build-support/rust/fetchcargo.nix b/pkgs/build-support/rust/fetchcargo.nix
new file mode 100644
index 000000000000..cd5d69e06d0d
--- /dev/null
+++ b/pkgs/build-support/rust/fetchcargo.nix
@@ -0,0 +1,19 @@
+{ stdenv, cacert, git, rustc, cargo, rustRegistry }:
+{ name ? "cargo-deps", src, sha256 }:
+
+stdenv.mkDerivation {
+  name = "${name}-fetch";
+  buildInputs = [ rustc cargo git ];
+  builder = ./fetch-builder.sh;
+  fetcher = ./fetch-cargo-deps;
+  inherit src rustRegistry;
+
+  outputHashAlgo = "sha256";
+  outputHashMode = "recursive";
+  outputHash = sha256;
+
+  SSL_CERT_FILE = "${cacert}/etc/ca-bundle.crt";
+
+  impureEnvVars = [ "http_proxy" "https_proxy" "ftp_proxy" "all_proxy" "no_proxy" ];
+  preferLocalBuild = true;
+}