Skip to content

Commit 3bc1f9f

Browse files
authored
Less default runtime exports (#5892)
More for #5836 (JS shrinking). This removes almost all default function exports from the runtime. In ASSERTIONS builds, a warning will be shown if they are used, using the mechanism we introduced for getValue/setValue (which we recently removed from being exported by default). This reduces the size of the #5836 testcase by almost 20% (!), shrinking us from 21.75 k to 17.65 k. There are still a few things exported by default, like filesystem support (the file packager emits code that uses those, we should make extra sure this is not confusing for people) and things that aren't functions (need to investigate a good mechanism for warning if they are used incorrectly in ASSERTIONS mode, perhaps a getter on the Module object). This PR also includes * Changelog update explaining the change. * Docs improvements. * An example in the SDL port of how to export runtime stuff if the port needs it (so e.g. people using SDL don't need to manually add exports, the port can do it for them).
1 parent 89f9fe5 commit 3bc1f9f

File tree

15 files changed

+51
-52
lines changed

15 files changed

+51
-52
lines changed

ChangeLog.markdown

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Not all changes are documented here. In particular, new features, user-oriented
99

1010
Current Trunk
1111
-------------
12+
- Breaking change: Similar to the getValue/setValue change from before (and with the same `ASSERTIONS` warnings to help users), do not export the following runtime methods by default: ccall, cwrap, allocate, Pointer_stringify, AsciiToString, stringToAscii, UTF8ArrayToString, UTF8ToString, stringToUTF8Array, stringToUTF8, lengthBytesUTF8, stackTrace, addOnPreRun, addOnInit, addOnPreMain, addOnExit, addOnPostRun, intArrayFromString, intArrayToString, writeStringToMemory, writeArrayToMemory, writeAsciiToMemory.
1213

1314
v1.37.17: 12/4/2017
1415
-------------------

emcc.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,9 @@ def check(input_file):
937937

938938
assert not (shared.Settings.NO_DYNAMIC_EXECUTION and options.use_closure_compiler), 'cannot have both NO_DYNAMIC_EXECUTION and closure compiler enabled at the same time'
939939

940+
if options.emrun:
941+
shared.Settings.EXPORTED_RUNTIME_METHODS.append('addOnExit')
942+
940943
if options.use_closure_compiler:
941944
shared.Settings.USE_CLOSURE_COMPILER = options.use_closure_compiler
942945
if not shared.check_closure_compiler():

site/source/docs/api_reference/module.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Module object
88

99
Developers can provide an implementation of ``Module`` to control the execution of code. For example, to define how notification messages from Emscripten are displayed, developers implement the :js:attr:`Module.print` attribute.
1010

11-
.. note:: ``Module`` is also used to provide access to all Emscripten API functions (for example :js:func:`ccall`) in a way that avoids issues with function name minification at higher optimisation levels. These functions are documented as part of their own APIs.
11+
.. note:: ``Module`` is also used to provide access to Emscripten API functions (for example :js:func:`ccall`) in a safe way. Any function or runtime method exported (using ``EXPORTED_FUNCTIONS`` for compiled functions, or ``EXTRA_EXPORTED_RUNTIME_METHODS`` for runtime methods like ``ccall``) will be accessible on the ``Module`` object, without minification changing the name, and the optimizer will make sure to keep the function present (and not remove it as unused).
1212

1313
.. contents:: Table of Contents
1414
:local:

site/source/docs/api_reference/preamble.js.rst

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,13 @@ preamble.js
66

77
The JavaScript APIs in `preamble.js <https://github.com/kripken/emscripten/blob/master/src/preamble.js>`_ provide programmatic access for interacting with the compiled C code, including: calling compiled C functions, accessing memory, converting pointers to JavaScript ``Strings`` and ``Strings`` to pointers (with different encodings/formats), and other convenience functions.
88

9-
We call this "``preamble.js``" because Emscripten's output JS, at a high level, contains the preamble (from ``src/preamble.js``), then the compiled code, then the postamble. (In slightly more detail, the preamble contains utility functions and setup, while the postamble connects things and handles running the application.) Thus, the preamble code is included in the output JS, which means you can use the APIs described in this document without needing to do anything special.
9+
We call this "``preamble.js``" because Emscripten's output JS, at a high level, contains the preamble (from ``src/preamble.js``), then the compiled code, then the postamble. (In slightly more detail, the preamble contains utility functions and setup, while the postamble connects things and handles running the application.)
1010

11-
.. note:: All functions should be called though the :ref:`Module <module>` object (for example: ``Module.functionName``). At optimisation ``-O2`` (and higher) function names are minified by the closure compiler, and calling them directly will fail.
11+
The preamble code is included in the output JS, which is then optimized all together by the compiler, together with any ``--pre-js`` and ``--post-js`` files you added and code from any JavaScript libraries (``--js-library``). That means that you can call methods from the preamble directly, and the compiler will see that you need them, and not remove them as being unused.
12+
13+
If you want to call preamble methods from somewhere the compiler can't see, like another script tag on the HTML, you need to **export** them. To do so, add them to ``EXTRA_EXPORTED_RUNTIME_METHODS`` (for example, ``-s 'EXTRA_EXPORTED_RUNTIME_METHODS=["ccall", "cwrap"]'`` will export ``call`` and ``cwrap``). Once exported, you can access them on the ``Module`` object (as ``Module.ccall``, for example).
14+
15+
.. note:: If you try to use ``Module.ccall`` or another runtime method without exporting it, you will get an error. In a build with ``-s ASSERTIONS=1``, the compiler emits code to show you a useful error message, which will explain that you need to export it. In general, if you see something odd, it's useful to build with assertions.
1216

1317

1418
.. contents:: Table of Contents

site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ to prevent C++ name mangling.
6969
To compile this code run the following command in the Emscripten
7070
home directory::
7171

72-
./emcc tests/hello_function.cpp -o function.html -s EXPORTED_FUNCTIONS="['_int_sqrt']"
72+
./emcc tests/hello_function.cpp -o function.html -s EXPORTED_FUNCTIONS='["_int_sqrt"]' -s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]'
73+
74+
``EXPORTED_FUNCTIONS`` tells the compiler what we want to be accessible from the compiled code (everything else might be removed if it is not used), and ``EXTRA_EXPORTED_RUNTIME_METHODS`` tells the compiler that we want to use the runtime functions ``ccall`` and ``cwrap`` (otherwise, it will remove them if it does not see they are used).
7375

7476
.. note::
7577

@@ -146,9 +148,17 @@ parameters to pass to the function:
146148
as the latter will force the method to actually be included in
147149
the build.
148150

149-
- Use ``Module.ccall`` and not ``ccall`` by itself. The former will work
150-
at all optimisation levels (even if the :term:`Closure Compiler`
151-
minifies the function names).
151+
- The compiler will remove code it does not see is used, to improve code
152+
size. If you use ``ccall`` in a place it sees, like code in a ``--pre-js``
153+
or ``--post-js``, it will just work. If you use it in a place the compiler
154+
didn't see, like another script tag on the HTML or in the JS console like
155+
we did in this tutorial, then because of optimizations
156+
and minification you should export ccall from the runtime, using
157+
``EXTRA_EXPORTED_RUNTIME_METHODS``, for example using
158+
``-s 'EXTRA_EXPORTED_RUNTIME_METHODS=["ccall", "cwrap"]'``,
159+
and call it on ``Module`` (which contains
160+
everything exported, in a safe way that is not influenced by minification
161+
or optimizations).
152162

153163

154164
Interacting with an API written in C/C++ from NodeJS

src/modules.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ function maybeExport(name) {
283283
// check if it already exists, to support EXPORT_ALL and other cases
284284
// (we could optimize this, but in ASSERTIONS mode code size doesn't
285285
// matter anyhow)
286-
return 'if (!Module["' + name + '"]) Module["' + name + '"] = function() { abort("\'' + name + '\' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS.") };';
286+
return 'if (!Module["' + name + '"]) Module["' + name + '"] = function() { abort("\'' + name + '\' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };';
287287
}
288288
return '';
289289
}

src/preamble.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ function Pointer_stringify(ptr, length) {
431431
}
432432
return ret;
433433
}
434-
return Module['UTF8ToString'](ptr);
434+
return UTF8ToString(ptr);
435435
}
436436
{{{ maybeExport('Pointer_stringify') }}}
437437

src/settings.js

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -355,34 +355,12 @@ var EXPORTED_RUNTIME_METHODS = [ // Runtime elements that are exported on Module
355355
'FS_createDevice',
356356
'FS_unlink',
357357
'Runtime',
358-
'ccall',
359-
'cwrap',
360358
'ALLOC_NORMAL',
361359
'ALLOC_STACK',
362360
'ALLOC_STATIC',
363361
'ALLOC_DYNAMIC',
364362
'ALLOC_NONE',
365-
'allocate',
366363
'getMemory',
367-
'Pointer_stringify',
368-
'AsciiToString',
369-
'stringToAscii',
370-
'UTF8ArrayToString',
371-
'UTF8ToString',
372-
'stringToUTF8Array',
373-
'stringToUTF8',
374-
'lengthBytesUTF8',
375-
'stackTrace',
376-
'addOnPreRun',
377-
'addOnInit',
378-
'addOnPreMain',
379-
'addOnExit',
380-
'addOnPostRun',
381-
'intArrayFromString',
382-
'intArrayToString',
383-
'writeStringToMemory',
384-
'writeArrayToMemory',
385-
'writeAsciiToMemory',
386364
'addRunDependency',
387365
'removeRunDependency',
388366
];
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
'setValue' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS.
1+
'setValue' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)

tests/fs/test_lz4fs.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ int main() {
147147
console.log('seeing compressed size of ' + compressedSize + ', expect in ' + [low, high]);
148148
assert(compressedSize > low && compressedSize < high); // more than 1/3, because 1/3 is uncompressible, but still, less than 1/2
149149

150-
Module['ccall']('finish');
150+
ccall('finish');
151151
}
152152

153153
var meta_xhr = new XMLHttpRequest();

0 commit comments

Comments
 (0)