summaryrefslogtreecommitdiff
path: root/rust-utils.nix
diff options
context:
space:
mode:
Diffstat (limited to 'rust-utils.nix')
-rw-r--r--rust-utils.nix197
1 files changed, 197 insertions, 0 deletions
diff --git a/rust-utils.nix b/rust-utils.nix
new file mode 100644
index 0000000..be6ed39
--- /dev/null
+++ b/rust-utils.nix
@@ -0,0 +1,197 @@
+{ lib, buildPlatform, stdenv }:
+
+let buildCrate = { crateName, crateVersion, dependencies, complete, crateFeatures, libName, build, release, libPath, crateType, metadata, crateBin, finalBins }:
+
+ let depsDir = builtins.foldl' (deps: dep: deps + " " + dep.out) "" dependencies;
+ completeDepsDir = builtins.foldl' (deps: dep: deps + " " + dep.out) "" complete;
+ deps =
+ builtins.foldl' (deps: dep:
+ let extern = lib.strings.replaceStrings ["-"] ["_"] dep.libName; in
+ deps + (if dep.crateType == "lib" then
+ " --extern ${extern}=${dep.out}/lib${extern}-${dep.metadata}.rlib"
+ else
+ " --extern ${extern}=${dep.out}/lib${extern}-${dep.metadata}.so")
+ ) "" dependencies;
+ optLevel = if release then 3 else 0;
+ rustcOpts = (if release then "-C opt-level=3" else "-g");
+ rustcMeta = "-C metadata=" + metadata + " -C extra-filename=-" + metadata;
+ in ''
+ mkdir -p target/deps
+ mkdir -p target/build
+ chmod uga+w target -R
+
+ for i in ${completeDepsDir}; do
+ ln -s -f $i/*.rlib target/deps #*/
+ ln -s -f $i/*.so target/deps #*/
+ if [ -e "$i/link" ]; then
+ cat $i/link >> target/link
+ cat $i/link >> target/link.final
+ fi
+ done
+
+ EXTRA_BUILD=""
+ BUILD_OUT_DIR=""
+ export CARGO_PKG_NAME=${crateName}
+ export CARGO_PKG_VERSION=${crateVersion}
+ export CARGO_CFG_TARGET_ARCH=$(echo ${buildPlatform.system} | sed -e "s/\([^-]*\)-\([^-]*\)/\1/")
+ export CARGO_CFG_TARGET_OS=$(echo ${buildPlatform.system} | sed -e "s/\([^-]*\)-\([^-]*\)/\2/")
+
+ export CARGO_CFG_TARGET_ENV="gnu"
+ export CARGO_MANIFEST_DIR="."
+ export DEBUG="${toString (!release)}"
+ export OPT_LEVEL="${toString optLevel}"
+ export TARGET="${buildPlatform.system}-gnu"
+ export HOST="${buildPlatform.system}-gnu"
+ export PROFILE=${if release then "release" else "debug"}
+ export OUT_DIR=target/build/${crateName}.out
+
+ if [[ ! -z "${build}" ]] ; then
+ echo "Building ${build}"
+ mkdir -p target/build/${crateName}
+ rustc --crate-name build_script_build ${build} --crate-type bin ${rustcOpts} ${crateFeatures} --out-dir target/build/${crateName} --emit=dep-info,link -L dependency=target/deps ${deps} --cap-lints allow
+ mkdir -p target/build/${crateName}.out
+ export RUST_BACKTRACE=1
+ BUILD_OUT_DIR="-L $OUT_DIR"
+ mkdir -p $OUT_DIR
+ target/build/${crateName}/build_script_build > target/build/${crateName}.opt
+ set +e
+ EXTRA_BUILD=$(grep "^cargo:rustc-flags=" target/build/${crateName}.opt | sed -e "s/cargo:rustc-flags=\(.*\)/\1/")
+ EXTRA_FEATURES=$(grep "^cargo:rustc-cfg=" target/build/${crateName}.opt | sed -e "s/cargo:rustc-cfg=\(.*\)/--cfg \1/")
+
+ EXTRA_LINK=$(grep "^cargo:rustc-link-lib=" target/build/${crateName}.opt | sed -e "s/cargo:rustc-link-lib=\(.*\)/\1/")
+ EXTRA_LINK_SEARCH=$(grep "^cargo:rustc-link-search=" target/build/${crateName}.opt | sed -e "s/cargo:rustc-link-search=\(.*\)/\1/")
+ set -e
+ if [ -n "$(ls target/build/${crateName}.out)" ]; then
+
+ if [ -e "${libPath}" ] ; then
+ cp -r target/build/${crateName}.out/* $(dirname ${libPath}) #*/
+ else
+ cp -r target/build/${crateName}.out/* src #*/
+ fi
+ fi
+ fi
+ # echo "Features: ${crateFeatures}" $EXTRA_FEATURES
+
+ EXTRA_LIB=""
+ CRATE_NAME=$(echo ${libName} | sed -e "s/-/_/g")
+ # echo "Libname" ${libName} ${libPath}
+ # echo "Deps: ${deps}"
+ if [ -e "${libPath}" ] ; then
+
+ echo "Building ${libPath}"
+ rustc --crate-name $CRATE_NAME ${libPath} --crate-type ${crateType} ${rustcOpts} ${rustcMeta} ${crateFeatures} --out-dir target/deps --emit=dep-info,link -L dependency=target/deps ${deps} --cap-lints allow $BUILD_OUT_DIR $EXTRA_BUILD $EXTRA_FEATURES
+ EXTRA_LIB=" --extern $CRATE_NAME=target/deps/lib$CRATE_NAME-${metadata}.rlib"
+
+ elif [ -e src/lib.rs ] ; then
+
+ echo "Building src/lib.rs"
+ rustc --crate-name $CRATE_NAME src/lib.rs --crate-type ${crateType} ${rustcOpts} ${rustcMeta} ${crateFeatures} --out-dir target/deps --emit=dep-info,link -L dependency=target/deps ${deps} --cap-lints allow $BUILD_OUT_DIR $EXTRA_BUILD $EXTRA_FEATURES
+ EXTRA_LIB=" --extern $CRATE_NAME=target/deps/lib$CRATE_NAME-${metadata}.rlib"
+
+ elif [ -e src/${libName}.rs ] ; then
+
+ echo "Building src/${libName}.rs"
+ rustc --crate-name $CRATE_NAME src/${libName}.rs --crate-type ${crateType} ${rustcOpts} ${rustcMeta} ${crateFeatures} --out-dir target/deps --emit=dep-info,link -L dependency=target/deps ${deps} --cap-lints allow $BUILD_OUT_DIR $EXTRA_BUILD $EXTRA_FEATURES
+ EXTRA_LIB=" --extern $CRATE_NAME=target/deps/lib$CRATE_NAME-${metadata}.rlib"
+
+ fi
+
+ echo "$EXTRA_LINK_SEARCH" | while read i; do
+ if [ ! -z "$i" ]; then
+ echo "-L $i" >> target/link
+ L=$(echo $i | sed -e "s#target/build#$out#")
+ echo "-L $L" >> target/link.final
+ fi
+ done
+ echo "$EXTRA_LINK" | while read i; do
+ if [ ! -z "$i" ]; then
+ echo "-l $i" >> target/link
+ echo "-l $i" >> target/link.final
+ fi
+ done
+
+ if [ -e target/link ]; then
+ LINK=$(cat target/link)
+ fi
+
+ mkdir -p target/bin
+ echo "${crateBin}" | sed -n 1'p' | tr ',' '\n' | while read BIN; do
+ if [ ! -z "$BIN" ]; then
+ echo "Building $BIN"
+ echo rustc --crate-name $BIN --crate-type bin ${rustcOpts} ${crateFeatures} --out-dir target/bin --emit=dep-info,link -L dependency=target/deps ${deps}$EXTRA_LIB --cap-lints allow $BUILD_OUT_DIR $EXTRA_BUILD $EXTRA_FEATURES -C link-args="$LINK"
+ rustc --crate-name $BIN --crate-type bin ${rustcOpts} ${crateFeatures} --out-dir target/bin --emit=dep-info,link -L dependency=target/deps ${deps}$EXTRA_LIB --cap-lints allow $BUILD_OUT_DIR $EXTRA_BUILD $EXTRA_FEATURES -C link-args="$LINK"
+ fi
+ done
+ if [[ (-z "${crateBin}") && (-e src/main.rs) ]]; then
+ echo "Building src/main.rs"
+ echo rustc --crate-name $CRATE_NAME src/main.rs --crate-type bin ${rustcOpts} ${crateFeatures} --out-dir target/bin --emit=dep-info,link -L dependency=target/deps ${deps}$EXTRA_LIB --cap-lints allow $BUILD_OUT_DIR $EXTRA_BUILD $EXTRA_FEATURES -C link-args="$LINK"
+ rustc --crate-name $CRATE_NAME src/main.rs --crate-type bin ${rustcOpts} ${crateFeatures} --out-dir target/bin --emit=dep-info,link -L dependency=target/deps ${deps}$EXTRA_LIB --cap-lints allow $BUILD_OUT_DIR $EXTRA_BUILD $EXTRA_FEATURES -C link-args="$LINK"
+ fi
+ '' + finalBins;
+
+ installCrate = crateName: ''
+ mkdir -p $out
+ if [ -e target/link.final ]; then
+ cp target/link.final $out/link
+ fi
+ cp -PR target/deps/* $out # */
+ if [ "$(ls -A target/build)" ]; then # */
+ cp -PR target/build/* $out # */
+ fi
+ if [ "$(ls -A target/bin)" ]; then # */
+ mkdir -p $out/bin
+ cp -P target/bin/* $out/bin # */
+ fi
+ '';
+in
+
+crate: rust: stdenv.mkDerivation rec {
+
+ inherit (crate) crateName src;
+
+ release = if crate ? release then crate.release else false;
+ name = "rust_${crate.crateName}-${crate.version}";
+ buildInputs = [ rust ] ++ (lib.attrByPath ["buildInputs"] [] crate);
+ dependencies = builtins.map (dep: dep rust) (lib.attrByPath ["dependencies"] [] crate);
+
+ complete = builtins.foldl' (comp: dep: if lib.lists.any (x: x == comp) dep.complete then comp ++ dep.complete else comp) dependencies dependencies;
+
+ crateFeatures = if crate ? features then
+ builtins.foldl' (features: f: features + " --cfg feature=\\\"${f}\\\"") "" crate.features
+ else "";
+
+ 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));
+
+ crateBin = if crate ? crateBin then
+ builtins.foldl' (bins: bin:
+ let name =
+ lib.strings.replaceStrings ["-"] ["_"]
+ (if bin ? name then bin.name else crateName);
+ path = if bin ? path then bin.path else "src/main.rs";
+ in
+ bins + (if bin == "" then "" else ",") + "${name} ${path}"
+
+ ) "" crate.crateBin
+ else "";
+
+ finalBins = if crate ? crateBin then
+ builtins.foldl' (bins: bin:
+ let name = lib.strings.replaceStrings ["-"] ["_"]
+ (if bin ? name then bin.name else crateName);
+ new_name = if bin ? name then bin.name else crateName;
+ in
+ if name == new_name then bins else
+ (bins + "mv target/bin/${name} target/bin/${new_name};")
+
+ ) "" crate.crateBin
+ else "";
+
+ build = if crate ? build then crate.build else "";
+ crateVersion = crate.version;
+ crateType = if crate ? procMacro then if crate.procMacro then "proc-macro" else "lib" else "lib";
+ buildPhase = buildCrate { inherit crateName dependencies complete crateFeatures libName build release libPath crateType crateVersion metadata crateBin finalBins; };
+ installPhase = installCrate crateName;
+}