Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion cmake/Modules/Platform/Emscripten.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bradking should I just delete line instead? (i.e. does this default to true?)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the CMakeGenericSystem module initializes the property to TRUE. It doesn't need to be set here.


# Advertise Emscripten as a 32-bit platform (as opposed to
# CMAKE_SYSTEM_PROCESSOR=x86_64 for 64-bit platform), since some projects (e.g.
Expand Down
11 changes: 5 additions & 6 deletions site/source/docs/tools_reference/settings_reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
you get the old emscripten behaivour where the ``-shared`` flag actually
you get the old emscripten behaviour 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:

Expand Down
11 changes: 5 additions & 6 deletions src/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
4 changes: 2 additions & 2 deletions test/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Verify that building with -sSIDE_MODULE is essentailly the same as building with `-shared -fPIC`
# Verify that building with -sSIDE_MODULE is essentially 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])
Expand Down
74 changes: 25 additions & 49 deletions test/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'))

Expand Down Expand Up @@ -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'])
Expand Down Expand Up @@ -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 <stdio.h>
Expand All @@ -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'))

Expand Down Expand Up @@ -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('...')
Expand Down Expand Up @@ -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']],
Expand Down Expand Up @@ -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({
'': ([],),
Expand Down Expand Up @@ -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')

Expand Down
4 changes: 3 additions & 1 deletion tools/building.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before this was just for main module - why is it different?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm.. yes I guess this part of the change would be removing the need for -sMAIN_MODULE (i.e. implicitly building a main module when dynamic libraries are present). Maybe that should be left for a followup.


if not settings.ERROR_ON_UNDEFINED_SYMBOLS:
cmd.append('--import-undefined')

Expand Down Expand Up @@ -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:
Expand Down
7 changes: 1 addition & 6 deletions tools/link.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down
Loading