From 9d6742aa991a9f75bcf759dd6d4183f3fbec5545 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 27 Jan 2025 12:38:03 -0800 Subject: [PATCH] Move all command line flag processing to emcc.py. NFC (#23497) This change paves to the way for link.py refactor I'm working on, but it also seems like a good idea to keep argument processing in one place. --- emcc.py | 23 +++++++++++++++++++++++ tools/link.py | 34 +++++++++++++--------------------- tools/system_libs.py | 14 +++++++------- 3 files changed, 43 insertions(+), 28 deletions(-) diff --git a/emcc.py b/emcc.py index 99fbc105313ee..e7ef01b4f78d5 100644 --- a/emcc.py +++ b/emcc.py @@ -183,6 +183,13 @@ def __init__(self): self.dash_S = False self.dash_M = False self.input_language = None + self.nostdlib = False + self.nostdlibxx = False + self.nodefaultlibs = False + self.nolibc = False + self.nostartfiles = False + self.sanitize_minimal_runtime = False + self.sanitize = set() def create_reproduce_file(name, args): @@ -1421,6 +1428,22 @@ def consume_arg_file(): # SSEx is implemented on top of SIMD128 instruction set, but do not pass SSE flags to LLVM # so it won't think about generating native x86 SSE code. newargs[i] = '' + elif arg == '-nostdlib': + options.nostdlib = True + elif arg == '-nostdlibxx': + options.nostdlibxx = True + elif arg == '-nodefaultlibs': + options.nodefaultlibs = True + elif arg == '-nolibc': + options.nolibc = True + elif arg == '-nostartfiles': + options.nostartfiles = True + elif arg == '-fsanitize-minimal-runtime': + options.sanitize_minimal_runtime = True + elif arg.startswith('-fsanitize='): + options.sanitize.update(arg.split('=', 1)[1].split(',')) + elif arg.startswith('-fno-sanitize='): + options.sanitize.difference_update(arg.split('=', 1)[1].split(',')) elif arg and (arg == '-' or not arg.startswith('-')): options.input_files.append(arg) diff --git a/tools/link.py b/tools/link.py index 11fed89ae1855..64e501d21486d 100644 --- a/tools/link.py +++ b/tools/link.py @@ -655,7 +655,7 @@ def phase_linker_setup(options, state): # noqa: C901, PLR0912, PLR0915 if not shared.SKIP_SUBPROCS: shared.check_llvm_version() - autoconf = os.environ.get('EMMAKEN_JUST_CONFIGURE') or 'conftest.c' in state.orig_args or 'conftest.cpp' in state.orig_args + autoconf = os.environ.get('EMMAKEN_JUST_CONFIGURE') or 'conftest.c' in options.input_files or 'conftest.cpp' in options.input_files if autoconf: # configure tests want a more shell-like style, where we emit return codes on exit() settings.EXIT_RUNTIME = 1 @@ -899,7 +899,7 @@ def phase_linker_setup(options, state): # noqa: C901, PLR0912, PLR0915 # PURE_WASI, or when we are linking without standard libraries because # STACK_OVERFLOW_CHECK depends on emscripten_stack_get_end which is defined # in libcompiler-rt. - if not settings.PURE_WASI and '-nostdlib' not in state.orig_args and '-nodefaultlibs' not in state.orig_args: + if not settings.PURE_WASI and not options.nostdlib and not options.nodefaultlibs: default_setting('STACK_OVERFLOW_CHECK', max(settings.ASSERTIONS, settings.STACK_OVERFLOW_CHECK)) # For users that opt out of WARN_ON_UNDEFINED_SYMBOLS we assume they also @@ -1536,15 +1536,7 @@ def phase_linker_setup(options, state): # noqa: C901, PLR0912, PLR0915 if settings.SIDE_MODULE and shared.suffix(target) == '.js': diagnostics.warning('emcc', 'output suffix .js requested, but wasm side modules are just wasm files; emitting only a .wasm, no .js') - sanitize = set() - - for arg in state.orig_args: - if arg.startswith('-fsanitize='): - sanitize.update(arg.split('=', 1)[1].split(',')) - elif arg.startswith('-fno-sanitize='): - sanitize.difference_update(arg.split('=', 1)[1].split(',')) - - if sanitize: + if options.sanitize: settings.USE_OFFSET_CONVERTER = 1 # These symbols are needed by `withBuiltinMalloc` which used to implement # the `__noleakcheck` attribute. However this dependency is not yet represented in the JS @@ -1560,7 +1552,7 @@ def phase_linker_setup(options, state): # noqa: C901, PLR0912, PLR0915 'emscripten_builtin_free', ] - if ('leak' in sanitize or 'address' in sanitize) and not settings.ALLOW_MEMORY_GROWTH: + if ('leak' in options.sanitize or 'address' in options.sanitize) and not settings.ALLOW_MEMORY_GROWTH: # Increase the minimum memory requirements to account for extra memory # that the sanitizers might need (in addition to the shadow memory # requirements handled below). @@ -1576,17 +1568,17 @@ def phase_linker_setup(options, state): # noqa: C901, PLR0912, PLR0915 exit_with_error('wasm2js is not compatible with USE_OFFSET_CONVERTER (see #14630)') settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.append('$UTF8ArrayToString') - if sanitize & UBSAN_SANITIZERS: - if '-fsanitize-minimal-runtime' in state.orig_args: + if options.sanitize & UBSAN_SANITIZERS: + if options.sanitize_minimal_runtime: settings.UBSAN_RUNTIME = 1 else: settings.UBSAN_RUNTIME = 2 - if 'leak' in sanitize: + if 'leak' in options.sanitize: settings.USE_LSAN = 1 default_setting('EXIT_RUNTIME', 1) - if 'address' in sanitize: + if 'address' in options.sanitize: settings.USE_ASAN = 1 default_setting('EXIT_RUNTIME', 1) if not settings.UBSAN_RUNTIME: @@ -1661,7 +1653,7 @@ def phase_linker_setup(options, state): # noqa: C901, PLR0912, PLR0915 # ASan and SAFE_HEAP check address 0 themselves settings.CHECK_NULL_WRITES = 0 - if sanitize and settings.GENERATE_SOURCE_MAP: + if options.sanitize and settings.GENERATE_SOURCE_MAP: settings.LOAD_SOURCE_MAP = 1 if 'GLOBAL_BASE' not in user_settings and not settings.SHRINK_LEVEL and not settings.OPT_LEVEL and not settings.USE_ASAN: @@ -1792,7 +1784,7 @@ def get_full_import_name(name): settings.EMSCRIPTEN_VERSION = utils.EMSCRIPTEN_VERSION settings.SOURCE_MAP_BASE = options.source_map_base or '' - settings.LINK_AS_CXX = (shared.run_via_emxx or settings.DEFAULT_TO_CXX) and '-nostdlib++' not in state.orig_args + settings.LINK_AS_CXX = (shared.run_via_emxx or settings.DEFAULT_TO_CXX) and not options.nostdlibxx # WASMFS itself is written in C++, and needs C++ standard libraries if settings.WASMFS: @@ -1867,13 +1859,13 @@ def get_full_import_name(name): @ToolchainProfiler.profile_block('calculate system libraries') -def phase_calculate_system_libraries(state, linker_arguments): +def phase_calculate_system_libraries(options, linker_arguments): extra_files_to_link = [] # Link in ports and system libraries, if necessary if not settings.SIDE_MODULE: # Ports are always linked into the main module, never the side module. extra_files_to_link += ports.get_libs(settings) - extra_files_to_link += system_libs.calculate(state.orig_args) + extra_files_to_link += system_libs.calculate(options) linker_arguments.extend(extra_files_to_link) @@ -3128,7 +3120,7 @@ def run(linker_inputs, options, state): logger.debug('stopping after linking to object file') return 0 - phase_calculate_system_libraries(state, linker_arguments) + phase_calculate_system_libraries(options, linker_arguments) js_syms = {} if (not settings.SIDE_MODULE or settings.ASYNCIFY) and not shared.SKIP_SUBPROCS: diff --git a/tools/system_libs.py b/tools/system_libs.py index d2b390d3ee925..3eed0447651df 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -2234,10 +2234,10 @@ class libstubs(DebugLibrary): src_files = ['emscripten_syscall_stubs.c', 'emscripten_libc_stubs.c'] -def get_libs_to_link(args): +def get_libs_to_link(options): libs_to_link = [] - if '-nostdlib' in args: + if options.nostdlib: return libs_to_link already_included = set() @@ -2277,7 +2277,7 @@ def add_library(libname, whole_archive=False): need_whole_archive = lib.name in force_include and lib.get_ext() == '.a' libs_to_link.append((lib.get_link_flag(), whole_archive or need_whole_archive)) - if '-nostartfiles' not in args: + if not options.nostartfiles: if settings.SHARED_MEMORY: add_library('crtbegin') @@ -2302,7 +2302,7 @@ def add_forced_libs(): shared.exit_with_error('invalid forced library: %s', forced) add_library(forced) - if '-nodefaultlibs' in args: + if options.nodefaultlibs: add_forced_libs() return libs_to_link @@ -2355,7 +2355,7 @@ def add_sanitizer_libs(): add_library('libstandalonewasm') if settings.ALLOW_UNIMPLEMENTED_SYSCALLS: add_library('libstubs') - if '-nolibc' not in args: + if not options.nolibc: if not settings.EXIT_RUNTIME: add_library('libnoexit') add_library('libc') @@ -2407,9 +2407,9 @@ def add_sanitizer_libs(): return libs_to_link -def calculate(args): +def calculate(options): - libs_to_link = get_libs_to_link(args) + libs_to_link = get_libs_to_link(options) # When LINKABLE is set the entire link command line is wrapped in --whole-archive by # building.link_ldd. And since --whole-archive/--no-whole-archive processing does not nest we