未验证 提交 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>
<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>
<UsingTask TaskName="MonoAOTCompiler" AssemblyFile="$(MonoAOTCompilerTasksAssemblyPath)" />
</Project>
<Project>
<!-- Property overrides -->
<PropertyGroup>
<WasmAppBuilderTasksAssemblyPath>$(MSBuildThisFileDirectory)..\tasks\WasmAppBuilder.dll</WasmAppBuilderTasksAssemblyPath>
<WasmBuildTasksAssemblyPath>$(MSBuildThisFileDirectory)..\tasks\WasmBuildTasks.dll</WasmBuildTasksAssemblyPath>
<_TasksDir Condition="'$(MSBuildRuntimeType)' == 'Core'">$(MSBuildThisFileDirectory)..\tasks\net6.0\</_TasksDir>
<_TasksDir Condition="'$(MSBuildRuntimeType)' != 'Core'">$(MSBuildThisFileDirectory)..\tasks\net472\</_TasksDir>
<WasmAppBuilderTasksAssemblyPath>$(_TasksDir)WasmAppBuilder.dll</WasmAppBuilderTasksAssemblyPath>
<WasmBuildTasksAssemblyPath>$(_TasksDir)WasmBuildTasks.dll</WasmBuildTasksAssemblyPath>
</PropertyGroup>
<Import Project="$(MSBuildThisFileDirectory)\WasmApp.props" />
......
......@@ -185,7 +185,7 @@ public override bool Execute()
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;
}
......@@ -217,7 +217,7 @@ public override bool Execute()
string? monoPaths = null;
if (AdditionalAssemblySearchPaths != null)
monoPaths = string.Join(Path.PathSeparator, AdditionalAssemblySearchPaths);
monoPaths = string.Join(Path.PathSeparator.ToString(), AdditionalAssemblySearchPaths);
if (DisableParallelAot)
{
......@@ -252,13 +252,13 @@ private bool PrecompileLibrary(ITaskItem assemblyItem, string? monoPaths)
var a = assemblyItem.GetMetadata("AotArguments");
if (a != null)
{
aotArgs.AddRange(a.Split(";", StringSplitOptions.RemoveEmptyEntries));
aotArgs.AddRange(a.Split(new char[]{ ';' }, StringSplitOptions.RemoveEmptyEntries));
}
var p = assemblyItem.GetMetadata("ProcessArguments");
if (p != null)
{
processArgs.AddRange(p.Split(";", StringSplitOptions.RemoveEmptyEntries));
processArgs.AddRange(p.Split(new char[]{ ';' }, StringSplitOptions.RemoveEmptyEntries));
}
Log.LogMessage(MessageImportance.Low, $"[AOT] {assembly}");
......
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>$(NetCoreAppToolCurrent)</TargetFramework>
<TargetFrameworks>$(NetCoreAppToolCurrent);$(TargetFrameworkForNETFramework)</TargetFrameworks>
<OutputType>Library</OutputType>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn),CA1050</NoWarn>
<!-- Ignore nullable warnings on net4* -->
<NoWarn Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETFramework'">$(NoWarn),CS8604,CS8602</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build" Version="$(RefOnlyMicrosoftBuildVersion)" />
......@@ -16,6 +19,7 @@
<ItemGroup>
<Compile Include="MonoAOTCompiler.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>
<Content Include="MonoAOTCompiler.props">
......@@ -26,7 +30,10 @@
<!-- 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)">
<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>
</Target>
</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)
return outputBuilder.ToString().Trim('\r', '\n');
}
#if NETCOREAPP
public static void DirectoryCopy(string sourceDir, string destDir, Func<string, bool> predicate)
{
string[] files = Directory.GetFiles(sourceDir, "*", SearchOption.AllDirectories);
......@@ -118,6 +119,7 @@ public static void DirectoryCopy(string sourceDir, string destDir, Func<string,
File.Copy(file, Path.Combine(destDir, relativePath), true);
}
}
#endif
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 ()
var config = new WasmAppConfig ();
// Create app
var asmRootPath = Path.Join(AppDir, config.AssemblyRoot);
var asmRootPath = Path.Combine(AppDir, config.AssemblyRoot);
Directory.CreateDirectory(AppDir!);
Directory.CreateDirectory(asmRootPath);
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)
{
var pdb = assembly;
pdb = Path.ChangeExtension(pdb, ".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 ()
if (!FileCopyChecked(item.ItemSpec, dest, "NativeAssets"))
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>";
File.WriteAllText(Path.Join(AppDir, "index.html"), html);
File.WriteAllText(Path.Combine(AppDir, "index.html"), html);
foreach (var assembly in _assemblies)
{
......@@ -190,16 +190,16 @@ public override bool Execute ()
string culture = assembly.GetMetadata("CultureName") ?? string.Empty;
string fullPath = assembly.GetMetadata("Identity");
string name = Path.GetFileName(fullPath);
string directory = Path.Join(AppDir, config.AssemblyRoot, culture);
string directory = Path.Combine(AppDir, config.AssemblyRoot, culture);
Directory.CreateDirectory(directory);
FileCopyChecked(fullPath, Path.Join(directory, name), "SatelliteAssemblies");
FileCopyChecked(fullPath, Path.Combine(directory, name), "SatelliteAssemblies");
config.Assets.Add(new SatelliteAssemblyEntry(name, culture));
}
}
if (FilesToIncludeInFileSystem != null)
{
string supportFilesDir = Path.Join(AppDir, "supportFiles");
string supportFilesDir = Path.Combine(AppDir, "supportFiles");
Directory.CreateDirectory(supportFilesDir);
var i = 0;
......@@ -216,7 +216,7 @@ public override bool Execute ()
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}") {
VirtualPath = targetPath
......@@ -246,7 +246,7 @@ public override bool Execute ()
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))
{
var json = JsonSerializer.Serialize (config, new JsonSerializerOptions { WriteIndented = true });
......@@ -284,9 +284,9 @@ private bool TryParseExtraConfigValue(ITaskItem extraItem, out object? valueObje
return true;
// 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;
}
......
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>$(NetCoreAppToolCurrent)</TargetFramework>
<TargetFrameworks>$(NetCoreAppToolCurrent);$(TargetFrameworkForNETFramework)</TargetFrameworks>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn),CA1050</NoWarn>
<!-- Ignore nullable warnings on net4* -->
<NoWarn Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETFramework'">$(NoWarn),CS8604,CS8602</NoWarn>
</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>
<PackageReference Include="Microsoft.Build" Version="$(RefOnlyMicrosoftBuildVersion)" />
<PackageReference Include="Microsoft.Build.Framework" Version="$(RefOnlyMicrosoftBuildFrameworkVersion)" />
......@@ -13,13 +22,29 @@
</ItemGroup>
<Target Name="PublishBuilder"
AfterTargets="Build"
DependsOnTargets="Publish" />
AfterTargets="Build">
<!-- 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)">
<ItemGroup>
<FilesToPackage Include="$(OutputPath)$(MSBuildProjectName)*" TargetPath="tasks" />
<FilesToPackage Include="$(PublishDir)System.Reflection.MetadataLoadContext.dll" TargetPath="tasks" />
<_PublishFramework Remove="@(_PublishFramework)" />
<_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>
</Target>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册