From 55550da68b1e906049954de20c29e4b63716ded2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Mon, 14 Aug 2023 17:19:42 +0200 Subject: [PATCH] SCons: Disable C++ exception handling Upon investigating the extremely slow MSVC build times in #80513, I noticed that while Godot policy is to never use exceptions, we weren't enforcing it with compiler flags, and thus still included exception handling code and stack unwinding. This is wasteful on multiple aspects: - Binary size: Around 20% binary size reduction with exceptions disabled for both MSVC and GCC binaries. - Compile time: * More than 50% build time reduction with MSVC. * 10% to 25% build time reduction with GCC + LTO. - Performance: Possibly, needs to be benchmarked. Since users may want to re-enable exceptions in their own thirdparty code or the libraries they compile with Godot, this behavior can be toggled with the `disable_exceptions` SCons option, which defaults to true. --- SConstruct | 13 +++++++++++-- editor/plugins/script_editor_plugin.cpp | 2 +- modules/denoise/SCsub | 9 +++++++++ modules/fbx/fbx_parser/FBXMaterial.cpp | 9 +++------ platform/android/detect.py | 4 ++-- platform/iphone/detect.py | 8 -------- platform/javascript/detect.py | 6 +++--- servers/audio_server.h | 4 ++-- 8 files changed, 31 insertions(+), 24 deletions(-) diff --git a/SConstruct b/SConstruct index e8f000b334c..e589ee5e00f 100644 --- a/SConstruct +++ b/SConstruct @@ -131,6 +131,7 @@ opts.Add(EnumVariable("lto", "Link-time optimization (production builds)", "none opts.Add(BoolVariable("deprecated", "Enable deprecated features", True)) opts.Add(BoolVariable("minizip", "Enable ZIP archive support using minizip", True)) opts.Add(BoolVariable("xaudio2", "Enable the XAudio2 audio driver", False)) +opts.Add(BoolVariable("disable_exceptions", "Force disabling exception handling code", True)) opts.Add("custom_modules", "A list of comma-separated directory paths containing custom modules to build.", "") opts.Add(BoolVariable("custom_modules_recursive", "Detect custom modules recursively for each specified path.", True)) @@ -480,6 +481,16 @@ if selected_platform in platform_list: print(" Please adjust your scripts accordingly.") Exit(255) + # Disable exception handling. Godot doesn't use exceptions anywhere, and this + # saves around 20% of binary size and very significant build time (GH-80513). + if env["disable_exceptions"]: + if env.msvc: + env.Append(CPPDEFINES=[("_HAS_EXCEPTIONS", 0)]) + else: + env.Append(CCFLAGS=["-fno-exceptions"]) + elif env.msvc: + env.Append(CCFLAGS=["/EHsc"]) + # Configure compiler warnings if env.msvc: # MSVC # Truncations, narrowing conversions, signed/unsigned comparisons... @@ -492,8 +503,6 @@ if selected_platform in platform_list: env.Append(CCFLAGS=["/W2"] + disable_nonessential_warnings) else: # 'no' env.Append(CCFLAGS=["/w"]) - # Set exception handling model to avoid warnings caused by Windows system headers. - env.Append(CCFLAGS=["/EHsc"]) if env["werror"]: env.Append(CCFLAGS=["/WX"]) diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 66a1520a805..4cb11b1c44c 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -73,7 +73,7 @@ static bool _is_built_in_script(Script *p_script) { class EditorScriptCodeCompletionCache : public ScriptCodeCompletionCache { struct Cache { - uint64_t time_loaded; + uint64_t time_loaded = 0; RES cache; }; diff --git a/modules/denoise/SCsub b/modules/denoise/SCsub index 89433130013..9515377f0f8 100644 --- a/modules/denoise/SCsub +++ b/modules/denoise/SCsub @@ -109,6 +109,15 @@ env_oidn.AppendUnique(CPPDEFINES=["NDEBUG"]) # No assert() even in debug builds env_thirdparty = env_oidn.Clone() env_thirdparty.disable_warnings() + +if env["disable_exceptions"]: + # OIDN hard-requires exceptions, so we re-enable them here. + if env.msvc and ("_HAS_EXCEPTIONS", 0) in env_thirdparty["CPPDEFINES"]: + env_thirdparty["CPPDEFINES"].remove(("_HAS_EXCEPTIONS", 0)) + env_thirdparty.AppendUnique(CCFLAGS=["/EHsc"]) + elif not env.msvc and "-fno-exceptions" in env_thirdparty["CCFLAGS"]: + env_thirdparty["CCFLAGS"].remove("-fno-exceptions") + env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources) env.modules_sources += thirdparty_obj diff --git a/modules/fbx/fbx_parser/FBXMaterial.cpp b/modules/fbx/fbx_parser/FBXMaterial.cpp index 1148106db93..e80b47f249b 100644 --- a/modules/fbx/fbx_parser/FBXMaterial.cpp +++ b/modules/fbx/fbx_parser/FBXMaterial.cpp @@ -329,8 +329,8 @@ Video::Video(uint64_t id, const ElementPtr element, const Document &doc, const s if (Content && !Content->Tokens().empty()) { //this field is omitted when the embedded texture is already loaded, let's ignore if it's not found - try { - const Token *token = GetRequiredToken(Content, 0); + const Token *token = GetRequiredToken(Content, 0); + if (token) { const char *data = token->begin(); if (!token->IsBinary()) { if (*data != '"') { @@ -341,6 +341,7 @@ Video::Video(uint64_t id, const ElementPtr element, const Document &doc, const s // First time compute size (it could be large like 64Gb and it is good to allocate it once) for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx) { const Token *dataToken = GetRequiredToken(Content, tokenIdx); + ERR_FAIL_COND(!dataToken); size_t tokenLength = dataToken->end() - dataToken->begin() - 2; // ignore double quotes const char *base64data = dataToken->begin() + 1; const size_t outLength = Util::ComputeDecodedSizeBase64(base64data, tokenLength); @@ -383,10 +384,6 @@ Video::Video(uint64_t id, const ElementPtr element, const Document &doc, const s content = new uint8_t[len]; ::memcpy(content, data + 5, len); } - } catch (...) { - // //we don't need the content data for contents that has already been loaded - // ASSIMP_LOG_VERBOSE_DEBUG_F("Caught exception in FBXMaterial (likely because content was already loaded): ", - // runtimeError.what()); } } diff --git a/platform/android/detect.py b/platform/android/detect.py index b575e9f162b..c9ce633b51d 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -173,11 +173,11 @@ def configure(env): env["RANLIB"] = compiler_path + "/llvm-ranlib" env["AS"] = compiler_path + "/clang" - # Disable exceptions and rtti on non-tools (template) builds + # Disable rtti on non-tools (template) builds. if env["tools"]: env.Append(CXXFLAGS=["-frtti"]) else: - env.Append(CXXFLAGS=["-fno-rtti", "-fno-exceptions"]) + env.Append(CXXFLAGS=["-fno-rtti"]) # Don't use dynamic_cast, necessary with no-rtti. env.Append(CPPDEFINES=["NO_SAFE_CAST"]) diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py index bfbcc46d2e3..8be184a7c45 100644 --- a/platform/iphone/detect.py +++ b/platform/iphone/detect.py @@ -34,7 +34,6 @@ def get_opts(): ), ("IPHONESDK", "Path to the iPhone SDK", ""), BoolVariable("ios_simulator", "Build for iOS Simulator", False), - BoolVariable("ios_exceptions", "Enable exceptions", False), ("ios_triple", "Triple for ios toolchain", ""), ] @@ -157,13 +156,6 @@ def configure(env): env.Append(CPPDEFINES=["NEED_LONG_INT"]) env.Append(CPPDEFINES=["LIBYUV_DISABLE_NEON"]) - # Disable exceptions on non-tools (template) builds - if not env["tools"]: - if env["ios_exceptions"]: - env.Append(CCFLAGS=["-fexceptions"]) - else: - env.Append(CCFLAGS=["-fno-exceptions"]) - # Temp fix for ABS/MAX/MIN macros in iPhone SDK blocking compilation env.Append(CCFLAGS=["-Wno-ambiguous-macro"]) diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py index e3cf28e70c6..b32133e3326 100644 --- a/platform/javascript/detect.py +++ b/platform/javascript/detect.py @@ -88,9 +88,9 @@ def configure(env): print('Note: Forcing "initial_memory=64" as it is required for the web editor.') env["initial_memory"] = 64 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"]) + # Disable rtti on non-tools (template) builds. + # This helps keep the file size down. + env.Append(CCFLAGS=["-fno-rtti"]) # Don't use dynamic_cast, necessary with no-rtti. env.Append(CPPDEFINES=["NO_SAFE_CAST"]) diff --git a/servers/audio_server.h b/servers/audio_server.h index 10aa5b5d3dc..4cbd949e240 100644 --- a/servers/audio_server.h +++ b/servers/audio_server.h @@ -208,9 +208,9 @@ private: struct Effect { Ref effect; - bool enabled; + bool enabled = false; #ifdef DEBUG_ENABLED - uint64_t prof_time; + uint64_t prof_time = 0; #endif };