emscripten_wrapper v2.1.0
Emscripten Wrapper
This is a helper repository to wrap an Emscripten generated module such that it is easier useable.
Installation
npm install emscripten_wrapper
npm install github:sgratzl/emscripten_wrapperPrerequisites
In order to work the Emscripten module has to be compiled with at least the following flags
-s FORCE_FILESYSTEM=1 -s MODULARIZE=1 -s EXTRA_EXPORTED_RUNTIME_METHODS="['cwrap', 'FS', 'ENV']"e.g.
emcc helloworld.cpp -s FORCE_FILESYSTEM=1 -s MODULARIZE=1 -s EXTRA_EXPORTED_RUNTIME_METHODS="['cwrap', 'FS', 'ENV']" -o helloworld.jsThis ensures that the FileSystem (FS) and crwap (to call custom functions) are available while also enforcing that emcc outputs a module.
!!!Important
the file_packager.py file that is currently used (e.g. when using --preload_file), doesn't work in node environments by default. There is a patch file included in this repo file_packager_patch.js that fixes this issue. However, since it has to be applied before the code of the file_packager.py, one need to manually bundle the files.
such as
python /emsdk_portable/sdk/tools/file_packager.py helloworld.data --preload ./share --from-emcc --js-output=file_packager.js
emcc helloworld.cpp --pre-js file_packager_patch.js --pre-js file_packager.js -s FORCE_FILESYSTEM=1 -s MODULARIZE=1 -s EXTRA_EXPORTED_RUNTIME_METHODS="['cwrap', 'FS', 'ENV']" -o helloworld.jsUsage
import createWrapper from 'emscripten_wrapper';
const wrapper = createWrapper(() => import('./helloworld.js'), {
functions: {
add_values: { returnType: 'number', arguments: ['number', 'number']}
}
});
export default wrapper;TypeScript
import createWrapper, {IAsyncEMWMainWrapper} from 'emscripten_wrapper';
export interface IHelloWorldFunctions {
add_values(a: number, b: number): number;
}
export interface IHelloWorldModule extends IAsyncEMWMainWrapper<IHelloWorldFunctions> {
}
const wrapper: IHelloWorldModule = createWrapper<IHelloWorldFunctions>(() => import('./helloworld'), {
functions: {
add_values: {
arguments: ['number', 'number'],
returnType: 'number'
}
}
});
export default wrapper;you also need to define a helloworld.d.ts with the following content:
import {IEMScriptModule} from 'emscripten_wrapper';
declare const loader: IEMScriptModule;
export default loader;the createdWrapper is of following the interface IAsyncEMWMainWrapper defined in index.ts. It is inspired by the child_process interface.
important methods
.main(args?: string[]): Promise<number>execute the main function and returns a promise when done. In case of an error (status code not 0) the promise will be rejected with the error.run(args?: string[]): Promise<{stdout: string, stderr: string, exitCode: number, error?: Error}>similar to.mainbut returns an object with combined output information similar tosubprocess.runfrom Python.fileSystem: Promise<EMScriptFS>lazy access to the filesystem of Emscripten.environmentVariables: {[key: string]: string}access to set virtual environment variables.fn.${functioname}(${arguments}): Promise<$returnType>provides easy access to all the defined functions, e.g. for the example above there would be an.fn.add_values(a: number, b: number): Promise<number>function.sync(): Promise<ISyncEMWWrapper>loads and waits till the module is ready, returning a sync version of the interface. e.g..FileSystemwon't return a promise but directly the file system. So do.main, and alll.fnfunctions. e.g. the signature changes to.fn.add_values(a: number, b: number): number.stdout.on(event: 'data', listener: (chunk: string) => void)to listen to stdout outputs.stderr.on(event: 'data', listener: (chunk: string) => void)to listen to stdout outputs
TODO