Handle satellite assemblies in the Blazor build targets
* Pass the same closure of assemblies that is used by the SDK's linker to Blazor's linker and ResolveBlazorRuntimeDependencies task * Quote the mono linker path Fixes https://github.com/dotnet/aspnetcore/issues/17644 Fixes https://github.com/dotnet/aspnetcore/issues/17754
This commit is contained in:
parent
2e2d0625e1
commit
3fb171e282
|
|
@ -66,7 +66,12 @@ namespace Microsoft.AspNetCore.Blazor.Build.Tasks
|
|||
|
||||
protected override string GenerateFullPathToTool() => DotNetPath;
|
||||
|
||||
protected override string GenerateCommandLineCommands() => ILLinkPath;
|
||||
protected override string GenerateCommandLineCommands()
|
||||
{
|
||||
var args = new StringBuilder();
|
||||
args.Append(Quote(ILLinkPath));
|
||||
return args.ToString();
|
||||
}
|
||||
|
||||
private static string Quote(string path)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// 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.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
|
@ -27,12 +28,23 @@ namespace Microsoft.AspNetCore.Blazor.Build
|
|||
public override bool Execute()
|
||||
{
|
||||
var entryAssemblyName = AssemblyName.GetAssemblyName(AssemblyPath).Name;
|
||||
var assemblies = References.Select(c => Path.GetFileName(c.ItemSpec)).ToArray();
|
||||
var assemblies = References.Select(GetUriPath).OrderBy(c => c, StringComparer.Ordinal).ToArray();
|
||||
|
||||
using var fileStream = File.Create(OutputPath);
|
||||
WriteBootJson(fileStream, entryAssemblyName, assemblies, LinkerEnabled);
|
||||
|
||||
return true;
|
||||
|
||||
static string GetUriPath(ITaskItem item)
|
||||
{
|
||||
var outputPath = item.GetMetadata("RelativeOutputPath");
|
||||
if (string.IsNullOrEmpty(outputPath))
|
||||
{
|
||||
outputPath = Path.GetFileName(item.ItemSpec);
|
||||
}
|
||||
|
||||
return outputPath.Replace('\\', '/');
|
||||
}
|
||||
}
|
||||
|
||||
internal static void WriteBootJson(Stream stream, string entryAssemblyName, string[] assemblies, bool linkerEnabled)
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@
|
|||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="_ResolveBlazorInputs">
|
||||
<Target Name="_ResolveBlazorInputs" DependsOnTargets="ResolveReferences;ResolveRuntimePackAssets">
|
||||
<PropertyGroup>
|
||||
<!-- /obj/<<configuration>>/<<targetframework>>/blazor -->
|
||||
<BlazorIntermediateOutputPath>$(IntermediateOutputPath)blazor\</BlazorIntermediateOutputPath>
|
||||
|
|
@ -94,8 +94,6 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<_BlazorDependencyInput Include="@(ReferenceCopyLocalPaths->WithMetadataValue('Extension','.dll')->'%(FullPath)')" />
|
||||
|
||||
<_WebAssemblyBCLFolder Include="
|
||||
$(DotNetWebAssemblyBCLPath);
|
||||
$(DotNetWebAssemblyBCLFacadesPath);
|
||||
|
|
@ -104,6 +102,22 @@
|
|||
<_WebAssemblyBCLAssembly Include="%(_WebAssemblyBCLFolder.Identity)*.dll" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--
|
||||
Calculate the assemblies that act as inputs to calculate assembly closure. Based on _ComputeAssembliesToPostprocessOnPublish which is used as input to SDK's linker
|
||||
https://github.com/dotnet/sdk/blob/d597e7b09d7657ba4e326d6734e14fcbf8473564/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets#L864-L873
|
||||
-->
|
||||
<ItemGroup>
|
||||
<!-- Assemblies from packages -->
|
||||
<_BlazorManagedRuntimeAssemby Include="@(RuntimeCopyLocalItems)" />
|
||||
|
||||
<!-- Assemblies from other references -->
|
||||
<_BlazorUserRuntimeAssembly Include="@(ReferencePath->WithMetadataValue('CopyLocal', 'true'))" />
|
||||
<_BlazorUserRuntimeAssembly Include="@(ReferenceDependencyPaths->WithMetadataValue('CopyLocal', 'true'))" />
|
||||
|
||||
<_BlazorManagedRuntimeAssemby Include="@(_BlazorUserRuntimeAssembly)" />
|
||||
<_BlazorManagedRuntimeAssemby Include="@(IntermediateAssembly)" />
|
||||
</ItemGroup>
|
||||
|
||||
<MakeDir Directories="$(BlazorIntermediateOutputPath)" />
|
||||
</Target>
|
||||
|
||||
|
|
@ -111,6 +125,27 @@
|
|||
<Error
|
||||
Message="Unrecongnized value for BlazorLinkOnBuild: '$(BlazorLinkOnBuild)'. Valid values are 'true' or 'false'."
|
||||
Condition="'$(BlazorLinkOnBuild)' != 'true' AND '$(BlazorLinkOnBuild)' != 'false'" />
|
||||
|
||||
<ItemGroup>
|
||||
<!--
|
||||
ReferenceCopyLocalPaths includes all files that are part of the build out with CopyLocalLockFileAssemblies on.
|
||||
Remove assemblies that are inputs to calculating the assembly closure. Instead use the resolved outputs, since it is the minimal set.
|
||||
-->
|
||||
<_BlazorCopyLocalPaths Include="@(ReferenceCopyLocalPaths)" />
|
||||
<_BlazorCopyLocalPaths Remove="@(_BlazorManagedRuntimeAssemby)" />
|
||||
|
||||
<BlazorOutputWithTargetPath Include="@(_BlazorCopyLocalPaths)">
|
||||
<BlazorRuntimeFile>true</BlazorRuntimeFile>
|
||||
<TargetOutputPath>$(BlazorRuntimeBinOutputPath)%(_BlazorCopyLocalPaths.DestinationSubDirectory)%(FileName)%(Extension)</TargetOutputPath>
|
||||
<RelativeOutputPath>%(_BlazorCopyLocalPaths.DestinationSubDirectory)%(FileName)%(Extension)</RelativeOutputPath>
|
||||
</BlazorOutputWithTargetPath>
|
||||
|
||||
<BlazorOutputWithTargetPath Include="@(_BlazorResolvedAssembly)">
|
||||
<BlazorRuntimeFile>true</BlazorRuntimeFile>
|
||||
<TargetOutputPath>$(BlazorRuntimeBinOutputPath)%(FileName)%(Extension)</TargetOutputPath>
|
||||
<RelativeOutputPath>%(FileName)%(Extension)</RelativeOutputPath>
|
||||
</BlazorOutputWithTargetPath>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<!--
|
||||
|
|
@ -128,14 +163,8 @@
|
|||
|
||||
<!-- _BlazorLinkerOutputCache records files linked during the last incremental build of the target. Read the contents and assign linked files to be copied to the output. -->
|
||||
<ReadLinesFromFile File="$(_BlazorLinkerOutputCache)">
|
||||
<Output TaskParameter="Lines" ItemName="_BlazorLinkedFile"/>
|
||||
<Output TaskParameter="Lines" ItemName="_BlazorResolvedAssembly"/>
|
||||
</ReadLinesFromFile>
|
||||
|
||||
<ItemGroup>
|
||||
<BlazorOutputWithTargetPath Include="%(_BlazorLinkedFile.Identity)">
|
||||
<TargetOutputPath>$(BlazorRuntimeBinOutputPath)%(FileName)%(Extension)</TargetOutputPath>
|
||||
</BlazorOutputWithTargetPath>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<UsingTask TaskName="BlazorCreateRootDescriptorFile" AssemblyFile="$(BlazorTasksPath)" />
|
||||
|
|
@ -163,8 +192,7 @@
|
|||
<Target
|
||||
Name="_LinkBlazorApplication"
|
||||
Inputs="$(ProjectAssetsFile);
|
||||
@(IntermediateAssembly);
|
||||
@(_BlazorDependencyInput);
|
||||
@(_BlazorManagedRuntimeAssemby);
|
||||
@(BlazorLinkerDescriptor);
|
||||
$(MSBuildAllProjects)"
|
||||
Outputs="$(_BlazorLinkerOutputCache)">
|
||||
|
|
@ -174,12 +202,15 @@
|
|||
<_BlazorDependencyAssembly IsLinkable="true" Condition="$([System.String]::Copy('%(Filename)').StartsWith('System.'))" />
|
||||
<_BlazorDependencyAssembly IsLinkable="true" TypeGranularity="true" Condition="$([System.String]::Copy('%(Filename)').StartsWith('Microsoft.AspNetCore.'))" />
|
||||
<_BlazorDependencyAssembly IsLinkable="true" TypeGranularity="true" Condition="$([System.String]::Copy('%(Filename)').StartsWith('Microsoft.Extensions.'))" />
|
||||
<!-- Any assembly from a package reference that starts with System. file name is allowed to be linked -->
|
||||
<_BlazorRuntimeCopyLocalItems Include="@(RuntimeCopyLocalItems)" IsLinkable="$([System.String]::Copy('%(FileName)').StartsWith('System.'))" />
|
||||
|
||||
<_BlazorAssemblyToLink Include="@(_WebAssemblyBCLAssembly)" />
|
||||
<_BlazorAssemblyToLink Include="@(_BlazorDependencyAssembly)" Condition="'%(_BlazorDependencyAssembly.IsLinkable)' == 'true'" />
|
||||
<_BlazorAssemblyToLink Include="@(_BlazorRuntimeCopyLocalItems)" Condition="'%(_BlazorRuntimeCopyLocalItems.IsLinkable)' == 'true'" />
|
||||
|
||||
<_BlazorLinkerRoot Include="@(IntermediateAssembly)" />
|
||||
<_BlazorLinkerRoot Include="@(_BlazorDependencyAssembly)" Condition="'%(_BlazorDependencyAssembly.IsLinkable)' != 'true'" />
|
||||
<_BlazorLinkerRoot Include="@(_BlazorUserRuntimeAssembly)" />
|
||||
<_BlazorLinkerRoot Include="@(_BlazorRuntimeCopyLocalItems)" Condition="'%(_BlazorRuntimeCopyLocalItems.IsLinkable)' != 'true'" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
|
@ -230,29 +261,22 @@
|
|||
<WriteLinesToFile File="$(_BlazorLinkerOutputCache)" Lines="@(_LinkerResult)" Overwrite="true" />
|
||||
</Target>
|
||||
|
||||
|
||||
<UsingTask TaskName="ResolveBlazorRuntimeDependencies" AssemblyFile="$(BlazorTasksPath)" />
|
||||
<Target
|
||||
Name="_ResolveBlazorOutputsWhenNotLinked"
|
||||
DependsOnTargets="_ResolveBlazorRuntimeDependencies"
|
||||
Condition="'$(BlazorLinkOnBuild)' != 'true'">
|
||||
|
||||
<ReadLinesFromFile File="$(_BlazorApplicationAssembliesCacheFile)" Condition="'@(_BlazorResolvedRuntimeDependencies->Count())' == '0'">
|
||||
<Output TaskParameter="Lines" ItemName="_BlazorResolvedRuntimeDependencies"/>
|
||||
<ReadLinesFromFile File="$(_BlazorApplicationAssembliesCacheFile)" Condition="'@(_BlazorResolvedAssembly->Count())' == '0'">
|
||||
<Output TaskParameter="Lines" ItemName="_BlazorResolvedAssembly"/>
|
||||
</ReadLinesFromFile>
|
||||
|
||||
<ItemGroup>
|
||||
<BlazorOutputWithTargetPath Include="@(_BlazorResolvedRuntimeDependencies)">
|
||||
<TargetOutputPath>$(BlazorRuntimeBinOutputPath)%(FileName)%(Extension)</TargetOutputPath>
|
||||
</BlazorOutputWithTargetPath>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target
|
||||
Name="_ResolveBlazorRuntimeDependencies"
|
||||
Inputs="$(ProjectAssetsFile);
|
||||
@(IntermediateAssembly);
|
||||
@(_BlazorDependencyInput)"
|
||||
@(_BlazorManagedRuntimeAssemby)"
|
||||
Outputs="$(_BlazorApplicationAssembliesCacheFile)">
|
||||
|
||||
<!--
|
||||
|
|
@ -262,10 +286,10 @@
|
|||
-->
|
||||
<ResolveBlazorRuntimeDependencies
|
||||
EntryPoint="@(IntermediateAssembly)"
|
||||
ApplicationDependencies="@(_BlazorDependencyInput)"
|
||||
ApplicationDependencies="@(_BlazorManagedRuntimeAssemby)"
|
||||
WebAssemblyBCLAssemblies="@(_WebAssemblyBCLAssembly)">
|
||||
|
||||
<Output TaskParameter="Dependencies" ItemName="_BlazorResolvedRuntimeDependencies" />
|
||||
<Output TaskParameter="Dependencies" ItemName="_BlazorResolvedAssembly" />
|
||||
</ResolveBlazorRuntimeDependencies>
|
||||
|
||||
<WriteLinesToFile File="$(_BlazorApplicationAssembliesCacheFile)" Lines="@(_BlazorResolvedRuntimeDependencies)" Overwrite="true" />
|
||||
|
|
@ -282,13 +306,12 @@
|
|||
Inputs="@(BlazorOutputWithTargetPath)"
|
||||
Outputs="$(BlazorBootJsonIntermediateOutputPath)">
|
||||
<ItemGroup>
|
||||
<_AppReferences Include="@(BlazorOutputWithTargetPath->WithMetadataValue('Extension','.dll'))" />
|
||||
<_AppReferences Include="@(BlazorOutputWithTargetPath->WithMetadataValue('Extension','.pdb'))" Condition="'$(BlazorEnableDebugging)' == 'true'" />
|
||||
<_BlazorRuntimeFile Include="@(BlazorOutputWithTargetPath->WithMetadataValue('BlazorRuntimeFile', 'true'))" />
|
||||
</ItemGroup>
|
||||
|
||||
<GenerateBlazorBootJson
|
||||
AssemblyPath="@(IntermediateAssembly)"
|
||||
References="@(_AppReferences)"
|
||||
References="@(_BlazorRuntimeFile)"
|
||||
LinkerEnabled="$(BlazorLinkOnBuild)"
|
||||
OutputPath="$(BlazorBootJsonIntermediateOutputPath)" />
|
||||
|
||||
|
|
|
|||
|
|
@ -70,5 +70,66 @@ namespace Microsoft.AspNetCore.Blazor.Build
|
|||
Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "standalone.dll");
|
||||
Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "Microsoft.Extensions.Logging.Abstractions.dll"); // Verify dependencies are part of the output.
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Build_SatelliteAssembliesAreCopiedToBuildOutput()
|
||||
{
|
||||
// Arrange
|
||||
using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary", "classlibrarywithsatelliteassemblies" });
|
||||
project.AddProjectFileContent(
|
||||
@"
|
||||
<PropertyGroup>
|
||||
<DefineConstants>$(DefineConstants);REFERENCE_classlibrarywithsatelliteassemblies</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include=""..\classlibrarywithsatelliteassemblies\classlibrarywithsatelliteassemblies.csproj"" />
|
||||
</ItemGroup>");
|
||||
|
||||
var result = await MSBuildProcessManager.DotnetMSBuild(project, args: "/restore");
|
||||
|
||||
Assert.BuildPassed(result);
|
||||
|
||||
var buildOutputDirectory = project.BuildOutputDirectory;
|
||||
|
||||
Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "standalone.dll");
|
||||
Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "classlibrarywithsatelliteassemblies.dll");
|
||||
Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "Microsoft.CodeAnalysis.CSharp.dll");
|
||||
Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "fr", "Microsoft.CodeAnalysis.CSharp.resources.dll"); // Verify satellite assemblies are present in the build output.
|
||||
|
||||
var bootJsonPath = Path.Combine(buildOutputDirectory, "dist", "_framework", "blazor.boot.json");
|
||||
Assert.FileContains(result, bootJsonPath, "\"Microsoft.CodeAnalysis.CSharp.dll\"");
|
||||
Assert.FileContains(result, bootJsonPath, "\"fr\\/Microsoft.CodeAnalysis.CSharp.resources.dll\"");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Build_WithBlazorLinkOnBuildFalse_SatelliteAssembliesAreCopiedToBuildOutput()
|
||||
{
|
||||
// Arrange
|
||||
using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary", "classlibrarywithsatelliteassemblies" });
|
||||
project.AddProjectFileContent(
|
||||
@"
|
||||
<PropertyGroup>
|
||||
<BlazorLinkOnBuild>false</BlazorLinkOnBuild>
|
||||
<DefineConstants>$(DefineConstants);REFERENCE_classlibrarywithsatelliteassemblies</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include=""..\classlibrarywithsatelliteassemblies\classlibrarywithsatelliteassemblies.csproj"" />
|
||||
</ItemGroup>");
|
||||
|
||||
var result = await MSBuildProcessManager.DotnetMSBuild(project, args: "/restore");
|
||||
|
||||
Assert.BuildPassed(result);
|
||||
|
||||
var buildOutputDirectory = project.BuildOutputDirectory;
|
||||
|
||||
Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "standalone.dll");
|
||||
Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "classlibrarywithsatelliteassemblies.dll");
|
||||
Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "Microsoft.CodeAnalysis.CSharp.dll");
|
||||
Assert.FileExists(result, buildOutputDirectory, "dist", "_framework", "_bin", "fr", "Microsoft.CodeAnalysis.CSharp.resources.dll"); // Verify satellite assemblies are present in the build output.
|
||||
|
||||
var bootJsonPath = Path.Combine(buildOutputDirectory, "dist", "_framework", "blazor.boot.json");
|
||||
Assert.FileContains(result, bootJsonPath, "\"Microsoft.CodeAnalysis.CSharp.dll\"");
|
||||
Assert.FileContains(result, bootJsonPath, "\"fr\\/Microsoft.CodeAnalysis.CSharp.resources.dll\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,6 +112,35 @@ namespace Microsoft.AspNetCore.Blazor.Build
|
|||
Assert.FileExists(result, publishDirectory, "web.config");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Publish_SatelliteAssemblies_AreCopiedToBuildOutput()
|
||||
{
|
||||
// Arrange
|
||||
using var project = ProjectDirectory.Create("standalone", additionalProjects: new[] { "razorclasslibrary", "classlibrarywithsatelliteassemblies" });
|
||||
project.AddProjectFileContent(
|
||||
@"
|
||||
<PropertyGroup>
|
||||
<DefineConstants>$(DefineConstants);REFERENCE_classlibrarywithsatelliteassemblies</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include=""..\classlibrarywithsatelliteassemblies\classlibrarywithsatelliteassemblies.csproj"" />
|
||||
</ItemGroup>");
|
||||
|
||||
var result = await MSBuildProcessManager.DotnetMSBuild(project, "Publish", args: "/restore");
|
||||
|
||||
Assert.BuildPassed(result);
|
||||
|
||||
var publishDirectory = project.PublishOutputDirectory;
|
||||
var blazorPublishDirectory = Path.Combine(publishDirectory, Path.GetFileNameWithoutExtension(project.ProjectFilePath));
|
||||
|
||||
Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "_bin", "Microsoft.CodeAnalysis.CSharp.dll");
|
||||
Assert.FileExists(result, blazorPublishDirectory, "dist", "_framework", "_bin", "fr", "Microsoft.CodeAnalysis.CSharp.resources.dll"); // Verify satellite assemblies are present in the build output.
|
||||
|
||||
var bootJsonPath = Path.Combine(blazorPublishDirectory, "dist", "_framework", "blazor.boot.json");
|
||||
Assert.FileContains(result, bootJsonPath, "\"Microsoft.CodeAnalysis.CSharp.dll\"");
|
||||
Assert.FileContains(result, bootJsonPath, "\"fr\\/Microsoft.CodeAnalysis.CSharp.resources.dll\"");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Publish_HostedApp_Works()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace classlibrarywithsatelliteassemblies
|
||||
{
|
||||
public class Class1
|
||||
{
|
||||
public static void Test()
|
||||
{
|
||||
GC.KeepAlive(typeof(Microsoft.CodeAnalysis.CSharp.CSharpCompilation));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<RazorLangVersion>3.0</RazorLangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- The compiler package contains quite a few satellite assemblies -->
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -1,10 +1,14 @@
|
|||
|
||||
using System;
|
||||
|
||||
namespace standalone
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
#if REFERENCE_classlibrarywithsatelliteassemblies
|
||||
GC.KeepAlive(typeof(classlibrarywithsatelliteassemblies.Class1));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue