Skip to content

Don't EXPORT_ALL for linkable code #7371

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Oct 30, 2018
Merged
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
7 changes: 7 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ full changeset diff at the end of each section.

Current Trunk
-------------
- Breaking change: Do not automatically set EXPORT_ALL for MAIN_MODULES or
SIDE_MODULES. This means that you must explicitly export things that will
be called from outside (normally, on EXPORTED_FUNCTIONS), or
you can manually enable EXPORT_ALL yourself (which returns to the exact
same behavior as before). This change brings us in line with more standard
dynamic linking, and will match what the LLVM wasm backend will have.
See #7312.

v1.38.14: 10/22/2018
--------------------
Expand Down
1 change: 0 additions & 1 deletion emcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1164,7 +1164,6 @@ def check(input_file):
if shared.Settings.EMULATED_FUNCTION_POINTERS == 0:
shared.Settings.EMULATED_FUNCTION_POINTERS = 2 # by default, use optimized function pointer emulation
shared.Settings.ERROR_ON_UNDEFINED_SYMBOLS = shared.Settings.WARN_ON_UNDEFINED_SYMBOLS = 0
shared.Settings.EXPORT_ALL = 1

if shared.Settings.EMTERPRETIFY:
shared.Settings.FINALIZE_ASM_JS = 0
Expand Down
24 changes: 12 additions & 12 deletions tests/test_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -2133,8 +2133,8 @@ def test_runtimelink(self):
print(wasm)
main, supp = self.setup_runtimelink_test()
open('supp.cpp', 'w').write(supp)
run_process([PYTHON, EMCC, 'supp.cpp', '-o', 'supp.' + ('wasm' if wasm else 'js'), '-s', 'SIDE_MODULE=1', '-O2', '-s', 'WASM=%d' % wasm])
self.btest(main, args=['-DBROWSER=1', '-s', 'MAIN_MODULE=1', '-O2', '-s', 'WASM=%d' % wasm, '-s', 'RUNTIME_LINKED_LIBS=["supp.' + ('wasm' if wasm else 'js') + '"]'], expected='76')
run_process([PYTHON, EMCC, 'supp.cpp', '-o', 'supp.' + ('wasm' if wasm else 'js'), '-s', 'SIDE_MODULE=1', '-O2', '-s', 'WASM=%d' % wasm, '-s', 'EXPORT_ALL=1'])
self.btest(main, args=['-DBROWSER=1', '-s', 'MAIN_MODULE=1', '-O2', '-s', 'WASM=%d' % wasm, '-s', 'RUNTIME_LINKED_LIBS=["supp.' + ('wasm' if wasm else 'js') + '"]', '-s', 'EXPORT_ALL=1'], expected='76')

def test_pre_run_deps(self):
# Adding a dependency in preRun will delay run
Expand Down Expand Up @@ -2326,7 +2326,7 @@ def test_emscripten_async_wget2(self):
@unittest.skip('non-fastcomp is deprecated and fails in 3.5')
def test_module(self):
run_process([PYTHON, EMCC, path_from_root('tests', 'browser_module.cpp'), '-o', 'module.js', '-O2', '-s', 'SIDE_MODULE=1', '-s', 'DLOPEN_SUPPORT=1', '-s', 'EXPORTED_FUNCTIONS=["_one", "_two"]'])
self.btest('browser_main.cpp', args=['-O2', '-s', 'MAIN_MODULE=1', '-s', 'DLOPEN_SUPPORT=1'], expected='8')
self.btest('browser_main.cpp', args=['-O2', '-s', 'MAIN_MODULE=1', '-s', 'DLOPEN_SUPPORT=1', '-s', 'EXPORT_ALL=1'], expected='8')

def test_preload_module(self):
open('library.c', 'w').write(r'''
Expand All @@ -2335,7 +2335,7 @@ def test_preload_module(self):
return 42;
}
''')
run_process([PYTHON, EMCC, 'library.c', '-s', 'SIDE_MODULE=1', '-O2', '-o', 'library.wasm', '-s', 'WASM=1'])
run_process([PYTHON, EMCC, 'library.c', '-s', 'SIDE_MODULE=1', '-O2', '-o', 'library.wasm', '-s', 'WASM=1', '-s', 'EXPORT_ALL=1'])
os.rename('library.wasm', 'library.so')
main = r'''
#include <dlfcn.h>
Expand Down Expand Up @@ -2366,7 +2366,7 @@ def test_preload_module(self):
'''
self.btest(
main,
args=['-s', 'MAIN_MODULE=1', '--preload-file', '.@/', '-O2', '-s', 'WASM=1', '--use-preload-plugins'],
args=['-s', 'MAIN_MODULE=1', '--preload-file', '.@/', '-O2', '-s', 'WASM=1', '--use-preload-plugins', '-s', 'EXPORT_ALL=1'],
expected='0')

def test_mmap_file(self):
Expand Down Expand Up @@ -3294,24 +3294,24 @@ def test_dynamic_link(self):
return ret;
}
''')
run_process([PYTHON, EMCC, 'side.cpp', '-s', 'SIDE_MODULE=1', '-O2', '-o', 'side.wasm'])
self.btest(self.in_dir('main.cpp'), '2', args=['-s', 'MAIN_MODULE=1', '-O2', '--pre-js', 'pre.js'])
run_process([PYTHON, EMCC, 'side.cpp', '-s', 'SIDE_MODULE=1', '-O2', '-o', 'side.wasm', '-s', 'EXPORT_ALL=1'])
self.btest(self.in_dir('main.cpp'), '2', args=['-s', 'MAIN_MODULE=1', '-O2', '--pre-js', 'pre.js', '-s', 'EXPORT_ALL=1'])

print('wasm in worker (we can read binary data synchronously there)')

open('pre.js', 'w').write('''
var Module = { dynamicLibraries: ['side.wasm'] };
''')
run_process([PYTHON, EMCC, 'side.cpp', '-s', 'SIDE_MODULE=1', '-O2', '-o', 'side.wasm', '-s', 'WASM=1'])
self.btest(self.in_dir('main.cpp'), '2', args=['-s', 'MAIN_MODULE=1', '-O2', '--pre-js', 'pre.js', '-s', 'WASM=1', '--proxy-to-worker'])
run_process([PYTHON, EMCC, 'side.cpp', '-s', 'SIDE_MODULE=1', '-O2', '-o', 'side.wasm', '-s', 'WASM=1', '-s', 'EXPORT_ALL=1'])
self.btest(self.in_dir('main.cpp'), '2', args=['-s', 'MAIN_MODULE=1', '-O2', '--pre-js', 'pre.js', '-s', 'WASM=1', '--proxy-to-worker', '-s', 'EXPORT_ALL=1'])

print('wasm (will auto-preload since no sync binary reading)')

open('pre.js', 'w').write('''
Module.dynamicLibraries = ['side.wasm'];
''')
# same wasm side module works
self.btest(self.in_dir('main.cpp'), '2', args=['-s', 'MAIN_MODULE=1', '-O2', '--pre-js', 'pre.js', '-s', 'WASM=1'])
self.btest(self.in_dir('main.cpp'), '2', args=['-s', 'MAIN_MODULE=1', '-O2', '--pre-js', 'pre.js', '-s', 'WASM=1', '-s', 'EXPORT_ALL=1'])

@requires_graphics_hardware
@no_chrome("required synchronous wasm compilation")
Expand Down Expand Up @@ -3341,9 +3341,9 @@ def test_dynamic_link_glemu(self):
return (const char *)glGetString(GL_EXTENSIONS);
}
''')
run_process([PYTHON, EMCC, 'side.cpp', '-s', 'SIDE_MODULE=1', '-O2', '-o', 'side.wasm', '-lSDL'])
run_process([PYTHON, EMCC, 'side.cpp', '-s', 'SIDE_MODULE=1', '-O2', '-o', 'side.wasm', '-lSDL', '-s', 'EXPORT_ALL=1'])

self.btest(self.in_dir('main.cpp'), '1', args=['-s', 'MAIN_MODULE=1', '-O2', '-s', 'LEGACY_GL_EMULATION=1', '-lSDL', '-lGL', '--pre-js', 'pre.js'])
self.btest(self.in_dir('main.cpp'), '1', args=['-s', 'MAIN_MODULE=1', '-O2', '-s', 'LEGACY_GL_EMULATION=1', '-lSDL', '-lGL', '--pre-js', 'pre.js', '-s', 'EXPORT_ALL=1'])

def test_memory_growth_during_startup(self):
open('data.dat', 'w').write('X' * (30 * 1024 * 1024))
Expand Down
9 changes: 7 additions & 2 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2426,10 +2426,12 @@ def test_runtimelink(self):
def prep_dlfcn_lib(self):
self.set_setting('MAIN_MODULE', 0)
self.set_setting('SIDE_MODULE', 1)
self.set_setting('EXPORT_ALL', 1)

def prep_dlfcn_main(self):
self.set_setting('MAIN_MODULE', 1)
self.set_setting('SIDE_MODULE', 0)
self.set_setting('EXPORT_ALL', 1)

with open('lib_so_pre.js', 'w') as f:
f.write('''
Expand Down Expand Up @@ -3325,6 +3327,9 @@ def zzztest_dlfcn_exceptions(self): # TODO: make this work. need to forward temp
''')

def dylink_test(self, main, side, expected, header=None, main_emcc_args=[], force_c=False, need_reverse=True, auto_load=True):
# shared settings
self.set_setting('EXPORT_ALL', 1)

if header:
open('header.h', 'w').write(header)

Expand Down Expand Up @@ -3800,7 +3805,7 @@ def test_dylink_global_var_jslib(self):
void call_side() {
printf("side: jslib_x is %d.\n", jslib_x);
}
''', expected=['main: jslib_x is 148.\nside: jslib_x is 148.\n'], main_emcc_args=['--js-library', 'lib.js'])
''', expected=['main: jslib_x is 148.\nside: jslib_x is 148.\n'], main_emcc_args=['--js-library', 'lib.js', '-s', 'EXPORTED_FUNCTIONS=["_main", "_jslib_x"]'])

@needs_dlfcn
def test_dylink_many_postSets(self):
Expand Down Expand Up @@ -4034,7 +4039,7 @@ def test_dylink_hyper_dupe(self):
printf("only_in_third_1: %d, %d, %d, %d\n", sidef(), sideg, second_to_third, x);
}
''')
run_process([PYTHON, EMCC, 'third.cpp', '-s', 'SIDE_MODULE=1'] + Building.COMPILER_TEST_OPTS + self.emcc_args + ['-o', 'third' + dylib_suffix])
run_process([PYTHON, EMCC, 'third.cpp', '-s', 'SIDE_MODULE=1', '-s', 'EXPORT_ALL=1'] + Building.COMPILER_TEST_OPTS + self.emcc_args + ['-o', 'third' + dylib_suffix])

self.dylink_test(main=r'''
#include <stdio.h>
Expand Down
33 changes: 18 additions & 15 deletions tests/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -3004,7 +3004,8 @@ def test_proxyfs(self):
'--embed-file', 'proxyfs_embed.txt', '--pre-js', 'proxyfs_pre.js',
'-s', 'EXTRA_EXPORTED_RUNTIME_METHODS=["ccall", "cwrap"]',
'-s', 'BINARYEN_ASYNC_COMPILATION=0',
'-s', 'MAIN_MODULE=1'])
'-s', 'MAIN_MODULE=1',
'-s', 'EXPORT_ALL=1'])
# Following shutil.copyfile just prevent 'require' of node.js from caching js-object.
# See https://nodejs.org/api/modules.html
shutil.copyfile('proxyfs_test.js', 'proxyfs_test1.js')
Expand Down Expand Up @@ -6230,7 +6231,7 @@ def test(main_args=[], library_args=[], expected='hello from main\nhello from li
#endif
}
''')
run_process([PYTHON, EMCC, 'library.c', '-s', 'SIDE_MODULE=1', '-O2', '-o', library_file, '-s', 'WASM=' + str(wasm)] + library_args)
run_process([PYTHON, EMCC, 'library.c', '-s', 'SIDE_MODULE=1', '-O2', '-o', library_file, '-s', 'WASM=' + str(wasm), '-s', 'EXPORT_ALL=1'] + library_args)
open('main.c', 'w').write(r'''
#include <dlfcn.h>
#include <stdio.h>
Expand Down Expand Up @@ -6266,12 +6267,14 @@ def percent_diff(x, y):
full = test()
# printf is not used in main, but libc was linked in, so it's there
printf = test(library_args=['-DUSE_PRINTF'])
# dce in main, and side happens to be ok since it uses puts as well
dce = test(main_args=['-s', 'MAIN_MODULE=2'])
# dce in main, and it fails since puts is not exported
dce = test(main_args=['-s', 'MAIN_MODULE=2'], expected=('cannot', 'undefined'))
# with exporting, it works
dce = test(main_args=['-s', 'MAIN_MODULE=2', '-s', 'EXPORTED_FUNCTIONS=["_main", "_puts"]'])
# printf is not used in main, and we dce, so we failz
dce_fail = test(main_args=['-s', 'MAIN_MODULE=2'], library_args=['-DUSE_PRINTF'], expected=('cannot', 'undefined'))
# exporting printf in main keeps it alive for the library
dce_save = test(main_args=['-s', 'MAIN_MODULE=2', '-s', 'EXPORTED_FUNCTIONS=["_main", "_printf"]'], library_args=['-DUSE_PRINTF'])
dce_save = test(main_args=['-s', 'MAIN_MODULE=2', '-s', 'EXPORTED_FUNCTIONS=["_main", "_printf", "_puts"]'], library_args=['-DUSE_PRINTF'])

assert percent_diff(full[0], printf[0]) < 4
assert percent_diff(dce[0], dce_fail[0]) < 4
Expand Down Expand Up @@ -6377,10 +6380,10 @@ def test_ld_library_path(self):

''')

run_process([PYTHON, EMCC, '-o', 'libhello1.wasm', 'hello1.c', '-s', 'SIDE_MODULE=1'])
run_process([PYTHON, EMCC, '-o', 'libhello2.wasm', 'hello2.c', '-s', 'SIDE_MODULE=1'])
run_process([PYTHON, EMCC, '-o', 'libhello3.wasm', 'hello3.c', '-s', 'SIDE_MODULE=1'])
run_process([PYTHON, EMCC, '-o', 'libhello4.wasm', 'hello4.c', '-s', 'SIDE_MODULE=1'])
run_process([PYTHON, EMCC, '-o', 'libhello1.wasm', 'hello1.c', '-s', 'SIDE_MODULE=1', '-s', 'EXPORT_ALL=1'])
run_process([PYTHON, EMCC, '-o', 'libhello2.wasm', 'hello2.c', '-s', 'SIDE_MODULE=1', '-s', 'EXPORT_ALL=1'])
run_process([PYTHON, EMCC, '-o', 'libhello3.wasm', 'hello3.c', '-s', 'SIDE_MODULE=1', '-s', 'EXPORT_ALL=1'])
run_process([PYTHON, EMCC, '-o', 'libhello4.wasm', 'hello4.c', '-s', 'SIDE_MODULE=1', '-s', 'EXPORT_ALL=1'])
run_process([PYTHON, EMCC, '-o', 'main.js', 'main.c', '-s', 'MAIN_MODULE=1', '-s', 'TOTAL_MEMORY=' + str(32 * 1024 * 1024),
'--embed-file', 'libhello1.wasm@/lib/libhello1.wasm',
'--embed-file', 'libhello2.wasm@/usr/lib/libhello2.wasm',
Expand Down Expand Up @@ -6453,8 +6456,8 @@ def test_dlopen_rtld_global(self):
}
''')

run_process([PYTHON, EMCC, '-o', 'libhello1.js', 'hello1.c', '-s', 'SIDE_MODULE=1', '-s', 'WASM=0'])
run_process([PYTHON, EMCC, '-o', 'libhello2.js', 'hello2.c', '-s', 'SIDE_MODULE=1', '-s', 'WASM=0'])
run_process([PYTHON, EMCC, '-o', 'libhello1.js', 'hello1.c', '-s', 'SIDE_MODULE=1', '-s', 'WASM=0', '-s', 'EXPORT_ALL=1'])
run_process([PYTHON, EMCC, '-o', 'libhello2.js', 'hello2.c', '-s', 'SIDE_MODULE=1', '-s', 'WASM=0', '-s', 'EXPORT_ALL=1'])
run_process([PYTHON, EMCC, '-o', 'main.js', 'main.c', '-s', 'MAIN_MODULE=1', '-s', 'WASM=0',
'--embed-file', 'libhello1.js',
'--embed-file', 'libhello2.js'])
Expand Down Expand Up @@ -8245,7 +8248,7 @@ def test(filename, expectations):
0, [], ['tempDoublePtr', 'waka'], 8, 0, 0, 0), # noqa; totally empty!
# but we don't metadce with linkable code! other modules may want it
(['-O3', '-s', 'MAIN_MODULE=1'],
1489, ['invoke_v'], ['waka'], 469663, 149, 1443, None), # noqa; don't compare the # of functions in a main module, which changes a lot
1489, ['invoke_v'], ['waka'], 226057, 30, 75, None), # noqa; don't compare the # of functions in a main module, which changes a lot
]) # noqa

print('test on a minimal pure computational thing')
Expand Down Expand Up @@ -8286,9 +8289,9 @@ def test_legalize_js_ffi(self):
# test disabling of JS FFI legalization
wasm_dis = os.path.join(Building.get_binaryen_bin(), 'wasm-dis')
for (args, js_ffi) in [
(['-s', 'LEGALIZE_JS_FFI=1', '-s', 'SIDE_MODULE=1', '-O2'], True),
(['-s', 'LEGALIZE_JS_FFI=0', '-s', 'SIDE_MODULE=1', '-O2'], False),
(['-s', 'LEGALIZE_JS_FFI=0', '-s', 'SIDE_MODULE=1', '-O0'], False),
(['-s', 'LEGALIZE_JS_FFI=1', '-s', 'SIDE_MODULE=1', '-O2', '-s', 'EXPORT_ALL=1'], True),
(['-s', 'LEGALIZE_JS_FFI=0', '-s', 'SIDE_MODULE=1', '-O2', '-s', 'EXPORT_ALL=1'], False),
(['-s', 'LEGALIZE_JS_FFI=0', '-s', 'SIDE_MODULE=1', '-O0', '-s', 'EXPORT_ALL=1'], False),
(['-s', 'LEGALIZE_JS_FFI=0', '-s', 'WARN_ON_UNDEFINED_SYMBOLS=0', '-O0'], False),
]:
if self.is_wasm_backend() and 'SIDE_MODULE=1' in args:
Expand Down