diff --git a/nixos/doc/manual/release-notes/rl-2411.section.md b/nixos/doc/manual/release-notes/rl-2411.section.md index 000df6e978b4..24481af73c87 100644 --- a/nixos/doc/manual/release-notes/rl-2411.section.md +++ b/nixos/doc/manual/release-notes/rl-2411.section.md @@ -719,6 +719,11 @@ - `python3Packages.nose` has been removed, as it has been deprecated and unmaintained for almost a decade and does not work on Python 3.12. Please switch to `pytest` or another test runner/framework. +- `dotnet-sdk`, `dotnet-runtime`, and all other dotnet packages now use a + wrapper package containing `bin/dotnet`, build hooks, etc. If you need to + reference the underlying dotnet distribution (DOTNET_ROOT) you should use e.g. + `dotnet-runtime.unwrapped`. + ## Other Notable Changes {#sec-release-24.11-notable-changes} diff --git a/pkgs/build-support/dotnet/build-dotnet-module/hooks/default.nix b/pkgs/build-support/dotnet/build-dotnet-module/hooks/default.nix index 98a52aee2fe6..8550ad8c9346 100644 --- a/pkgs/build-support/dotnet/build-dotnet-module/hooks/default.nix +++ b/pkgs/build-support/dotnet/build-dotnet-module/hooks/default.nix @@ -52,7 +52,8 @@ { name = "dotnet-fixup-hook"; substitutions = { - dotnetRuntime = dotnet-runtime; + # this is used for DOTNET_ROOT, so we need unwrapped + dotnetRuntime = dotnet-runtime.unwrapped; wrapperPath = lib.makeBinPath [ which coreutils ]; }; } diff --git a/pkgs/by-name/dy/dyalog/package.nix b/pkgs/by-name/dy/dyalog/package.nix index b983a88b5656..df0465079b12 100644 --- a/pkgs/by-name/dy/dyalog/package.nix +++ b/pkgs/by-name/dy/dyalog/package.nix @@ -32,7 +32,7 @@ let dyalogHome = "$out/lib/dyalog"; - makeWrapperArgs = lib.optional dotnetSupport "--set DOTNET_ROOT ${dotnet-sdk_8}"; + makeWrapperArgs = lib.optional dotnetSupport "--set DOTNET_ROOT ${dotnet-sdk_8.unwrapped}"; licenseUrl = "https://www.dyalog.com/uploads/documents/Developer_Software_Licence.pdf"; diff --git a/pkgs/by-name/ms/msbuild/package.nix b/pkgs/by-name/ms/msbuild/package.nix index 8710ea93c0a9..e60b71bb6582 100644 --- a/pkgs/by-name/ms/msbuild/package.nix +++ b/pkgs/by-name/ms/msbuild/package.nix @@ -72,7 +72,7 @@ mkPackage rec { # The provided libhostfxr.dylib is for x86_64-darwin, so we remove it rm artifacts/mono-msbuild/SdkResolvers/Microsoft.DotNet.MSBuildSdkResolver/libhostfxr.dylib - ln -s $(find ${dotnet-sdk} -name libhostfxr${sharedLibrary}) artifacts/mono-msbuild/SdkResolvers/Microsoft.DotNet.MSBuildSdkResolver/ + ln -s $(find ${dotnet-sdk.unwrapped} -name libhostfxr${sharedLibrary}) artifacts/mono-msbuild/SdkResolvers/Microsoft.DotNet.MSBuildSdkResolver/ # overwrite the file echo "#!${stdenv.shell}" > eng/common/dotnet-install.sh @@ -82,7 +82,7 @@ mkPackage rec { echo "#!${stdenv.shell}" > mono/build/extract_and_copy_hostfxr.sh mkdir -p mono/dotnet-overlay/msbuild-bin - cp ${dotnet-sdk}/sdk/*/{Microsoft.NETCoreSdk.BundledVersions.props,RuntimeIdentifierGraph.json} mono/dotnet-overlay/msbuild-bin + cp ${dotnet-sdk.unwrapped}/sdk/*/{Microsoft.NETCoreSdk.BundledVersions.props,RuntimeIdentifierGraph.json} mono/dotnet-overlay/msbuild-bin # DisableNerdbankVersioning https://gitter.im/Microsoft/msbuild/archives/2018/06/27?at=5b33dbc4ce3b0f268d489bfa # TODO there are some (many?) failing tests @@ -99,7 +99,7 @@ mkPackage rec { --set-default MONO_GC_PARAMS "nursery-size=64m" \ --add-flags "$out/lib/mono/msbuild/15.0/bin/MSBuild.dll" - ln -s $(find ${dotnet-sdk} -name libhostfxr${sharedLibrary}) $out/lib/mono/msbuild/Current/bin/SdkResolvers/Microsoft.DotNet.MSBuildSdkResolver/ + ln -s $(find ${dotnet-sdk.unwrapped} -name libhostfxr${sharedLibrary}) $out/lib/mono/msbuild/Current/bin/SdkResolvers/Microsoft.DotNet.MSBuildSdkResolver/ ''; doInstallCheck = true; diff --git a/pkgs/by-name/ne/netcoredbg/package.nix b/pkgs/by-name/ne/netcoredbg/package.nix index a225d814aae2..2695f9c2832e 100644 --- a/pkgs/by-name/ne/netcoredbg/package.nix +++ b/pkgs/by-name/ne/netcoredbg/package.nix @@ -36,7 +36,7 @@ let cmakeFlags = [ "-DCORECLR_DIR=${coreclr-src}/src/coreclr" - "-DDOTNET_DIR=${dotnet-sdk}" + "-DDOTNET_DIR=${dotnet-sdk.unwrapped}" "-DBUILD_MANAGED=0" ]; }; diff --git a/pkgs/by-name/pr/pre-commit/package.nix b/pkgs/by-name/pr/pre-commit/package.nix index 0b645519a0f5..b80d85b93330 100644 --- a/pkgs/by-name/pr/pre-commit/package.nix +++ b/pkgs/by-name/pr/pre-commit/package.nix @@ -90,7 +90,7 @@ buildPythonApplication rec { VIRTUALENV_NO_DOWNLOAD=1 PRE_COMMIT_NO_CONCURRENCY=1 LANG=en_US.UTF-8 # Resolve `.NET location: Not found` errors for dotnet tests - export DOTNET_ROOT="${dotnet-sdk}" + export DOTNET_ROOT="${dotnet-sdk.unwrapped}" export HOME=$(mktemp -d) diff --git a/pkgs/development/compilers/dotnet/build-dotnet.nix b/pkgs/development/compilers/dotnet/build-dotnet.nix index 3d48e1d98178..82710223628c 100644 --- a/pkgs/development/compilers/dotnet/build-dotnet.nix +++ b/pkgs/development/compilers/dotnet/build-dotnet.nix @@ -57,7 +57,7 @@ let sdk = ".NET SDK ${version}"; }; - mkCommon = callPackage ./common.nix { }; + mkWrapper = callPackage ./wrapper.nix { }; hostRid = systemToDotnetRid stdenv.hostPlatform.system; targetRid = systemToDotnetRid stdenv.targetPlatform.system; @@ -91,7 +91,7 @@ let ); in -mkCommon type rec { +mkWrapper type (stdenv.mkDerivation rec { inherit pname version; # Some of these dependencies are `dlopen()`ed. @@ -222,4 +222,4 @@ mkCommon type rec { binaryNativeCode ]; }; -} +}) diff --git a/pkgs/development/compilers/dotnet/combine-packages.nix b/pkgs/development/compilers/dotnet/combine-packages.nix index 661f9c482a12..d0f25c3ed3b1 100644 --- a/pkgs/development/compilers/dotnet/combine-packages.nix +++ b/pkgs/development/compilers/dotnet/combine-packages.nix @@ -20,7 +20,7 @@ assert lib.assertMsg ((builtins.length dotnetPackages) > 0) '' ];`''; buildEnv { name = "dotnet-core-combined"; - paths = dotnetPackages; + paths = map (x: x.unwrapped) dotnetPackages; pathsToLink = [ "/host" "/packs" @@ -31,10 +31,10 @@ buildEnv { ]; ignoreCollisions = true; postBuild = '' - cp -R ${cli}/{dotnet,share,nix-support} $out/ - - mkdir $out/bin - ln -s $out/dotnet $out/bin/dotnet + cp -R "${cli.unwrapped}"/dotnet $out/ + cp -R "${cli}"/nix-support "$out"/ + mkdir "$out"/bin + ln -s "$out"/dotnet "$out"/bin/dotnet ''; passthru = { inherit (cli) icu; diff --git a/pkgs/development/compilers/dotnet/common.nix b/pkgs/development/compilers/dotnet/common.nix deleted file mode 100644 index afe12279fd72..000000000000 --- a/pkgs/development/compilers/dotnet/common.nix +++ /dev/null @@ -1,240 +0,0 @@ -{ - stdenv, - stdenvNoCC, - lib, - writeText, - testers, - runCommand, - runCommandWith, - expect, - curl, - installShellFiles, - callPackage, - zlib, - swiftPackages, - darwin, - icu, - lndir, - substituteAll, - nugetPackageHook, - xmlstarlet, -}: -type: args: -stdenvNoCC.mkDerivation ( - finalAttrs: - args - // { - doInstallCheck = true; - - # TODO: this should probably be postInstallCheck - # TODO: send output to /dev/null - installCheckPhase = - args.installCheckPhase or "" - + '' - $out/bin/dotnet --info - ''; - - setupHooks = - args.setupHooks or [ ] - ++ [ - ./dotnet-setup-hook.sh - ] - ++ lib.optional (type == "sdk") (substituteAll { - src = ./dotnet-sdk-setup-hook.sh; - inherit lndir xmlstarlet; - }); - - propagatedBuildInputs = - (args.propagatedBuildInputs or [ ]) - ++ lib.optional (type == "sdk") nugetPackageHook; - - nativeBuildInputs = (args.nativeBuildInputs or [ ]) ++ [ installShellFiles ]; - - postInstall = '' - # completions snippets taken from https://learn.microsoft.com/en-us/dotnet/core/tools/enable-tab-autocomplete - installShellCompletion --cmd dotnet \ - --bash ${./completions/dotnet.bash} \ - --zsh ${./completions/dotnet.zsh} \ - --fish ${./completions/dotnet.fish} - ''; - - passthru = { - tests = - let - mkDotnetTest = - { - name, - stdenv ? stdenvNoCC, - template, - usePackageSource ? false, - build, - buildInputs ? [ ], - # TODO: use correct runtimes instead of sdk - runtime ? finalAttrs.finalPackage, - runInputs ? [ ], - run ? null, - runAllowNetworking ? false, - }: - let - sdk = finalAttrs.finalPackage; - built = stdenv.mkDerivation { - name = "dotnet-test-${name}"; - buildInputs = [ sdk ] ++ buildInputs ++ lib.optional (usePackageSource) sdk.packages; - # make sure ICU works in a sandbox - propagatedSandboxProfile = toString sdk.__propagatedSandboxProfile; - unpackPhase = '' - mkdir test - cd test - dotnet new ${template} -o . --no-restore - ''; - buildPhase = build; - dontPatchELF = true; - }; - in - if run == null then - built - else - runCommand "${built.name}-run" - ( - { - src = built; - nativeBuildInputs = [ built ] ++ runInputs; - passthru = { - inherit built; - }; - } - // lib.optionalAttrs (stdenv.hostPlatform.isDarwin && runAllowNetworking) { - sandboxProfile = '' - (allow network-inbound (local ip)) - (allow mach-lookup (global-name "com.apple.FSEvents")) - ''; - __darwinAllowLocalNetworking = true; - } - ) - ( - lib.optionalString (runtime != null) '' - # TODO: use runtime here - export DOTNET_ROOT=${runtime} - '' - + run - ); - - # Setting LANG to something other than 'C' forces the runtime to search - # for ICU, which will be required in most user environments. - checkConsoleOutput = command: '' - output="$(LANG=C.UTF-8 ${command})" - # yes, older SDKs omit the comma - [[ "$output" =~ Hello,?\ World! ]] && touch "$out" - ''; - in - { - version = testers.testVersion ( - { - package = finalAttrs.finalPackage; - } - // lib.optionalAttrs (type != "sdk") { - command = "dotnet --info"; - } - ); - } - // lib.optionalAttrs (type == "sdk") ( - { - console = mkDotnetTest { - name = "console"; - template = "console"; - build = checkConsoleOutput "dotnet run"; - }; - - publish = mkDotnetTest { - name = "publish"; - template = "console"; - build = "dotnet publish -o $out/bin"; - run = checkConsoleOutput "$src/bin/test"; - }; - - self-contained = mkDotnetTest { - name = "self-contained"; - template = "console"; - usePackageSource = true; - build = "dotnet publish --use-current-runtime --sc -o $out"; - runtime = null; - run = checkConsoleOutput "$src/test"; - }; - - single-file = mkDotnetTest { - name = "single-file"; - template = "console"; - usePackageSource = true; - build = "dotnet publish --use-current-runtime -p:PublishSingleFile=true -o $out/bin"; - runtime = null; - run = checkConsoleOutput "$src/bin/test"; - }; - - web = mkDotnetTest { - name = "web"; - template = "web"; - build = "dotnet publish -o $out/bin"; - runInputs = [ - expect - curl - ]; - run = '' - expect <<"EOF" - set status 1 - spawn $env(src)/bin/test - proc abort { } { exit 2 } - expect_before default abort - expect -re {Now listening on: ([^\r]+)\r} { - set url $expect_out(1,string) - } - expect "Application started. Press Ctrl+C to shut down." - set output [exec curl -sSf $url] - if {$output != "Hello World!"} { - send_error "Unexpected output: $output\n" - exit 1 - } - send \x03 - expect_before timeout abort - expect eof - catch wait result - exit [lindex $result 3] - EOF - touch $out - ''; - runAllowNetworking = true; - }; - } - // lib.optionalAttrs finalAttrs.finalPackage.hasILCompiler { - aot = mkDotnetTest { - name = "aot"; - stdenv = if stdenv.hostPlatform.isDarwin then swiftPackages.stdenv else stdenv; - template = "console"; - usePackageSource = true; - buildInputs = - [ - zlib - ] - ++ lib.optional stdenv.hostPlatform.isDarwin ( - with darwin; - with apple_sdk.frameworks; - [ - swiftPackages.swift - Foundation - CryptoKit - GSS - ICU - ] - ); - build = '' - dotnet restore -p:PublishAot=true - dotnet publish -p:PublishAot=true -o $out/bin - ''; - runtime = null; - run = checkConsoleOutput "$src/bin/test"; - }; - } - ) - // args.passthru.tests or { }; - } // args.passthru or { }; - } -) diff --git a/pkgs/development/compilers/dotnet/dotnet.nix b/pkgs/development/compilers/dotnet/dotnet.nix index c56ff5527982..2a61a5cb01ed 100644 --- a/pkgs/development/compilers/dotnet/dotnet.nix +++ b/pkgs/development/compilers/dotnet/dotnet.nix @@ -26,7 +26,7 @@ let tarballHash depsFile ; - bootstrapSdk = (buildDotnetSdk bootstrapSdkFile).sdk.overrideAttrs (old: { + bootstrapSdk = (buildDotnetSdk bootstrapSdkFile).sdk.unwrapped.overrideAttrs (old: { passthru = old.passthru or { } // { artifacts = stdenvNoCC.mkDerivation rec { name = lib.nameFromURL artifactsUrl ".tar.gz"; diff --git a/pkgs/development/compilers/dotnet/packages.nix b/pkgs/development/compilers/dotnet/packages.nix index b32bf3f2d9cf..5f278d5a8dd2 100644 --- a/pkgs/development/compilers/dotnet/packages.nix +++ b/pkgs/development/compilers/dotnet/packages.nix @@ -12,7 +12,8 @@ }: let - mkCommon = callPackage ./common.nix { }; + mkWrapper = callPackage ./wrapper.nix { }; + mkCommon = type: args: mkWrapper type (stdenvNoCC.mkDerivation args); inherit (vmr) targetRid releaseManifest; # TODO: do this properly diff --git a/pkgs/development/compilers/dotnet/stage1.nix b/pkgs/development/compilers/dotnet/stage1.nix index 0aa67615ade5..729ff7866a75 100644 --- a/pkgs/development/compilers/dotnet/stage1.nix +++ b/pkgs/development/compilers/dotnet/stage1.nix @@ -23,7 +23,7 @@ let vmr = (mkVMR { inherit releaseManifestFile tarballHash; - bootstrapSdk = stage0.sdk; + bootstrapSdk = stage0.sdk.unwrapped; }).overrideAttrs (old: { passthru = old.passthru or { } // { diff --git a/pkgs/development/compilers/dotnet/vmr.nix b/pkgs/development/compilers/dotnet/vmr.nix index 7cdbd36e9b5d..525611c5001a 100644 --- a/pkgs/development/compilers/dotnet/vmr.nix +++ b/pkgs/development/compilers/dotnet/vmr.nix @@ -100,7 +100,7 @@ stdenv.mkDerivation rec { buildInputs = [ - # this gets copied into the tree, but we still want the hooks to run + # this gets copied into the tree, but we still need the sandbox profile bootstrapSdk # the propagated build inputs in llvm.dev break swift compilation llvm.out @@ -364,6 +364,7 @@ stdenv.mkDerivation rec { cp -Tr ${bootstrapSdk} .dotnet chmod -R +w .dotnet + export HOME=$(mktemp -d) ${prepScript} $prepFlags runHook postConfigure diff --git a/pkgs/development/compilers/dotnet/wrapper.nix b/pkgs/development/compilers/dotnet/wrapper.nix new file mode 100644 index 000000000000..61a1e1ab2473 --- /dev/null +++ b/pkgs/development/compilers/dotnet/wrapper.nix @@ -0,0 +1,247 @@ +{ + stdenv, + stdenvNoCC, + lib, + writeText, + testers, + runCommand, + runCommandWith, + expect, + curl, + installShellFiles, + callPackage, + zlib, + swiftPackages, + darwin, + icu, + lndir, + substituteAll, + nugetPackageHook, + xmlstarlet, +}: +type: unwrapped: +stdenvNoCC.mkDerivation (finalAttrs: { + pname = "${unwrapped.pname}-wrapped"; + inherit (unwrapped) version meta; + + src = unwrapped; + dontUnpack = true; + + doInstallCheck = true; + + installPhase = '' + runHook preInstall + mkdir -p "$out"/bin + ln -s "$src"/bin/* "$out"/bin + runHook postInstall + ''; + + installCheckPhase = '' + runHook preInstallCheck + $out/bin/dotnet --info + runHook postInstallCheck + ''; + + setupHooks = + [ + ./dotnet-setup-hook.sh + ] + ++ lib.optional (type == "sdk") (substituteAll { + src = ./dotnet-sdk-setup-hook.sh; + inherit lndir xmlstarlet; + }); + + propagatedSandboxProfile = toString unwrapped.__propagatedSandboxProfile; + + propagatedBuildInputs = lib.optional (type == "sdk") nugetPackageHook; + + nativeBuildInputs = [ installShellFiles ]; + + postInstall = '' + # completions snippets taken from https://learn.microsoft.com/en-us/dotnet/core/tools/enable-tab-autocomplete + installShellCompletion --cmd dotnet \ + --bash ${./completions/dotnet.bash} \ + --zsh ${./completions/dotnet.zsh} \ + --fish ${./completions/dotnet.fish} + ''; + + passthru = unwrapped.passthru // { + inherit unwrapped; + tests = + let + mkDotnetTest = + { + name, + stdenv ? stdenvNoCC, + template, + usePackageSource ? false, + build, + buildInputs ? [ ], + # TODO: use correct runtimes instead of sdk + runtime ? finalAttrs.finalPackage, + runInputs ? [ ], + run ? null, + runAllowNetworking ? false, + }: + let + sdk = finalAttrs.finalPackage; + built = stdenv.mkDerivation { + name = "dotnet-test-${name}"; + buildInputs = [ sdk ] ++ buildInputs ++ lib.optional (usePackageSource) sdk.packages; + # make sure ICU works in a sandbox + propagatedSandboxProfile = toString sdk.__propagatedSandboxProfile; + unpackPhase = '' + mkdir test + cd test + dotnet new ${template} -o . --no-restore + ''; + buildPhase = build; + dontPatchELF = true; + }; + in + if run == null then + built + else + runCommand "${built.name}-run" + ( + { + src = built; + nativeBuildInputs = [ built ] ++ runInputs; + passthru = { + inherit built; + }; + } + // lib.optionalAttrs (stdenv.hostPlatform.isDarwin && runAllowNetworking) { + sandboxProfile = '' + (allow network-inbound (local ip)) + (allow mach-lookup (global-name "com.apple.FSEvents")) + ''; + __darwinAllowLocalNetworking = true; + } + ) + ( + lib.optionalString (runtime != null) '' + # TODO: use runtime here + export DOTNET_ROOT=${runtime.unwrapped} + '' + + run + ); + + # Setting LANG to something other than 'C' forces the runtime to search + # for ICU, which will be required in most user environments. + checkConsoleOutput = command: '' + output="$(LANG=C.UTF-8 ${command})" + # yes, older SDKs omit the comma + [[ "$output" =~ Hello,?\ World! ]] && touch "$out" + ''; + in + unwrapped.passthru.tests or { } + // { + version = testers.testVersion ( + { + package = finalAttrs.finalPackage; + } + // lib.optionalAttrs (type != "sdk") { + command = "dotnet --info"; + } + ); + } + // lib.optionalAttrs (type == "sdk") ( + { + console = mkDotnetTest { + name = "console"; + template = "console"; + build = checkConsoleOutput "dotnet run"; + }; + + publish = mkDotnetTest { + name = "publish"; + template = "console"; + build = "dotnet publish -o $out/bin"; + run = checkConsoleOutput "$src/bin/test"; + }; + + self-contained = mkDotnetTest { + name = "self-contained"; + template = "console"; + usePackageSource = true; + build = "dotnet publish --use-current-runtime --sc -o $out"; + runtime = null; + run = checkConsoleOutput "$src/test"; + }; + + single-file = mkDotnetTest { + name = "single-file"; + template = "console"; + usePackageSource = true; + build = "dotnet publish --use-current-runtime -p:PublishSingleFile=true -o $out/bin"; + runtime = null; + run = checkConsoleOutput "$src/bin/test"; + }; + + web = mkDotnetTest { + name = "web"; + template = "web"; + build = "dotnet publish -o $out/bin"; + runInputs = [ + expect + curl + ]; + run = '' + expect <<"EOF" + set status 1 + spawn $env(src)/bin/test + proc abort { } { exit 2 } + expect_before default abort + expect -re {Now listening on: ([^\r]+)\r} { + set url $expect_out(1,string) + } + expect "Application started. Press Ctrl+C to shut down." + set output [exec curl -sSf $url] + if {$output != "Hello World!"} { + send_error "Unexpected output: $output\n" + exit 1 + } + send \x03 + expect_before timeout abort + expect eof + catch wait result + exit [lindex $result 3] + EOF + touch $out + ''; + runAllowNetworking = true; + }; + } + // lib.optionalAttrs finalAttrs.finalPackage.hasILCompiler { + aot = mkDotnetTest { + name = "aot"; + stdenv = if stdenv.hostPlatform.isDarwin then swiftPackages.stdenv else stdenv; + template = "console"; + usePackageSource = true; + buildInputs = + [ + zlib + ] + ++ lib.optional stdenv.hostPlatform.isDarwin ( + with darwin; + with apple_sdk.frameworks; + [ + swiftPackages.swift + Foundation + CryptoKit + GSS + ICU + ] + ); + build = '' + dotnet restore -p:PublishAot=true + dotnet publish -p:PublishAot=true -o $out/bin + ''; + runtime = null; + run = checkConsoleOutput "$src/bin/test"; + }; + } + ); + }; +}) diff --git a/pkgs/test/dotnet/use-dotnet-from-env/default.nix b/pkgs/test/dotnet/use-dotnet-from-env/default.nix index 711a98eb0c29..d26458a86a3d 100644 --- a/pkgs/test/dotnet/use-dotnet-from-env/default.nix +++ b/pkgs/test/dotnet/use-dotnet-from-env/default.nix @@ -21,7 +21,7 @@ let removeReferencesTo ]; postFixup = (oldAttrs.postFixup or "") + '' - remove-references-to -t ${dotnet-runtime} "$out/bin/Application" + remove-references-to -t ${dotnet-runtime.unwrapped} "$out/bin/Application" ''; }); @@ -46,7 +46,7 @@ in use-dotnet-root-env = testers.testEqualContents { assertion = "buildDotnetModule uses DOTNET_ROOT from environment in wrapper"; expected = runtimeVersionFile; - actual = runCommand "use-dotnet-from-env-root-test" { env.DOTNET_ROOT = dotnet-runtime; } '' + actual = runCommand "use-dotnet-from-env-root-test" { env.DOTNET_ROOT = dotnet-runtime.unwrapped; } '' ${appWithoutFallback}/bin/Application >"$out" ''; };