summary refs log tree commit diff
path: root/pkgs/build-support
diff options
context:
space:
mode:
authorVladimír Čunát <vcunat@gmail.com>2015-05-24 20:39:58 +0200
committerVladimír Čunát <vcunat@gmail.com>2015-05-24 20:39:58 +0200
commitf83d12a382c15caaf2486f6cb0d288881f459097 (patch)
tree7e0ff39a6c08be0fe79532e17e8ef54b8d88492c /pkgs/build-support
parentcdd93463c0677b4aeb1f7a75825c6a8f36c6de16 (diff)
parentc505b8ac287aac0d5fecfc3b8e91f5cdc22ed649 (diff)
downloadnixlib-f83d12a382c15caaf2486f6cb0d288881f459097.tar
nixlib-f83d12a382c15caaf2486f6cb0d288881f459097.tar.gz
nixlib-f83d12a382c15caaf2486f6cb0d288881f459097.tar.bz2
nixlib-f83d12a382c15caaf2486f6cb0d288881f459097.tar.lz
nixlib-f83d12a382c15caaf2486f6cb0d288881f459097.tar.xz
nixlib-f83d12a382c15caaf2486f6cb0d288881f459097.tar.zst
nixlib-f83d12a382c15caaf2486f6cb0d288881f459097.zip
Merge 'master' into staging
Diffstat (limited to 'pkgs/build-support')
-rw-r--r--pkgs/build-support/agda/default.nix73
-rw-r--r--pkgs/build-support/cc-wrapper/default.nix3
-rw-r--r--pkgs/build-support/emacs/wrapper.nix6
-rw-r--r--pkgs/build-support/fetchgit/builder.sh3
-rw-r--r--pkgs/build-support/fetchgit/default.nix3
-rwxr-xr-xpkgs/build-support/fetchgit/nix-prefetch-git14
-rw-r--r--pkgs/build-support/rust/default.nix101
-rw-r--r--pkgs/build-support/rust/fetch-builder.sh17
-rwxr-xr-xpkgs/build-support/rust/fetch-cargo-deps174
-rw-r--r--pkgs/build-support/rust/fetchcargo.nix19
-rw-r--r--pkgs/build-support/rust/patch-registry-deps/pkg-config8
-rw-r--r--pkgs/build-support/vm/default.nix65
12 files changed, 437 insertions, 49 deletions
diff --git a/pkgs/build-support/agda/default.nix b/pkgs/build-support/agda/default.nix
index cb6059e00cd2..69c4897d1a4b 100644
--- a/pkgs/build-support/agda/default.nix
+++ b/pkgs/build-support/agda/default.nix
@@ -21,24 +21,34 @@ in
         sourceDirectories = filter (y: !(y == null)) x.sourceDirectories;
         propagatedBuildInputs = filter (y : ! (y == null)) x.propagatedBuildInputs;
         propagatedUserEnvPkgs = filter (y : ! (y == null)) x.propagatedUserEnvPkgs;
-        extraBuildFlags = filter (y : ! (y == null)) x.extraBuildFlags;
         everythingFile = if x.everythingFile == "" then "Everything.agda" else x.everythingFile;
+
+        passthru = { inherit (x) extras; };
+        extras = null;
       };
 
       defaults = self : {
         # There is no Hackage for Agda so we require src.
         inherit (self) src name;
 
+        isAgdaPackage = true;
+
         buildInputs = [ Agda ] ++ self.buildDepends;
         buildDepends = [];
+
+        buildDependsAgda = filter
+          (dep: dep ? isAgdaPackage && dep.isAgdaPackage)
+          self.buildDepends;
+        buildDependsAgdaShareAgda = map (x: x + "/share/agda") self.buildDependsAgda;
+
         # Not much choice here ;)
         LANG = "en_US.UTF-8";
         LOCALE_ARCHIVE = optionalString stdenv.isLinux "${glibcLocales}/lib/locale/locale-archive";
 
         everythingFile = "Everything.agda";
 
-        propagatedBuildInputs = self.buildDepends ++ self.buildTools;
-        propagatedUserEnvPkgs = self.buildDepends;
+        propagatedBuildInputs = self.buildDependsAgda;
+        propagatedUserEnvPkgs = self.buildDependsAgda;
 
         # Immediate source directories under which modules can be found.
         sourceDirectories = [ ];
@@ -50,43 +60,44 @@ in
         # would make a direct copy of the whole thing.
         topSourceDirectories = [ "src" ];
 
-        buildTools = [];
-
-        # Extra stuff to pass to the Agda binary.
-        extraBuildFlags = [ "-i ." ];
-        buildFlags = let r = map (x: "-i " + x + "/share/agda") self.buildDepends;
-                         d = map (x : "-i " + x) (self.sourceDirectories ++ self.topSourceDirectories);
-                     in unwords (r ++ d ++ self.extraBuildFlags);
-
-        # We expose this as a mere convenience for any tools.
-        AGDA_PACKAGE_PATH = concatMapStrings (x: x + ":") self.buildDepends;
+        # FIXME: `dirOf self.everythingFile` is what we really want, not hardcoded "./"
+        includeDirs = self.buildDependsAgdaShareAgda
+                      ++ self.sourceDirectories ++ self.topSourceDirectories
+                      ++ [ "." ];
+        buildFlags = unwords (map (x: "-i " + x) self.includeDirs);
 
-        # Makes a wrapper available to the user. Very useful in
-        # nix-shell where all dependencies are -i'd.
-        agdaWrapper = writeScriptBin "agda" ''
-          ${Agda}/bin/agda ${self.buildFlags} "$@"
-        '';
-
-        # configurePhase is idempotent
-        configurePhase = ''
-          eval "$preConfigure"
-          export AGDA_PACKAGE_PATH=${self.AGDA_PACKAGE_PATH};
-          export PATH="${self.agdaWrapper}/bin:$PATH"
-          eval "$postConfigure"
-        '';
+        agdaWithArgs = "${Agda}/bin/agda ${self.buildFlags}";
 
         buildPhase = ''
-          eval "$preBuild"
-          ${Agda}/bin/agda ${self.buildFlags} ${self.everythingFile}
-          eval "$postBuild"
+          runHook preBuild
+          ${self.agdaWithArgs} ${self.everythingFile}
+          runHook postBuild
         '';
 
         installPhase = ''
-          eval "$preInstall"
+          runHook preInstall
           mkdir -p $out/share/agda
           cp -pR ${unwords self.sourceDirectories} ${mapInside self.topSourceDirectories} $out/share/agda
-          eval "$postInstall"
+          runHook postInstall
         '';
+
+        # Optionally-built conveniences
+        extras = {
+          # Makes a wrapper available to the user. Very useful in
+          # nix-shell where all dependencies are -i'd.
+          agdaWrapper = writeScriptBin "agda" ''
+            ${self.agdaWithArgs} "$@"
+          '';
+
+          # Use this to stick `agdaWrapper` at the front of the PATH:
+          #
+          # agda.mkDerivation (self: { PATH = self.extras.agdaWrapperPATH; })
+          #
+          # Not sure this is the best way to handle conflicts....
+          agdaWrapperPATH = "${self.extras.agdaWrapper}/bin:$PATH";
+
+          AGDA_PACKAGE_PATH = concatMapStrings (x: x + ":") self.buildDependsAgdaShareAgda;
+        };
       };
     in stdenv.mkDerivation
          (postprocess (let super = defaults self // args self;
diff --git a/pkgs/build-support/cc-wrapper/default.nix b/pkgs/build-support/cc-wrapper/default.nix
index f6826c837ca1..c8af548a2ca4 100644
--- a/pkgs/build-support/cc-wrapper/default.nix
+++ b/pkgs/build-support/cc-wrapper/default.nix
@@ -10,6 +10,7 @@
 , zlib ? null, extraPackages ? []
 , dyld ? null # TODO: should this be a setup-hook on dyld?
 , setupHook ? ./setup-hook.sh
+, isGNU ? false, isClang ? false
 }:
 
 with stdenv.lib;
@@ -41,7 +42,7 @@ stdenv.mkDerivation {
   # The wrapper scripts use 'cat', so we may need coreutils.
   coreutils = if nativeTools then null else coreutils;
 
-  passthru = { inherit nativeTools nativeLibc nativePrefix; };
+  passthru = { inherit nativeTools nativeLibc nativePrefix isGNU isClang; };
 
   buildCommand =
     ''
diff --git a/pkgs/build-support/emacs/wrapper.nix b/pkgs/build-support/emacs/wrapper.nix
index 678ba4502112..4020a1aca337 100644
--- a/pkgs/build-support/emacs/wrapper.nix
+++ b/pkgs/build-support/emacs/wrapper.nix
@@ -66,6 +66,12 @@ stdenv.mkDerivation {
       makeWrapper "$prog" $out/bin/$(basename "$prog") \
         --suffix EMACSLOADPATH ":" "$out/share/emacs/site-lisp:"
     done
+
+    mkdir -p $out/share
+    # Link icons and desktop files into place
+    for dir in applications icons info man; do
+      ln -s $emacs/share/$dir $out/share/$dir
+    done
   '';
   inherit (emacs) meta;
 }
diff --git a/pkgs/build-support/fetchgit/builder.sh b/pkgs/build-support/fetchgit/builder.sh
index 71374d1f2383..64eea4ae1000 100644
--- a/pkgs/build-support/fetchgit/builder.sh
+++ b/pkgs/build-support/fetchgit/builder.sh
@@ -9,6 +9,7 @@ header "exporting $url (rev $rev) into $out"
 $fetcher --builder --url "$url" --out "$out" --rev "$rev" \
   ${leaveDotGit:+--leave-dotGit} \
   ${deepClone:+--deepClone} \
-  ${fetchSubmodules:+--fetch-submodules}
+  ${fetchSubmodules:+--fetch-submodules} \
+  ${branchName:+--branch-name "$branchName"}
 
 stopNest
diff --git a/pkgs/build-support/fetchgit/default.nix b/pkgs/build-support/fetchgit/default.nix
index bb89a8f55329..e5ad7200cecf 100644
--- a/pkgs/build-support/fetchgit/default.nix
+++ b/pkgs/build-support/fetchgit/default.nix
@@ -13,6 +13,7 @@
 in
 { url, rev ? "HEAD", md5 ? "", sha256 ? "", leaveDotGit ? deepClone
 , fetchSubmodules ? true, deepClone ? false
+, branchName ? null
 , name ? urlToName url rev
 }:
 
@@ -51,7 +52,7 @@ stdenv.mkDerivation {
   outputHashMode = "recursive";
   outputHash = if sha256 == "" then md5 else sha256;
 
-  inherit url rev leaveDotGit fetchSubmodules deepClone;
+  inherit url rev leaveDotGit fetchSubmodules deepClone branchName;
 
   GIT_SSL_CAINFO = "${cacert}/etc/ca-bundle.crt";
 
diff --git a/pkgs/build-support/fetchgit/nix-prefetch-git b/pkgs/build-support/fetchgit/nix-prefetch-git
index 486fd3acafb7..ceedf313f28e 100755
--- a/pkgs/build-support/fetchgit/nix-prefetch-git
+++ b/pkgs/build-support/fetchgit/nix-prefetch-git
@@ -8,6 +8,7 @@ deepClone=$NIX_PREFETCH_GIT_DEEP_CLONE
 leaveDotGit=$NIX_PREFETCH_GIT_LEAVE_DOT_GIT
 fetchSubmodules=
 builder=
+branchName=$NIX_PREFETCH_GIT_BRANCH_NAME
 
 if test -n "$deepClone"; then
     deepClone=true
@@ -31,6 +32,7 @@ for arg; do
             --url) argfun=set_url;;
             --rev) argfun=set_rev;;
             --hash) argfun=set_hashType;;
+            --branch-name) argfun=set_branchName;;
             --deepClone) deepClone=true;;
             --no-deepClone) deepClone=false;;
             --leave-dotGit) leaveDotGit=true;;
@@ -108,7 +110,7 @@ checkout_hash(){
     fi
 
     git fetch ${builder:+--progress} origin || return 1
-    git checkout -b fetchgit $hash || return 1
+    git checkout -b $branchName $hash || return 1
 }
 
 # Fetch only a branch/tag and checkout it.
@@ -131,7 +133,7 @@ checkout_ref(){
     if test -n "$ref"; then
         # --depth option is ignored on http repository.
         git fetch ${builder:+--progress} --depth 1 origin +"$ref" || return 1
-        git checkout -b fetchgit FETCH_HEAD || return 1
+        git checkout -b $branchName FETCH_HEAD || return 1
     else
         return 1
     fi
@@ -222,7 +224,7 @@ make_deterministic_repo(){
         fi
     done
 
-    # Do a full repack. Must run single-threaded, or else we loose determinism.
+    # 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 .git/config
@@ -251,7 +253,7 @@ clone_user_rev() {
             fi;;
     esac
 
-    local full_revision=$(cd $dir && (git rev-parse $rev 2> /dev/null || git rev-parse refs/heads/fetchgit) | tail -n1)
+    local full_revision=$(cd $dir && (git rev-parse $rev 2> /dev/null || git rev-parse refs/heads/$branchName) | tail -n1)
     echo "git revision is $full_revision"
     echo "git human-readable version is $(cd $dir && (git describe $full_revision 2> /dev/null || git describe --tags $full_revision 2> /dev/null || echo -- none --))" >&2
     echo "Commit date is $(cd $dir && git show --no-patch --pretty=%ci $full_revision)"
@@ -268,6 +270,10 @@ clone_user_rev() {
     fi
 }
 
+if test -z "$branchName"; then
+    branchName=fetchgit
+fi
+
 if test -n "$builder"; then
     test -n "$out" -a -n "$url" -a -n "$rev" || usage
     mkdir $out
diff --git a/pkgs/build-support/rust/default.nix b/pkgs/build-support/rust/default.nix
new file mode 100644
index 000000000000..87115e392daf
--- /dev/null
+++ b/pkgs/build-support/rust/default.nix
@@ -0,0 +1,101 @@
+{ stdenv, cacert, git, rustc, cargo, rustRegistry }:
+{ name, src, depsSha256, buildInputs ? [], cargoUpdateHook ? "", ... } @ args:
+
+let
+  fetchDeps = import ./fetchcargo.nix {
+    inherit stdenv cacert git rustc cargo rustRegistry;
+  };
+
+  cargoDeps = fetchDeps {
+    inherit name src cargoUpdateHook;
+    sha256 = depsSha256;
+  };
+
+in stdenv.mkDerivation (args // {
+  inherit cargoDeps rustRegistry;
+
+  patchRegistryDeps = ./patch-registry-deps;
+
+  buildInputs = [ git cargo rustc ] ++ buildInputs;
+
+  configurePhase = args.configurePhase or "true";
+
+  postUnpack = ''
+    echo "Using cargo deps from $cargoDeps"
+
+    cp -r "$cargoDeps" deps
+    chmod +w deps -R
+
+    # It's OK to use /dev/null as the URL because by the time we do this, cargo
+    # won't attempt to update the registry anymore, so the URL is more or less
+    # irrelevant
+
+    cat <<EOF > deps/config
+    [registry]
+    index = "file:///dev/null"
+    EOF
+
+    export CARGO_HOME="$(realpath deps)"
+
+    # Let's find out which $indexHash cargo uses for file:///dev/null
+    (cd $sourceRoot && cargo fetch &>/dev/null)
+    cd deps
+    indexHash="$(basename $(echo registry/index/*))"
+
+    echo "Using indexHash '$indexHash'"
+
+    rm -rf -- "registry/cache/$indexHash" \
+              "registry/index/$indexHash"
+
+    mv registry/cache/HASH "registry/cache/$indexHash"
+
+    echo "Using rust registry from $rustRegistry"
+    ln -s "$rustRegistry" "registry/index/$indexHash"
+
+    # Retrieved the Cargo.lock file which we saved during the fetch
+    cd ..
+    mv deps/Cargo.lock $sourceRoot/
+
+    (
+        cd $sourceRoot
+
+        cargo fetch
+        cargo clean
+    )
+  '' + (args.postUnpack or "");
+
+  prePatch = ''
+    # Patch registry dependencies, using the scripts in $patchRegistryDeps
+    (
+        set -euo pipefail
+
+        cd ../deps/registry/src/*
+
+        for script in $patchRegistryDeps/*; do
+          # Run in a subshell so that directory changes and shell options don't
+          # affect any following commands
+
+          ( . $script)
+        done
+    )
+  '' + (args.prePatch or "");
+
+  buildPhase = args.buildPhase or ''
+    echo "Running cargo build --release"
+    cargo build --release
+  '';
+
+  checkPhase = args.checkPhase or ''
+    echo "Running cargo test"
+    cargo test
+  '';
+
+  doCheck = args.doCheck or true;
+
+  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..69eb404e6445
--- /dev/null
+++ b/pkgs/build-support/rust/fetch-cargo-deps
@@ -0,0 +1,174 @@
+#! /bin/sh
+
+source $stdenv/setup
+
+set -euo 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
+
+echo "Using rust registry from $rustRegistry"
+
+cat <<EOF > $out/config
+[registry]
+index = "file://$rustRegistry"
+EOF
+
+export CARGO_HOME=$out
+cd $src
+
+if [[ ! -f Cargo.lock ]]; then
+    echo "ERROR: The Cargo.lock file doesn't exist"
+    echo
+    echo "Cargo.lock is needed to make sure that depsSha256 doesn't change"
+    echo "when the registry is updated."
+
+    exit 1
+fi
+
+# We need to do the following string replacement so that 'cargo fetch'
+# doesn't ignore the versions specified in Cargo.lock
+set +u
+substituteInPlace Cargo.lock \
+    --replace "registry+https://github.com/rust-lang/crates.io-index" \
+              "registry+file://$rustRegistry"
+set -u
+
+# Do any possible 'cargo update -p <pkgName> --precise <version>' ad-hoc updates
+eval "$cargoUpdateHook"
+
+# Do the fetch
+cargo fetch --verbose
+
+# Now that we have fetched everything, let's make the output deterministic
+
+# Cargo uses the following directory structure for fetched data, where
+# $indexHash is a hash of the registry index URL:
+#
+#
+# /config:
+#
+#     Cargo config file. We'll delete this because it's not deterministic,
+#     and instead recreate it just before running 'cargo build'.
+#
+# /registry/cache/$indexHash/:
+#
+#     This is where tarballs of registry package dependencies are kept
+#     We'll need to keep this, but make sure $indexHash is a fixed name.
+#
+# /registry/index/$indexHash/:
+#
+#     A copy of the registry index is kept here. We can delete this, and
+#     instead, just before running 'cargo build', we'll symlink this
+#     directory to our static copy of the registry in the Nix store.
+#
+# /registry/src/$indexHash/{pkgName-pkgVersion}/:
+#
+#     Here cargo keeps extracted sources of the cached tarballs.
+#     We'll just delete this because cargo will re-populate them from the
+#     tarballs.
+#
+# /git/db/{domain-hash}/:
+#
+#     Here cargo keeps the `.git` directories of git dependencies.
+#     We'll need to keep these, but make them deterministic.
+#
+# /git/checkouts/{domain-hash}/{branchName}/:
+#
+#     Here cargo keeps checked-out sources of the git dependencies.
+#     We can delete this, because cargo will re-populate them from the above
+#     `.git` directories.
+#
+# Let's start
+
+# Remove cargo config file, which points to the ever-changing registry
+rm $out/config
+
+# Save the Cargo.lock file into the output, so that we don't have to do another
+# 'cargo update' during the build (which would try to access the network) for
+# any ad-hoc package updates (through $cargoUpdateHook).
+#
+# We need to replace the rustRegistry URL with something deterministic.
+# Since the URL won't actually be accessed anymore, it's fine to use /dev/null.
+
+set +u
+substituteInPlace Cargo.lock \
+    --replace "registry+file://$rustRegistry" \
+              "registry+file:///dev/null"
+set -u
+mv Cargo.lock $out/
+
+
+# Let's replace $indexHash with something more deterministic
+mv $out/registry/cache/* $out/registry/cache/HASH
+
+# The registry index changes all the time, so it's not deterministic
+# We'll symlink it before running 'cargo build'
+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 all tags
+        git tag | while read tag; do
+            git tag -d "$tag" >&2
+        done
+
+        # Remove all local branches
+        branchrefs=()
+        eval "$(git for-each-ref --shell --format='branchrefs+=(%(refname))' refs/heads/)"
+
+        for branchref in "${branchrefs[@]}"; do
+            git update-ref -d "$branchref" >&2
+        done
+
+        # Create ad-hoc branches for the revs we need
+        echo "$revs" | while read rev; do
+            echo "Creating 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..7ebd02a485d7
--- /dev/null
+++ b/pkgs/build-support/rust/fetchcargo.nix
@@ -0,0 +1,19 @@
+{ stdenv, cacert, git, rustc, cargo, rustRegistry }:
+{ name ? "cargo-deps", src, sha256, cargoUpdateHook ? "" }:
+
+stdenv.mkDerivation {
+  name = "${name}-fetch";
+  buildInputs = [ rustc cargo git ];
+  builder = ./fetch-builder.sh;
+  fetcher = ./fetch-cargo-deps;
+  inherit src rustRegistry cargoUpdateHook;
+
+  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;
+}
diff --git a/pkgs/build-support/rust/patch-registry-deps/pkg-config b/pkgs/build-support/rust/patch-registry-deps/pkg-config
new file mode 100644
index 000000000000..2acf489851e9
--- /dev/null
+++ b/pkgs/build-support/rust/patch-registry-deps/pkg-config
@@ -0,0 +1,8 @@
+for dir in pkg-config-*; do
+    [ -d "$dir" ] || continue
+
+    echo "Patching pkg-config registry dep"
+
+    substituteInPlace "$dir/src/lib.rs" \
+        --replace '"/usr"' '"/nix/store/"'
+done
diff --git a/pkgs/build-support/vm/default.nix b/pkgs/build-support/vm/default.nix
index 838548f94bfe..b96ac19177a4 100644
--- a/pkgs/build-support/vm/default.nix
+++ b/pkgs/build-support/vm/default.nix
@@ -120,8 +120,10 @@ rec {
     mkdir -p /fs/nix/store
     mount -t 9p store /fs/nix/store -o trans=virtio,version=9p2000.L,msize=262144,cache=loose
 
-    mkdir -p /fs/tmp
+    mkdir -p /fs/tmp /fs/run /fs/var
     mount -t tmpfs -o "mode=1777" none /fs/tmp
+    mount -t tmpfs -o "mode=755" none /fs/run
+    ln -sfn /run /fs/var/run
 
     echo "mounting host's temporary directory..."
     mkdir -p /fs/tmp/xchg
@@ -138,15 +140,7 @@ rec {
     echo "127.0.0.1 localhost" > /fs/etc/hosts
 
     echo "starting stage 2 ($command)"
-    test -n "$command"
-
-    set +e
-    chroot /fs $command $out
-    echo $? > /fs/tmp/xchg/in-vm-exit
-
-    mount -o remount,ro dummy /fs
-
-    poweroff -f
+    exec switch_root /fs $command $out
   '';
 
 
@@ -179,12 +173,27 @@ rec {
       ${coreutils}/bin/ln -s ${bash}/bin/sh /bin/sh
     fi
 
+    # Set up automatic kernel module loading.
+    export MODULE_DIR=${linux}/lib/modules/
+    ${coreutils}/bin/cat <<EOF > /run/modprobe
+    #! /bin/sh
+    export MODULE_DIR=$MODULE_DIR
+    exec ${kmod}/bin/modprobe "\$@"
+    EOF
+    ${coreutils}/bin/chmod 755 /run/modprobe
+    echo /run/modprobe > /proc/sys/kernel/modprobe
+
     # For debugging: if this is the second time this image is run,
     # then don't start the build again, but instead drop the user into
     # an interactive shell.
     if test -n "$origBuilder" -a ! -e /.debug; then
       ${coreutils}/bin/touch /.debug
-      exec $origBuilder $origArgs
+      $origBuilder $origArgs
+      echo $? > /tmp/xchg/in-vm-exit
+
+      ${busybox}/bin/mount -o remount,ro dummy /
+
+      ${busybox}/bin/poweroff -f
     else
       export PATH=/bin:/usr/bin:${coreutils}/bin
       echo "Starting interactive shell..."
@@ -1563,6 +1572,40 @@ rec {
       packages = commonDebPackages ++ [ "diffutils" "libc-bin" ];
     };
 
+    ubuntu1504i386 = {
+      name = "ubuntu-15.04-vivid-i386";
+      fullName = "Ubuntu 15.04 Vivid (i386)";
+      packagesLists =
+        [ (fetchurl {
+            url = mirror://ubuntu/dists/vivid/main/binary-i386/Packages.bz2;
+            sha256 = "0bf587152fa3fc3524bf3a3caaf46ea43cc640a27b2b448577232f014a3ec1e4";
+          })
+          (fetchurl {
+            url = mirror://ubuntu/dists/vivid/universe/binary-i386/Packages.bz2;
+            sha256 = "3452cff96eb715ca36b73d4d0cdffbf06064cbc30b1097e334a2e493b94c7fac";
+          })
+        ];
+      urlPrefix = mirror://ubuntu;
+      packages = commonDebPackages ++ [ "diffutils" "libc-bin" ];
+    };
+
+    ubuntu1504x86_64 = {
+      name = "ubuntu-15.04-vivid-amd64";
+      fullName = "Ubuntu 15.04 Vivid (amd64)";
+      packagesList =
+        [ (fetchurl {
+            url = mirror://ubuntu/dists/vivid/main/binary-amd64/Packages.bz2;
+            sha256 = "8f22c9bd389822702e65713e816250aa0d5829d6b3d75fd34f068de5f93de1d9";
+          })
+          (fetchurl {
+            url = mirror://ubuntu/dists/vivid/universe/binary-amd64/Packages.bz2;
+            sha256 = "feb88768e245a63ee04b0f3bcfc8899a1f03b2f831646dc2a59e4e58884b5cb9";
+          })
+        ];
+      urlPrefix = mirror://ubuntu;
+      packages = commonDebPackages ++ [ "diffutils" "libc-bin" ];
+    };
+
     debian40i386 = {
       name = "debian-4.0r9-etch-i386";
       fullName = "Debian 4.0r9 Etch (i386)";