[HTML5] GDNative support via SIDE_MODULE.
Working with emscripten >= 2.0.10
This commit is contained in:
parent
1167ab96e9
commit
ca34b5e57a
|
@ -308,11 +308,11 @@ GDNativeLibraryEditor::GDNativeLibraryEditor() {
|
|||
platform_android.library_extension = "*.so";
|
||||
platforms["Android"] = platform_android;
|
||||
|
||||
// TODO: Javascript platform is not supported yet
|
||||
// NativePlatformConfig platform_html5;
|
||||
// platform_html5.name = "HTML5";
|
||||
// platform_html5.library_extension = "*.wasm";
|
||||
// platforms["Javascript"] = platform_html5;
|
||||
NativePlatformConfig platform_html5;
|
||||
platform_html5.name = "HTML5";
|
||||
platform_html5.entries.push_back("web");
|
||||
platform_html5.library_extension = "*.wasm";
|
||||
platforms["HTML5"] = platform_html5;
|
||||
|
||||
NativePlatformConfig platform_ios;
|
||||
platform_ios.name = "iOS";
|
||||
|
|
|
@ -12,13 +12,8 @@ javascript_files = [
|
|||
"api/javascript_tools_editor_plugin.cpp",
|
||||
]
|
||||
|
||||
build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"]
|
||||
if env["threads_enabled"]:
|
||||
build_targets.append("#bin/godot${PROGSUFFIX}.worker.js")
|
||||
|
||||
build = env.add_program(build_targets, javascript_files)
|
||||
|
||||
env.AddJSLibraries(
|
||||
sys_env = env.Clone()
|
||||
sys_env.AddJSLibraries(
|
||||
[
|
||||
"js/libs/library_godot_audio.js",
|
||||
"js/libs/library_godot_display.js",
|
||||
|
@ -29,12 +24,47 @@ env.AddJSLibraries(
|
|||
)
|
||||
|
||||
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"]:
|
||||
env.AddJSLibraries(["js/libs/library_godot_eval.js"])
|
||||
for lib in env["JS_LIBS"]:
|
||||
env.Append(LINKFLAGS=["--js-library", lib])
|
||||
env.Depends(build, env["JS_LIBS"])
|
||||
sys_env.AddJSLibraries(["js/libs/library_godot_eval.js"])
|
||||
for lib in sys_env["JS_LIBS"]:
|
||||
sys_env.Append(LINKFLAGS=["--js-library", lib])
|
||||
|
||||
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 = [
|
||||
"js/engine/preloader.js",
|
||||
|
@ -61,8 +91,11 @@ out_files = [
|
|||
]
|
||||
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"]
|
||||
if env["threads_enabled"]:
|
||||
in_files.append(build[2])
|
||||
if env["gdnative_enabled"]:
|
||||
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"))
|
||||
|
||||
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.
|
||||
BoolVariable("javascript_eval", "Enable JavaScript eval interface", True),
|
||||
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),
|
||||
]
|
||||
|
||||
|
@ -85,10 +86,8 @@ def configure(env):
|
|||
|
||||
# LTO
|
||||
if env["use_lto"]:
|
||||
env.Append(CCFLAGS=["-s", "WASM_OBJECT_FILES=0"])
|
||||
env.Append(LINKFLAGS=["-s", "WASM_OBJECT_FILES=0"])
|
||||
env.Append(CCFLAGS=["-flto"])
|
||||
env.Append(LINKFLAGS=["-flto"])
|
||||
env.Append(CCFLAGS=["-flto=full"])
|
||||
env.Append(LINKFLAGS=["-flto=full"])
|
||||
|
||||
# Closure compiler
|
||||
if env["use_closure_compiler"]:
|
||||
|
@ -135,6 +134,9 @@ def configure(env):
|
|||
if env["javascript_eval"]:
|
||||
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).
|
||||
if env["threads_enabled"]:
|
||||
env.Append(CPPDEFINES=["PTHREAD_NO_RENAME"])
|
||||
|
@ -146,14 +148,15 @@ def configure(env):
|
|||
else:
|
||||
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).
|
||||
env.Append(LINKFLAGS=["-s", "ENVIRONMENT=web,worker"])
|
||||
|
||||
# We use IDBFS in javascript_main.cpp. Since Emscripten 1.39.1 it needs to
|
||||
# be linked explicitly.
|
||||
env.Append(LIBS=["idbfs.js"])
|
||||
|
||||
env.Append(LINKFLAGS=["-s", "BINARYEN=1"])
|
||||
# Wrap the JavaScript support code around a closure named Godot.
|
||||
env.Append(LINKFLAGS=["-s", "MODULARIZE=1", "-s", "EXPORT_NAME='Godot'"])
|
||||
|
||||
# Allow increasing memory buffer size during runtime. This is efficient
|
||||
|
@ -164,12 +167,14 @@ def configure(env):
|
|||
# This setting just makes WebGL 2 APIs available, it does NOT disable WebGL 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"])
|
||||
|
||||
# Allow use to take control of swapping WebGL buffers.
|
||||
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']"])
|
||||
|
||||
# Add code that allow exiting runtime.
|
||||
env.Append(LINKFLAGS=["-s", "EXIT_RUNTIME=1"])
|
||||
|
|
|
@ -75,7 +75,7 @@ void main_loop_callback() {
|
|||
}
|
||||
|
||||
/// When calling main, it is assumed FS is setup and synced.
|
||||
int main(int argc, char *argv[]) {
|
||||
extern EMSCRIPTEN_KEEPALIVE int godot_js_main(int argc, char *argv[]) {
|
||||
os = new OS_JavaScript();
|
||||
|
||||
// We must override main when testing is enabled
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
Module['dynamicLibraries'] = [Module['thisProgram'] + '.side.wasm'];
|
|
@ -58,6 +58,9 @@ const Engine = (function () {
|
|||
initPromise = new Promise(function (resolve, reject) {
|
||||
config['locateFile'] = Utils.createLocateRewrite(loadPath);
|
||||
config['instantiateWasm'] = Utils.createInstantiatePromise(loadPromise);
|
||||
// Emscripten configuration.
|
||||
config['thisProgram'] = me.executableName;
|
||||
config['noExitRuntime'] = true;
|
||||
Godot(config).then(function (module) {
|
||||
module['initFS'](me.persistentPaths).then(function (fs_err) {
|
||||
me.rtenv = module;
|
||||
|
@ -119,9 +122,6 @@ const Engine = (function () {
|
|||
locale = navigator.languages ? navigator.languages[0] : navigator.language;
|
||||
locale = locale.split('.')[0];
|
||||
}
|
||||
// Emscripten configuration.
|
||||
me.rtenv['thisProgram'] = me.executableName;
|
||||
me.rtenv['noExitRuntime'] = true;
|
||||
// Godot configuration.
|
||||
me.rtenv['initConfig']({
|
||||
'resizeCanvasOnStart': me.resizeCanvasOnStart,
|
||||
|
|
|
@ -8,6 +8,8 @@ const Utils = { // eslint-disable-line no-unused-vars
|
|||
return `${execName}.audio.worklet.js`;
|
||||
} else if (path.endsWith('.js')) {
|
||||
return `${execName}.js`;
|
||||
} else if (path.endsWith('.side.wasm')) {
|
||||
return `${execName}.side.wasm`;
|
||||
} else if (path.endsWith('.wasm')) {
|
||||
return `${execName}.wasm`;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue