diff options
Diffstat (limited to 'rust-utils.nix')
-rw-r--r-- | rust-utils.nix | 197 |
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; +} |