diff --git a/emcc.py b/emcc.py index a92a10e27964b..fb668a136e6ac 100755 --- a/emcc.py +++ b/emcc.py @@ -2460,7 +2460,7 @@ def get_full_import_name(name): @ToolchainProfiler.profile_block('compile inputs') def phase_compile_inputs(options, state, newargs, input_files): def is_link_flag(flag): - if flag.startswith('-nostdlib'): + if flag in ('-nostdlib', '-nostartfiles', '-nolibc', '-nodefaultlibs'): return True return flag.startswith(('-l', '-L', '-Wl,')) @@ -2626,8 +2626,8 @@ def phase_calculate_system_libraries(state, linker_arguments, linker_inputs, new if not settings.SIDE_MODULE: # Ports are always linked into the main module, never the size module. extra_files_to_link += ports.get_libs(settings) - if '-nostdlib' not in newargs and '-nodefaultlibs' not in newargs: - extra_files_to_link += system_libs.calculate([f for _, f in sorted(linker_inputs)] + extra_files_to_link, forced=state.forced_stdlibs) + all_linker_inputs = [f for _, f in sorted(linker_inputs)] + extra_files_to_link + extra_files_to_link += system_libs.calculate(all_linker_inputs, newargs, forced=state.forced_stdlibs) linker_arguments.extend(extra_files_to_link) diff --git a/tests/test_other.py b/tests/test_other.py index b633c3342be76..b737926cd4f16 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -10131,6 +10131,8 @@ def test_nostdlib(self): libs = ['-lc', '-lcompiler_rt', '-lc_rt'] self.run_process([EMCC, test_file('unistd/close.c'), '-nostdlib'] + libs) self.run_process([EMCC, test_file('unistd/close.c'), '-nodefaultlibs'] + libs) + self.run_process([EMCC, test_file('unistd/close.c'), '-nolibc', '-lc']) + self.run_process([EMCC, test_file('unistd/close.c'), '-nostartfiles']) def test_argument_match(self): # Verify that emcc arguments match precisely. We had a bug where only the prefix diff --git a/tools/system_libs.py b/tools/system_libs.py index 47cad9824b7a4..4cb20a8feb1a5 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -1651,22 +1651,12 @@ def add_reverse_deps(need): add_reverse_deps(symbols) -def calculate(input_files, forced): - # Setting this will only use the forced libs in EMCC_FORCE_STDLIBS. This avoids spending time checking - # for unresolved symbols in your project files, which can speed up linking, but if you do not have - # the proper list of actually needed libraries, errors can occur. See below for how we must - # export all the symbols in deps_info when using this option. - only_forced = os.environ.get('EMCC_ONLY_FORCED_STDLIBS') - if only_forced: - # One of the purposes EMCC_ONLY_FORCED_STDLIBS was to skip the scanning - # of the input files for reverse dependencies. - diagnostics.warning('deprecated', 'EMCC_ONLY_FORCED_STDLIBS is deprecated. Use `-nostdlib` and/or `-s REVERSE_DEPS=none` depending on the desired result') - settings.REVERSE_DEPS = 'all' +def get_libs_to_link(args, forced, only_forced): + libs_to_link = [] - handle_reverse_deps(input_files) + if '-nostdlib' in args: + return libs_to_link - force_include = [] - libs_to_link = [] already_included = set() system_libs_map = Library.get_usable_variations() @@ -1675,6 +1665,7 @@ def calculate(input_files, forced): # it can be the name of a lib (libc++, etc.). # You can provide 1 to include everything, or a comma-separated list with the # ones you want + force_include = [] force = os.environ.get('EMCC_FORCE_STDLIBS') if force == '1': force_include = [name for name, lib in system_libs_map.items() if not lib.never_force] @@ -1695,93 +1686,118 @@ def add_library(libname): need_whole_archive = lib.name in force_include and lib.get_ext() == '.a' libs_to_link.append((lib.get_link_flag(), need_whole_archive)) - if settings.USE_PTHREADS: - add_library('crtbegin') + if '-nostartfiles' not in args: + if settings.USE_PTHREADS: + add_library('crtbegin') - if settings.SIDE_MODULE: - return [l[0] for l in libs_to_link] + if settings.STANDALONE_WASM: + if settings.EXPECT_MAIN: + add_library('crt1') + else: + add_library('crt1_reactor') - if settings.STANDALONE_WASM: - if settings.EXPECT_MAIN: - add_library('crt1') - else: - add_library('crt1_reactor') + if settings.SIDE_MODULE: + return libs_to_link for forced in force_include: if forced not in system_libs_map: shared.exit_with_error('invalid forced library: %s', forced) add_library(forced) + if '-nodefaultlibs' in args: + return libs_to_link + if only_forced: add_library('libc_rt') add_library('libcompiler_rt') - else: - if settings.AUTO_NATIVE_LIBRARIES: - add_library('libGL') - add_library('libal') - add_library('libhtml5') + return libs_to_link - sanitize = settings.USE_LSAN or settings.USE_ASAN or settings.UBSAN_RUNTIME + if settings.AUTO_NATIVE_LIBRARIES: + add_library('libGL') + add_library('libal') + add_library('libhtml5') - # JS math must come before anything else, so that it overrides the normal - # libc math. - if settings.JS_MATH: - add_library('libjsmath') + sanitize = settings.USE_LSAN or settings.USE_ASAN or settings.UBSAN_RUNTIME - # to override the normal libc printf, we must come before it - if settings.PRINTF_LONG_DOUBLE: - add_library('libprintf_long_double') + # JS math must come before anything else, so that it overrides the normal + # libc math. + if settings.JS_MATH: + add_library('libjsmath') - if settings.ALLOW_UNIMPLEMENTED_SYSCALLS: - add_library('libstubs') + # to override the normal libc printf, we must come before it + if settings.PRINTF_LONG_DOUBLE: + add_library('libprintf_long_double') + + if settings.ALLOW_UNIMPLEMENTED_SYSCALLS: + add_library('libstubs') + if '-nolibc' not in args: if not settings.EXIT_RUNTIME: add_library('libnoexit') add_library('libc') - add_library('libcompiler_rt') - if settings.LINK_AS_CXX: - add_library('libc++') - if settings.LINK_AS_CXX or sanitize: - add_library('libc++abi') - if settings.EXCEPTION_HANDLING: - add_library('libunwind') if settings.MALLOC != 'none': add_library('libmalloc') - if settings.STANDALONE_WASM: - add_library('libstandalonewasm') - add_library('libc_rt') + add_library('libcompiler_rt') + if settings.LINK_AS_CXX: + add_library('libc++') + if settings.LINK_AS_CXX or sanitize: + add_library('libc++abi') + if settings.EXCEPTION_HANDLING: + add_library('libunwind') + if settings.STANDALONE_WASM: + add_library('libstandalonewasm') + add_library('libc_rt') - if settings.USE_LSAN: - force_include.append('liblsan_rt') - add_library('liblsan_rt') + if settings.USE_LSAN: + force_include.append('liblsan_rt') + add_library('liblsan_rt') - if settings.USE_ASAN: - force_include.append('libasan_rt') - add_library('libasan_rt') - add_library('libasan_js') + if settings.USE_ASAN: + force_include.append('libasan_rt') + add_library('libasan_rt') + add_library('libasan_js') - if settings.UBSAN_RUNTIME == 1: - add_library('libubsan_minimal_rt') - elif settings.UBSAN_RUNTIME == 2: - add_library('libubsan_rt') + if settings.UBSAN_RUNTIME == 1: + add_library('libubsan_minimal_rt') + elif settings.UBSAN_RUNTIME == 2: + add_library('libubsan_rt') - if settings.USE_LSAN or settings.USE_ASAN: - add_library('liblsan_common_rt') + if settings.USE_LSAN or settings.USE_ASAN: + add_library('liblsan_common_rt') - if sanitize: - add_library('libsanitizer_common_rt') + if sanitize: + add_library('libsanitizer_common_rt') - if settings.PROXY_POSIX_SOCKETS: - add_library('libsockets_proxy') - else: - add_library('libsockets') + if settings.PROXY_POSIX_SOCKETS: + add_library('libsockets_proxy') + else: + add_library('libsockets') + + if settings.USE_WEBGPU: + add_library('libwebgpu_cpp') + + return libs_to_link + + +def calculate(input_files, args, forced): + # Setting this will only use the forced libs in EMCC_FORCE_STDLIBS. This avoids spending time checking + # for unresolved symbols in your project files, which can speed up linking, but if you do not have + # the proper list of actually needed libraries, errors can occur. See below for how we must + # export all the symbols in deps_info when using this option. + only_forced = os.environ.get('EMCC_ONLY_FORCED_STDLIBS') + if only_forced: + # One of the purposes EMCC_ONLY_FORCED_STDLIBS was to skip the scanning + # of the input files for reverse dependencies. + diagnostics.warning('deprecated', 'EMCC_ONLY_FORCED_STDLIBS is deprecated. Use `-nostdlib` and/or `-s REVERSE_DEPS=none` depending on the desired result') + settings.REVERSE_DEPS = 'all' + + handle_reverse_deps(input_files) - if settings.USE_WEBGPU: - add_library('libwebgpu_cpp') + libs_to_link = get_libs_to_link(args, forced, only_forced) # 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 # shouldn't add any extra `--no-whole-archive` or we will undo the intent of building.link_ldd. - if settings.LINKABLE: + if settings.LINKABLE or settings.SIDE_MODULE: return [l[0] for l in libs_to_link] # Wrap libraries in --whole-archive, as needed. We need to do this last