From 66ef2151a4bff4f4c50b3fad89db81a9b596305c Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Thu, 20 Aug 2026 21:50:10 +0000 Subject: [PATCH] Force __cxa_can_catch in LTO with exceptions During LTO code generation, the LLVM backend lowers Emscripten exception handling into calls to __cxa_find_matching_catch_N, which is provided by JS library code and requires __cxa_can_catch from libc++abi. Because libc++abi is an archive of bitcode files in LTO builds, __cxa_can_catch is not extracted before LTO codegen unless explicitly referenced, leading to undefined symbol errors. --- tools/building.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/tools/building.py b/tools/building.py index fa0e0ee02fac5..1db1e4a906295 100644 --- a/tools/building.py +++ b/tools/building.py @@ -195,14 +195,19 @@ def lld_flags_for_executable(external_symbols): not settings.ASYNCIFY): cmd.append('--strip-debug') - if cmdline.options.lto and not settings.EXIT_RUNTIME: - # The WebAssembly backend can generate new references to `__cxa_atexit` at - # LTO time. This `-u` flag forces the `__cxa_atexit` symbol to be - # included at LTO time. For other such symbols we exclude them from LTO - # and always build them as normal object files, but that would inhibit the - # LowerGlobalDtors optimization which allows destructors to be completely - # removed when __cxa_atexit is a no-op. - cmd.append('-u__cxa_atexit') + if cmdline.options.lto: + if not settings.EXIT_RUNTIME: + # The WebAssembly backend can generate new references to `__cxa_atexit` at + # LTO time. This `-u` flag forces the `__cxa_atexit` symbol to be + # included at LTO time. For other such symbols we exclude them from LTO + # and always build them as normal object files, but that would inhibit the + # LowerGlobalDtors optimization which allows destructors to be completely + # removed when __cxa_atexit is a no-op. + cmd.append('-u__cxa_atexit') + if not settings.DISABLE_EXCEPTION_CATCHING: + # The WebAssembly backend can generate new references to `__cxa_find_matching_catch_N` + # at LTO time, which depends on `__cxa_can_catch` in libc++abi. + cmd.append('-u__cxa_can_catch') c_exports = [e for e in settings.EXPORTED_FUNCTIONS if is_c_symbol(e)] # Strip the leading underscores