diff --git a/ChangeLog.md b/ChangeLog.md index 3fd97ff14a760..cdafbfd45dc35 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,8 @@ See docs/process.md for more on how version tagging works. 4.0.22 (in development) ----------------------- +- The FAKE_DYLIBS setting is now disabled by default. This means that `-shared` + will now produce real dynamic libraries by default. (#25930) - Emscripten will now cache the JS code that it generates and re-use when linking with the same settings at a later date. This should improve link times generally but should especially noticeable when linking lots of small diff --git a/cmake/Modules/Platform/Emscripten.cmake b/cmake/Modules/Platform/Emscripten.cmake index 4e03775e8598b..5efc150062e1e 100644 --- a/cmake/Modules/Platform/Emscripten.cmake +++ b/cmake/Modules/Platform/Emscripten.cmake @@ -18,7 +18,7 @@ set(CMAKE_SYSTEM_NAME Emscripten) set(CMAKE_SYSTEM_VERSION 1) set(CMAKE_CROSSCOMPILING TRUE) -set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS FALSE) +set_property(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE) # Advertise Emscripten as a 32-bit platform (as opposed to # CMAKE_SYSTEM_PROCESSOR=x86_64 for 64-bit platform), since some projects (e.g. diff --git a/site/source/docs/tools_reference/settings_reference.rst b/site/source/docs/tools_reference/settings_reference.rst index 77871dc3d80af..8f1fb1aadb7ee 100644 --- a/site/source/docs/tools_reference/settings_reference.rst +++ b/site/source/docs/tools_reference/settings_reference.rst @@ -3429,13 +3429,12 @@ Default value: false FAKE_DYLIBS =========== -This setting changes the behaviour of the ``-shared`` flag. The default -setting of ``true`` means the ``-shared`` flag actually produces a normal -object file (i.e. ``ld -r``). Setting this to false will cause ``-shared`` -to behave like :ref:`SIDE_MODULE` and produce and dynamically linked -library. +This setting changes the behaviour of the ``-shared`` flag. When set to true +you get the old emscripten behaivour where the ``-shared`` flag actually +produces a normal object file (i.e. ``ld -r``). The default behaviour is that +`-shared` is the as :ref:`SIDE_MODULE`. -Default value: true +Default value: false .. _deprecated-settings: diff --git a/src/settings.js b/src/settings.js index 1ba3b7856b8da..8aa61981bab57 100644 --- a/src/settings.js +++ b/src/settings.js @@ -2241,9 +2241,8 @@ var WASM_JS_TYPES = false; // indirectly using `importScripts` var CROSS_ORIGIN = false; -// This setting changes the behaviour of the ``-shared`` flag. The default -// setting of ``true`` means the ``-shared`` flag actually produces a normal -// object file (i.e. ``ld -r``). Setting this to false will cause ``-shared`` -// to behave like :ref:`SIDE_MODULE` and produce and dynamically linked -// library. -var FAKE_DYLIBS = true; +// This setting changes the behaviour of the ``-shared`` flag. When set to true +// you get the old emscripten behaivour where the ``-shared`` flag actually +// produces a normal object file (i.e. ``ld -r``). The default behaviour is that +// `-shared` is the as :ref:`SIDE_MODULE`. +var FAKE_DYLIBS = false; diff --git a/test/test_core.py b/test/test_core.py index ff5d94c96a8f0..2f80ea1e4c8cc 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -4047,8 +4047,8 @@ def dylink_testf(self, main, side=None, expected=None, force_c=False, main_cflag shutil.move(so_file, so_file + '.orig') - # Verify that building with -sSIDE_MODULE is essentailly the same as building with `-shared -fPIC -sFAKE_DYLIBS=0`. - flags = ['-shared', '-fPIC', '-sFAKE_DYLIBS=0'] + # Verify that building with -sSIDE_MODULE is essentailly the same as building with `-shared -fPIC` + flags = ['-shared', '-fPIC'] if isinstance(side, list): # side is just a library self.run_process([EMCC] + side + self.get_cflags() + flags + ['-o', so_file]) diff --git a/test/test_other.py b/test/test_other.py index 76b051cc9206a..36f5a6f161d88 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -1238,7 +1238,7 @@ def test_odd_suffixes(self): for suffix in ('lo',): self.clear() print(suffix) - self.run_process([EMCC, test_file('hello_world.c'), '-shared', '-o', 'binary.' + suffix]) + self.run_process([EMCC, test_file('hello_world.c'), '-sFAKE_DYLIBS', '-shared', '-o', 'binary.' + suffix]) self.run_process([EMCC, 'binary.' + suffix]) self.assertContained('hello, world!', self.run_js('a.out.js')) @@ -1419,7 +1419,7 @@ def test_multiply_defined_libsymbols(self): ''') self.cflags.remove('-Werror') - self.emcc('libA.c', ['-shared', '-o', 'libA.so']) + self.emcc('libA.c', ['-shared', '-sFAKE_DYLIBS', '-o', 'libA.so']) self.emcc('a2.c', ['-r', '-L.', '-lA', '-o', 'a2.o']) self.emcc('b2.c', ['-r', '-L.', '-lA', '-o', 'b2.o']) @@ -1552,7 +1552,12 @@ def test_link_group_bitcode(self): # We deliberately ignore duplicate input files in order to allow # "libA.so" on the command line twice. This is not really .so support # and the .so files are really object files. - def test_redundant_link(self): + @parameterized({ + '': ([],), + 'fake_dylibs': (['-sFAKE_DYLIBS'],), + }) + def test_redundant_link(self, args): + self.cflags += args create_file('libA.c', 'int mult() { return 1; }') create_file('main.c', r''' #include @@ -1564,7 +1569,7 @@ def test_redundant_link(self): ''') self.cflags.remove('-Werror') - self.emcc('libA.c', ['-shared', '-o', 'libA.so']) + self.emcc('libA.c', ['-fPIC', '-shared', '-o', 'libA.so']) self.emcc('main.c', ['libA.so', 'libA.so', '-o', 'a.out.js']) self.assertContained('result: 1', self.run_js('a.out.js')) @@ -2159,9 +2164,9 @@ def test_multidynamic_link(self, link_flags, lib_suffix): ''') # Build libfile normally into an .so - self.run_process([EMCC, 'libdir/libfile.c', '-shared', '-o', 'libdir/libfile.so' + lib_suffix]) + self.run_process([EMCC, 'libdir/libfile.c', '-sFAKE_DYLIBS', '-shared', '-fPIC', '-o', 'libdir/libfile.so' + lib_suffix]) # Build libother and dynamically link it to libfile - self.run_process([EMCC, '-Llibdir', 'libdir/libother.c'] + link_flags + ['-shared', '-o', 'libdir/libother.so']) + self.run_process([EMCC, '-Llibdir', 'libdir/libother.c'] + link_flags + ['-sFAKE_DYLIBS', '-shared', '-fPIC', '-o', 'libdir/libother.so']) # Build the main file, linking in both the libs self.run_process([EMCC, '-Llibdir', os.path.join('main.c')] + link_flags + ['-lother', '-c']) print('...') @@ -4896,20 +4901,6 @@ def test_valid_abspath_2(self): self.run_process(cmd) self.assertContained('hello, world!', self.run_js('a.out.js')) - def test_warn_dylibs(self): - shared_suffixes = ['.so', '.dylib', '.dll'] - - for suffix in ('.o', '.bc', '.so', '.dylib', '.js', '.html'): - print(suffix) - cmd = [EMCC, test_file('hello_world.c'), '-o', 'out' + suffix] - if suffix in ['.o', '.bc']: - cmd.append('-c') - if suffix in ['.dylib', '.so']: - cmd.append('-shared') - err = self.run_process(cmd, stderr=PIPE).stderr - warning = 'linking a library with `-shared` will emit a static object file' - self.assertContainedIf(warning, err, suffix in shared_suffixes) - @crossplatform @parameterized({ 'O2': [['-O2']], @@ -8388,19 +8379,6 @@ def test_side_module_folder_deps(self): self.run_process([EMCC, test_file('hello_world.c'), '-sSIDE_MODULE', '-o', 'subdir/libside2.so', '-L', 'subdir', '-lside1']) self.run_process([EMCC, test_file('hello_world.c'), '-sMAIN_MODULE', '-o', 'main.js', '-L', 'subdir', '-lside2']) - @crossplatform - def test_side_module_ignore(self): - self.run_process([EMCC, test_file('hello_world.c'), '-sSIDE_MODULE', '-o', 'libside.so']) - - # Attempting to link statically against a side module (libside.so) should fail. - self.assert_fail([EMCC, '-L.', '-lside'], 'wasm-ld: error: unable to find library -lside') - - # But a static library in the same location (libside.a) should take precedence. - self.run_process([EMCC, test_file('hello_world.c'), '-c']) - self.run_process([EMAR, 'cr', 'libside.a', 'hello_world.o']) - self.run_process([EMCC, '-L.', '-lside']) - self.assertContained('hello, world!', self.run_js('a.out.js')) - @is_slow_test @parameterized({ '': ([],), @@ -11922,42 +11900,40 @@ def test_err(self): def test_euidaccess(self): self.do_other_test('test_euidaccess.c') - def test_shared_flag(self): - create_file('side.c', 'int foo;') - self.run_process([EMCC, '-shared', 'side.c', '-o', 'libother.so']) + def test_fake_dylibs(self): + create_file('other.c', 'int foo = 10;') + self.run_process([EMCC, '-shared', '-sFAKE_DYLIBS', '-fPIC', 'other.c', '-o', 'libother.so']) + self.assertIsObjectFile('libother.so') - # Test that `-shared` flag causes object file generation but gives a warning - err = self.run_process([EMCC, '-shared', test_file('hello_world.c'), '-o', 'out.foo', 'libother.so'], stderr=PIPE).stderr - self.assertContained('linking a library with `-shared` will emit a static object', err) + # Test that `-sFAKE_DYLIBS` flag causes object file generation and will generate a warning about + # dylink dependencies being ignored. + err = self.run_process([EMCC, '-shared', '-sFAKE_DYLIBS', '-fPIC', test_file('hello_world.c'), '-o', 'out.foo', 'libother.so'], stderr=PIPE).stderr 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 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) self.assertIsWasmDylib('out.foo') # Test that using an executable output name overrides the `-shared` flag, but produces a warning. - err = self.run_process([EMCC, '-shared', test_file('hello_world.c'), '-o', 'out.js'], + err = self.run_process([EMCC, '-shared', '-sFAKE_DYLIBS', '-fPIC', test_file('hello_world.c'), '-o', 'out.js'], stderr=PIPE).stderr self.assertContained('warning: -shared/-r used with executable output suffix', err) self.run_js('out.js') def test_shared_soname(self): - self.run_process([EMCC, '-shared', '-Wl,-soname', '-Wl,libfoo.so.13', test_file('hello_world.c'), '-lc', '-o', 'libfoo.so']) + self.run_process([EMCC, '-shared', '-sFAKE_DYLIBS', '-Wl,-soname', '-Wl,libfoo.so.13', test_file('hello_world.c'), '-lc', '-o', 'libfoo.so']) self.run_process([EMCC, '-sSTRICT', 'libfoo.so']) self.assertContained('hello, world!', self.run_js('a.out.js')) - def test_shared_and_side_module_flag(self): - # Test that `-shared` and `-sSIDE_MODULE` flag causes wasm dylib generation without a warning. - err = self.run_process([EMCC, '-shared', '-sSIDE_MODULE', test_file('hello_world.c'), '-o', 'out.foo'], stderr=PIPE).stderr - self.assertNotContained('linking a library with `-shared` will emit a static object', err) + def test_shared_flag(self): + # Test that `-shared` flag causes wasm dylib generation + self.run_process([EMCC, '-shared', '-fPIC', test_file('hello_world.c'), '-o', 'out.foo']) self.assertIsWasmDylib('out.foo') - # Test that `-shared` and `-sSIDE_MODULE` flag causes wasm dylib generation without a warning even if given executable output name. - err = self.run_process([EMCC, '-shared', '-sSIDE_MODULE', test_file('hello_world.c'), '-o', 'out.wasm'], - stderr=PIPE).stderr + # Test that `-shared` causes wasm dylib generation warning even if given executable output name. + err = self.run_process([EMCC, '-shared', '-fPIC', test_file('hello_world.c'), '-o', 'out.wasm'], stderr=PIPE).stderr self.assertNotContained('warning: -shared/-r used with executable output suffix', err) self.assertIsWasmDylib('out.wasm') diff --git a/tools/building.py b/tools/building.py index 15dd80e57c14c..1707d5165321d 100644 --- a/tools/building.py +++ b/tools/building.py @@ -170,6 +170,9 @@ def lld_flags_for_executable(external_symbols): stub = create_stub_object(external_symbols) cmd.append(stub) + if not settings.FAKE_DYLIBS: + cmd.append('-Bdynamic') + if not settings.ERROR_ON_UNDEFINED_SYMBOLS: cmd.append('--import-undefined') @@ -208,7 +211,6 @@ def lld_flags_for_executable(external_symbols): c_exports = [e for e in c_exports if e not in external_symbols] c_exports += settings.REQUIRED_EXPORTS if settings.MAIN_MODULE: - cmd.append('-Bdynamic') c_exports += side_module_external_deps(external_symbols) for export in c_exports: if settings.ERROR_ON_UNDEFINED_SYMBOLS: diff --git a/tools/link.py b/tools/link.py index ecb2df25adaa6..2637f3cb163d5 100644 --- a/tools/link.py +++ b/tools/link.py @@ -807,9 +807,6 @@ def phase_linker_setup(options, linker_args): # noqa: C901, PLR0912, PLR0915 apply_library_settings(linker_args) - if settings.SIDE_MODULE or settings.MAIN_MODULE: - default_setting('FAKE_DYLIBS', 0) - if options.shared and not settings.FAKE_DYLIBS: default_setting('SIDE_MODULE', 1) default_setting('RELOCATABLE', 1) @@ -920,8 +917,6 @@ def phase_linker_setup(options, linker_args): # noqa: C901, PLR0912, PLR0915 if final_suffix in EXECUTABLE_EXTENSIONS: diagnostics.warning('emcc', '-shared/-r used with executable output suffix. This behaviour is deprecated. Please remove -shared/-r to build an executable or avoid the executable suffix (%s) when building object files.' % final_suffix) else: - if options.shared and 'FAKE_DYLIBS' not in user_settings: - diagnostics.warning('emcc', 'linking a library with `-shared` will emit a static object file (FAKE_DYLIBS defaults to true). If you want to build a runtime shared library use the SIDE_MODULE or FAKE_DYLIBS=0.') options.oformat = OFormat.OBJECT if not options.oformat: @@ -3059,7 +3054,7 @@ def phase_calculate_linker_inputs(options, linker_args): else: linker_args = filter_out_duplicate_fake_dynamic_libs(linker_args) - if settings.MAIN_MODULE: + if not settings.SIDE_MODULE and not settings.FAKE_DYLIBS: process_dynamic_libs(options.dylibs, options.lib_dirs) return linker_args