about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPierre-Etienne Meunier <pierre-etienne.meunier@inria.fr>2018-02-20 08:55:04 +0100
committerJoachim Schiele <js@lastlog.de>2018-02-20 08:55:04 +0100
commit8e5ab6e7ac582d2787ba2e10eabbcacf09da270c (patch)
tree8f48892431486d38cf3e1dd41d73b60b6cb93554
parent507a3a9a39d772c51a76ce4598042d57f45e2ed0 (diff)
downloadnixlib-8e5ab6e7ac582d2787ba2e10eabbcacf09da270c.tar
nixlib-8e5ab6e7ac582d2787ba2e10eabbcacf09da270c.tar.gz
nixlib-8e5ab6e7ac582d2787ba2e10eabbcacf09da270c.tar.bz2
nixlib-8e5ab6e7ac582d2787ba2e10eabbcacf09da270c.tar.lz
nixlib-8e5ab6e7ac582d2787ba2e10eabbcacf09da270c.tar.xz
nixlib-8e5ab6e7ac582d2787ba2e10eabbcacf09da270c.tar.zst
nixlib-8e5ab6e7ac582d2787ba2e10eabbcacf09da270c.zip
BuildRustCrate: more general overrides, and handling the "dylib" crate type (#35171)
* buildRustCrate: adding a symlink from libblah-xxxxx.so to libblah.so
* BuildRustCrate: overriding phases
* Carnix: 0.6.5 -> 0.6.6
* Fixing symlink_dependencies --buildDep
* Shorter symlink_dependencies
* running `runHook postBuild` *after* the build
-rw-r--r--doc/languages-frameworks/rust.md35
-rw-r--r--pkgs/build-support/rust/build-rust-crate.nix296
-rw-r--r--pkgs/build-support/rust/carnix.nix16
3 files changed, 221 insertions, 126 deletions
diff --git a/doc/languages-frameworks/rust.md b/doc/languages-frameworks/rust.md
index d3a25e9d1358..f0498eac5b19 100644
--- a/doc/languages-frameworks/rust.md
+++ b/doc/languages-frameworks/rust.md
@@ -58,6 +58,8 @@ To install crates with nix there is also an experimental project called
 
 ## Compiling Rust crates using Nix instead of Cargo
 
+### Simple operation
+
 When run, `cargo build` produces a file called `Cargo.lock`,
 containing pinned versions of all dependencies. Nixpkgs contains a
 tool called `carnix` (`nix-env -iA nixos.carnix`), which can be used
@@ -153,6 +155,8 @@ Here, the `libc` crate has no `src` attribute, so `buildRustCrate`
 will fetch it from [crates.io](https://crates.io). A `sha256`
 attribute is still needed for Nix purity.
 
+### Handling external dependencies
+
 Some crates require external libraries. For crates from
 [crates.io](https://crates.io), such libraries can be specified in
 `defaultCrateOverrides` package in nixpkgs itself.
@@ -210,7 +214,10 @@ with import <nixpkgs> {};
 }
 ```
 
-Three more parameters can be overridden:
+### Options and phases configuration
+
+Actually, the overrides introduced in the previous section are more
+general. A number of other parameters can be overridden:
 
 - The version of rustc used to compile the crate:
 
@@ -232,6 +239,30 @@ Three more parameters can be overridden:
   (hello {}).override { verbose = false; };
   ```
 
+- Extra arguments to be passed to `rustc`:
+
+  ```
+  (hello {}).override { extraRustcOpts = "-Z debuginfo=2"; };
+  ```
+
+- Phases, just like in any other derivation, can be specified using
+  the following attributes: `preUnpack`, `postUnpack`, `prePatch`,
+  `patches`, `postPatch`, `preConfigure` (in the case of a Rust crate,
+  this is run before calling the "build" script), `postConfigure`
+  (after the "build" script),`preBuild`, `postBuild`, `preInstall` and
+  `postInstall`. As an example, here is how to create a new module
+  before running the build script:
+
+  ```
+  (hello {}).override {
+    preConfigure = ''
+       echo "pub const PATH=\"${hi.out}\";" >> src/path.rs"
+    '';
+  };
+  ```
+
+### Features
+
 One can also supply features switches. For example, if we want to
 compile `diesel_cli` only with the `postgres` feature, and no default
 features, we would write:
@@ -243,7 +274,7 @@ features, we would write:
 }
 ```
 
-
+Where `diesel.nix` is the file generated by Carnix, as explained above.
 
 ## Using the Rust nightlies overlay
 
diff --git a/pkgs/build-support/rust/build-rust-crate.nix b/pkgs/build-support/rust/build-rust-crate.nix
index f1f344ca3c7d..8a9a07fd7a8f 100644
--- a/pkgs/build-support/rust/build-rust-crate.nix
+++ b/pkgs/build-support/rust/build-rust-crate.nix
@@ -6,44 +6,16 @@
 
 { lib, buildPlatform, stdenv, defaultCrateOverrides, fetchCrate, ncurses, rustc  }:
 
-let buildCrate = { crateName, crateVersion, crateAuthors, buildDependencies,
-                   dependencies, completeDeps, completeBuildDeps,
-                   crateFeatures, libName, build, release, libPath,
-                   crateType, metadata, crateBin, finalBins,
-                   verbose, colors }:
-
-      let depsDir = lib.concatStringsSep " " dependencies;
-          completeDepsDir = lib.concatStringsSep " " completeDeps;
-          completeBuildDepsDir = lib.concatStringsSep " " completeBuildDeps;
-          makeDeps = dependencies:
-            (lib.concatMapStringsSep " " (dep:
-              let extern = lib.strings.replaceStrings ["-"] ["_"] dep.libName; in
-              (if dep.crateType == "lib" then
-                 " --extern ${extern}=${dep.out}/lib/lib${extern}-${dep.metadata}.rlib"
-              else
-                 " --extern ${extern}=${dep.out}/lib/lib${extern}-${dep.metadata}${buildPlatform.extensions.sharedLibrary}")
-            ) dependencies);
-          deps = makeDeps dependencies;
-          buildDeps = makeDeps buildDependencies;
-          optLevel = if release then 3 else 0;
-          rustcOpts = (if release then "-C opt-level=3" else "-C debuginfo=2");
-          rustcMeta = "-C metadata=${metadata} -C extra-filename=-${metadata}";
-          version_ = lib.splitString "-" crateVersion;
-          versionPre = if lib.tail version_ == [] then "" else builtins.elemAt version_ 1;
-          version = lib.splitString "." (lib.head version_);
-          authors = lib.concatStringsSep ":" crateAuthors;
-      in ''
-      norm=""
-      bold=""
-      green=""
-      boldgreen=""
-      if [[ "${colors}" -eq "always" ]]; then
-        norm="$(printf '\033[0m')" #returns to "normal"
-        bold="$(printf '\033[0;1m')" #set bold
-        green="$(printf '\033[0;32m')" #set green
-        boldgreen="$(printf '\033[0;1;32m')" #set bold, and set green.
-      fi
-
+let makeDeps = dependencies:
+      (lib.concatMapStringsSep " " (dep:
+        let extern = lib.strings.replaceStrings ["-"] ["_"] dep.libName; in
+        (if dep.crateType == "lib" then
+           " --extern ${extern}=${dep.out}/lib/lib${extern}-${dep.metadata}.rlib"
+         else
+           " --extern ${extern}=${dep.out}/lib/lib${extern}-${dep.metadata}${buildPlatform.extensions.sharedLibrary}")
+      ) dependencies);
+
+    echo_build_heading = colors: ''
       echo_build_heading() {
        start=""
        end=""
@@ -57,7 +29,8 @@ let buildCrate = { crateName, crateVersion, crateAuthors, buildDependencies,
          echo "$start""Building $1 ($2)""$end"
        fi
       }
-
+    '';
+    noisily = colors: verbose: ''
       noisily() {
         start=""
         end=""
@@ -71,18 +44,29 @@ let buildCrate = { crateName, crateVersion, crateAuthors, buildDependencies,
 	''}
 	$@
       }
+    '';
 
+    configureCrate =
+      { crateName, crateVersion, crateAuthors, build, libName, crateFeatures, colors, libPath, release, buildDependencies, completeDeps, completeBuildDeps, verbose, dependencies }:
+      let version_ = lib.splitString "-" crateVersion;
+          versionPre = if lib.tail version_ == [] then "" else builtins.elemAt version_ 1;
+          version = lib.splitString "." (lib.head version_);
+          rustcOpts = (if release then "-C opt-level=3" else "-C debuginfo=2");
+          buildDeps = makeDeps buildDependencies;
+          authors = lib.concatStringsSep ":" crateAuthors;
+          optLevel = if release then 3 else 0;
+          completeDepsDir = lib.concatStringsSep " " completeDeps;
+          completeBuildDepsDir = lib.concatStringsSep " " completeBuildDeps;
+      in ''
+      runHook preConfigure
+      ${echo_build_heading colors}
+      ${noisily colors verbose}
       symlink_dependency() {
-      # $1 is the nix-store path of a dependency
+        # $1 is the nix-store path of a dependency
+        # $2 is the target path
         i=$1
-	dest=target/deps
-	if [ ! -z $2 ]; then
-           if [ "$2" = "--buildDep" ]; then
-             dest=target/buildDeps
-           fi
-	fi
-        ln -s -f $i/lib/*.rlib $dest #*/
-        ln -s -f $i/lib/*.so $i/lib/*.dylib $dest #*/
+        ln -s -f $i/lib/*.rlib $2 #*/
+        ln -s -f $i/lib/*.so $i/lib/*.dylib $2 #*/
         if [ -e "$i/lib/link" ]; then
             cat $i/lib/link >> target/link
             cat $i/lib/link >> target/link.final
@@ -92,48 +76,15 @@ let buildCrate = { crateName, crateVersion, crateAuthors, buildDependencies,
         fi
       }
 
-      build_lib() {
-         lib_src=$1
-         echo_build_heading $lib_src ${libName}
-
-         noisily rustc --crate-name $CRATE_NAME $lib_src --crate-type ${crateType} \
-           ${rustcOpts} ${rustcMeta} ${crateFeatures} --out-dir target/lib \
-           --emit=dep-info,link -L dependency=target/deps ${deps} --cap-lints allow \
-           $BUILD_OUT_DIR $EXTRA_BUILD $EXTRA_FEATURES --color ${colors}
-
-         EXTRA_LIB=" --extern $CRATE_NAME=target/lib/lib$CRATE_NAME-${metadata}.rlib"
-         if [ -e target/deps/lib$CRATE_NAME-${metadata}${buildPlatform.extensions.sharedLibrary} ]; then
-            EXTRA_LIB="$EXTRA_LIB --extern $CRATE_NAME=target/lib/lib$CRATE_NAME-${metadata}${buildPlatform.extensions.sharedLibrary}"
-         fi
-      }
-
-      build_bin() {
-        crate_name=$1
-        crate_name_=$(echo $crate_name | sed -e "s/-/_/g")
-	main_file=""
-	if [[ ! -z $2 ]]; then
-          main_file=$2
-	fi
-	echo_build_heading $@
-	noisily rustc --crate-name $crate_name_ $main_file --crate-type bin ${rustcOpts}\
-          ${crateFeatures} --out-dir target/bin --emit=dep-info,link -L dependency=target/deps \
-          $LINK ${deps}$EXTRA_LIB --cap-lints allow \
-          $BUILD_OUT_DIR $EXTRA_BUILD $EXTRA_FEATURES --color ${colors}
-        if [ "$crate_name_" -ne "$crate_name" ]; then
-          mv target/bin/$crate_name_ target/bin/$crate_name
-        fi
-      }
-
-      runHook preBuild
       mkdir -p target/{deps,lib,build,buildDeps}
       chmod uga+w target -R
       for i in ${completeDepsDir}; do
-        symlink_dependency $i
+        symlink_dependency $i target/deps
       done
       for i in ${completeBuildDepsDir}; do
-         symlink_dependency $i --buildDep
+         symlink_dependency $i target/buildDeps
       done
-      if [ -e target/link ]; then
+      if [[ -e target/link ]]; then
         sort -u target/link > target/link.sorted
         mv target/link.sorted target/link
         sort -u target/link.final > target/link.final.sorted
@@ -145,10 +96,16 @@ let buildCrate = { crateName, crateVersion, crateAuthors, buildDependencies,
       export CARGO_PKG_NAME=${crateName}
       export CARGO_PKG_VERSION=${crateVersion}
       export CARGO_PKG_AUTHORS="${authors}"
+
       export CARGO_CFG_TARGET_ARCH=${buildPlatform.parsed.cpu.name}
       export CARGO_CFG_TARGET_OS=${buildPlatform.parsed.kernel.name}
-
+      export CARGO_CFG_TARGET_FAMILY="unix"
+      export CARGO_CFG_UNIX=1
       export CARGO_CFG_TARGET_ENV="gnu"
+      export CARGO_CFG_TARGET_ENDIAN=${if buildPlatform.parsed.cpu.significantByte.name == "littleEndian" then "little" else "big"}
+      export CARGO_CFG_TARGET_POINTER_WIDTH=${toString buildPlatform.parsed.cpu.bits}
+      export CARGO_CFG_TARGET_VENDOR=${buildPlatform.parsed.vendor.name}
+
       export CARGO_MANIFEST_DIR="."
       export DEBUG="${toString (!release)}"
       export OPT_LEVEL="${toString optLevel}"
@@ -159,7 +116,7 @@ let buildCrate = { crateName, crateVersion, crateAuthors, buildDependencies,
       export CARGO_PKG_VERSION_MAJOR=${builtins.elemAt version 0}
       export CARGO_PKG_VERSION_MINOR=${builtins.elemAt version 1}
       export CARGO_PKG_VERSION_PATCH=${builtins.elemAt version 2}
-      if [ -n "${versionPre}" ]; then
+      if [[ -n "${versionPre}" ]]; then
         export CARGO_PKG_VERSION_PRE="${versionPre}"
       fi
 
@@ -180,8 +137,8 @@ let buildCrate = { crateName, crateVersion, crateAuthors, buildDependencies,
            EXTRA_BUILD_FLAGS="$EXTRA_BUILD_FLAGS $(cat target/link.build)"
          fi
          noisily rustc --crate-name build_script_build $BUILD --crate-type bin ${rustcOpts} \
-          ${crateFeatures} --out-dir target/build/${crateName} --emit=dep-info,link \
-          -L dependency=target/buildDeps ${buildDeps} --cap-lints allow $EXTRA_BUILD_FLAGS --color ${colors}
+           ${crateFeatures} --out-dir target/build/${crateName} --emit=dep-info,link \
+           -L dependency=target/buildDeps ${buildDeps} --cap-lints allow $EXTRA_BUILD_FLAGS --color ${colors}
 
          mkdir -p target/build/${crateName}.out
          export RUST_BACKTRACE=1
@@ -198,33 +155,104 @@ let buildCrate = { crateName, crateVersion, crateAuthors, buildDependencies,
            | sed -e "s/cargo:\([^=]*\)=\(.*\)/export DEP_$(echo $CRATENAME)_\U\1\E=\2/" > target/env
 
          set -e
-         if [ -n "$(ls target/build/${crateName}.out)" ]; then
+         if [[ -n "$(ls target/build/${crateName}.out)" ]]; then
 
-            if [ -e "${libPath}" ] ; then
+            if [[ -e "${libPath}" ]]; then
                cp -r target/build/${crateName}.out/* $(dirname ${libPath}) #*/
             else
                cp -r target/build/${crateName}.out/* src #*/
             fi
          fi
       fi
+      runHook postConfigure
+    '';
+
+    buildCrate = { crateName, crateVersion, crateAuthors,
+                   dependencies, completeDeps, completeBuildDeps,
+                   crateFeatures, libName, build, release, libPath,
+                   crateType, metadata, crateBin, finalBins,
+                   extraRustcOpts,
+                   verbose, colors }:
+
+      let depsDir = lib.concatStringsSep " " dependencies;
+          completeDepsDir = lib.concatStringsSep " " completeDeps;
+          completeBuildDepsDir = lib.concatStringsSep " " completeBuildDeps;
+          deps = makeDeps dependencies;
+          optLevel = if release then 3 else 0;
+          rustcOpts =
+            lib.lists.foldl' (opts: opt: opts + " " + opt)
+              (if release then "-C opt-level=3" else "-C debuginfo=2")
+              extraRustcOpts;
+          rustcMeta = "-C metadata=${metadata} -C extra-filename=-${metadata}";
+          version_ = lib.splitString "-" crateVersion;
+          versionPre = if lib.tail version_ == [] then "" else builtins.elemAt version_ 1;
+          version = lib.splitString "." (lib.head version_);
+          authors = lib.concatStringsSep ":" crateAuthors;
+      in ''
+      runHook preBuild
+      norm=""
+      bold=""
+      green=""
+      boldgreen=""
+      if [[ "${colors}" -eq "always" ]]; then
+        norm="$(printf '\033[0m')" #returns to "normal"
+        bold="$(printf '\033[0;1m')" #set bold
+        green="$(printf '\033[0;32m')" #set green
+        boldgreen="$(printf '\033[0;1;32m')" #set bold, and set green.
+      fi
+      ${echo_build_heading colors}
+      ${noisily colors verbose}
+
+      build_lib() {
+         lib_src=$1
+         echo_build_heading $lib_src ${libName}
+
+         noisily rustc --crate-name $CRATE_NAME $lib_src --crate-type ${crateType} \
+           ${rustcOpts} ${rustcMeta} ${crateFeatures} --out-dir target/lib \
+           --emit=dep-info,link -L dependency=target/deps ${deps} --cap-lints allow \
+           $BUILD_OUT_DIR $EXTRA_BUILD $EXTRA_FEATURES --color ${colors}
+
+         EXTRA_LIB=" --extern $CRATE_NAME=target/lib/lib$CRATE_NAME-${metadata}.rlib"
+         if [ -e target/deps/lib$CRATE_NAME-${metadata}${buildPlatform.extensions.sharedLibrary} ]; then
+            EXTRA_LIB="$EXTRA_LIB --extern $CRATE_NAME=target/lib/lib$CRATE_NAME-${metadata}${buildPlatform.extensions.sharedLibrary}"
+         fi
+      }
+
+      build_bin() {
+        crate_name=$1
+        crate_name_=$(echo $crate_name | sed -e "s/-/_/g")
+	main_file=""
+	if [[ ! -z $2 ]]; then
+          main_file=$2
+	fi
+	echo_build_heading $@
+	noisily rustc --crate-name $crate_name_ $main_file --crate-type bin ${rustcOpts}\
+          ${crateFeatures} --out-dir target/bin --emit=dep-info,link -L dependency=target/deps \
+          $LINK ${deps}$EXTRA_LIB --cap-lints allow \
+          $BUILD_OUT_DIR $EXTRA_BUILD $EXTRA_FEATURES --color ${colors}
+        if [ "$crate_name_" -ne "$crate_name" ]; then
+          mv target/bin/$crate_name_ target/bin/$crate_name
+        fi
+      }
+
 
       EXTRA_LIB=""
       CRATE_NAME=$(echo ${libName} | sed -e "s/-/_/g")
 
-      if [ -e target/link_ ]; then
+      if [[ -e target/link_ ]]; then
         EXTRA_BUILD="$(cat target/link_) $EXTRA_BUILD"
       fi
 
-      if [ -e "${libPath}" ] ; then
+      if [[ -e "${libPath}" ]]; then
          build_lib ${libPath}
-      elif [ -e src/lib.rs ] ; then
+      elif [[ -e src/lib.rs ]]; then
          build_lib src/lib.rs
-      elif [ -e src/${libName}.rs ] ; then
+      elif [[ -e src/${libName}.rs ]]; then
          build_lib src/${libName}.rs
       fi
 
       echo "$EXTRA_LINK_SEARCH" | while read i; do
-         if [ ! -z "$i" ]; then
+         if [[ ! -z "$i" ]]; then
            for lib in $i; do
              echo "-L $lib" >> target/link
              L=$(echo $lib | sed -e "s#$(pwd)/target/build#$out/lib#")
@@ -233,7 +261,7 @@ let buildCrate = { crateName, crateVersion, crateAuthors, buildDependencies,
          fi
       done
       echo "$EXTRA_LINK" | while read i; do
-         if [ ! -z "$i" ]; then
+         if [[ ! -z "$i" ]]; then
            for lib in $i; do
              echo "-l $lib" >> target/link
              echo "-l $lib" >> target/link.final
@@ -241,7 +269,7 @@ let buildCrate = { crateName, crateVersion, crateAuthors, buildDependencies,
          fi
       done
 
-      if [ -e target/link ]; then
+      if [[ -e target/link ]]; then
          sort -u target/link.final > target/link.final.sorted
          mv target/link.final.sorted target/link.final
          sort -u target/link > target/link.sorted
@@ -253,7 +281,7 @@ let buildCrate = { crateName, crateVersion, crateAuthors, buildDependencies,
 
       mkdir -p target/bin
       echo "${crateBin}" | sed -n 1'p' | tr ',' '\n' | while read BIN; do
-         if [ ! -z "$BIN" ]; then
+         if [[ ! -z "$BIN" ]]; then
            build_bin $BIN
          fi
       done
@@ -267,27 +295,32 @@ let buildCrate = { crateName, crateVersion, crateAuthors, buildDependencies,
       ''}
       # Remove object files to avoid "wrong ELF type"
       find target -type f -name "*.o" -print0 | xargs -0 rm -f
+    '' + finalBins + ''
       runHook postBuild
-    '' + finalBins;
+    '';
 
-    installCrate = crateName: ''
+    installCrate = crateName: metadata: ''
+      runHook preInstall
       mkdir -p $out
-      if [ -s target/env ]; then
+      if [[ -s target/env ]]; then
         cp target/env $out/env
       fi
-      if [ -s target/link.final ]; then
+      if [[ -s target/link.final ]]; then
         mkdir -p $out/lib
         cp target/link.final $out/lib/link
       fi
-      if [ "$(ls -A target/lib)" ]; then
+      if [[ "$(ls -A target/lib)" ]]; then
         mkdir -p $out/lib
         cp target/lib/* $out/lib #*/
+        for lib in $out/lib/*.so $out/lib/*.dylib; do #*/
+          ln -s $lib $(echo $lib | sed -e "s/-${metadata}//")
+        done
       fi
-      if [ "$(ls -A target/build)" ]; then # */
+      if [[ "$(ls -A target/build)" ]]; then # */
         mkdir -p $out/lib
         cp -r target/build/* $out/lib # */
       fi
-      if [ "$(ls -A target/bin)" ]; then
+      if [[ "$(ls -A target/bin)" ]]; then
         mkdir -p $out/bin
         cp -P target/bin/* $out/bin # */
       fi
@@ -295,9 +328,16 @@ let buildCrate = { crateName, crateVersion, crateAuthors, buildDependencies,
     '';
 in
 
-crate_: lib.makeOverridable ({ rust, release, verbose, features, buildInputs, crateOverrides }:
+crate_: lib.makeOverridable ({ rust, release, verbose, features, buildInputs, crateOverrides,
+  dependencies, buildDependencies,
+  extraRustcOpts,
+  preUnpack, postUnpack, prePatch, patches, postPatch,
+  preConfigure, postConfigure, preBuild, postBuild, preInstall, postInstall }:
 
 let crate = crate_ // (lib.attrByPath [ crate_.crateName ] (attr: {}) crateOverrides crate_);
+    release_ = release;
+    dependencies_ = dependencies;
+    buildDependencies_ = buildDependencies;
     processedAttrs = [
       "src" "buildInputs" "crateBin" "crateLib" "libName" "libPath"
       "buildDependencies" "dependencies" "features"
@@ -309,6 +349,7 @@ in
 stdenv.mkDerivation (rec {
 
     inherit (crate) crateName;
+    inherit preUnpack postUnpack prePatch patches postPatch preConfigure postConfigure preBuild postBuild preInstall postInstall;
 
     src = if lib.hasAttr "src" crate then
         crate.src
@@ -319,12 +360,12 @@ stdenv.mkDerivation (rec {
     dependencies =
       builtins.map
         (dep: dep.override { rust = rust; release = release; verbose = verbose; crateOverrides = crateOverrides; })
-        (crate.dependencies or []);
+        dependencies_;
 
     buildDependencies =
       builtins.map
         (dep: dep.override { rust = rust; release = release; verbose = verbose; crateOverrides = crateOverrides; })
-        (crate.buildDependencies or []);
+        buildDependencies_;
 
     completeDeps = lib.lists.unique (dependencies ++ lib.lists.concatMap (dep: dep.completeDeps) dependencies);
     completeBuildDeps = lib.lists.unique (
@@ -339,7 +380,8 @@ stdenv.mkDerivation (rec {
     libName = if crate ? libName then crate.libName else crate.crateName;
     libPath = if crate ? libPath then crate.libPath else "";
 
-    metadata = builtins.substring 0 10 (builtins.hashString "sha256" (crateName + "-" + crateVersion));
+    depsMetadata = builtins.foldl' (str: dep: str + dep.metadata) "" (dependencies ++ buildDependencies);
+    metadata = builtins.substring 0 10 (builtins.hashString "sha256" (crateName + "-" + crateVersion + "___" + toString crateFeatures + "___" + depsMetadata ));
 
     crateBin = if crate ? crateBin then
        builtins.foldl' (bins: bin:
@@ -370,20 +412,42 @@ stdenv.mkDerivation (rec {
     crateAuthors = if crate ? authors && lib.isList crate.authors then crate.authors else [];
     crateType =
       if lib.attrByPath ["procMacro"] false crate then "proc-macro" else
-      if lib.attrByPath ["plugin"] false crate then "dylib" else "lib";
+      if lib.attrByPath ["plugin"] false crate then "dylib" else
+      if crate ? type then crate.type else "lib";
     colors = lib.attrByPath [ "colors" ] "always" crate;
-    buildPhase = buildCrate {
+    configurePhase = configureCrate {
       inherit crateName dependencies buildDependencies completeDeps completeBuildDeps
+              crateFeatures libName build release libPath crateVersion
+              crateAuthors verbose colors;
+    };
+    extraRustcOpts = if crate ? extraRustcOpts then crate.extraRustcOpts else [];
+    buildPhase = buildCrate {
+      inherit crateName dependencies completeDeps completeBuildDeps
               crateFeatures libName build release libPath crateType crateVersion
-              crateAuthors metadata crateBin finalBins verbose colors;
+              crateAuthors metadata crateBin finalBins verbose colors extraRustcOpts;
     };
-    installPhase = installCrate crateName;
+    installPhase = installCrate crateName metadata;
 
-} // extraDerivationAttrs)) {
+} // extraDerivationAttrs
+)) {
   rust = rustc;
-  release = true;
-  verbose = true;
+  release = crate_.release or true;
+  verbose = crate_.verbose or true;
+  extraRustcOpts = [];
   features = [];
   buildInputs = [];
   crateOverrides = defaultCrateOverrides;
+  preUnpack = crate_.preUnpack or "";
+  postUnpack = crate_.postUnpack or "";
+  prePatch = crate_.prePatch or "";
+  patches = crate_.patches or [];
+  postPatch = crate_.postPatch or "";
+  preConfigure = crate_.preConfigure or "";
+  postConfigure = crate_.postConfigure or "";
+  preBuild = crate_.preBuild or "";
+  postBuild = crate_.postBuild or "";
+  preInstall = crate_.preInstall or "";
+  postInstall = crate_.postInstall or "";
+  dependencies = crate_.dependencies or [];
+  buildDependencies = crate_.buildDependencies or [];
 }
diff --git a/pkgs/build-support/rust/carnix.nix b/pkgs/build-support/rust/carnix.nix
index 8b0af499c8f1..ebb46b0f5921 100644
--- a/pkgs/build-support/rust/carnix.nix
+++ b/pkgs/build-support/rust/carnix.nix
@@ -1,4 +1,4 @@
-# Generated by carnix 0.6.5: carnix -o carnix.nix Cargo.lock --src ./.
+# Generated by carnix 0.6.5: carnix -o carnix.nix Cargo.lock
 { lib, buildPlatform, buildRustCrate, fetchgit }:
 let kernel = buildPlatform.parsed.kernel.name;
     abi = buildPlatform.parsed.abi.name;
@@ -18,7 +18,7 @@ let kernel = buildPlatform.parsed.kernel.name;
     ) [] (builtins.attrNames feat);
 in
 rec {
-  carnix = f: carnix_0_6_5 { features = carnix_0_6_5_features { carnix_0_6_5 = f; }; };
+  carnix = f: carnix_0_6_6 { features = carnix_0_6_6_features { carnix_0_6_6 = f; }; };
   aho_corasick_0_6_3_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
     crateName = "aho-corasick";
     version = "0.6.3";
@@ -71,11 +71,11 @@ rec {
     sha256 = "0p4b3nr0s5nda2qmm7xdhnvh4lkqk3xd8l9ffmwbvqw137vx7mj1";
     inherit dependencies buildDependencies features;
   };
-  carnix_0_6_5_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
+  carnix_0_6_6_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
     crateName = "carnix";
-    version = "0.6.5";
+    version = "0.6.6";
     authors = [ "pe@pijul.org <pe@pijul.org>" ];
-    sha256 = "0r952s5az5mhw7z2r421i5lr0w5h436hah61md2bdb3204c2pl9c";
+    sha256 = "1ai2r52j6vlrclhb7cvifx3lsg9naiy3jpsrbi3mmfmr6zbi7rdw";
     inherit dependencies buildDependencies features;
   };
   cc_1_0_3_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
@@ -623,11 +623,11 @@ rec {
       (f.bitflags_1_0_1.default or false) ||
       (bitflags_1_0_1.default or false);
   }) [];
-  carnix_0_6_5 = { features?(carnix_0_6_5_features {}) }: carnix_0_6_5_ {
+  carnix_0_6_6 = { features?(carnix_0_6_6_features {}) }: carnix_0_6_6_ {
     dependencies = mapFeatures features ([ clap_2_28_0 env_logger_0_5_3 error_chain_0_11_0 itertools_0_7_3 log_0_4_1 nom_3_2_1 regex_0_2_2 rusqlite_0_13_0 serde_1_0_21 serde_derive_1_0_21 serde_json_1_0_6 tempdir_0_3_5 toml_0_4_5 ]);
   };
-  carnix_0_6_5_features = f: updateFeatures f (rec {
-    carnix_0_6_5.default = (f.carnix_0_6_5.default or true);
+  carnix_0_6_6_features = f: updateFeatures f (rec {
+    carnix_0_6_6.default = (f.carnix_0_6_6.default or true);
     clap_2_28_0.default = true;
     env_logger_0_5_3.default = true;
     error_chain_0_11_0.default = true;