Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src/tasks
diff options
context:
space:
mode:
authorAnkit Jain <radical@gmail.com>2021-09-15 16:16:48 +0300
committerGitHub <noreply@github.com>2021-09-15 16:16:48 +0300
commitf38d58f1b1abc1b2c394481236f5cbcaaaf24545 (patch)
tree1491c953831e589a96d760d6854e993eb09dd9a8 /src/tasks
parente72aafc9b51cf2c0a59608a8a73bf1b9cffd8753 (diff)
[release/6.0][wasm] Add support for native relinking after Build, and AOT after publish (#58913)
Diffstat (limited to 'src/tasks')
-rw-r--r--src/tasks/AotCompilerTask/MonoAOTCompiler.cs190
-rw-r--r--src/tasks/Common/Utils.cs2
-rw-r--r--src/tasks/WasmAppBuilder/EmccCompile.cs19
-rw-r--r--src/tasks/WasmAppBuilder/IcallTableGenerator.cs4
-rw-r--r--src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs42
-rw-r--r--src/tasks/WasmAppBuilder/WasmAppBuilder.cs25
-rw-r--r--src/tasks/WasmAppBuilder/WasmAppBuilder.csproj1
7 files changed, 203 insertions, 80 deletions
diff --git a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs
index 71ae231a0fb..4ee7389c04d 100644
--- a/src/tasks/AotCompilerTask/MonoAOTCompiler.cs
+++ b/src/tasks/AotCompilerTask/MonoAOTCompiler.cs
@@ -191,11 +191,15 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
/// </summary>
public string? CacheFilePath { get; set; }
+ [Required]
+ public string IntermediateOutputPath { get; set; } = string.Empty;
+
[Output]
public string[]? FileWrites { get; private set; }
private List<string> _fileWrites = new();
+ private IList<ITaskItem>? _assembliesToCompile;
private ConcurrentDictionary<string, ITaskItem> compiledAssemblies = new();
private MonoAotMode parsedAotMode;
@@ -207,7 +211,7 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
private int _numCompiled;
private int _totalNumAssemblies;
- public override bool Execute()
+ private bool ProcessAndValidateArguments()
{
if (!File.Exists(CompilerBinaryPath))
{
@@ -230,6 +234,9 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
return false;
}
+ if (!Directory.Exists(IntermediateOutputPath))
+ Directory.CreateDirectory(IntermediateOutputPath);
+
if (AotProfilePath != null)
{
foreach (var path in AotProfilePath)
@@ -246,7 +253,7 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
{
if (string.IsNullOrEmpty(LLVMPath))
// prevent using some random llc/opt from PATH (installed with clang)
- throw new ArgumentException($"'{nameof(LLVMPath)}' is required when '{nameof(UseLLVM)}' is true.", nameof(LLVMPath));
+ throw new LogAsErrorException($"'{nameof(LLVMPath)}' is required when '{nameof(UseLLVM)}' is true.");
if (!Directory.Exists(LLVMPath))
{
@@ -270,7 +277,7 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
Log.LogWarning($"'{nameof(OutputType)}=Normal' is deprecated, use 'ObjectFile' instead.");
parsedOutputType = MonoAotOutputType.ObjectFile; break;
default:
- throw new ArgumentException($"'{nameof(OutputType)}' must be one of: '{nameof(MonoAotOutputType.ObjectFile)}', '{nameof(MonoAotOutputType.AsmOnly)}', '{nameof(MonoAotOutputType.Library)}'. Received: '{OutputType}'.", nameof(OutputType));
+ throw new LogAsErrorException($"'{nameof(OutputType)}' must be one of: '{nameof(MonoAotOutputType.ObjectFile)}', '{nameof(MonoAotOutputType.AsmOnly)}', '{nameof(MonoAotOutputType.Library)}'. Received: '{OutputType}'.");
}
switch (LibraryFormat)
@@ -280,13 +287,13 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
case "So": parsedLibraryFormat = MonoAotLibraryFormat.So; break;
default:
if (parsedOutputType == MonoAotOutputType.Library)
- throw new ArgumentException($"'{nameof(LibraryFormat)}' must be one of: '{nameof(MonoAotLibraryFormat.Dll)}', '{nameof(MonoAotLibraryFormat.Dylib)}', '{nameof(MonoAotLibraryFormat.So)}'. Received: '{LibraryFormat}'.", nameof(LibraryFormat));
+ throw new LogAsErrorException($"'{nameof(LibraryFormat)}' must be one of: '{nameof(MonoAotLibraryFormat.Dll)}', '{nameof(MonoAotLibraryFormat.Dylib)}', '{nameof(MonoAotLibraryFormat.So)}'. Received: '{LibraryFormat}'.");
break;
}
if (parsedAotMode == MonoAotMode.LLVMOnly && !UseLLVM)
{
- throw new ArgumentException($"'{nameof(UseLLVM)}' must be true when '{nameof(Mode)}' is {nameof(MonoAotMode.LLVMOnly)}.", nameof(UseLLVM));
+ throw new LogAsErrorException($"'{nameof(UseLLVM)}' must be true when '{nameof(Mode)}' is {nameof(MonoAotMode.LLVMOnly)}.");
}
switch (AotModulesTableLanguage)
@@ -294,32 +301,55 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
case "C": parsedAotModulesTableLanguage = MonoAotModulesTableLanguage.C; break;
case "ObjC": parsedAotModulesTableLanguage = MonoAotModulesTableLanguage.ObjC; break;
default:
- throw new ArgumentException($"'{nameof(AotModulesTableLanguage)}' must be one of: '{nameof(MonoAotModulesTableLanguage.C)}', '{nameof(MonoAotModulesTableLanguage.ObjC)}'. Received: '{AotModulesTableLanguage}'.", nameof(AotModulesTableLanguage));
+ throw new LogAsErrorException($"'{nameof(AotModulesTableLanguage)}' must be one of: '{nameof(MonoAotModulesTableLanguage.C)}', '{nameof(MonoAotModulesTableLanguage.ObjC)}'. Received: '{AotModulesTableLanguage}'.");
}
if (!string.IsNullOrEmpty(AotModulesTablePath))
{
// AOT modules for static linking, needs the aot modules table
UseStaticLinking = true;
-
- if (!GenerateAotModulesTable(Assemblies, Profilers, AotModulesTablePath))
- return false;
}
if (UseDirectIcalls && !UseStaticLinking)
{
- throw new ArgumentException($"'{nameof(UseDirectIcalls)}' can only be used with '{nameof(UseStaticLinking)}=true'.", nameof(UseDirectIcalls));
+ throw new LogAsErrorException($"'{nameof(UseDirectIcalls)}' can only be used with '{nameof(UseStaticLinking)}=true'.");
}
if (UseDirectPInvoke && !UseStaticLinking)
{
- throw new ArgumentException($"'{nameof(UseDirectPInvoke)}' can only be used with '{nameof(UseStaticLinking)}=true'.", nameof(UseDirectPInvoke));
+ throw new LogAsErrorException($"'{nameof(UseDirectPInvoke)}' can only be used with '{nameof(UseStaticLinking)}=true'.");
}
if (UseStaticLinking && (parsedOutputType == MonoAotOutputType.Library))
{
- throw new ArgumentException($"'{nameof(OutputType)}=Library' can not be used with '{nameof(UseStaticLinking)}=true'.", nameof(OutputType));
+ throw new LogAsErrorException($"'{nameof(OutputType)}=Library' can not be used with '{nameof(UseStaticLinking)}=true'.");
+ }
+
+ return !Log.HasLoggedErrors;
+ }
+
+ public override bool Execute()
+ {
+ try
+ {
+ return ExecuteInternal();
+ }
+ catch (LogAsErrorException laee)
+ {
+ Log.LogError(laee.Message);
+ return false;
}
+ }
+
+ private bool ExecuteInternal()
+ {
+ if (!ProcessAndValidateArguments())
+ return false;
+
+ _assembliesToCompile = EnsureAndGetAssembliesInTheSameDir(Assemblies);
+
+ if (!string.IsNullOrEmpty(AotModulesTablePath) && !GenerateAotModulesTable(_assembliesToCompile, Profilers, AotModulesTablePath))
+ return false;
string? monoPaths = null;
if (AdditionalAssemblySearchPaths != null)
@@ -329,14 +359,14 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
//FIXME: check the nothing changed at all case
- _totalNumAssemblies = Assemblies.Length;
- int allowedParallelism = Math.Min(Assemblies.Length, Environment.ProcessorCount);
+ _totalNumAssemblies = _assembliesToCompile.Count;
+ int allowedParallelism = Math.Min(_assembliesToCompile.Count, Environment.ProcessorCount);
if (BuildEngine is IBuildEngine9 be9)
allowedParallelism = be9.RequestCores(allowedParallelism);
if (DisableParallelAot || allowedParallelism == 1)
{
- foreach (var assemblyItem in Assemblies)
+ foreach (var assemblyItem in _assembliesToCompile)
{
if (!PrecompileLibrarySerial(assemblyItem, monoPaths))
return !Log.HasLoggedErrors;
@@ -345,15 +375,12 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
else
{
ParallelLoopResult result = Parallel.ForEach(
- Assemblies,
+ _assembliesToCompile,
new ParallelOptions { MaxDegreeOfParallelism = allowedParallelism },
(assemblyItem, state) => PrecompileLibraryParallel(assemblyItem, monoPaths, state));
if (!result.IsCompleted)
{
- if (!Log.HasLoggedErrors)
- Log.LogError("Unknown failure occured while compiling");
-
return false;
}
}
@@ -365,15 +392,71 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
if (_cache.Save(CacheFilePath!))
_fileWrites.Add(CacheFilePath!);
- CompiledAssemblies = ConvertAssembliesDictToOrderedList(compiledAssemblies, Assemblies).ToArray();
+ CompiledAssemblies = ConvertAssembliesDictToOrderedList(compiledAssemblies, _assembliesToCompile).ToArray();
FileWrites = _fileWrites.ToArray();
return !Log.HasLoggedErrors;
}
+ private IList<ITaskItem> EnsureAndGetAssembliesInTheSameDir(ITaskItem[] originalAssemblies)
+ {
+ List<ITaskItem> filteredAssemblies = new();
+ string firstAsmDir = Path.GetDirectoryName(originalAssemblies[0].GetMetadata("FullPath")) ?? string.Empty;
+ bool allInSameDir = true;
+
+ foreach (var origAsm in originalAssemblies)
+ {
+ if (allInSameDir && Path.GetDirectoryName(origAsm.GetMetadata("FullPath")) != firstAsmDir)
+ allInSameDir = false;
+
+ if (ShouldSkip(origAsm))
+ {
+ if (parsedAotMode == MonoAotMode.LLVMOnly)
+ throw new LogAsErrorException($"Building in AOTMode=LLVMonly is not compatible with excluding any assemblies for AOT. Excluded assembly: {origAsm.ItemSpec}");
+
+ Log.LogMessage(MessageImportance.Low, $"Skipping {origAsm.ItemSpec} because it has %(AOT_InternalForceToInterpret)=true");
+ continue;
+ }
+
+ filteredAssemblies.Add(origAsm);
+ }
+
+ if (allInSameDir)
+ return filteredAssemblies;
+
+ // Copy to aot-in
+
+ string aotInPath = Path.Combine(IntermediateOutputPath, "aot-in");
+ Directory.CreateDirectory(aotInPath);
+
+ List<ITaskItem> newAssemblies = new();
+ foreach (var origAsm in originalAssemblies)
+ {
+ string asmPath = origAsm.GetMetadata("FullPath");
+ string newPath = Path.Combine(aotInPath, Path.GetFileName(asmPath));
+
+ // FIXME: delete files not in originalAssemblies though
+ // FIXME: or .. just delete the whole dir?
+ if (Utils.CopyIfDifferent(asmPath, newPath, useHash: true))
+ Log.LogMessage(MessageImportance.Low, $"Copying {asmPath} to {newPath}");
+
+ if (!ShouldSkip(origAsm))
+ {
+ ITaskItem newAsm = new TaskItem(newPath);
+ origAsm.CopyMetadataTo(newAsm);
+ newAssemblies.Add(newAsm);
+ }
+ }
+
+ return newAssemblies;
+
+ static bool ShouldSkip(ITaskItem asmItem)
+ => bool.TryParse(asmItem.GetMetadata("AOT_InternalForceToInterpret"), out bool skip) && skip;
+ }
+
private bool PrecompileLibrary(ITaskItem assemblyItem, string? monoPaths)
{
- string assembly = assemblyItem.ItemSpec;
+ string assembly = assemblyItem.GetMetadata("FullPath");
string assemblyDir = Path.GetDirectoryName(assembly)!;
var aotAssembly = new TaskItem(assembly);
var aotArgs = new List<string>();
@@ -567,38 +650,20 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
// values, which wont work.
processArgs.Add($"\"--aot={string.Join(",", aotArgs)}\"");
- string paths = "";
if (isDedup)
{
- StringBuilder sb = new StringBuilder();
- HashSet<string> allPaths = new HashSet<string>();
- foreach (var aItem in Assemblies)
- {
- string filename = aItem.ItemSpec;
- processArgs.Add(filename);
- string dir = Path.GetDirectoryName(filename)!;
- if (!allPaths.Contains(dir))
- {
- allPaths.Add(dir);
- if (sb.Length > 0)
- sb.Append(Path.PathSeparator);
- sb.Append(dir);
- }
- }
- if (sb.Length > 0)
- sb.Append(Path.PathSeparator);
- sb.Append(monoPaths);
- paths = sb.ToString();
+ foreach (var aItem in _assembliesToCompile!)
+ processArgs.Add(aItem.ItemSpec);
}
else
{
- paths = $"{assemblyDir}{Path.PathSeparator}{monoPaths}";
processArgs.Add('"' + assemblyFilename + '"');
}
+ monoPaths = $"{assemblyDir}{Path.PathSeparator}{monoPaths}";
var envVariables = new Dictionary<string, string>
{
- {"MONO_PATH", paths},
+ {"MONO_PATH", monoPaths },
{"MONO_ENV_OPTIONS", string.Empty} // we do not want options to be provided out of band to the cross compilers
};
@@ -713,7 +778,7 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
state.Break();
}
- private bool GenerateAotModulesTable(ITaskItem[] assemblies, string[]? profilers, string outputFile)
+ private bool GenerateAotModulesTable(IEnumerable<ITaskItem> assemblies, string[]? profilers, string outputFile)
{
var symbols = new List<string>();
foreach (var asm in assemblies)
@@ -831,12 +896,12 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
}
}
- private IList<ITaskItem> ConvertAssembliesDictToOrderedList(ConcurrentDictionary<string, ITaskItem> dict, ITaskItem[] items)
+ private static IList<ITaskItem> ConvertAssembliesDictToOrderedList(ConcurrentDictionary<string, ITaskItem> dict, IList<ITaskItem> originalAssemblies)
{
- List<ITaskItem> outItems = new(items.Length);
- foreach (ITaskItem item in items)
+ List<ITaskItem> outItems = new(originalAssemblies.Count);
+ foreach (ITaskItem item in originalAssemblies)
{
- if (!dict.TryGetValue(item.ItemSpec, out ITaskItem? dictItem))
+ if (!dict.TryGetValue(item.GetMetadata("FullPath"), out ITaskItem? dictItem))
throw new LogAsErrorException($"Bug: Could not find item in the dict with key {item.ItemSpec}");
outItems.Add(dictItem);
@@ -931,23 +996,26 @@ internal class ProxyFile
if (!_cache.Enabled)
return true;
- if (!File.Exists(TempFile))
- throw new LogAsErrorException($"Could not find output file {TempFile}");
-
- if (!_cache.ShouldCopy(this, out string? cause))
+ try
{
- _cache.Log.LogMessage(MessageImportance.Low, $"Skipping copying over {TargetFile} as the contents are unchanged");
- return false;
- }
+ if (!_cache.ShouldCopy(this, out string? cause))
+ {
+ _cache.Log.LogMessage(MessageImportance.Low, $"Skipping copying over {TargetFile} as the contents are unchanged");
+ return false;
+ }
- if (File.Exists(TargetFile))
- File.Delete(TargetFile);
+ if (File.Exists(TargetFile))
+ File.Delete(TargetFile);
- File.Copy(TempFile, TargetFile);
- File.Delete(TempFile);
+ File.Copy(TempFile, TargetFile);
- _cache.Log.LogMessage(MessageImportance.Low, $"Copying {TempFile} to {TargetFile} because {cause}");
- return true;
+ _cache.Log.LogMessage(MessageImportance.Low, $"Copying {TempFile} to {TargetFile} because {cause}");
+ return true;
+ }
+ finally
+ {
+ File.Delete(TempFile);
+ }
}
}
diff --git a/src/tasks/Common/Utils.cs b/src/tasks/Common/Utils.cs
index 2c1a8b49370..2c624214937 100644
--- a/src/tasks/Common/Utils.cs
+++ b/src/tasks/Common/Utils.cs
@@ -212,7 +212,7 @@ internal static class Utils
throw new ArgumentException($"Cannot find {src} file to copy", nameof(src));
bool areDifferent = !File.Exists(dst) ||
- (useHash && Utils.ComputeHash(src) != Utils.ComputeHash(dst)) ||
+ (useHash && ComputeHash(src) != ComputeHash(dst)) ||
(File.ReadAllText(src) != File.ReadAllText(dst));
if (areDifferent)
diff --git a/src/tasks/WasmAppBuilder/EmccCompile.cs b/src/tasks/WasmAppBuilder/EmccCompile.cs
index e869e98e856..a5d6af6c3b4 100644
--- a/src/tasks/WasmAppBuilder/EmccCompile.cs
+++ b/src/tasks/WasmAppBuilder/EmccCompile.cs
@@ -45,6 +45,19 @@ namespace Microsoft.WebAssembly.Build.Tasks
public override bool Execute()
{
+ try
+ {
+ return ExecuteActual();
+ }
+ catch (LogAsErrorException laee)
+ {
+ Log.LogError(laee.Message);
+ return false;
+ }
+ }
+
+ private bool ExecuteActual()
+ {
if (SourceFiles.Length == 0)
{
Log.LogError($"No SourceFiles to compile");
@@ -133,7 +146,7 @@ namespace Microsoft.WebAssembly.Build.Tasks
});
if (!result.IsCompleted && !Log.HasLoggedErrors)
- Log.LogError("Unknown failed occured while compiling");
+ Log.LogError("Unknown failure occured while compiling. Check logs to get more details.");
}
if (!Log.HasLoggedErrors)
@@ -211,7 +224,7 @@ namespace Microsoft.WebAssembly.Build.Tasks
private bool ShouldCompile(string srcFile, string objFile, string[] depFiles, out string reason)
{
if (!File.Exists(srcFile))
- throw new ArgumentException($"Could not find source file {srcFile}");
+ throw new LogAsErrorException($"Could not find source file {srcFile}");
if (!File.Exists(objFile))
{
@@ -228,7 +241,7 @@ namespace Microsoft.WebAssembly.Build.Tasks
return true;
}
- reason = "everything is up-to-date.";
+ reason = "everything is up-to-date";
return false;
bool IsNewerThanOutput(string inFile, string outFile, out string reason)
diff --git a/src/tasks/WasmAppBuilder/IcallTableGenerator.cs b/src/tasks/WasmAppBuilder/IcallTableGenerator.cs
index 13c75c39bc6..cc4d8af1ac7 100644
--- a/src/tasks/WasmAppBuilder/IcallTableGenerator.cs
+++ b/src/tasks/WasmAppBuilder/IcallTableGenerator.cs
@@ -23,6 +23,9 @@ public class IcallTableGenerator : Task
[Required, NotNull]
public string? OutputPath { get; set; }
+ [Output]
+ public string? FileWrites { get; private set; } = "";
+
private List<Icall> _icalls = new List<Icall> ();
private Dictionary<string, IcallClass> _runtimeIcalls = new Dictionary<string, IcallClass> ();
@@ -58,6 +61,7 @@ public class IcallTableGenerator : Task
Log.LogMessage(MessageImportance.Low, $"Generating icall table to '{OutputPath}'.");
else
Log.LogMessage(MessageImportance.Low, $"Icall table in {OutputPath} is unchanged.");
+ FileWrites = OutputPath;
File.Delete(tmpFileName);
}
diff --git a/src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs b/src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs
index f6b89533f98..825de67d6e2 100644
--- a/src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs
+++ b/src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs
@@ -16,20 +16,43 @@ using Microsoft.Build.Utilities;
public class PInvokeTableGenerator : Task
{
- [Required]
- public ITaskItem[]? Modules { get; set; }
- [Required]
- public ITaskItem[]? Assemblies { get; set; }
+ [Required, NotNull]
+ public string[]? Modules { get; set; }
+ [Required, NotNull]
+ public string[]? Assemblies { get; set; }
[Required, NotNull]
public string? OutputPath { get; set; }
+ [Output]
+ public string FileWrites { get; private set; } = string.Empty;
+
private static char[] s_charsToReplace = new[] { '.', '-', };
public override bool Execute()
{
- GenPInvokeTable(Modules!.Select(item => item.ItemSpec).ToArray(), Assemblies!.Select(item => item.ItemSpec).ToArray());
- return true;
+ if (Assemblies.Length == 0)
+ {
+ Log.LogError($"No assemblies given to scan for pinvokes");
+ return false;
+ }
+
+ if (Modules.Length == 0)
+ {
+ Log.LogError($"{nameof(PInvokeTableGenerator)}.{nameof(Modules)} cannot be empty");
+ return false;
+ }
+
+ try
+ {
+ GenPInvokeTable(Modules, Assemblies);
+ return !Log.HasLoggedErrors;
+ }
+ catch (LogAsErrorException laee)
+ {
+ Log.LogError(laee.Message);
+ return false;
+ }
}
public void GenPInvokeTable(string[] pinvokeModules, string[] assemblies)
@@ -61,6 +84,7 @@ public class PInvokeTableGenerator : Task
Log.LogMessage(MessageImportance.Low, $"Generating pinvoke table to '{OutputPath}'.");
else
Log.LogMessage(MessageImportance.Low, $"PInvoke table in {OutputPath} is unchanged.");
+ FileWrites = OutputPath;
File.Delete(tmpFileName);
}
@@ -339,11 +363,7 @@ public class PInvokeTableGenerator : Task
return false;
}
- private static void Error (string msg)
- {
- // FIXME:
- throw new Exception(msg);
- }
+ private static void Error (string msg) => throw new LogAsErrorException(msg);
}
internal class PInvoke
diff --git a/src/tasks/WasmAppBuilder/WasmAppBuilder.cs b/src/tasks/WasmAppBuilder/WasmAppBuilder.cs
index 57cb7c383f1..58b4b9259e6 100644
--- a/src/tasks/WasmAppBuilder/WasmAppBuilder.cs
+++ b/src/tasks/WasmAppBuilder/WasmAppBuilder.cs
@@ -118,10 +118,23 @@ public class WasmAppBuilder : Task
public override bool Execute ()
{
+ try
+ {
+ return ExecuteInternal();
+ }
+ catch (LogAsErrorException laee)
+ {
+ Log.LogError(laee.Message);
+ return false;
+ }
+ }
+
+ private bool ExecuteInternal ()
+ {
if (!File.Exists(MainJS))
- throw new ArgumentException($"File MainJS='{MainJS}' doesn't exist.");
+ throw new LogAsErrorException($"File MainJS='{MainJS}' doesn't exist.");
if (!InvariantGlobalization && string.IsNullOrEmpty(IcuDataFileName))
- throw new ArgumentException("IcuDataFileName property shouldn't be empty if InvariantGlobalization=false");
+ throw new LogAsErrorException("IcuDataFileName property shouldn't be empty if InvariantGlobalization=false");
if (Assemblies?.Length == 0)
{
@@ -162,8 +175,12 @@ public class WasmAppBuilder : Task
}
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.Combine(AppDir, "index.html"), html);
+ string indexHtmlPath = Path.Combine(AppDir, "index.html");
+ if (!File.Exists(indexHtmlPath))
+ {
+ var html = @"<html><body><script type=""text/javascript"" src=""runtime.js""></script></body></html>";
+ File.WriteAllText(indexHtmlPath, html);
+ }
foreach (var assembly in _assemblies)
{
diff --git a/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj b/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj
index d7cb1b1f5b7..a487a4f270a 100644
--- a/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj
+++ b/src/tasks/WasmAppBuilder/WasmAppBuilder.csproj
@@ -15,6 +15,7 @@
<ItemGroup>
<Compile Include="..\Common\Utils.cs" />
+ <Compile Include="..\Common\LogAsErrorException.cs" />
<PackageReference Include="Microsoft.Build" Version="$(RefOnlyMicrosoftBuildVersion)" />
<PackageReference Include="Microsoft.Build.Framework" Version="$(RefOnlyMicrosoftBuildFrameworkVersion)" />