diff --git a/pkgs/applications/misc/ArchiSteamFarm/default.nix b/pkgs/applications/misc/ArchiSteamFarm/default.nix
index 7c334fb804558..fc3335ca3a927 100644
--- a/pkgs/applications/misc/ArchiSteamFarm/default.nix
+++ b/pkgs/applications/misc/ArchiSteamFarm/default.nix
@@ -41,7 +41,7 @@ buildDotnetModule rec {
doCheck = true;
preBuild = ''
- export projectFile=(ArchiSteamFarm)
+ dotnetProjectFiles=(ArchiSteamFarm)
'';
preInstall = ''
diff --git a/pkgs/build-support/dotnet/build-dotnet-global-tool/default.nix b/pkgs/build-support/dotnet/build-dotnet-global-tool/default.nix
index 16cf029ca3451..7ae9cfc9f6618 100644
--- a/pkgs/build-support/dotnet/build-dotnet-global-tool/default.nix
+++ b/pkgs/build-support/dotnet/build-dotnet-global-tool/default.nix
@@ -28,7 +28,7 @@ buildDotnetModule (args // {
] ++ (nugetDeps fetchNuGet);
};
- projectFile = "";
+ dotnetGlobalTool = true;
useDotnetFromEnv = true;
diff --git a/pkgs/build-support/dotnet/build-dotnet-module/default.nix b/pkgs/build-support/dotnet/build-dotnet-module/default.nix
index 6f5df2d34b882..7b88b16064bca 100644
--- a/pkgs/build-support/dotnet/build-dotnet-module/default.nix
+++ b/pkgs/build-support/dotnet/build-dotnet-module/default.nix
@@ -69,7 +69,7 @@
, disabledTests ? [ ]
# The project file to run unit tests against. This is usually referenced in the regular project file, but sometimes it needs to be manually set.
# It gets restored and build, but not installed. You may need to regenerate your nuget lockfile after setting this.
-, testProjectFile ? ""
+, testProjectFile ? null
# The type of build to perform. This is passed to `dotnet` with the `--configuration` flag. Possible values are `Release`, `Debug`, etc.
, buildType ? "Release"
@@ -88,17 +88,18 @@
} @ args:
let
+ projectFiles =
+ lib.optionals (projectFile != null) (lib.toList projectFile);
+ testProjectFiles =
+ lib.optionals (testProjectFile != null) (lib.toList testProjectFile);
+
platforms =
if args ? meta.platforms
then lib.intersectLists args.meta.platforms dotnet-sdk.meta.platforms
else dotnet-sdk.meta.platforms;
inherit (callPackage ./hooks {
- inherit dotnet-sdk disabledTests nuget-source dotnet-runtime runtimeDeps buildType;
- runtimeId =
- if runtimeId != null
- then runtimeId
- else dotnetCorePackages.systemToDotnetRid stdenvNoCC.targetPlatform.system;
+ inherit dotnet-sdk dotnet-runtime;
}) dotnetConfigureHook dotnetBuildHook dotnetCheckHook dotnetInstallHook dotnetFixupHook;
localDeps =
@@ -143,6 +144,19 @@ let
nugetDepsFile = _nugetDeps.sourceFile;
in
stdenvNoCC.mkDerivation (args // {
+ dotnetInstallPath = installPath;
+ dotnetExecutables = executables;
+ dotnetBuildType = buildType;
+ dotnetProjectFiles = projectFiles;
+ dotnetTestProjectFiles = testProjectFiles;
+ dotnetDisabledTests = disabledTests;
+ dotnetRuntimeId = runtimeId;
+ nugetSource = nuget-source;
+ dotnetRuntimeDeps = map lib.getLib runtimeDeps;
+ dotnetSelfContainedBuild = selfContainedBuild;
+ dotnetUseAppHost = useAppHost;
+ inherit useDotnetFromEnv;
+
nativeBuildInputs = args.nativeBuildInputs or [ ] ++ [
dotnetConfigureHook
dotnetBuildHook
@@ -172,7 +186,7 @@ stdenvNoCC.mkDerivation (args // {
else [ ]));
makeWrapperArgs = args.makeWrapperArgs or [ ] ++ [
- "--prefix LD_LIBRARY_PATH : ${dotnet-sdk.icu}/lib"
+ "--prefix" "LD_LIBRARY_PATH" ":" "${dotnet-sdk.icu}/lib"
];
# Stripping breaks the executable
@@ -181,8 +195,6 @@ stdenvNoCC.mkDerivation (args // {
# gappsWrapperArgs gets included when wrapping for dotnet, as to avoid double wrapping
dontWrapGApps = args.dontWrapGApps or true;
- inherit selfContainedBuild useAppHost useDotnetFromEnv;
-
# propagate the runtime sandbox profile since the contents apply to published
# executables
propagatedSandboxProfile = toString dotnet-runtime.__propagatedSandboxProfile;
@@ -267,11 +279,11 @@ stdenvNoCC.mkDerivation (args // {
--no-cache \
--force \
${lib.optionalString (!enableParallelBuilding) "--disable-parallel"} \
- ${lib.optionalString (flags != []) (toString flags)}
+ ${lib.escapeShellArgs flags}
}
- declare -a projectFiles=( ${toString (lib.toList projectFile)} )
- declare -a testProjectFiles=( ${toString (lib.toList testProjectFile)} )
+ declare -a projectFiles=( ${lib.escapeShellArgs projectFiles} )
+ declare -a testProjectFiles=( ${lib.escapeShellArgs testProjectFiles} )
export DOTNET_NOLOGO=1
export DOTNET_CLI_TELEMETRY_OPTOUT=1
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 44091604f5c2c..b9c51a743c6a6 100644
--- a/pkgs/build-support/dotnet/build-dotnet-module/hooks/default.nix
+++ b/pkgs/build-support/dotnet/build-dotnet-module/hooks/default.nix
@@ -4,28 +4,21 @@
, coreutils
, zlib
, openssl
-, callPackage
, makeSetupHook
-, makeWrapper
+, dotnetCorePackages
+ # Passed from ../default.nix
, dotnet-sdk
-, disabledTests
-, nuget-source
, dotnet-runtime
-, runtimeDeps
-, buildType
-, runtimeId
}:
-assert (builtins.isString runtimeId);
-
let
- libraryPath = lib.makeLibraryPath runtimeDeps;
+ runtimeId = dotnetCorePackages.systemToDotnetRid stdenv.hostPlatform.system;
in
{
dotnetConfigureHook = makeSetupHook
{
name = "dotnet-configure-hook";
substitutions = {
- nugetSource = nuget-source;
+ runtimeId = lib.escapeShellArg runtimeId;
dynamicLinker = "${stdenv.cc}/nix-support/dynamic-linker";
libPath = lib.makeLibraryPath [
stdenv.cc.cc.lib
@@ -34,7 +27,6 @@ in
zlib
openssl
];
- inherit runtimeId;
};
}
./dotnet-configure-hook.sh;
@@ -43,7 +35,7 @@ in
{
name = "dotnet-build-hook";
substitutions = {
- inherit buildType runtimeId;
+ runtimeId = lib.escapeShellArg runtimeId;
};
}
./dotnet-build-hook.sh;
@@ -52,15 +44,7 @@ in
{
name = "dotnet-check-hook";
substitutions = {
- inherit buildType runtimeId libraryPath;
- disabledTests = lib.optionalString (disabledTests != [ ])
- (
- let
- escapedNames = lib.lists.map (n: lib.replaceStrings [ "," ] [ "%2C" ] n) disabledTests;
- filters = lib.lists.map (n: "FullyQualifiedName!=${n}") escapedNames;
- in
- "${lib.concatStringsSep "&" filters}"
- );
+ runtimeId = lib.escapeShellArg runtimeId;
};
}
./dotnet-check-hook.sh;
@@ -69,7 +53,7 @@ in
{
name = "dotnet-install-hook";
substitutions = {
- inherit buildType runtimeId;
+ runtimeId = lib.escapeShellArg runtimeId;
};
}
./dotnet-install-hook.sh;
@@ -79,11 +63,7 @@ in
name = "dotnet-fixup-hook";
substitutions = {
dotnetRuntime = dotnet-runtime;
- runtimeDeps = libraryPath;
- shell = stdenv.shell;
- which = "${which}/bin/which";
- dirname = "${coreutils}/bin/dirname";
- realpath = "${coreutils}/bin/realpath";
+ wrapperPath = lib.makeBinPath [ which coreutils ];
};
}
./dotnet-fixup-hook.sh;
diff --git a/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-build-hook.sh b/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-build-hook.sh
index 798109291f92a..f209861f79b15 100644
--- a/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-build-hook.sh
+++ b/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-build-hook.sh
@@ -1,12 +1,25 @@
-# inherit arguments from derivation
-dotnetBuildFlags=( ${dotnetBuildFlags[@]-} )
-
dotnetBuildHook() {
echo "Executing dotnetBuildHook"
runHook preBuild
- if [ "${enableParallelBuilding-}" ]; then
+ local -r hostRuntimeId=@runtimeId@
+ local -r dotnetBuildType="${dotnetBuildType-Release}"
+ local -r dotnetRuntimeId="${dotnetRuntimeId-$hostRuntimeId}"
+
+ if [[ -n $__structuredAttrs ]]; then
+ local dotnetProjectFilesArray=( "${dotnetProjectFiles[@]}" )
+ local dotnetTestProjectFilesArray=( "${dotnetTestProjectFiles[@]}" )
+ local dotnetFlagsArray=( "${dotnetFlags[@]}" )
+ local dotnetBuildFlagsArray=( "${dotnetBuildFlags[@]}" )
+ else
+ local dotnetProjectFilesArray=($dotnetProjectFiles)
+ local dotnetTestProjectFilesArray=($dotnetTestProjectFiles)
+ local dotnetFlagsArray=($dotnetFlags)
+ local dotnetBuildFlagsArray=($dotnetBuildFlags)
+ fi
+
+ if [[ -n "${enableParallelBuilding-}" ]]; then
local -r maxCpuFlag="$NIX_BUILD_CORES"
local -r parallelBuildFlag="true"
else
@@ -14,50 +27,53 @@ dotnetBuildHook() {
local -r parallelBuildFlag="false"
fi
- if [ "${selfContainedBuild-}" ]; then
- dotnetBuildFlags+=("-p:SelfContained=true")
+ if [[ -n ${dotnetSelfContainedBuild-} ]]; then
+ dotnetBuildFlagsArray+=("-p:SelfContained=true")
else
- dotnetBuildFlags+=("-p:SelfContained=false")
+ dotnetBuildFlagsArray+=("-p:SelfContained=false")
fi
- if [ "${useAppHost-}" ]; then
- dotnetBuildFlags+=("-p:UseAppHost=true")
+ if [[ -n ${dotnetUseAppHost-} ]]; then
+ dotnetBuildFlagsArray+=("-p:UseAppHost=true")
fi
- local versionFlags=()
- if [ "${version-}" ]; then
- versionFlags+=("-p:InformationalVersion=${version-}")
+ local versionFlagsArray=()
+ if [[ -n ${version-} ]]; then
+ versionFlagsArray+=("-p:InformationalVersion=$version")
fi
- if [ "${versionForDotnet-}" ]; then
- versionFlags+=("-p:Version=${versionForDotnet-}")
+ if [[ -n ${versionForDotnet-} ]]; then
+ versionFlagsArray+=("-p:Version=$versionForDotnet")
fi
dotnetBuild() {
- local -r project="${1-}"
+ local -r projectFile="${1-}"
- runtimeIdFlags=()
- if [[ "$project" == *.csproj ]] || [ "${selfContainedBuild-}" ]; then
- runtimeIdFlags+=("--runtime @runtimeId@")
+ local runtimeIdFlagsArray=()
+ if [[ $projectFile == *.csproj || -n ${dotnetSelfContainedBuild-} ]]; then
+ runtimeIdFlagsArray+=("--runtime" "$dotnetRuntimeId")
fi
- dotnet build ${project-} \
- -maxcpucount:$maxCpuFlag \
- -p:BuildInParallel=$parallelBuildFlag \
+ dotnet build ${1+"$projectFile"} \
+ -maxcpucount:"$maxCpuFlag" \
+ -p:BuildInParallel="$parallelBuildFlag" \
-p:ContinuousIntegrationBuild=true \
-p:Deterministic=true \
- --configuration "@buildType@" \
+ --configuration "$dotnetBuildType" \
--no-restore \
- ${versionFlags[@]} \
- ${runtimeIdFlags[@]} \
- ${dotnetBuildFlags[@]} \
- ${dotnetFlags[@]}
+ "${versionFlagsArray[@]}" \
+ "${runtimeIdFlagsArray[@]}" \
+ "${dotnetBuildFlagsArray[@]}" \
+ "${dotnetFlagsArray[@]}"
}
- (( "${#projectFile[@]}" == 0 )) && dotnetBuild
+ if (( ${#dotnetProjectFilesArray[@]} == 0 )); then
+ dotnetBuild
+ fi
- for project in ${projectFile[@]} ${testProjectFile[@]-}; do
- dotnetBuild "$project"
+ local projectFile
+ for projectFile in "${dotnetProjectFilesArray[@]}" "${dotnetTestProjectFilesArray[@]}"; do
+ dotnetBuild "$projectFile"
done
runHook postBuild
@@ -65,6 +81,6 @@ dotnetBuildHook() {
echo "Finished dotnetBuildHook"
}
-if [[ -z "${dontDotnetBuild-}" && -z "${buildPhase-}" ]]; then
+if [[ -z ${dontDotnetBuild-} && -z ${buildPhase-} ]]; then
buildPhase=dotnetBuildHook
fi
diff --git a/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-check-hook.sh b/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-check-hook.sh
index f19bf9f620feb..c91251f4f1807 100644
--- a/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-check-hook.sh
+++ b/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-check-hook.sh
@@ -1,39 +1,65 @@
-# inherit arguments from derivation
-dotnetTestFlags=( ${dotnetTestFlags[@]-} )
-
dotnetCheckHook() {
echo "Executing dotnetCheckHook"
runHook preCheck
- if [ "${disabledTests-}" ]; then
- local -r disabledTestsFlag="--filter @disabledTests@"
+ local -r hostRuntimeId=@runtimeId@
+ local -r dotnetBuildType="${dotnetBuildType-Release}"
+ local -r dotnetRuntimeId="${dotnetRuntimeId-$hostRuntimeId}"
+
+ if [[ -n $__structuredAttrs ]]; then
+ local dotnetProjectFilesArray=( "${dotnetProjectFiles[@]}" )
+ local dotnetTestProjectFilesArray=( "${dotnetTestProjectFiles[@]}" )
+ local dotnetTestFlagsArray=( "${dotnetTestFlags[@]}" )
+ local dotnetDisabledTestsArray=( "${dotnetDisabledTests[@]}" )
+ local dotnetRuntimeDepsArray=( "${dotnetRuntimeDeps[@]}" )
+ else
+ local dotnetProjectFilesArray=($dotnetProjectFiles)
+ local dotnetTestProjectFilesArray=($dotnetTestProjectFiles)
+ local dotnetTestFlagsArray=($dotnetTestFlags)
+ local dotnetDisabledTestsArray=($dotnetDisabledTests)
+ local dotnetRuntimeDepsArray=($dotnetRuntimeDeps)
+ fi
+
+ if (( ${#dotnetDisabledTestsArray[@]} > 0 )); then
+ local disabledTestsFilters=("${dotnetDisabledTestsArray[@]/#/FullyQualifiedName!=}")
+ local OLDIFS="$IFS" IFS='&'
+ dotnetTestFlagsArray+=("--filter:${disabledTestsFilters[*]//,/%2C}")
+ IFS="$OLDIFS"
+ fi
+
+ local libraryPath="${LD_LIBRARY_PATH-}"
+ if (( ${#dotnetRuntimeDepsArray[@]} > 0 )); then
+ local libraryPathArray=("${dotnetRuntimeDepsArray[@]/%//lib}")
+ local OLDIFS="$IFS" IFS=':'
+ libraryPath="${libraryPathArray[*]}${libraryPath:+':'}$libraryPath"
+ IFS="$OLDIFS"
fi
- if [ "${enableParallelBuilding-}" ]; then
+ if [[ -n ${enableParallelBuilding-} ]]; then
local -r maxCpuFlag="$NIX_BUILD_CORES"
else
local -r maxCpuFlag="1"
fi
- for project in ${testProjectFile[@]-${projectFile[@]}}; do
- runtimeIdFlags=()
- if [[ "$project" == *.csproj ]]; then
- runtimeIdFlags=("--runtime @runtimeId@")
+ local projectFile
+ for projectFile in "${dotnetTestProjectFilesArray[@]-${dotnetProjectFilesArray[@]}}"; do
+ local runtimeIdFlagsArray=()
+ if [[ $projectFile == *.csproj ]]; then
+ runtimeIdFlagsArray=("--runtime" "$dotnetRuntimeId")
fi
- LD_LIBRARY_PATH="@libraryPath@" \
- dotnet test "$project" \
- -maxcpucount:$maxCpuFlag \
+ LD_LIBRARY_PATH=$libraryPath \
+ dotnet test "$projectFile" \
+ -maxcpucount:"$maxCpuFlag" \
-p:ContinuousIntegrationBuild=true \
-p:Deterministic=true \
- --configuration "@buildType@" \
+ --configuration "$dotnetBuildType" \
--no-build \
--logger "console;verbosity=normal" \
- ${disabledTestsFlag-} \
- ${runtimeIdFlags[@]} \
- "${dotnetTestFlags[@]}" \
- "${dotnetFlags[@]}"
+ "${runtimeIdFlagsArray[@]}" \
+ "${dotnetTestFlagsArray[@]}" \
+ "${dotnetFlagsArray[@]}"
done
runHook postCheck
diff --git a/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-configure-hook.sh b/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-configure-hook.sh
index 3eb0d4e1f2309..12fa348699865 100644
--- a/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-configure-hook.sh
+++ b/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-configure-hook.sh
@@ -1,63 +1,103 @@
-declare -a projectFile testProjectFile
-
-# Inherit arguments from derivation
-dotnetFlags=( ${dotnetFlags[@]-} )
-dotnetRestoreFlags=( ${dotnetRestoreFlags[@]-} )
-
dotnetConfigureHook() {
echo "Executing dotnetConfigureHook"
runHook preConfigure
- if [ -z "${enableParallelBuilding-}" ]; then
+ if [[ -z ${nugetSource-} ]]; then
+ echo
+ echo "ERROR: no dependencies were specified"
+ echo 'Hint: set `nugetSource` if using these hooks individually. If this is happening with `buildDotnetModule`, please open an issue.'
+ echo
+
+ exit 1
+ fi
+
+ local nugetSourceSedQuoted="${nugetSource//[\/\\&$'\n']/\\&}"
+ local nugetSourceXMLQuoted="$nugetSource"
+ nugetSourceXMLQuoted="${nugetSource//&/\&}"
+ nugetSourceXMLQuoted="${nugetSourceXMLQuoted//\"/\"}"
+
+ local -r hostRuntimeId=@runtimeId@
+ local -r dynamicLinker=@dynamicLinker@
+ local -r libPath=@libPath@
+ local -r dotnetRuntimeId="${dotnetRuntimeId-$hostRuntimeId}"
+
+ if [[ -n $__structuredAttrs ]]; then
+ local dotnetProjectFilesArray=( "${dotnetProjectFiles[@]}" )
+ local dotnetTestProjectFilesArray=( "${dotnetTestProjectFiles[@]}" )
+ local dotnetFlagsArray=( "${dotnetFlags[@]}" )
+ local dotnetRestoreFlagsArray=( "${dotnetRestoreFlags[@]}" )
+ else
+ local dotnetProjectFilesArray=($dotnetProjectFiles)
+ local dotnetTestProjectFilesArray=($dotnetTestProjectFiles)
+ local dotnetFlagsArray=($dotnetFlags)
+ local dotnetRestoreFlagsArray=($dotnetRestoreFlags)
+ fi
+
+ if [[ -z ${enableParallelBuilding-} ]]; then
local -r parallelFlag="--disable-parallel"
fi
dotnetRestore() {
- local -r project="${1-}"
- dotnet restore ${project-} \
+ local -r projectFile="${1-}"
+ dotnet restore ${1+"$projectFile"} \
-p:ContinuousIntegrationBuild=true \
-p:Deterministic=true \
- --runtime "@runtimeId@" \
- --source "@nugetSource@/lib" \
+ --runtime "$dotnetRuntimeId" \
+ --source "$nugetSource/lib" \
${parallelFlag-} \
- ${dotnetRestoreFlags[@]} \
- ${dotnetFlags[@]}
+ "${dotnetRestoreFlagsArray[@]}" \
+ "${dotnetFlagsArray[@]}"
}
# Generate a NuGet.config file to make sure everything,
# including things like dependencies, is restored from the proper source
-cat < "./NuGet.config"
+ cat >NuGet.config <
-
+
EOF
- # Patch paket.dependencies and paket.lock (if found) to use the proper source. This ensures
- # paket restore works correctly
- # We use + instead of / in sed to avoid problems with slashes
- find -name paket.dependencies -exec sed -i 's+source .*+source @nugetSource@/lib+g' {} \;
- find -name paket.lock -exec sed -i 's+remote:.*+remote: @nugetSource@/lib+g' {} \;
-
- dotnet tool restore --add-source "@nugetSource@/lib"
-
- (( "${#projectFile[@]}" == 0 )) && dotnetRestore
+ # Patch paket.dependencies and paket.lock (if found) to use the proper
+ # source. This ensures paket restore works correctly. Note that the
+ # nugetSourceSedQuoted abomination below safely escapes nugetSource string
+ # for use as a sed replacement string to avoid issues with slashes and other
+ # special characters ('&', '\\' and '\n').
+ find -name paket.dependencies -exec sed -i "s/source .*/source $nugetSourceSedQuoted\/lib/g" {} \;
+ find -name paket.lock -exec sed -i "s/remote:.*/remote: $nugetSourceSedQuoted\/lib/g" {} \;
+
+ dotnet tool restore --add-source "$nugetSource/lib"
+
+ # dotnetGlobalTool is set in buildDotnetGlobalTool to patch dependencies but
+ # avoid other project-specific logic. This is a hack, but the old behavior
+ # is worse as it relied on a bug: setting projectFile to an empty string
+ # made the hooks actually skip all project-specific logic. It’s hard to keep
+ # backwards compatibility with this odd behavior now since we are using
+ # arrays, so instead we just pass a variable to indicate that we don’t have
+ # projects.
+ if [[ -z ${dotnetGlobalTool-} ]]; then
+ if (( ${#dotnetProjectFilesArray[@]} == 0 )); then
+ dotnetRestore
+ fi
- for project in ${projectFile[@]} ${testProjectFile[@]-}; do
- dotnetRestore "$project"
- done
+ local projectFile
+ for projectFile in "${dotnetProjectFilesArray[@]}" "${dotnetTestProjectFilesArray[@]}"; do
+ dotnetRestore "$projectFile"
+ done
+ fi
echo "Fixing up native binaries..."
# Find all native binaries and nuget libraries, and fix them up,
# by setting the proper interpreter and rpath to some commonly used libraries
+ local binary
for binary in $(find "$HOME/.nuget/packages/" -type f -executable); do
if patchelf --print-interpreter "$binary" >/dev/null 2>/dev/null; then
echo "Found binary: $binary, fixing it up..."
- patchelf --set-interpreter "$(cat "@dynamicLinker@")" "$binary"
+ patchelf --set-interpreter "$(cat "$dynamicLinker")" "$binary"
# This makes sure that if the binary requires some specific runtime dependencies, it can find it.
# This fixes dotnet-built binaries like crossgen2
@@ -68,7 +108,7 @@ EOF
--add-needed libssl.so \
"$binary"
- patchelf --set-rpath "@libPath@" "$binary"
+ patchelf --set-rpath "$libPath" "$binary"
fi
done
diff --git a/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-fixup-hook.sh b/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-fixup-hook.sh
index e3671728af35e..f9aba29a43555 100644
--- a/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-fixup-hook.sh
+++ b/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-fixup-hook.sh
@@ -1,28 +1,55 @@
-# Inherit arguments from the derivation
-declare -a derivationMakeWrapperArgs="( ${makeWrapperArgs-} )"
-makeWrapperArgs=( "${derivationMakeWrapperArgs[@]}" )
-
# First argument is the executable you want to wrap,
# the second is the destination for the wrapper.
wrapDotnetProgram() {
- local dotnetRootFlags=()
+ local -r dotnetRuntime=@dotnetRuntime@
+ local -r wrapperPath=@wrapperPath@
+
+ local -r dotnetFromEnvScript='dotnetFromEnv() {
+ local dotnetPath
+ if command -v dotnet 2>&1 >/dev/null; then
+ dotnetPath=$(which dotnet) && \
+ dotnetPath=$(realpath "$dotnetPath") && \
+ dotnetPath=$(dirname "$dotnetPath") && \
+ export DOTNET_ROOT="$dotnetPath"
+ fi
+}
+dotnetFromEnv'
+
+ if [[ -n $__structuredAttrs ]]; then
+ local -r dotnetRuntimeDepsArray=( "${dotnetRuntimeDeps[@]}" )
+ local -r makeWrapperArgsArray=( "${makeWrapperArgs[@]}" )
+ else
+ local -r dotnetRuntimeDepsArray=($dotnetRuntimeDeps)
+ local -r makeWrapperArgsArray=($makeWrapperArgs)
+ fi
- if [ ! "${selfContainedBuild-}" ]; then
- if [ "${useDotnetFromEnv-}" ]; then
+ local dotnetRuntimeDepsFlags=()
+ if (( ${#dotnetRuntimeDepsArray[@]} > 0 )); then
+ local libraryPathArray=("${dotnetRuntimeDepsArray[@]/%//lib}")
+ local OLDIFS="$IFS" IFS=':'
+ dotnetRuntimeDepsFlags+=("--suffix" "LD_LIBRARY_PATH" ":" "${libraryPathArray[*]}")
+ IFS="$OLDIFS"
+ fi
+
+ local dotnetRootFlagsArray=()
+ if [[ -z ${dotnetSelfContainedBuild-} ]]; then
+ if [[ -n ${useDotnetFromEnv-} ]]; then
# if dotnet CLI is available, set DOTNET_ROOT based on it. Otherwise set to default .NET runtime
- dotnetRootFlags+=("--run" 'command -v dotnet &>/dev/null && export DOTNET_ROOT="$(@dirname@ "$(@realpath@ "$(@which@ dotnet)")")" || export DOTNET_ROOT="@dotnetRuntime@"')
- dotnetRootFlags+=("--suffix" "PATH" ":" "@dotnetRuntime@/bin")
+ dotnetRootFlagsArray+=("--suffix" "PATH" ":" "$wrapperPath")
+ dotnetRootFlagsArray+=("--run" "$dotnetFromEnvScript")
+ dotnetRootFlagsArray+=("--set-default" "DOTNET_ROOT" "$dotnetRuntime")
+ dotnetRootFlagsArray+=("--suffix" "PATH" ":" "$dotnetRuntime/bin")
else
- dotnetRootFlags+=("--set" "DOTNET_ROOT" "@dotnetRuntime@")
- dotnetRootFlags+=("--prefix" "PATH" ":" "@dotnetRuntime@/bin")
+ dotnetRootFlagsArray+=("--set" "DOTNET_ROOT" "$dotnetRuntime")
+ dotnetRootFlagsArray+=("--prefix" "PATH" ":" "$dotnetRuntime/bin")
fi
fi
makeWrapper "$1" "$2" \
- --suffix "LD_LIBRARY_PATH" : "@runtimeDeps@" \
- "${dotnetRootFlags[@]}" \
+ "${dotnetRuntimeDepsFlags[@]}" \
+ "${dotnetRootFlagsArray[@]}" \
"${gappsWrapperArgs[@]}" \
- "${makeWrapperArgs[@]}"
+ "${makeWrapperArgsArray[@]}"
echo "installed wrapper to "$2""
}
@@ -30,13 +57,24 @@ wrapDotnetProgram() {
dotnetFixupHook() {
echo "Executing dotnetFixupPhase"
- # check if executables is declared (including empty values, in which case we generate no executables)
- if declare -p executables &>/dev/null; then
- for executable in ${executables[@]}; do
- path="${installPath-$out/lib/$pname}/$executable"
+ local -r dotnetInstallPath="${dotnetInstallPath-$out/lib/$pname}"
+
+ local executable executableBasename
+
+ # check if dotnetExecutables is declared (including empty values, in which case we generate no executables)
+ if declare -p dotnetExecutables &>/dev/null; then
+ if [[ -n $__structuredAttrs ]]; then
+ local dotnetExecutablesArray=( "${dotnetExecutables[@]}" )
+ else
+ local dotnetExecutablesArray=($dotnetExecutables)
+ fi
+ for executable in "${dotnetExecutablesArray[@]}"; do
+ executableBasename=$(basename "$executable")
+
+ local path="$dotnetInstallPath/$executable"
if test -x "$path"; then
- wrapDotnetProgram "$path" "$out/bin/$(basename "$executable")"
+ wrapDotnetProgram "$path" "$out/bin/$executableBasename"
else
echo "Specified binary \"$executable\" is either not an executable or does not exist!"
echo "Looked in $path"
@@ -45,8 +83,9 @@ dotnetFixupHook() {
done
else
while IFS= read -d '' executable; do
- wrapDotnetProgram "$executable" "$out/bin/$(basename "$executable")" \;
- done < <(find "${installPath-$out/lib/$pname}" ! -name "*.dll" -executable -type f -print0)
+ executableBasename=$(basename "$executable")
+ wrapDotnetProgram "$executable" "$out/bin/$executableBasename" \;
+ done < <(find "$dotnetInstallPath" ! -name "*.dll" -executable -type f -print0)
fi
echo "Finished dotnetFixupPhase"
diff --git a/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-install-hook.sh b/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-install-hook.sh
index ed754d8ffcad9..4d9b3c502c354 100644
--- a/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-install-hook.sh
+++ b/pkgs/build-support/dotnet/build-dotnet-module/hooks/dotnet-install-hook.sh
@@ -1,70 +1,86 @@
-# inherit arguments from derivation
-dotnetInstallFlags=( ${dotnetInstallFlags[@]-} )
-
dotnetInstallHook() {
echo "Executing dotnetInstallHook"
runHook preInstall
- if [ "${selfContainedBuild-}" ]; then
- dotnetInstallFlags+=("--self-contained")
+ local -r hostRuntimeId=@runtimeId@
+ local -r dotnetInstallPath="${dotnetInstallPath-$out/lib/$pname}"
+ local -r dotnetBuildType="${dotnetBuildType-Release}"
+ local -r dotnetRuntimeId="${dotnetRuntimeId-$hostRuntimeId}"
+
+ if [[ -n $__structuredAttrs ]]; then
+ local dotnetProjectFilesArray=( "${dotnetProjectFiles[@]}" )
+ local dotnetFlagsArray=( "${dotnetFlags[@]}" )
+ local dotnetInstallFlagsArray=( "${dotnetInstallFlags[@]}" )
+ local dotnetPackFlagsArray=( "${dotnetPackFlags[@]}" )
+ else
+ local dotnetProjectFilesArray=($dotnetProjectFiles)
+ local dotnetFlagsArray=($dotnetFlags)
+ local dotnetInstallFlagsArray=($dotnetInstallFlags)
+ local dotnetPackFlagsArray=($dotnetPackFlags)
+ fi
+
+ if [[ -n ${dotnetSelfContainedBuild-} ]]; then
+ dotnetInstallFlagsArray+=("--self-contained")
else
- dotnetInstallFlags+=("--no-self-contained")
+ dotnetInstallFlagsArray+=("--no-self-contained")
# https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trim-self-contained
# Trimming is only available for self-contained build, so force disable it here
- dotnetInstallFlags+=("-p:PublishTrimmed=false")
+ dotnetInstallFlagsArray+=("-p:PublishTrimmed=false")
fi
- if [ "${useAppHost-}" ]; then
- dotnetInstallFlags+=("-p:UseAppHost=true")
+ if [[ -n ${dotnetUseAppHost-} ]]; then
+ dotnetInstallFlagsArray+=("-p:UseAppHost=true")
fi
dotnetPublish() {
- local -r project="${1-}"
+ local -r projectFile="${1-}"
- runtimeIdFlags=()
- if [[ "$project" == *.csproj ]] || [ "${selfContainedBuild-}" ]; then
- runtimeIdFlags+=("--runtime @runtimeId@")
+ runtimeIdFlagsArray=()
+ if [[ $projectFile == *.csproj || -n ${dotnetSelfContainedBuild-} ]]; then
+ runtimeIdFlagsArray+=("--runtime" "$dotnetRuntimeId")
fi
- dotnet publish ${project-} \
+ dotnet publish ${1+"$projectFile"} \
-p:ContinuousIntegrationBuild=true \
-p:Deterministic=true \
- --output "${installPath-$out/lib/$pname}" \
- --configuration "@buildType@" \
+ --output "$dotnetInstallPath" \
+ --configuration "$dotnetBuildType" \
--no-build \
- ${runtimeIdFlags[@]} \
- ${dotnetInstallFlags[@]} \
- ${dotnetFlags[@]}
+ "${runtimeIdFlagsArray[@]}" \
+ "${dotnetInstallFlagsArray[@]}" \
+ "${dotnetFlagsArray[@]}"
}
dotnetPack() {
- local -r project="${1-}"
- dotnet pack ${project-} \
+ local -r projectFile="${1-}"
+ dotnet pack ${1+"$projectFile"} \
-p:ContinuousIntegrationBuild=true \
-p:Deterministic=true \
--output "$out/share" \
- --configuration "@buildType@" \
+ --configuration "$dotnetBuildType" \
--no-build \
- --runtime "@runtimeId@" \
- ${dotnetPackFlags[@]} \
- ${dotnetFlags[@]}
+ --runtime "$dotnetRuntimeId" \
+ "${dotnetPackFlagsArray[@]}" \
+ "${dotnetFlagsArray[@]}"
}
- if (( "${#projectFile[@]}" == 0 )); then
+ if (( ${#dotnetProjectFilesArray[@]} == 0 )); then
dotnetPublish
else
- for project in ${projectFile[@]}; do
- dotnetPublish "$project"
+ local projectFile
+ for projectFile in "${dotnetProjectFilesArray[@]}"; do
+ dotnetPublish "$projectFile"
done
fi
- if [[ "${packNupkg-}" ]]; then
- if (( "${#projectFile[@]}" == 0 )); then
+ if [[ -n ${packNupkg-} ]]; then
+ if (( ${#dotnetProjectFilesArray[@]} == 0 )); then
dotnetPack
else
- for project in ${projectFile[@]}; do
- dotnetPack "$project"
+ local projectFile
+ for projectFile in "${dotnetProjectFilesArray[@]}"; do
+ dotnetPack "$projectFile"
done
fi
fi
diff --git a/pkgs/test/dotnet/default.nix b/pkgs/test/dotnet/default.nix
index 7592b09d76e3c..d70850c05fdb0 100644
--- a/pkgs/test/dotnet/default.nix
+++ b/pkgs/test/dotnet/default.nix
@@ -1,5 +1,7 @@
-{ callPackage }:
+{ lib, callPackage }:
{
project-references = callPackage ./project-references { };
+ use-dotnet-from-env = lib.recurseIntoAttrs (callPackage ./use-dotnet-from-env { });
+ structured-attrs = lib.recurseIntoAttrs (callPackage ./structured-attrs { });
}
diff --git a/pkgs/test/dotnet/project-references/default.nix b/pkgs/test/dotnet/project-references/default.nix
index 0736cedc9096b..762686a7d01ff 100644
--- a/pkgs/test/dotnet/project-references/default.nix
+++ b/pkgs/test/dotnet/project-references/default.nix
@@ -4,11 +4,13 @@
{ lib
, dotnet-sdk
-, buildDotnetModule
+, buildPackages # buildDotnetModule
, runCommand
}:
let
+ inherit (buildPackages) buildDotnetModule;
+
nugetDeps = ./nuget-deps.nix;
# Specify the TargetFramework via an environment variable so that we don't
@@ -18,7 +20,8 @@ let
library = buildDotnetModule {
name = "project-references-test-library";
src = ./library;
- inherit nugetDeps TargetFramework;
+ inherit nugetDeps;
+ env.TargetFramework = TargetFramework;
packNupkg = true;
};
@@ -26,7 +29,8 @@ let
application = buildDotnetModule {
name = "project-references-test-application";
src = ./application;
- inherit nugetDeps TargetFramework;
+ inherit nugetDeps;
+ env.TargetFramework = TargetFramework;
projectReferences = [ library ];
};
diff --git a/pkgs/test/dotnet/structured-attrs/default.nix b/pkgs/test/dotnet/structured-attrs/default.nix
new file mode 100644
index 0000000000000..cf96fef8dbdcc
--- /dev/null
+++ b/pkgs/test/dotnet/structured-attrs/default.nix
@@ -0,0 +1,36 @@
+{ lib
+, dotnet-sdk
+, buildPackages # buildDotnetModule
+, testers
+, runCommand
+}:
+let
+ # Note: without structured attributes, we can’t use derivation arguments that
+ # contain spaces unambiguously because arguments are passed as space-separated
+ # environment variables.
+ copyrightString = "Public domain 🅮";
+
+ inherit (buildPackages) buildDotnetModule;
+
+ app = buildDotnetModule {
+ name = "structured-attrs-test-application";
+ src = ./src;
+ nugetDeps = ./nuget-deps.nix;
+ dotnetFlags = [ "--property:Copyright=${copyrightString}" ];
+ env.TargetFramework = "net${lib.versions.majorMinor (lib.getVersion dotnet-sdk)}";
+ __structuredAttrs = true;
+ };
+in
+{
+ no-structured-attrs = testers.testBuildFailure (app.overrideAttrs {
+ __structuredAttrs = false;
+ });
+
+ check-output = testers.testEqualContents {
+ assertion = "buildDotnetModule sets AssemblyCopyrightAttribute with structured attributes";
+ expected = builtins.toFile "expected-copyright.txt" copyrightString;
+ actual = runCommand "dotnet-structured-attrs-test" { } ''
+ ${app}/bin/Application >"$out"
+ '';
+ };
+}
diff --git a/pkgs/test/dotnet/structured-attrs/nuget-deps.nix b/pkgs/test/dotnet/structured-attrs/nuget-deps.nix
new file mode 100644
index 0000000000000..f3a17967e25c8
--- /dev/null
+++ b/pkgs/test/dotnet/structured-attrs/nuget-deps.nix
@@ -0,0 +1,5 @@
+# This file was automatically generated by passthru.fetch-deps.
+# Please dont edit it manually, your changes might get overwritten!
+
+{ fetchNuGet }: [
+]
diff --git a/pkgs/test/dotnet/structured-attrs/src/Application.cs b/pkgs/test/dotnet/structured-attrs/src/Application.cs
new file mode 100644
index 0000000000000..3bc548105c2b4
--- /dev/null
+++ b/pkgs/test/dotnet/structured-attrs/src/Application.cs
@@ -0,0 +1,10 @@
+using System;
+using System.Reflection;
+
+Console.Write(
+ (
+ (AssemblyCopyrightAttribute)Assembly
+ .GetExecutingAssembly()
+ .GetCustomAttributes(typeof(AssemblyCopyrightAttribute), true)[0]
+ ).Copyright
+);
diff --git a/pkgs/test/dotnet/structured-attrs/src/Application.csproj b/pkgs/test/dotnet/structured-attrs/src/Application.csproj
new file mode 100644
index 0000000000000..decaa6d961aab
--- /dev/null
+++ b/pkgs/test/dotnet/structured-attrs/src/Application.csproj
@@ -0,0 +1,5 @@
+
+
+ exe
+
+
diff --git a/pkgs/test/dotnet/use-dotnet-from-env/default.nix b/pkgs/test/dotnet/use-dotnet-from-env/default.nix
new file mode 100644
index 0000000000000..711a98eb0c29d
--- /dev/null
+++ b/pkgs/test/dotnet/use-dotnet-from-env/default.nix
@@ -0,0 +1,60 @@
+{ lib
+, dotnet-sdk
+, buildPackages # buildDotnetModule, dotnet-runtime
+, testers
+, runCommand
+, removeReferencesTo
+}:
+let
+ inherit (buildPackages) buildDotnetModule dotnet-runtime;
+
+ app = buildDotnetModule {
+ name = "use-dotnet-from-env-test-application";
+ src = ./src;
+ nugetDeps = ./nuget-deps.nix;
+ useDotnetFromEnv = true;
+ env.TargetFramework = "net${lib.versions.majorMinor (lib.getVersion dotnet-sdk)}";
+ };
+
+ appWithoutFallback = app.overrideAttrs (oldAttrs: {
+ nativeBuildInputs = (oldAttrs.nativeBuildInputs or [ ]) ++ [
+ removeReferencesTo
+ ];
+ postFixup = (oldAttrs.postFixup or "") + ''
+ remove-references-to -t ${dotnet-runtime} "$out/bin/Application"
+ '';
+ });
+
+ runtimeVersion = lib.getVersion dotnet-runtime;
+ runtimeVersionFile = builtins.toFile "dotnet-version.txt" runtimeVersion;
+in
+{
+ fallback = testers.testEqualContents {
+ assertion = "buildDotnetModule sets fallback DOTNET_ROOT in wrapper";
+ expected = runtimeVersionFile;
+ actual = runCommand "use-dotnet-from-env-fallback-test" { } ''
+ ${app}/bin/Application >"$out"
+ '';
+ };
+
+ # Check that appWithoutFallback does not use fallback .NET runtime.
+ without-fallback = testers.testBuildFailure (runCommand "use-dotnet-from-env-without-fallback-test" { } ''
+ ${appWithoutFallback}/bin/Application >"$out"
+ '');
+
+ # NB assumes that without-fallback above to passes.
+ 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; } ''
+ ${appWithoutFallback}/bin/Application >"$out"
+ '';
+ };
+ use-dotnet-path-env = testers.testEqualContents {
+ assertion = "buildDotnetModule uses DOTNET_ROOT from dotnet in PATH in wrapper";
+ expected = runtimeVersionFile;
+ actual = runCommand "use-dotnet-from-env-path-test" { dotnetRuntime = dotnet-runtime; } ''
+ PATH=$dotnetRuntime''${PATH+:}$PATH ${appWithoutFallback}/bin/Application >"$out"
+ '';
+ };
+}
diff --git a/pkgs/test/dotnet/use-dotnet-from-env/nuget-deps.nix b/pkgs/test/dotnet/use-dotnet-from-env/nuget-deps.nix
new file mode 100644
index 0000000000000..f3a17967e25c8
--- /dev/null
+++ b/pkgs/test/dotnet/use-dotnet-from-env/nuget-deps.nix
@@ -0,0 +1,5 @@
+# This file was automatically generated by passthru.fetch-deps.
+# Please dont edit it manually, your changes might get overwritten!
+
+{ fetchNuGet }: [
+]
diff --git a/pkgs/test/dotnet/use-dotnet-from-env/src/Application.cs b/pkgs/test/dotnet/use-dotnet-from-env/src/Application.cs
new file mode 100644
index 0000000000000..5efc571ca9a3e
--- /dev/null
+++ b/pkgs/test/dotnet/use-dotnet-from-env/src/Application.cs
@@ -0,0 +1,3 @@
+using System;
+
+Console.Write(Environment.Version.ToString());
diff --git a/pkgs/test/dotnet/use-dotnet-from-env/src/Application.csproj b/pkgs/test/dotnet/use-dotnet-from-env/src/Application.csproj
new file mode 100644
index 0000000000000..decaa6d961aab
--- /dev/null
+++ b/pkgs/test/dotnet/use-dotnet-from-env/src/Application.csproj
@@ -0,0 +1,5 @@
+
+
+ exe
+
+