uboot: (firmwareOdroidC2/C4) don't invoke patch tool, use patches = [] instead
https://github.com/NixOS/nixpkgs/blob/master/pkgs/stdenv/generic/setup.sh#L948 this can do it nicely. Signed-off-by: Anton Arapov <anton@deadbeef.mx>
This commit is contained in:
commit
56de2bcd43
30691 changed files with 3076956 additions and 0 deletions
113
pkgs/build-support/rust/build-rust-crate/build-crate.nix
Normal file
113
pkgs/build-support/rust/build-rust-crate/build-crate.nix
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
{ lib, stdenv, mkRustcDepArgs, mkRustcFeatureArgs, rust }:
|
||||
{ crateName,
|
||||
dependencies,
|
||||
crateFeatures, crateRenames, libName, release, libPath,
|
||||
crateType, metadata, crateBin, hasCrateBin,
|
||||
extraRustcOpts, verbose, colors,
|
||||
buildTests,
|
||||
codegenUnits
|
||||
}:
|
||||
|
||||
let
|
||||
baseRustcOpts =
|
||||
[
|
||||
(if release then "-C opt-level=3" else "-C debuginfo=2")
|
||||
"-C codegen-units=${toString codegenUnits}"
|
||||
"--remap-path-prefix=$NIX_BUILD_TOP=/"
|
||||
(mkRustcDepArgs dependencies crateRenames)
|
||||
(mkRustcFeatureArgs crateFeatures)
|
||||
] ++ lib.optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
|
||||
"--target" (rust.toRustTargetSpec stdenv.hostPlatform)
|
||||
] ++ extraRustcOpts
|
||||
# since rustc 1.42 the "proc_macro" crate is part of the default crate prelude
|
||||
# https://github.com/rust-lang/cargo/commit/4d64eb99a4#diff-7f98585dbf9d30aa100c8318e2c77e79R1021-R1022
|
||||
++ lib.optional (lib.elem "proc-macro" crateType) "--extern proc_macro"
|
||||
;
|
||||
rustcMeta = "-C metadata=${metadata} -C extra-filename=-${metadata}";
|
||||
|
||||
|
||||
# build the final rustc arguments that can be different between different
|
||||
# crates
|
||||
libRustcOpts = lib.concatStringsSep " " (
|
||||
baseRustcOpts
|
||||
++ [rustcMeta]
|
||||
++ (map (x: "--crate-type ${x}") crateType)
|
||||
);
|
||||
|
||||
binRustcOpts = lib.concatStringsSep " " (
|
||||
baseRustcOpts
|
||||
);
|
||||
|
||||
build_bin = if buildTests then "build_bin_test" else "build_bin";
|
||||
in ''
|
||||
runHook preBuild
|
||||
|
||||
# configure & source common build functions
|
||||
LIB_RUSTC_OPTS="${libRustcOpts}"
|
||||
BIN_RUSTC_OPTS="${binRustcOpts}"
|
||||
LIB_EXT="${stdenv.hostPlatform.extensions.sharedLibrary}"
|
||||
LIB_PATH="${libPath}"
|
||||
LIB_NAME="${libName}"
|
||||
|
||||
CRATE_NAME='${lib.replaceStrings ["-"] ["_"] libName}'
|
||||
|
||||
setup_link_paths
|
||||
|
||||
if [[ -e "$LIB_PATH" ]]; then
|
||||
build_lib "$LIB_PATH"
|
||||
${lib.optionalString buildTests ''build_lib_test "$LIB_PATH"''}
|
||||
elif [[ -e src/lib.rs ]]; then
|
||||
build_lib src/lib.rs
|
||||
${lib.optionalString buildTests "build_lib_test src/lib.rs"}
|
||||
fi
|
||||
|
||||
|
||||
|
||||
${lib.optionalString (lib.length crateBin > 0) (lib.concatMapStringsSep "\n" (bin: ''
|
||||
mkdir -p target/bin
|
||||
BIN_NAME='${bin.name or crateName}'
|
||||
${if !bin ? path then ''
|
||||
BIN_PATH=""
|
||||
search_for_bin_path "$BIN_NAME"
|
||||
'' else ''
|
||||
BIN_PATH='${bin.path}'
|
||||
''}
|
||||
${build_bin} "$BIN_NAME" "$BIN_PATH"
|
||||
'') crateBin)}
|
||||
|
||||
${lib.optionalString buildTests ''
|
||||
# When tests are enabled build all the files in the `tests` directory as
|
||||
# test binaries.
|
||||
if [ -d tests ]; then
|
||||
# find all the .rs files (or symlinks to those) in the tests directory, no subdirectories
|
||||
find tests -maxdepth 1 \( -type f -o -type l \) -a -name '*.rs' -print0 | while IFS= read -r -d ''' file; do
|
||||
mkdir -p target/bin
|
||||
build_bin_test_file "$file"
|
||||
done
|
||||
|
||||
# find all the subdirectories of tests/ that contain a main.rs file as
|
||||
# that is also a test according to cargo
|
||||
find tests/ -mindepth 1 -maxdepth 2 \( -type f -o -type l \) -a -name 'main.rs' -print0 | while IFS= read -r -d ''' file; do
|
||||
mkdir -p target/bin
|
||||
build_bin_test_file "$file"
|
||||
done
|
||||
|
||||
fi
|
||||
''}
|
||||
|
||||
# If crateBin is empty and hasCrateBin is not set then we must try to
|
||||
# detect some kind of bin target based on some files that might exist.
|
||||
${lib.optionalString (lib.length crateBin == 0 && !hasCrateBin) ''
|
||||
if [[ -e src/main.rs ]]; then
|
||||
mkdir -p target/bin
|
||||
${build_bin} ${crateName} src/main.rs
|
||||
fi
|
||||
for i in src/bin/*.rs; do #*/
|
||||
mkdir -p target/bin
|
||||
${build_bin} "$(basename $i .rs)" "$i"
|
||||
done
|
||||
''}
|
||||
# Remove object files to avoid "wrong ELF type"
|
||||
find target -type f -name "*.o" -print0 | xargs -0 rm -f
|
||||
runHook postBuild
|
||||
''
|
||||
202
pkgs/build-support/rust/build-rust-crate/configure-crate.nix
Normal file
202
pkgs/build-support/rust/build-rust-crate/configure-crate.nix
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
{ lib, stdenv, rust, echo_colored, noisily, mkRustcDepArgs, mkRustcFeatureArgs }:
|
||||
{
|
||||
build
|
||||
, buildDependencies
|
||||
, codegenUnits
|
||||
, colors
|
||||
, completeBuildDeps
|
||||
, completeDeps
|
||||
, crateAuthors
|
||||
, crateDescription
|
||||
, crateHomepage
|
||||
, crateFeatures
|
||||
, crateName
|
||||
, crateRenames
|
||||
, crateVersion
|
||||
, extraLinkFlags
|
||||
, extraRustcOptsForBuildRs
|
||||
, libName
|
||||
, libPath
|
||||
, release
|
||||
, verbose
|
||||
, workspace_member }:
|
||||
let version_ = lib.splitString "-" crateVersion;
|
||||
versionPre = if lib.tail version_ == [] then "" else 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.replaceChars ["-"] ["_"] (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=""
|
||||
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=${rust.toTargetArch stdenv.hostPlatform}
|
||||
export CARGO_CFG_TARGET_OS=${rust.toTargetOs stdenv.hostPlatform}
|
||||
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=${toString stdenv.hostPlatform.parsed.cpu.bits}
|
||||
export CARGO_CFG_TARGET_VENDOR=${stdenv.hostPlatform.parsed.vendor.name}
|
||||
|
||||
export CARGO_MANIFEST_DIR=$(pwd)
|
||||
export DEBUG="${toString (!release)}"
|
||||
export OPT_LEVEL="${toString optLevel}"
|
||||
export TARGET="${rust.toRustTargetSpec stdenv.hostPlatform}"
|
||||
export HOST="${rust.toRustTargetSpec stdenv.buildPlatform}"
|
||||
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 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=$(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)
|
||||
|
||||
for env in $(sed -n "s/^cargo:rustc-env=\(.*\)/\1/p" target/build/${crateName}.opt); do
|
||||
export $env
|
||||
done
|
||||
|
||||
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
|
||||
''
|
||||
380
pkgs/build-support/rust/build-rust-crate/default.nix
Normal file
380
pkgs/build-support/rust/build-rust-crate/default.nix
Normal file
|
|
@ -0,0 +1,380 @@
|
|||
# Code for buildRustCrate, a Nix function that builds Rust code, just
|
||||
# like Cargo, but using Nix instead.
|
||||
#
|
||||
# This can be useful for deploying packages with NixOps, and to share
|
||||
# binary dependencies between projects.
|
||||
|
||||
{ lib
|
||||
, stdenv
|
||||
, defaultCrateOverrides
|
||||
, fetchCrate
|
||||
, pkgsBuildBuild
|
||||
, rustc
|
||||
, rust
|
||||
, cargo
|
||||
, jq
|
||||
, libiconv
|
||||
}:
|
||||
|
||||
let
|
||||
# Create rustc arguments to link against the given list of dependencies
|
||||
# and renames.
|
||||
#
|
||||
# See docs for crateRenames below.
|
||||
mkRustcDepArgs = dependencies: crateRenames:
|
||||
lib.concatMapStringsSep " "
|
||||
(dep:
|
||||
let
|
||||
normalizeName = lib.replaceStrings [ "-" ] [ "_" ];
|
||||
extern = normalizeName dep.libName;
|
||||
# Find a choice that matches in name and optionally version.
|
||||
findMatchOrUseExtern = choices:
|
||||
lib.findFirst
|
||||
(choice:
|
||||
(!(choice ? version)
|
||||
|| choice.version == dep.version or ""))
|
||||
{ rename = extern; }
|
||||
choices;
|
||||
name =
|
||||
if lib.hasAttr dep.crateName crateRenames then
|
||||
let choices = crateRenames.${dep.crateName};
|
||||
in
|
||||
normalizeName (
|
||||
if builtins.isList choices
|
||||
then (findMatchOrUseExtern choices).rename
|
||||
else choices
|
||||
)
|
||||
else
|
||||
extern;
|
||||
in
|
||||
(if lib.any (x: x == "lib" || x == "rlib") dep.crateType then
|
||||
" --extern ${name}=${dep.lib}/lib/lib${extern}-${dep.metadata}.rlib"
|
||||
else
|
||||
" --extern ${name}=${dep.lib}/lib/lib${extern}-${dep.metadata}${stdenv.hostPlatform.extensions.sharedLibrary}")
|
||||
)
|
||||
dependencies;
|
||||
|
||||
# Create feature arguments for rustc.
|
||||
mkRustcFeatureArgs = lib.concatMapStringsSep " " (f: ''--cfg feature=\"${f}\"'');
|
||||
|
||||
inherit (import ./log.nix { inherit lib; }) noisily echo_colored;
|
||||
|
||||
configureCrate = import ./configure-crate.nix {
|
||||
inherit lib stdenv rust echo_colored noisily mkRustcDepArgs mkRustcFeatureArgs;
|
||||
};
|
||||
|
||||
buildCrate = import ./build-crate.nix {
|
||||
inherit lib stdenv mkRustcDepArgs mkRustcFeatureArgs rust;
|
||||
};
|
||||
|
||||
installCrate = import ./install-crate.nix { inherit stdenv; };
|
||||
|
||||
# Allow access to the rust attribute set from inside buildRustCrate, which
|
||||
# has a parameter that shadows the name.
|
||||
rustAttrs = rust;
|
||||
in
|
||||
|
||||
/* The overridable pkgs.buildRustCrate function.
|
||||
*
|
||||
* Any unrecognized parameters will be passed as to
|
||||
* the underlying stdenv.mkDerivation.
|
||||
*/
|
||||
crate_: lib.makeOverridable
|
||||
(
|
||||
# The rust compiler to use.
|
||||
#
|
||||
# Default: pkgs.rustc
|
||||
{ rust
|
||||
# Whether to build a release version (`true`) or a debug
|
||||
# version (`false`). Debug versions are faster to build
|
||||
# but might be much slower at runtime.
|
||||
, release
|
||||
# Whether to print rustc invocations etc.
|
||||
#
|
||||
# Example: false
|
||||
# Default: true
|
||||
, verbose
|
||||
# A list of rust/cargo features to enable while building the crate.
|
||||
# Example: [ "std" "async" ]
|
||||
, features
|
||||
# Additional native build inputs for building this crate.
|
||||
, nativeBuildInputs
|
||||
# Additional build inputs for building this crate.
|
||||
#
|
||||
# Example: [ pkgs.openssl ]
|
||||
, buildInputs
|
||||
# Allows to override the parameters to buildRustCrate
|
||||
# for any rust dependency in the transitive build tree.
|
||||
#
|
||||
# Default: pkgs.defaultCrateOverrides
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# pkgs.defaultCrateOverrides // {
|
||||
# hello = attrs: { buildInputs = [ openssl ]; };
|
||||
# }
|
||||
, crateOverrides
|
||||
# Rust library dependencies, i.e. other libaries that were built
|
||||
# with buildRustCrate.
|
||||
, dependencies
|
||||
# Rust build dependencies, i.e. other libaries that were built
|
||||
# with buildRustCrate and are used by a build script.
|
||||
, buildDependencies
|
||||
# Specify the "extern" name of a library if it differs from the library target.
|
||||
# See above for an extended explanation.
|
||||
#
|
||||
# Default: no renames.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# `crateRenames` supports two formats.
|
||||
#
|
||||
# The simple version is an attrset that maps the
|
||||
# `crateName`s of the dependencies to their alternative
|
||||
# names.
|
||||
#
|
||||
# ```nix
|
||||
# {
|
||||
# my_crate_name = "my_alternative_name";
|
||||
# # ...
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# The extended version is also keyed by the `crateName`s but allows
|
||||
# different names for different crate versions:
|
||||
#
|
||||
# ```nix
|
||||
# {
|
||||
# my_crate_name = [
|
||||
# { version = "1.2.3"; rename = "my_alternative_name01"; }
|
||||
# { version = "3.2.3"; rename = "my_alternative_name03"; }
|
||||
# ]
|
||||
# # ...
|
||||
# }
|
||||
# ```
|
||||
#
|
||||
# This roughly corresponds to the following snippet in Cargo.toml:
|
||||
#
|
||||
# ```toml
|
||||
# [dependencies]
|
||||
# my_alternative_name01 = { package = "my_crate_name", version = "0.1" }
|
||||
# my_alternative_name03 = { package = "my_crate_name", version = "0.3" }
|
||||
# ```
|
||||
#
|
||||
# Dependencies which use the lib target name as extern name, do not need
|
||||
# to be specified in the crateRenames, even if their crate name differs.
|
||||
#
|
||||
# Including multiple versions of a crate is very popular during
|
||||
# ecosystem transitions, e.g. from futures 0.1 to futures 0.3.
|
||||
, crateRenames
|
||||
# A list of extra options to pass to rustc.
|
||||
#
|
||||
# Example: [ "-Z debuginfo=2" ]
|
||||
# Default: []
|
||||
, extraRustcOpts
|
||||
# A list of extra options to pass to rustc when building a build.rs.
|
||||
#
|
||||
# Example: [ "-Z debuginfo=2" ]
|
||||
# Default: []
|
||||
, extraRustcOptsForBuildRs
|
||||
# Whether to enable building tests.
|
||||
# Use true to enable.
|
||||
# Default: false
|
||||
, buildTests
|
||||
# Passed to stdenv.mkDerivation.
|
||||
, preUnpack
|
||||
# Passed to stdenv.mkDerivation.
|
||||
, postUnpack
|
||||
# Passed to stdenv.mkDerivation.
|
||||
, prePatch
|
||||
# Passed to stdenv.mkDerivation.
|
||||
, patches
|
||||
# Passed to stdenv.mkDerivation.
|
||||
, postPatch
|
||||
# Passed to stdenv.mkDerivation.
|
||||
, preConfigure
|
||||
# Passed to stdenv.mkDerivation.
|
||||
, postConfigure
|
||||
# Passed to stdenv.mkDerivation.
|
||||
, preBuild
|
||||
# Passed to stdenv.mkDerivation.
|
||||
, postBuild
|
||||
# Passed to stdenv.mkDerivation.
|
||||
, preInstall
|
||||
# Passed to stdenv.mkDerivation.
|
||||
, postInstall
|
||||
}:
|
||||
|
||||
let
|
||||
crate = crate_ // (lib.attrByPath [ crate_.crateName ] (attr: { }) crateOverrides crate_);
|
||||
dependencies_ = dependencies;
|
||||
buildDependencies_ = buildDependencies;
|
||||
processedAttrs = [
|
||||
"src"
|
||||
"nativeBuildInputs"
|
||||
"buildInputs"
|
||||
"crateBin"
|
||||
"crateLib"
|
||||
"libName"
|
||||
"libPath"
|
||||
"buildDependencies"
|
||||
"dependencies"
|
||||
"features"
|
||||
"crateRenames"
|
||||
"crateName"
|
||||
"version"
|
||||
"build"
|
||||
"authors"
|
||||
"colors"
|
||||
"edition"
|
||||
"buildTests"
|
||||
"codegenUnits"
|
||||
];
|
||||
extraDerivationAttrs = builtins.removeAttrs crate processedAttrs;
|
||||
nativeBuildInputs_ = nativeBuildInputs;
|
||||
buildInputs_ = buildInputs;
|
||||
extraRustcOpts_ = extraRustcOpts;
|
||||
extraRustcOptsForBuildRs_ = extraRustcOptsForBuildRs;
|
||||
buildTests_ = buildTests;
|
||||
|
||||
# crate2nix has a hack for the old bash based build script that did split
|
||||
# entries at `,`. No we have to work around that hack.
|
||||
# https://github.com/kolloch/crate2nix/blame/5b19c1b14e1b0e5522c3e44e300d0b332dc939e7/crate2nix/templates/build.nix.tera#L89
|
||||
crateBin = lib.filter (bin: !(bin ? name && bin.name == ",")) (crate.crateBin or [ ]);
|
||||
hasCrateBin = crate ? crateBin;
|
||||
in
|
||||
stdenv.mkDerivation (rec {
|
||||
|
||||
inherit (crate) crateName;
|
||||
inherit
|
||||
preUnpack
|
||||
postUnpack
|
||||
prePatch
|
||||
patches
|
||||
postPatch
|
||||
preConfigure
|
||||
postConfigure
|
||||
preBuild
|
||||
postBuild
|
||||
preInstall
|
||||
postInstall
|
||||
buildTests
|
||||
;
|
||||
|
||||
src = crate.src or (fetchCrate { inherit (crate) crateName version sha256; });
|
||||
name = "rust_${crate.crateName}-${crate.version}${lib.optionalString buildTests_ "-test"}";
|
||||
version = crate.version;
|
||||
depsBuildBuild = [ pkgsBuildBuild.stdenv.cc ];
|
||||
nativeBuildInputs = [ rust stdenv.cc cargo jq ] ++ (crate.nativeBuildInputs or [ ]) ++ nativeBuildInputs_;
|
||||
buildInputs = lib.optionals stdenv.isDarwin [ libiconv ] ++ (crate.buildInputs or [ ]) ++ buildInputs_;
|
||||
dependencies = map lib.getLib dependencies_;
|
||||
buildDependencies = map lib.getLib buildDependencies_;
|
||||
|
||||
completeDeps = lib.unique (dependencies ++ lib.concatMap (dep: dep.completeDeps) dependencies);
|
||||
completeBuildDeps = lib.unique (
|
||||
buildDependencies
|
||||
++ lib.concatMap (dep: dep.completeBuildDeps ++ dep.completeDeps) buildDependencies
|
||||
);
|
||||
|
||||
# Create a list of features that are enabled by the crate itself and
|
||||
# through the features argument of buildRustCrate. Exclude features
|
||||
# with a forward slash, since they are passed through to dependencies,
|
||||
# and dep: features, since they're internal-only and do nothing except
|
||||
# enable optional dependencies.
|
||||
crateFeatures = lib.optionals (crate ? features)
|
||||
(builtins.filter
|
||||
(f: !(lib.hasInfix "/" f || lib.hasPrefix "dep:" f))
|
||||
(crate.features ++ features)
|
||||
);
|
||||
|
||||
libName = if crate ? libName then crate.libName else crate.crateName;
|
||||
libPath = if crate ? libPath then crate.libPath else "";
|
||||
|
||||
# Seed the symbol hashes with something unique every time.
|
||||
# https://doc.rust-lang.org/1.0.0/rustc/metadata/loader/index.html#frobbing-symbols
|
||||
metadata =
|
||||
let
|
||||
depsMetadata = lib.foldl' (str: dep: str + dep.metadata) "" (dependencies ++ buildDependencies);
|
||||
hashedMetadata = builtins.hashString "sha256"
|
||||
(crateName + "-" + crateVersion + "___" + toString (mkRustcFeatureArgs crateFeatures) +
|
||||
"___" + depsMetadata + "___" + rustAttrs.toRustTarget stdenv.hostPlatform);
|
||||
in
|
||||
lib.substring 0 10 hashedMetadata;
|
||||
|
||||
build = crate.build or "";
|
||||
# Either set to a concrete sub path to the crate root
|
||||
# or use `null` for auto-detect.
|
||||
workspace_member = crate.workspace_member or ".";
|
||||
crateVersion = crate.version;
|
||||
crateDescription = crate.description or "";
|
||||
crateAuthors = if crate ? authors && lib.isList crate.authors then crate.authors else [ ];
|
||||
crateHomepage = crate.homepage or "";
|
||||
crateType =
|
||||
if lib.attrByPath [ "procMacro" ] false crate then [ "proc-macro" ] else
|
||||
if lib.attrByPath [ "plugin" ] false crate then [ "dylib" ] else
|
||||
(crate.type or [ "lib" ]);
|
||||
colors = lib.attrByPath [ "colors" ] "always" crate;
|
||||
extraLinkFlags = lib.concatStringsSep " " (crate.extraLinkFlags or [ ]);
|
||||
edition = crate.edition or null;
|
||||
codegenUnits = if crate ? codegenUnits then crate.codegenUnits else 1;
|
||||
extraRustcOpts =
|
||||
lib.optionals (crate ? extraRustcOpts) crate.extraRustcOpts
|
||||
++ extraRustcOpts_
|
||||
++ (lib.optional (edition != null) "--edition ${edition}");
|
||||
extraRustcOptsForBuildRs =
|
||||
lib.optionals (crate ? extraRustcOptsForBuildRs) crate.extraRustcOptsForBuildRs
|
||||
++ extraRustcOptsForBuildRs_
|
||||
++ (lib.optional (edition != null) "--edition ${edition}");
|
||||
|
||||
|
||||
configurePhase = configureCrate {
|
||||
inherit crateName buildDependencies completeDeps completeBuildDeps crateDescription
|
||||
crateFeatures crateRenames libName build workspace_member release libPath crateVersion
|
||||
extraLinkFlags extraRustcOptsForBuildRs
|
||||
crateAuthors crateHomepage verbose colors codegenUnits;
|
||||
};
|
||||
buildPhase = buildCrate {
|
||||
inherit crateName dependencies
|
||||
crateFeatures crateRenames libName release libPath crateType
|
||||
metadata hasCrateBin crateBin verbose colors
|
||||
extraRustcOpts buildTests codegenUnits;
|
||||
};
|
||||
installPhase = installCrate crateName metadata buildTests;
|
||||
|
||||
# depending on the test setting we are either producing something with bins
|
||||
# and libs or just test binaries
|
||||
outputs = if buildTests then [ "out" ] else [ "out" "lib" ];
|
||||
outputDev = if buildTests then [ "out" ] else [ "lib" ];
|
||||
|
||||
meta = {
|
||||
mainProgram = crateName;
|
||||
};
|
||||
} // extraDerivationAttrs
|
||||
)
|
||||
)
|
||||
{
|
||||
rust = rustc;
|
||||
release = crate_.release or true;
|
||||
verbose = crate_.verbose or true;
|
||||
extraRustcOpts = [ ];
|
||||
extraRustcOptsForBuildRs = [ ];
|
||||
features = [ ];
|
||||
nativeBuildInputs = [ ];
|
||||
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 [ ];
|
||||
crateRenames = crate_.crateRenames or { };
|
||||
buildTests = crate_.buildTests or false;
|
||||
}
|
||||
26
pkgs/build-support/rust/build-rust-crate/helpers.nix
Normal file
26
pkgs/build-support/rust/build-rust-crate/helpers.nix
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
{stdenv, lib}:
|
||||
{
|
||||
kernel = stdenv.hostPlatform.parsed.kernel.name;
|
||||
abi = stdenv.hostPlatform.parsed.abi.name;
|
||||
cpu = stdenv.hostPlatform.parsed.cpu.name;
|
||||
updateFeatures = f: up: functions: lib.deepSeq f (lib.foldl' (features: fun: fun features) (lib.attrsets.recursiveUpdate f up) functions);
|
||||
mapFeatures = features: map (fun: fun { features = features; });
|
||||
mkFeatures = feat: lib.foldl (features: featureName:
|
||||
if feat.${featureName} or false then
|
||||
[ featureName ] ++ features
|
||||
else
|
||||
features
|
||||
) [] (lib.attrNames feat);
|
||||
include = includedFiles: src: builtins.filterSource (path: type:
|
||||
lib.any (f:
|
||||
let p = toString (src + ("/" + f));
|
||||
in
|
||||
p == path || (lib.strings.hasPrefix (p + "/") path)
|
||||
) includedFiles
|
||||
) src;
|
||||
exclude = excludedFiles: src: builtins.filterSource (path: type:
|
||||
lib.all (f:
|
||||
!lib.strings.hasPrefix (toString (src + ("/" + f))) path
|
||||
) excludedFiles
|
||||
) src;
|
||||
}
|
||||
51
pkgs/build-support/rust/build-rust-crate/install-crate.nix
Normal file
51
pkgs/build-support/rust/build-rust-crate/install-crate.nix
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
{ stdenv }:
|
||||
crateName: metadata: buildTests:
|
||||
if !buildTests then ''
|
||||
runHook preInstall
|
||||
# always create $out even if we do not have binaries. We are detecting binary targets during compilation, if those are missing there is no way to only have $lib
|
||||
mkdir $out
|
||||
if [[ -s target/env ]]; then
|
||||
mkdir -p $lib
|
||||
cp target/env $lib/env
|
||||
fi
|
||||
if [[ -s target/link.final ]]; then
|
||||
mkdir -p $lib/lib
|
||||
cp target/link.final $lib/lib/link
|
||||
fi
|
||||
if [[ "$(ls -A target/lib)" ]]; then
|
||||
mkdir -p $lib/lib
|
||||
cp -r target/lib/* $lib/lib #*/
|
||||
for library in $lib/lib/*.so $lib/lib/*.dylib; do #*/
|
||||
ln -s $library $(echo $library | sed -e "s/-${metadata}//")
|
||||
done
|
||||
fi
|
||||
if [[ "$(ls -A target/build)" ]]; then # */
|
||||
mkdir -p $lib/lib
|
||||
cp -r target/build/* $lib/lib # */
|
||||
fi
|
||||
if [[ -d target/bin ]]; then
|
||||
if [[ "$(ls -A target/bin)" ]]; then
|
||||
mkdir -p $out/bin
|
||||
cp -rP target/bin/* $out/bin # */
|
||||
fi
|
||||
fi
|
||||
runHook postInstall
|
||||
'' else
|
||||
# for tests we just put them all in the output. No execution.
|
||||
''
|
||||
runHook preInstall
|
||||
|
||||
mkdir -p $out/tests
|
||||
if [ -e target/bin ]; then
|
||||
find target/bin/ -type f -executable -exec cp {} $out/tests \;
|
||||
fi
|
||||
if [ -e target/lib ]; then
|
||||
find target/lib/ -type f \! -name '*.rlib' \
|
||||
-a \! -name '*${stdenv.hostPlatform.extensions.sharedLibrary}' \
|
||||
-a \! -name '*.d' \
|
||||
-executable \
|
||||
-print0 | xargs --no-run-if-empty --null install --target $out/tests;
|
||||
fi
|
||||
|
||||
runHook postInstall
|
||||
''
|
||||
174
pkgs/build-support/rust/build-rust-crate/lib.sh
Normal file
174
pkgs/build-support/rust/build-rust-crate/lib.sh
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
echo_build_heading() {
|
||||
if (( $# == 1 )); then
|
||||
echo_colored "Building $1"
|
||||
else
|
||||
echo_colored "Building $1 ($2)"
|
||||
fi
|
||||
}
|
||||
|
||||
build_lib() {
|
||||
lib_src=$1
|
||||
echo_build_heading $lib_src ${libName}
|
||||
|
||||
noisily rustc \
|
||||
--crate-name $CRATE_NAME \
|
||||
$lib_src \
|
||||
--out-dir target/lib \
|
||||
-L dependency=target/deps \
|
||||
--cap-lints allow \
|
||||
$LIB_RUSTC_OPTS \
|
||||
$BUILD_OUT_DIR \
|
||||
$EXTRA_BUILD \
|
||||
$EXTRA_FEATURES \
|
||||
$EXTRA_RUSTC_FLAGS \
|
||||
--color $colors
|
||||
|
||||
EXTRA_LIB=" --extern $CRATE_NAME=target/lib/lib$CRATE_NAME-$metadata.rlib"
|
||||
if [ -e target/deps/lib$CRATE_NAME-$metadata$LIB_EXT ]; then
|
||||
EXTRA_LIB="$EXTRA_LIB --extern $CRATE_NAME=target/lib/lib$CRATE_NAME-$metadata$LIB_EXT"
|
||||
fi
|
||||
}
|
||||
|
||||
build_bin() {
|
||||
local crate_name=$1
|
||||
local crate_name_=$(echo $crate_name | tr '-' '_')
|
||||
local main_file=""
|
||||
|
||||
if [[ ! -z $2 ]]; then
|
||||
main_file=$2
|
||||
fi
|
||||
echo_build_heading $@
|
||||
noisily rustc \
|
||||
--crate-name $crate_name_ \
|
||||
$main_file \
|
||||
--crate-type bin \
|
||||
$BIN_RUSTC_OPTS \
|
||||
--out-dir target/bin \
|
||||
-L dependency=target/deps \
|
||||
$LINK \
|
||||
$EXTRA_LIB \
|
||||
--cap-lints allow \
|
||||
$BUILD_OUT_DIR \
|
||||
$EXTRA_BUILD \
|
||||
$EXTRA_FEATURES \
|
||||
$EXTRA_RUSTC_FLAGS \
|
||||
--color ${colors} \
|
||||
|
||||
if [ "$crate_name_" != "$crate_name" ]; then
|
||||
mv target/bin/$crate_name_ target/bin/$crate_name
|
||||
fi
|
||||
}
|
||||
|
||||
build_lib_test() {
|
||||
local file="$1"
|
||||
EXTRA_RUSTC_FLAGS="--test $EXTRA_RUSTC_FLAGS" build_lib "$1" "$2"
|
||||
}
|
||||
|
||||
build_bin_test() {
|
||||
local crate="$1"
|
||||
local file="$2"
|
||||
EXTRA_RUSTC_FLAGS="--test $EXTRA_RUSTC_FLAGS" build_bin "$1" "$2"
|
||||
}
|
||||
|
||||
build_bin_test_file() {
|
||||
local file="$1"
|
||||
local derived_crate_name="${file//\//_}"
|
||||
derived_crate_name="${derived_crate_name%.rs}"
|
||||
build_bin_test "$derived_crate_name" "$file"
|
||||
}
|
||||
|
||||
# Add additional link options that were provided by the build script.
|
||||
setup_link_paths() {
|
||||
EXTRA_LIB=""
|
||||
if [[ -e target/link_ ]]; then
|
||||
EXTRA_BUILD="$(cat target/link_) $EXTRA_BUILD"
|
||||
fi
|
||||
|
||||
echo "$EXTRA_LINK_SEARCH" | while read i; do
|
||||
if [[ ! -z "$i" ]]; then
|
||||
for library in $i; do
|
||||
echo "-L $library" >> target/link
|
||||
L=$(echo $library | sed -e "s#$(pwd)/target/build#$lib/lib#")
|
||||
echo "-L $L" >> target/link.final
|
||||
done
|
||||
fi
|
||||
done
|
||||
echo "$EXTRA_LINK" | while read i; do
|
||||
if [[ ! -z "$i" ]]; then
|
||||
for library in $i; do
|
||||
echo "-l $library" >> target/link
|
||||
echo "-l $library" >> target/link.final
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -e target/link ]]; then
|
||||
tr '\n' ' ' < target/link > target/link_
|
||||
LINK=$(cat target/link_)
|
||||
fi
|
||||
}
|
||||
|
||||
search_for_bin_path() {
|
||||
# heuristic to "guess" the correct source file as found in cargo:
|
||||
# https://github.com/rust-lang/cargo/blob/90fc9f620190d5fa3c80b0c8c65a1e1361e6b8ae/src/cargo/util/toml/targets.rs#L308-L325
|
||||
|
||||
BIN_NAME=$1
|
||||
BIN_NAME_=$(echo $BIN_NAME | tr '-' '_')
|
||||
|
||||
# the first two cases are the "new" default IIRC
|
||||
FILES=( "src/bin/$BIN_NAME.rs" "src/bin/$BIN_NAME/main.rs" "src/bin/$BIN_NAME_.rs" "src/bin/$BIN_NAME_/main.rs" "src/bin/main.rs" "src/main.rs" )
|
||||
|
||||
if ! [ -e "$LIB_PATH" -o -e src/lib.rs -o -e "src/$LIB_NAME.rs" ]; then
|
||||
# if this is not a library the following path is also valid
|
||||
FILES=( "src/$BIN_NAME.rs" "src/$BIN_NAME_.rs" "${FILES[@]}" )
|
||||
fi
|
||||
|
||||
for file in "${FILES[@]}";
|
||||
do
|
||||
echo "checking file $file"
|
||||
# first file that exists wins
|
||||
if [[ -e "$file" ]]; then
|
||||
BIN_PATH="$file"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -z "$BIN_PATH" ]]; then
|
||||
echo_error "ERROR: failed to find file for binary target: $BIN_NAME" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Extracts cargo_toml_path of the matching crate.
|
||||
matching_cargo_toml_path() {
|
||||
local manifest_path="$1"
|
||||
local expected_crate_name="$2"
|
||||
|
||||
# If the Cargo.toml is not a workspace root,
|
||||
# it will only contain one package in ".packages"
|
||||
# because "--no-deps" suppressed dependency resolution.
|
||||
#
|
||||
# But to make it more general, we search for a matching
|
||||
# crate in all packages and use the manifest path that
|
||||
# is referenced there.
|
||||
cargo metadata --no-deps --format-version 1 \
|
||||
--manifest-path "$manifest_path" \
|
||||
| jq -r '.packages[]
|
||||
| select( .name == "'$expected_crate_name'")
|
||||
| .manifest_path'
|
||||
}
|
||||
|
||||
# Find a Cargo.toml in the current or any sub directory
|
||||
# with a matching crate name.
|
||||
matching_cargo_toml_dir() {
|
||||
local expected_crate_name="$1"
|
||||
|
||||
find -L -name Cargo.toml | sort | while read manifest_path; do
|
||||
echo "...checking manifest_path $manifest_path" >&2
|
||||
local matching_path="$(matching_cargo_toml_path "$manifest_path" "$expected_crate_name")"
|
||||
if [ -n "${matching_path}" ]; then
|
||||
echo "$(dirname $matching_path)"
|
||||
break
|
||||
fi
|
||||
done
|
||||
}
|
||||
59
pkgs/build-support/rust/build-rust-crate/log.nix
Normal file
59
pkgs/build-support/rust/build-rust-crate/log.nix
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
{ lib }:
|
||||
|
||||
let echo_colored_body = start_escape:
|
||||
# Body of a function that behaves like "echo" but
|
||||
# has the output colored by the given start_escape
|
||||
# sequence. E.g.
|
||||
#
|
||||
# * echo_x "Building ..."
|
||||
# * echo_x -n "Running "
|
||||
#
|
||||
# This is more complicated than apparent at first sight
|
||||
# because:
|
||||
# * The color markers and the text must be print
|
||||
# in the same echo statement. Otherise, other
|
||||
# intermingled text from concurrent builds will
|
||||
# be colored as well.
|
||||
# * We need to preserve the trailing newline of the
|
||||
# echo if and only if it is present. Bash likes
|
||||
# to strip those if we capture the output of echo
|
||||
# in a variable.
|
||||
# * Leading "-" will be interpreted by test as an
|
||||
# option for itself. Therefore, we prefix it with
|
||||
# an x in `[[ "x$1" =~ ^x- ]]`.
|
||||
''
|
||||
local echo_args="";
|
||||
while [[ "x$1" =~ ^x- ]]; do
|
||||
echo_args+=" $1"
|
||||
shift
|
||||
done
|
||||
|
||||
local start_escape="$(printf '${start_escape}')"
|
||||
local reset="$(printf '\033[0m')"
|
||||
echo $echo_args $start_escape"$@"$reset
|
||||
'';
|
||||
echo_conditional_colored_body = colors: start_escape:
|
||||
if colors == "always"
|
||||
then (echo_colored_body start_escape)
|
||||
else ''echo "$@"'';
|
||||
in {
|
||||
echo_colored = colors: ''
|
||||
echo_colored() {
|
||||
${echo_conditional_colored_body colors ''\033[0;1;32m''}
|
||||
}
|
||||
|
||||
echo_error() {
|
||||
${echo_conditional_colored_body colors ''\033[0;1;31m''}
|
||||
}
|
||||
'';
|
||||
|
||||
noisily = colors: verbose: ''
|
||||
noisily() {
|
||||
${lib.optionalString verbose ''
|
||||
echo_colored -n "Running "
|
||||
echo $@
|
||||
''}
|
||||
$@
|
||||
}
|
||||
'';
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
{ lib, buildPlatform, buildRustCrate, fetchgit }:
|
||||
let kernel = buildPlatform.parsed.kernel.name;
|
||||
abi = buildPlatform.parsed.abi.name;
|
||||
include = includedFiles: src: builtins.filterSource (path: type:
|
||||
lib.lists.any (f:
|
||||
let p = toString (src + ("/" + f)); in
|
||||
(path == p) || (type == "directory" && lib.strings.hasPrefix path p)
|
||||
) includedFiles
|
||||
) src;
|
||||
updateFeatures = f: up: functions: builtins.deepSeq f (lib.lists.foldl' (features: fun: fun features) (lib.attrsets.recursiveUpdate f up) functions);
|
||||
mapFeatures = features: map (fun: fun { features = features; });
|
||||
mkFeatures = feat: lib.lists.foldl (features: featureName:
|
||||
if feat.${featureName} or false then
|
||||
[ featureName ] ++ features
|
||||
else
|
||||
features
|
||||
) [] (builtins.attrNames feat);
|
||||
in
|
||||
rec {
|
||||
alloc_no_stdlib_1_3_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
|
||||
crateName = "alloc-no-stdlib";
|
||||
version = "1.3.0";
|
||||
authors = [ "Daniel Reiter Horn <danielrh@dropbox.com>" ];
|
||||
sha256 = "1jcp27pzmqdszgp80y484g4kwbjbg7x8a589drcwbxg0i8xwkir9";
|
||||
crateBin = [ { name = "example"; } ];
|
||||
inherit dependencies buildDependencies features;
|
||||
};
|
||||
brotli_2_5_0_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
|
||||
crateName = "brotli";
|
||||
version = "2.5.0";
|
||||
authors = [ "Daniel Reiter Horn <danielrh@dropbox.com>" "The Brotli Authors" ];
|
||||
sha256 = "1ynw4hkdwnp0kj30p86ls44ahv4s99258s019bqrq4mya8hlsb5b";
|
||||
crateBin = [ { name = "brotli"; } ];
|
||||
inherit dependencies buildDependencies features;
|
||||
};
|
||||
brotli_decompressor_1_3_1_ = { dependencies?[], buildDependencies?[], features?[] }: buildRustCrate {
|
||||
crateName = "brotli-decompressor";
|
||||
version = "1.3.1";
|
||||
authors = [ "Daniel Reiter Horn <danielrh@dropbox.com>" "The Brotli Authors" ];
|
||||
sha256 = "022g69q1xzwdj0130qm3fa4qwpn4q1jx3lc8yz0v0v201p7bm8fb";
|
||||
crateBin = [ { name = "brotli-decompressor"; } ];
|
||||
inherit dependencies buildDependencies features;
|
||||
};
|
||||
alloc_no_stdlib_1_3_0 = { features?(alloc_no_stdlib_1_3_0_features {}) }: alloc_no_stdlib_1_3_0_ {
|
||||
features = mkFeatures (features.alloc_no_stdlib_1_3_0 or {});
|
||||
};
|
||||
alloc_no_stdlib_1_3_0_features = f: updateFeatures f ({
|
||||
alloc_no_stdlib_1_3_0.default = (f.alloc_no_stdlib_1_3_0.default or true);
|
||||
}) [];
|
||||
brotli_2_5_0 = { features?(brotli_2_5_0_features {}) }: brotli_2_5_0_ {
|
||||
dependencies = mapFeatures features ([ alloc_no_stdlib_1_3_0 brotli_decompressor_1_3_1 ]);
|
||||
features = mkFeatures (features.brotli_2_5_0 or {});
|
||||
};
|
||||
brotli_2_5_0_features = f: updateFeatures f (rec {
|
||||
alloc_no_stdlib_1_3_0.no-stdlib =
|
||||
(f.alloc_no_stdlib_1_3_0.no-stdlib or false) ||
|
||||
(brotli_2_5_0.no-stdlib or false) ||
|
||||
(f.brotli_2_5_0.no-stdlib or false);
|
||||
alloc_no_stdlib_1_3_0.default = true;
|
||||
brotli_2_5_0.default = (f.brotli_2_5_0.default or true);
|
||||
brotli_decompressor_1_3_1.disable-timer =
|
||||
(f.brotli_decompressor_1_3_1.disable-timer or false) ||
|
||||
(brotli_2_5_0.disable-timer or false) ||
|
||||
(f.brotli_2_5_0.disable-timer or false);
|
||||
brotli_decompressor_1_3_1.no-stdlib =
|
||||
(f.brotli_decompressor_1_3_1.no-stdlib or false) ||
|
||||
(brotli_2_5_0.no-stdlib or false) ||
|
||||
(f.brotli_2_5_0.no-stdlib or false);
|
||||
brotli_decompressor_1_3_1.benchmark =
|
||||
(f.brotli_decompressor_1_3_1.benchmark or false) ||
|
||||
(brotli_2_5_0.benchmark or false) ||
|
||||
(f.brotli_2_5_0.benchmark or false);
|
||||
brotli_decompressor_1_3_1.default = true;
|
||||
brotli_decompressor_1_3_1.seccomp =
|
||||
(f.brotli_decompressor_1_3_1.seccomp or false) ||
|
||||
(brotli_2_5_0.seccomp or false) ||
|
||||
(f.brotli_2_5_0.seccomp or false);
|
||||
}) [ alloc_no_stdlib_1_3_0_features brotli_decompressor_1_3_1_features ];
|
||||
brotli_decompressor_1_3_1 = { features?(brotli_decompressor_1_3_1_features {}) }: brotli_decompressor_1_3_1_ {
|
||||
dependencies = mapFeatures features ([ alloc_no_stdlib_1_3_0 ]);
|
||||
features = mkFeatures (features.brotli_decompressor_1_3_1 or {});
|
||||
};
|
||||
brotli_decompressor_1_3_1_features = f: updateFeatures f (rec {
|
||||
alloc_no_stdlib_1_3_0.no-stdlib =
|
||||
(f.alloc_no_stdlib_1_3_0.no-stdlib or false) ||
|
||||
(brotli_decompressor_1_3_1.no-stdlib or false) ||
|
||||
(f.brotli_decompressor_1_3_1.no-stdlib or false);
|
||||
alloc_no_stdlib_1_3_0.default = true;
|
||||
alloc_no_stdlib_1_3_0.unsafe =
|
||||
(f.alloc_no_stdlib_1_3_0.unsafe or false) ||
|
||||
(brotli_decompressor_1_3_1.unsafe or false) ||
|
||||
(f.brotli_decompressor_1_3_1.unsafe or false);
|
||||
brotli_decompressor_1_3_1.default = (f.brotli_decompressor_1_3_1.default or true);
|
||||
}) [ alloc_no_stdlib_1_3_0_features ];
|
||||
}
|
||||
657
pkgs/build-support/rust/build-rust-crate/test/default.nix
Normal file
657
pkgs/build-support/rust/build-rust-crate/test/default.nix
Normal file
|
|
@ -0,0 +1,657 @@
|
|||
{ lib
|
||||
, buildPackages
|
||||
, buildRustCrate
|
||||
, callPackage
|
||||
, releaseTools
|
||||
, runCommand
|
||||
, runCommandCC
|
||||
, stdenv
|
||||
, symlinkJoin
|
||||
, writeTextFile
|
||||
}:
|
||||
|
||||
let
|
||||
mkCrate = buildRustCrate: args: let
|
||||
p = {
|
||||
crateName = "nixtestcrate";
|
||||
version = "0.1.0";
|
||||
authors = [ "Test <test@example.com>" ];
|
||||
} // args;
|
||||
in buildRustCrate p;
|
||||
mkHostCrate = mkCrate buildRustCrate;
|
||||
|
||||
mkCargoToml =
|
||||
{ name, crateVersion ? "0.1.0", path ? "Cargo.toml" }:
|
||||
mkFile path ''
|
||||
[package]
|
||||
name = ${builtins.toJSON name}
|
||||
version = ${builtins.toJSON crateVersion}
|
||||
'';
|
||||
|
||||
mkFile = destination: text: writeTextFile {
|
||||
name = "src";
|
||||
destination = "/${destination}";
|
||||
inherit text;
|
||||
};
|
||||
|
||||
mkBin = name: mkFile name ''
|
||||
use std::env;
|
||||
fn main() {
|
||||
let name: String = env::args().nth(0).unwrap();
|
||||
println!("executed {}", name);
|
||||
}
|
||||
'';
|
||||
|
||||
mkBinExtern = name: extern: mkFile name ''
|
||||
extern crate ${extern};
|
||||
fn main() {
|
||||
assert_eq!(${extern}::test(), 23);
|
||||
}
|
||||
'';
|
||||
|
||||
mkTestFile = name: functionName: mkFile name ''
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn ${functionName}() {
|
||||
assert!(true);
|
||||
}
|
||||
'';
|
||||
mkTestFileWithMain = name: functionName: mkFile name ''
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn ${functionName}() {
|
||||
assert!(true);
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
'';
|
||||
|
||||
|
||||
mkLib = name: mkFile name "pub fn test() -> i32 { return 23; }";
|
||||
|
||||
mkTest = crateArgs: let
|
||||
crate = mkHostCrate (builtins.removeAttrs crateArgs ["expectedTestOutput"]);
|
||||
hasTests = crateArgs.buildTests or false;
|
||||
expectedTestOutputs = crateArgs.expectedTestOutputs or null;
|
||||
binaries = map (v: lib.escapeShellArg v.name) (crateArgs.crateBin or []);
|
||||
isLib = crateArgs ? libName || crateArgs ? libPath;
|
||||
crateName = crateArgs.crateName or "nixtestcrate";
|
||||
libName = crateArgs.libName or crateName;
|
||||
|
||||
libTestBinary = if !isLib then null else mkHostCrate {
|
||||
crateName = "run-test-${crateName}";
|
||||
dependencies = [ crate ];
|
||||
src = mkBinExtern "src/main.rs" libName;
|
||||
};
|
||||
|
||||
in
|
||||
assert expectedTestOutputs != null -> hasTests;
|
||||
assert hasTests -> expectedTestOutputs != null;
|
||||
|
||||
runCommand "run-buildRustCrate-${crateName}-test" {
|
||||
nativeBuildInputs = [ crate ];
|
||||
} (if !hasTests then ''
|
||||
${lib.concatMapStringsSep "\n" (binary:
|
||||
# Can't actually run the binary when cross-compiling
|
||||
(lib.optionalString (stdenv.hostPlatform != stdenv.buildPlatform) "type ") + binary
|
||||
) binaries}
|
||||
${lib.optionalString isLib ''
|
||||
test -e ${crate}/lib/*.rlib || exit 1
|
||||
${lib.optionalString (stdenv.hostPlatform != stdenv.buildPlatform) "test -x "} \
|
||||
${libTestBinary}/bin/run-test-${crateName}
|
||||
''}
|
||||
touch $out
|
||||
'' else if stdenv.hostPlatform == stdenv.buildPlatform then ''
|
||||
for file in ${crate}/tests/*; do
|
||||
$file 2>&1 >> $out
|
||||
done
|
||||
set -e
|
||||
${lib.concatMapStringsSep "\n" (o: "grep '${o}' $out || { echo 'output \"${o}\" not found in:'; cat $out; exit 23; }") expectedTestOutputs}
|
||||
'' else ''
|
||||
for file in ${crate}/tests/*; do
|
||||
test -x "$file"
|
||||
done
|
||||
touch "$out"
|
||||
''
|
||||
);
|
||||
|
||||
/* Returns a derivation that asserts that the crate specified by `crateArgs`
|
||||
has the specified files as output.
|
||||
|
||||
`name` is used as part of the derivation name that performs the checking.
|
||||
|
||||
`crateArgs` is passed to `mkHostCrate` to build the crate with `buildRustCrate`.
|
||||
|
||||
`expectedFiles` contains a list of expected file paths in the output. E.g.
|
||||
`[ "./bin/my_binary" ]`.
|
||||
|
||||
`output` specifies the name of the output to use. By default, the default
|
||||
output is used but e.g. `output = "lib";` will cause the lib output
|
||||
to be checked instead. You do not need to specify any directories.
|
||||
*/
|
||||
assertOutputs = { name, crateArgs, expectedFiles, output? null }:
|
||||
assert (builtins.isString name);
|
||||
assert (builtins.isAttrs crateArgs);
|
||||
assert (builtins.isList expectedFiles);
|
||||
|
||||
let
|
||||
crate = mkHostCrate (builtins.removeAttrs crateArgs ["expectedTestOutput"]);
|
||||
crateOutput = if output == null then crate else crate."${output}";
|
||||
expectedFilesFile = writeTextFile {
|
||||
name = "expected-files-${name}";
|
||||
text =
|
||||
let sorted = builtins.sort (a: b: a<b) expectedFiles;
|
||||
concatenated = builtins.concatStringsSep "\n" sorted;
|
||||
in "${concatenated}\n";
|
||||
};
|
||||
in
|
||||
runCommand "assert-outputs-${name}" {
|
||||
} (''
|
||||
local actualFiles=$(mktemp)
|
||||
|
||||
cd "${crateOutput}"
|
||||
find . -type f \
|
||||
| sort \
|
||||
''
|
||||
# sed out the hash because it differs per platform
|
||||
+ ''
|
||||
| sed -E -e 's/-[0-9a-fA-F]{10}\.rlib/-HASH.rlib/g' \
|
||||
> "$actualFiles"
|
||||
diff -q ${expectedFilesFile} "$actualFiles" > /dev/null || {
|
||||
echo -e "\033[0;1;31mERROR: Difference in expected output files in ${crateOutput} \033[0m" >&2
|
||||
echo === Got:
|
||||
sed -e 's/^/ /' $actualFiles
|
||||
echo === Expected:
|
||||
sed -e 's/^/ /' ${expectedFilesFile}
|
||||
echo === Diff:
|
||||
diff -u ${expectedFilesFile} $actualFiles |\
|
||||
tail -n +3 |\
|
||||
sed -e 's/^/ /'
|
||||
exit 1
|
||||
}
|
||||
touch $out
|
||||
'')
|
||||
;
|
||||
|
||||
in rec {
|
||||
|
||||
tests = let
|
||||
cases = rec {
|
||||
libPath = { libPath = "src/my_lib.rs"; src = mkLib "src/my_lib.rs"; };
|
||||
srcLib = { src = mkLib "src/lib.rs"; };
|
||||
|
||||
# This used to be supported by cargo but as of 1.40.0 I can't make it work like that with just cargo anymore.
|
||||
# This might be a regression or deprecated thing they finally removed…
|
||||
# customLibName = { libName = "test_lib"; src = mkLib "src/test_lib.rs"; };
|
||||
# rustLibTestsCustomLibName = {
|
||||
# libName = "test_lib";
|
||||
# src = mkTestFile "src/test_lib.rs" "foo";
|
||||
# buildTests = true;
|
||||
# expectedTestOutputs = [ "test foo ... ok" ];
|
||||
# };
|
||||
|
||||
customLibNameAndLibPath = { libName = "test_lib"; libPath = "src/best-lib.rs"; src = mkLib "src/best-lib.rs"; };
|
||||
crateBinWithPath = { crateBin = [{ name = "test_binary1"; path = "src/foobar.rs"; }]; src = mkBin "src/foobar.rs"; };
|
||||
crateBinNoPath1 = { crateBin = [{ name = "my-binary2"; }]; src = mkBin "src/my_binary2.rs"; };
|
||||
crateBinNoPath2 = {
|
||||
crateBin = [{ name = "my-binary3"; } { name = "my-binary4"; }];
|
||||
src = symlinkJoin {
|
||||
name = "buildRustCrateMultipleBinariesCase";
|
||||
paths = [ (mkBin "src/bin/my_binary3.rs") (mkBin "src/bin/my_binary4.rs") ];
|
||||
};
|
||||
};
|
||||
crateBinNoPath3 = { crateBin = [{ name = "my-binary5"; }]; src = mkBin "src/bin/main.rs"; };
|
||||
crateBinNoPath4 = { crateBin = [{ name = "my-binary6"; }]; src = mkBin "src/main.rs";};
|
||||
crateBinRename1 = {
|
||||
crateBin = [{ name = "my-binary-rename1"; }];
|
||||
src = mkBinExtern "src/main.rs" "foo_renamed";
|
||||
dependencies = [ (mkHostCrate { crateName = "foo"; src = mkLib "src/lib.rs"; }) ];
|
||||
crateRenames = { "foo" = "foo_renamed"; };
|
||||
};
|
||||
crateBinRename2 = {
|
||||
crateBin = [{ name = "my-binary-rename2"; }];
|
||||
src = mkBinExtern "src/main.rs" "foo_renamed";
|
||||
dependencies = [ (mkHostCrate { crateName = "foo"; libName = "foolib"; src = mkLib "src/lib.rs"; }) ];
|
||||
crateRenames = { "foo" = "foo_renamed"; };
|
||||
};
|
||||
crateBinRenameMultiVersion = let
|
||||
crateWithVersion = version: mkHostCrate {
|
||||
crateName = "my_lib";
|
||||
inherit version;
|
||||
src = mkFile "src/lib.rs" ''
|
||||
pub const version: &str = "${version}";
|
||||
'';
|
||||
};
|
||||
depCrate01 = crateWithVersion "0.1.2";
|
||||
depCrate02 = crateWithVersion "0.2.1";
|
||||
in {
|
||||
crateName = "my_bin";
|
||||
src = symlinkJoin {
|
||||
name = "my_bin_src";
|
||||
paths = [
|
||||
(mkFile "src/main.rs" ''
|
||||
#[test]
|
||||
fn my_lib_01() { assert_eq!(lib01::version, "0.1.2"); }
|
||||
|
||||
#[test]
|
||||
fn my_lib_02() { assert_eq!(lib02::version, "0.2.1"); }
|
||||
|
||||
fn main() { }
|
||||
'')
|
||||
];
|
||||
};
|
||||
dependencies = [ depCrate01 depCrate02 ];
|
||||
crateRenames = {
|
||||
"my_lib" = [
|
||||
{
|
||||
version = "0.1.2";
|
||||
rename = "lib01";
|
||||
}
|
||||
{
|
||||
version = "0.2.1";
|
||||
rename = "lib02";
|
||||
}
|
||||
];
|
||||
};
|
||||
buildTests = true;
|
||||
expectedTestOutputs = [
|
||||
"test my_lib_01 ... ok"
|
||||
"test my_lib_02 ... ok"
|
||||
];
|
||||
};
|
||||
rustLibTestsDefault = {
|
||||
src = mkTestFile "src/lib.rs" "baz";
|
||||
buildTests = true;
|
||||
expectedTestOutputs = [ "test baz ... ok" ];
|
||||
};
|
||||
rustLibTestsCustomLibPath = {
|
||||
libPath = "src/test_path.rs";
|
||||
src = mkTestFile "src/test_path.rs" "bar";
|
||||
buildTests = true;
|
||||
expectedTestOutputs = [ "test bar ... ok" ];
|
||||
};
|
||||
rustLibTestsCustomLibPathWithTests = {
|
||||
libPath = "src/test_path.rs";
|
||||
src = symlinkJoin {
|
||||
name = "rust-lib-tests-custom-lib-path-with-tests-dir";
|
||||
paths = [
|
||||
(mkTestFile "src/test_path.rs" "bar")
|
||||
(mkTestFile "tests/something.rs" "something")
|
||||
];
|
||||
};
|
||||
buildTests = true;
|
||||
expectedTestOutputs = [
|
||||
"test bar ... ok"
|
||||
"test something ... ok"
|
||||
];
|
||||
};
|
||||
rustBinTestsCombined = {
|
||||
src = symlinkJoin {
|
||||
name = "rust-bin-tests-combined";
|
||||
paths = [
|
||||
(mkTestFileWithMain "src/main.rs" "src_main")
|
||||
(mkTestFile "tests/foo.rs" "tests_foo")
|
||||
(mkTestFile "tests/bar.rs" "tests_bar")
|
||||
];
|
||||
};
|
||||
buildTests = true;
|
||||
expectedTestOutputs = [
|
||||
"test src_main ... ok"
|
||||
"test tests_foo ... ok"
|
||||
"test tests_bar ... ok"
|
||||
];
|
||||
};
|
||||
rustBinTestsSubdirCombined = {
|
||||
src = symlinkJoin {
|
||||
name = "rust-bin-tests-subdir-combined";
|
||||
paths = [
|
||||
(mkTestFileWithMain "src/main.rs" "src_main")
|
||||
(mkTestFile "tests/foo/main.rs" "tests_foo")
|
||||
(mkTestFile "tests/bar/main.rs" "tests_bar")
|
||||
];
|
||||
};
|
||||
buildTests = true;
|
||||
expectedTestOutputs = [
|
||||
"test src_main ... ok"
|
||||
"test tests_foo ... ok"
|
||||
"test tests_bar ... ok"
|
||||
];
|
||||
};
|
||||
linkAgainstRlibCrate = {
|
||||
crateName = "foo";
|
||||
src = mkFile "src/main.rs" ''
|
||||
extern crate somerlib;
|
||||
fn main() {}
|
||||
'';
|
||||
dependencies = [
|
||||
(mkHostCrate {
|
||||
crateName = "somerlib";
|
||||
type = [ "rlib" ];
|
||||
src = mkLib "src/lib.rs";
|
||||
})
|
||||
];
|
||||
};
|
||||
buildScriptDeps = let
|
||||
depCrate = buildRustCrate: boolVal: mkCrate buildRustCrate {
|
||||
crateName = "bar";
|
||||
src = mkFile "src/lib.rs" ''
|
||||
pub const baz: bool = ${boolVal};
|
||||
'';
|
||||
};
|
||||
in {
|
||||
crateName = "foo";
|
||||
src = symlinkJoin {
|
||||
name = "build-script-and-main";
|
||||
paths = [
|
||||
(mkFile "src/main.rs" ''
|
||||
extern crate bar;
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn baz_false() { assert!(!bar::baz); }
|
||||
fn main() { }
|
||||
'')
|
||||
(mkFile "build.rs" ''
|
||||
extern crate bar;
|
||||
fn main() { assert!(bar::baz); }
|
||||
'')
|
||||
];
|
||||
};
|
||||
buildDependencies = [ (depCrate buildPackages.buildRustCrate "true") ];
|
||||
dependencies = [ (depCrate buildRustCrate "false") ];
|
||||
buildTests = true;
|
||||
expectedTestOutputs = [ "test baz_false ... ok" ];
|
||||
};
|
||||
buildScriptFeatureEnv = {
|
||||
crateName = "build-script-feature-env";
|
||||
features = [ "some-feature" "crate/another_feature" ];
|
||||
src = symlinkJoin {
|
||||
name = "build-script-feature-env";
|
||||
paths = [
|
||||
(mkFile "src/main.rs" ''
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn feature_not_visible() {
|
||||
assert!(std::env::var("CARGO_FEATURE_SOME_FEATURE").is_err());
|
||||
assert!(option_env!("CARGO_FEATURE_SOME_FEATURE").is_none());
|
||||
}
|
||||
fn main() {}
|
||||
'')
|
||||
(mkFile "build.rs" ''
|
||||
fn main() {
|
||||
assert!(std::env::var("CARGO_FEATURE_SOME_FEATURE").is_ok());
|
||||
assert!(option_env!("CARGO_FEATURE_SOME_FEATURE").is_none());
|
||||
}
|
||||
'')
|
||||
];
|
||||
};
|
||||
buildTests = true;
|
||||
expectedTestOutputs = [ "test feature_not_visible ... ok" ];
|
||||
};
|
||||
# Regression test for https://github.com/NixOS/nixpkgs/pull/88054
|
||||
# Build script output should be rewritten as valid env vars.
|
||||
buildScriptIncludeDirDeps = let
|
||||
depCrate = mkHostCrate {
|
||||
crateName = "bar";
|
||||
src = symlinkJoin {
|
||||
name = "build-script-and-include-dir-bar";
|
||||
paths = [
|
||||
(mkFile "src/lib.rs" ''
|
||||
fn main() { }
|
||||
'')
|
||||
(mkFile "build.rs" ''
|
||||
use std::path::PathBuf;
|
||||
fn main() { println!("cargo:include-dir={}/src", std::env::current_dir().unwrap_or(PathBuf::from(".")).to_str().unwrap()); }
|
||||
'')
|
||||
];
|
||||
};
|
||||
};
|
||||
in {
|
||||
crateName = "foo";
|
||||
src = symlinkJoin {
|
||||
name = "build-script-and-include-dir-foo";
|
||||
paths = [
|
||||
(mkFile "src/main.rs" ''
|
||||
fn main() { }
|
||||
'')
|
||||
(mkFile "build.rs" ''
|
||||
fn main() { assert!(std::env::var_os("DEP_BAR_INCLUDE_DIR").is_some()); }
|
||||
'')
|
||||
];
|
||||
};
|
||||
buildDependencies = [ depCrate ];
|
||||
dependencies = [ depCrate ];
|
||||
};
|
||||
# Regression test for https://github.com/NixOS/nixpkgs/issues/74071
|
||||
# Whenevever a build.rs file is generating files those should not be overlayed onto the actual source dir
|
||||
buildRsOutDirOverlay = {
|
||||
src = symlinkJoin {
|
||||
name = "buildrs-out-dir-overlay";
|
||||
paths = [
|
||||
(mkLib "src/lib.rs")
|
||||
(mkFile "build.rs" ''
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
fn main() {
|
||||
let out_dir = env::var_os("OUT_DIR").expect("OUT_DIR not set");
|
||||
let out_file = Path::new(&out_dir).join("lib.rs");
|
||||
fs::write(out_file, "invalid rust code!").expect("failed to write lib.rs");
|
||||
}
|
||||
'')
|
||||
];
|
||||
};
|
||||
};
|
||||
# Regression test for https://github.com/NixOS/nixpkgs/pull/83379
|
||||
# link flag order should be preserved
|
||||
linkOrder = {
|
||||
src = symlinkJoin {
|
||||
name = "buildrs-out-dir-overlay";
|
||||
paths = [
|
||||
(mkFile "build.rs" ''
|
||||
fn main() {
|
||||
// in the other order, linkage will fail
|
||||
println!("cargo:rustc-link-lib=b");
|
||||
println!("cargo:rustc-link-lib=a");
|
||||
}
|
||||
'')
|
||||
(mkFile "src/main.rs" ''
|
||||
extern "C" {
|
||||
fn hello_world();
|
||||
}
|
||||
fn main() {
|
||||
unsafe {
|
||||
hello_world();
|
||||
}
|
||||
}
|
||||
'')
|
||||
];
|
||||
};
|
||||
buildInputs = let
|
||||
compile = name: text: let
|
||||
src = writeTextFile {
|
||||
name = "${name}-src.c";
|
||||
inherit text;
|
||||
};
|
||||
in runCommandCC name {} ''
|
||||
mkdir -p $out/lib
|
||||
# Note: On darwin (which defaults to clang) we have to add
|
||||
# `-undefined dynamic_lookup` as otherwise the compilation fails.
|
||||
$CC -shared \
|
||||
${lib.optionalString stdenv.isDarwin "-undefined dynamic_lookup"} \
|
||||
-o $out/lib/${name}${stdenv.hostPlatform.extensions.sharedLibrary} ${src}
|
||||
'';
|
||||
b = compile "libb" ''
|
||||
#include <stdio.h>
|
||||
|
||||
void hello();
|
||||
|
||||
void hello_world() {
|
||||
hello();
|
||||
printf(" world!\n");
|
||||
}
|
||||
'';
|
||||
a = compile "liba" ''
|
||||
#include <stdio.h>
|
||||
|
||||
void hello() {
|
||||
printf("hello");
|
||||
}
|
||||
'';
|
||||
in [ a b ];
|
||||
};
|
||||
rustCargoTomlInSubDir = {
|
||||
# The "workspace_member" can be set to the sub directory with the crate to build.
|
||||
# By default ".", meaning the top level directory is assumed.
|
||||
# Using null will trigger a search.
|
||||
workspace_member = null;
|
||||
src = symlinkJoin rec {
|
||||
name = "find-cargo-toml";
|
||||
paths = [
|
||||
(mkCargoToml { name = "ignoreMe"; })
|
||||
(mkTestFileWithMain "src/main.rs" "ignore_main")
|
||||
|
||||
(mkCargoToml { name = "rustCargoTomlInSubDir"; path = "subdir/Cargo.toml"; })
|
||||
(mkTestFileWithMain "subdir/src/main.rs" "src_main")
|
||||
(mkTestFile "subdir/tests/foo/main.rs" "tests_foo")
|
||||
(mkTestFile "subdir/tests/bar/main.rs" "tests_bar")
|
||||
];
|
||||
};
|
||||
buildTests = true;
|
||||
expectedTestOutputs = [
|
||||
"test src_main ... ok"
|
||||
"test tests_foo ... ok"
|
||||
"test tests_bar ... ok"
|
||||
];
|
||||
};
|
||||
|
||||
rustCargoTomlInTopDir =
|
||||
let
|
||||
withoutCargoTomlSearch = builtins.removeAttrs rustCargoTomlInSubDir [ "workspace_member" ];
|
||||
in
|
||||
withoutCargoTomlSearch // {
|
||||
expectedTestOutputs = [
|
||||
"test ignore_main ... ok"
|
||||
];
|
||||
};
|
||||
procMacroInPrelude = {
|
||||
procMacro = true;
|
||||
edition = "2018";
|
||||
src = symlinkJoin {
|
||||
name = "proc-macro-in-prelude";
|
||||
paths = [
|
||||
(mkFile "src/lib.rs" ''
|
||||
use proc_macro::TokenTree;
|
||||
'')
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
brotliCrates = (callPackage ./brotli-crates.nix {});
|
||||
tests = lib.mapAttrs (key: value: mkTest (value // lib.optionalAttrs (!value?crateName) { crateName = key; })) cases;
|
||||
in tests // rec {
|
||||
|
||||
crateBinWithPathOutputs = assertOutputs {
|
||||
name="crateBinWithPath";
|
||||
crateArgs = {
|
||||
crateBin = [{ name = "test_binary1"; path = "src/foobar.rs"; }];
|
||||
src = mkBin "src/foobar.rs";
|
||||
};
|
||||
expectedFiles = [
|
||||
"./bin/test_binary1"
|
||||
];
|
||||
};
|
||||
|
||||
crateBinWithPathOutputsDebug = assertOutputs {
|
||||
name="crateBinWithPath";
|
||||
crateArgs = {
|
||||
release = false;
|
||||
crateBin = [{ name = "test_binary1"; path = "src/foobar.rs"; }];
|
||||
src = mkBin "src/foobar.rs";
|
||||
};
|
||||
expectedFiles = [
|
||||
"./bin/test_binary1"
|
||||
] ++ lib.optionals stdenv.isDarwin [
|
||||
# On Darwin, the debug symbols are in a seperate directory.
|
||||
"./bin/test_binary1.dSYM/Contents/Info.plist"
|
||||
"./bin/test_binary1.dSYM/Contents/Resources/DWARF/test_binary1"
|
||||
];
|
||||
};
|
||||
|
||||
crateBinNoPath1Outputs = assertOutputs {
|
||||
name="crateBinNoPath1";
|
||||
crateArgs = {
|
||||
crateBin = [{ name = "my-binary2"; }];
|
||||
src = mkBin "src/my_binary2.rs";
|
||||
};
|
||||
expectedFiles = [
|
||||
"./bin/my-binary2"
|
||||
];
|
||||
};
|
||||
|
||||
crateLibOutputs = assertOutputs {
|
||||
name="crateLib";
|
||||
output="lib";
|
||||
crateArgs = {
|
||||
libName = "test_lib";
|
||||
type = [ "rlib" ];
|
||||
libPath = "src/lib.rs";
|
||||
src = mkLib "src/lib.rs";
|
||||
};
|
||||
expectedFiles = [
|
||||
"./nix-support/propagated-build-inputs"
|
||||
"./lib/libtest_lib-HASH.rlib"
|
||||
"./lib/link"
|
||||
];
|
||||
};
|
||||
|
||||
crateLibOutputsDebug = assertOutputs {
|
||||
name="crateLib";
|
||||
output="lib";
|
||||
crateArgs = {
|
||||
release = false;
|
||||
libName = "test_lib";
|
||||
type = [ "rlib" ];
|
||||
libPath = "src/lib.rs";
|
||||
src = mkLib "src/lib.rs";
|
||||
};
|
||||
expectedFiles = [
|
||||
"./nix-support/propagated-build-inputs"
|
||||
"./lib/libtest_lib-HASH.rlib"
|
||||
"./lib/link"
|
||||
];
|
||||
};
|
||||
|
||||
brotliTest = let
|
||||
pkg = brotliCrates.brotli_2_5_0 {};
|
||||
in runCommand "run-brotli-test-cmd" {
|
||||
nativeBuildInputs = [ pkg ];
|
||||
} (if stdenv.hostPlatform == stdenv.buildPlatform then ''
|
||||
${pkg}/bin/brotli -c ${pkg}/bin/brotli > /dev/null && touch $out
|
||||
'' else ''
|
||||
test -x '${pkg}/bin/brotli' && touch $out
|
||||
'');
|
||||
allocNoStdLibTest = let
|
||||
pkg = brotliCrates.alloc_no_stdlib_1_3_0 {};
|
||||
in runCommand "run-alloc-no-stdlib-test-cmd" {
|
||||
nativeBuildInputs = [ pkg ];
|
||||
} ''
|
||||
test -e ${pkg}/bin/example && touch $out
|
||||
'';
|
||||
brotliDecompressorTest = let
|
||||
pkg = brotliCrates.brotli_decompressor_1_3_1 {};
|
||||
in runCommand "run-brotli-decompressor-test-cmd" {
|
||||
nativeBuildInputs = [ pkg ];
|
||||
} ''
|
||||
test -e ${pkg}/bin/brotli-decompressor && touch $out
|
||||
'';
|
||||
};
|
||||
test = releaseTools.aggregate {
|
||||
name = "buildRustCrate-tests";
|
||||
meta = {
|
||||
description = "Test cases for buildRustCrate";
|
||||
maintainers = [ ];
|
||||
};
|
||||
constituents = builtins.attrValues tests;
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue