-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add option to emit TypeScript definitions for Wasm module exports. #21279
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,8 @@ | ||
// TypeScript bindings for emscripten-generated code. Automatically generated at compile time. | ||
interface WasmModule { | ||
_main(_0: number, _1: number): number; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As a followup we could try to give better name here perhaps? Maybe for well known functions like |
||
} | ||
|
||
export interface Test { | ||
x: number; | ||
readonly y: number; | ||
|
@@ -69,7 +74,7 @@ export interface DerivedClass extends BaseClass { | |
|
||
export type ValArr = [ number, number, number ]; | ||
|
||
export interface MainModule { | ||
interface EmbindModule { | ||
Test: {staticFunction(_0: number): number; staticFunctionWithParam(x: number): number; staticProperty: number}; | ||
class_returning_fn(): Test; | ||
class_unique_ptr_returning_fn(): Test; | ||
|
@@ -95,3 +100,4 @@ export interface MainModule { | |
string_test(_0: ArrayBuffer|Uint8Array|Uint8ClampedArray|Int8Array|string): string; | ||
wstring_test(_0: string): string; | ||
} | ||
export type MainModule = WasmModule & EmbindModule; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,8 @@ | ||
export interface MainModule { | ||
// TypeScript bindings for emscripten-generated code. Automatically generated at compile time. | ||
interface WasmModule { | ||
} | ||
|
||
interface EmbindModule { | ||
bigintFn(_0: bigint): bigint; | ||
} | ||
export type MainModule = WasmModule & EmbindModule; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
// TypeScript bindings for emscripten-generated code. Automatically generated at compile time. | ||
interface WasmModule { | ||
_pthread_self(): number; | ||
_main(_0: number, _1: number): number; | ||
__emscripten_tls_init(): number; | ||
__emscripten_proxy_main(_0: number, _1: number): number; | ||
__embind_initialize_bindings(): void; | ||
__emscripten_thread_init(_0: number, _1: number, _2: number, _3: number, _4: number, _5: number): void; | ||
__emscripten_thread_crashed(): void; | ||
__emscripten_thread_exit(_0: number): void; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Kind of cool to see these like this. I think it might be good if we could ensure that the |
||
} | ||
|
||
export interface Test { | ||
x: number; | ||
readonly y: number; | ||
functionOne(_0: number, _1: number): number; | ||
functionTwo(_0: number, _1: number): number; | ||
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; | ||
} | ||
|
||
export interface BarValue<T extends number> { | ||
value: T; | ||
} | ||
export type Bar = BarValue<0>|BarValue<1>|BarValue<2>; | ||
|
||
export interface EmptyEnumValue<T extends number> { | ||
value: T; | ||
} | ||
export type EmptyEnum = never/* Empty Enumerator */; | ||
|
||
export type ValArrIx = [ Bar, Bar, Bar, Bar ]; | ||
|
||
export interface IntVec { | ||
push_back(_0: number): void; | ||
resize(_0: number, _1: number): void; | ||
size(): number; | ||
set(_0: number, _1: number): boolean; | ||
get(_0: number): any; | ||
delete(): void; | ||
} | ||
|
||
export interface Foo { | ||
process(_0: Test): void; | ||
delete(): void; | ||
} | ||
|
||
export type ValObj = { | ||
foo: Foo, | ||
bar: Bar | ||
}; | ||
|
||
export interface ClassWithConstructor { | ||
fn(_0: number): number; | ||
delete(): void; | ||
} | ||
|
||
export interface ClassWithTwoConstructors { | ||
delete(): void; | ||
} | ||
|
||
export interface ClassWithSmartPtrConstructor { | ||
fn(_0: number): number; | ||
delete(): void; | ||
} | ||
|
||
export interface BaseClass { | ||
fn(_0: number): number; | ||
delete(): void; | ||
} | ||
|
||
export interface DerivedClass extends BaseClass { | ||
fn2(_0: number): number; | ||
delete(): void; | ||
} | ||
|
||
export type ValArr = [ number, number, number ]; | ||
|
||
interface EmbindModule { | ||
Test: {staticFunction(_0: number): number; staticFunctionWithParam(x: number): number; staticProperty: number}; | ||
class_returning_fn(): Test; | ||
class_unique_ptr_returning_fn(): Test; | ||
a_class_instance: Test; | ||
an_enum: Bar; | ||
Bar: {valueOne: BarValue<0>, valueTwo: BarValue<1>, valueThree: BarValue<2>}; | ||
EmptyEnum: {}; | ||
enum_returning_fn(): Bar; | ||
IntVec: {new(): IntVec}; | ||
Foo: {}; | ||
ClassWithConstructor: {new(_0: number, _1: ValArr): ClassWithConstructor}; | ||
ClassWithTwoConstructors: {new(): ClassWithTwoConstructors; new(_0: number): ClassWithTwoConstructors}; | ||
ClassWithSmartPtrConstructor: {new(_0: number, _1: ValArr): ClassWithSmartPtrConstructor}; | ||
BaseClass: {}; | ||
DerivedClass: {}; | ||
a_bool: boolean; | ||
an_int: number; | ||
global_fn(_0: number, _1: number): number; | ||
optional_test(_0: Foo | undefined): number | undefined; | ||
smart_ptr_function(_0: ClassWithSmartPtrConstructor): number; | ||
smart_ptr_function_with_params(foo: ClassWithSmartPtrConstructor): number; | ||
function_with_callback_param(_0: (message: string) => void): number; | ||
string_test(_0: ArrayBuffer|Uint8Array|Uint8ClampedArray|Int8Array|string): string; | ||
wstring_test(_0: string): string; | ||
} | ||
export type MainModule = WasmModule & EmbindModule; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
// TypeScript bindings for emscripten-generated code. Automatically generated at compile time. | ||
interface WasmModule { | ||
} | ||
|
||
export interface Test { | ||
x: number; | ||
readonly y: number; | ||
functionOne(_0: number, _1: number): number; | ||
functionTwo(_0: number, _1: number): number; | ||
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; | ||
} | ||
|
||
export interface BarValue<T extends number> { | ||
value: T; | ||
} | ||
export type Bar = BarValue<0>|BarValue<1>|BarValue<2>; | ||
|
||
export interface EmptyEnumValue<T extends number> { | ||
value: T; | ||
} | ||
export type EmptyEnum = never/* Empty Enumerator */; | ||
|
||
export type ValArrIx = [ Bar, Bar, Bar, Bar ]; | ||
|
||
export interface IntVec { | ||
push_back(_0: number): void; | ||
resize(_0: number, _1: number): void; | ||
size(): number; | ||
set(_0: number, _1: number): boolean; | ||
get(_0: number): any; | ||
delete(): void; | ||
} | ||
|
||
export interface Foo { | ||
process(_0: Test): void; | ||
delete(): void; | ||
} | ||
|
||
export type ValObj = { | ||
foo: Foo, | ||
bar: Bar | ||
}; | ||
|
||
export interface ClassWithConstructor { | ||
fn(_0: number): number; | ||
delete(): void; | ||
} | ||
|
||
export interface ClassWithTwoConstructors { | ||
delete(): void; | ||
} | ||
|
||
export interface ClassWithSmartPtrConstructor { | ||
fn(_0: number): number; | ||
delete(): void; | ||
} | ||
|
||
export interface BaseClass { | ||
fn(_0: number): number; | ||
delete(): void; | ||
} | ||
|
||
export interface DerivedClass extends BaseClass { | ||
fn2(_0: number): number; | ||
delete(): void; | ||
} | ||
|
||
export type ValArr = [ number, number, number ]; | ||
|
||
interface EmbindModule { | ||
Test: {staticFunction(_0: number): number; staticFunctionWithParam(x: number): number; staticProperty: number}; | ||
class_returning_fn(): Test; | ||
class_unique_ptr_returning_fn(): Test; | ||
a_class_instance: Test; | ||
an_enum: Bar; | ||
Bar: {valueOne: BarValue<0>, valueTwo: BarValue<1>, valueThree: BarValue<2>}; | ||
EmptyEnum: {}; | ||
enum_returning_fn(): Bar; | ||
IntVec: {new(): IntVec}; | ||
Foo: {}; | ||
ClassWithConstructor: {new(_0: number, _1: ValArr): ClassWithConstructor}; | ||
ClassWithTwoConstructors: {new(): ClassWithTwoConstructors; new(_0: number): ClassWithTwoConstructors}; | ||
ClassWithSmartPtrConstructor: {new(_0: number, _1: ValArr): ClassWithSmartPtrConstructor}; | ||
BaseClass: {}; | ||
DerivedClass: {}; | ||
a_bool: boolean; | ||
an_int: number; | ||
global_fn(_0: number, _1: number): number; | ||
optional_test(_0: Foo | undefined): number | undefined; | ||
smart_ptr_function(_0: ClassWithSmartPtrConstructor): number; | ||
smart_ptr_function_with_params(foo: ClassWithSmartPtrConstructor): number; | ||
function_with_callback_param(_0: (message: string) => void): number; | ||
string_test(_0: ArrayBuffer|Uint8Array|Uint8ClampedArray|Int8Array|string): string; | ||
wstring_test(_0: string): string; | ||
} | ||
export type MainModule = WasmModule & EmbindModule; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,8 @@ | ||
export interface MainModule { | ||
// TypeScript bindings for emscripten-generated code. Automatically generated at compile time. | ||
interface WasmModule { | ||
} | ||
|
||
interface EmbindModule { | ||
longFn(_0: bigint): bigint; | ||
} | ||
export type MainModule = WasmModule & EmbindModule; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
#include <emscripten.h> | ||
|
||
EMSCRIPTEN_KEEPALIVE void fooVoid() {} | ||
EMSCRIPTEN_KEEPALIVE int fooInt(int a, int b) { | ||
return 42; | ||
} | ||
|
||
int main() { | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
// TypeScript bindings for emscripten-generated code. Automatically generated at compile time. | ||
interface WasmModule { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about adding a comment to the of this file? Something like |
||
_fooVoid(): void; | ||
_fooInt(_0: number, _1: number): number; | ||
_main(_0: number, _1: number): number; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks great! |
||
|
||
export type MainModule = WasmModule; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where does There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure if you mean where the name comes from our where it's defined. MainModule is defined here, it's basically an alias to WasmModule. The name is what embind previously used, so I'm sticking with that for now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair enough for now. I'm not sure why we need alias though.. why not just call it |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3083,14 +3083,14 @@ def test_embind_tsgen_ignore(self): | |
'-lembind', # Test duplicated link option. | ||
] | ||
self.emcc(test_file('other/embind_tsgen.cpp'), extra_args) | ||
self.assertFileContents(test_file('other/embind_tsgen.d.ts'), read_file('embind_tsgen.d.ts')) | ||
self.assertFileContents(test_file('other/embind_tsgen_ignore_1.d.ts'), read_file('embind_tsgen.d.ts')) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What rename these? How do they differ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They have different options enabled which changes the output of the wasm module exports. |
||
# Test these args separately since they conflict with arguments in the first test. | ||
extra_args = ['-sMODULARIZE', | ||
'--embed-file', 'fail.js', | ||
'-sMINIMAL_RUNTIME=2', | ||
'-sEXPORT_ES6=1'] | ||
self.emcc(test_file('other/embind_tsgen.cpp'), extra_args) | ||
self.assertFileContents(test_file('other/embind_tsgen.d.ts'), read_file('embind_tsgen.d.ts')) | ||
self.assertFileContents(test_file('other/embind_tsgen_ignore_2.d.ts'), read_file('embind_tsgen.d.ts')) | ||
|
||
def test_embind_tsgen_test_embind(self): | ||
self.run_process([EMCC, test_file('embind/embind_test.cpp'), | ||
|
@@ -3136,6 +3136,12 @@ def test_embind_jsgen_method_pointer_stability(self): | |
# AOT JS generation still works correctly. | ||
self.do_runf('other/embind_jsgen_method_pointer_stability.cpp', 'done') | ||
|
||
def test_emit_tsd(self): | ||
self.run_process([EMCC, test_file('other/test_emit_tsd.c'), | ||
'--emit-tsd', 'test_emit_tsd.d.ts', '-Wno-experimental'] + | ||
self.get_emcc_args()) | ||
self.assertFileContents(test_file('other/test_emit_tsd.d.ts'), read_file('test_emit_tsd.d.ts')) | ||
|
||
def test_emconfig(self): | ||
output = self.run_process([emconfig, 'LLVM_ROOT'], stdout=PIPE).stdout.strip() | ||
self.assertEqual(output, config.LLVM_ROOT) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't added docs for this yet. I'd like to do a little more work on it before we advertise it, but if the reviewer prefers I can add them now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In that case it might be worth marking it as experimental by doing something like we do for wasm64:
diagnostics.warning('experimental', '-sMEMORY64 is still experimental. Many features may not work.')