From c572d6b029d4ccaddec0c6127085b6103a561596 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 23 Jul 2026 09:28:59 -0700 Subject: [PATCH] Remove internal `settings.LTO` in favor of `options.lto` Followup to #27407 Because `settings.LTO` was an internal setting not used anywhere in JavaScript libraries or runtime code. This change removes `LTO` from `src/settings_internal.js` and stores `-flto` / `-fno-lto` state in `options.lto` on `EmccOptions` instead. --- embuilder.py | 3 ++- emcc.py | 2 +- src/settings_internal.js | 2 -- test/test_other.py | 9 +++++---- tools/building.py | 3 ++- tools/cache.py | 6 ++++-- tools/cmdline.py | 7 ++++--- tools/link.py | 2 +- tools/system_libs.py | 4 ++-- 9 files changed, 21 insertions(+), 17 deletions(-) diff --git a/embuilder.py b/embuilder.py index 69faad238315f..56d1763990a9a 100755 --- a/embuilder.py +++ b/embuilder.py @@ -21,6 +21,7 @@ from contextlib import contextmanager from tools import cache, ports, shared, system_libs, utils +from tools.cmdline import options from tools.settings import settings from tools.system_libs import USE_NINJA @@ -232,7 +233,7 @@ def main(): shared.check_sanity() if args.lto: - settings.LTO = args.lto + options.lto = args.lto if args.verbose: shared.PRINT_SUBPROCS = True diff --git a/emcc.py b/emcc.py index 5db5426514e14..1e12e427fbe3d 100644 --- a/emcc.py +++ b/emcc.py @@ -524,7 +524,7 @@ def get_clang_command_asm(): return compiler + compile.get_target_flags() if state.mode == Mode.COMPILE_ONLY: - if options.output_file and get_file_suffix(options.output_file) == '.bc' and not settings.LTO and '-emit-llvm' not in state.orig_args: + if options.output_file and get_file_suffix(options.output_file) == '.bc' and not options.lto and '-emit-llvm' not in state.orig_args: diagnostics.warning('emcc', '.bc output file suffix used without -flto or -emit-llvm. Consider using .o extension since emcc will output an object file, not a bitcode file') if all(get_file_suffix(i) in ASSEMBLY_EXTENSIONS for i in options.input_files): cmd = get_clang_command_asm() + newargs diff --git a/src/settings_internal.js b/src/settings_internal.js index 7405b50118136..2570058c62da3 100644 --- a/src/settings_internal.js +++ b/src/settings_internal.js @@ -152,8 +152,6 @@ var MINIFY_WASM_IMPORTED_MODULES = false; // Whether to minify exports from the Wasm module. var MINIFY_WASM_EXPORT_NAMES = true; -// Internal: value of -flto argument (either full or thin) -var LTO = 0; // Whether we may be accessing the address 2GB or higher. If so, then we need // to interpret incoming i32 pointers as unsigned. diff --git a/test/test_other.py b/test/test_other.py index 3b4223dfbb81b..2692fcf07299d 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -102,6 +102,7 @@ from tools import building, cache, response_file, shared, utils, webassembly from tools.building import get_building_env +from tools.cmdline import options from tools.link import binary_encode from tools.settings import settings from tools.shared import ( @@ -753,7 +754,7 @@ def test_print_search_dirs(self, args): libpath = output.split('libraries: =', 1)[1].strip() libpath = libpath.split(os.pathsep) libpath = [Path(p) for p in libpath] - settings.LTO = '-flto' in args + options.lto = 'full' if '-flto' in args else None settings.MEMORY64 = int('-m64' in args) expected = cache.get_lib_dir(absolute=True) self.assertIn(expected, libpath) @@ -768,7 +769,7 @@ def test_print_libgcc_file_name(self, args): output = self.run_process([EMCC, '-print-libgcc-file-name'] + args, stdout=PIPE).stdout output2 = self.run_process([EMCC, '--print-libgcc-file-name'] + args, stdout=PIPE).stdout self.assertEqual(output, output2) - settings.LTO = '-flto' in args + options.lto = 'full' if '-flto' in args else None settings.MEMORY64 = int('-m64' in args) libdir = cache.get_lib_dir(absolute=True) expected = os.path.join(libdir, 'libclang_rt.builtins.a') @@ -805,7 +806,7 @@ def test_print_file_name(self, args): output2 = self.run_process([EMCC, '--print-file-name=libc.a'] + args, stdout=PIPE).stdout.rstrip() self.assertEqual(output, output2) filename = Path(output) - settings.LTO = '-flto' in args + options.lto = 'full' if '-flto' in args else None settings.MEMORY64 = int('-m64' in args) self.assertContained(cache.get_lib_name('libc.a'), str(filename)) @@ -11791,7 +11792,7 @@ def test_setjmp_emulated_casts(self): self.do_runf('src.c', 'ok\ndone\n', cflags=['-sEMULATE_FUNCTION_POINTER_CASTS']) def test_no_lto(self): - # This used to fail because settings.LTO didn't reflect `-fno-lto`. + # This used to fail because options.lto didn't reflect `-fno-lto`. # See bug https://github.com/emscripten-core/emscripten/issues/20308 create_file('src.c', r''' #include diff --git a/tools/building.py b/tools/building.py index bf635e96142f3..10b1888d5738e 100644 --- a/tools/building.py +++ b/tools/building.py @@ -16,6 +16,7 @@ from . import ( cache, + cmdline, config, diagnostics, js_optimizer, @@ -190,7 +191,7 @@ def lld_flags_for_executable(external_symbols): not settings.ASYNCIFY): cmd.append('--strip-debug') - if settings.LTO and not settings.EXIT_RUNTIME: + 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 diff --git a/tools/cache.py b/tools/cache.py index a933ace8b1efb..c90b0d38acdbb 100644 --- a/tools/cache.py +++ b/tools/cache.py @@ -110,6 +110,8 @@ def get_sysroot_dir(*parts): def get_lib_dir(absolute): + from .cmdline import options + ensure_setup() path = Path(get_sysroot(absolute=absolute), 'lib') if settings.MEMORY64: @@ -118,8 +120,8 @@ def get_lib_dir(absolute): path = Path(path, 'wasm32-emscripten') # if relevant, use a subdir of the cache subdir = [] - if settings.LTO: - if settings.LTO == 'thin': + if options.lto: + if options.lto == 'thin': subdir.append('thinlto') else: subdir.append('lto') diff --git a/tools/cmdline.py b/tools/cmdline.py index a41142a424dbf..e77e5f66821e0 100644 --- a/tools/cmdline.py +++ b/tools/cmdline.py @@ -73,6 +73,7 @@ class EmccOptions: input_language = None js_transform = None lib_dirs: list[str] = [] + lto: str | None = None memory_profiler = False no_entry = False no_minify = False @@ -315,11 +316,11 @@ def consume_arg_file(): settings.OPT_LEVEL = level elif arg.startswith('-flto'): if '=' in arg: - settings.LTO = arg.split('=')[1] + options.lto = arg.split('=')[1] else: - settings.LTO = 'full' + options.lto = 'full' elif arg == "-fno-lto": - settings.LTO = 0 + options.lto = None elif arg == "--save-temps": options.save_temps = True elif check_arg('--closure-args'): diff --git a/tools/link.py b/tools/link.py index a5772f709679d..daad61cc53659 100644 --- a/tools/link.py +++ b/tools/link.py @@ -3111,7 +3111,7 @@ def package_files(target): @ToolchainProfiler.profile_block('calculate linker inputs') def phase_calculate_linker_inputs(linker_args): - using_lld = not (options.oformat == OFormat.OBJECT and settings.LTO) + using_lld = not (options.oformat == OFormat.OBJECT and options.lto) linker_args = filter_link_flags(linker_args, using_lld) diff --git a/tools/system_libs.py b/tools/system_libs.py index 1e879ced24731..4a61793bd280b 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -62,8 +62,8 @@ def get_base_cflags(build_dir, force_object_files=False, preprocess=True): # Always build system libraries with debug information. Non-debug builds # will ignore this at link time because we link with `-strip-debug`. flags = ['-g', '-sSTRICT', '-Werror'] - if settings.LTO and not force_object_files: - flags += ['-flto=' + settings.LTO] + if options.lto and not force_object_files: + flags += ['-flto=' + options.lto] if settings.MAIN_MODULE or settings.SIDE_MODULE: # Explicitly include `-sMAIN_MODULE` when building system libraries. # `-fPIC` alone is not enough to configure trigger the building and