Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
89d4f74
wip
pavelsavara Feb 22, 2023
c0e9a8b
Merge branch 'main' into wasi_bundle_timezones
pavelsavara Feb 22, 2023
42db50f
fix
pavelsavara Feb 23, 2023
e4a68d3
Merge branch 'main' into wasi_bundle_timezones
radical Feb 23, 2023
7a1a3a7
Update src/mono/wasi/build/WasiApp.Native.targets
pavelsavara Feb 24, 2023
e359c67
Update src/mono/wasi/wasi.proj
pavelsavara Feb 24, 2023
0c0c168
Update src/mono/wasi/wasi.proj
pavelsavara Feb 24, 2023
ced7efb
Update src/mono/wasm/runtime/driver.c
pavelsavara Feb 24, 2023
5c0c0d1
Update src/native/libs/System.Native/pal_datetime.c
pavelsavara Feb 24, 2023
787c19f
Update src/tasks/WasmAppBuilder/EmitWasmBundleFiles.cs
pavelsavara Feb 24, 2023
0b17bee
Update src/mono/wasi/build/WasiApp.Native.targets
pavelsavara Feb 24, 2023
2c28f81
Update src/mono/wasi/build/WasiApp.Native.targets
pavelsavara Feb 24, 2023
9ca46db
Update src/mono/wasm/wasm.proj
pavelsavara Feb 24, 2023
1181767
feedback
pavelsavara Feb 24, 2023
72d1512
Merge branch 'main' into wasi_bundle_timezones
pavelsavara Feb 24, 2023
214e0b4
fix
pavelsavara Feb 24, 2023
883a116
feedback
pavelsavara Feb 24, 2023
3863a1f
Merge branch 'main' into wasi_bundle_timezones
pavelsavara Feb 24, 2023
416e45c
Update src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.U…
pavelsavara Feb 27, 2023
ac2521d
Update src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.U…
pavelsavara Feb 27, 2023
8cbf72f
feedback
pavelsavara Feb 27, 2023
01d3c60
added /usr/share/zoneinfo/ prefix - namespace so that we don't mix di…
pavelsavara Feb 27, 2023
9d3e75c
Merge branch 'main' into wasi_bundle_timezones
pavelsavara Feb 27, 2023
26d5f31
fix
pavelsavara Feb 27, 2023
c8af4b8
Update src/tasks/WasmAppBuilder/EmitWasmBundleBase.cs
pavelsavara Mar 1, 2023
e674fd7
feedback
pavelsavara Mar 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feedback
  • Loading branch information
pavelsavara committed Feb 27, 2023
commit 8cbf72f78af8c4df55e063fd6e0dee8f00be895f
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public sealed partial class TimeZoneInfo

#if TARGET_WASI || TARGET_BROWSER
// if TZDIR is set, then the embedded TZ data will be ignored and normal unix behavior will be used
private static readonly bool UseEmbeddedTzDatabase = Environment.GetEnvironmentVariable(TimeZoneDirectoryEnvironmentVariable) == null;
private static readonly bool UseEmbeddedTzDatabase = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable(TimeZoneDirectoryEnvironmentVariable));
#endif

private static TimeZoneInfo GetLocalTimeZoneCore()
Expand All @@ -38,7 +38,7 @@ private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachineCore(string id,
#if TARGET_WASI || TARGET_BROWSER
if (UseEmbeddedTzDatabase)
{
if(!TryLoadEmbeddedTzFile(id, ref rawData))
if(!TryLoadEmbeddedTzFile(id, out rawData))
{
e = new FileNotFoundException(id, "Embedded TZ data not found");
return TimeZoneInfoResult.TimeZoneNotFoundException;
Expand Down Expand Up @@ -102,20 +102,19 @@ private static TimeZoneInfoResult TryGetTimeZoneFromLocalMachineCore(string id,
/// </remarks>
private static IEnumerable<string> GetTimeZoneIds()
{
try
{
#if TARGET_WASI || TARGET_BROWSER
byte[]? rawData = null;
if (UseEmbeddedTzDatabase)
{
if(!TryLoadEmbeddedTzFile(TimeZoneFileName, ref rawData))
if(!TryLoadEmbeddedTzFile(TimeZoneFileName, out var rawData))
{
return Array.Empty<string>();
}
using var reader = new StreamReader(new MemoryStream(rawData), Encoding.UTF8);
return ParseTimeZoneIds(reader);
}
#endif
try
{
using var reader = new StreamReader(Path.Combine(GetTimeZoneDirectory(), TimeZoneFileName), Encoding.UTF8);
return ParseTimeZoneIds(reader);
}
Expand Down Expand Up @@ -422,7 +421,7 @@ private static bool TryLoadTzFile(string tzFilePath, [NotNullWhen(true)] ref byt
}

#if TARGET_WASI || TARGET_BROWSER
private static bool TryLoadEmbeddedTzFile(string name, [NotNullWhen(true)] ref byte[]? rawData)
private static bool TryLoadEmbeddedTzFile(string name, [NotNullWhen(true)] out byte[]? rawData)
{
IntPtr bytes = Interop.Sys.GetTimeZoneData(name, out int length);
if(bytes == IntPtr.Zero)
Expand Down Expand Up @@ -489,7 +488,7 @@ private static bool TryGetLocalTzFile([NotNullWhen(true)] out byte[]? rawData, [
#if TARGET_WASI || TARGET_BROWSER
if (UseEmbeddedTzDatabase)
{
if(!TryLoadEmbeddedTzFile(tzVariable, ref rawData))
if(!TryLoadEmbeddedTzFile(tzVariable, out rawData))
{
return false;
}
Expand Down
6 changes: 3 additions & 3 deletions src/mono/wasi/build/WasiApp.Native.targets
Original file line number Diff line number Diff line change
Expand Up @@ -345,9 +345,9 @@
<!--EnvironmentVariables="@(EmscriptenEnvVars)" />-->
<!--</Target>-->

<UsingTask TaskName="Microsoft.WebAssembly.Build.Tasks.EmitWasmBundleFiles" AssemblyFile="$(WasmAppBuilderTasksAssemblyPath)" />
<UsingTask TaskName="Microsoft.WebAssembly.Build.Tasks.EmitWasmBundleObjectFiles" AssemblyFile="$(WasmAppBuilderTasksAssemblyPath)" />
<Target Name="_GenerateAssemblyObjectFiles" Returns="@(_WasiObjectFilesForBundle)">
<!-- Get the file hashes of everything in @(_WasmBundleFiles), then pass it all to EmitWasmBundleFiles. This
<!-- Get the file hashes of everything in @(_WasmBundleFiles), then pass it all to EmitWasmBundleObjectFiles. This
will emit corresponding .o files for anything we don't already have on disk. -->
<PropertyGroup>
<_WasmAssembliesBundleObjectFile>$(_WasmIntermediateOutputPath)wasi_bundled_assemblies.o</_WasmAssembliesBundleObjectFile>
Expand All @@ -361,7 +361,7 @@
</WasmBundleAssembliesWithHashes>
</ItemGroup>
<!-- TODO make this incremental compilation -->
<EmitWasmBundleFiles
<EmitWasmBundleObjectFiles
FilesToBundle="@(WasmBundleAssembliesWithHashes)"
ClangExecutable="$(WasiClang)"
BundleName="assemblies"
Expand Down
6 changes: 3 additions & 3 deletions src/mono/wasi/wasi.proj
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
</ManagedToNativeGenerator>
</Target>

<UsingTask TaskName="Microsoft.WebAssembly.Build.Tasks.EmitWasmBundleFiles" AssemblyFile="$(WasmAppBuilderTasksAssemblyPath)" />
<UsingTask TaskName="Microsoft.WebAssembly.Build.Tasks.EmitWasmBundleObjectFiles" AssemblyFile="$(WasmAppBuilderTasksAssemblyPath)" />
<Target Name="GenerateTimezonesArchive" Returns="@(_WasmArchivedTimezones)">
<PropertyGroup>
<_WasmTimezonesPath>$([MSBuild]::NormalizePath('$(PkgSystem_Runtime_TimeZoneData)', 'contentFiles', 'any', 'any', 'data'))</_WasmTimezonesPath>
Expand All @@ -86,14 +86,14 @@
</_WasmBundleTimezonesWithHashes>
</ItemGroup>
<!-- TODO make this incremental compilation -->
<EmitWasmBundleFiles
<EmitWasmBundleObjectFiles
FilesToBundle="@(_WasmBundleTimezonesWithHashes)"
ClangExecutable="$(WasiClang)"
BundleName="timezones"
BundleFile="$(_WasmTimezonesBundleObjectFile)"
RegistrationCallbackFunctionName="mono_wasm_add_bundled_file"
>
</EmitWasmBundleFiles>
</EmitWasmBundleObjectFiles>
<ItemGroup>
<WasmBundleTimezonesObjects Include="$([MSBuild]::MakeRelative($(WasiObjDir), %(_WasmBundleTimezonesWithHashes.DestinationFile)).Replace('\','/'))" />
<WasmBundleTimezonesObjects Include="$([MSBuild]::MakeRelative($(WasiObjDir), $(_WasmTimezonesBundleObjectFile)).Replace('\','/'))" />
Expand Down
12 changes: 6 additions & 6 deletions src/mono/wasm/wasm.proj
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
</ManagedToNativeGenerator>
</Target>

<UsingTask TaskName="Microsoft.WebAssembly.Build.Tasks.EmitWasmBundleFiles" AssemblyFile="$(WasmAppBuilderTasksAssemblyPath)" />
<UsingTask TaskName="Microsoft.WebAssembly.Build.Tasks.EmitWasmBundleSourceFiles" AssemblyFile="$(WasmAppBuilderTasksAssemblyPath)" />
<Target Name="GenerateTimezonesArchive" Returns="@(_WasmArchivedTimezones)">
<PropertyGroup>
<_WasmTimezonesPath>$([MSBuild]::NormalizePath('$(PkgSystem_Runtime_TimeZoneData)', 'contentFiles', 'any', 'any', 'data'))</_WasmTimezonesPath>
Expand All @@ -104,20 +104,20 @@
</_WasmBundleTimezonesWithHashes>
</ItemGroup>
<!-- TODO make this incremental compilation -->
<EmitWasmBundleFiles
<EmitWasmBundleSourceFiles
FilesToBundle="@(_WasmBundleTimezonesWithHashes)"
BundleName="timezones"
BundleFile="$(WasmObjDir)\wasm-bundled-timezones.c"
RegistrationCallbackFunctionName="mono_wasm_add_bundled_file"
>
</EmitWasmBundleFiles>
</EmitWasmBundleSourceFiles>
<ItemGroup>
<WasmBundleTimezonesSources Include="$([MSBuild]::MakeRelative($(WasmObjDir), %(_WasmBundleTimezonesWithHashes.DestinationFile)).Replace('\','/'))" />
<WasmBundleTimezonesSources Include="$([MSBuild]::MakeRelative($(WasmObjDir), $(_WasmTimezonesBundleSourceFile)).Replace('\','/'))" />
<_WasmBundleTimezonesSources Include="$([MSBuild]::MakeRelative($(WasmObjDir), %(_WasmBundleTimezonesWithHashes.DestinationFile)).Replace('\','/'))" />
<_WasmBundleTimezonesSources Include="$([MSBuild]::MakeRelative($(WasmObjDir), $(_WasmTimezonesBundleSourceFile)).Replace('\','/'))" />
</ItemGroup>
<WriteLinesToFile File="$(_WasmTimezonesSourcesRsp)"
Overwrite="true"
Lines="@(WasmBundleTimezonesSources, ' ')"
Lines="@(_WasmBundleTimezonesSources, ' ')"
WriteOnlyWhenDifferent="true" />
<RunWithEmSdkEnv Command="$(EmccCmd) -xc -c @$(_WasmTimezonesSourcesRsp)"
WorkingDirectory="$(WasmObjDir)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,13 @@

namespace Microsoft.WebAssembly.Build.Tasks;

public class EmitWasmBundleFiles : Microsoft.Build.Utilities.Task, ICancelableTask
public abstract class EmitWasmBundleBase : Microsoft.Build.Utilities.Task, ICancelableTask
{
private CancellationTokenSource BuildTaskCancelled { get; } = new();

[Required]
public ITaskItem[] FilesToBundle { get; set; } = default!;

// if not provided the task will generate source files to disk
public string? ClangExecutable { get; set; }

[Required]
public string BundleName { get; set; } = default!;

Expand All @@ -34,16 +31,6 @@ public class EmitWasmBundleFiles : Microsoft.Build.Utilities.Task, ICancelableTa

public override bool Execute()
{
if (!string.IsNullOrEmpty(ClangExecutable) && !File.Exists(ClangExecutable))
{
Log.LogError($"Cannot find {nameof(ClangExecutable)}={ClangExecutable}");
return false;
}
// It would be ideal that this Task would always produce object files.
// We do it with clang by streaming code directly to clang input stream.
// For emcc it's not possible, so we need to write the code to disk first and then compile it in MSBuild.
Action<string, Action<Stream>> emitter = string.IsNullOrEmpty(ClangExecutable) ? WriteSource : Compile;

// The DestinationFile (output filename) already includes a content hash. Grouping by this filename therefore
// produces one group per file-content. We only want to emit one copy of each file-content, and one symbol for it.
var filesToBundleByDestinationFileName = FilesToBundle.GroupBy(f => f.GetMetadata("DestinationFile")).ToList();
Expand All @@ -58,13 +45,32 @@ public override bool Execute()
var verbose = remainingDestinationFilesToBundle.Length > 1;
var verboseCount = 0;

var filesToBundleByRegisteredName = FilesToBundle.GroupBy(file => {
var registeredName = file.GetMetadata("RegisteredName");
if(string.IsNullOrEmpty(registeredName))
{
registeredName = Path.GetFileName(file.ItemSpec);
}
return registeredName;
}).ToList();

var files = filesToBundleByRegisteredName.Select(group => {
var registeredFile = group.First();
var outputFile = registeredFile.GetMetadata("DestinationFile");
var registeredName = group.Key;
var symbolName = ToSafeSymbolName(outputFile);
return (registeredName, symbolName);
}).ToList();

Log.LogMessage(MessageImportance.Low, "Bundling {numFiles} files for {bundleName}", files.Count, BundleName);

if (remainingDestinationFilesToBundle.Length > 0)
{
int allowedParallelism = Math.Max(Math.Min(remainingDestinationFilesToBundle.Length, Environment.ProcessorCount), 1);
if (BuildEngine is IBuildEngine9 be9)
allowedParallelism = be9.RequestCores(allowedParallelism);

Parallel.For(0, remainingDestinationFilesToBundle.Length, new ParallelOptions { MaxDegreeOfParallelism = allowedParallelism, CancellationToken = BuildTaskCancelled.Token }, i =>
Parallel.For(0, remainingDestinationFilesToBundle.Length, new ParallelOptions { MaxDegreeOfParallelism = allowedParallelism, CancellationToken = BuildTaskCancelled.Token }, (i, state) =>
{
var group = remainingDestinationFilesToBundle[i];

Expand All @@ -87,38 +93,21 @@ public override bool Execute()

Log.LogMessage(MessageImportance.Low, "Bundling {0} as {1}", inputFile, outputFile);
var symbolName = ToSafeSymbolName(outputFile);
emitter(outputFile, (codeStream) => {
if (!Emit(outputFile, (codeStream) => {
using var inputStream = File.OpenRead(inputFile);
BundleFileToCSource(symbolName, inputStream, codeStream);
});
}))
{
state.Stop();
}
});
}

var filesToBundleByRegisteredName = FilesToBundle.GroupBy(file => {
var registeredName = file.GetMetadata("RegisteredName");
if(string.IsNullOrEmpty(registeredName))
{
registeredName = Path.GetFileName(file.ItemSpec);
}
return registeredName;
}).ToList();

var files = filesToBundleByRegisteredName.Select(group => {
var registeredFile = group.First();
var outputFile = registeredFile.GetMetadata("DestinationFile");
var registeredName = group.Key;
var symbolName = ToSafeSymbolName(outputFile);
return (registeredName, symbolName);
}).ToList();

Log.LogMessage(MessageImportance.High, "Bundling {2} objects into mono_wasm_register_{0}_bundle as {1}", BundleName, BundleFile, files.Count);
emitter(BundleFile, (inputStream) =>
return Emit(BundleFile, (inputStream) =>
{
using var outputUtf8Writer = new StreamWriter(inputStream, Utf8NoBom);
GenerateRegisterBundledObjects($"mono_wasm_register_{BundleName}_bundle", RegistrationCallbackFunctionName, files, outputUtf8Writer);
});

return !Log.HasLoggedErrors;
}) && !Log.HasLoggedErrors;
}

public void Cancel()
Expand Down Expand Up @@ -156,29 +145,7 @@ private static byte[] InitLookupTable()
return lookup;
}

public void WriteSource(string destinationFile, Action<Stream> inputProvider)
{
using (var fileStream = File.Create(destinationFile))
{
inputProvider(fileStream);
}
}

public void Compile(string destinationFile, Action<Stream> inputProvider)
{
if (Path.GetDirectoryName(destinationFile) is string destDir && !string.IsNullOrEmpty(destDir))
Directory.CreateDirectory(destDir);

(int exitCode, string output) = Utils.TryRunProcess(Log,
ClangExecutable!,
$"-xc -o \"{destinationFile}\" -c -",
null, null, true, false, MessageImportance.Low, null,
inputProvider);
if (exitCode != 0)
{
Log.LogError($"workload install failed with exit code {exitCode}: {output}");
}
}
public abstract bool Emit(string destinationFile, Action<Stream> inputProvider);

public static void GenerateRegisterBundledObjects(string newFunctionName, string callbackFunctionName, ICollection<(string registeredName, string symbol)> files, StreamWriter outputUtf8Writer)
{
Expand Down
45 changes: 45 additions & 0 deletions src/tasks/WasmAppBuilder/EmitWasmBundleObjectFiles.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics;
using System.IO;
using Microsoft.Build.Framework;

namespace Microsoft.WebAssembly.Build.Tasks;

public class EmitWasmBundleObjectFiles : EmitWasmBundleBase
{
[Required]
public string ClangExecutable { get; set; } = default!;

public override bool Execute()
{
if (!File.Exists(ClangExecutable))
{
Log.LogError($"Cannot find {nameof(ClangExecutable)}={ClangExecutable}");
return false;
}

return base.Execute();
}

public override bool Emit(string destinationFile, Action<Stream> inputProvider)
{
if (Path.GetDirectoryName(destinationFile) is string destDir && !string.IsNullOrEmpty(destDir))
Directory.CreateDirectory(destDir);

(int exitCode, string output) = Utils.TryRunProcess(Log,
ClangExecutable!,
args: $"-xc -o \"{destinationFile}\" -c -",
envVars: null, workingDir: null, silent: true, logStdErrAsMessage: false,
debugMessageImportance: MessageImportance.Low, label: null,
inputProvider);
if (exitCode != 0)
{
Log.LogError($"Failed to compile with exit code {exitCode}{Environment.NewLine}Output: {output}");
}
return exitCode == 0;
}

}
24 changes: 24 additions & 0 deletions src/tasks/WasmAppBuilder/EmitWasmBundleSourceFiles.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.IO;
using Microsoft.Build.Framework;

namespace Microsoft.WebAssembly.Build.Tasks;

// It would be ideal that this Task would always produce object files as EmitWasmBundleObjectFiles does.
// EmitWasmBundleObjectFiles could do it with clang by streaming code directly to clang input stream.
// For emcc it's not possible, so we need to write the code to disk first and then compile it in MSBuild.
public class EmitWasmBundleSourceFiles : EmitWasmBundleBase
{
public override bool Emit(string destinationFile, Action<Stream> inputProvider)
{
using (var fileStream = File.Create(destinationFile))
{
inputProvider(fileStream);
}

return true;
}
}