[HTML5] GDNative support via SIDE_MODULE.
Working, with emscripten > 2.0.9 Yes, the unreleased version. 2.0.9 works, but throws and error due to a bug in emscripten with the thirdparty ENet library. The issue is fixed upstream so newer releases will work.
This commit is contained in:
parent
8ebb52fad6
commit
4d1ebaad0f
8 changed files with 109 additions and 33 deletions
|
@ -333,11 +333,11 @@ GDNativeLibraryEditor::GDNativeLibraryEditor() {
|
||||||
platform_android.library_extension = "*.so";
|
platform_android.library_extension = "*.so";
|
||||||
platforms["Android"] = platform_android;
|
platforms["Android"] = platform_android;
|
||||||
|
|
||||||
// TODO: Javascript platform is not supported yet
|
NativePlatformConfig platform_html5;
|
||||||
// NativePlatformConfig platform_html5;
|
platform_html5.name = "HTML5";
|
||||||
// platform_html5.name = "HTML5";
|
platform_html5.entries.push_back("web");
|
||||||
// platform_html5.library_extension = "*.wasm";
|
platform_html5.library_extension = "*.wasm";
|
||||||
// platforms["Javascript"] = platform_html5;
|
platforms["HTML5"] = platform_html5;
|
||||||
|
|
||||||
NativePlatformConfig platform_ios;
|
NativePlatformConfig platform_ios;
|
||||||
platform_ios.name = "iOS";
|
platform_ios.name = "iOS";
|
||||||
|
|
|
@ -11,13 +11,8 @@ javascript_files = [
|
||||||
"api/javascript_tools_editor_plugin.cpp",
|
"api/javascript_tools_editor_plugin.cpp",
|
||||||
]
|
]
|
||||||
|
|
||||||
build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"]
|
sys_env = env.Clone()
|
||||||
if env["threads_enabled"]:
|
sys_env.AddJSLibraries(
|
||||||
build_targets.append("#bin/godot${PROGSUFFIX}.worker.js")
|
|
||||||
|
|
||||||
build = env.add_program(build_targets, javascript_files)
|
|
||||||
|
|
||||||
env.AddJSLibraries(
|
|
||||||
[
|
[
|
||||||
"js/libs/library_godot_audio.js",
|
"js/libs/library_godot_audio.js",
|
||||||
"js/libs/library_godot_display.js",
|
"js/libs/library_godot_display.js",
|
||||||
|
@ -28,12 +23,47 @@ env.AddJSLibraries(
|
||||||
)
|
)
|
||||||
|
|
||||||
if env["tools"]:
|
if env["tools"]:
|
||||||
env.AddJSLibraries(["js/libs/library_godot_editor_tools.js"])
|
sys_env.AddJSLibraries(["js/libs/library_godot_editor_tools.js"])
|
||||||
if env["javascript_eval"]:
|
if env["javascript_eval"]:
|
||||||
env.AddJSLibraries(["js/libs/library_godot_eval.js"])
|
sys_env.AddJSLibraries(["js/libs/library_godot_eval.js"])
|
||||||
for lib in env["JS_LIBS"]:
|
for lib in sys_env["JS_LIBS"]:
|
||||||
env.Append(LINKFLAGS=["--js-library", lib])
|
sys_env.Append(LINKFLAGS=["--js-library", lib])
|
||||||
env.Depends(build, env["JS_LIBS"])
|
|
||||||
|
build = []
|
||||||
|
if env["gdnative_enabled"]:
|
||||||
|
build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"]
|
||||||
|
# Reset libraries. The main runtime will only link emscripten libraries, not godot ones.
|
||||||
|
sys_env["LIBS"] = []
|
||||||
|
# We use IDBFS. Since Emscripten 1.39.1 it needs to be linked explicitly.
|
||||||
|
sys_env.Append(LIBS=["idbfs.js"])
|
||||||
|
# JS prepended to the module code loading the side library.
|
||||||
|
sys_env.Append(LINKFLAGS=["--pre-js", sys_env.File("js/dynlink.pre.js")])
|
||||||
|
# Configure it as a main module (dynamic linking support).
|
||||||
|
sys_env.Append(CCFLAGS=["-s", "MAIN_MODULE=1"])
|
||||||
|
sys_env.Append(LINKFLAGS=["-s", "MAIN_MODULE=1"])
|
||||||
|
sys_env.Append(CCFLAGS=["-s", "EXPORT_ALL=1"])
|
||||||
|
sys_env.Append(LINKFLAGS=["-s", "EXPORT_ALL=1"])
|
||||||
|
# Force exporting the standard library (printf, malloc, etc.)
|
||||||
|
sys_env["ENV"]["EMCC_FORCE_STDLIBS"] = "libc,libc++,libc++abi"
|
||||||
|
# The main emscripten runtime, with exported standard libraries.
|
||||||
|
sys = sys_env.Program(build_targets, ["javascript_runtime.cpp"])
|
||||||
|
sys_env.Depends(sys, "js/dynlink.pre.js")
|
||||||
|
|
||||||
|
# The side library, containing all Godot code.
|
||||||
|
wasm_env = env.Clone()
|
||||||
|
wasm_env.Append(CCFLAGS=["-s", "SIDE_MODULE=2"])
|
||||||
|
wasm_env.Append(LINKFLAGS=["-s", "SIDE_MODULE=2"])
|
||||||
|
wasm = wasm_env.add_program("#bin/godot.side${PROGSUFFIX}.wasm", javascript_files)
|
||||||
|
build = [sys[0], sys[1], wasm[0]]
|
||||||
|
else:
|
||||||
|
build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"]
|
||||||
|
if env["threads_enabled"]:
|
||||||
|
build_targets.append("#bin/godot${PROGSUFFIX}.worker.js")
|
||||||
|
# We use IDBFS. Since Emscripten 1.39.1 it needs to be linked explicitly.
|
||||||
|
sys_env.Append(LIBS=["idbfs.js"])
|
||||||
|
build = sys_env.Program(build_targets, javascript_files + ["javascript_runtime.cpp"])
|
||||||
|
|
||||||
|
sys_env.Depends(build[0], sys_env["JS_LIBS"])
|
||||||
|
|
||||||
engine = [
|
engine = [
|
||||||
"js/engine/preloader.js",
|
"js/engine/preloader.js",
|
||||||
|
@ -60,8 +90,11 @@ out_files = [
|
||||||
]
|
]
|
||||||
html_file = "#misc/dist/html/editor.html" if env["tools"] else "#misc/dist/html/full-size.html"
|
html_file = "#misc/dist/html/editor.html" if env["tools"] else "#misc/dist/html/full-size.html"
|
||||||
in_files = [js_wrapped, build[1], html_file, "#platform/javascript/js/libs/audio.worklet.js"]
|
in_files = [js_wrapped, build[1], html_file, "#platform/javascript/js/libs/audio.worklet.js"]
|
||||||
if env["threads_enabled"]:
|
if env["gdnative_enabled"]:
|
||||||
in_files.append(build[2])
|
in_files.append(build[2]) # Runtime
|
||||||
|
out_files.append(zip_dir.File(binary_name + ".side.wasm"))
|
||||||
|
elif env["threads_enabled"]:
|
||||||
|
in_files.append(build[2]) # Worker
|
||||||
out_files.append(zip_dir.File(binary_name + ".worker.js"))
|
out_files.append(zip_dir.File(binary_name + ".worker.js"))
|
||||||
|
|
||||||
zip_files = env.InstallAs(out_files, in_files)
|
zip_files = env.InstallAs(out_files, in_files)
|
||||||
|
|
|
@ -23,6 +23,7 @@ def get_opts():
|
||||||
# eval() can be a security concern, so it can be disabled.
|
# eval() can be a security concern, so it can be disabled.
|
||||||
BoolVariable("javascript_eval", "Enable JavaScript eval interface", True),
|
BoolVariable("javascript_eval", "Enable JavaScript eval interface", True),
|
||||||
BoolVariable("threads_enabled", "Enable WebAssembly Threads support (limited browser support)", False),
|
BoolVariable("threads_enabled", "Enable WebAssembly Threads support (limited browser support)", False),
|
||||||
|
BoolVariable("gdnative_enabled", "Enable WebAssembly GDNative support (produces bigger binaries)", False),
|
||||||
BoolVariable("use_closure_compiler", "Use closure compiler to minimize JavaScript code", False),
|
BoolVariable("use_closure_compiler", "Use closure compiler to minimize JavaScript code", False),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -83,10 +84,8 @@ def configure(env):
|
||||||
|
|
||||||
# LTO
|
# LTO
|
||||||
if env["use_lto"]:
|
if env["use_lto"]:
|
||||||
env.Append(CCFLAGS=["-s", "WASM_OBJECT_FILES=0"])
|
env.Append(CCFLAGS=["-flto=full"])
|
||||||
env.Append(LINKFLAGS=["-s", "WASM_OBJECT_FILES=0"])
|
env.Append(LINKFLAGS=["-flto=full"])
|
||||||
env.Append(CCFLAGS=["-flto"])
|
|
||||||
env.Append(LINKFLAGS=["-flto"])
|
|
||||||
|
|
||||||
# Closure compiler
|
# Closure compiler
|
||||||
if env["use_closure_compiler"]:
|
if env["use_closure_compiler"]:
|
||||||
|
@ -133,6 +132,9 @@ def configure(env):
|
||||||
if env["javascript_eval"]:
|
if env["javascript_eval"]:
|
||||||
env.Append(CPPDEFINES=["JAVASCRIPT_EVAL_ENABLED"])
|
env.Append(CPPDEFINES=["JAVASCRIPT_EVAL_ENABLED"])
|
||||||
|
|
||||||
|
if env["threads_enabled"] and env["gdnative_enabled"]:
|
||||||
|
raise Exception("Threads and GDNative support can't be both enabled due to WebAssembly limitations")
|
||||||
|
|
||||||
# Thread support (via SharedArrayBuffer).
|
# Thread support (via SharedArrayBuffer).
|
||||||
if env["threads_enabled"]:
|
if env["threads_enabled"]:
|
||||||
env.Append(CPPDEFINES=["PTHREAD_NO_RENAME"])
|
env.Append(CPPDEFINES=["PTHREAD_NO_RENAME"])
|
||||||
|
@ -144,14 +146,15 @@ def configure(env):
|
||||||
else:
|
else:
|
||||||
env.Append(CPPDEFINES=["NO_THREADS"])
|
env.Append(CPPDEFINES=["NO_THREADS"])
|
||||||
|
|
||||||
|
if env["gdnative_enabled"]:
|
||||||
|
env.Append(CCFLAGS=["-s", "RELOCATABLE=1"])
|
||||||
|
env.Append(LINKFLAGS=["-s", "RELOCATABLE=1"])
|
||||||
|
env.extra_suffix = ".gdnative" + env.extra_suffix
|
||||||
|
|
||||||
# Reduce code size by generating less support code (e.g. skip NodeJS support).
|
# Reduce code size by generating less support code (e.g. skip NodeJS support).
|
||||||
env.Append(LINKFLAGS=["-s", "ENVIRONMENT=web,worker"])
|
env.Append(LINKFLAGS=["-s", "ENVIRONMENT=web,worker"])
|
||||||
|
|
||||||
# We use IDBFS in javascript_main.cpp. Since Emscripten 1.39.1 it needs to
|
# Wrap the JavaScript support code around a closure named Godot.
|
||||||
# be linked explicitly.
|
|
||||||
env.Append(LIBS=["idbfs.js"])
|
|
||||||
|
|
||||||
env.Append(LINKFLAGS=["-s", "BINARYEN=1"])
|
|
||||||
env.Append(LINKFLAGS=["-s", "MODULARIZE=1", "-s", "EXPORT_NAME='Godot'"])
|
env.Append(LINKFLAGS=["-s", "MODULARIZE=1", "-s", "EXPORT_NAME='Godot'"])
|
||||||
|
|
||||||
# Allow increasing memory buffer size during runtime. This is efficient
|
# Allow increasing memory buffer size during runtime. This is efficient
|
||||||
|
@ -162,12 +165,14 @@ def configure(env):
|
||||||
# This setting just makes WebGL 2 APIs available, it does NOT disable WebGL 1.
|
# This setting just makes WebGL 2 APIs available, it does NOT disable WebGL 1.
|
||||||
env.Append(LINKFLAGS=["-s", "USE_WEBGL2=1"])
|
env.Append(LINKFLAGS=["-s", "USE_WEBGL2=1"])
|
||||||
|
|
||||||
|
# Do not call main immediately when the support code is ready.
|
||||||
env.Append(LINKFLAGS=["-s", "INVOKE_RUN=0"])
|
env.Append(LINKFLAGS=["-s", "INVOKE_RUN=0"])
|
||||||
|
|
||||||
# Allow use to take control of swapping WebGL buffers.
|
# Allow use to take control of swapping WebGL buffers.
|
||||||
env.Append(LINKFLAGS=["-s", "OFFSCREEN_FRAMEBUFFER=1"])
|
env.Append(LINKFLAGS=["-s", "OFFSCREEN_FRAMEBUFFER=1"])
|
||||||
|
|
||||||
# callMain for manual start, FS for preloading, PATH and ERRNO_CODES for BrowserFS.
|
# callMain for manual start.
|
||||||
env.Append(LINKFLAGS=["-s", "EXTRA_EXPORTED_RUNTIME_METHODS=['callMain']"])
|
env.Append(LINKFLAGS=["-s", "EXTRA_EXPORTED_RUNTIME_METHODS=['callMain']"])
|
||||||
|
|
||||||
# Add code that allow exiting runtime.
|
# Add code that allow exiting runtime.
|
||||||
env.Append(LINKFLAGS=["-s", "EXIT_RUNTIME=1"])
|
env.Append(LINKFLAGS=["-s", "EXIT_RUNTIME=1"])
|
||||||
|
|
|
@ -74,7 +74,7 @@ void main_loop_callback() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
extern EMSCRIPTEN_KEEPALIVE int godot_js_main(int argc, char *argv[]) {
|
||||||
// Set locale
|
// Set locale
|
||||||
char locale_ptr[16];
|
char locale_ptr[16];
|
||||||
godot_js_config_locale_get(locale_ptr, sizeof(locale_ptr));
|
godot_js_config_locale_get(locale_ptr, sizeof(locale_ptr));
|
||||||
|
|
35
platform/javascript/javascript_runtime.cpp
Normal file
35
platform/javascript/javascript_runtime.cpp
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*************************************************************************/
|
||||||
|
/* javascript_runtime.cpp */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
extern int godot_js_main(int argc, char *argv[]);
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
return godot_js_main(argc, argv);
|
||||||
|
}
|
1
platform/javascript/js/dynlink.pre.js
Normal file
1
platform/javascript/js/dynlink.pre.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Module['dynamicLibraries'] = [Module['thisProgram'] + '.side.wasm'];
|
|
@ -58,6 +58,9 @@ const Engine = (function () {
|
||||||
initPromise = new Promise(function (resolve, reject) {
|
initPromise = new Promise(function (resolve, reject) {
|
||||||
config['locateFile'] = Utils.createLocateRewrite(loadPath);
|
config['locateFile'] = Utils.createLocateRewrite(loadPath);
|
||||||
config['instantiateWasm'] = Utils.createInstantiatePromise(loadPromise);
|
config['instantiateWasm'] = Utils.createInstantiatePromise(loadPromise);
|
||||||
|
// Emscripten configuration.
|
||||||
|
config['thisProgram'] = me.executableName;
|
||||||
|
config['noExitRuntime'] = true;
|
||||||
Godot(config).then(function (module) {
|
Godot(config).then(function (module) {
|
||||||
module['initFS'](me.persistentPaths).then(function (fs_err) {
|
module['initFS'](me.persistentPaths).then(function (fs_err) {
|
||||||
me.rtenv = module;
|
me.rtenv = module;
|
||||||
|
@ -119,9 +122,6 @@ const Engine = (function () {
|
||||||
locale = navigator.languages ? navigator.languages[0] : navigator.language;
|
locale = navigator.languages ? navigator.languages[0] : navigator.language;
|
||||||
locale = locale.split('.')[0];
|
locale = locale.split('.')[0];
|
||||||
}
|
}
|
||||||
// Emscripten configuration.
|
|
||||||
me.rtenv['thisProgram'] = me.executableName;
|
|
||||||
me.rtenv['noExitRuntime'] = true;
|
|
||||||
// Godot configuration.
|
// Godot configuration.
|
||||||
me.rtenv['initConfig']({
|
me.rtenv['initConfig']({
|
||||||
'resizeCanvasOnStart': me.resizeCanvasOnStart,
|
'resizeCanvasOnStart': me.resizeCanvasOnStart,
|
||||||
|
|
|
@ -8,6 +8,8 @@ const Utils = { // eslint-disable-line no-unused-vars
|
||||||
return `${execName}.audio.worklet.js`;
|
return `${execName}.audio.worklet.js`;
|
||||||
} else if (path.endsWith('.js')) {
|
} else if (path.endsWith('.js')) {
|
||||||
return `${execName}.js`;
|
return `${execName}.js`;
|
||||||
|
} else if (path.endsWith('.side.wasm')) {
|
||||||
|
return `${execName}.side.wasm`;
|
||||||
} else if (path.endsWith('.wasm')) {
|
} else if (path.endsWith('.wasm')) {
|
||||||
return `${execName}.wasm`;
|
return `${execName}.wasm`;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue