Skip to content

Commit 778fdf4

Browse files
authored
Export symbols on Module when using MINIMAL_RUNTIME + MODULARIZE + EXPORT_ALL (emscripten-core#17911)
1 parent 5c756de commit 778fdf4

5 files changed

Lines changed: 62 additions & 16 deletions

File tree

ChangeLog.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ See docs/process.md for more on how version tagging works.
3131
- --pre-js and --post-js files are now fed through the JS preprocesor, just
3232
like JS library files and the core runtime JS files. This means they can
3333
now contain #if/#else/#endif blocks and {{{ }}} macro blocks. (#18525)
34+
- `-sEXPORT_ALL` can now be used to export symbols on the `Module` object
35+
when used with `-sMINIMA_RUNTIME` and `-sMODULARIZE` together. (#17911)
3436

3537
3.1.30 - 01/11/23
3638
-----------------
@@ -387,7 +389,7 @@ See docs/process.md for more on how version tagging works.
387389
binaryen optimizations are limited due to DWARF information being requested.
388390
Several binaryen passed are not compatible with the preservation of DWARF
389391
information. (#16428)
390-
- Use normalized mouse wheel delta for GLFW 3 in `library_glfw.js`. This changes
392+
- Use normalized mouse wheel delta for GLFW 3 in `library_glfw.js`. This changes
391393
the vertical scroll amount for GLFW 3. (#16480)
392394
- The emsdk binaries for macOS now require macOS 10.14 Mojave (or above).
393395
Prior versions of emsdk could run on 10.11 (or above), but supporting those

emscripten.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -756,7 +756,10 @@ def create_receiving(exports):
756756
for s in exports_that_are_not_initializers:
757757
mangled = asmjs_mangle(s)
758758
dynCallAssignment = ('dynCalls["' + s.replace('dynCall_', '') + '"] = ') if generate_dyncall_assignment and mangled.startswith('dynCall_') else ''
759-
receiving += [dynCallAssignment + mangled + ' = asm["' + s + '"];']
759+
export_assignment = ''
760+
if settings.MODULARIZE and settings.EXPORT_ALL:
761+
export_assignment = f'Module["{mangled}"] = '
762+
receiving += [f'{export_assignment}{dynCallAssignment}{mangled} = asm["{s}"]']
760763
else:
761764
receiving += make_export_wrappers(exports, delay_assignment)
762765
else:

src/modules.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ function exportRuntime() {
444444
const exports = runtimeElements.map(maybeExport);
445445
const results = exports.filter((name) => name);
446446

447-
if (ASSERTIONS) {
447+
if (ASSERTIONS && !EXPORT_ALL) {
448448
const unusedLibSymbols = getUnusedLibarySymbols();
449449
if (unusedLibSymbols.size) {
450450
results.push(addMissingLibraryStubs(unusedLibSymbols));

src/preamble_minimal.js

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@
44
* SPDX-License-Identifier: MIT
55
*/
66

7+
{{{
8+
// Helper function to export a symbol on the module object
9+
// if requested.
10+
global.maybeExport = function(x) {
11+
return MODULARIZE && EXPORT_ALL ? `Module['${x}'] = ` : '';
12+
};
13+
null;
14+
}}}
15+
716
#if SAFE_HEAP
817
#include "runtime_safe_heap.js"
918
#endif
@@ -56,26 +65,25 @@ var HEAP8, HEAP16, HEAP32, HEAPU8, HEAPU16, HEAPU32, HEAPF32, HEAPF64,
5665
#endif
5766
wasmMemory, wasmTable;
5867

59-
6068
function updateMemoryViews() {
6169
var b = wasmMemory.buffer;
6270
#if ASSERTIONS && SHARED_MEMORY
6371
assert(b instanceof SharedArrayBuffer, 'requested a shared WebAssembly.Memory but the returned buffer is not a SharedArrayBuffer, indicating that while the browser has SharedArrayBuffer it does not have WebAssembly threads support - you may need to set a flag');
6472
#endif
6573
#if SUPPORT_BIG_ENDIAN
66-
HEAP_DATA_VIEW = new DataView(b);
67-
#endif
68-
HEAP8 = new Int8Array(b);
69-
HEAP16 = new Int16Array(b);
70-
HEAP32 = new Int32Array(b);
71-
HEAPU8 = new Uint8Array(b);
72-
HEAPU16 = new Uint16Array(b);
73-
HEAPU32 = new Uint32Array(b);
74-
HEAPF32 = new Float32Array(b);
75-
HEAPF64 = new Float64Array(b);
74+
{{{ maybeExport('HEAP_DATA_VIEW') }}}HEAP_DATA_VIEW = new DataView(b);
75+
#endif
76+
{{{ maybeExport('HEAP8') }}}HEAP8 = new Int8Array(b);
77+
{{{ maybeExport('HEAP16') }}}HEAP16 = new Int16Array(b);
78+
{{{ maybeExport('HEAP32') }}}HEAP32 = new Int32Array(b);
79+
{{{ maybeExport('HEAPU8') }}}HEAPU8 = new Uint8Array(b);
80+
{{{ maybeExport('HEAPU16') }}}HEAPU16 = new Uint16Array(b);
81+
{{{ maybeExport('HEAPU32') }}}HEAPU32 = new Uint32Array(b);
82+
{{{ maybeExport('HEAPF32') }}}HEAPF32 = new Float32Array(b);
83+
{{{ maybeExport('HEAPF64') }}}HEAPF64 = new Float64Array(b);
7684
#if WASM_BIGINT
77-
HEAP64 = new BigInt64Array(b);
78-
HEAPU64 = new BigUint64Array(b);
85+
{{{ maybeExport('HEAP64') }}}HEAP64 = new BigInt64Array(b);
86+
{{{ maybeExport('HEAPU64') }}}HEAPU64 = new BigUint64Array(b);
7987
#endif
8088
}
8189

test/test_other.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1307,6 +1307,39 @@ def test_export_all(self):
13071307
self.emcc('lib.c', ['-Oz', '-sEXPORT_ALL', '-sLINKABLE', '--pre-js', 'main.js'], output_filename='a.out.js')
13081308
self.assertContained('libf1\nlibf2\n', self.run_js('a.out.js'))
13091309

1310+
def test_minimal_runtime_export_all_modularize(self):
1311+
"""This test ensures that MODULARIZE and EXPORT_ALL work simultaneously.
1312+
1313+
In addition, it ensures that EXPORT_ALL is honored while using MINIMAL_RUNTIME.
1314+
"""
1315+
1316+
create_file('main.c', r'''
1317+
#include <stdio.h>
1318+
#include <emscripten.h>
1319+
EMSCRIPTEN_KEEPALIVE void libf1() { printf("libf1\n"); }
1320+
EMSCRIPTEN_KEEPALIVE void libf2() { printf("libf2\n"); }
1321+
''')
1322+
1323+
self.emcc('main.c', ['-sMODULARIZE=1', '-sMINIMAL_RUNTIME=2', '-sEXPORT_ALL', '-sEXPORT_ES6'], output_filename='test.mjs')
1324+
1325+
# We must expose __dirname and require globally because emscripten
1326+
# uses those under the hood.
1327+
create_file('main.mjs', '''
1328+
import { dirname } from 'path';
1329+
import { createRequire } from 'module';
1330+
globalThis.__dirname = dirname(import.meta.url).substring(7);
1331+
globalThis.require = createRequire(import.meta.url);
1332+
1333+
import Test from './test.mjs';
1334+
async function main() {
1335+
const mod = await Test();
1336+
mod._libf1();
1337+
mod._libf2();
1338+
}
1339+
main();
1340+
''')
1341+
self.assertContained('libf1\nlibf2\n', self.run_js('main.mjs'))
1342+
13101343
def test_export_all_and_exported_functions(self):
13111344
# EXPORT_ALL should not export library functions by default.
13121345
# This means that to export library function you also need to explicitly

0 commit comments

Comments
 (0)