Skip to content

Commit 25d9714

Browse files
committed
Don't allow EXPORTED_FUNCTIONS with MAIN_MODULE=1/SIDE_MODULE=1
This doesn't make sense since these imply all functionm are to be exported.
1 parent deed1c5 commit 25d9714

File tree

3 files changed

+87
-81
lines changed

3 files changed

+87
-81
lines changed

emcc.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,17 +1158,23 @@ def check(input_file):
11581158
options.memory_init_file = False # memory init file is not supported with asm.js side modules, must be executable synchronously (for dlopen)
11591159

11601160
if shared.Settings.MAIN_MODULE or shared.Settings.SIDE_MODULE:
1161-
assert shared.Settings.ASM_JS, 'module linking requires asm.js output (-s ASM_JS=1)'
1161+
if not shared.Settings.ASM_JS:
1162+
exit_with_error('module linking requires asm.js output (-s ASM_JS=1)')
11621163
if shared.Settings.MAIN_MODULE != 2 and shared.Settings.SIDE_MODULE != 2:
11631164
shared.Settings.LINKABLE = 1
11641165
shared.Settings.RELOCATABLE = 1
1165-
assert not options.use_closure_compiler, 'cannot use closure compiler on shared modules'
1166+
if options.use_closure_compiler:
1167+
exit_with_error('cannot use closure compiler on shared modules')
11661168
# shared modules need memory utilities to allocate their memory
11671169
shared.Settings.EXPORTED_RUNTIME_METHODS += [
11681170
'allocate',
11691171
'getMemory',
11701172
]
11711173

1174+
if shared.Settings.LINKABLE and shared.Settings.USER_EXPORTED_FUNCTIONS:
1175+
exit_with_error('EXPORTED_FUNCTIONS is not valid with LINKABLE set (normally due to SIDE_MODULE=1/MAIN_MODULE=1) '
1176+
'since all functions are exported. To export only a subset use SIDE_MODULE=2/MAIN_MODULE=2')
1177+
11721178
if shared.Settings.RELOCATABLE:
11731179
shared.Settings.ALLOW_TABLE_GROWTH = 1
11741180

tests/test_other.py

Lines changed: 72 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -6364,91 +6364,91 @@ def test(args, expected):
63646364
test(['-O' + str(opts), '-s', 'MAIN_MODULE=1', '-s', 'EMULATED_FUNCTION_POINTERS=2'], unchanged)
63656365
test(['-O' + str(opts), '-s', 'MAIN_MODULE=1', '-s', 'EMULATED_FUNCTION_POINTERS=1'], flipped) # but you can disable that
63666366

6367-
def test_minimal_dynamic(self):
6368-
def run(wasm):
6369-
print('wasm?', wasm)
6370-
library_file = 'library.wasm' if wasm else 'library.js'
6367+
@parameterized({
6368+
'wasm': [True],
6369+
'asmjs': [False],
6370+
})
6371+
def test_minimal_dynamic(self, wasm):
6372+
if self.is_wasm_backend() and not wasm:
6373+
self.skipTest("asmjs only")
6374+
library_file = 'library.wasm' if wasm else 'library.js'
63716375

6372-
def test(main_args, library_args=[], expected='hello from main\nhello from library'):
6373-
print('testing', main_args, library_args)
6374-
self.clear()
6375-
create_test_file('library.c', r'''
6376-
#include <stdio.h>
6377-
void library_func() {
6378-
#ifdef USE_PRINTF
6379-
printf("hello from library: %p\n", &library_func);
6380-
#else
6381-
puts("hello from library");
6382-
#endif
6383-
}
6384-
''')
6385-
# -fno-builtin to prevent printf -> iprintf optimization
6386-
run_process([PYTHON, EMCC, 'library.c', '-fno-builtin', '-s', 'SIDE_MODULE=1', '-O2', '-o', library_file, '-s', 'WASM=' + str(wasm), '-s', 'EXPORT_ALL'] + library_args)
6387-
create_test_file('main.c', r'''
6388-
#include <dlfcn.h>
6389-
#include <stdio.h>
6390-
int main() {
6391-
puts("hello from main");
6392-
void *lib_handle = dlopen("%s", 0);
6393-
if (!lib_handle) {
6394-
puts("cannot load side module");
6395-
return 1;
6396-
}
6397-
typedef void (*voidfunc)();
6398-
voidfunc x = (voidfunc)dlsym(lib_handle, "library_func");
6399-
if (!x) puts("cannot find side function");
6400-
else x();
6376+
def test(main_args, library_args=[], expected='hello from main\nhello from library'):
6377+
print('testing', main_args, library_args)
6378+
self.clear()
6379+
create_test_file('library.c', r'''
6380+
#include <stdio.h>
6381+
void library_func() {
6382+
#ifdef USE_PRINTF
6383+
printf("hello from library: %p\n", &library_func);
6384+
#else
6385+
puts("hello from library");
6386+
#endif
6387+
}
6388+
''')
6389+
# -fno-builtin to prevent printf -> iprintf optimization
6390+
run_process([PYTHON, EMCC, 'library.c', '-fno-builtin', '-s', 'SIDE_MODULE=1', '-O2', '-o', library_file, '-s', 'WASM=' + str(wasm), '-s', 'EXPORT_ALL'] + library_args)
6391+
create_test_file('main.c', r'''
6392+
#include <dlfcn.h>
6393+
#include <stdio.h>
6394+
int main() {
6395+
puts("hello from main");
6396+
void *lib_handle = dlopen("%s", 0);
6397+
if (!lib_handle) {
6398+
puts("cannot load side module");
6399+
return 1;
64016400
}
6402-
''' % library_file)
6403-
run_process([PYTHON, EMCC, 'main.c', '--embed-file', library_file, '-O2', '-s', 'WASM=' + str(wasm)] + main_args)
6404-
self.assertContained(expected, run_js('a.out.js', assert_returncode=None, stderr=STDOUT))
6405-
size = os.path.getsize('a.out.js')
6406-
if wasm:
6407-
size += os.path.getsize('a.out.wasm')
6408-
side_size = os.path.getsize(library_file)
6409-
print(' sizes:', size, side_size)
6410-
return (size, side_size)
6411-
6412-
def percent_diff(x, y):
6413-
small = min(x, y)
6414-
large = max(x, y)
6415-
return float(100 * large) / small - 100
6401+
typedef void (*voidfunc)();
6402+
voidfunc x = (voidfunc)dlsym(lib_handle, "library_func");
6403+
if (!x) puts("cannot find side function");
6404+
else x();
6405+
}
6406+
''' % library_file)
6407+
run_process([PYTHON, EMCC, 'main.c', '--embed-file', library_file, '-O2', '-s', 'WASM=' + str(wasm)] + main_args)
6408+
self.assertContained(expected, run_js('a.out.js', assert_returncode=None, stderr=STDOUT))
6409+
size = os.path.getsize('a.out.js')
6410+
if wasm:
6411+
size += os.path.getsize('a.out.wasm')
6412+
side_size = os.path.getsize(library_file)
6413+
print(' sizes:', size, side_size)
6414+
return (size, side_size)
64166415

6417-
full = test(main_args=['-s', 'MAIN_MODULE=1'])
6418-
# printf is not used in main, but libc was linked in, so it's there
6419-
printf = test(main_args=['-s', 'MAIN_MODULE=1'], library_args=['-DUSE_PRINTF'])
6416+
def percent_diff(x, y):
6417+
small = min(x, y)
6418+
large = max(x, y)
6419+
return float(100 * large) / small - 100
64206420

6421-
# main module tests
6421+
full = test(main_args=['-s', 'MAIN_MODULE=1'])
6422+
# printf is not used in main, but libc was linked in, so it's there
6423+
printf = test(main_args=['-s', 'MAIN_MODULE=1'], library_args=['-DUSE_PRINTF'])
64226424

6423-
# dce in main, and it fails since puts is not exported
6424-
dce = test(main_args=['-s', 'MAIN_MODULE=2'], expected=('cannot', 'undefined'))
6425+
# main module tests
64256426

6426-
# with exporting, it works
6427-
dce = test(main_args=['-s', 'MAIN_MODULE=2', '-s', 'EXPORTED_FUNCTIONS=["_main", "_puts"]'])
6427+
# dce in main, and it fails since puts is not exported
6428+
dce = test(main_args=['-s', 'MAIN_MODULE=2'], expected=('cannot', 'undefined'))
64286429

6429-
# printf is not used in main, and we dce, so we failz
6430-
dce_fail = test(main_args=['-s', 'MAIN_MODULE=2'], library_args=['-DUSE_PRINTF'], expected=('cannot', 'undefined'))
6430+
# with exporting, it works
6431+
dce = test(main_args=['-s', 'MAIN_MODULE=2', '-s', 'EXPORTED_FUNCTIONS=["_main", "_puts"]'])
64316432

6432-
# exporting printf in main keeps it alive for the library
6433-
dce_save = test(main_args=['-s', 'MAIN_MODULE=2', '-s', 'EXPORTED_FUNCTIONS=["_main", "_printf", "_puts"]'], library_args=['-DUSE_PRINTF'])
6433+
# printf is not used in main, and we dce, so we failz
6434+
dce_fail = test(main_args=['-s', 'MAIN_MODULE=2'], library_args=['-DUSE_PRINTF'], expected=('cannot', 'undefined'))
64346435

6435-
self.assertLess(percent_diff(full[0], printf[0]), 4)
6436-
self.assertLess(percent_diff(dce[0], dce_fail[0]), 4)
6437-
self.assertLess(dce[0], 0.2 * full[0]) # big effect, 80%+ is gone
6438-
self.assertGreater(dce_save[0], 1.05 * dce[0]) # save exported all of printf
6436+
# exporting printf in main keeps it alive for the library
6437+
dce_save = test(main_args=['-s', 'MAIN_MODULE=2', '-s', 'EXPORTED_FUNCTIONS=["_main", "_printf", "_puts"]'], library_args=['-DUSE_PRINTF'])
64396438

6440-
# side module tests
6439+
self.assertLess(percent_diff(full[0], printf[0]), 4)
6440+
self.assertLess(percent_diff(dce[0], dce_fail[0]), 4)
6441+
self.assertLess(dce[0], 0.2 * full[0]) # big effect, 80%+ is gone
6442+
self.assertGreater(dce_save[0], 1.05 * dce[0]) # save exported all of printf
64416443

6442-
# mode 2, so dce in side, but library_func is not exported, so it is dce'd
6443-
side_dce_fail = test(main_args=['-s', 'MAIN_MODULE=1'], library_args=['-s', 'SIDE_MODULE=2'], expected='cannot find side function')
6444-
# mode 2, so dce in side, and library_func is not exported
6445-
side_dce_work = test(main_args=['-s', 'MAIN_MODULE=1'], library_args=['-s', 'SIDE_MODULE=2', '-s', 'EXPORTED_FUNCTIONS=["_library_func"]'], expected='hello from library')
6444+
# side module tests
64466445

6447-
self.assertLess(side_dce_fail[1], 0.95 * side_dce_work[1]) # removing that function saves a chunk
6446+
# mode 2, so dce in side, but library_func is not exported, so it is dce'd
6447+
side_dce_fail = test(main_args=['-s', 'MAIN_MODULE=1'], library_args=['-s', 'SIDE_MODULE=2'], expected='cannot find side function')
6448+
# mode 2, so dce in side, and library_func is not exported
6449+
side_dce_work = test(main_args=['-s', 'MAIN_MODULE=1'], library_args=['-s', 'SIDE_MODULE=2', '-s', 'EXPORTED_FUNCTIONS=["_library_func"]'], expected='hello from library')
64486450

6449-
run(wasm=1)
6450-
if not self.is_wasm_backend():
6451-
run(wasm=0)
6451+
self.assertLess(side_dce_fail[1], 0.95 * side_dce_work[1]) # removing that function saves a chunk
64526452

64536453
def test_ld_library_path(self):
64546454
create_test_file('hello1.c', r'''

tools/shared.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1909,15 +1909,15 @@ def link_lld(args, target, opts=[], lto_level=0):
19091909

19101910
if Settings.LINKABLE:
19111911
cmd.append('--export-all')
1912+
else:
1913+
# in standalone mode, crt1 will call the constructors from inside the wasm
1914+
if not Settings.STANDALONE_WASM:
1915+
cmd += ['--export', '__wasm_call_ctors']
19121916

1913-
# in standalone mode, crt1 will call the constructors from inside the wasm
1914-
if not Settings.STANDALONE_WASM:
1915-
cmd += ['--export', '__wasm_call_ctors']
1916-
1917-
cmd += ['--export', '__data_end']
1917+
cmd += ['--export', '__data_end']
19181918

1919-
for export in Settings.EXPORTED_FUNCTIONS:
1920-
cmd += ['--export', export[1:]] # Strip the leading underscore
1919+
for export in Settings.EXPORTED_FUNCTIONS:
1920+
cmd += ['--export', export[1:]] # Strip the leading underscore
19211921

19221922
if Settings.RELOCATABLE:
19231923
if Settings.SIDE_MODULE:

0 commit comments

Comments
 (0)