未验证 提交 bfd6048a 编写于 作者: L Larry Ewing 提交者: GitHub

[release/6.0-preview4][wasm] Fix Blazor AOT builds inside Visual Studio (#52078)

* [wasm] Build tasks for net472 also (#51959)

* [wasm] Fix loading WebAssembly tasks in VS

- In case of `WasmAppBuilder.dll`, we were packaging only the task assembly, and
  `System.Reflection.MetadataLoadContext` for net472, same as net6.0 .

- But for net472, VS fails with errors like:

```
C:\Program Files\dotnet\packs\Microsoft.NET.Runtime.WebAssembly.Sdk\6.0.0-preview.4.21222.10\Sdk\WasmApp.targets(424,4): Error MSB4018: The "PInvokeTableGenerator" task failed unexpectedly.
System.IO.FileNotFoundException: Could not load file or assembly 'System.Reflection.Metadata, Version=1.4.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
File name: 'System.Reflection.Metadata, Version=1.4.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
   at System.Reflection.MetadataLoadContext.LoadFromStreamCore(Stream peStream)
   at System.Reflection.MetadataLoadContext.LoadFromAssemblyPath(String assemblyPath)
   at System.Reflection.PathAssemblyResolver.Resolve(MetadataLoadContext context, AssemblyName assemblyName)
   at System.Reflection.MetadataLoadContext.TryFindAssemblyByCallingResolveHandler(RoAssemblyName refName)
   at System.Reflection.MetadataLoadContext.ResolveToAssemblyOrExceptionAssembly(RoAssemblyName refName)
   at System.Reflection.MetadataLoadContext.TryResolveAssembly(RoAssemblyName refName, Exception& e)
   at System.Reflection.MetadataLoadContext.TryGetCoreAssembly(String coreAssemblyName, Exception& e)
   at System.Reflection.TypeLoading.CoreTypes..ctor(MetadataLoadContext loader, String coreAssemblyName)
   at System.Reflection.MetadataLoadContext..ctor(MetadataAssemblyResolver resolver, String coreAssemblyName)
   at PInvokeTableGenerator.GenPInvokeTable(String[] pinvokeModules, String[] assemblies) in /Users/radical/dev/r2/src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs:line 42
   at PInvokeTableGenerator.Execute() in /Users/radical/dev/r2/src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs:line 28
   at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute()
   at Microsoft.Build.BackEnd.TaskBuilder.<ExecuteInstantiatedTask>d__26.MoveNext()
```

- So, bundle all the dependent assemblies from the publish folder

* Address review feedback

* Update src/tasks/AotCompilerTask/MonoAOTCompiler.csproj
Co-authored-by: NDaniel Plaisted <dsplaisted@gmail.com>

* Update src/tasks/AotCompilerTask/MonoAOTCompiler.csproj
Co-authored-by: NDaniel Plaisted <dsplaisted@gmail.com>

* Update src/tasks/WasmAppBuilder/WasmAppBuilder.csproj
Co-authored-by: NDaniel Plaisted <dsplaisted@gmail.com>

* Update src/tasks/WasmAppBuilder/WasmAppBuilder.csproj
Co-authored-by: NDaniel Plaisted <dsplaisted@gmail.com>

* Apply suggestions from code review
Co-authored-by: NDaniel Plaisted <dsplaisted@gmail.com>

* Use a property for net472
Co-authored-by: NAnkit Jain <radical@gmail.com>
Co-authored-by: NDaniel Plaisted <dsplaisted@gmail.com>
上级 bd2d701e
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<MonoAOTCompilerTasksAssemblyPath>$(MSBuildThisFileDirectory)..\tasks\MonoAOTCompiler.dll</MonoAOTCompilerTasksAssemblyPath> <MonoAOTCompilerTasksAssemblyPath Condition="'$(MSBuildRuntimeType)' == 'Core'">$(MSBuildThisFileDirectory)..\tasks\net6.0\MonoAOTCompiler.dll</MonoAOTCompilerTasksAssemblyPath>
<MonoAOTCompilerTasksAssemblyPath Condition="'$(MSBuildRuntimeType)' != 'Core'">$(MSBuildThisFileDirectory)..\tasks\net472\MonoAOTCompiler.dll</MonoAOTCompilerTasksAssemblyPath>
</PropertyGroup> </PropertyGroup>
<UsingTask TaskName="MonoAOTCompiler" AssemblyFile="$(MonoAOTCompilerTasksAssemblyPath)" /> <UsingTask TaskName="MonoAOTCompiler" AssemblyFile="$(MonoAOTCompilerTasksAssemblyPath)" />
</Project> </Project>
<Project> <Project>
<!-- Property overrides --> <!-- Property overrides -->
<PropertyGroup> <PropertyGroup>
<WasmAppBuilderTasksAssemblyPath>$(MSBuildThisFileDirectory)..\tasks\WasmAppBuilder.dll</WasmAppBuilderTasksAssemblyPath> <_TasksDir Condition="'$(MSBuildRuntimeType)' == 'Core'">$(MSBuildThisFileDirectory)..\tasks\net6.0\</_TasksDir>
<WasmBuildTasksAssemblyPath>$(MSBuildThisFileDirectory)..\tasks\WasmBuildTasks.dll</WasmBuildTasksAssemblyPath> <_TasksDir Condition="'$(MSBuildRuntimeType)' != 'Core'">$(MSBuildThisFileDirectory)..\tasks\net472\</_TasksDir>
<WasmAppBuilderTasksAssemblyPath>$(_TasksDir)WasmAppBuilder.dll</WasmAppBuilderTasksAssemblyPath>
<WasmBuildTasksAssemblyPath>$(_TasksDir)WasmBuildTasks.dll</WasmBuildTasksAssemblyPath>
</PropertyGroup> </PropertyGroup>
<Import Project="$(MSBuildThisFileDirectory)\WasmApp.props" /> <Import Project="$(MSBuildThisFileDirectory)\WasmApp.props" />
......
...@@ -185,7 +185,7 @@ public override bool Execute() ...@@ -185,7 +185,7 @@ public override bool Execute()
if (!Enum.TryParse(Mode, true, out parsedAotMode)) if (!Enum.TryParse(Mode, true, out parsedAotMode))
{ {
Log.LogError($"Unknown Mode value: {Mode}. '{nameof(Mode)}' must be one of: {string.Join(',', Enum.GetNames(typeof(MonoAotMode)))}"); Log.LogError($"Unknown Mode value: {Mode}. '{nameof(Mode)}' must be one of: {string.Join(",", Enum.GetNames(typeof(MonoAotMode)))}");
return false; return false;
} }
...@@ -217,7 +217,7 @@ public override bool Execute() ...@@ -217,7 +217,7 @@ public override bool Execute()
string? monoPaths = null; string? monoPaths = null;
if (AdditionalAssemblySearchPaths != null) if (AdditionalAssemblySearchPaths != null)
monoPaths = string.Join(Path.PathSeparator, AdditionalAssemblySearchPaths); monoPaths = string.Join(Path.PathSeparator.ToString(), AdditionalAssemblySearchPaths);
if (DisableParallelAot) if (DisableParallelAot)
{ {
...@@ -252,13 +252,13 @@ private bool PrecompileLibrary(ITaskItem assemblyItem, string? monoPaths) ...@@ -252,13 +252,13 @@ private bool PrecompileLibrary(ITaskItem assemblyItem, string? monoPaths)
var a = assemblyItem.GetMetadata("AotArguments"); var a = assemblyItem.GetMetadata("AotArguments");
if (a != null) if (a != null)
{ {
aotArgs.AddRange(a.Split(";", StringSplitOptions.RemoveEmptyEntries)); aotArgs.AddRange(a.Split(new char[]{ ';' }, StringSplitOptions.RemoveEmptyEntries));
} }
var p = assemblyItem.GetMetadata("ProcessArguments"); var p = assemblyItem.GetMetadata("ProcessArguments");
if (p != null) if (p != null)
{ {
processArgs.AddRange(p.Split(";", StringSplitOptions.RemoveEmptyEntries)); processArgs.AddRange(p.Split(new char[]{ ';' }, StringSplitOptions.RemoveEmptyEntries));
} }
Log.LogMessage(MessageImportance.Low, $"[AOT] {assembly}"); Log.LogMessage(MessageImportance.Low, $"[AOT] {assembly}");
......
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>$(NetCoreAppToolCurrent)</TargetFramework> <TargetFrameworks>$(NetCoreAppToolCurrent);$(TargetFrameworkForNETFramework)</TargetFrameworks>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems> <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<NoWarn>$(NoWarn),CA1050</NoWarn> <NoWarn>$(NoWarn),CA1050</NoWarn>
<!-- Ignore nullable warnings on net4* -->
<NoWarn Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETFramework'">$(NoWarn),CS8604,CS8602</NoWarn>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Build" Version="$(RefOnlyMicrosoftBuildVersion)" /> <PackageReference Include="Microsoft.Build" Version="$(RefOnlyMicrosoftBuildVersion)" />
...@@ -16,6 +19,7 @@ ...@@ -16,6 +19,7 @@
<ItemGroup> <ItemGroup>
<Compile Include="MonoAOTCompiler.cs" /> <Compile Include="MonoAOTCompiler.cs" />
<Compile Include="..\Common\Utils.cs" /> <Compile Include="..\Common\Utils.cs" />
<Compile Include="$(RepoRoot)src\libraries\System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs" Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="MonoAOTCompiler.props"> <Content Include="MonoAOTCompiler.props">
...@@ -26,7 +30,10 @@ ...@@ -26,7 +30,10 @@
<!-- GetFilesToPackage assists to place `MonoAOTCompiler.dll` in a NuGet package in Microsoft.NET.Runtime.MonoAOTCompiler.Task.pkgproj for external use --> <!-- GetFilesToPackage assists to place `MonoAOTCompiler.dll` in a NuGet package in Microsoft.NET.Runtime.MonoAOTCompiler.Task.pkgproj for external use -->
<Target Name="GetFilesToPackage" Returns="@(FilesToPackage)"> <Target Name="GetFilesToPackage" Returns="@(FilesToPackage)">
<ItemGroup> <ItemGroup>
<FilesToPackage Include="$(OutputPath)$(AssemblyName).dll" TargetPath="tasks" /> <_PublishFramework Remove="@(_PublishFramework)" />
<_PublishFramework Include="$(TargetFrameworks)" />
<FilesToPackage Include="$(OutputPath)%(_PublishFramework.Identity)\$(AssemblyName).dll" TargetPath="tasks\%(_PublishFramework.Identity)" />
</ItemGroup> </ItemGroup>
</Target> </Target>
</Project> </Project>
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace System.Runtime.CompilerServices
{
internal sealed class IsExternalInit { }
}
...@@ -102,6 +102,7 @@ public static string GetEmbeddedResource(string file) ...@@ -102,6 +102,7 @@ public static string GetEmbeddedResource(string file)
return outputBuilder.ToString().Trim('\r', '\n'); return outputBuilder.ToString().Trim('\r', '\n');
} }
#if NETCOREAPP
public static void DirectoryCopy(string sourceDir, string destDir, Func<string, bool> predicate) public static void DirectoryCopy(string sourceDir, string destDir, Func<string, bool> predicate)
{ {
string[] files = Directory.GetFiles(sourceDir, "*", SearchOption.AllDirectories); string[] files = Directory.GetFiles(sourceDir, "*", SearchOption.AllDirectories);
...@@ -118,6 +119,7 @@ public static void DirectoryCopy(string sourceDir, string destDir, Func<string, ...@@ -118,6 +119,7 @@ public static void DirectoryCopy(string sourceDir, string destDir, Func<string,
File.Copy(file, Path.Combine(destDir, relativePath), true); File.Copy(file, Path.Combine(destDir, relativePath), true);
} }
} }
#endif
public static TaskLoggingHelper? Logger { get; set; } public static TaskLoggingHelper? Logger { get; set; }
......
<Project>
<Import Project="$([MSBuild]::GetPathOfFileAbove(Directory.Build.props, '$(MSBuildThisFileDirectory)..'))" />
<PropertyGroup>
<TargetFrameworkForNETFramework>net472</TargetFrameworkForNETFramework>
</PropertyGroup>
</Project>
...@@ -144,18 +144,18 @@ public override bool Execute () ...@@ -144,18 +144,18 @@ public override bool Execute ()
var config = new WasmAppConfig (); var config = new WasmAppConfig ();
// Create app // Create app
var asmRootPath = Path.Join(AppDir, config.AssemblyRoot); var asmRootPath = Path.Combine(AppDir, config.AssemblyRoot);
Directory.CreateDirectory(AppDir!); Directory.CreateDirectory(AppDir!);
Directory.CreateDirectory(asmRootPath); Directory.CreateDirectory(asmRootPath);
foreach (var assembly in _assemblies) foreach (var assembly in _assemblies)
{ {
FileCopyChecked(assembly, Path.Join(asmRootPath, Path.GetFileName(assembly)), "Assemblies"); FileCopyChecked(assembly, Path.Combine(asmRootPath, Path.GetFileName(assembly)), "Assemblies");
if (DebugLevel != 0) if (DebugLevel != 0)
{ {
var pdb = assembly; var pdb = assembly;
pdb = Path.ChangeExtension(pdb, ".pdb"); pdb = Path.ChangeExtension(pdb, ".pdb");
if (File.Exists(pdb)) if (File.Exists(pdb))
FileCopyChecked(pdb, Path.Join(asmRootPath, Path.GetFileName(pdb)), "Assemblies"); FileCopyChecked(pdb, Path.Combine(asmRootPath, Path.GetFileName(pdb)), "Assemblies");
} }
} }
...@@ -165,10 +165,10 @@ public override bool Execute () ...@@ -165,10 +165,10 @@ public override bool Execute ()
if (!FileCopyChecked(item.ItemSpec, dest, "NativeAssets")) if (!FileCopyChecked(item.ItemSpec, dest, "NativeAssets"))
return false; return false;
} }
FileCopyChecked(MainJS!, Path.Join(AppDir, "runtime.js"), string.Empty); FileCopyChecked(MainJS!, Path.Combine(AppDir, "runtime.js"), string.Empty);
var html = @"<html><body><script type=""text/javascript"" src=""runtime.js""></script></body></html>"; var html = @"<html><body><script type=""text/javascript"" src=""runtime.js""></script></body></html>";
File.WriteAllText(Path.Join(AppDir, "index.html"), html); File.WriteAllText(Path.Combine(AppDir, "index.html"), html);
foreach (var assembly in _assemblies) foreach (var assembly in _assemblies)
{ {
...@@ -190,16 +190,16 @@ public override bool Execute () ...@@ -190,16 +190,16 @@ public override bool Execute ()
string culture = assembly.GetMetadata("CultureName") ?? string.Empty; string culture = assembly.GetMetadata("CultureName") ?? string.Empty;
string fullPath = assembly.GetMetadata("Identity"); string fullPath = assembly.GetMetadata("Identity");
string name = Path.GetFileName(fullPath); string name = Path.GetFileName(fullPath);
string directory = Path.Join(AppDir, config.AssemblyRoot, culture); string directory = Path.Combine(AppDir, config.AssemblyRoot, culture);
Directory.CreateDirectory(directory); Directory.CreateDirectory(directory);
FileCopyChecked(fullPath, Path.Join(directory, name), "SatelliteAssemblies"); FileCopyChecked(fullPath, Path.Combine(directory, name), "SatelliteAssemblies");
config.Assets.Add(new SatelliteAssemblyEntry(name, culture)); config.Assets.Add(new SatelliteAssemblyEntry(name, culture));
} }
} }
if (FilesToIncludeInFileSystem != null) if (FilesToIncludeInFileSystem != null)
{ {
string supportFilesDir = Path.Join(AppDir, "supportFiles"); string supportFilesDir = Path.Combine(AppDir, "supportFiles");
Directory.CreateDirectory(supportFilesDir); Directory.CreateDirectory(supportFilesDir);
var i = 0; var i = 0;
...@@ -216,7 +216,7 @@ public override bool Execute () ...@@ -216,7 +216,7 @@ public override bool Execute ()
var generatedFileName = $"{i++}_{Path.GetFileName(item.ItemSpec)}"; var generatedFileName = $"{i++}_{Path.GetFileName(item.ItemSpec)}";
FileCopyChecked(item.ItemSpec, Path.Join(supportFilesDir, generatedFileName), "FilesToIncludeInFileSystem"); FileCopyChecked(item.ItemSpec, Path.Combine(supportFilesDir, generatedFileName), "FilesToIncludeInFileSystem");
var asset = new VfsEntry ($"supportFiles/{generatedFileName}") { var asset = new VfsEntry ($"supportFiles/{generatedFileName}") {
VirtualPath = targetPath VirtualPath = targetPath
...@@ -246,7 +246,7 @@ public override bool Execute () ...@@ -246,7 +246,7 @@ public override bool Execute ()
config.Extra[name] = valueObject; config.Extra[name] = valueObject;
} }
string monoConfigPath = Path.Join(AppDir, "mono-config.js"); string monoConfigPath = Path.Combine(AppDir, "mono-config.js");
using (var sw = File.CreateText(monoConfigPath)) using (var sw = File.CreateText(monoConfigPath))
{ {
var json = JsonSerializer.Serialize (config, new JsonSerializerOptions { WriteIndented = true }); var json = JsonSerializer.Serialize (config, new JsonSerializerOptions { WriteIndented = true });
...@@ -284,9 +284,9 @@ private bool TryParseExtraConfigValue(ITaskItem extraItem, out object? valueObje ...@@ -284,9 +284,9 @@ private bool TryParseExtraConfigValue(ITaskItem extraItem, out object? valueObje
return true; return true;
// Try parsing as a quoted string // Try parsing as a quoted string
if (rawValue!.Length > 1 && rawValue![0] == '"' && rawValue![^1] == '"') if (rawValue!.Length > 1 && rawValue![0] == '"' && rawValue![rawValue!.Length - 1] == '"')
{ {
valueObject = rawValue![1..^1]; valueObject = rawValue!.Substring(1, rawValue!.Length - 2);
return true; return true;
} }
......
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>$(NetCoreAppToolCurrent)</TargetFramework> <TargetFrameworks>$(NetCoreAppToolCurrent);$(TargetFrameworkForNETFramework)</TargetFrameworks>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<NoWarn>$(NoWarn),CA1050</NoWarn> <NoWarn>$(NoWarn),CA1050</NoWarn>
<!-- Ignore nullable warnings on net4* -->
<NoWarn Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETFramework'">$(NoWarn),CS8604,CS8602</NoWarn>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'">
<Compile Include="..\Common\IsExternalInit.cs" />
<Compile Include="$(RepoRoot)src\libraries\System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Build" Version="$(RefOnlyMicrosoftBuildVersion)" /> <PackageReference Include="Microsoft.Build" Version="$(RefOnlyMicrosoftBuildVersion)" />
<PackageReference Include="Microsoft.Build.Framework" Version="$(RefOnlyMicrosoftBuildFrameworkVersion)" /> <PackageReference Include="Microsoft.Build.Framework" Version="$(RefOnlyMicrosoftBuildFrameworkVersion)" />
...@@ -13,13 +22,29 @@ ...@@ -13,13 +22,29 @@
</ItemGroup> </ItemGroup>
<Target Name="PublishBuilder" <Target Name="PublishBuilder"
AfterTargets="Build" AfterTargets="Build">
DependsOnTargets="Publish" />
<!-- needed for publishing with multi-targeting. We are publishing essentially to get the SR.MetadataLoadContext.dll :/ -->
<ItemGroup>
<_PublishFramework Include="$(TargetFrameworks)" />
</ItemGroup>
<MSBuild Projects="$(MSBuildProjectFile)" Targets="Publish" Properties="TargetFramework=%(_PublishFramework.Identity)" />
</Target>
<Target Name="GetFilesToPackage" Returns="@(FilesToPackage)"> <Target Name="GetFilesToPackage" Returns="@(FilesToPackage)">
<ItemGroup> <ItemGroup>
<FilesToPackage Include="$(OutputPath)$(MSBuildProjectName)*" TargetPath="tasks" /> <_PublishFramework Remove="@(_PublishFramework)" />
<FilesToPackage Include="$(PublishDir)System.Reflection.MetadataLoadContext.dll" TargetPath="tasks" /> <_PublishFramework Include="$(TargetFrameworks)" />
<!-- non-net4* -->
<FilesToPackage Include="$(OutputPath)$(NetCoreAppToolCurrent)\$(MSBuildProjectName)*"
TargetPath="tasks\$(NetCoreAppToolCurrent)" />
<FilesToPackage Include="$(OutputPath)$(NetCoreAppToolCurrent)\publish\System.Reflection.MetadataLoadContext.dll"
TargetPath="tasks\$(NetCoreAppToolCurrent)" />
<!-- for net472 we need all the dependent assemblies too, so copy from the publish folder -->
<FilesToPackage Include="$(OutputPath)$(TargetFrameworkForNETFramework)\publish\*"
TargetPath="tasks\$(TargetFrameworkForNETFramework)" />
</ItemGroup> </ItemGroup>
</Target> </Target>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册