Merge pull request #313005 from tie/dotnet-cross

buildDotnetModule: fix structured attributes support
This commit is contained in:
David McFarland 2024-06-17 09:43:51 -03:00 committed by GitHub
commit b5447275d2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 440 additions and 176 deletions

View File

@ -41,7 +41,7 @@ buildDotnetModule rec {
doCheck = true;
preBuild = ''
export projectFile=(ArchiSteamFarm)
dotnetProjectFiles=(ArchiSteamFarm)
'';
preInstall = ''

View File

@ -28,7 +28,7 @@ buildDotnetModule (args // {
] ++ (nugetDeps fetchNuGet);
};
projectFile = "";
dotnetGlobalTool = true;
useDotnetFromEnv = true;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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 [ "${enableParallelBuilding-}" ]; then
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 [[ -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

View File

@ -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 <Sdk /> dependencies, is restored from the proper source
cat <<EOF > "./NuGet.config"
cat >NuGet.config <<EOF
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nugetSource" value="@nugetSource@/lib" />
<add key="nugetSource" value="$nugetSourceXMLQuoted/lib" />
</packageSources>
</configuration>
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' {} \;
# 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"
dotnet tool restore --add-source "$nugetSource/lib"
(( "${#projectFile[@]}" == 0 )) && dotnetRestore
# 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. Its 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 dont 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

View File

@ -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@
if [ ! "${selfContainedBuild-}" ]; then
if [ "${useDotnetFromEnv-}" ]; then
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
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"

View File

@ -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
dotnetInstallFlags+=("--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")
local dotnetProjectFilesArray=($dotnetProjectFiles)
local dotnetFlagsArray=($dotnetFlags)
local dotnetInstallFlagsArray=($dotnetInstallFlags)
local dotnetPackFlagsArray=($dotnetPackFlags)
fi
if [ "${useAppHost-}" ]; then
dotnetInstallFlags+=("-p:UseAppHost=true")
if [[ -n ${dotnetSelfContainedBuild-} ]]; then
dotnetInstallFlagsArray+=("--self-contained")
else
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
dotnetInstallFlagsArray+=("-p:PublishTrimmed=false")
fi
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

View File

@ -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 { });
}

View File

@ -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 ];
};

View File

@ -0,0 +1,36 @@
{ lib
, dotnet-sdk
, buildPackages # buildDotnetModule
, testers
, runCommand
}:
let
# Note: without structured attributes, we cant 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"
'';
};
}

View File

@ -0,0 +1,5 @@
# This file was automatically generated by passthru.fetch-deps.
# Please dont edit it manually, your changes might get overwritten!
{ fetchNuGet }: [
]

View File

@ -0,0 +1,10 @@
using System;
using System.Reflection;
Console.Write(
(
(AssemblyCopyrightAttribute)Assembly
.GetExecutingAssembly()
.GetCustomAttributes(typeof(AssemblyCopyrightAttribute), true)[0]
).Copyright
);

View File

@ -0,0 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>exe</OutputType>
</PropertyGroup>
</Project>

View File

@ -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"
'';
};
}

View File

@ -0,0 +1,5 @@
# This file was automatically generated by passthru.fetch-deps.
# Please dont edit it manually, your changes might get overwritten!
{ fetchNuGet }: [
]

View File

@ -0,0 +1,3 @@
using System;
Console.Write(Environment.Version.ToString());

View File

@ -0,0 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>exe</OutputType>
</PropertyGroup>
</Project>