Răsfoiți Sursa

Create new 'runtime pack' nuget packages for Microsoft.AspNetCore.App (#7475)

* Create a new package  - Microsoft.AspNetCore.App.Runtime.${rid} - which contains crossgen-ed versions of shared framework assemblies. This will be used by the SDK to replace rid-split packages
* Add a task which can generate the .deps.json file for the shared framework. Unlike the existing task we have, this does not rely on consuming a .deps.json file generated by first running a restore on packages.
* Move the reference to xunit.runner.console into the normal targets and files for managing dependencies
* Produce binlogs during build
Nate McMaster 7 ani în urmă
părinte
comite
0ec25d3167

+ 10 - 10
.azure/pipelines/ci.yml

@@ -49,14 +49,14 @@ jobs:
     # if they have already been signed. This results in slower builds due to re-submitting the same .nupkg many times for signing.
     # The sign settings have been configured to
 
-    - script: ./eng/scripts/cibuild.cmd -arch x64 /p:DisableCodeSigning=true
+    - script: ./eng/scripts/cibuild.cmd -arch x64 /p:DisableCodeSigning=true /bl:artifacts/logs/build.x64.binlog
       displayName: Build x64
     # TODO: make it possible to build for one Windows architecture at a time
     # This is going to actually build x86 native assets. See https://github.com/aspnet/AspNetCore/issues/7196
 
     # Build the x86 shared framework
     # Set DisableSignCheck because we'll run sign check in an explicit step after installers build
-    - script: ./eng/scripts/cibuild.cmd -arch x86 /t:BuildSharedFx /p:DisableCodeSigning=true
+    - script: ./eng/scripts/cibuild.cmd -arch x86 /t:BuildSharedFx /p:DisableCodeSigning=true /bl:artifacts/logs/build.x86.binlog
       displayName: Build x86
 
     # This is in a separate build step with -forceCoreMsbuild to workaround MAX_PATH limitations - https://github.com/Microsoft/msbuild/issues/53
@@ -66,7 +66,7 @@ jobs:
     # This runs code-signing on all packages, zips, and jar files as defined in build/CodeSign.targets. If https://github.com/dotnet/arcade/issues/1957 is resolved,
     # consider running code-signing inline with the other previous steps.
     # Sign check is disabled because it is run in a separate step below, after installers are built.
-    - script: ./build.cmd -ci -sign /t:CodeSign /p:SignType=$(_SignType) /p:DisableSignCheck=true
+    - script: ./build.cmd -ci -sign /t:CodeSign /p:SignType=$(_SignType) /p:DisableSignCheck=true /bl:artifacts/logs/build.codesign.binlog
       displayName: Code sign packages
 
     # Windows installers bundle both x86 and x64 assets
@@ -74,7 +74,7 @@ jobs:
       displayName: Build Installers
 
     # Run sign check to verify everything was code signed.
-    - script: ./build.cmd -ci -sign /t:SignCheck /p:SignType=$(_SignType)
+    - script: ./build.cmd -ci -sign /t:SignCheck /p:SignType=$(_SignType) /bl:artifacts/logs/build.signcheck.binlog
       displayName: Run sign check
       condition: eq(variables['_SignType'], 'real')
 
@@ -109,7 +109,7 @@ jobs:
     afterBuild:
     # Remove packages that are not rid-specific.
     # TODO add a flag so builds only produce runtime packages
-    - powershell: gci artifacts/packages/ -recurse -exclude 'runtime.*' -file | rm -ea ignore
+    - powershell: gci artifacts/packages/ -recurse -exclude 'runtime.*', 'Microsoft.AspNetCore.App.Runtime.*' -file | rm -ea ignore
     artifacts:
     - name: Windows_arm_Packages
       path: artifacts/packages/
@@ -133,7 +133,7 @@ jobs:
     afterBuild:
     # Remove packages that are not rid-specific.
     # TODO add a flag so macOS/Linux builds only produce runtime packages
-    - script: if [ -d 'artifacts/packages' ]; then find artifacts/packages/ -type f -not -name 'runtime.*' -delete; fi
+    - script: if [ -d 'artifacts/packages' ]; then find artifacts/packages/ -type f -not -name 'runtime.*' -not -name 'Microsoft.AspNetCore.App.Runtime.*' -delete; fi
       condition: always()
     artifacts:
     - name: MacOS_x64_Packages
@@ -184,7 +184,7 @@ jobs:
     afterBuild:
     # Remove packages that are not rid-specific.
     # TODO add a flag so macOS/Linux builds only produce runtime packages
-    - script: if [ -d 'artifacts/packages' ]; then find artifacts/packages/ -type f -not -name 'runtime.*' -delete; fi
+    - script: if [ -d 'artifacts/packages' ]; then find artifacts/packages/ -type f -not -name 'runtime.*' -not -name 'Microsoft.AspNetCore.App.Runtime.*' -delete; fi
       condition: always()
     artifacts:
     - name: Linux_x64_Packages
@@ -212,7 +212,7 @@ jobs:
     afterBuild:
     # Remove packages that are not rid-specific.
     # TODO add a flag so macOS/Linux builds only produce runtime packages
-    - script: if [ -d 'artifacts/packages' ]; then find artifacts/packages/ -type f -not -name 'runtime.*' -delete; fi
+    - script: if [ -d 'artifacts/packages' ]; then find artifacts/packages/ -type f -not -name 'runtime.*' -not -name 'Microsoft.AspNetCore.App.Runtime.*' -delete; fi
       condition: always()
     artifacts:
     - name: Linux_arm_Packages
@@ -240,7 +240,7 @@ jobs:
     afterBuild:
     # Remove packages that are not rid-specific.
     # TODO add a flag so macOS/Linux builds only produce runtime packages
-    - script: if [ -d 'artifacts/packages' ]; then find artifacts/packages/ -type f -not -name 'runtime.*' -delete; fi
+    - script: if [ -d 'artifacts/packages' ]; then find artifacts/packages/ -type f -not -name 'runtime.*' -not -name 'Microsoft.AspNetCore.App.Runtime.*' -delete; fi
       condition: always()
     artifacts:
     - name: Linux_arm64_Packages
@@ -268,7 +268,7 @@ jobs:
     afterBuild:
     # Remove packages that are not rid-specific.
     # TODO add a flag so macOS/Linux builds only produce runtime packages
-    - script: if [ -d 'artifacts/packages' ]; then find artifacts/packages/ -type f -not -name 'runtime.*' -delete; fi
+    - script: if [ -d 'artifacts/packages' ]; then find artifacts/packages/ -type f -not -name 'runtime.*' -not -name 'Microsoft.AspNetCore.App.Runtime.*' -delete; fi
       condition: always()
     artifacts:
     - name: Linux_musl_x64_Packages

+ 0 - 5
Directory.Build.targets

@@ -75,11 +75,6 @@
   <Import Project="eng\targets\Wix.Common.targets"  Condition="'$(MSBuildProjectExtension)' == '.wixproj'" />
   <Import Project="eng\targets\Npm.Common.targets"  Condition="'$(MSBuildProjectExtension)' == '.npmproj'" />
 
-  <!-- Move to CSharp.Common.props -->
-  <ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework' AND '$(IsHelixJob)' == 'true' ">
-    <PackageReference Include="xunit.runner.console" Version="2.4.1" />
-  </ItemGroup>
-
   <!-- Prepares the test projects for helix by including xunit and publishing -->
   <Target Name="PrepareHelixPayload" Returns="@(HelixDirectory)">
     <ItemGroup>

+ 6 - 0
build.ps1

@@ -21,6 +21,9 @@ Suppress running restore on projects.
 .PARAMETER NoBuild
 Suppress re-compile projects. (Implies -NoRestore)
 
+.PARAMETER NoBuildDeps
+Do not build project-to-project references and only build the specified project.
+
 .PARAMETER Pack
 Produce packages.
 
@@ -88,6 +91,7 @@ param(
     [switch]$Restore,
     [switch]$NoRestore, # Suppress restore
     [switch]$NoBuild, # Suppress compiling
+    [switch]$NoBuildDeps, # Suppress project to project dependencies
     [switch]$Pack, # Produce packages
     [switch]$Test, # Run tests
     [switch]$Sign, # Code sign
@@ -269,6 +273,8 @@ if ($BuildNative) { $MSBuildArguments += "/p:BuildNative=true" }
 if ($BuildNodeJS) { $MSBuildArguments += "/p:BuildNodeJS=true" }
 if ($BuildJava) { $MSBuildArguments += "/p:BuildJava=true" }
 
+if ($NoBuildDeps) { $MSBuildArguments += "/p:BuildProjectReferences=false" }
+
 if ($NoBuildInstallers) { $MSBuildArguments += "/p:BuildInstallers=false" }
 if ($NoBuildManaged) { $MSBuildArguments += "/p:BuildManaged=false" }
 if ($NoBuildNative) { $MSBuildArguments += "/p:BuildNative=false" }

+ 9 - 0
build.sh

@@ -25,6 +25,7 @@ run_build=true
 run_pack=false
 run_tests=false
 build_all=false
+build_deps=true
 build_managed=''
 build_native=''
 build_nodejs=''
@@ -60,6 +61,7 @@ Options:
 
     --projects             A list of projects to build. (Must be an absolute path.)
                            Globbing patterns are supported, such as \"$(pwd)/**/*.csproj\".
+    --no-build-deps        Do not build project-to-project references and only build the specified project.
 
     --all                  Build all project types.
     --[no-]build-native    Build native projects (C, C++).
@@ -190,6 +192,9 @@ while [[ $# -gt 0 ]]; do
             # --no-build implies --no-restore
             run_restore=false
             ;;
+        --no-build-deps)
+            build_deps=false
+            ;;
         --pack|-[Pp]ack)
             run_pack=true
             ;;
@@ -298,6 +303,10 @@ elif [ -z "$build_managed" ] && [ -z "$build_nodejs" ] && [ -z "$build_java" ] &
     build_managed=true
 fi
 
+if [ "$build_deps" = false ]; then
+    msbuild_args[${#msbuild_args[*]}]="-p:BuildProjectReferences=false"
+fi
+
 # Only set these MSBuild properties if they were explicitly set by build parameters.
 [ ! -z "$build_java" ] && msbuild_args[${#msbuild_args[*]}]="-p:BuildJava=$build_java"
 [ ! -z "$build_native" ] && msbuild_args[${#msbuild_args[*]}]="-p:BuildNative=$build_native"

+ 1 - 0
build/repo.props

@@ -141,6 +141,7 @@
         -->
         <DotNetProjects Include="
                           $(RepositoryRoot)src\Framework\ref\Microsoft.AspNetCore.App.Ref.csproj;
+                          $(RepositoryRoot)src\Framework\src\Microsoft.AspNetCore.App.Runtime.csproj;
                           $(RepositoryRoot)src\DefaultBuilder\**\*.*proj;
                           $(RepositoryRoot)src\Features\JsonPatch\**\*.*proj;
                           $(RepositoryRoot)src\DataProtection\**\*.*proj;

+ 47 - 0
build/tasks/FileUtilities.cs

@@ -0,0 +1,47 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+
+namespace Microsoft.DotNet.Build.Tasks
+{
+    internal static class FileUtilities
+    {
+        public static Version GetFileVersion(string sourcePath)
+        {
+            var fvi = FileVersionInfo.GetVersionInfo(sourcePath);
+
+            return fvi != null
+                ? new Version(fvi.FileMajorPart, fvi.FileMinorPart, fvi.FileBuildPart, fvi.FilePrivatePart)
+                : null;
+        }
+
+        private static readonly HashSet<string> _assemblyExtensions = new HashSet<string>(new[] { ".dll", ".exe", ".winmd" }, StringComparer.OrdinalIgnoreCase);
+
+        public static Version TryGetAssemblyVersion(string sourcePath)
+        {
+            var extension = Path.GetExtension(sourcePath);
+
+            return _assemblyExtensions.Contains(extension)
+                ? GetAssemblyVersion(sourcePath)
+                : null;
+        }
+
+        private static Version GetAssemblyVersion(string sourcePath)
+        {
+            try
+            {
+                return AssemblyName.GetAssemblyName(sourcePath)?.Version;
+            }
+            catch (BadImageFormatException)
+            {
+                // If an .dll file cannot be read, it may be a native .dll which would not have an assembly version.
+                return null;
+            }
+        }
+    }
+}

+ 113 - 0
build/tasks/GenerateSharedFrameworkDepsFile.cs

@@ -0,0 +1,113 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+using Microsoft.DotNet.Build.Tasks;
+using Microsoft.Extensions.DependencyModel;
+using RepoTasks.Utilities;
+
+namespace RepoTasks
+{
+    public class GenerateSharedFrameworkDepsFile : Task
+    {
+        [Required]
+        public string DepsFilePath { get; set; }
+
+        [Required]
+        public string TargetFramework { get; set; }
+
+        [Required]
+        public string FrameworkName { get; set; }
+
+        [Required]
+        public string FrameworkVersion { get; set; }
+
+        [Required]
+        public ITaskItem[] References { get; set; }
+
+        [Required]
+        public string RuntimeIdentifier { get; set; }
+
+        [Required]
+        public string RuntimePackageName { get; set; }
+
+        public override bool Execute()
+        {
+            ExecuteCore();
+
+            return !Log.HasLoggedErrors;
+        }
+
+        private void ExecuteCore()
+        {
+            var target = new TargetInfo(TargetFramework, RuntimeIdentifier, string.Empty, isPortable: false);
+            var runtimeFiles = new List<RuntimeFile>();
+            var nativeFiles = new List<RuntimeFile>();
+            var resourceAssemblies = new List<ResourceAssembly>();
+
+            foreach (var reference in References)
+            {
+                var filePath = reference.ItemSpec;
+                var fileName = Path.GetFileName(filePath);
+                var fileVersion = FileUtilities.GetFileVersion(filePath)?.ToString() ?? string.Empty;
+                var assemblyVersion = FileUtilities.TryGetAssemblyVersion(filePath);
+                if (assemblyVersion == null)
+                {
+                    var nativeFile = new RuntimeFile(fileName, null, fileVersion);
+                    nativeFiles.Add(nativeFile);
+                }
+                else
+                {
+                    var runtimeFile = new RuntimeFile(fileName,
+                        fileVersion: fileVersion,
+                        assemblyVersion: assemblyVersion.ToString());
+                    runtimeFiles.Add(runtimeFile);
+                }
+            }
+
+            var runtimeLibrary = new RuntimeLibrary("package",
+               RuntimePackageName,
+               FrameworkVersion,
+               hash: string.Empty,
+               runtimeAssemblyGroups: new[] { new RuntimeAssetGroup(string.Empty, runtimeFiles) },
+               nativeLibraryGroups: new[] { new RuntimeAssetGroup(string.Empty, nativeFiles) },
+               Enumerable.Empty<ResourceAssembly>(),
+               Array.Empty<Dependency>(),
+               hashPath: null,
+               path: $"{RuntimePackageName.ToLowerInvariant()}/{FrameworkVersion}",
+               serviceable: true);
+
+            var context = new DependencyContext(target,
+                CompilationOptions.Default,
+                Enumerable.Empty<CompilationLibrary>(),
+                new[] { runtimeLibrary },
+                Enumerable.Empty<RuntimeFallbacks>());
+
+            Directory.CreateDirectory(Path.GetDirectoryName(DepsFilePath));
+
+            try
+            {
+                using (var depsStream = File.Create(DepsFilePath))
+                {
+                    new DependencyContextWriter().Write(context, depsStream);
+                }
+            }
+            catch (Exception ex)
+            {
+                // If there is a problem, ensure we don't write a partially complete version to disk.
+                if (File.Exists(DepsFilePath))
+                {
+                    File.Delete(DepsFilePath);
+                }
+                Log.LogErrorFromException(ex);
+            }
+        }
+    }
+}

+ 2 - 0
build/tasks/RepoTasks.csproj

@@ -5,6 +5,8 @@
     <TargetFramework Condition="'$(MSBuildRuntimeType)' == 'Core' ">netcoreapp2.2</TargetFramework>
     <TargetFramework Condition="'$(MSBuildRuntimeType)' != 'Core' ">net461</TargetFramework>
     <DefineConstants Condition="'$(BuildInstallers)' == 'true' AND '$(TargetOsName)' == 'win'">$(DefineConstants);BUILD_MSI_TASKS</DefineConstants>
+    <Optimize>false</Optimize>
+    <DebugType>embedded</DebugType>
     <DisablePackageReferenceRestrictions>true</DisablePackageReferenceRestrictions>
   </PropertyGroup>
 

+ 1 - 0
build/tasks/RepoTasks.tasks

@@ -6,6 +6,7 @@
   <UsingTask TaskName="RepoTasks.GenerateRestoreSourcesPropsFile" AssemblyFile="$(_RepoTaskAssembly)" />
   <UsingTask TaskName="RepoTasks.GenerateGuid" AssemblyFile="$(_RepoTaskAssembly)" />
   <UsingTask TaskName="RepoTasks.GetMsiProperty" AssemblyFile="$(_RepoTaskAssembly)" />
+  <UsingTask TaskName="RepoTasks.GenerateSharedFrameworkDepsFile" AssemblyFile="$(_RepoTaskAssembly)" />
   <UsingTask TaskName="RepoTasks.GenerateSharedFrameworkMetadataFiles" AssemblyFile="$(_RepoTaskAssembly)" />
   <UsingTask TaskName="RepoTasks.RemoveSharedFrameworkDependencies" AssemblyFile="$(_RepoTaskAssembly)" />
 </Project>

+ 3 - 3
docs/SharedFramework.md

@@ -24,7 +24,7 @@ The ASP.NET Core shared framework contains assemblies that are fully developed,
 
 The contents of the shared framework are defined in two ways:
 
-* [src/Framework/LocalDependencies.props](/src/Framework/LocalDependencies.props) - this file is generated from the .csproj files in this repo
+* [eng/SharedFramework.Local.props](/eng/SharedFramework.Local.props) - this file is generated from the .csproj files in this repo
   by looking for projects which have set `<IsAspNetCoreApp>true</IsAspNetCoreApp>`.
-* [src/Framework/Microsoft.AspNetCore.App.props](/src/Framework/Microsoft.AspNetCore.App.props) - this file lists all assemblies shipped
-  in Microsoft.AspNetCore.App which are built by source code found in other repositories.
+* [eng/SharedFramework.External.props](/eng/SharedFramework.External.props) - this file lists all assemblies shipped
+  in Microsoft.AspNetCore.App which are built by source code found in other repositories.

+ 1 - 0
eng/Dependencies.props

@@ -160,6 +160,7 @@ and are generated based on the last package release.
     <LatestPackageReference Include="xunit.assert" Version="$(XunitAssertPackageVersion)" />
     <LatestPackageReference Include="xunit.extensibility.core" Version="$(XunitExtensibilityCorePackageVersion)" />
     <LatestPackageReference Include="xunit.extensibility.execution" Version="$(XunitExtensibilityExecutionPackageVersion)" />
+    <LatestPackageReference Include="xunit.runner.console" Version="$(XunitRunnerConsolePackageVersion)" />
     <LatestPackageReference Include="xunit.runner.visualstudio" Version="$(XunitRunnerVisualStudioPackageVersion)" />
     <LatestPackageReference Include="xunit" Version="$(XunitPackageVersion)" />
   </ItemGroup>

+ 1 - 0
eng/Versions.props

@@ -194,5 +194,6 @@
     <XunitExtensibilityExecutionPackageVersion>2.3.1</XunitExtensibilityExecutionPackageVersion>
     <XunitPackageVersion>2.4.0</XunitPackageVersion>
     <XunitRunnerVisualStudioPackageVersion>2.4.0</XunitRunnerVisualStudioPackageVersion>
+    <XunitRunnerConsolePackageVersion>2.4.1</XunitRunnerConsolePackageVersion>
   </PropertyGroup>
 </Project>

+ 2 - 1
eng/targets/CSharp.Common.props

@@ -28,13 +28,14 @@
     <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="$(MicrosoftNETFrameworkReferenceAssembliesPackageVersion)" PrivateAssets="All" AllowExplicitReference="true" />
   </ItemGroup>
 
-  <ItemGroup Condition=" '$(AddImplicitReferences)' != 'false' AND '$(IsTestProject)' == 'true' ">
+  <ItemGroup Condition=" '$(IsTestProject)' == 'true' ">
     <Reference Include="Microsoft.AspNetCore.Testing" />
     <Reference Include="Microsoft.NET.Test.Sdk" />
     <Reference Include="Moq" />
     <Reference Include="xunit" />
     <Reference Include="xunit.analyzers" />
     <Reference Include="xunit.runner.visualstudio" />
+    <Reference Include="xunit.runner.console" Condition=" '$(TargetFrameworkIdentifier)' == '.NETFramework' AND '$(IsHelixJob)' == 'true' " />
   </ItemGroup>
 
 </Project>

+ 296 - 0
src/Framework/src/Microsoft.AspNetCore.App.Runtime.csproj

@@ -0,0 +1,296 @@
+<Project>
+  <PropertyGroup>
+    <OutputInRepoRoot>true</OutputInRepoRoot>
+  </PropertyGroup>
+
+  <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
+
+  <PropertyGroup>
+    <TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
+    <RuntimeIdentifier>$(TargetRuntimeIdentifier)</RuntimeIdentifier>
+    <!-- Even though RuntimeIdentifier is set, shared framework projects are not self-contained projects -->
+    <SelfContained>false</SelfContained>
+    <SharedFxName>Microsoft.AspNetCore.App</SharedFxName>
+    <PackageId>$(MSBuildProjectName).$(RuntimeIdentifier)</PackageId>
+    <IsShippingPackage>true</IsShippingPackage>
+
+    <PackageDescription>Provides a default set of APIs for building an ASP.NET Core application. Contains assets used for self-contained deployments.
+
+This package is an internal implementation of the .NET Core SDK and is not meant to be used as a normal PackageReference.
+    </PackageDescription>
+    <PackageTags>aspnetcore;shared-framework</PackageTags>
+    <SuppressDependenciesWhenPacking>true</SuppressDependenciesWhenPacking>
+
+    <!-- Subject to change: see https://github.com/dotnet/designs/pull/50 -->
+    <PackageType>RuntimePack</PackageType>
+    <!-- NuGet appends target framework to this value. Example: runtimes/win-x64/lib/netcoreapp3.0/ -->
+    <BuildOutputTargetFolder>runtimes/$(RuntimeIdentifier)/lib/</BuildOutputTargetFolder>
+    <!-- Target framework is not append to this because native assets to not have a target framework. -->
+    <NativeAssetsPackagePath>runtimes/$(RuntimeIdentifier)/native/</NativeAssetsPackagePath>
+
+    <!-- Setting this suppresses getting documentation .xml files in the shared runtime output. -->
+    <AllowedReferenceRelatedFileExtensions>.pdb</AllowedReferenceRelatedFileExtensions>
+
+    <!-- Pack .map files in symbols package (native symbols for Linux) -->
+    <AllowedOutputExtensionsInSymbolsPackageBuildOutputFolder>$(AllowedOutputExtensionsInSymbolsPackageBuildOutputFolder);.map</AllowedOutputExtensionsInSymbolsPackageBuildOutputFolder>
+
+    <!-- Optimize the framework using the crossgen tool -->
+    <CrossgenOutput Condition="'$(Configuration)' != 'Debug'">true</CrossgenOutput>
+
+    <!-- Produce crossgen profiling symbols (.ni.pdb or .map files). -->
+    <GenerateCrossgenProfilingSymbols>true</GenerateCrossgenProfilingSymbols>
+    <GenerateCrossgenProfilingSymbols Condition=" '$(CrossgenOutput)' == 'false' OR '$(TargetOsName)' == 'osx'">false</GenerateCrossgenProfilingSymbols>
+
+    <!-- Always generated, even though output type == Library -->
+    <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
+    <ProjectRuntimeConfigFileName>$(SharedFxName).runtimeconfig.json</ProjectRuntimeConfigFileName>
+
+    <!-- Suppress .deps generation (we have to customize its layout. -->
+    <GenerateDependencyFile>false</GenerateDependencyFile>
+    <ProjectDepsFileName>$(SharedFxName).deps.json</ProjectDepsFileName>
+
+    <!-- There is no way to suppress the .dev.runtimeconfig.json generation. -->
+    <ProjectRuntimeConfigDevFilePath>$(IntermediateOutputPath)ignoreme.dev.runtimeconfig.json</ProjectRuntimeConfigDevFilePath>
+
+    <!-- The project representing the shared framework doesn't produce a .NET assembly or symbols. -->
+    <DebugType>none</DebugType>
+    <CopyBuildOutputToPublishDirectory>false</CopyBuildOutputToPublishDirectory>
+    <CopyBuildOutputToOutputDirectory>false</CopyBuildOutputToOutputDirectory>
+    <CopyOutputSymbolsToOutputDirectory>false</CopyOutputSymbolsToOutputDirectory>
+
+    <!-- Copy assets to output path from NuGet packages. -->
+    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
+
+    <!-- Workaround for the way Microsoft.AspNetCore.Server.IIS.csproj references ANCM native deps. Do not copy content from ProjectReference's CopyToOutput items.  -->
+    <_GetChildProjectCopyToOutputDirectoryItems>false</_GetChildProjectCopyToOutputDirectoryItems>
+
+    <!-- This project should not be referenced via the `<Reference>` impementation. -->
+    <IsProjectReferenceProvider>false</IsProjectReferenceProvider>
+
+    <!-- Properties related to crossgen -->
+    <CrossGenSymbolsType>PerfMap</CrossGenSymbolsType>
+    <CrossGenSymbolsType Condition="'$(TargetOsName)' == 'win'">PDB</CrossGenSymbolsType>
+
+    <LibPrefix Condition=" '$(TargetOsName)' != 'win' ">lib</LibPrefix>
+    <LibExtension>.so</LibExtension>
+    <LibExtension Condition=" '$(TargetOsName)' == 'win' ">.dll</LibExtension>
+    <LibExtension Condition=" '$(TargetOsName)' == 'osx' ">.dylib</LibExtension>
+    <ExeExtension Condition=" '$(TargetOsName)' == 'win' ">.exe</ExeExtension>
+    <!-- 3B = semicolon in ASCII -->
+    <PathSeparator Condition="'$(PathSeparator)' == ''">:</PathSeparator>
+    <PathSeparator Condition=" '$(TargetOsName)' == 'win' ">%3B</PathSeparator>
+
+    <!-- Crossgen executable name -->
+    <CrossgenToolFileName>crossgen</CrossgenToolFileName>
+    <CrossgenToolFileName Condition=" '$(TargetOsName)' == 'win' ">$(CrossgenToolFileName).exe</CrossgenToolFileName>
+    <!-- Default crossgen executable relative path -->
+    <CrossgenToolPackagePath>$(CrossgenToolFileName)</CrossgenToolPackagePath>
+    <!-- Disambiguated RID-specific crossgen executable relative path -->
+    <CrossgenToolPackagePath Condition=" '$(TargetRuntimeIdentifier)' == 'linux-arm' ">x64_arm\$(CrossgenToolPackagePath)</CrossgenToolPackagePath>
+    <CrossgenToolPackagePath Condition=" '$(TargetRuntimeIdentifier)' == 'linux-arm64' ">x64_arm64\$(CrossgenToolPackagePath)</CrossgenToolPackagePath>
+    <CrossgenToolPackagePath Condition=" '$(TargetRuntimeIdentifier)' == 'win-arm' ">x86_arm\$(CrossgenToolPackagePath)</CrossgenToolPackagePath>
+
+    <RuntimePackageRoot>$(NuGetPackageRoot)/runtime.$(RuntimeIdentifier).microsoft.netcore.app/$(MicrosoftNETCoreAppPackageVersion)/</RuntimePackageRoot>
+    <CrossgenToolPath>$(RuntimePackageRoot)tools/$(CrossgenToolPackagePath)</CrossgenToolPath>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <!-- Note: do not add _TransitiveExternalAspNetCoreAppReference to this list. This is intentionally not listed as a direct package reference. -->
+    <Reference Include="@(AspNetCoreAppReference);@(AspNetCoreAppReferenceAndPackage);@(ExternalAspNetCoreAppReference)">
+      <IncludeAssets>Runtime;Native</IncludeAssets>
+    </Reference>
+
+    <ProjectReference Condition="'$(BuildIisNativeProjects)' == 'true' AND '$(BuildNative)' != 'false'" Include="$(RepositoryRoot)src\Servers\IIS\AspNetCoreModuleV2\InProcessRequestHandler\InProcessRequestHandler.vcxproj">
+      <SetPlatform>Platform=$(TargetArchitecture)</SetPlatform>
+      <SetPlatform Condition="'$(TargetArchitecture)' == 'x86'">Platform=Win32</SetPlatform>
+      <!-- Suppress NuGet compatibility checks. We compensate for flowing .dll/.pdb files with the _ResolveCopyLocalNativeReference target. -->
+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+      <!-- Optimization. Native projects don't have a .NET TargetFramework -->
+      <SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties>
+      <UndefineProperties>TargetFramework</UndefineProperties>
+      <OutputItemType>_ResolvedNativeProjectReferencePaths</OutputItemType>
+    </ProjectReference>
+  </ItemGroup>
+
+  <ItemGroup>
+    <GenerateRuntimeConfigurationFilesInputs Include="$(MSBuildAllProjects)" />
+  </ItemGroup>
+
+  <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
+
+  <!-- Target chain -->
+  <PropertyGroup>
+    <ResolveReferencesDependsOn>
+      $(ResolveReferencesDependsOn);
+      FilterUnwantedContent;
+      _ResolveCopyLocalNativeReference;
+      PrepareForCrossGen;
+    </ResolveReferencesDependsOn>
+    <CoreBuildDependsOn>
+      $(CoreBuildDependsOn);
+      GenerateSharedFxDepsFile;
+      Crossgen;
+    </CoreBuildDependsOn>
+    <CrossGenDependsOn>
+      ResolveReferences;
+    </CrossGenDependsOn>
+    <CrossGenDependsOn Condition=" '$(CrossgenOutput)' == 'true' ">
+      $(CrossGenDependsOn);
+      _BatchCrossGenAssemblies;
+    </CrossGenDependsOn>
+    <TargetsForTfmSpecificBuildOutput>
+      $(TargetsForTfmSpecificBuildOutput);
+      _ResolveRuntimePackBuildOutput
+    </TargetsForTfmSpecificBuildOutput>
+  </PropertyGroup>
+
+  <!-- Override the default MSBuild targets so that nothing is returned from the project since it represents a collection of assemblies. -->
+  <Target Name="GetTargetPath" />
+  <Target Name="Build" DependsOnTargets="$(BuildDependsOn)">
+    <Message Importance="High" Text="$(MSBuildProjectName) -> $(TargetDir)" />
+  </Target>
+
+  <!-- There is no Microsoft.AspNetCore.App.Runtime.dll file. This clears the default vaule for the build output group. -->
+  <ItemGroup>
+    <BuiltProjectOutputGroupKeyOutput Remove="@(BuiltProjectOutputGroupKeyOutput)" />
+  </ItemGroup>
+
+  <!-- Override target from internal.aspnetcore.sdk which asserts DebugType == portable if IncludeSymbols = true, which is not right for this project. -->
+  <Target Name="_EnsureDebugTypeIsPortable" />
+
+  <!-- This project doesn't compile anything. -->
+  <Target Name="CoreCompile" />
+
+  <Target Name="FilterUnwantedContent">
+    <ItemGroup>
+      <!-- These files end up in this item group as a result of setting CopyLocalLockFileAssemblies, but shouldn't be. -->
+      <ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)" Condition="'%(FileName)' == 'apphost' OR '%(FileName)' == '$(LibPrefix)hostfxr' OR '%(FileName)' == '$(LibPrefix)hostpolicy' "/>
+    </ItemGroup>
+  </Target>
+
+  <Target Name="_WarnAboutUnbuiltNativeDependencies"
+          BeforeTargets="Build"
+          Condition=" '$(BuildIisNativeProjects)' == 'true' AND '$(BuildNative)' == 'false' ">
+    <Warning Text="This project has native dependencies which were not built. Without this, tests may not function correctly. Run `build.cmd -BuildNative -BuildManaged` to build both C# and C++." />
+  </Target>
+
+  <Target Name="_ResolveCopyLocalNativeReference">
+    <ItemGroup>
+      <ReferenceCopyLocalPaths Include="@(_ResolvedNativeProjectReferencePaths)" IsNativeImage="true" />
+      <ReferenceCopyLocalPaths Include="@(_ResolvedNativeProjectReferencePaths->'%(RootDir)%(Directory)%(FileName).pdb')" IsNativeImage="true" />
+    </ItemGroup>
+  </Target>
+
+  <Target Name="GenerateSharedFxDepsFile"
+          DependsOnTargets="ResolveReferences;CrossGen"
+          Inputs="@(ReferenceCopyLocalPaths);$(_RepoTaskAssembly);$(ProjectAssetsFile);$(MSBuildAllProjects)"
+          Outputs="$(ProjectDepsFilePath)">
+
+    <ItemGroup>
+      <_RuntimeReference Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.Extension)' != '.pdb' AND '%(ReferenceCopyLocalPaths.Extension)' != '.map'" />
+    </ItemGroup>
+
+    <RepoTasks.GenerateSharedFrameworkDepsFile
+      DepsFilePath="$(ProjectDepsFilePath)"
+      TargetFramework="$(TargetFrameworkMoniker)"
+      FrameworkName="$(SharedFxName)"
+      FrameworkVersion="$(SharedFxVersion)"
+      References="@(_RuntimeReference)"
+      RuntimeIdentifier="$(RuntimeIdentifier)"
+      RuntimePackageName="$(PackageId)" />
+  </Target>
+
+  <!-- This target resolves files into the BuiltProjectOutputGroupOutput which NuGet uses to generate the package files. -->
+  <Target Name="_ResolveRuntimePackBuildOutput"
+          DependsOnTargets="ResolveReferences;Crossgen">
+    <ItemGroup>
+      <BuiltProjectOutputGroupOutput Include="$(ProjectDepsFilePath)" />
+      <BuiltProjectOutputGroupOutput Include="@(ReferenceCopyLocalPaths)" Condition=" '%(ReferenceCopyLocalPaths.IsNativeImage)' != 'true' " />
+      <!-- Include all .pdbs in build output. Some .pdb files are part of ReferenceCopyLocalPaths, but this can change when running /t:Pack /p:NoBuild=true. -->
+      <BuiltProjectOutputGroupOutput Include="$(TargetDir)*.pdb" Exclude="@(ReferenceCopyLocalPaths)" />
+      <!-- Crossgen symbols for Linux include a GUID in the file name which cannot be predicted. -->
+      <BuiltProjectOutputGroupOutput Include="$(TargetDir)*.map" Condition="'$(CrossGenSymbolsType)' == 'PerfMap'" />
+
+      <NuGetPackInput Include="@(BuiltProjectOutputGroupOutput)" />
+    </ItemGroup>
+  </Target>
+
+  <Target Name="_ResolveNativePackContent"
+          BeforeTargets="_GetPackageFiles;GenerateNuspec"
+          DependsOnTargets="ResolveReferences">
+    <ItemGroup>
+      <!-- Native files are included in _PackageFile instead because they belong in a separate package folder.r -->
+      <Content Include="@(ReferenceCopyLocalPaths)" PackagePath="$(NativeAssetsPackagePath)" Condition=" '%(ReferenceCopyLocalPaths.IsNativeImage)' == 'true' AND '%(ReferenceCopyLocalPaths.Extension)' != '.pdb' " />
+    </ItemGroup>
+  </Target>
+
+  <!--
+  ##############################################
+  Targets related to crossgen
+  ##############################################
+  -->
+  <PropertyGroup>
+    <CrossgenToolDir>$(IntermediateOutputPath)crossgen\</CrossgenToolDir>
+    <CoreCLRJitPath>$(CrossgenToolDir)$(LibPrefix)clrjit$(LibExtension)</CoreCLRJitPath>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <CreateDirectory Include="$(CrossgenToolDir)" />
+  </ItemGroup>
+
+  <Target Name="Crossgen" DependsOnTargets="$(CrossgenDependsOn)" />
+
+  <Target Name="PrepareForCrossGen" Condition="'$(CrossgenOutput)' == 'true'">
+    <!-- Resolve list of assemblies to crossgen -->
+    <ItemGroup>
+      <IntermediateCrossgenAssembly Include="@(ReferenceCopyLocalPaths)" Condition=" '%(ReferenceCopyLocalPaths.IsNativeImage)' != 'true' AND '%(ReferenceCopyLocalPaths.Extension)' != '.pdb'" />
+
+      <!-- These are the paths used by crossgen to find assemblies that are expected to exist at runtime in the shared frameworks. -->
+      <_PlatformAssemblyPaths Include="$(CrossgenToolDir)" />
+      <_PlatformAssemblyPaths Include="@(ReferenceCopyLocalPaths->'%(RootDir)%(Directory)')" />
+
+      <ReferenceCopyLocalPaths Remove="@(IntermediateCrossgenAssembly)" />
+      <ReferenceCopyLocalPaths Include="@(IntermediateCrossgenAssembly->'$(TargetDir)%(FileName)%(Extension)')" />
+    </ItemGroup>
+
+    <PropertyGroup>
+      <CrossgenSymbolsTargetDir>$(TargetDir)</CrossgenSymbolsTargetDir>
+      <CrossgenPlatformAssemblyPaths>@(_PlatformAssemblyPaths->Distinct(), '$(PathSeparator)')</CrossgenPlatformAssemblyPaths>
+      <!-- Escaping required due to the way batch processes backslashes. -->
+      <CrossgenSymbolsTargetDir Condition="HasTrailingSlash($(CrossgenSymbolsTargetDir)) AND '$(OS)' == 'Windows_NT'">$(TargetDir)\</CrossgenSymbolsTargetDir>
+      <CrossgenPlatformAssemblyPaths Condition="HasTrailingSlash($(CrossgenPlatformAssemblyPaths)) AND '$(OS)' == 'Windows_NT'">$(CrossgenPlatformAssemblyPaths)\</CrossgenPlatformAssemblyPaths>
+    </PropertyGroup>
+
+    <WriteLinesToFile
+        Lines="-platform_assemblies_paths &quot;$(CrossgenPlatformAssemblyPaths)&quot;"
+        File="$(CrossgenToolDir)PlatformAssembliesPaths.rsp"
+        Overwrite="true" />
+
+    <ItemGroup>
+      <RuntimePackageFiles Include="$(RuntimePackageRoot)runtimes\**\*" />
+    </ItemGroup>
+
+    <Error Text="Could not find crossgen $(CrossgenToolPath)" Condition=" ! Exists($(CrossgenToolPath))" />
+
+    <!-- Create tool directory with crossgen executable and runtime assemblies -->
+    <Copy SourceFiles="@(RuntimePackageFiles);$(CrossgenToolPath)" DestinationFolder="$(CrossGenToolDir)"/>
+    <Exec Command="chmod +x &quot;$(CrossGenToolDir)$(CrossgenToolFileName)&quot;" Condition="'$(OS)' != 'Windows_NT'" />
+  </Target>
+
+  <Target Name="_BatchCrossGenAssemblies"
+    Inputs="@(IntermediateCrossgenAssembly)"
+    Outputs="@(IntermediateCrossgenAssembly->'$(TargetDir)%(FileName)%(Extension)')">
+
+    <Exec Command="&quot;$(CrossgenToolDir)$(CrossgenToolFileName)&quot; -nologo -readytorun -in &quot;%(IntermediateCrossgenAssembly.Identity)&quot; -out &quot;$(TargetDir)%(FileName)%(Extension)&quot; -jitpath &quot;$(CoreCLRJitPath)&quot; &quot;@$(CrossgenToolDir)PlatformAssembliesPaths.rsp&quot;"
+          EnvironmentVariables="COMPlus_PartialNGen=0"
+          IgnoreStandardErrorWarningFormat="true"
+          StandardOutputImportance="High" />
+
+    <Exec Condition=" '$(GenerateCrossgenProfilingSymbols)' == 'true' "
+          Command="&quot;$(CrossgenToolDir)$(CrossgenToolFileName)&quot; -nologo -readytorun -in &quot;$(TargetDir)%(IntermediateCrossgenAssembly.FileName)%(Extension)&quot; -Create$(CrossGenSymbolsType) &quot;$(CrossgenSymbolsTargetDir)&quot; &quot;@$(CrossgenToolDir)PlatformAssembliesPaths.rsp&quot;"
+          EnvironmentVariables="COMPlus_PartialNGen=0"
+          IgnoreStandardErrorWarningFormat="true"
+          StandardOutputImportance="High" />
+  </Target>
+
+</Project>