Image suorce: Rainbow Colors Electronic
Foreign Function Interface Adapter Powered by Decorator & TypeScript
- Binding shared library(
.dll/.so/.dylib) to a TypeScript class by decorators. - Support
asyncmode when a class method defined with a return type ofPromise. - Supports Windows(
.dll), Linux(.so), and MacOS(.dylib). - The class will be forced singleton.
- Node.js v10 or v11 for ffi (neither v12 nor v13, see #554)
- TypeScript with
--target ES5,--experimentalDecorators, and--emitDecoratorMetadataoptions on.
Background:
- We have a shared library file
libfactorial.so(.dll/.dylibas well) - the library has a function
uint64_t factorial(int) - We want to use
factorial()in TypeScript.
import {
LIBRARY,
API,
RETURN,
} from 'ffi-adapter'
@LIBRARY('./libfactorial')
export class LibFactorial {
@API() factorial (n: number): number { return RETURN(n) }
}
const lib = new LibFactorial()
console.log('factorial(5) =', lib.factorial(5))
// Output: factorial(5) = 120That's it! Use it is that easy!
import {
LIBRARY,
API,
RETURN,
} from 'ffi-adapter'All you need is the above two decorators and one function:
LIBRARY(libraryFile: string)- Class decoratorAPI(returnType?: FfiReturnType)- Method decoratorRETURN(...args: any[])- Method need to return this function to confirm the adapting.
libraryFile:string- The shared library file path, which will be adapted and binding to the class.
@LIBRARY('./libfactorial')
class LibFactorial { /* ... */ }returnType:FfiReturnType- Optional. Specify the library function return type. Can be refered automatically by the TypeScript if the method return is not aPromise.
Specific the library function return type, and bind the same name function from library to the decorated class method.
@API('uint64') factorial(n: number): Promise<number> { ... }args:any[]- The method args. Just place every args of the method, to th RETURN function.
@API() factorial(...args: any[]) { return RETURN(...args) }The actual return value will be take care by the @API decorator.
Credit: https://github.com/node-ffi/node-ffi/tree/master/example/factorial
#include <stdint.h>
#if defined(WIN32) || defined(_WIN32)
#define EXPORT __declspec(dllexport)
#else
#define EXPORT
#endif
EXPORT uint64_t factorial(int max) {
int i = max;
uint64_t result = 1;
while (i >= 2) {
result *= i--;
}
return result;
}gcc -dynamiclib -undefined suppress -flat_namespace factorial.c -o libfactorial.dylibgcc -shared -fpic factorial.c -o libfactorial.so2.3 To compile libfactorial.dll on Windows (http://stackoverflow.com/a/2220213)
cl.exe /D_USRDLL /D_WINDLL factorial.c /link /DLL /OUT:libfactorial.dllSave the following code to file lib-factorial.ts:
import {
LIBRARY,
API,
RETURN,
} from 'ffi-adapter'
@LIBRARY('./libfactorial')
export class LibFactorial {
@API() factorial (n: number): number { return RETURN(n) }
}import { LibFactorial } from './lib-factorial.ts'
const lib = new LibFactorial()
console.log('factorial(5) =', lib.factorial(5))
// Output: factorial(5) = 120You will agree with me that it's super clean, beautiful, and easy to maintain! ;-)
- TypeScript - Class Decorators
- Generate ffi bindings from header files
- node-ffi使用指南
- Node FFI Tutorial
- Use the Microsoft C++ toolset from the command line - To open a developer command prompt window
- FFI Definitions of Windows win32 api for node-ffi-napi
- Decorators & metadata reflection in TypeScript: From Novice to Expert - PART IV: Types serialization & The metadata reflection API
- decorator metadata is emitted only on decorated members
Support all Node.js versions (10/11/12/13/14/15/16) now!
The first version.
- Use
@LIBRARY(),@API(), andRETURN()as decorators to bind a shared library to a TypeScript Class.
- Code & Docs © 2020-now Huan LI <zixia@zixia.net>
- Code released under the Apache-2.0 License
- Docs released under Creative Commons