feat: Add support for custom EXPORTED_RUNTIME_METHODS

This commit is contained in:
Jerome Laban 2022-09-27 20:44:46 -04:00
Родитель bbb4d0b955
Коммит 0e422a7111
12 изменённых файлов: 89 добавлений и 6 удалений

Просмотреть файл

@ -153,3 +153,14 @@ Or use emscripten functions:
```
[DllImport("__Internal_emscripten")]
public static extern void emscripten_console_log(string str);
### Exposing additional methods from emscripten
When interoperating with native features, such as OpenGL, it may be needed to expose additional features from emscripten.
The `EXPORTED_RUNTIME_METHODS` flag can be filled through the following msbuild items:
```xml
<ItemGroup>
<WasmShellEmccExportedRuntimeMethod Include="GL" />
</ItemGroup>
```

Просмотреть файл

@ -163,6 +163,8 @@ namespace Uno.Wasm.Bootstrap
public Microsoft.Build.Framework.ITaskItem[]? NativeCompile { get; set; }
public Microsoft.Build.Framework.ITaskItem[]? EmccExportedRuntimeMethods { get; set; }
public bool GenerateCompressedFiles { get; set; }
public string? DistCompressionLayoutMode { get; set; }
@ -798,6 +800,9 @@ namespace Uno.Wasm.Bootstrap
? string.Join(" ", NativeCompile.Select(f => $"\"--native-compile={AlignPath(GetFilePaths(f).fullPath)}\""))
: "";
var emccExportedRuntimeMethodsParams =
string.Join(" ", EmccExportedRuntimeMethods.Select(f => $"\"--emcc-exported-runtime-method={f.ItemSpec}\""));
if (_runtimeExecutionMode != RuntimeExecutionMode.Interpreter && GenerateAOTProfile)
{
Log.LogMessage($"Forcing Interpreter mode because GenerateAOTProfile is set");
@ -814,7 +819,7 @@ namespace Uno.Wasm.Bootstrap
var dedupOption = !EnableAOTDeduplication ? "--no-dedup" : "";
var aotOptions = $"{aotMode} {dedupOption} {dynamicLibraryParams} {bitcodeFilesParams} {additionalNativeCompile} --emscripten-sdkdir=\"{emsdkPath}\" --builddir=\"{AlignPath(workAotPath)}\"";
var aotOptions = $"{aotMode} {dedupOption} {dynamicLibraryParams} {bitcodeFilesParams} {additionalNativeCompile} {emccExportedRuntimeMethodsParams} --emscripten-sdkdir=\"{emsdkPath}\" --builddir=\"{AlignPath(workAotPath)}\"";
if (EnableEmccProfiling)
{
@ -1743,6 +1748,10 @@ namespace Uno.Wasm.Bootstrap
var enablePWA = !string.IsNullOrEmpty(PWAManifestFile);
var offlineFiles = enablePWA ? string.Join(", ", GetPWACacheableFiles().Select(f => $"\".{f}\"")) : "";
var emccExportedRuntimeMethodsParams = string.Join(
",",
EmccExportedRuntimeMethods.Select(f => $"\'{f.ItemSpec}\'"));
config.AppendLine($"let config = {{}};");
config.AppendLine($"config.uno_remote_managedpath = \"{ Path.GetFileName(_managedPath) }\";");
config.AppendLine($"config.uno_app_base = \"{WebAppBasePath}{_remoteBasePackagePath}\";");
@ -1757,6 +1766,7 @@ namespace Uno.Wasm.Bootstrap
config.AppendLine($"config.enable_pwa = {enablePWA.ToString().ToLowerInvariant()};");
config.AppendLine($"config.offline_files = ['{WebAppBasePath}', {offlineFiles}];");
config.AppendLine($"config.uno_shell_mode = \"{_shellMode}\";");
config.AppendLine($"config.emcc_exported_runtime_methods = [{emccExportedRuntimeMethodsParams}];");
if (GenerateAOTProfile)
{

Просмотреть файл

@ -206,6 +206,7 @@
CustomLinkerPath="$(MonoRuntimeCustomLinkerPath)"
DistCompressionLayoutMode="$(WasmShellCompressionLayoutMode)"
DistPath="$(WasmShellDistPath)"
EmccExportedRuntimeMethods="@(WasmShellEmccExportedRuntimeMethod)"
EmccLinkOptimization="$(WasmShellEmccLinkOptimization)"
EmccLinkOptimizationLevel="$(WasmShellEmccLinkOptimizationLevel)"
EnableAOTDeduplication="$(WasmShellEnableAOTDeduplication)"

Просмотреть файл

@ -120,7 +120,7 @@ namespace Uno.WebAssembly.Bootstrap {
onConfigLoaded: this.onConfigLoaded,
onDotnetReady: this.onDotnetReady,
onAbort: this.onAbort,
exports: ["IDBFS", "FS"],
exports: ["IDBFS", "FS"].concat(this._unoConfig.emcc_exported_runtime_methods),
downloadResource: this.onDownloadResource
};
}

Просмотреть файл

@ -29,6 +29,8 @@
offline_files: string[];
emcc_exported_runtime_methods?: string[];
uno_shell_mode: string;
environmentVariables?: {

Просмотреть файл

@ -446,6 +446,7 @@ class Driver {
var native_libs = new List<string> ();
var preload_files = new List<string> ();
var embed_files = new List<string> ();
var emcc_exported_runtime_methods = new List<string> ();
var native_compile = new List<string> ();
var pinvoke_libs = "";
var copyTypeParm = "default";
@ -515,6 +516,7 @@ class Driver {
{ "native-lib=", s => native_libs.Add (s) },
{ "preload-file=", s => preload_files.Add (s) },
{ "embed-file=", s => embed_files.Add (s) },
{ "emcc-exported-runtime-method=", s => emcc_exported_runtime_methods.Add (s) },
{ "framework=", s => framework = s },
{ "extra-emccflags=", s => extra_emccflags = s },
{ "extra-linkerflags=", s => extra_linkerflags = s },
@ -1095,7 +1097,29 @@ class Driver {
emcc_link_flags.Add("-s ALLOW_MEMORY_GROWTH=1");
emcc_link_flags.Add("-s NO_EXIT_RUNTIME=1");
emcc_link_flags.Add("-s FORCE_FILESYSTEM=1");
emcc_link_flags.Add("-s EXPORTED_RUNTIME_METHODS=\"[\'FS\',\'print\',\'ccall\',\'cwrap\',\'setValue\',\'getValue\',\'UTF8ToString\',\'UTF8ArrayToString\',\'FS_createPath\',\'FS_createDataFile\',\'removeRunDependency\',\'addRunDependency\',\'FS_readFile\',\'lengthBytesUTF8\',\'stringToUTF8\',\'addFunction\',\'removeFunction\',\'IDBFS\']\"");
emcc_exported_runtime_methods.Add("FS");
emcc_exported_runtime_methods.Add("print");
emcc_exported_runtime_methods.Add("ccall");
emcc_exported_runtime_methods.Add("cwrap");
emcc_exported_runtime_methods.Add("setValue");
emcc_exported_runtime_methods.Add("getValue");
emcc_exported_runtime_methods.Add("UTF8ToString");
emcc_exported_runtime_methods.Add("UTF8ArrayToString");
emcc_exported_runtime_methods.Add("FS_createPath");
emcc_exported_runtime_methods.Add("FS_createDataFile");
emcc_exported_runtime_methods.Add("removeRunDependency");
emcc_exported_runtime_methods.Add("addRunDependency");
emcc_exported_runtime_methods.Add("FS_readFile");
emcc_exported_runtime_methods.Add("lengthBytesUTF8");
emcc_exported_runtime_methods.Add("stringToUTF8");
emcc_exported_runtime_methods.Add("addFunction");
emcc_exported_runtime_methods.Add("removeFunction");
emcc_exported_runtime_methods.Add("IDBFS");
var exports = string.Join(",", emcc_exported_runtime_methods.Distinct().Select(m => $"\'{m}\'"));
emcc_link_flags.Add("-s EXPORTED_RUNTIME_METHODS=\"[" + exports + "]\"");
// https://github.com/dotnet/runtime/blob/8a043bf7adb0fbf5e60a8dd557c98686bc0a8377/src/mono/wasm/wasm.proj#L133
emcc_link_flags.Add("-s EXPORTED_FUNCTIONS=_malloc,stackSave,stackRestore,stackAlloc,_memalign,_memset,_htons,_ntohs,_free");

Просмотреть файл

@ -43,7 +43,7 @@ const path = require("path");
else {
console.log(`Results: ${value}`);
}
const expected = "InterpreterAndAOT;42;42.30;42.7;e42;True;true;True;1.3;1.4;3.1;0;42;requireJs:true;jsInterop:Invoked;";
const expected = "InterpreterAndAOT;42;42.30;42.7;e42;True;true;True;1.3;1.4;3.1;0;42;requireJs:true;jsInterop:Invoked;gl:true;";
if (value !== expected) {
console.log(`Invalid results got ${value}, expected ${expected}`);
process.exit(1);

Просмотреть файл

@ -42,7 +42,7 @@ const path = require("path");
console.log(`Results: ${value}`);
}
const expected = "InterpreterAndAOT;42;42.30;42.7;e42;True;true;True;1.3;1.4;3.1;0;42;requireJs:true;jsInterop:Invoked;";
const expected = "InterpreterAndAOT;42;42.30;42.7;e42;True;true;True;1.3;1.4;3.1;0;42;requireJs:true;jsInterop:Invoked;gl:true;";
if (value !== expected) {
console.log(`Invalid results got ${value}, expected ${expected}`);

Просмотреть файл

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<ItemGroup Condition="'$(UseAOT)'=='true' or '$(WasmShellGenerateAOTProfile)'=='true'">
<Content Include="$(MSBuildThisFileDirectory)native/**/*.bc" />
<WasmShellNativeCompile Include="$(MSBuildThisFileDirectory)test.cpp" />
</ItemGroup>
<ItemGroup>
<WasmShellEmccExportedRuntimeMethod Include="GL" />
<!-- Based on https://github.com/dotnet/runtime/issues/76077#issuecomment-1260231545 -->
<WasmShellExtraEmccFlags Include="-s LEGACY_GL_EMULATION=1" />
<WasmShellExtraEmccFlags Include="-s USE_CLOSURE_COMPILER=1" />
</ItemGroup>
</Project>

Просмотреть файл

@ -50,6 +50,9 @@ namespace Uno.Wasm.Sample
var requireAvailable = Runtime.InvokeJS($"typeof require.config !== 'undefined'");
Console.WriteLine($"requireAvailable: {idbFSValidation}");
var glAvailable = Runtime.InvokeJS($"typeof GL !== 'undefined'");
Console.WriteLine($"glAvailable: {glAvailable}");
#if NET7_0_OR_GREATER
var jsInteropResult = Imports.TestCallback();
#else
@ -93,7 +96,8 @@ namespace Uno.Wasm.Sample
$"{chmodRes};" +
$"{additionalNativeAdd};" +
$"requireJs:{requireAvailable};" +
$"jsInterop:{jsInteropResult};"
$"jsInterop:{jsInteropResult};" +
$"gl:{glAvailable};"
;
var r = Runtime.InvokeJS($"Interop.appendResult(\"{res}\")");

Просмотреть файл

@ -34,7 +34,15 @@
<Content Include="$(MSBuildThisFileDirectory)native/**/*.bc" />
<WasmShellNativeCompile Include="$(MSBuildThisFileDirectory)test.cpp" />
</ItemGroup>
<ItemGroup>
<WasmShellEmccExportedRuntimeMethod Include="GL" />
<WasmShellExtraEmccFlags Include="-s LEGACY_GL_EMULATION=1" />
<WasmShellExtraEmccFlags Include="-s USE_CLOSURE_COMPILER=1" />
</ItemGroup>
<ItemGroup>
<Folder Include="$(MSBuildThisFileDirectory)native\" />
</ItemGroup>
<ItemGroup>
<Content Include="$(MSBuildThisFileDirectory)Common.props" />
</ItemGroup>
</Project>

Просмотреть файл

@ -1,6 +1,9 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <SDL/SDL.h>
#define WASM_EXPORT __attribute__((visibility("default")))
@ -12,3 +15,9 @@ WASM_EXPORT int additional_native_add(int a, int b) {
printf("additional_native_add(%d, %d)\r\n", a, b);
return a + b;
}
WASM_EXPORT int test_gl() {
GLuint programObject;
glGetString(GL_VENDOR);
SDL_Init(SDL_INIT_VIDEO);
}