Skip to content

Commit 0d862de

Browse files
authored
Merge pull request #903 from unoplatform/dev/jela/cache-break
fix: Restore cache breaking
2 parents 2aa82e3 + ca336cc commit 0d862de

13 files changed

+453
-362
lines changed

.vsts-ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,4 @@ stages:
5353
- template: build/ci/stage-build-macos-tests.yml
5454
parameters:
5555
jobName: macOS_Tests
56-
vmImage: macOS-12
56+
vmImage: macOS-14

src/Uno.Wasm.Bootstrap/WasmScripts/service-worker.js renamed to src/Uno.Wasm.Bootstrap/Embedded/service-worker.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { config as unoConfig } from "$(REMOTE_WEBAPP_PATH)uno-config.js";
1+
import { config as unoConfig } from "$(REMOTE_WEBAPP_PATH)$(REMOTE_BASE_PATH)/uno-config.js";
22

33

44
if (unoConfig.environmentVariables["UNO_BOOTSTRAP_DEBUGGER_ENABLED"] !== "True") {
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Text;
5+
using Microsoft.Build.Framework;
6+
7+
namespace Uno.Wasm.Bootstrap.Extensions;
8+
9+
internal static class TaskItemExtensions
10+
{
11+
public static (string fullPath, string relativePath) GetFilePaths(this ITaskItem item, Microsoft.Build.Utilities.TaskLoggingHelper log, string currentProjectPath)
12+
{
13+
if (item.GetMetadata("RelativePath") is { } relativePath && !string.IsNullOrEmpty(relativePath))
14+
{
15+
log.LogMessage(MessageImportance.Low, $"RelativePath '{relativePath}' for full path '{item.GetMetadata("FullPath")}' (ItemSpec: {item.ItemSpec})");
16+
17+
// This case is mainly for shared projects and files out of the baseSourceFile path
18+
return (item.GetMetadata("FullPath"), relativePath);
19+
}
20+
else if (item.GetMetadata("TargetPath") is { } targetPath && !string.IsNullOrEmpty(targetPath))
21+
{
22+
log.LogMessage(MessageImportance.Low, $"TargetPath '{targetPath}' for full path '{item.GetMetadata("FullPath")}' (ItemSpec: {item.ItemSpec})");
23+
24+
// This is used for item remapping
25+
return (item.GetMetadata("FullPath"), targetPath);
26+
}
27+
else if (item.GetMetadata("Link") is { } link && !string.IsNullOrEmpty(link))
28+
{
29+
log.LogMessage(MessageImportance.Low, $"Link '{link}' for full path '{item.GetMetadata("FullPath")}' (ItemSpec: {item.ItemSpec})");
30+
31+
// This case is mainly for shared projects and files out of the baseSourceFile path
32+
return (item.GetMetadata("FullPath"), link);
33+
}
34+
else if (item.GetMetadata("FullPath") is { } fullPath && File.Exists(fullPath))
35+
{
36+
log.LogMessage(MessageImportance.Low, $"FullPath '{fullPath}' (ItemSpec: {item.ItemSpec})");
37+
38+
var sourceFilePath = item.ItemSpec;
39+
40+
if (sourceFilePath.StartsWith(currentProjectPath))
41+
{
42+
// This is for files added explicitly through other targets (e.g. Microsoft.TypeScript.MSBuild)
43+
return (fullPath: fullPath, sourceFilePath.Replace(currentProjectPath + Path.DirectorySeparatorChar, ""));
44+
}
45+
else
46+
{
47+
return (fullPath, sourceFilePath);
48+
}
49+
}
50+
else
51+
{
52+
log.LogMessage(MessageImportance.Low, $"Without metadata '{item.GetMetadata("FullPath")}' (ItemSpec: {item.ItemSpec})");
53+
54+
return (item.GetMetadata("FullPath"), item.ItemSpec);
55+
}
56+
}
57+
58+
}

src/Uno.Wasm.Bootstrap/GenerateUnoAssetsManifestTask.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ public class GenerateUnoAssetsManifest_v0 : Microsoft.Build.Utilities.Task
4242
[Required]
4343
public string IntermediateOutputPath { get; set; } = "";
4444

45+
[Required]
46+
public string OutputPackagePath { get; set; } = "";
47+
4548
[Output]
4649
public ITaskItem[] UnoAssetsFile { get; set; } = [];
4750

@@ -76,7 +79,7 @@ private void AddStaticAsset(string targetPath, string filePath)
7679
{
7780
["CopyToOutputDirectory"] = "PreserveNewest",
7881
["ContentRoot"] = contentRoot,
79-
["Link"] = "wwwroot/" + targetPath,
82+
["Link"] = $"wwwroot/{OutputPackagePath}/" + targetPath,
8083
});
8184

8285
UnoAssetsFile = UnoAssetsFile.Concat([indexMetadata]).ToArray();
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
// ******************************************************************
2+
// Copyright � 2015-2022 Uno Platform inc. All rights reserved.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
// ******************************************************************
17+
//
18+
// This file is based on the work from https://github.com/praeclarum/Ooui
19+
//
20+
using System;
21+
using System.Collections.Generic;
22+
using System.Collections.Immutable;
23+
using System.Diagnostics;
24+
using System.IO;
25+
using System.IO.Compression;
26+
using System.Linq;
27+
using System.Net;
28+
using System.Runtime.InteropServices;
29+
using System.Security;
30+
using System.Security.Cryptography;
31+
using System.Text;
32+
using System.Text.RegularExpressions;
33+
using System.Transactions;
34+
using Microsoft.Build.Framework;
35+
using Microsoft.Win32.SafeHandles;
36+
using Mono.Cecil;
37+
using Mono.CompilerServices.SymbolWriter;
38+
using Newtonsoft.Json.Linq;
39+
using Uno.Wasm.Bootstrap.Extensions;
40+
41+
namespace Uno.Wasm.Bootstrap;
42+
43+
public partial class GenerateUnoNativeAssetsTask_v0
44+
{
45+
/// <summary>
46+
/// Applies a temporary workaround for https://github.com/mono/mono/issues/19824
47+
/// </summary>
48+
private string? TransformAOTProfile()
49+
{
50+
var profilePath = AotProfile;
51+
52+
if (profilePath != null)
53+
{
54+
var reader = new Mono.Profiler.Aot.ProfileReader();
55+
Mono.Profiler.Aot.ProfileData profile;
56+
using (FileStream stream = File.OpenRead(profilePath))
57+
{
58+
profile = reader.ReadAllData(stream);
59+
}
60+
61+
var excludedMethodsList = AOTProfileExcludedMethods
62+
.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)
63+
.ToList();
64+
65+
var excludedAssemblies = MixedModeExcludedAssembly?.ToDictionary(i => i.ItemSpec, i => i.ItemSpec)
66+
?? new Dictionary<string, string>();
67+
68+
if (excludedMethodsList.Any() || excludedAssemblies.Any())
69+
{
70+
// LoadIntoBufferAsync uses exception filtering
71+
excludedMethodsList.AddRange(DefaultAOTProfileExcludedMethods);
72+
73+
TryDumpProfileMethods(profile, "AOTProfileDump.Original.txt");
74+
75+
var excludedMethods = excludedMethodsList.Select(e => new Regex(e)).ToList();
76+
77+
var q = from m in profile.Methods
78+
where !excludedMethods.Any(e => e.Match(m.Type.FullName + '.' + m.Name).Success)
79+
&& !excludedAssemblies.ContainsKey(m.Type.Module.Name)
80+
select m;
81+
82+
profile.Methods = q.ToArray();
83+
84+
TryDumpProfileMethods(profile, "AOTProfileDump.Filtered.txt");
85+
86+
var writer = new Mono.Profiler.Aot.ProfileWriter();
87+
88+
var outputFile = Path.Combine(IntermediateOutputPath, "aot-filtered.profile");
89+
using (var outStream = File.Create(outputFile))
90+
{
91+
writer.WriteAllData(outStream, profile);
92+
}
93+
94+
return outputFile;
95+
}
96+
}
97+
98+
return profilePath;
99+
}
100+
101+
private IEnumerable<string> DefaultAOTProfileExcludedMethods =>
102+
new[]
103+
{
104+
@"ManifestBasedResourceGroveler\.InternalGetSatelliteAssembly", // https://github.com/dotnet/runtime/issues/45698
105+
106+
@"System\.Reflection\.Assembly\.GetExecutingAssembly", // https://github.com/dotnet/runtime/issues/47996
107+
@"System\.RuntimeType\.GetType",
108+
@"System\.RuntimeTypeHandle\.internal_from_name",
109+
@"System\.RuntimeTypeHandle\.GetTypeByName",
110+
@"System\.Type\.GetType",
111+
@"System\.Runtime\.Loader\.AssemblyLoadContext\.InternalLoadFromPath",
112+
@"System\.Runtime\.Loader\.AssemblyLoadContext\.InternalLoadFile",
113+
@"System\.Runtime\.Loader\.AssemblyLoadContext\.LoadFromAssemblyName",
114+
@"System\.Reflection\.Assembly\.Load",
115+
@"System\.Reflection\.Assembly\.InternalLoad",
116+
@"System\.Reflection\.RuntimeAssembly\.InternalGetSatelliteAssembly",
117+
@"System\.Reflection\.RuntimeAssembly\.InternalLoad",
118+
};
119+
120+
private void TryDumpProfileMethods(Mono.Profiler.Aot.ProfileData profile, string filePath)
121+
{
122+
if (GenerateAOTProfileDebugList)
123+
{
124+
var sb = new StringBuilder();
125+
126+
foreach (var method in profile.Methods)
127+
{
128+
var genericParameters = string.Join("|", method.GenericInst?.Types.Select(t => t.ToString()) ?? []);
129+
130+
sb.AppendLine($"{method.Type.Module.Name};{method.Type.FullName}.{method.Name};{method.GenericInst?.Id};{genericParameters}");
131+
}
132+
133+
File.WriteAllText(Path.Combine(IntermediateOutputPath, filePath), sb.ToString());
134+
}
135+
}
136+
137+
private bool UseAotProfile
138+
=> !string.IsNullOrEmpty(AotProfile) && _runtimeExecutionMode == RuntimeExecutionMode.InterpreterAndAOT;
139+
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+

2+
// ******************************************************************
3+
// Copyright � 2015-2022 Uno Platform inc. All rights reserved.
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
//
17+
// ******************************************************************
18+
//
19+
// This file is based on the work from https://github.com/praeclarum/Ooui
20+
//
21+
using System;
22+
using System.Collections.Generic;
23+
using System.Diagnostics;
24+
using System.IO;
25+
using System.Linq;
26+
using System.Numerics;
27+
using System.Runtime.InteropServices;
28+
using System.Security.Cryptography;
29+
using Microsoft.Build.Framework;
30+
using Microsoft.Build.Utilities;
31+
using Uno.Wasm.Bootstrap.Extensions;
32+
33+
namespace Uno.Wasm.Bootstrap;
34+
35+
public partial class GenerateUnoNativeAssetsTask_v0 : Microsoft.Build.Utilities.Task
36+
{
37+
private RuntimeExecutionMode _runtimeExecutionMode;
38+
39+
public string AotProfile { get; set; } = "";
40+
41+
public bool GenerateAOTProfile { get; set; }
42+
43+
public string AOTProfileExcludedMethods { get; set; } = "";
44+
45+
public bool GenerateAOTProfileDebugList { get; set; } = false;
46+
47+
public bool WasmBuildNative { get; set; }
48+
49+
public bool RunAOTCompilation { get; set; }
50+
51+
public Microsoft.Build.Framework.ITaskItem[]? MixedModeExcludedAssembly { get; set; }
52+
53+
public bool EnableThreads { get; set; }
54+
55+
public ITaskItem[]? Assets { get; set; }
56+
57+
public string EmscriptenVersion { get; set; } = "";
58+
59+
[Required]
60+
public string IntermediateOutputPath { get; set; } = "";
61+
62+
[Required]
63+
public string CurrentProjectPath { get; set; } = "";
64+
65+
[Output]
66+
public ITaskItem[] NativeFileReference { get; set; } = [];
67+
68+
[Output]
69+
public string? FilteredAotProfile { get; set; } = "";
70+
71+
public override bool Execute()
72+
{
73+
ParseProperties();
74+
GenerateBitcodeFiles();
75+
BuildAOTProfile();
76+
77+
return true;
78+
}
79+
80+
private void ParseProperties()
81+
=> _runtimeExecutionMode
82+
= WasmBuildNative && RunAOTCompilation ? RuntimeExecutionMode.InterpreterAndAOT : RuntimeExecutionMode.Interpreter;
83+
84+
private void BuildAOTProfile()
85+
{
86+
var useAotProfile = !GenerateAOTProfile && UseAotProfile;
87+
88+
if (useAotProfile)
89+
{
90+
// If the profile was transformed, we need to use the transformed profile
91+
FilteredAotProfile = TransformAOTProfile();
92+
}
93+
}
94+
private void GenerateBitcodeFiles()
95+
{
96+
var bitcodeFiles = Assets
97+
?.Where(a => a.ItemSpec.EndsWith(".o") || a.ItemSpec.EndsWith(".a"))
98+
.Where(a => !bool.TryParse(a.GetMetadata("UnoAotCompile"), out var compile) || compile)
99+
.Select(a => a.GetFilePaths(Log, CurrentProjectPath).fullPath)
100+
.ToArray()
101+
?? [];
102+
103+
List<string> features = new()
104+
{
105+
EnableThreads ? "mt" : "st",
106+
"simd"
107+
};
108+
109+
Log.LogMessage(MessageImportance.Low, $"Bitcode files features lookup filter: {string.Join(",", features)}");
110+
111+
if (Version.TryParse(EmscriptenVersion, out var emsdkVersion))
112+
{
113+
var list = BitcodeFilesSelector.Filter(emsdkVersion, features.ToArray(), bitcodeFiles);
114+
115+
NativeFileReference = list.Select(i => new TaskItem(i)).ToArray();
116+
}
117+
else
118+
{
119+
Log.LogMessage(MessageImportance.Low, $"EmscriptenVersion is not set, skipping native assets");
120+
}
121+
}
122+
123+
}

src/Uno.Wasm.Bootstrap/RemoveDirTask.cs

Lines changed: 0 additions & 43 deletions
This file was deleted.

0 commit comments

Comments
 (0)