232 lines
9 KiB
Nix
232 lines
9 KiB
Nix
|
{ lib, stdenv, echo_colored, noisily, mkRustcDepArgs, mkRustcFeatureArgs }:
|
||
|
{
|
||
|
build
|
||
|
, buildDependencies
|
||
|
, codegenUnits
|
||
|
, colors
|
||
|
, completeBuildDeps
|
||
|
, completeDeps
|
||
|
, crateAuthors
|
||
|
, crateDescription
|
||
|
, crateFeatures
|
||
|
, crateHomepage
|
||
|
, crateLicense
|
||
|
, crateLicenseFile
|
||
|
, crateLinks
|
||
|
, crateName
|
||
|
, crateReadme
|
||
|
, crateRenames
|
||
|
, crateRepository
|
||
|
, crateRustVersion
|
||
|
, crateVersion
|
||
|
, extraLinkFlags
|
||
|
, extraRustcOptsForBuildRs
|
||
|
, libName
|
||
|
, libPath
|
||
|
, release
|
||
|
, verbose
|
||
|
, workspace_member }:
|
||
|
let version_ = lib.splitString "-" crateVersion;
|
||
|
versionPre = lib.optionalString (lib.tail version_ != []) (lib.elemAt version_ 1);
|
||
|
version = lib.splitVersion (lib.head version_);
|
||
|
rustcOpts = lib.foldl' (opts: opt: opts + " " + opt)
|
||
|
(if release then "-C opt-level=3" else "-C debuginfo=2")
|
||
|
(["-C codegen-units=${toString codegenUnits}"] ++ extraRustcOptsForBuildRs);
|
||
|
buildDeps = mkRustcDepArgs buildDependencies crateRenames;
|
||
|
authors = lib.concatStringsSep ":" crateAuthors;
|
||
|
optLevel = if release then 3 else 0;
|
||
|
completeDepsDir = lib.concatStringsSep " " completeDeps;
|
||
|
completeBuildDepsDir = lib.concatStringsSep " " completeBuildDeps;
|
||
|
envFeatures = lib.concatStringsSep " " (
|
||
|
map (f: lib.replaceStrings ["-"] ["_"] (lib.toUpper f)) crateFeatures
|
||
|
);
|
||
|
in ''
|
||
|
${echo_colored colors}
|
||
|
${noisily colors verbose}
|
||
|
source ${./lib.sh}
|
||
|
|
||
|
${lib.optionalString (workspace_member != null) ''
|
||
|
noisily cd "${workspace_member}"
|
||
|
''}
|
||
|
${lib.optionalString (workspace_member == null) ''
|
||
|
echo_colored "Searching for matching Cargo.toml (${crateName})"
|
||
|
local cargo_toml_dir=$(matching_cargo_toml_dir "${crateName}")
|
||
|
if [ -z "$cargo_toml_dir" ]; then
|
||
|
echo_error "ERROR configuring ${crateName}: No matching Cargo.toml in $(pwd) found." >&2
|
||
|
exit 23
|
||
|
fi
|
||
|
noisily cd "$cargo_toml_dir"
|
||
|
''}
|
||
|
|
||
|
runHook preConfigure
|
||
|
|
||
|
symlink_dependency() {
|
||
|
# $1 is the nix-store path of a dependency
|
||
|
# $2 is the target path
|
||
|
i=$1
|
||
|
ln -s -f $i/lib/*.rlib $2 #*/
|
||
|
ln -s -f $i/lib/*.so $i/lib/*.dylib $2 #*/
|
||
|
if [ -e $i/env ]; then
|
||
|
source $i/env
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
# The following steps set up the dependencies of the crate. Two
|
||
|
# kinds of dependencies are distinguished: build dependencies
|
||
|
# (used by the build script) and crate dependencies. For each
|
||
|
# dependency we have to:
|
||
|
#
|
||
|
# - Make its Rust library available to rustc. This is done by
|
||
|
# symlinking all library dependencies into a directory that
|
||
|
# can be provided to rustc.
|
||
|
# - Accumulate linking flags. These flags are largely used for
|
||
|
# linking native libraries.
|
||
|
#
|
||
|
# The crate link flags are added to the `link` and `link.final`
|
||
|
# files. The `link` file is used for linkage in the current
|
||
|
# crate. The `link.final` file will be copied to the output and can
|
||
|
# be used by downstream crates to get the linker flags of this
|
||
|
# crate.
|
||
|
|
||
|
mkdir -p target/{deps,lib,build,buildDeps}
|
||
|
chmod uga+w target -R
|
||
|
echo ${extraLinkFlags} > target/link
|
||
|
echo ${extraLinkFlags} > target/link.final
|
||
|
|
||
|
# Prepare crate dependencies
|
||
|
for i in ${completeDepsDir}; do
|
||
|
symlink_dependency $i target/deps
|
||
|
if [ -e "$i/lib/link" ]; then
|
||
|
cat $i/lib/link >> target/link
|
||
|
cat $i/lib/link >> target/link.final
|
||
|
fi
|
||
|
done
|
||
|
|
||
|
# Prepare crate build dependencies that are used for the build script.
|
||
|
for i in ${completeBuildDepsDir}; do
|
||
|
symlink_dependency $i target/buildDeps
|
||
|
if [ -e "$i/lib/link" ]; then
|
||
|
cat $i/lib/link >> target/link.build
|
||
|
fi
|
||
|
done
|
||
|
|
||
|
# Remove duplicate linker flags from the build dependencies.
|
||
|
if [[ -e target/link.build ]]; then
|
||
|
sort -uo target/link.build target/link.build
|
||
|
fi
|
||
|
|
||
|
# Remove duplicate linker flags from the dependencies.
|
||
|
sort -uo target/link target/link
|
||
|
tr '\n' ' ' < target/link > target/link_
|
||
|
|
||
|
# Remove duplicate linker flags from the that are written
|
||
|
# to the derivation's output.
|
||
|
sort -uo target/link.final target/link.final
|
||
|
|
||
|
EXTRA_BUILD=""
|
||
|
BUILD_OUT_DIR=""
|
||
|
|
||
|
# Set up Cargo Environment variables: https://doc.rust-lang.org/cargo/reference/environment-variables.html
|
||
|
export CARGO_PKG_NAME=${crateName}
|
||
|
export CARGO_PKG_VERSION=${crateVersion}
|
||
|
export CARGO_PKG_AUTHORS="${authors}"
|
||
|
export CARGO_PKG_DESCRIPTION="${crateDescription}"
|
||
|
|
||
|
export CARGO_CFG_TARGET_ARCH=${stdenv.hostPlatform.rust.platform.arch}
|
||
|
export CARGO_CFG_TARGET_OS=${stdenv.hostPlatform.rust.platform.os}
|
||
|
export CARGO_CFG_TARGET_FAMILY="unix"
|
||
|
export CARGO_CFG_UNIX=1
|
||
|
export CARGO_CFG_TARGET_ENV="gnu"
|
||
|
export CARGO_CFG_TARGET_ENDIAN=${if stdenv.hostPlatform.parsed.cpu.significantByte.name == "littleEndian" then "little" else "big"}
|
||
|
export CARGO_CFG_TARGET_POINTER_WIDTH=${with stdenv.hostPlatform; toString (if isILP32 then 32 else parsed.cpu.bits)}
|
||
|
export CARGO_CFG_TARGET_VENDOR=${stdenv.hostPlatform.parsed.vendor.name}
|
||
|
|
||
|
export CARGO_MANIFEST_DIR=$(pwd)
|
||
|
export CARGO_MANIFEST_LINKS=${crateLinks}
|
||
|
export DEBUG="${toString (!release)}"
|
||
|
export OPT_LEVEL="${toString optLevel}"
|
||
|
export TARGET="${stdenv.hostPlatform.rust.rustcTargetSpec}"
|
||
|
export HOST="${stdenv.buildPlatform.rust.rustcTargetSpec}"
|
||
|
export PROFILE=${if release then "release" else "debug"}
|
||
|
export OUT_DIR=$(pwd)/target/build/${crateName}.out
|
||
|
export CARGO_PKG_VERSION_MAJOR=${lib.elemAt version 0}
|
||
|
export CARGO_PKG_VERSION_MINOR=${lib.elemAt version 1}
|
||
|
export CARGO_PKG_VERSION_PATCH=${lib.elemAt version 2}
|
||
|
export CARGO_PKG_VERSION_PRE="${versionPre}"
|
||
|
export CARGO_PKG_HOMEPAGE="${crateHomepage}"
|
||
|
export CARGO_PKG_LICENSE="${crateLicense}"
|
||
|
export CARGO_PKG_LICENSE_FILE="${crateLicenseFile}"
|
||
|
export CARGO_PKG_README="${crateReadme}"
|
||
|
export CARGO_PKG_REPOSITORY="${crateRepository}"
|
||
|
export CARGO_PKG_RUST_VERSION="${crateRustVersion}"
|
||
|
export NUM_JOBS=$NIX_BUILD_CORES
|
||
|
export RUSTC="rustc"
|
||
|
export RUSTDOC="rustdoc"
|
||
|
|
||
|
BUILD=""
|
||
|
if [[ ! -z "${build}" ]] ; then
|
||
|
BUILD=${build}
|
||
|
elif [[ -e "build.rs" ]]; then
|
||
|
BUILD="build.rs"
|
||
|
fi
|
||
|
|
||
|
# Compile and run the build script, when available.
|
||
|
if [[ ! -z "$BUILD" ]] ; then
|
||
|
echo_build_heading "$BUILD" ${libName}
|
||
|
mkdir -p target/build/${crateName}
|
||
|
EXTRA_BUILD_FLAGS=""
|
||
|
if [ -e target/link.build ]; then
|
||
|
EXTRA_BUILD_FLAGS="$EXTRA_BUILD_FLAGS $(tr '\n' ' ' < target/link.build)"
|
||
|
fi
|
||
|
noisily rustc --crate-name build_script_build $BUILD --crate-type bin ${rustcOpts} \
|
||
|
${mkRustcFeatureArgs 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
|
||
|
BUILD_OUT_DIR="-L $OUT_DIR"
|
||
|
mkdir -p $OUT_DIR
|
||
|
|
||
|
(
|
||
|
# Features should be set as environment variable for build scripts:
|
||
|
# https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts
|
||
|
for feature in ${envFeatures}; do
|
||
|
export CARGO_FEATURE_$feature=1
|
||
|
done
|
||
|
|
||
|
target/build/${crateName}/build_script_build > target/build/${crateName}.opt
|
||
|
)
|
||
|
|
||
|
set +e
|
||
|
EXTRA_BUILD=$(sed -n "s/^cargo:rustc-flags=\(.*\)/\1/p" target/build/${crateName}.opt | tr '\n' ' ' | sort -u)
|
||
|
EXTRA_FEATURES=$(sed -n "s/^cargo:rustc-cfg=\(.*\)/--cfg \1/p" target/build/${crateName}.opt | tr '\n' ' ')
|
||
|
EXTRA_LINK_ARGS=$(sed -n "s/^cargo:rustc-link-arg=\(.*\)/-C link-arg=\1/p" target/build/${crateName}.opt | tr '\n' ' ')
|
||
|
EXTRA_LINK_ARGS_BINS=$(sed -n "s/^cargo:rustc-link-arg-bins=\(.*\)/-C link-arg=\1/p" target/build/${crateName}.opt | tr '\n' ' ')
|
||
|
EXTRA_LINK_ARGS_LIB=$(sed -n "s/^cargo:rustc-link-arg-lib=\(.*\)/-C link-arg=\1/p" target/build/${crateName}.opt | tr '\n' ' ')
|
||
|
EXTRA_LINK_LIBS=$(sed -n "s/^cargo:rustc-link-lib=\(.*\)/\1/p" target/build/${crateName}.opt | tr '\n' ' ')
|
||
|
EXTRA_LINK_SEARCH=$(sed -n "s/^cargo:rustc-link-search=\(.*\)/\1/p" target/build/${crateName}.opt | tr '\n' ' ' | sort -u)
|
||
|
|
||
|
# We want to read part of every line that has cargo:rustc-env= prefix and
|
||
|
# export it as environment variables. This turns out tricky if the lines
|
||
|
# have spaces: we can't wrap the command in double quotes as that captures
|
||
|
# all the lines in single output. We can't use while read loop because
|
||
|
# exporting from inside of it doesn't make it to the outside scope. We
|
||
|
# can't use xargs as export is a built-in and does not work from it. As a
|
||
|
# last resort then, we change the IFS so that the for loop does not split
|
||
|
# on spaces and reset it after we are done. See ticket #199298.
|
||
|
#
|
||
|
_OLDIFS="$IFS"
|
||
|
IFS=$'\n'
|
||
|
for env in $(sed -n "s/^cargo:rustc-env=\(.*\)/\1/p" target/build/${crateName}.opt); do
|
||
|
export "$env"
|
||
|
done
|
||
|
IFS="$_OLDIFS"
|
||
|
|
||
|
CRATENAME=$(echo ${crateName} | sed -e "s/\(.*\)-sys$/\U\1/" -e "s/-/_/g")
|
||
|
grep -P "^cargo:(?!(rustc-|warning=|rerun-if-changed=|rerun-if-env-changed))" target/build/${crateName}.opt \
|
||
|
| awk -F= "/^cargo:/ { sub(/^cargo:/, \"\", \$1); gsub(/-/, \"_\", \$1); print \"export \" toupper(\"DEP_$(echo $CRATENAME)_\" \$1) \"=\" \$2 }" > target/env
|
||
|
set -e
|
||
|
fi
|
||
|
runHook postConfigure
|
||
|
''
|