Skip to content

Commit fd23b8c

Browse files
authored
Refactor system library claculation to better handle -nostdlib and friends. (#15618)
This refactoring splits out `get_libs_to_link` into its own function which can early return once the list is complete. The follow gcc/clang flags are now (kind of) supported: - `-nostartfiles` - don't link crt1 and other startup files - `-nolibc` - don't link libc - `-nodefualtlibs`- don't link libc or compiler-rt or other stdlibs (but do link startup files) - `-nostdlib` - don't link any system libraries or startup files.
1 parent 1934a98 commit fd23b8c

File tree

3 files changed

+91
-73
lines changed

3 files changed

+91
-73
lines changed

emcc.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2460,7 +2460,7 @@ def get_full_import_name(name):
24602460
@ToolchainProfiler.profile_block('compile inputs')
24612461
def phase_compile_inputs(options, state, newargs, input_files):
24622462
def is_link_flag(flag):
2463-
if flag.startswith('-nostdlib'):
2463+
if flag in ('-nostdlib', '-nostartfiles', '-nolibc', '-nodefaultlibs'):
24642464
return True
24652465
return flag.startswith(('-l', '-L', '-Wl,'))
24662466

@@ -2626,8 +2626,8 @@ def phase_calculate_system_libraries(state, linker_arguments, linker_inputs, new
26262626
if not settings.SIDE_MODULE:
26272627
# Ports are always linked into the main module, never the size module.
26282628
extra_files_to_link += ports.get_libs(settings)
2629-
if '-nostdlib' not in newargs and '-nodefaultlibs' not in newargs:
2630-
extra_files_to_link += system_libs.calculate([f for _, f in sorted(linker_inputs)] + extra_files_to_link, forced=state.forced_stdlibs)
2629+
all_linker_inputs = [f for _, f in sorted(linker_inputs)] + extra_files_to_link
2630+
extra_files_to_link += system_libs.calculate(all_linker_inputs, newargs, forced=state.forced_stdlibs)
26312631
linker_arguments.extend(extra_files_to_link)
26322632

26332633

tests/test_other.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10131,6 +10131,8 @@ def test_nostdlib(self):
1013110131
libs = ['-lc', '-lcompiler_rt', '-lc_rt']
1013210132
self.run_process([EMCC, test_file('unistd/close.c'), '-nostdlib'] + libs)
1013310133
self.run_process([EMCC, test_file('unistd/close.c'), '-nodefaultlibs'] + libs)
10134+
self.run_process([EMCC, test_file('unistd/close.c'), '-nolibc', '-lc'])
10135+
self.run_process([EMCC, test_file('unistd/close.c'), '-nostartfiles'])
1013410136

1013510137
def test_argument_match(self):
1013610138
# Verify that emcc arguments match precisely. We had a bug where only the prefix

tools/system_libs.py

Lines changed: 86 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1651,22 +1651,12 @@ def add_reverse_deps(need):
16511651
add_reverse_deps(symbols)
16521652

16531653

1654-
def calculate(input_files, forced):
1655-
# Setting this will only use the forced libs in EMCC_FORCE_STDLIBS. This avoids spending time checking
1656-
# for unresolved symbols in your project files, which can speed up linking, but if you do not have
1657-
# the proper list of actually needed libraries, errors can occur. See below for how we must
1658-
# export all the symbols in deps_info when using this option.
1659-
only_forced = os.environ.get('EMCC_ONLY_FORCED_STDLIBS')
1660-
if only_forced:
1661-
# One of the purposes EMCC_ONLY_FORCED_STDLIBS was to skip the scanning
1662-
# of the input files for reverse dependencies.
1663-
diagnostics.warning('deprecated', 'EMCC_ONLY_FORCED_STDLIBS is deprecated. Use `-nostdlib` and/or `-s REVERSE_DEPS=none` depending on the desired result')
1664-
settings.REVERSE_DEPS = 'all'
1654+
def get_libs_to_link(args, forced, only_forced):
1655+
libs_to_link = []
16651656

1666-
handle_reverse_deps(input_files)
1657+
if '-nostdlib' in args:
1658+
return libs_to_link
16671659

1668-
force_include = []
1669-
libs_to_link = []
16701660
already_included = set()
16711661
system_libs_map = Library.get_usable_variations()
16721662

@@ -1675,6 +1665,7 @@ def calculate(input_files, forced):
16751665
# it can be the name of a lib (libc++, etc.).
16761666
# You can provide 1 to include everything, or a comma-separated list with the
16771667
# ones you want
1668+
force_include = []
16781669
force = os.environ.get('EMCC_FORCE_STDLIBS')
16791670
if force == '1':
16801671
force_include = [name for name, lib in system_libs_map.items() if not lib.never_force]
@@ -1695,93 +1686,118 @@ def add_library(libname):
16951686
need_whole_archive = lib.name in force_include and lib.get_ext() == '.a'
16961687
libs_to_link.append((lib.get_link_flag(), need_whole_archive))
16971688

1698-
if settings.USE_PTHREADS:
1699-
add_library('crtbegin')
1689+
if '-nostartfiles' not in args:
1690+
if settings.USE_PTHREADS:
1691+
add_library('crtbegin')
17001692

1701-
if settings.SIDE_MODULE:
1702-
return [l[0] for l in libs_to_link]
1693+
if settings.STANDALONE_WASM:
1694+
if settings.EXPECT_MAIN:
1695+
add_library('crt1')
1696+
else:
1697+
add_library('crt1_reactor')
17031698

1704-
if settings.STANDALONE_WASM:
1705-
if settings.EXPECT_MAIN:
1706-
add_library('crt1')
1707-
else:
1708-
add_library('crt1_reactor')
1699+
if settings.SIDE_MODULE:
1700+
return libs_to_link
17091701

17101702
for forced in force_include:
17111703
if forced not in system_libs_map:
17121704
shared.exit_with_error('invalid forced library: %s', forced)
17131705
add_library(forced)
17141706

1707+
if '-nodefaultlibs' in args:
1708+
return libs_to_link
1709+
17151710
if only_forced:
17161711
add_library('libc_rt')
17171712
add_library('libcompiler_rt')
1718-
else:
1719-
if settings.AUTO_NATIVE_LIBRARIES:
1720-
add_library('libGL')
1721-
add_library('libal')
1722-
add_library('libhtml5')
1713+
return libs_to_link
17231714

1724-
sanitize = settings.USE_LSAN or settings.USE_ASAN or settings.UBSAN_RUNTIME
1715+
if settings.AUTO_NATIVE_LIBRARIES:
1716+
add_library('libGL')
1717+
add_library('libal')
1718+
add_library('libhtml5')
17251719

1726-
# JS math must come before anything else, so that it overrides the normal
1727-
# libc math.
1728-
if settings.JS_MATH:
1729-
add_library('libjsmath')
1720+
sanitize = settings.USE_LSAN or settings.USE_ASAN or settings.UBSAN_RUNTIME
17301721

1731-
# to override the normal libc printf, we must come before it
1732-
if settings.PRINTF_LONG_DOUBLE:
1733-
add_library('libprintf_long_double')
1722+
# JS math must come before anything else, so that it overrides the normal
1723+
# libc math.
1724+
if settings.JS_MATH:
1725+
add_library('libjsmath')
17341726

1735-
if settings.ALLOW_UNIMPLEMENTED_SYSCALLS:
1736-
add_library('libstubs')
1727+
# to override the normal libc printf, we must come before it
1728+
if settings.PRINTF_LONG_DOUBLE:
1729+
add_library('libprintf_long_double')
1730+
1731+
if settings.ALLOW_UNIMPLEMENTED_SYSCALLS:
1732+
add_library('libstubs')
1733+
if '-nolibc' not in args:
17371734
if not settings.EXIT_RUNTIME:
17381735
add_library('libnoexit')
17391736
add_library('libc')
1740-
add_library('libcompiler_rt')
1741-
if settings.LINK_AS_CXX:
1742-
add_library('libc++')
1743-
if settings.LINK_AS_CXX or sanitize:
1744-
add_library('libc++abi')
1745-
if settings.EXCEPTION_HANDLING:
1746-
add_library('libunwind')
17471737
if settings.MALLOC != 'none':
17481738
add_library('libmalloc')
1749-
if settings.STANDALONE_WASM:
1750-
add_library('libstandalonewasm')
1751-
add_library('libc_rt')
1739+
add_library('libcompiler_rt')
1740+
if settings.LINK_AS_CXX:
1741+
add_library('libc++')
1742+
if settings.LINK_AS_CXX or sanitize:
1743+
add_library('libc++abi')
1744+
if settings.EXCEPTION_HANDLING:
1745+
add_library('libunwind')
1746+
if settings.STANDALONE_WASM:
1747+
add_library('libstandalonewasm')
1748+
add_library('libc_rt')
17521749

1753-
if settings.USE_LSAN:
1754-
force_include.append('liblsan_rt')
1755-
add_library('liblsan_rt')
1750+
if settings.USE_LSAN:
1751+
force_include.append('liblsan_rt')
1752+
add_library('liblsan_rt')
17561753

1757-
if settings.USE_ASAN:
1758-
force_include.append('libasan_rt')
1759-
add_library('libasan_rt')
1760-
add_library('libasan_js')
1754+
if settings.USE_ASAN:
1755+
force_include.append('libasan_rt')
1756+
add_library('libasan_rt')
1757+
add_library('libasan_js')
17611758

1762-
if settings.UBSAN_RUNTIME == 1:
1763-
add_library('libubsan_minimal_rt')
1764-
elif settings.UBSAN_RUNTIME == 2:
1765-
add_library('libubsan_rt')
1759+
if settings.UBSAN_RUNTIME == 1:
1760+
add_library('libubsan_minimal_rt')
1761+
elif settings.UBSAN_RUNTIME == 2:
1762+
add_library('libubsan_rt')
17661763

1767-
if settings.USE_LSAN or settings.USE_ASAN:
1768-
add_library('liblsan_common_rt')
1764+
if settings.USE_LSAN or settings.USE_ASAN:
1765+
add_library('liblsan_common_rt')
17691766

1770-
if sanitize:
1771-
add_library('libsanitizer_common_rt')
1767+
if sanitize:
1768+
add_library('libsanitizer_common_rt')
17721769

1773-
if settings.PROXY_POSIX_SOCKETS:
1774-
add_library('libsockets_proxy')
1775-
else:
1776-
add_library('libsockets')
1770+
if settings.PROXY_POSIX_SOCKETS:
1771+
add_library('libsockets_proxy')
1772+
else:
1773+
add_library('libsockets')
1774+
1775+
if settings.USE_WEBGPU:
1776+
add_library('libwebgpu_cpp')
1777+
1778+
return libs_to_link
1779+
1780+
1781+
def calculate(input_files, args, forced):
1782+
# Setting this will only use the forced libs in EMCC_FORCE_STDLIBS. This avoids spending time checking
1783+
# for unresolved symbols in your project files, which can speed up linking, but if you do not have
1784+
# the proper list of actually needed libraries, errors can occur. See below for how we must
1785+
# export all the symbols in deps_info when using this option.
1786+
only_forced = os.environ.get('EMCC_ONLY_FORCED_STDLIBS')
1787+
if only_forced:
1788+
# One of the purposes EMCC_ONLY_FORCED_STDLIBS was to skip the scanning
1789+
# of the input files for reverse dependencies.
1790+
diagnostics.warning('deprecated', 'EMCC_ONLY_FORCED_STDLIBS is deprecated. Use `-nostdlib` and/or `-s REVERSE_DEPS=none` depending on the desired result')
1791+
settings.REVERSE_DEPS = 'all'
1792+
1793+
handle_reverse_deps(input_files)
17771794

1778-
if settings.USE_WEBGPU:
1779-
add_library('libwebgpu_cpp')
1795+
libs_to_link = get_libs_to_link(args, forced, only_forced)
17801796

17811797
# When LINKABLE is set the entire link command line is wrapped in --whole-archive by
17821798
# building.link_ldd. And since --whole-archive/--no-whole-archive processing does not nest we
17831799
# shouldn't add any extra `--no-whole-archive` or we will undo the intent of building.link_ldd.
1784-
if settings.LINKABLE:
1800+
if settings.LINKABLE or settings.SIDE_MODULE:
17851801
return [l[0] for l in libs_to_link]
17861802

17871803
# Wrap libraries in --whole-archive, as needed. We need to do this last

0 commit comments

Comments
 (0)