buildRustCrate: support cargo:: invocation syntax for build script outputs

In order to allow for the new `cargo::` prefix for build script outputs
we have to adjust the configure-crate bash scripts in buildRustCrate to
properly parse the new additional syntax.

These changes don't affect existing build scripts configured with the
old `cargo:` prefix.

For more information, see https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script
This commit is contained in:
Ahmad Sattar 2024-06-20 09:51:43 +02:00
parent 8c811054a5
commit 95bb410817
2 changed files with 61 additions and 10 deletions

View File

@ -198,13 +198,16 @@ in ''
)
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 support the new prefix invocation syntax which uses two colons
# See https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script
EXTRA_BUILD=$(sed -n "s/^cargo::\{0,1\}rustc-flags=\(.*\)/\1/p" target/build/${crateName}.opt | tr '\n' ' ' | sort -u)
EXTRA_FEATURES=$(sed -n "s/^cargo::\{0,1\}rustc-cfg=\(.*\)/--cfg \1/p" target/build/${crateName}.opt | tr '\n' ' ')
EXTRA_LINK_ARGS=$(sed -n "s/^cargo::\{0,1\}rustc-link-arg=\(.*\)/-C link-arg=\1/p" target/build/${crateName}.opt | tr '\n' ' ')
EXTRA_LINK_ARGS_BINS=$(sed -n "s/^cargo::\{0,1\}rustc-link-arg-bins=\(.*\)/-C link-arg=\1/p" target/build/${crateName}.opt | tr '\n' ' ')
EXTRA_LINK_ARGS_LIB=$(sed -n "s/^cargo::\{0,1\}rustc-link-arg-lib=\(.*\)/-C link-arg=\1/p" target/build/${crateName}.opt | tr '\n' ' ')
EXTRA_LINK_LIBS=$(sed -n "s/^cargo::\{0,1\}rustc-link-lib=\(.*\)/\1/p" target/build/${crateName}.opt | tr '\n' ' ')
EXTRA_LINK_SEARCH=$(sed -n "s/^cargo::\{0,1\}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
@ -217,14 +220,15 @@ in ''
#
_OLDIFS="$IFS"
IFS=$'\n'
for env in $(sed -n "s/^cargo:rustc-env=\(.*\)/\1/p" target/build/${crateName}.opt); do
for env in $(sed -n "s/^cargo::\{0,1\}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
grep -P "^cargo:(?!:?(rustc-|warning=|rerun-if-changed=|rerun-if-env-changed))" target/build/${crateName}.opt \
| awk -F= "/^cargo::metadata=/ { gsub(/-/, \"_\", \$2); print \"export \" toupper(\"DEP_$(echo $CRATENAME)_\" \$2) \"=\" \"\\\"\"\$3\"\\\"\"; next }
/^cargo:/ { sub(/^cargo::?/, \"\", \$1); gsub(/-/, \"_\", \$1); print \"export \" toupper(\"DEP_$(echo $CRATENAME)_\" \$1) \"=\" \"\\\"\"\$2\"\\\"\"; next }" > target/env
set -e
fi
runHook postConfigure

View File

@ -421,6 +421,53 @@ let
buildDependencies = [ depCrate ];
dependencies = [ depCrate ];
};
# Support new invocation prefix for build scripts `cargo::`
# https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script
buildScriptInvocationPrefix = let
depCrate = buildRustCrate: mkCrate buildRustCrate {
crateName = "bar";
src = mkFile "build.rs" ''
fn main() {
// Old invocation prefix
// We likely won't see be mixing these syntaxes in the same build script in the wild.
println!("cargo:key_old=value_old");
// New invocation prefix
println!("cargo::metadata=key=value");
println!("cargo::metadata=key_complex=complex(value)");
}
'';
};
in {
crateName = "foo";
src = symlinkJoin {
name = "build-script-and-main-invocation-prefix";
paths = [
(mkFile "src/main.rs" ''
const BUILDFOO: &'static str = env!("BUILDFOO");
#[test]
fn build_foo_check() { assert!(BUILDFOO == "yes(check)"); }
fn main() { }
'')
(mkFile "build.rs" ''
use std::env;
fn main() {
assert!(env::var_os("DEP_BAR_KEY_OLD").expect("metadata key 'key_old' not set in dependency") == "value_old");
assert!(env::var_os("DEP_BAR_KEY").expect("metadata key 'key' not set in dependency") == "value");
assert!(env::var_os("DEP_BAR_KEY_COMPLEX").expect("metadata key 'key_complex' not set in dependency") == "complex(value)");
println!("cargo::rustc-env=BUILDFOO=yes(check)");
}
'')
];
};
buildDependencies = [ (depCrate buildPackages.buildRustCrate) ];
dependencies = [ (depCrate buildRustCrate) ];
buildTests = true;
expectedTestOutputs = [ "test build_foo_check ... ok" ];
};
# 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 = {