Skip to content
2 changes: 2 additions & 0 deletions eng/testing/tests.wasm.targets
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
<!-- Some tests expect to load satellite assemblies by path, eg. System.Runtime.Loader.Tests,
so, just setting it true by default -->
<IncludeSatelliteAssembliesInVFS Condition="'$(IncludeSatelliteAssembliesInVFS)' == ''">true</IncludeSatelliteAssembliesInVFS>

<WasmNativeStrip>false</WasmNativeStrip>
</PropertyGroup>

<PropertyGroup>
Expand Down
4 changes: 4 additions & 0 deletions src/mono/wasm/build/WasmApp.Native.targets
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
<WasmUseEMSDK_PATH Condition="'$(WasmUseEMSDK_PATH)' == '' and '$(EMSDK_PATH)' != '' and Exists('$(MSBuildThisFileDirectory)WasmApp.InTree.targets')">true</WasmUseEMSDK_PATH>
</PropertyGroup>

<ItemGroup>
<UpToDateCheckInput Include="@(NativeFileReference)" />
</ItemGroup>

<ItemGroup Condition="'$(Configuration)' == 'Debug' and '@(_MonoComponent->Count())' == 0">
<_MonoComponent Include="hot_reload;debugger" />
</ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/mono/wasm/build/WasmApp.targets
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@

<Target Name="_InitializeCommonProperties">
<Error Condition="'$(MicrosoftNetCoreAppRuntimePackDir)' == '' and ('%(ResolvedRuntimePack.PackageDirectory)' == '' or !Exists(%(ResolvedRuntimePack.PackageDirectory)))"
Text="Could not find %25(ResolvedRuntimePack.PackageDirectory)=%(ResolvedRuntimePack.PackageDirectory)" />
Text="%24(MicrosoftNetCoreAppRuntimePackDir)='', and cannot find %25(ResolvedRuntimePack.PackageDirectory)=%(ResolvedRuntimePack.PackageDirectory). One of these need to be set to a valid path" />
<Error Condition="'$(IntermediateOutputPath)' == ''" Text="%24(IntermediateOutputPath) property needs to be set" />

<PropertyGroup>
Expand Down
73 changes: 73 additions & 0 deletions src/mono/wasm/sln/WasmBuild.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31722.452
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WasmBuildTasks", "..\..\..\tasks\WasmBuildTasks\WasmBuildTasks.csproj", "{D5BD9C0C-8A05-493E-BE45-13AF8286CD92}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WasmAppBuilder", "..\..\..\tasks\WasmAppBuilder\WasmAppBuilder.csproj", "{8DEBFDE2-B127-46D7-92CF-EEA6D1DA2554}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MonoAOTCompiler", "..\..\..\tasks\AotCompilerTask\MonoAOTCompiler.csproj", "{A9C02284-0387-42E7-BF78-47DF13656D5E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wasm.Build.Tests", "..\..\..\tests\BuildWasmApps\Wasm.Build.Tests\Wasm.Build.Tests.csproj", "{94E18644-B0E5-4DBB-9CE4-EA1515ACE4C2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DebuggerTestSuite", "..\debugger\DebuggerTestSuite\DebuggerTestSuite.csproj", "{4C0EE027-FC30-4167-B2CF-A6D18F00E08F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BrowserDebugHost", "..\debugger\BrowserDebugHost\BrowserDebugHost.csproj", "{292A88FD-795F-467A-8801-B5B791CEF96E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BrowserDebugProxy", "..\debugger\BrowserDebugProxy\BrowserDebugProxy.csproj", "{F5AE2AF5-3C30-45E3-A0C6-D962C51FE5E7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WasmAppHost", "..\host\WasmAppHost.csproj", "{C7099764-EC2E-4FAF-9057-0321893DE4F8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApplyUpdateReferencedAssembly", "..\debugger\tests\ApplyUpdateReferencedAssembly\ApplyUpdateReferencedAssembly.csproj", "{75477B6F-DC8E-4002-88B8-017C992C568E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D5BD9C0C-8A05-493E-BE45-13AF8286CD92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D5BD9C0C-8A05-493E-BE45-13AF8286CD92}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D5BD9C0C-8A05-493E-BE45-13AF8286CD92}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D5BD9C0C-8A05-493E-BE45-13AF8286CD92}.Release|Any CPU.Build.0 = Release|Any CPU
{8DEBFDE2-B127-46D7-92CF-EEA6D1DA2554}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8DEBFDE2-B127-46D7-92CF-EEA6D1DA2554}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8DEBFDE2-B127-46D7-92CF-EEA6D1DA2554}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8DEBFDE2-B127-46D7-92CF-EEA6D1DA2554}.Release|Any CPU.Build.0 = Release|Any CPU
{A9C02284-0387-42E7-BF78-47DF13656D5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A9C02284-0387-42E7-BF78-47DF13656D5E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A9C02284-0387-42E7-BF78-47DF13656D5E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A9C02284-0387-42E7-BF78-47DF13656D5E}.Release|Any CPU.Build.0 = Release|Any CPU
{94E18644-B0E5-4DBB-9CE4-EA1515ACE4C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{94E18644-B0E5-4DBB-9CE4-EA1515ACE4C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{94E18644-B0E5-4DBB-9CE4-EA1515ACE4C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{94E18644-B0E5-4DBB-9CE4-EA1515ACE4C2}.Release|Any CPU.Build.0 = Release|Any CPU
{4C0EE027-FC30-4167-B2CF-A6D18F00E08F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4C0EE027-FC30-4167-B2CF-A6D18F00E08F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4C0EE027-FC30-4167-B2CF-A6D18F00E08F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4C0EE027-FC30-4167-B2CF-A6D18F00E08F}.Release|Any CPU.Build.0 = Release|Any CPU
{292A88FD-795F-467A-8801-B5B791CEF96E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{292A88FD-795F-467A-8801-B5B791CEF96E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{292A88FD-795F-467A-8801-B5B791CEF96E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{292A88FD-795F-467A-8801-B5B791CEF96E}.Release|Any CPU.Build.0 = Release|Any CPU
{F5AE2AF5-3C30-45E3-A0C6-D962C51FE5E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F5AE2AF5-3C30-45E3-A0C6-D962C51FE5E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F5AE2AF5-3C30-45E3-A0C6-D962C51FE5E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F5AE2AF5-3C30-45E3-A0C6-D962C51FE5E7}.Release|Any CPU.Build.0 = Release|Any CPU
{75477B6F-DC8E-4002-88B8-017C992C568E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{75477B6F-DC8E-4002-88B8-017C992C568E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{75477B6F-DC8E-4002-88B8-017C992C568E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{75477B6F-DC8E-4002-88B8-017C992C568E}.Release|Any CPU.Build.0 = Release|Any CPU
{C7099764-EC2E-4FAF-9057-0321893DE4F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C7099764-EC2E-4FAF-9057-0321893DE4F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C7099764-EC2E-4FAF-9057-0321893DE4F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C7099764-EC2E-4FAF-9057-0321893DE4F8}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2BDE8FDE-4261-4B4D-8B54-ACC88B06C8D1}
EndGlobalSection
EndGlobal
1 change: 1 addition & 0 deletions src/mono/wasm/wasm.proj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<EmccCmd>emcc</EmccCmd>
<WasmObjDir>$(ArtifactsObjDir)wasm</WasmObjDir>
<_EmccDefaultsRspPath>$(NativeBinDir)src\emcc-default.rsp</_EmccDefaultsRspPath>
<WasmNativeStrip Condition="'$(ContinuousIntegrationBuild)' == 'true'">false</WasmNativeStrip>
</PropertyGroup>

<Target Name="CheckEnv">
Expand Down
6 changes: 3 additions & 3 deletions src/tasks/AotCompilerTask/MonoAOTCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -744,13 +744,13 @@ private bool PrecompileLibrary(PrecompileArguments args)
Log.LogMessage(importance, $"{msgPrefix}Exec (with response file contents expanded) in {args.WorkingDir}: {envStr}{CompilerBinaryPath} {File.ReadAllText(args.ResponseFilePath)}");
}

Log.LogMessage(importance, output);

if (exitCode != 0)
{
Log.LogError($"Precompiling failed for {assembly}");
Log.LogError($"Precompiling failed for {assembly}.{Environment.NewLine}{output}");
return false;
}

Log.LogMessage(importance, output);
}
catch (Exception ex)
{
Expand Down
64 changes: 59 additions & 5 deletions src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class PInvokeTableGenerator : Task
[Output]
public string FileWrites { get; private set; } = string.Empty;

private static char[] s_charsToReplace = new[] { '.', '-', };
private static char[] s_charsToReplace = new[] { '.', '-', '+' };

public override bool Execute()
{
Expand Down Expand Up @@ -88,7 +88,21 @@ public void GenPInvokeTable(string[] pinvokeModules, string[] assemblies)

private void CollectPInvokes(List<PInvoke> pinvokes, List<PInvokeCallback> callbacks, Type type)
{
foreach (var method in type.GetMethods(BindingFlags.DeclaredOnly|BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static|BindingFlags.Instance)) {
foreach (var method in type.GetMethods(BindingFlags.DeclaredOnly|BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static|BindingFlags.Instance))
{
try
{
CollectPInvokesForMethod(method);
}
catch (Exception ex)
{
Log.LogMessage(MessageImportance.Low, $"Could not get pinvoke, or callbacks for method {method.Name}: {ex}");
continue;
}
}

void CollectPInvokesForMethod(MethodInfo method)
{
if ((method.Attributes & MethodAttributes.PinvokeImpl) != 0)
{
var dllimport = method.CustomAttributes.First(attr => attr.AttributeType.Name == "DllImportAttribute");
Expand Down Expand Up @@ -164,7 +178,8 @@ private void EmitPInvokeTable(StreamWriter w, Dictionary<string, string> modules
Where(l => l.Module == module && !l.Skip).
OrderBy(l => l.EntryPoint).
GroupBy(d => d.EntryPoint).
Select (l => "{\"" + l.Key + "\", " + l.Key + "}, // " + string.Join (", ", l.Select(c => c.Method.DeclaringType!.Module!.Assembly!.GetName ()!.Name!).Distinct().OrderBy(n => n)));
Select (l => "{\"" + FixupSymbolName(l.Key) + "\", " + FixupSymbolName(l.Key) + "}, " +
"// " + string.Join (", ", l.Select(c => c.Method.DeclaringType!.Module!.Assembly!.GetName ()!.Name!).Distinct().OrderBy(n => n)));

foreach (var pinvoke in assemblies_pinvokes) {
w.WriteLine (pinvoke);
Expand Down Expand Up @@ -216,6 +231,45 @@ static bool ShouldTreatAsVariadic(PInvoke[] candidates)
}
}

private static string FixupSymbolName(string name)
{
UTF8Encoding utf8 = new();
byte[] bytes = utf8.GetBytes(name);
StringBuilder sb = new();

foreach (byte b in bytes)
{
if ((b >= (byte)'0' && b <= (byte)'9') ||
(b >= (byte)'a' && b <= (byte)'z') ||
(b >= (byte)'A' && b <= (byte)'Z') ||
(b == (byte)'_'))
{
sb.Append((char) b);
}
else if (s_charsToReplace.Contains((char) b))
{
sb.Append('_');
}
else
{
sb.Append($"_{b:X}_");
}
}

return sb.ToString();
}

private static string SymbolNameForMethod(MethodInfo method)
{
StringBuilder sb = new();
Type? type = method.DeclaringType;
sb.Append($"{type!.Module!.Assembly!.GetName()!.Name!}_");
sb.Append($"{(type!.IsNested ? type!.FullName : type!.Name)}_");
sb.Append(method.Name);

return FixupSymbolName(sb.ToString());
}

private string MapType (Type t)
{
string name = t.Name;
Expand Down Expand Up @@ -262,7 +316,7 @@ private static bool TryIsMethodGetParametersUnsupported(MethodInfo method, [NotN
if (method.Name == "EnumCalendarInfo") {
// FIXME: System.Reflection.MetadataLoadContext can't decode function pointer types
// https://github.com/dotnet/runtime/issues/43791
sb.Append($"int {pinvoke.EntryPoint} (int, int, int, int, int);");
sb.Append($"int {FixupSymbolName(pinvoke.EntryPoint)} (int, int, int, int, int);");
return sb.ToString();
}

Expand All @@ -274,7 +328,7 @@ private static bool TryIsMethodGetParametersUnsupported(MethodInfo method, [NotN
}

sb.Append(MapType(method.ReturnType));
sb.Append($" {pinvoke.EntryPoint} (");
sb.Append($" {FixupSymbolName(pinvoke.EntryPoint)} (");
int pindex = 0;
var pars = method.GetParameters();
foreach (var p in pars) {
Expand Down
57 changes: 32 additions & 25 deletions src/tests/BuildWasmApps/Wasm.Build.Tests/BuildPublishTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,14 @@ public void BuildThenPublishNoAOT(BuildArgs buildArgs, RunHost host, string id)
// no relinking for build
bool relinked = false;
BuildProject(buildArgs,
initProject: () => File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), s_mainReturns42),
dotnetWasmFromRuntimePack: !relinked,
id: id,
createProject: true,
publish: false);
new BuildProjectOptions(
InitProject: () => File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), s_mainReturns42),
DotnetWasmFromRuntimePack: !relinked,
CreateProject: true,
Publish: false
));


Run();

Expand All @@ -53,10 +56,11 @@ public void BuildThenPublishNoAOT(BuildArgs buildArgs, RunHost host, string id)
relinked = buildArgs.Config == "Release";
BuildProject(buildArgs,
id: id,
dotnetWasmFromRuntimePack: !relinked,
createProject: false,
publish: true,
useCache: false);
new BuildProjectOptions(
DotnetWasmFromRuntimePack: !relinked,
CreateProject: false,
Publish: true,
UseCache: false));

Run();

Expand All @@ -79,12 +83,13 @@ public void BuildThenPublishWithAOT(BuildArgs buildArgs, RunHost host, string id
// no relinking for build
bool relinked = false;
(_, string output) = BuildProject(buildArgs,
initProject: () => File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), s_mainReturns42),
dotnetWasmFromRuntimePack: !relinked,
id: id,
createProject: true,
publish: false,
label: "first_build");
id,
new BuildProjectOptions(
InitProject: () => File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), s_mainReturns42),
DotnetWasmFromRuntimePack: !relinked,
CreateProject: true,
Publish: false,
Label: "first_build"));

BuildPaths paths = GetBuildPaths(buildArgs);
var pathsDict = GetFilesTable(buildArgs, paths, unchanged: false);
Expand All @@ -109,11 +114,12 @@ public void BuildThenPublishWithAOT(BuildArgs buildArgs, RunHost host, string id
// relink by default for Release+publish
(_, output) = BuildProject(buildArgs,
id: id,
dotnetWasmFromRuntimePack: false,
createProject: false,
publish: true,
useCache: false,
label: "first_publish");
new BuildProjectOptions(
DotnetWasmFromRuntimePack: false,
CreateProject: false,
Publish: true,
UseCache: false,
Label: "first_publish"));

var publishStat = StatFiles(pathsDict.Select(kvp => kvp.Value.fullPath));
Assert.True(publishStat["pinvoke.o"].Exists);
Expand All @@ -125,12 +131,13 @@ public void BuildThenPublishWithAOT(BuildArgs buildArgs, RunHost host, string id

// second build
(_, output) = BuildProject(buildArgs,
initProject: () => File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), s_mainReturns42),
dotnetWasmFromRuntimePack: !relinked,
id: id,
createProject: true,
publish: false,
label: "second_build");
id: id,
new BuildProjectOptions(
InitProject: () => File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), s_mainReturns42),
DotnetWasmFromRuntimePack: !relinked,
CreateProject: true,
Publish: false,
Label: "second_build"));
var secondBuildStat = StatFiles(pathsDict.Select(kvp => kvp.Value.fullPath));

// no relinking, or AOT
Expand Down
Loading