Skip to content

Commit a5f3599

Browse files
authored
Allow user JS libraries to be specified via -lfoo.js (#23345)
We already allowed this for system JS libraries but it is now also possible for user libraries. Fixes: #23338
1 parent 8abb175 commit a5f3599

File tree

7 files changed

+39
-7
lines changed

7 files changed

+39
-7
lines changed

ChangeLog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ See docs/process.md for more on how version tagging works.
5858
- The `POLYFILL_OLD_MATH_FUNCTIONS` setting was removed. The browser versions
5959
that require these polyfills are no longer supported by emscripten so the
6060
polyfills should never be needed. (#23262)
61+
- JavaScript libraries can now be specified via `-lfoo.js`. This works like the
62+
existing `--js-library` flag but will search the library path (all paths
63+
specified with `-L`) for `libfoo.js`. (#23338)
6164

6265
3.1.74 - 12/14/24
6366
-----------------

site/source/docs/tools_reference/settings_reference.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1417,7 +1417,7 @@ A list of imported module functions that will potentially do asynchronous
14171417
work. The imported function should return a ``Promise`` when doing
14181418
asynchronous work.
14191419

1420-
Note when using ``--js-library``, the function can be marked with
1420+
Note when using JS library files, the function can be marked with
14211421
``<function_name>_async:: true`` in the library instead of this setting.
14221422

14231423
Default value: []

src/modules.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ export const LibraryManager = {
205205
libraries.push('library_little_endian_heap.js');
206206
}
207207

208-
// Add all user specified --js-library files to the link.
208+
// Add all user specified JS library files to the link.
209209
// These must be added last after all Emscripten-provided system libraries
210210
// above, so that users can override built-in JS library symbols in their
211211
// own code.

src/settings.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -953,7 +953,7 @@ var JSPI_EXPORTS = [];
953953
// work. The imported function should return a ``Promise`` when doing
954954
// asynchronous work.
955955
//
956-
// Note when using ``--js-library``, the function can be marked with
956+
// Note when using JS library files, the function can be marked with
957957
// ``<function_name>_async:: true`` in the library instead of this setting.
958958
// [link]
959959
var JSPI_IMPORTS = [];

src/settings_internal.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,9 @@ var MAIN_READS_PARAMS = true;
9797

9898
var WASI_MODULE_NAME = "wasi_snapshot_preview1";
9999

100-
// List of JS libraries explicitly linked against. This includes JS system
101-
// libraries (specified via -lfoo or -lfoo.js) in addition to user libraries
102-
// passed via `--js-library`. It does not include implicitly linked libraries
103-
// added by the JS compiler.
100+
// List of JS libraries explicitly linked against. This includes JS specified
101+
// on the command line via `-lfoo.js` / `--js-library`. It does not include
102+
// implicitly linked libraries added by the JS compiler.
104103
var JS_LIBRARIES = [];
105104

106105
// This will contain the emscripten version. This can be useful in combination

test/test_other.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4886,6 +4886,25 @@ def test_jslib_exported_functions(self):
48864886
self.run_process([EMCC, test_file('hello_world.c'), '--js-library=lib.js', '-sEXPORTED_FUNCTIONS=Foo,_main'])
48874887
self.assertContained("Module['Foo'] = ", read_file('a.out.js'))
48884888

4889+
def test_jslib_search_path(self):
4890+
create_file('libfoo.js', '''
4891+
addToLibrary({
4892+
foo: () => 42,
4893+
});
4894+
''')
4895+
create_file('main.c', r'''
4896+
#include <stdio.h>
4897+
int foo();
4898+
int main() {
4899+
printf("%d\n", foo());
4900+
return 0;
4901+
}''')
4902+
self.do_runf('main.c', '42\n', emcc_args=['-L.', '-lfoo.js'])
4903+
4904+
# If the library path is not included with `-L` we expect the command to fail
4905+
err = self.expect_fail([EMCC, 'main.c', '-lfoo.js'])
4906+
self.assertContained('emcc: error: unable to find library -lfoo.js', err)
4907+
48894908
def test_EMCC_BUILD_DIR(self):
48904909
# EMCC_BUILD_DIR env var contains the dir we were building in, when running the js compiler (e.g. when
48914910
# running a js library). We force the cwd to be src/ for technical reasons, so this lets you find out

tools/link.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2804,6 +2804,9 @@ def map_to_js_libs(library_name):
28042804
logger.debug('Mapping library `%s` to JS libraries: %s' % (library_name, libs))
28052805
return libs
28062806

2807+
# TODO(sbc): Remove this special handling for system libraries by renaming
2808+
# the system libraries from `library_foo.js` to `libfoo.js` (the latter is
2809+
# the more standard name by which `-l` flags resolve libraries).
28072810
if library_name.endswith('.js') and os.path.isfile(utils.path_from_root('src', f'library_{library_name}')):
28082811
return [f'library_{library_name}']
28092812

@@ -2842,6 +2845,14 @@ def process_libraries(state):
28422845
if js_libs is not None:
28432846
continue
28442847

2848+
if lib.endswith('.js'):
2849+
name = 'lib' + lib
2850+
path = find_library(name, state.lib_dirs)
2851+
if not path:
2852+
exit_with_error(f'unable to find library {flag}')
2853+
settings.JS_LIBRARIES.append(os.path.abspath(path))
2854+
continue
2855+
28452856
if not settings.RELOCATABLE:
28462857
# Normally we can rely on the native linker to expand `-l` args.
28472858
# However, emscripten also supports `.so` files that are actually just

0 commit comments

Comments
 (0)