Always warn/error about undefined symbols if they are explicitly exported (#11604)
ERROR_ON_UNDEFINED_SYMBOLS and WARN_ON_UNDEFINED_SYMBOLS exist to allow build that contains undefined symbols to build created with the missing symbols supplied at runtime somehow. However, I think we should have a separate warning system for when function that are explicitly exported by the user via EXPORTED_FUNCTIONS are missing from a build. In that case we always want to fail or warn.
This commit is contained in:
Родитель
0bfe9f584d
Коммит
121ca5561e
|
@ -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,
|
||||
|
|
5
emcc.py
5
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.')
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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 <stdio.h>
|
||||
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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
|
Загрузка…
Ссылка в новой задаче