blob: e8d26e1618087525159f959e75f29791dc809e7b [file]
# Copyright 2025 The Emscripten Authors. All rights reserved.
# Emscripten is available under two separate licenses, the MIT license and the
# University of Illinois/NCSA Open Source License. Both these licenses can be
# found in the LICENSE file.
from subprocess import PIPE
from common import RunnerCore, copy_asset, create_file, read_file, test_file
from decorators import also_with_wasm64, also_without_bigint, parameterized
from tools.shared import EMCC
from tools.utils import delete_file
class jslib(RunnerCore):
def test_jslib_no_override(self):
create_file('duplicated_func.c', '''
#include <stdio.h>
extern int duplicatedFunc();
int main() {
int res = duplicatedFunc();
printf("*%d*\\n", res);
return 0;
}
''')
create_file('duplicated_func_1.js', '''
addToLibrary(
{ duplicatedFunc: () => 1 },
{ noOverride: true }
);
''')
create_file('duplicated_func_2.js', '''
addToLibrary(
{ duplicatedFunc: () => 2 },
{ noOverride: true }
);
''')
self.cflags += ['--js-library', 'duplicated_func_1.js', '--js-library', 'duplicated_func_2.js']
self.assert_fail([EMCC, 'duplicated_func.c'] + self.get_cflags(),
'duplicated_func_2.js: Symbol re-definition in JavaScript library: duplicatedFunc. Do not use noOverride if this is intended')
def test_jslib_missing_sig(self):
create_file('some_func.c', '''
#include <stdio.h>
extern int someFunc();
int main() {
int res = someFunc();
printf("*%d*\\n", res);
return 0;
}
''')
create_file('some_func.js', '''
addToLibrary(
{ someFunc: () => 1 },
{ checkSig: true }
);
''')
self.cflags += ['--js-library', 'some_func.js']
self.assert_fail([EMCC, 'some_func.c'] + self.get_cflags(),
'some_func.js: __sig is missing for function: someFunc. Do not use checkSig if this is intended')
def test_jslib_extra_args(self):
# Verify that extra arguments in addition to those listed in `__sig` are still present
# in the generated JS library function.
# See https://github.com/emscripten-core/emscripten/issues/21056
create_file('some_func.js', '''
addToLibrary({
someFunc: (arg1, arg2) => {
err('arg1:' + arg1);
err('arg2:' + arg2);
},
someFunc__sig: 'pp',
});
''')
create_file('test.c', '''
void someFunc(long p);
int main() {
someFunc(42);
}
''')
self.cflags += ['--js-library', 'some_func.js', '-sALLOW_MEMORY_GROWTH', '-sMAXIMUM_MEMORY=4Gb']
self.do_runf('test.c', 'arg1:42\narg2:undefined\n')
def test_jslib_quoted_key(self):
create_file('lib.js', r'''
addToLibrary({
__internal_data:{
'<' : 0,
'white space' : 1
},
foo__deps: ['__internal_data'],
foo: () => {
return 0;
}
});
''')
self.do_runf_out_file('hello_world.c', cflags=['--js-library', 'lib.js'])
def test_jslib_proxying(self):
# Regression test for a bug we had where jsifier would find and use
# the inner function in a library function consisting of a single
# line arrow function.
# See https://github.com/emscripten-core/emscripten/issues/20264
create_file('lib.js', r'''
addToLibrary({
$doNotCall: (x) => {},
foo__deps: ['$doNotCall'],
foo__proxy: 'sync',
foo: () => doNotCall(() => {
out('should never see this');
}),
});
''')
create_file('src.c', r'''
#include <stdio.h>
void foo();
int main() {
printf("main\n");
foo();
printf("done\n");
}
''')
self.do_runf('src.c', 'main\ndone\n', cflags=['-sEXIT_RUNTIME', '-pthread', '-sPROXY_TO_PTHREAD', '--js-library', 'lib.js'])
def test_jslib_method_syntax(self):
create_file('lib.js', r'''
addToLibrary({
foo() {
out('foo');
},
});
''')
create_file('src.c', r'''
#include <stdio.h>
void foo();
int main() {
foo();
}
''')
self.do_runf('src.c', 'foo', cflags=['--js-library', 'lib.js'])
def test_jslib_exported(self):
create_file('lib.js', r'''
addToLibrary({
jslibfunc: (x) => 2 * x
});
''')
create_file('src.c', r'''
#include <emscripten.h>
#include <stdio.h>
int jslibfunc(int x);
int main() {
printf("c calling: %d\n", jslibfunc(6));
EM_ASM({
out('js calling: ' + Module['_jslibfunc'](5) + '.');
});
}
''')
self.do_runf('src.c', 'c calling: 12\njs calling: 10.',
cflags=['--js-library', 'lib.js', '-sEXPORTED_FUNCTIONS=_main,_jslibfunc'])
def test_jslib_using_asm_lib(self):
create_file('lib.js', r'''
addToLibrary({
jslibfunc__deps: ['asmlibfunc'],
jslibfunc: (x) => 2 * _asmlibfunc(x),
asmlibfunc__asm: true,
asmlibfunc__sig: 'ii',
asmlibfunc: (x) => {
x = x | 0;
return x + 1 | 0;
}
});
''')
create_file('src.c', r'''
#include <stdio.h>
int jslibfunc(int x);
int main() {
printf("c calling: %d\n", jslibfunc(6));
}
''')
self.do_runf('src.c', 'c calling: 14\n', cflags=['--js-library', 'lib.js'])
def test_jslib_preprocessor_errors(self):
create_file('lib.js', '''\
// This is a library file
#endif // line 2
''')
self.assert_fail([EMCC, test_file('hello_world.c'), '--js-library', 'lib.js'], 'lib.js:2: #endif without matching #if')
create_file('lib.js', '''\
// This is a library file
#else // line 3
''')
self.assert_fail([EMCC, test_file('hello_world.c'), '--js-library', 'lib.js'], 'lib.js:3: #else without matching #if')
def test_jslib_internal_deps(self):
create_file('lib.js', r'''
addToLibrary({
jslibfunc__deps: ['$callRuntimeCallbacks'],
jslibfunc: (x) => {
callRuntimeCallbacks();
},
});
''')
create_file('src.c', r'''
#include <stdio.h>
int jslibfunc();
int main() {
printf("c calling: %d\n", jslibfunc());
}
''')
err = self.run_process([EMCC, 'src.c', '--js-library', 'lib.js'], stderr=PIPE).stderr
self.assertContained("warning: user library symbol 'jslibfunc' depends on internal symbol '$callRuntimeCallbacks'", err)
def test_jslib_sig_redefinition(self):
create_file('lib.js', r'''
addToLibrary({
jslibfunc__sig: 'ii',
jslibfunc: (x) => {},
});
addToLibrary({
jslibfunc__sig: 'ii',
jslibfunc: (x) => {},
});
''')
create_file('src.c', r'''
#include <stdio.h>
int jslibfunc();
int main() {
printf("c calling: %d\n", jslibfunc());
}
''')
err = self.run_process([EMCC, 'src.c', '--js-library', 'lib.js'], stderr=PIPE).stderr
self.assertContained('lib.js: signature redefinition for: jslibfunc__sig', err)
# Add another redefinition, this time not matching
create_file('lib2.js', r'''
addToLibrary({
jslibfunc__sig: 'pp',
jslibfunc: (x) => {},
});
''')
self.assert_fail([EMCC, 'src.c', '--js-library', 'lib.js', '--js-library', 'lib2.js'],
'lib2.js: signature redefinition for: jslibfunc__sig. (old=ii vs new=pp)')
def test_jslib_invalid_deps(self):
create_file('lib.js', r'''
addToLibrary({
jslibfunc__deps: 'hello',
jslibfunc: (x) => {},
});
''')
self.assert_fail([EMCC, test_file('hello_world.c'), '--js-library', 'lib.js'],
'lib.js: JS library directive jslibfunc__deps=hello is of type \'string\', but it should be an array')
create_file('lib2.js', r'''
addToLibrary({
jslibfunc__deps: [1,2,3],
jslibfunc: (x) => {},
});
''')
self.assert_fail([EMCC, test_file('hello_world.c'), '--js-library', 'lib2.js'],
"lib2.js: __deps entries must be of type 'string' or 'function' not 'number': jslibfunc__deps")
def test_jslib_invalid_decorator(self):
create_file('lib.js', r'''
addToLibrary({
jslibfunc__internal: 'hello',
jslibfunc: (x) => {},
});
''')
self.assert_fail([EMCC, test_file('hello_world.c'), '--js-library', 'lib.js'],
"lib.js: Decorator (jslibfunc__internal) has wrong type. Expected 'boolean' not 'string'")
@also_with_wasm64
@also_without_bigint
def test_jslib_i53abi(self):
create_file('lib.js', r'''
addToLibrary({
jslibfunc__i53abi: true,
jslibfunc__sig: 'j',
jslibfunc: (x) => { return 42 },
});
''')
create_file('test.c', r'''
#include <stdio.h>
int64_t jslibfunc();
int main() {
printf("main: %lld\n", jslibfunc());
}
''')
self.do_runf('test.c', 'main: 42\n', cflags=['--js-library', 'lib.js'])
def test_jslib_i53abi_errors(self):
create_file('lib.js', r'''
addToLibrary({
jslibfunc__i53abi: true,
jslibfunc: (x) => { return 42 },
});
''')
self.assert_fail([EMCC, test_file('hello_world.c'), '-sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=jslibfunc', '--js-library', 'lib.js'],
"error: JS library error: '__i53abi' decorator requires '__sig' decorator: 'jslibfunc'")
create_file('lib.js', r'''
addToLibrary({
jslibfunc__i53abi: true,
jslibfunc__sig: 'ii',
jslibfunc: (x) => { return 42 },
});
''')
self.assert_fail([EMCC, test_file('hello_world.c'), '-sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=jslibfunc', '--js-library', 'lib.js'],
"error: JS library error: '__i53abi' only makes sense when '__sig' includes 'j' (int64): 'jslibfunc'")
def test_jslib_invalid_proxy_mode(self):
create_file('lib.js', r'''
addToLibrary({
jslibfunc__proxy: 'foo',
jslibfunc: (x) => 42,
});
''')
self.assert_fail([EMCC, test_file('hello_world.c'), '-sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=jslibfunc', '--js-library', 'lib.js'],
"error: JS library error: invalid proxying mode 'jslibfunc__proxy: foo' specified")
def test_jslib_legacy(self):
# Test that the legacy `mergeInfo` function work instead of `addToLibrary`
create_file('lib.js', r'''
mergeInto(LibraryManager.library, {
jslibfunc: (x) => { return 42 },
});
''')
create_file('src.c', r'''
#include <stdio.h>
int jslibfunc();
int main() {
printf("main: %d\n", jslibfunc());
}
''')
self.do_runf('src.c', 'main: 42\n', cflags=['--js-library', 'lib.js'])
# Tests that users can pass custom JS options from command line using
# the -jsDfoo=val syntax:
# See https://github.com/emscripten-core/emscripten/issues/10580.
def test_jslib_custom_settings(self):
test_file_path = test_file('jslib/test_jslib_custom_settings.c')
js_lib = test_file('jslib/test_jslib_custom_settings.js')
self.do_runf(test_file_path, '1\n', cflags=['--js-library', js_lib, '-jsDCUSTOM_JS_OPTION=1'])
# verify that the settings can be specified more than once, and that the last one wins.
self.do_runf(test_file_path, '2\n', cflags=['--js-library', js_lib, '-jsDCUSTOM_JS_OPTION=1', '-jsDCUSTOM_JS_OPTION=2'])
self.assert_fail([EMCC, '-jsDWASM=1'], 'cannot change built-in settings values with a -jsD directive')
def test_jslib_native_deps(self):
# Verify that memset (which lives in compiled code), can be specified as a JS library
# dependency.
create_file('lib.js', r'''
addToLibrary({
depper__deps: ['memset'],
depper: (ptr) => {
_memset(ptr, 'd'.charCodeAt(0), 10);
},
});
''')
create_file('test.c', r'''
#include <stdio.h>
void depper(char*);
int main(int argc, char** argv) {
char buffer[11] = { 0 };
depper(buffer);
puts(buffer);
}
''')
self.do_runf('test.c', 'dddddddddd\n', cflags=['--js-library', 'lib.js'])
def test_jslib_native_deps_extra(self):
# Similar to above but the JS symbol is not used by the native code.
# Instead is it explicitly injected using `extraLibraryFuncs`.
create_file('lib.js', r'''
addToLibrary({
jsfunc__deps: ['raise'],
jsfunc: (ptr) => {
_raise(1);
},
});
extraLibraryFuncs.push('jsfunc');
''')
self.do_runf('hello_world.c', cflags=['--js-library', 'lib.js'])
def test_jslib_clobber_i(self):
# Regression check for an issue we have where a library clobbering the global `i` variable could
# prevent processing of further libraries.
create_file('lib1.js', 'for (var i = 0; i < 100; i++) {}')
create_file('lib2.js', '''
addToLibrary({
foo: () => {}
});
''')
self.run_process([EMCC, test_file('hello_world.c'),
'-sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=foo',
'--js-library=lib1.js',
'--js-library=lib2.js'])
def test_jslib_bad_config(self):
create_file('lib.js', '''
addToLibrary({
foo__sig: 'ii',
});
''')
self.assert_fail([EMCC, test_file('hello_world.c'), '--js-library=lib.js'], "lib.js: Missing library element 'foo' for library config 'foo__sig'")
def test_jslib_ifdef(self):
create_file('lib.js', '''
#ifdef ASSERTIONS
var foo;
#endif
''')
proc = self.run_process([EMCC, test_file('hello_world.c'), '--js-library=lib.js'], stderr=PIPE)
self.assertContained('lib.js: use of #ifdef in js library. Use #if instead.', proc.stderr)
def test_jslib_mangling(self):
create_file('lib.js', '''
addToLibrary({
$__foo: () => 43,
});
''')
self.run_process([EMCC, test_file('hello_world.c'), '--js-library=lib.js', '-sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=$__foo'])
def test_jslib_exported_functions(self):
create_file('lib.js', '''
addToLibrary({
$Foo: () => 43,
});
''')
create_file('post.js', 'console.log("Foo:", Module.Foo())')
self.do_runf('hello_world.c', cflags=['--post-js=post.js', '--js-library=lib.js', '-sEXPORTED_FUNCTIONS=Foo,_main'])
def test_jslib_search_path(self):
create_file('libfoo.js', '''
addToLibrary({
foo: () => 42,
});
''')
create_file('main.c', r'''
#include <stdio.h>
int foo();
int main() {
printf("%d\n", foo());
return 0;
}''')
self.do_runf('main.c', '42\n', cflags=['-L.', '-lfoo.js'])
# If the library path is not included with `-L` we expect the command to fail
self.assert_fail([EMCC, 'main.c', '-lfoo.js'], 'emcc: error: unable to find library -lfoo.js')
# Tests using the #warning directive in JS library files
def test_jslib_warnings(self):
copy_asset('warning_in_js_libraries.js')
proc = self.run_process([EMCC, test_file('hello_world.c'), '--js-library', 'warning_in_js_libraries.js'], stdout=PIPE, stderr=PIPE)
self.assertNotContained('This warning should not be present!', proc.stderr)
self.assertContained('warning: warning_in_js_libraries.js:5: #warning This is a warning string!', proc.stderr)
self.assertContained('warning: warning_in_js_libraries.js:7: #warning This is a second warning string!', proc.stderr)
self.assertContained('emcc: warning: warnings in JS library compilation [-Wjs-compiler]', proc.stderr)
err = self.expect_fail([EMCC, test_file('hello_world.c'), '--js-library', 'warning_in_js_libraries.js', '-Werror'])
self.assertNotContained('This warning should not be present!', err)
self.assertContained('warning: warning_in_js_libraries.js:5: #warning This is a warning string!', err)
self.assertContained('warning: warning_in_js_libraries.js:7: #warning This is a second warning string!', err)
self.assertContained('emcc: error: warnings in JS library compilation [-Wjs-compiler] [-Werror]', err)
# Tests using the #error directive in JS library files
def test_jslib_errors(self):
copy_asset('jslib/error_in_js_libraries.js')
err = self.expect_fail([EMCC, test_file('hello_world.c'), '--js-library', 'error_in_js_libraries.js'])
self.assertNotContained('This error should not be present!', err)
self.assertContained('error: error_in_js_libraries.js:5: #error This is an error string!', err)
self.assertContained('error: error_in_js_libraries.js:7: #error This is a second error string!', err)
def test_jslib_include(self):
create_file('inc.js', '''
let MY_VAR = 10;
''')
create_file('foo.js', '''
// Include a file from system directory
#include "IDBStore.js"
// Include a local file.
#include "inc.js"
''')
self.run_process([EMCC, test_file('hello_world.c'), '--js-library', 'foo.js'])
delete_file('inc.js')
self.assert_fail([EMCC, test_file('hello_world.c'), '--js-library', 'foo.js'], 'foo.js:5: file not found: inc.js')
@also_with_wasm64
@also_without_bigint
@parameterized({
'': ([],),
'closure': (['--closure=1'],),
})
def test_jslib_aliases(self, args):
create_file('foo.js', '''
addToLibrary({
foo: () => 42,
foo__sig: 'i',
foo_alias: 'foo',
foo_alias_i64: 'foo',
foo_alias_i64__sig: 'j',
foo_alias_i64__i53abi: true,
foo_alias_ptr: 'foo',
foo_alias_ptr__sig: 'p',
// Normal JS function that calls a native function
call_native__deps: ['native_func'],
call_native: () => _native_func(),
// JS function that calls nativeAlias
call_native_alias__deps: ['$nativeAlias'],
call_native_alias: () => nativeAlias(),
// This is a JS-only symbol (i.e. no leading underscore) that
// aliases a native symbol.
$nativeAlias__deps: ['native_func2'],
$nativeAlias: 'native_func2',
});
''')
create_file('main.c', r'''
#include <stdio.h>
#include <emscripten.h>
int foo();
int foo_alias();
void* foo_alias_ptr();
int64_t foo_alias_i64();
int call_native();
int call_native_alias();
int native_func() {
return 43;
}
int native_func2() {
return 44;
}
int main() {
printf("foo: %d\n", foo());
printf("foo_alias: %d\n", foo_alias());
printf("foo_alias_i64: %lld\n", foo_alias_i64());
printf("foo_alias_ptr: %p\n", foo_alias_ptr());
printf("call_native: %d\n", call_native());
printf("call_native_alias: %d\n", call_native_alias());
return 0;
}
''')
expected = '''\
foo: 42
foo_alias: 42
foo_alias_i64: 42
foo_alias_ptr: 0x2a
call_native: 43
call_native_alias: 44
'''
self.do_runf('main.c', expected, cflags=['--js-library', 'foo.js'] + args)
@parameterized({
'': ([],),
'closure': (['--closure=1'],),
})
def test_jslib_export_alias(self, args):
create_file('lib.js', '''
addToLibrary({
$foo: 'main',
$bar: '__indirect_function_table',
$baz: 'memory',
});
''')
create_file('extern_pre.js', r'''
Module = {
onRuntimeInitialized: () => {
const assert = require('assert');
console.log("onRuntimeInitialized");
console.log('foo:', typeof Module.foo)
console.log('bar:', typeof Module.bar)
console.log('baz:', typeof Module.baz)
assert(Module.foo instanceof Function);
assert(Module.bar instanceof WebAssembly.Table);
assert(Module.baz instanceof WebAssembly.Memory);
console.log('done');
}
};
''')
self.do_runf('hello_world.c', 'done\n', cflags=['--js-library=lib.js', '--extern-pre-js=extern_pre.js', '-sEXPORTED_RUNTIME_METHODS=foo,bar,baz'] + args)
def test_postjs_errors(self):
create_file('post.js', '#preprocess\n#error This is an error')
self.assert_fail([EMCC, test_file('hello_world.c'), '--post-js', 'post.js'], 'post.js:2: #error This is an error')
def test_jslib_has_library(self):
create_file('libfoo.js', '''
// libwasi.js should be included.
#if !LibraryManager.has('libwasi.js')
#error "oops 1"
#endif
// Checking for the legacy name should also work
#if !LibraryManager.has('library_wasi.js')
#error "oops 2"
#endif
#if LibraryManager.has('libbar.js')
#error "oops 3"
#endif
''')
self.do_runf('hello_world.c', cflags=['-L', '-lfoo.js'])
def test_jslib_new_objects_basic(self):
create_file('lib.js', '''
addToLibrary({
$obj: {
a: new Map(),
b: new Set(),
c: new WeakMap(),
d: new WeakSet()
}
});
''')
self.run_process([EMCC, test_file('hello_world.c'), '--js-library=lib.js', '-sEXPORTED_FUNCTIONS=obj,_main'])
self.assertContained("a:new Map,", read_file('a.out.js'))
self.assertContained("b:new Set,", read_file('a.out.js'))
self.assertContained("c:new WeakMap,", read_file('a.out.js'))
self.assertContained("d:new WeakSet,", read_file('a.out.js'))
def test_jslib_new_objects_non_empty(self):
create_file('lib.js', '''
addToLibrary({
$obj: {
bad: new Map([[1,2],[3,4]])
}
});
''')
self.assert_fail([EMCC, test_file('hello_world.c'), '--js-library=lib.js', '-sEXPORTED_FUNCTIONS=obj,_main'], 'cannot stringify Map with data')
def test_jslib_system_lib_name(self):
create_file('libcore.js', r'''
addToLibrary({
jslibfunc: (x) => 2 * x
});
''')
create_file('src.c', r'''
#include <emscripten.h>
#include <stdio.h>
int jslibfunc(int x);
int main() {
printf("jslibfunc: %d\n", jslibfunc(6));
return 0;
}
''')
self.do_runf('src.c', 'jslibfunc: 12', cflags=['--js-library', 'libcore.js'])
def test_jslib_preprocess(self):
# Use stderr rather than stdout here because stdout is redirected to the output JS file itself.
create_file('lib.js', '''
#if MAIN_MODULE == 1
console.error('JSLIB: MAIN_MODULE=1');
#elif MAIN_MODULE == 2
console.error('JSLIB: MAIN_MODULE=2');
#elif EXIT_RUNTIME
console.error('JSLIB: EXIT_RUNTIME');
#else
console.error('JSLIB: none of the above');
#endif
''')
err = self.run_process([EMCC, test_file('hello_world.c'), '--js-library', 'lib.js'], stderr=PIPE).stderr
self.assertContained('JSLIB: none of the above', err)
self.assertNotContained('JSLIB: MAIN_MODULE', err)
self.assertNotContained('JSLIB: EXIT_RUNTIME', err)
err = self.run_process([EMCC, test_file('hello_world.c'), '--js-library', 'lib.js', '-sMAIN_MODULE'], stderr=PIPE).stderr
self.assertContained('JSLIB: MAIN_MODULE=1', err)
self.assertNotContained('JSLIB: EXIT_RUNTIME', err)
err = self.run_process([EMCC, test_file('hello_world.c'), '--js-library', 'lib.js', '-sMAIN_MODULE=2'], stderr=PIPE).stderr
self.assertContained('JSLIB: MAIN_MODULE=2', err)
self.assertNotContained('JSLIB: EXIT_RUNTIME', err)
err = self.run_process([EMCC, test_file('hello_world.c'), '--js-library', 'lib.js', '-sEXIT_RUNTIME'], stderr=PIPE).stderr
self.assertContained('JSLIB: EXIT_RUNTIME', err)
self.assertNotContained('JSLIB: MAIN_MODULE', err)
# Tests that it is possible to hook into/override a symbol defined in a system library.
def test_jslib_override_system_symbol(self):
# This test verifies it is possible to override a symbol from WebGL library.
# When WebGL is implicitly linked in, the implicit linking should happen before any user
# --js-libraries, so that they can adjust the behavior afterwards.
self.do_runf_out_file('jslib/test_jslib_override_system_symbol.c', cflags=['--js-library', test_file('jslib/test_jslib_override_system_symbol.js'), '-sMAX_WEBGL_VERSION=2'])
# When WebGL is explicitly linked to in strict mode, the linking order on command line should enable overriding.
self.cflags += ['-sAUTO_JS_LIBRARIES=0', '-sMAX_WEBGL_VERSION=2', '-lwebgl.js', '--js-library', test_file('jslib/test_jslib_override_system_symbol.js')]
self.do_runf_out_file('jslib/test_jslib_override_system_symbol.c')
def test_jslib_version_check(self):
create_file('libfoo.js', '''
#if parseInt(EMSCRIPTEN_VERSION.split('.')[0]) > 3
#error "library does not support emscripten > 3.0.0"
#endif
''')
self.assert_fail([EMCC, '--js-library=libfoo.js'], 'error: libfoo.js:3: #error "library does not support emscripten > 3.0.0"')
def test_jslib_named_class(self):
create_file('lib.js', r'''
class ParentClass {}
addToLibrary({
$ParentClass: ParentClass,
$MyClass__deps: ['$ParentClass'],
$MyClass: class extends ParentClass {
constructor() { super(); this.x = 42; }
},
log_class__deps: ['$MyClass'],
log_class: () => {
var i = new MyClass();
out('MyClass: ' + i.x);
}
});
''')
create_file('src.c', r'''
#include <stdio.h>
#include <emscripten.h>
extern void log_class();
int main() {
log_class();
return 0;
}
''')
self.do_runf('src.c', 'MyClass: 42', cflags=['--js-library', 'lib.js'])
# Tests that JS library functions containing multiline strings are not disturbed by e.g. inserting indentation into the output.
@parameterized({
'': ([],),
'single_file': (['-sSINGLE_FILE'],),
'closure': (['--closure', '1'],),
})
def test_multiline_string(self, args):
self.do_runf_out_file('jslib/test_multiline_string.c', cflags=['--js-library', test_file('jslib/test_multiline_string.js')] + args)
def test_export(self):
create_file('post.js', 'Module.myFunc();')
self.do_runf('hello_world.c', 'myFunc included\nmyFunc called\n', cflags=['--js-library', test_file('jslib/test_export.js'), '--extern-post-js=post.js'])