diff --git a/ChangeLog.md b/ChangeLog.md index 90c535e03..4a5a60d97 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -17,6 +17,10 @@ See docs/process.md for how version tagging works. Current Trunk ------------- +- It is now an error if a function listed in the `EXPORTED_FUNCTIONS` list is + missing from the build (can be disabled via `-Wno-undefined`) + (ERROR_ON_UNDEFINED_SYMBOLS and WARN_ON_UNDEFINED_SYMBOLS no longer apply + to these symbols which are explicly exported). - Support for pthreads with wasm2js (`WASM=0`; #11505). - Rename `emscripten/math.h` to `emscripten/em_math.h` because if a user adds `emscripten/` as an include path with `-I`, that can override libc math.h, diff --git a/emcc.py b/emcc.py index dbe3fe25e..dc37c0f1c 100755 --- a/emcc.py +++ b/emcc.py @@ -1573,11 +1573,6 @@ There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR P shared.Settings.ERROR_ON_UNDEFINED_SYMBOLS = 0 shared.Settings.WARN_ON_UNDEFINED_SYMBOLS = 0 - if shared.Settings.WARN_ON_UNDEFINED_SYMBOLS: - diagnostics.enable_warning('undefined', shared.Settings.ERROR_ON_UNDEFINED_SYMBOLS) - else: - diagnostics.disable_warning('undefined') - if shared.Settings.ASYNCIFY: if not shared.Settings.WASM_BACKEND: exit_with_error('ASYNCIFY has been removed from fastcomp. There is a new implementation which can be used in the upstream wasm backend.') diff --git a/emscripten.py b/emscripten.py index c4c58c398..c82ae9d9f 100644 --- a/emscripten.py +++ b/emscripten.py @@ -313,7 +313,8 @@ def function_tables_and_exports(funcs, metadata, mem_init, glue, forwarded_data, pre, funcs_js = get_js_funcs(pre, funcs) all_exported_functions = get_all_exported_functions(function_table_data) all_implemented = get_all_implemented(forwarded_json, metadata) - report_missing_symbols(all_implemented, pre) + all_implemented_with_aliases = set(all_implemented).union(set(metadata['aliases'].keys())) + report_missing_symbols(all_implemented_with_aliases, pre) implemented_functions = get_implemented_functions(metadata) pre = include_asm_consts(pre, forwarded_json, metadata) pre = apply_table(pre) @@ -890,10 +891,6 @@ def get_all_implemented(forwarded_json, metadata): def report_missing_symbols(all_implemented, pre): - # we are not checking anyway, so just skip this - if not shared.Settings.ERROR_ON_UNDEFINED_SYMBOLS and not shared.Settings.WARN_ON_UNDEFINED_SYMBOLS: - return - # the initial list of missing functions are that the user explicitly exported # but were not implemented in compiled code missing = list(set(shared.Settings.USER_EXPORTED_FUNCTIONS) - all_implemented) diff --git a/tests/test_core.py b/tests/test_core.py index 19918be21..4c083d064 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -4324,7 +4324,7 @@ res64 - external 64\n''', header=''' 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', '-s', 'EXPORTED_FUNCTIONS=["_main", "_jslib_x"]']) + ''', expected=['main: jslib_x is 148.\nside: jslib_x is 148.\n'], main_emcc_args=['--js-library', 'lib.js']) @needs_dlfcn def test_dylink_many_postsets(self): diff --git a/tests/test_other.py b/tests/test_other.py index 7fe9b8b5b..fb4fb3017 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -1553,7 +1553,7 @@ int f() { def test_export_from_archive(self): export_name = 'this_is_an_entry_point' - full_export_name = '_' + export_name + full_export_name = '_this_is_an_entry_point' # The wasm backend exports symbols without the leading '_' if self.is_wasm_backend(): @@ -1563,10 +1563,10 @@ int f() { create_test_file('export.c', r''' #include - void %s(void) { + void this_is_an_entry_point(void) { printf("Hello, world!\n"); } - ''' % export_name) + ''') run_process([EMCC, 'export.c', '-c', '-o', 'export.o']) run_process([EMAR, 'rc', 'libexport.a', 'export.o']) @@ -1580,12 +1580,7 @@ int f() { run_process([EMCC, 'main.c', '-L.', '-lexport']) self.assertFalse(self.is_exported_in_wasm(expect_export, 'a.out.wasm')) - # Sanity check: exporting without a definition does not cause it to appear. - # Note: exporting main prevents emcc from warning that it generated no code. - run_process([EMCC, 'main.c', '-s', 'ERROR_ON_UNDEFINED_SYMBOLS=0', '-s', "EXPORTED_FUNCTIONS=['_main', '%s']" % full_export_name]) - self.assertFalse(self.is_exported_in_wasm(expect_export, 'a.out.wasm')) - - # Actual test: defining symbol in library and exporting it causes it to appear in the output. + # Exporting it causes it to appear in the output. run_process([EMCC, 'main.c', '-L.', '-lexport', '-s', "EXPORTED_FUNCTIONS=['%s']" % full_export_name]) self.assertTrue(self.is_exported_in_wasm(expect_export, 'a.out.wasm')) @@ -1849,7 +1844,7 @@ int f() { ''', output) self.assertNotContained('warning: library.js memcpy should not be running, it is only for testing!', output) - def test_undefined_function(self): + def test_undefined_exported_function(self): cmd = [EMCC, path_from_root('tests', 'hello_world.cpp')] run_process(cmd) @@ -1858,8 +1853,8 @@ int f() { err = self.expect_fail(cmd) self.assertContained('undefined exported function: "foobar"', err) - # setting ERROR_ON_UNDEFINED_SYMBOLS=0 suppresses error - cmd += ['-s', 'ERROR_ON_UNDEFINED_SYMBOLS=0'] + # setting `-Wno-undefined` should suppress error + cmd += ['-Wno-undefined'] run_process(cmd) def test_undefined_symbols(self): diff --git a/tools/diagnostics.py b/tools/diagnostics.py index 2da53ba14..598e2eabf 100644 --- a/tools/diagnostics.py +++ b/tools/diagnostics.py @@ -158,13 +158,13 @@ def warn(msg, *args): class WarningManager(object): warnings = {} - def add_warning(self, name, enabled=True, part_of_all=True, shared=False): + def add_warning(self, name, enabled=True, part_of_all=True, shared=False, error=False): self.warnings[name] = { 'enabled': enabled, 'part_of_all': part_of_all, # True for flags that are shared with the underlying clang driver 'shared': shared, - 'error': False, + 'error': error, } def capture_warnings(self, cmd_args): @@ -227,8 +227,8 @@ class WarningManager(object): logger.debug('disabled warning: ' + msg) -def add_warning(name, enabled=True, part_of_all=True, shared=False): - manager.add_warning(name, enabled, part_of_all, shared) +def add_warning(name, enabled=True, part_of_all=True, shared=False, error=False): + manager.add_warning(name, enabled, part_of_all, shared, error) def enable_warning(name, as_error=False): diff --git a/tools/shared.py b/tools/shared.py index 6f8f6a17f..e5f763a24 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -63,7 +63,7 @@ diagnostics.add_warning('legacy-settings', enabled=False, part_of_all=False) # Catch-all for other emcc warnings diagnostics.add_warning('linkflags') diagnostics.add_warning('emcc') -diagnostics.add_warning('undefined') +diagnostics.add_warning('undefined', error=True) diagnostics.add_warning('version-check') diagnostics.add_warning('fastcomp') diagnostics.add_warning('unused-command-line-argument', shared=True)