From d455efae97140da1efd545ac4297aa04307bf8da Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 11 May 2026 16:05:30 -0700 Subject: [PATCH] Honor `-Bstatic` and `-Bdynamic` and pass these down the wasm-ld --- emcc.py | 2 +- test/test_other.py | 40 +++++++++++++++++++++++++++++++++++++++- tools/link.py | 17 ++++++++++++----- 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/emcc.py b/emcc.py index c36423fcdb359..9d3d45d0686d6 100644 --- a/emcc.py +++ b/emcc.py @@ -370,7 +370,7 @@ def get_next_arg(): add_link_arg(flag) elif arg == '-Xlinker': add_link_arg(get_next_arg()) - elif arg == '-s' or arg.startswith(('-l', '-L', '--js-library=', '-z', '-u')): + elif arg in {'-s', '-Bstatic', '-Bdynamic'} or arg.startswith(('-l', '-L', '--js-library=', '-z', '-u')): add_link_arg(arg) elif not arg.startswith('-o') and arg not in {'-nostdlib', '-nostartfiles', '-nolibc', '-nodefaultlibs', '-s'}: # All other flags are for the compiler diff --git a/test/test_other.py b/test/test_other.py index 82db20c0f6609..671914a230821 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -2428,6 +2428,44 @@ def test_dylink_LEGACY_GL_EMULATION(self): }''') self.do_runf('test.c', 'done\n', cflags=['-sLEGACY_GL_EMULATION', '-sMAIN_MODULE=2']) + def test_dylink_library_search(self): + # Test library resolution in the case when both static and dynamic library are present. + create_file('side_dyn.c', r''' + #include + void side_func() { + printf("dynamic linking used\n"); + } + ''') + create_file('side_static.c', r''' + #include + void side_func() { + printf("static linking used\n"); + } + ''') + self.emcc('side_dyn.c', ['-sSIDE_MODULE', '-olibside.so']) + self.emcc('side_static.c', ['-oside_static.o', '-c']) + self.run_process([EMAR, 'rc', 'libside.a', 'side_static.o']) + + create_file('main.c', ''' + void side_func(); + int main() { + side_func(); + return 0; + } + ''') + + # By deafult we use static linking and prefer libside.a + self.do_runf('main.c', 'static linking used\n', cflags=['-L.', '-lside']) + + # When using -sMAIN_MODULE we choose the dyanmic library + self.do_runf('main.c', 'dynamic linking used\n', cflags=['-sMAIN_MODULE=2', '-L.', '-lside']) + + # Same for `-sFAKE_DYLIBS=0 + self.do_runf('main.c', 'dynamic linking used\n', cflags=['-sFAKE_DYLIBS=0', '-L.', '-lside']) + + # With can also force static linking using `-Bstatic` linker falgs + self.do_runf('main.c', 'static linking used\n', cflags=['-sMAIN_MODULE=2', '-L.', '-Bstatic', '-lside']) + def test_js_link(self): create_file('before.js', ''' var MESSAGE = 'hello from js'; @@ -12086,7 +12124,7 @@ def test_shared_flag(self): self.assertContained('emcc: warning: ignoring dynamic library libother.so when generating an object file, this will need to be included explicitly in the final link', err) self.assertIsObjectFile('out.foo') - # Test that adding `-sFAKE_DYIBS=0` build a real side module + # Test that adding `-sFAKE_DYLIBS=0` build a real side module err = self.run_process([EMCC, '-shared', '-fPIC', '-sFAKE_DYLIBS=0', test_file('hello_world.c'), '-o', 'out.foo', 'libother.so'], stderr=PIPE).stderr self.assertNotContained('linking a library with `-shared` will emit a static object', err) self.assertNotContained('emcc: warning: ignoring dynamic library libother.so when generating an object file, this will need to be included explicitly in the final link', err) diff --git a/tools/link.py b/tools/link.py index 9e770ac078f97..70fdfe43a2ce8 100644 --- a/tools/link.py +++ b/tools/link.py @@ -773,12 +773,19 @@ def get_dylibs(options, linker_args): This can either be via `-lfoo` or via `libfoo.so` directly. """ dylibs = [] + # Mimic the behavior of the native linker WRT to the `-Bstack/-Bdynamic` flags. + search_for_dylibs = True for arg in linker_args: - if arg.startswith('-l'): - for ext in DYLIB_EXTENSIONS: - path = find_library('lib' + arg[2:] + ext, options.lib_dirs) - if path and building.is_wasm_dylib(path): - dylibs.append(path) + if arg in {'-Bstatic', '-static'}: + search_for_dylibs = False + elif arg == '-Bdynamic': + search_for_dylibs = True + elif arg.startswith('-l'): + if search_for_dylibs: + for ext in DYLIB_EXTENSIONS: + path = find_library('lib' + arg[2:] + ext, options.lib_dirs) + if path and building.is_wasm_dylib(path): + dylibs.append(path) elif building.is_wasm_dylib(arg): dylibs.append(arg) return dylibs