mesonEmulatorHook: fix canExecute safety assertion

Currently the throw codepath will never be hit. Specifically it doesn't
guard against a misuse of the hook:

pkgsCross.aarch64-multiplatform.mesonEmulatorHook # this should fail
pkgsCross.aarch64-multiplatform.buildPackages.mesonEmulatorHook # this should (and does) succeed

The check sort of worked to guard against use in situations where the
hook wasn't misplaced between nativeBuildInputs and buildInputs, but
the build platform was actually able to execute binaries built for the
host platform.

This worked because nativeBuildInputs would first of all need to
evaluate pkgsHostTarget.mesonEmulatorHook in order to access the spliced
derivation it wants, pkgsBuildHost.mesonEmulatorHook. For this, you'd
need to pass the if expression, at which point buildPlatform and
targetPlatform would match the build and target platform of the
derivation that uses the hook. Consequently the check is “correct”,
since it is its build platform that needs not to be able execute stuff
built for its host platform.

The target platform is technically wrong here, but it works out
since (at least currently) in nixpkgs either build and host or host and
target platform are equal. When doing the check in pkgsHostTarget,
target and host platform are equal.

However, this is a kind of incomprehensible rube goldberg machine, let's
some mistakes slip through the cracks and relies on implementation
details of splicing.

To alleviate this, we do the following:

- We move the check _into_ the derivation. By doing the check when
obtaining the file for the setup hook and not before calling
`makeSetupHook`. This means that we can force `mesonEmulatorHook`
even if forcing `mesonEmulatorHook.outPath` would throw. This ensures
that splicing can work even if the some of the derivation variants
would fail to evaluate.

- Since splicing works now, we can no longer have to do the check
“globally” before splicing happens. This means we can use the setup
hook derivation's own platforms. buildPlatform is irrelevant here,
since this is only the platform on which the shell script is put
together. hostPlatform matters, since it is were the setup hook is
executed later (i.e. the using derivation's build platform). target
platform is the platform the adjacent meson builds executables for,
i.e. the platform we may need to emulate for.

To verify this change, I have evaluated all derivations using
mesonEmulatorHook in `pkgsCross.aarch64-multiplatform` before and after
this change. The hashes don't change.

+15 -10
+15 -10
pkgs/top-level/all-packages.nix
··· 5821 5821 # example of an error which this fixes 5822 5822 # [Errno 8] Exec format error: './gdk3-scan' 5823 5823 mesonEmulatorHook = 5824 - if (!stdenv.buildPlatform.canExecute stdenv.targetPlatform) then 5825 - makeSetupHook 5826 - { 5827 - name = "mesonEmulatorHook"; 5828 - substitutions = { 5829 - crossFile = writeText "cross-file.conf" '' 5824 + makeSetupHook 5825 + { 5826 + name = "mesonEmulatorHook"; 5827 + substitutions = { 5828 + crossFile = writeText "cross-file.conf" '' 5830 5829 [binaries] 5831 - exe_wrapper = ${lib.escapeShellArg (stdenv.targetPlatform.emulator buildPackages)} 5830 + exe_wrapper = ${lib.escapeShellArg (stdenv.targetPlatform.emulator pkgs)} 5832 5831 ''; 5833 - }; 5834 - } ../development/tools/build-managers/meson/emulator-hook.sh 5835 - else throw "mesonEmulatorHook has to be in a conditional to check if the target binaries can be executed i.e. (!stdenv.buildPlatform.canExecute stdenv.hostPlatform)"; 5832 + }; 5833 + } 5834 + # The throw is moved into the `makeSetupHook` derivation, so that its 5835 + # outer level, but not its outPath can still be evaluated if the condition 5836 + # doesn't hold. This ensures that splicing still can work correctly. 5837 + (if (!stdenv.hostPlatform.canExecute stdenv.targetPlatform) then 5838 + ../development/tools/build-managers/meson/emulator-hook.sh 5839 + else 5840 + throw "mesonEmulatorHook may only be added to nativeBuildInputs when the target binaries can't be executed; however you are attempting to use it in a situation where ${stdenv.hostPlatform.config} can execute ${stdenv.targetPlatform.config}. Consider only adding mesonEmulatorHook according to a conditional based canExecute in your package expression."); 5836 5841 5837 5842 meson-tools = callPackage ../misc/meson-tools { }; 5838 5843