Skip to content

Commit 6f9e532

Browse files
authored
Make EXPORTED_RUNTIME_METHODS work for library functions (#17369)
This helps when moving function from runtime to JS library since it means that users who were previously using `EXPORTED_RUNTIME_METHODS` to export such symbols will not be effected by the transition.
1 parent bbafe45 commit 6f9e532

11 files changed

+63
-32
lines changed

ChangeLog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ See docs/process.md for more on how version tagging works.
2020

2121
3.1.16
2222
------
23+
- When JS library functions are included as part of `EXPORTED_RUNTIME_METHODS`
24+
it is no longer necessary to also add them to
25+
`DEFAULT_LIBRARY_FUNCS_TO_INCLUDE`. This change allows us to transition
26+
runtime functions to JS library functions without the need to folks to add
27+
`DEFAULT_LIBRARY_FUNCS_TO_INCLUDE`. (#17369)
2328

2429
3.1.15 - 07/01/2022
2530
-------------------

src/jsifier.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ function runJSify(functionsOnly) {
8181
LibraryManager.load();
8282

8383
const libFuncsToInclude = DEFAULT_LIBRARY_FUNCS_TO_INCLUDE;
84+
for (const sym of EXPORTED_RUNTIME_METHODS) {
85+
if ('$' + sym in LibraryManager.library) {
86+
libFuncsToInclude.push('$' + sym);
87+
}
88+
}
8489
if (INCLUDE_FULL_LIBRARY) {
8590
for (const key in LibraryManager.library) {
8691
if (!isJsLibraryConfigIdentifier(key)) {

src/modules.js

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,33 @@ function isExportedByForceFilesystem(name) {
344344
name === 'removeRunDependency';
345345
}
346346

347+
function isInternalSymbol(ident) {
348+
return ident + '__internal' in LibraryManager.library;
349+
}
350+
351+
// When running with ASSERTIONS enabled we create stubs for each library
352+
// function that that was not included in the build. This gives useful errors
353+
// when library dependencies are missing from `__deps` or depended on without
354+
// being added to DEFAULT_LIBRARY_FUNCS_TO_INCLUDE
355+
// TODO(sbc): These errors could potentially be generated at build time via
356+
// some kind of acorn pass that searched for uses of these missing symbols.
357+
function addMissingLibraryStubs() {
358+
if (!ASSERTIONS) return '';
359+
let rtn = '';
360+
const librarySymbolSet = new Set(libraryFunctions);
361+
for (const ident in LibraryManager.library) {
362+
if (typeof LibraryManager.library[ident] === 'function') {
363+
if (ident[0] === '$' && !isJsLibraryConfigIdentifier(ident) && !isInternalSymbol(ident)) {
364+
const name = ident.substr(1);
365+
if (!librarySymbolSet.has(name)) {
366+
rtn += `var ${name} = missingLibraryFunc('${name}');\n`;
367+
}
368+
}
369+
}
370+
}
371+
return rtn;
372+
}
373+
347374
// export parts of the JS runtime that the user asked for
348375
function exportRuntime() {
349376
const EXPORTED_RUNTIME_METHODS_SET = new Set(EXPORTED_RUNTIME_METHODS);
@@ -379,7 +406,6 @@ function exportRuntime() {
379406
return `unexportedRuntimeFunction('${name}', ${fssymbol});`;
380407
}
381408
}
382-
return '';
383409
}
384410

385411
function maybeExportNumber(name) {
@@ -499,7 +525,7 @@ function exportRuntime() {
499525
// '$ which indicates they are JS methods.
500526
const runtimeElementsSet = new Set(runtimeElements);
501527
for (const ident in LibraryManager.library) {
502-
if (ident[0] === '$' && !isJsLibraryConfigIdentifier(ident) && !LibraryManager.library[ident + '__internal']) {
528+
if (ident[0] === '$' && !isJsLibraryConfigIdentifier(ident) && !isInternalSymbol(ident)) {
503529
const jsname = ident.substr(1);
504530
assert(!runtimeElementsSet.has(jsname), 'runtimeElements contains library symbol: ' + ident);
505531
runtimeElements.push(jsname);
@@ -516,12 +542,12 @@ function exportRuntime() {
516542
const runtimeNumbersSet = new Set(runtimeNumbers);
517543
for (const name of EXPORTED_RUNTIME_METHODS_SET) {
518544
if (!runtimeElementsSet.has(name) && !runtimeNumbersSet.has(name)) {
519-
printErr(`warning: invalid item (maybe a typo?) in EXPORTED_RUNTIME_METHODS: ${name}`);
545+
printErr(`warning: invalid item in EXPORTED_RUNTIME_METHODS: ${name}`);
520546
}
521547
}
522548
}
523549
let exports = runtimeElements.map((name) => maybeExport(name));
524550
exports = exports.concat(runtimeNumbers.map((name) => maybeExportNumber(name)));
525-
exports = exports.filter((name) => name != '');
526-
return exports.join('\n');
551+
exports = exports.filter((name) => name);
552+
return exports.join('\n') + '\n' + addMissingLibraryStubs();
527553
}

src/parseTools.js

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,14 +1045,6 @@ function makeRemovedFSAssert(fsName) {
10451045
return `var ${fsName} = '${fsName} is no longer included by default; build with -l${lower}.js';`;
10461046
}
10471047

1048-
function makeRemovedRuntimeFunction(name) {
1049-
assert(ASSERTIONS);
1050-
if (libraryFunctions.includes(name)) {
1051-
return '';
1052-
}
1053-
return `function ${name}() { abort('\`${name}\` is now a library function and not included by default; add it to your library.js __deps or to DEFAULT_LIBRARY_FUNCS_TO_INCLUDE on the command line'); }`;
1054-
}
1055-
10561048
// Given an array of elements [elem1,elem2,elem3], returns a string "['elem1','elem2','elem3']"
10571049
function buildStringArray(array) {
10581050
if (array.length > 0) {

src/runtime_debug.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ function unexportedMessage(sym, isFSSybol) {
3030
return msg;
3131
}
3232

33+
function missingLibraryFunc(sym) {
34+
return () => abort('Call to `' + sym + '` which is a library function and not included by default; add it to your library.js __deps or to DEFAULT_LIBRARY_FUNCS_TO_INCLUDE on the command line');
35+
}
36+
3337
function unexportedRuntimeSymbol(sym, isFSSybol) {
3438
if (!Object.getOwnPropertyDescriptor(Module, sym)) {
3539
Object.defineProperty(Module, sym, {

src/settings.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -863,10 +863,7 @@ var ASYNCIFY_DEBUG = 0;
863863

864864
// Runtime elements that are exported on Module by default. We used to export
865865
// quite a lot here, but have removed them all. You should use
866-
// EXPORTED_RUNTIME_METHODS for things you want to export from the runtime. Note
867-
// that methods on this list are only exported if they are included (either
868-
// automatically from linking, or due to being in
869-
// DEFAULT_LIBRARY_FUNCS_TO_INCLUDE).
866+
// EXPORTED_RUNTIME_METHODS for things you want to export from the runtime.
870867
// Note that the name may be slightly misleading, as this is for any JS library
871868
// element, and not just methods. For example, we can export the FS object by
872869
// having "FS" in this list.

src/shell.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,6 @@ assert(typeof Module['TOTAL_MEMORY'] == 'undefined', 'Module.TOTAL_MEMORY has be
477477
#if !NODERAWFS
478478
{{{ makeRemovedFSAssert('NODEFS') }}}
479479
#endif
480-
{{{ makeRemovedRuntimeFunction('alignMemory') }}}
481480

482481
#if USE_PTHREADS
483482
assert(ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER || ENVIRONMENT_IS_NODE, 'Pthreads do not work in this environment yet (need Web Workers, or an alternative to them)');
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
89932
1+
98207
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
59666
1+
59667

tests/test_core.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5680,22 +5680,16 @@ def test_utf(self):
56805680
self.do_core_test('test_utf.c')
56815681

56825682
def test_utf32(self):
5683-
if self.get_setting('MINIMAL_RUNTIME'):
5684-
self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', ['$UTF32ToString', '$stringToUTF32', '$lengthBytesUTF32'])
5685-
else:
5686-
self.set_setting('EXPORTED_RUNTIME_METHODS', ['UTF32ToString', 'stringToUTF32', 'lengthBytesUTF32'])
5683+
self.set_setting('EXPORTED_RUNTIME_METHODS', ['UTF32ToString', 'stringToUTF32', 'lengthBytesUTF32'])
56875684
self.do_runf(test_file('utf32.cpp'), 'OK.')
56885685
self.do_runf(test_file('utf32.cpp'), 'OK.', args=['-fshort-wchar'])
56895686

56905687
def test_utf16(self):
5688+
self.set_setting('EXPORTED_RUNTIME_METHODS', ['writeAsciiToMemory'])
56915689
self.do_runf(test_file('core/test_utf16.cpp'), 'OK.')
56925690

56935691
def test_utf8(self):
5694-
if self.get_setting('MINIMAL_RUNTIME'):
5695-
self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', ['$AsciiToString', '$stringToAscii', '$writeAsciiToMemory'])
5696-
else:
5697-
self.set_setting('EXPORTED_RUNTIME_METHODS',
5698-
['UTF8ToString', 'stringToUTF8', 'AsciiToString', 'stringToAscii'])
5692+
self.set_setting('EXPORTED_RUNTIME_METHODS', ['UTF8ToString', 'stringToUTF8', 'AsciiToString', 'stringToAscii', 'writeAsciiToMemory'])
56995693
self.do_runf(test_file('utf8.cpp'), 'OK.')
57005694

57015695
@also_with_wasm_bigint

0 commit comments

Comments
 (0)