multi-outputs.sh: Improve _assignFirst error message

Closes #16182

This improves the error message

    Error: _assignFirst found no valid variant!

which occurred when the set of outputs was not sufficient to set
the various outputDev, outputBin, etc variables. Specifically, this
would mean that "out" is not among the outputs, which is valid for
a derivation.

This changes the message to something like

    error: _assignFirst: could not find a non-empty variable to assign to outputDev. The following variables were all unset or empty: dev out.
          If you did not define an "out" output, make sure to define all the specific required outputs: define an output for one of the unset variables.

While this isn't a full explanation of what stdenv can and can not do,
I think it's vast improvement over the 0 bits of information that it
used to provide. This at least gives a clue as to what's going on, and
even suggests a fix, although probably multiple such fixes are required
in an instance where someone starts with a no-out derivation from scratch
(and decide to persist).
This commit is contained in:
Robert Hensing 2023-01-15 20:54:48 +01:00
parent 5fb9ccbd5b
commit 01d7f19346
3 changed files with 41 additions and 7 deletions

View file

@ -253,7 +253,7 @@ The propagated equivalent of `depsTargetTarget`. This is prefixed for the same r
#### `NIX_DEBUG` {#var-stdenv-NIX_DEBUG} #### `NIX_DEBUG` {#var-stdenv-NIX_DEBUG}
A natural number indicating how much information to log. If set to 1 or higher, `stdenv` will print moderate debugging information during the build. In particular, the `gcc` and `ld` wrapper scripts will print out the complete command line passed to the wrapped tools. If set to 6 or higher, the `stdenv` setup script will be run with `set -x` tracing. If set to 7 or higher, the `gcc` and `ld` wrapper scripts will also be run with `set -x` tracing. A number between 0 and 7 indicating how much information to log. If set to 1 or higher, `stdenv` will print moderate debugging information during the build. In particular, the `gcc` and `ld` wrapper scripts will print out the complete command line passed to the wrapped tools. If set to 6 or higher, the `stdenv` setup script will be run with `set -x` tracing. If set to 7 or higher, the `gcc` and `ld` wrapper scripts will also be run with `set -x` tracing.
### Attributes affecting build properties {#attributes-affecting-build-properties} ### Attributes affecting build properties {#attributes-affecting-build-properties}

View file

@ -4,16 +4,30 @@ preFixupHooks+=(_multioutDocs)
preFixupHooks+=(_multioutDevs) preFixupHooks+=(_multioutDevs)
postFixupHooks+=(_multioutPropagateDev) postFixupHooks+=(_multioutPropagateDev)
# Assign the first string containing nonempty variable to the variable named $1 # _assignFirst varName otherVarNames*
#
# Set the value of the variable named $varName to the first of otherVarNames
# that refers to a non-empty variable name.
#
# If none of otherVarNames refers to a non-empty variable, the error message is
# specific to this function's use case, which is setting up the output variables.
_assignFirst() { _assignFirst() {
local varName="$1" local varName="$1"
local REMOVE=REMOVE # slightly hacky - we allow REMOVE (i.e. not a variable name) local REMOVE=REMOVE # slightly hacky - we allow REMOVE (i.e. not a variable name)
shift shift
while (( $# )); do for var in "$@"; do
if [ -n "${!1-}" ]; then eval "${varName}"="$1"; return; fi if [ -n "${!var-}" ]; then eval "${varName}"="${var}"; return; fi
shift
done done
echo "Error: _assignFirst found no valid variant!" echo
echo "error: _assignFirst: could not find a non-empty variable to assign to ${varName}. The following variables were all unset or empty: $*."
if [ -z "${out:-}" ]; then
echo ' If you do not want an "out" output in your derivation, make sure to define'
echo ' the other specific required outputs. This can be achieved by picking one'
echo " of $* to add as an output."
echo ' You do not have to remove "out" if you want to have a different default'
echo ' output, as it is the first output in `outputs` that is the default output.'
echo
fi
return 1 # none found return 1 # none found
} }

View file

@ -4,7 +4,8 @@
{ stdenv { stdenv
, pkgs , pkgs
, lib , lib
, , runCommand
, testers
}: }:
let let
@ -99,6 +100,25 @@ in
# tests for hooks in `stdenv.defaultNativeBuildInputs` # tests for hooks in `stdenv.defaultNativeBuildInputs`
hooks = lib.recurseIntoAttrs (import ./hooks.nix { stdenv = bootStdenv; pkgs = earlyPkgs; }); hooks = lib.recurseIntoAttrs (import ./hooks.nix { stdenv = bootStdenv; pkgs = earlyPkgs; });
outputs-no-out = runCommand "outputs-no-out-assert" {
result = testers.testBuildFailure (stdenv.mkDerivation {
NIX_DEBUG = 1;
name = "outputs-no-out";
outputs = ["foo"];
buildPhase = ":";
installPhase = ''
touch $foo
'';
});
# Assumption: the first output* variable to be configured is
# _overrideFirst outputDev "dev" "out"
expectedMsg = "_assignFirst: could not find a non-empty variable to assign to outputDev. The following variables were all unset or empty: dev out.";
} ''
grep -F "$expectedMsg" $result/testBuildFailure.log >/dev/null
touch $out
'';
test-env-attrset = testEnvAttrset { name = "test-env-attrset"; stdenv' = bootStdenv; }; test-env-attrset = testEnvAttrset { name = "test-env-attrset"; stdenv' = bootStdenv; };
# Test compatibility with derivations using `env` as a regular variable. # Test compatibility with derivations using `env` as a regular variable.