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:
Sam Clegg 2020-07-09 22:15:23 -07:00 коммит произвёл GitHub
Родитель 0bfe9f584d
Коммит 121ca5561e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 19 добавлений и 28 удалений

Просмотреть файл

@ -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,

Просмотреть файл

@ -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)

2
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):

19
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 <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)