[Web] Require threads, rtti, allow optimize=speed.
Update export names (web[_dlink]_[release|debug].zip). The Build with dynamic linking is broken due to high number of imports in output wasm (likely emscripten regression issue 15487).
This commit is contained in:
parent
4c0f5f751e
commit
f958f00283
|
@ -6,7 +6,7 @@ env:
|
|||
# Only used for the cache key. Increment version to force clean build.
|
||||
GODOT_BASE_BRANCH: master
|
||||
SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no
|
||||
EM_VERSION: 3.1.10
|
||||
EM_VERSION: 3.1.20
|
||||
EM_CACHE_FOLDER: "emsdk-cache"
|
||||
|
||||
concurrency:
|
||||
|
|
|
@ -140,15 +140,9 @@ if env["builtin_harfbuzz"]:
|
|||
env_harfbuzz.Prepend(CPPPATH=["#thirdparty/graphite/include"])
|
||||
env_harfbuzz.Append(CCFLAGS=["-DGRAPHITE2_STATIC"])
|
||||
|
||||
if env["platform"] == "android" or env["platform"] == "linuxbsd":
|
||||
if env["platform"] in ["android", "linuxbsd", "web"]:
|
||||
env_harfbuzz.Append(CCFLAGS=["-DHAVE_PTHREAD"])
|
||||
|
||||
if env["platform"] == "web":
|
||||
if env["threads_enabled"]:
|
||||
env_harfbuzz.Append(CCFLAGS=["-DHAVE_PTHREAD"])
|
||||
else:
|
||||
env_harfbuzz.Append(CCFLAGS=["-DHB_NO_MT"])
|
||||
|
||||
env_text_server_adv.Prepend(CPPPATH=["#thirdparty/harfbuzz/src"])
|
||||
|
||||
lib = env_harfbuzz.add_library("harfbuzz_builtin", thirdparty_sources)
|
||||
|
|
|
@ -35,18 +35,17 @@ for ext in env["JS_EXTERNS"]:
|
|||
sys_env["ENV"]["EMCC_CLOSURE_ARGS"] += " --externs " + ext.abspath
|
||||
|
||||
build = []
|
||||
if env["gdnative_enabled"]:
|
||||
build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"]
|
||||
if env["threads_enabled"]:
|
||||
build_targets.append("#bin/godot${PROGSUFFIX}.worker.js")
|
||||
build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm", "#bin/godot${PROGSUFFIX}.worker.js"]
|
||||
if env["dlink_enabled"]:
|
||||
# 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"])
|
||||
# Configure it as a main module (dynamic linking support).
|
||||
sys_env["CCFLAGS"].remove("SIDE_MODULE=2")
|
||||
sys_env["LINKFLAGS"].remove("SIDE_MODULE=2")
|
||||
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"])
|
||||
sys_env.Append(LINKFLAGS=["-s", "WARN_ON_UNDEFINED_SYMBOLS=0"])
|
||||
# Force exporting the standard library (printf, malloc, etc.)
|
||||
|
@ -55,16 +54,9 @@ if env["gdnative_enabled"]:
|
|||
sys = sys_env.Program(build_targets, ["web_runtime.cpp"])
|
||||
|
||||
# The side library, containing all Godot code.
|
||||
wasm_env = env.Clone()
|
||||
wasm_env.Append(CPPDEFINES=["WASM_GDNATIVE"]) # So that OS knows it can run GDNative libraries.
|
||||
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", web_files)
|
||||
wasm = env.add_program("#bin/godot.side${PROGSUFFIX}.wasm", web_files)
|
||||
build = sys + [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, web_files + ["web_runtime.cpp"])
|
||||
|
@ -88,6 +80,8 @@ wrap_list = [
|
|||
]
|
||||
js_wrapped = env.Textfile("#bin/godot", [env.File(f) for f in wrap_list], TEXTFILESUFFIX="${PROGSUFFIX}.wrapped.js")
|
||||
|
||||
# Extra will be the thread worker, or the GDNative side, or None
|
||||
extra = build[2:] if len(build) > 2 else None
|
||||
env.CreateTemplateZip(js_wrapped, build[1], extra)
|
||||
# 0 - unwrapped js file (use wrapped one instead)
|
||||
# 1 - wasm file
|
||||
# 2 - worker file
|
||||
# 3 - wasm side (when dlink is enabled).
|
||||
env.CreateTemplateZip(js_wrapped, build[1], build[2], build[3] if len(build) > 3 else None)
|
||||
|
|
|
@ -38,8 +38,9 @@ def get_opts():
|
|||
BoolVariable("use_safe_heap", "Use Emscripten SAFE_HEAP sanitizer", False),
|
||||
# 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)", True),
|
||||
BoolVariable("gdnative_enabled", "Enable WebAssembly GDNative support (produces bigger binaries)", False),
|
||||
BoolVariable(
|
||||
"dlink_enabled", "Enable WebAssembly dynamic linking (GDExtension support). Produces bigger binaries", False
|
||||
),
|
||||
BoolVariable("use_closure_compiler", "Use closure compiler to minimize JavaScript code", False),
|
||||
]
|
||||
|
||||
|
@ -50,6 +51,13 @@ def get_flags():
|
|||
("tools", False),
|
||||
("builtin_pcre2_with_jit", False),
|
||||
("vulkan", False),
|
||||
# Use -Os to prioritize optimizing for reduced file size. This is
|
||||
# particularly valuable for the web platform because it directly
|
||||
# decreases download time.
|
||||
# -Os reduces file size by around 5 MiB over -O3. -Oz only saves about
|
||||
# 100 KiB over -Os, which does not justify the negative impact on
|
||||
# run-time performance.
|
||||
("optimize", "size"),
|
||||
]
|
||||
|
||||
|
||||
|
@ -71,15 +79,12 @@ def configure(env):
|
|||
|
||||
## Build type
|
||||
if env["target"].startswith("release"):
|
||||
# Use -Os to prioritize optimizing for reduced file size. This is
|
||||
# particularly valuable for the web platform because it directly
|
||||
# decreases download time.
|
||||
# -Os reduces file size by around 5 MiB over -O3. -Oz only saves about
|
||||
# 100 KiB over -Os, which does not justify the negative impact on
|
||||
# run-time performance.
|
||||
if env["optimize"] != "none":
|
||||
if env["optimize"] == "size":
|
||||
env.Append(CCFLAGS=["-Os"])
|
||||
env.Append(LINKFLAGS=["-Os"])
|
||||
elif env["optimize"] == "speed":
|
||||
env.Append(CCFLAGS=["-O3"])
|
||||
env.Append(LINKFLAGS=["-O3"])
|
||||
|
||||
if env["target"] == "release_debug":
|
||||
# Retain function names for backtraces at the cost of file size.
|
||||
|
@ -93,21 +98,11 @@ def configure(env):
|
|||
env.Append(LINKFLAGS=["-s", "ASSERTIONS=1"])
|
||||
|
||||
if env["tools"]:
|
||||
if not env["threads_enabled"]:
|
||||
print('Note: Forcing "threads_enabled=yes" as it is required for the web editor.')
|
||||
env["threads_enabled"] = "yes"
|
||||
if env["initial_memory"] < 64:
|
||||
print('Note: Forcing "initial_memory=64" as it is required for the web editor.')
|
||||
env["initial_memory"] = 64
|
||||
env.Append(CCFLAGS=["-frtti"])
|
||||
elif env["builtin_icu"]:
|
||||
env.Append(CCFLAGS=["-fno-exceptions", "-frtti"])
|
||||
else:
|
||||
# Disable exceptions and rtti on non-tools (template) builds
|
||||
# These flags help keep the file size down.
|
||||
env.Append(CCFLAGS=["-fno-exceptions", "-fno-rtti"])
|
||||
# Don't use dynamic_cast, necessary with no-rtti.
|
||||
env.Append(CPPDEFINES=["NO_SAFE_CAST"])
|
||||
env.Append(CPPFLAGS=["-fno-exceptions"])
|
||||
|
||||
env.Append(LINKFLAGS=["-s", "INITIAL_MEMORY=%sMB" % env["initial_memory"]])
|
||||
|
||||
|
@ -171,9 +166,9 @@ def configure(env):
|
|||
env["ARCOM_POSIX"] = env["ARCOM"].replace("$TARGET", "$TARGET.posix").replace("$SOURCES", "$SOURCES.posix")
|
||||
env["ARCOM"] = "${TEMPFILE(ARCOM_POSIX)}"
|
||||
|
||||
# All intermediate files are just LLVM bitcode.
|
||||
# All intermediate files are just object files.
|
||||
env["OBJPREFIX"] = ""
|
||||
env["OBJSUFFIX"] = ".bc"
|
||||
env["OBJSUFFIX"] = ".o"
|
||||
env["PROGPREFIX"] = ""
|
||||
# Program() output consists of multiple files, so specify suffixes manually at builder.
|
||||
env["PROGSUFFIX"] = ""
|
||||
|
@ -196,31 +191,22 @@ def configure(env):
|
|||
env.Append(CPPDEFINES=["JAVASCRIPT_EVAL_ENABLED"])
|
||||
|
||||
# Thread support (via SharedArrayBuffer).
|
||||
if env["threads_enabled"]:
|
||||
env.Append(CPPDEFINES=["PTHREAD_NO_RENAME"])
|
||||
env.Append(CCFLAGS=["-s", "USE_PTHREADS=1"])
|
||||
env.Append(LINKFLAGS=["-s", "USE_PTHREADS=1"])
|
||||
env.Append(LINKFLAGS=["-s", "PTHREAD_POOL_SIZE=8"])
|
||||
env.Append(LINKFLAGS=["-s", "WASM_MEM_MAX=2048MB"])
|
||||
env.extra_suffix = ".threads" + env.extra_suffix
|
||||
else:
|
||||
env.Append(CPPDEFINES=["NO_THREADS"])
|
||||
|
||||
if env["gdnative_enabled"]:
|
||||
if env["dlink_enabled"]:
|
||||
cc_version = get_compiler_version(env)
|
||||
cc_semver = (int(cc_version["major"]), int(cc_version["minor"]), int(cc_version["patch"]))
|
||||
if cc_semver < (2, 0, 10):
|
||||
print("GDNative support requires emscripten >= 2.0.10, detected: %s.%s.%s" % cc_semver)
|
||||
if cc_semver < (3, 1, 14):
|
||||
print("GDExtension support requires emscripten >= 3.1.14, detected: %s.%s.%s" % cc_semver)
|
||||
sys.exit(255)
|
||||
|
||||
if env["threads_enabled"] and cc_semver < (3, 1, 14):
|
||||
print("Threads and GDNative requires emscripten >= 3.1.14, detected: %s.%s.%s" % cc_semver)
|
||||
sys.exit(255)
|
||||
env.Append(CCFLAGS=["-s", "RELOCATABLE=1"])
|
||||
env.Append(LINKFLAGS=["-s", "RELOCATABLE=1"])
|
||||
# Weak symbols are broken upstream: https://github.com/emscripten-core/emscripten/issues/12819
|
||||
env.Append(CPPDEFINES=["ZSTD_HAVE_WEAK_SYMBOLS=0"])
|
||||
env.extra_suffix = ".gdnative" + env.extra_suffix
|
||||
env.Append(CCFLAGS=["-s", "SIDE_MODULE=2"])
|
||||
env.Append(LINKFLAGS=["-s", "SIDE_MODULE=2"])
|
||||
env.extra_suffix = ".dlink" + env.extra_suffix
|
||||
|
||||
# Reduce code size by generating less support code (e.g. skip NodeJS support).
|
||||
env.Append(LINKFLAGS=["-s", "ENVIRONMENT=web,worker"])
|
||||
|
|
|
@ -37,26 +37,25 @@ def create_engine_file(env, target, source, externs):
|
|||
return env.Textfile(target, [env.File(s) for s in source])
|
||||
|
||||
|
||||
def create_template_zip(env, js, wasm, extra):
|
||||
def create_template_zip(env, js, wasm, worker, side):
|
||||
binary_name = "godot.tools" if env["tools"] else "godot"
|
||||
zip_dir = env.Dir("#bin/.web_zip")
|
||||
in_files = [
|
||||
js,
|
||||
wasm,
|
||||
worker,
|
||||
"#platform/web/js/libs/audio.worklet.js",
|
||||
]
|
||||
out_files = [
|
||||
zip_dir.File(binary_name + ".js"),
|
||||
zip_dir.File(binary_name + ".wasm"),
|
||||
zip_dir.File(binary_name + ".worker.js"),
|
||||
zip_dir.File(binary_name + ".audio.worklet.js"),
|
||||
]
|
||||
# GDNative/Threads specific
|
||||
if env["gdnative_enabled"]:
|
||||
in_files.append(extra.pop()) # Runtime
|
||||
# Dynamic linking (extensions) specific.
|
||||
if env["dlink_enabled"]:
|
||||
in_files.append(side) # Side wasm (contains the actual Godot code).
|
||||
out_files.append(zip_dir.File(binary_name + ".side.wasm"))
|
||||
if env["threads_enabled"]:
|
||||
in_files.append(extra.pop()) # Worker
|
||||
out_files.append(zip_dir.File(binary_name + ".worker.js"))
|
||||
|
||||
service_worker = "#misc/dist/html/service-worker.js"
|
||||
if env["tools"]:
|
||||
|
|
|
@ -201,7 +201,7 @@ Error EditorExportPlatformWeb::_build_pwa(const Ref<EditorExportPreset> &p_prese
|
|||
// Service worker
|
||||
const String dir = p_path.get_base_dir();
|
||||
const String name = p_path.get_file().get_basename();
|
||||
const ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
|
||||
bool extensions = (bool)p_preset->get("variant/extensions_support");
|
||||
HashMap<String, String> replaces;
|
||||
replaces["@GODOT_VERSION@"] = String::num_int64(OS::get_singleton()->get_unix_time()) + "|" + String::num_int64(OS::get_singleton()->get_ticks_usec());
|
||||
replaces["@GODOT_NAME@"] = proj_name.substr(0, 16);
|
||||
|
@ -216,17 +216,15 @@ Error EditorExportPlatformWeb::_build_pwa(const Ref<EditorExportPreset> &p_prese
|
|||
cache_files.push_back(name + ".icon.png");
|
||||
cache_files.push_back(name + ".apple-touch-icon.png");
|
||||
}
|
||||
if (mode & EXPORT_MODE_THREADS) {
|
||||
cache_files.push_back(name + ".worker.js");
|
||||
cache_files.push_back(name + ".audio.worklet.js");
|
||||
}
|
||||
replaces["@GODOT_CACHE@"] = Variant(cache_files).to_json_string();
|
||||
|
||||
// Heavy files that are cached on demand.
|
||||
Array opt_cache_files;
|
||||
opt_cache_files.push_back(name + ".wasm");
|
||||
opt_cache_files.push_back(name + ".pck");
|
||||
if (mode & EXPORT_MODE_GDNATIVE) {
|
||||
if (extensions) {
|
||||
opt_cache_files.push_back(name + ".side.wasm");
|
||||
for (int i = 0; i < p_shared_objects.size(); i++) {
|
||||
opt_cache_files.push_back(p_shared_objects[i].path.get_file());
|
||||
|
@ -317,20 +315,14 @@ void EditorExportPlatformWeb::get_preset_features(const Ref<EditorExportPreset>
|
|||
r_features->push_back("etc2");
|
||||
}
|
||||
}
|
||||
ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
|
||||
if (mode & EXPORT_MODE_THREADS) {
|
||||
r_features->push_back("threads");
|
||||
}
|
||||
if (mode & EXPORT_MODE_GDNATIVE) {
|
||||
r_features->push_back("wasm32");
|
||||
}
|
||||
}
|
||||
|
||||
void EditorExportPlatformWeb::get_export_options(List<ExportOption> *r_options) {
|
||||
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
|
||||
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
|
||||
|
||||
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "variant/export_type", PROPERTY_HINT_ENUM, "Regular,Threads,GDNative"), 0)); // Export type.
|
||||
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "variant/extensions_support"), false)); // Export type.
|
||||
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_desktop"), true)); // S3TC
|
||||
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_mobile"), false)); // ETC or ETC2, depending on renderer
|
||||
|
||||
|
@ -374,11 +366,11 @@ bool EditorExportPlatformWeb::has_valid_export_configuration(const Ref<EditorExp
|
|||
|
||||
String err;
|
||||
bool valid = false;
|
||||
ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
|
||||
bool extensions = (bool)p_preset->get("variant/extensions_support");
|
||||
|
||||
// Look for export templates (first official, and if defined custom templates).
|
||||
bool dvalid = exists_export_template(_get_template_name(mode, true), &err);
|
||||
bool rvalid = exists_export_template(_get_template_name(mode, false), &err);
|
||||
bool dvalid = exists_export_template(_get_template_name(extensions, true), &err);
|
||||
bool rvalid = exists_export_template(_get_template_name(extensions, false), &err);
|
||||
|
||||
if (p_preset->get("custom_template/debug") != "") {
|
||||
dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
|
||||
|
@ -456,8 +448,8 @@ Error EditorExportPlatformWeb::export_project(const Ref<EditorExportPreset> &p_p
|
|||
String template_path = p_debug ? custom_debug : custom_release;
|
||||
template_path = template_path.strip_edges();
|
||||
if (template_path.is_empty()) {
|
||||
ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
|
||||
template_path = find_export_template(_get_template_name(mode, p_debug));
|
||||
bool extensions = (bool)p_preset->get("variant/extensions_support");
|
||||
template_path = find_export_template(_get_template_name(extensions, p_debug));
|
||||
}
|
||||
|
||||
if (!DirAccess::exists(base_dir)) {
|
||||
|
|
|
@ -57,20 +57,10 @@ class EditorExportPlatformWeb : public EditorExportPlatform {
|
|||
Mutex server_lock;
|
||||
Thread server_thread;
|
||||
|
||||
enum ExportMode {
|
||||
EXPORT_MODE_NORMAL = 0,
|
||||
EXPORT_MODE_THREADS = 1,
|
||||
EXPORT_MODE_GDNATIVE = 2,
|
||||
EXPORT_MODE_THREADS_GDNATIVE = 3,
|
||||
};
|
||||
|
||||
String _get_template_name(ExportMode p_mode, bool p_debug) const {
|
||||
String name = "webassembly";
|
||||
if (p_mode & EXPORT_MODE_GDNATIVE) {
|
||||
name += "_gdnative";
|
||||
}
|
||||
if (p_mode & EXPORT_MODE_THREADS) {
|
||||
name += "_threads";
|
||||
String _get_template_name(bool p_extension, bool p_debug) const {
|
||||
String name = "web";
|
||||
if (p_extension) {
|
||||
name += "_dlink";
|
||||
}
|
||||
if (p_debug) {
|
||||
name += "_debug.zip";
|
||||
|
|
|
@ -140,26 +140,9 @@ int OS_Web::get_processor_count() const {
|
|||
}
|
||||
|
||||
bool OS_Web::_check_internal_feature_support(const String &p_feature) {
|
||||
if (p_feature == "html5" || p_feature == "web") {
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef JAVASCRIPT_EVAL_ENABLED
|
||||
if (p_feature == "web") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#ifndef NO_THREADS
|
||||
if (p_feature == "threads") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#if WASM_GDNATIVE
|
||||
if (p_feature == "wasm32") {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue