Skip to content

Commit

Permalink
Move all command line flag processing to emcc.py. NFC (#23497)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
sbc100 authored Jan 27, 2025
1 parent db69527 commit 9d6742a
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 28 deletions.
23 changes: 23 additions & 0 deletions emcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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)

Expand Down
34 changes: 13 additions & 21 deletions tools/link.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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).
Expand All @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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)


Expand Down Expand Up @@ -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:
Expand Down
14 changes: 7 additions & 7 deletions tools/system_libs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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')

Expand All @@ -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

Expand Down Expand Up @@ -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')
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 9d6742a

Please sign in to comment.