diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs index 55e93530680f41..6353d154389204 100644 --- a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs +++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs @@ -243,6 +243,7 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task private FileCache? _cache; private int _numCompiled; private int _totalNumAssemblies; + private readonly Dictionary _symbolNameFixups = new(); private bool ProcessAndValidateArguments() { @@ -928,7 +929,7 @@ private bool GenerateAotModulesTable(IEnumerable assemblies, string[] if (!TryGetAssemblyName(asmPath, out string? assemblyName)) return false; - string symbolName = assemblyName.Replace ('.', '_').Replace ('-', '_').Replace(' ', '_'); + string symbolName = FixupSymbolName(assemblyName); symbols.Add($"mono_aot_module_{symbolName}_info"); } @@ -1042,6 +1043,35 @@ private static IList ConvertAssembliesDictToOrderedList(ConcurrentDic return outItems; } + private string FixupSymbolName(string name) + { + if (_symbolNameFixups.TryGetValue(name, out string? fixedName)) + return fixedName; + + 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 + { + sb.Append('_'); + } + } + + fixedName = sb.ToString(); + _symbolNameFixups[name] = fixedName; + return fixedName; + } + internal sealed class PrecompileArguments { public PrecompileArguments(string ResponseFilePath, IDictionary EnvironmentVariables, string WorkingDir, ITaskItem AOTAssembly, IList ProxyFiles) diff --git a/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildPublishTests.cs b/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildPublishTests.cs index 66fed9a630d16b..79477a42cce280 100644 --- a/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildPublishTests.cs +++ b/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildPublishTests.cs @@ -70,11 +70,15 @@ void Run() => RunAndTestWasmApp( } [Theory] - [BuildAndRun(host: RunHost.Chrome, aot: true, config: "Release")] - [BuildAndRun(host: RunHost.Chrome, aot: true, config: "Debug")] - public void BuildThenPublishWithAOT(BuildArgs buildArgs, RunHost host, string id) + [BuildAndRun(host: RunHost.Chrome, aot: true, config: "Release", testUnicode: false)] + [BuildAndRun(host: RunHost.Chrome, aot: true, config: "Debug", testUnicode: false)] + [BuildAndRun(host: RunHost.Chrome, aot: true, config: "Release", testUnicode: true)] + [BuildAndRun(host: RunHost.Chrome, aot: true, config: "Debug", testUnicode: true)] + public void BuildThenPublishWithAOT(BuildArgs buildArgs, RunHost host, string id, bool testUnicode) { - string projectName = $"build_publish_{buildArgs.Config}"; + string projectName = testUnicode ? + $"build_publish_{buildArgs.Config}_{s_unicodeChar}" : + $"build_publish_{buildArgs.Config}"; buildArgs = buildArgs with { ProjectName = projectName }; buildArgs = ExpandBuildArgs(buildArgs, extraProperties: "<_WasmDevel>true"); @@ -109,8 +113,13 @@ public void BuildThenPublishWithAOT(BuildArgs buildArgs, RunHost host, string id _testOutput.WriteLine($"{Environment.NewLine}Publishing with no changes ..{Environment.NewLine}"); - // relink by default for Release+publish - (_, output) = BuildProject(buildArgs, + // FIXME: relinking for paths with unicode does not work: + // [ActiveIssue("https://github.com/dotnet/runtime/issues/83497")] + // remove the condition when the issue is fixed + if (!testUnicode) + { + // relink by default for Release+publish + (_, output) = BuildProject(buildArgs, id: id, new BuildProjectOptions( DotnetWasmFromRuntimePack: false, @@ -119,13 +128,14 @@ public void BuildThenPublishWithAOT(BuildArgs buildArgs, RunHost host, string id UseCache: false, Label: "first_publish")); - var publishStat = StatFiles(pathsDict.Select(kvp => kvp.Value.fullPath)); - Assert.True(publishStat["pinvoke.o"].Exists); - Assert.True(publishStat[$"{mainDll}.bc"].Exists); - CheckOutputForNativeBuild(expectAOT: true, expectRelinking: false, buildArgs, output); - CompareStat(firstBuildStat, publishStat, pathsDict.Values); + var publishStat = StatFiles(pathsDict.Select(kvp => kvp.Value.fullPath)); + Assert.True(publishStat["pinvoke.o"].Exists); + Assert.True(publishStat[$"{mainDll}.bc"].Exists); + CheckOutputForNativeBuild(expectAOT: true, expectRelinking: false, buildArgs, output); + CompareStat(firstBuildStat, publishStat, pathsDict.Values); - Run(expectAOT: true); + Run(expectAOT: true); + } // second build (_, output) = BuildProject(buildArgs, @@ -143,7 +153,10 @@ public void BuildThenPublishWithAOT(BuildArgs buildArgs, RunHost host, string id // no native files changed pathsDict.UpdateTo(unchanged: true); - CompareStat(publishStat, secondBuildStat, pathsDict.Values); + if (!testUnicode) + { + CompareStat(publishStat, secondBuildStat, pathsDict.Values); + } void Run(bool expectAOT) => RunAndTestWasmApp( buildArgs with { AOT = expectAOT },