Skip to content

Commit 5f417e5

Browse files
committed
Build-time error on use of emscripten_promise_any if Promise.any is not available
1 parent 2e9314e commit 5f417e5

File tree

5 files changed

+48
-3
lines changed

5 files changed

+48
-3
lines changed

emcc.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2432,7 +2432,10 @@ def phase_linker_setup(options, state, newargs):
24322432
settings.WASM_WORKER_FILE = unsuffixed(os.path.basename(target)) + '.ww.js'
24332433
settings.JS_LIBRARIES.append((0, shared.path_from_root('src', 'library_wasm_worker.js')))
24342434

2435+
# TODO(sbc): Find make a generic way to expose the feature matrix to JS
2436+
# compiler rather then adding them all ad-hoc as internal settings
24352437
settings.SUPPORTS_GLOBALTHIS = feature_matrix.caniuse(feature_matrix.Feature.GLOBALTHIS)
2438+
settings.SUPPORTS_PROMISE_ANY = feature_matrix.caniuse(feature_matrix.Feature.PROMISE_ANY)
24362439
if not settings.BULK_MEMORY:
24372440
settings.BULK_MEMORY = feature_matrix.caniuse(feature_matrix.Feature.BULK_MEMORY)
24382441

src/library_promise.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,15 @@ mergeInto(LibraryManager.library, {
216216
return id;
217217
},
218218

219-
emscripten_promise_any__deps: ['$promiseMap', '$idsToPromises'],
219+
220+
emscripten_promise_any__deps: [
221+
'$promiseMap', '$idsToPromises',
222+
#if !SUPPORTS_PROMISE_ANY
223+
// Adding a function here as a dependency will trigger it to be run
224+
// at build time, if and only if this function gets included.
225+
() => error("emscripten_promise_any used, but Promise.any is not supported the current browser configuration"),
226+
#endif
227+
],
220228
emscripten_promise_any: function(idBuf, errorBuf, size) {
221229
var promises = idsToPromises(idBuf, size);
222230
#if RUNTIME_DEBUG

src/settings_internal.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ var TARGET_NOT_SUPPORTED = 0x7FFFFFFF;
175175
// Used to track whether target environment supports the 'globalThis' attribute.
176176
var SUPPORTS_GLOBALTHIS = false;
177177

178+
// Used to track whether target environment supports the 'Promise.any'.
179+
var SUPPORTS_PROMISE_ANY = false;
180+
178181
// Wasm backend symbols that are considered system symbols and don't
179182
// have the normal C symbol name mangled applied (== prefix with an underscore)
180183
// (Also implicily on this list is any function that starts with string "dynCall_")

test/test_core.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9761,6 +9761,14 @@ def test_main_reads_args(self):
97619761

97629762
@requires_node
97639763
def test_promise(self):
9764+
# This test depends on Promise.any, which in turn requires a modern target. Check that it
9765+
# fails to even build without bumping the min versions:
9766+
err = self.expect_fail([EMCC, test_file('core/test_promise.c')])
9767+
self.assertContained('error: emscripten_promise_any used, but Promise.any is not supported the current browser configuration', err)
9768+
self.set_setting('MIN_NODE_VERSION', '150000')
9769+
self.set_setting('MIN_SAFARI_VERSION', '150000')
9770+
self.set_setting('MIN_FIREFOX_VERSION', '79')
9771+
self.set_setting('MIN_CHROME_VERSION', '85')
97649772
self.do_core_test('test_promise.c')
97659773

97669774

tools/feature_matrix.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,17 @@
1515

1616

1717
class Feature(IntEnum):
18+
# Wasm features
1819
NON_TRAPPING_FPTOINT = auto()
1920
SIGN_EXT = auto()
2021
BULK_MEMORY = auto()
2122
MUTABLE_GLOBALS = auto()
22-
JS_BIGINT_INTEGRATION = auto()
2323
THREADS = auto()
24+
25+
# JS Features
26+
JS_BIGINT_INTEGRATION = auto()
2427
GLOBALTHIS = auto()
28+
PROMISE_ANY = auto()
2529

2630

2731
default_features = {Feature.SIGN_EXT, Feature.MUTABLE_GLOBALS}
@@ -62,25 +66,44 @@ class Feature(IntEnum):
6266
'edge': 79,
6367
'firefox': 65,
6468
'safari': 120100,
65-
# 'node': 120000
69+
'node': 120000,
70+
},
71+
Feature.PROMISE_ANY: {
72+
'chrome': 85,
73+
'firefox': 79,
74+
'safari': 140000,
75+
'node': 150000,
6676
},
6777
}
6878

6979

7080
def caniuse(feature):
7181
min_versions = min_browser_versions[feature]
82+
83+
def report_missing(setting_name):
84+
setting_value = getattr(settings, setting_name)
85+
logger.debug(f'cannot use {feature.name} because {setting_name} is too old: {setting_value}')
86+
7287
if settings.MIN_CHROME_VERSION < min_versions['chrome']:
88+
report_missing('MIN_CHROME_VERSION')
7389
return False
7490
# For edge we just use the same version requirements as chrome since,
7591
# at least for modern versions of edge, they share version numbers.
7692
if settings.MIN_EDGE_VERSION < min_versions['chrome']:
93+
report_missing('MIN_EDGE_VERSION')
7794
return False
7895
if settings.MIN_FIREFOX_VERSION < min_versions['firefox']:
96+
report_missing('MIN_FIREFOX_VERSION')
7997
return False
8098
if settings.MIN_SAFARI_VERSION < min_versions['safari']:
99+
report_missing('MIN_SAFARI_VERSION')
81100
return False
82101
# IE don't support any non-MVP features
83102
if settings.MIN_IE_VERSION != 0x7FFFFFFF:
103+
report_missing('MIN_IE_VERSION')
104+
return False
105+
if 'node' in min_versions and settings.MIN_NODE_VERSION < min_versions['node']:
106+
report_missing('MIN_NODE_VERSION')
84107
return False
85108
return True
86109

0 commit comments

Comments
 (0)