Skip to content

Commit

Permalink
[release/6.0-preview4][wasm] Fix Blazor AOT builds inside Visual Stud…
Browse files Browse the repository at this point in the history
…io (#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: Daniel Plaisted <[email protected]>

* Update src/tasks/AotCompilerTask/MonoAOTCompiler.csproj

Co-authored-by: Daniel Plaisted <[email protected]>

* Update src/tasks/WasmAppBuilder/WasmAppBuilder.csproj

Co-authored-by: Daniel Plaisted <[email protected]>

* Update src/tasks/WasmAppBuilder/WasmAppBuilder.csproj

Co-authored-by: Daniel Plaisted <[email protected]>

* Apply suggestions from code review

Co-authored-by: Daniel Plaisted <[email protected]>

* Use a property for net472

Co-authored-by: Ankit Jain <[email protected]>
Co-authored-by: Daniel Plaisted <[email protected]>
  • Loading branch information
3 people authored May 3, 2021
1 parent bd2d701 commit bfd6048
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<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>
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
<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" />
Expand Down
8 changes: 4 additions & 4 deletions src/tasks/AotCompilerTask/MonoAOTCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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}");
Expand Down
11 changes: 9 additions & 2 deletions src/tasks/AotCompilerTask/MonoAOTCompiler.csproj
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
<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)" />
Expand All @@ -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">
Expand All @@ -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>
7 changes: 7 additions & 0 deletions src/tasks/Common/IsExternalInit.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// 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 { }
}
2 changes: 2 additions & 0 deletions src/tasks/Common/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ public static string RunProcess(
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);
Expand All @@ -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; }

Expand Down
7 changes: 7 additions & 0 deletions src/tasks/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Project>
<Import Project="$([MSBuild]::GetPathOfFileAbove(Directory.Build.props, '$(MSBuildThisFileDirectory)..'))" />

<PropertyGroup>
<TargetFrameworkForNETFramework>net472</TargetFrameworkForNETFramework>
</PropertyGroup>
</Project>
24 changes: 12 additions & 12 deletions src/tasks/WasmAppBuilder/WasmAppBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
}

Expand All @@ -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)
{
Expand All @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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 });
Expand Down Expand Up @@ -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;
}

Expand Down
35 changes: 30 additions & 5 deletions src/tasks/WasmAppBuilder/WasmAppBuilder.csproj
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
<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)" />
Expand All @@ -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>

Expand Down

0 comments on commit bfd6048

Please sign in to comment.