Skip to content

Commit

Permalink
embind: Better support memory64 for TS generation (emscripten-core#20568
Browse files Browse the repository at this point in the history
)

* fix: enable flags needed to run tsgen js based on settings

* fix: add missing mappings for longs & unsigned longs

* style: use shared helper to get nodejs memory64 flags

* fix: map longs to bigints if memory64 is enabled

* test: update normal test case w/ long values

* test: add test case for memory64 longs ts bindings

* chore: disable wasm exceptions when generating ts typings

* docs: explain new behavior in docs

* docs: add missing or
  • Loading branch information
Dabolus authored Nov 20, 2023
1 parent c46987e commit d1c731c
Show file tree
Hide file tree
Showing 8 changed files with 42 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -909,17 +909,17 @@ Out of the box, *embind* provides converters for many standard C++ types:
+---------------------+--------------------------------------------------------------------+
| ``unsigned int`` | Number |
+---------------------+--------------------------------------------------------------------+
| ``long`` | Number |
| ``long`` | Number, or BigInt* |
+---------------------+--------------------------------------------------------------------+
| ``unsigned long`` | Number |
| ``unsigned long`` | Number, or BigInt* |
+---------------------+--------------------------------------------------------------------+
| ``float`` | Number |
+---------------------+--------------------------------------------------------------------+
| ``double`` | Number |
+---------------------+--------------------------------------------------------------------+
| ``int64_t`` | BigInt* |
| ``int64_t`` | BigInt** |
+---------------------+--------------------------------------------------------------------+
| ``uint64_t`` | BigInt* |
| ``uint64_t`` | BigInt** |
+---------------------+--------------------------------------------------------------------+
| ``std::string`` | ArrayBuffer, Uint8Array, Uint8ClampedArray, Int8Array, or String |
+---------------------+--------------------------------------------------------------------+
Expand All @@ -928,7 +928,9 @@ Out of the box, *embind* provides converters for many standard C++ types:
| ``emscripten::val`` | anything |
+---------------------+--------------------------------------------------------------------+

\*Requires BigInt support to be enabled with the `-sWASM_BIGINT` flag.
\*BigInt when MEMORY64 is used, Number otherwise.

\*\*Requires BigInt support to be enabled with the `-sWASM_BIGINT` flag.

For convenience, *embind* provides factory functions to register
``std::vector<T>`` (:cpp:func:`register_vector`) and ``std::map<K, V>``
Expand Down
4 changes: 4 additions & 0 deletions src/embind/embind_ts.js
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,10 @@ var LibraryEmbind = {
['bool', 'boolean'],
['float', 'number'],
['double', 'number'],
#if MEMORY64
['long', 'bigint'],
['unsigned long', 'bigint'],
#endif
#if WASM_BIGINT
['int64_t', 'bigint'],
['uint64_t', 'bigint'],
Expand Down
3 changes: 3 additions & 0 deletions test/other/embind_tsgen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class Test {
int function_three(const std::string&) { return 1; }
int function_four(bool x) { return 2; }

long long_fn(unsigned long a) { return 3; }

int const_fn() const { return 0; }

int getX() const { return x; }
Expand Down Expand Up @@ -101,6 +103,7 @@ EMSCRIPTEN_BINDINGS(Test) {
.function("functionFour", &Test::function_four)
.function("functionFive(x, y)", &Test::function_one)
.function("functionSix(str)", &Test::function_three)
.function("longFn", &Test::long_fn)
.function("constFn", &Test::const_fn)
.property("x", &Test::getX, &Test::setX)
.property("y", &Test::getY)
Expand Down
1 change: 1 addition & 0 deletions test/other/embind_tsgen.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface Test {
functionFour(_0: boolean): number;
functionFive(x: number, y: number): number;
constFn(): number;
longFn(_0: number): number;
functionThree(_0: ArrayBuffer|Uint8Array|Uint8ClampedArray|Int8Array|string): number;
functionSix(str: ArrayBuffer|Uint8Array|Uint8ClampedArray|Int8Array|string): number;
delete(): void;
Expand Down
10 changes: 10 additions & 0 deletions test/other/embind_tsgen_memory64.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include <emscripten/bind.h>
#include <emscripten/val.h>

using namespace emscripten;

long long_fn(unsigned long) { return 0; }

EMSCRIPTEN_BINDINGS(Test) {
function("longFn", &long_fn);
}
3 changes: 3 additions & 0 deletions test/other/embind_tsgen_memory64.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface MainModule {
longFn(_0: bigint): bigint;
}
6 changes: 6 additions & 0 deletions test/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -3047,6 +3047,12 @@ def test_embind_tsgen_bigint(self):
self.run_process(args + ['-sWASM_BIGINT'])
self.assertFileContents(test_file('other/embind_tsgen_bigint.d.ts'), read_file('embind_tsgen_bigint.d.ts'))

def test_embind_tsgen_memory64(self):
# Check that when memory64 is enabled longs & unsigned longs are mapped to bigint in the generated TS bindings
self.run_process([EMCC, test_file('other/embind_tsgen_memory64.cpp'),
'-lembind', '--embind-emit-tsd', 'embind_tsgen_memory64.d.ts', '-sMEMORY64'])
self.assertFileContents(test_file('other/embind_tsgen_memory64.d.ts'), read_file('embind_tsgen_memory64.d.ts'))

def test_emconfig(self):
output = self.run_process([emconfig, 'LLVM_ROOT'], stdout=PIPE).stdout.strip()
self.assertEqual(output, config.LLVM_ROOT)
Expand Down
9 changes: 8 additions & 1 deletion tools/link.py
Original file line number Diff line number Diff line change
Expand Up @@ -1938,6 +1938,8 @@ def phase_embind_emit_tsd(options, wasm_target, js_syms):
setup_environment_settings()
# Use a separate Wasm file so the JS does not need to be modified after emscripten.run.
settings.SINGLE_FILE = False
# Disable support for wasm exceptions
settings.WASM_EXCEPTIONS = False
# Embind may be included multiple times, de-duplicate the list first.
settings.JS_LIBRARIES = dedup_list(settings.JS_LIBRARIES)
# Replace embind with the TypeScript generation version.
Expand All @@ -1947,7 +1949,12 @@ def phase_embind_emit_tsd(options, wasm_target, js_syms):
# The Wasm outfile may be modified by emscripten.run, so use a temporary file.
outfile_wasm = in_temp('tsgen_a.out.wasm')
emscripten.run(wasm_target, outfile_wasm, outfile_js, js_syms, False)
out = shared.run_js_tool(outfile_js, [], stdout=PIPE)
# Build the flags needed by Node.js to properly run the output file.
node_args = []
if settings.MEMORY64:
node_args += shared.node_memory64_flags()
# Run the generated JS file with the proper flags to generate the TypeScript bindings.
out = shared.run_js_tool(outfile_js, [], node_args, stdout=PIPE)
write_file(
os.path.join(os.path.dirname(wasm_target), options.embind_emit_tsd), out)
settings.restore(original_settings)
Expand Down

0 comments on commit d1c731c

Please sign in to comment.