@lakutata/ffi 0.0.0-stage → 3.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +23 -0
- package/README.md +163 -2
- package/README.zh-CN.md +140 -0
- package/dist/cjs/components/NativeLibrary.d.ts +229 -0
- package/dist/cjs/components/NativeLibrary.js +346 -0
- package/dist/cjs/decorators/Library.d.ts +61 -0
- package/dist/cjs/decorators/Library.js +44 -0
- package/dist/cjs/decorators/Native.d.ts +69 -0
- package/dist/cjs/decorators/Native.js +90 -0
- package/dist/cjs/exceptions/NativeDeclarationException.d.ts +12 -0
- package/dist/cjs/exceptions/NativeDeclarationException.js +19 -0
- package/dist/cjs/exceptions/NativeLibraryClosedException.d.ts +12 -0
- package/dist/cjs/exceptions/NativeLibraryClosedException.js +19 -0
- package/dist/cjs/exceptions/NativeLibraryNotFoundException.d.ts +11 -0
- package/dist/cjs/exceptions/NativeLibraryNotFoundException.js +18 -0
- package/dist/cjs/exceptions/NativeMemoryException.d.ts +11 -0
- package/dist/cjs/exceptions/NativeMemoryException.js +18 -0
- package/dist/cjs/exports/FFI.d.ts +12 -0
- package/dist/cjs/exports/FFI.js +40 -0
- package/dist/cjs/exports/Generator.d.ts +2 -0
- package/dist/cjs/exports/Generator.js +10 -0
- package/dist/cjs/lib/Memory.d.ts +188 -0
- package/dist/cjs/lib/Memory.js +227 -0
- package/dist/cjs/lib/Runtime.d.ts +98 -0
- package/dist/cjs/lib/Runtime.js +209 -0
- package/dist/cjs/lib/backend/Functions.d.ts +65 -0
- package/dist/cjs/lib/backend/Functions.js +214 -0
- package/dist/cjs/lib/backend/KoffiTypes.d.ts +53 -0
- package/dist/cjs/lib/backend/KoffiTypes.js +426 -0
- package/dist/cjs/lib/declarations/Builtins.d.ts +33 -0
- package/dist/cjs/lib/declarations/Builtins.js +179 -0
- package/dist/cjs/lib/declarations/Layout.d.ts +41 -0
- package/dist/cjs/lib/declarations/Layout.js +180 -0
- package/dist/cjs/lib/declarations/Lexer.d.ts +40 -0
- package/dist/cjs/lib/declarations/Lexer.js +325 -0
- package/dist/cjs/lib/declarations/Parser.d.ts +90 -0
- package/dist/cjs/lib/declarations/Parser.js +1425 -0
- package/dist/cjs/lib/declarations/Platform.d.ts +50 -0
- package/dist/cjs/lib/declarations/Platform.js +27 -0
- package/dist/cjs/lib/declarations/Types.d.ts +173 -0
- package/dist/cjs/lib/declarations/Types.js +179 -0
- package/dist/cjs/lib/generator/CText.d.ts +14 -0
- package/dist/cjs/lib/generator/CText.js +133 -0
- package/dist/cjs/lib/generator/Generator.d.ts +136 -0
- package/dist/cjs/lib/generator/Generator.js +395 -0
- package/dist/cjs/lib/generator/Preprocessor.d.ts +60 -0
- package/dist/cjs/lib/generator/Preprocessor.js +94 -0
- package/dist/cjs/lib/generator/TypeScriptTypes.d.ts +35 -0
- package/dist/cjs/lib/generator/TypeScriptTypes.js +153 -0
- package/dist/cjs/lib/library/NativeCallback.d.ts +44 -0
- package/dist/cjs/lib/library/NativeCallback.js +66 -0
- package/dist/cjs/lib/library/NativeLibraryHandle.d.ts +268 -0
- package/dist/cjs/lib/library/NativeLibraryHandle.js +540 -0
- package/dist/cjs/lib/library/Resolve.d.ts +49 -0
- package/dist/cjs/lib/library/Resolve.js +130 -0
- package/dist/cjs/lib/thread/NativeThreads.d.ts +80 -0
- package/dist/cjs/lib/thread/NativeThreads.js +384 -0
- package/dist/cjs/lib/thread/NativeWorker.d.ts +6 -0
- package/dist/cjs/lib/thread/NativeWorker.js +96 -0
- package/dist/cjs/lib/thread/NativeWorkerCode.d.ts +5 -0
- package/dist/cjs/lib/thread/NativeWorkerCode.js +4 -0
- package/dist/cjs/lib/thread/PackageRequire.d.ts +6 -0
- package/dist/cjs/lib/thread/PackageRequire.js +4 -0
- package/dist/cjs/lib/thread/ThreadProtocol.d.ts +77 -0
- package/dist/cjs/lib/thread/ThreadProtocol.js +2 -0
- package/dist/cjs/package.json +1 -0
- package/dist/esm/components/NativeLibrary.js +338 -0
- package/dist/esm/decorators/Library.js +40 -0
- package/dist/esm/decorators/Native.js +85 -0
- package/dist/esm/exceptions/NativeDeclarationException.js +15 -0
- package/dist/esm/exceptions/NativeLibraryClosedException.js +15 -0
- package/dist/esm/exceptions/NativeLibraryNotFoundException.js +14 -0
- package/dist/esm/exceptions/NativeMemoryException.js +14 -0
- package/dist/esm/exports/FFI.js +10 -0
- package/dist/esm/exports/Generator.js +2 -0
- package/dist/esm/lib/Memory.js +210 -0
- package/dist/esm/lib/Runtime.js +192 -0
- package/dist/esm/lib/backend/Functions.js +206 -0
- package/dist/esm/lib/backend/KoffiTypes.js +418 -0
- package/dist/esm/lib/declarations/Builtins.js +174 -0
- package/dist/esm/lib/declarations/Layout.js +175 -0
- package/dist/esm/lib/declarations/Lexer.js +321 -0
- package/dist/esm/lib/declarations/Parser.js +1421 -0
- package/dist/esm/lib/declarations/Platform.js +23 -0
- package/dist/esm/lib/declarations/Types.js +170 -0
- package/dist/esm/lib/generator/CText.js +129 -0
- package/dist/esm/lib/generator/Generator.js +388 -0
- package/dist/esm/lib/generator/Preprocessor.js +87 -0
- package/dist/esm/lib/generator/TypeScriptTypes.js +149 -0
- package/dist/esm/lib/library/NativeCallback.js +59 -0
- package/dist/esm/lib/library/NativeLibraryHandle.js +532 -0
- package/dist/esm/lib/library/Resolve.js +122 -0
- package/dist/esm/lib/thread/NativeThreads.js +377 -0
- package/dist/esm/lib/thread/NativeWorker.js +93 -0
- package/dist/esm/lib/thread/NativeWorkerCode.js +1 -0
- package/dist/esm/lib/thread/PackageRequire.js +2 -0
- package/dist/esm/lib/thread/ThreadProtocol.js +1 -0
- package/dist/types/components/NativeLibrary.d.ts +229 -0
- package/dist/types/decorators/Library.d.ts +61 -0
- package/dist/types/decorators/Native.d.ts +69 -0
- package/dist/types/exceptions/NativeDeclarationException.d.ts +12 -0
- package/dist/types/exceptions/NativeLibraryClosedException.d.ts +12 -0
- package/dist/types/exceptions/NativeLibraryNotFoundException.d.ts +11 -0
- package/dist/types/exceptions/NativeMemoryException.d.ts +11 -0
- package/dist/types/exports/FFI.d.ts +12 -0
- package/dist/types/exports/Generator.d.ts +2 -0
- package/dist/types/lib/Memory.d.ts +188 -0
- package/dist/types/lib/Runtime.d.ts +98 -0
- package/dist/types/lib/backend/Functions.d.ts +65 -0
- package/dist/types/lib/backend/KoffiTypes.d.ts +53 -0
- package/dist/types/lib/declarations/Builtins.d.ts +33 -0
- package/dist/types/lib/declarations/Layout.d.ts +41 -0
- package/dist/types/lib/declarations/Lexer.d.ts +40 -0
- package/dist/types/lib/declarations/Parser.d.ts +90 -0
- package/dist/types/lib/declarations/Platform.d.ts +50 -0
- package/dist/types/lib/declarations/Types.d.ts +173 -0
- package/dist/types/lib/generator/CText.d.ts +14 -0
- package/dist/types/lib/generator/Generator.d.ts +136 -0
- package/dist/types/lib/generator/Preprocessor.d.ts +60 -0
- package/dist/types/lib/generator/TypeScriptTypes.d.ts +35 -0
- package/dist/types/lib/library/NativeCallback.d.ts +44 -0
- package/dist/types/lib/library/NativeLibraryHandle.d.ts +268 -0
- package/dist/types/lib/library/Resolve.d.ts +49 -0
- package/dist/types/lib/thread/NativeThreads.d.ts +80 -0
- package/dist/types/lib/thread/NativeWorker.d.ts +6 -0
- package/dist/types/lib/thread/NativeWorkerCode.d.ts +5 -0
- package/dist/types/lib/thread/PackageRequire.d.ts +6 -0
- package/dist/types/lib/thread/ThreadProtocol.d.ts +77 -0
- package/package.json +85 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023-present Lakutata
|
|
4
|
+
|
|
5
|
+
All rights reserved
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
in the Software without restriction, including without limitation the rights
|
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
furnished to do so, subject to the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,164 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @lakutata/ffi
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
English | [中文](README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
Native libraries for the [lakutata](https://github.com/lakutata/lakutata) framework: the C functions of `.so`, `.dylib`
|
|
6
|
+
and `.dll` files called from Node.js, the main process of Electron and Bun, without compiling anything. A library is
|
|
7
|
+
declared with the C declarations of its headers (structs, unions, enums, typedefs, pointers to functions, prototypes,
|
|
8
|
+
`#define`), and each library is a component of the application. It is built on [koffi](https://koffi.dev/). The
|
|
9
|
+
`lakutata` package does not re-export this package: import it from `@lakutata/ffi`.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```shell
|
|
14
|
+
npm install lakutata @lakutata/ffi
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
- koffi comes with a package of prebuilt binaries for each platform, installed with it; npm may warn that its install
|
|
18
|
+
script was not run: it is not needed.
|
|
19
|
+
- Node.js `^22.13.0 || >=24.11.0`, the main process of Electron, or Bun. Its peer dependency `@lakutata/core` is
|
|
20
|
+
installed with `lakutata`.
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
### A library
|
|
25
|
+
|
|
26
|
+
A subclass of `NativeLibrary`: `@Library` gives its file names (one by platform, or one completed as each platform names
|
|
27
|
+
libraries) and its declarations, `@Native` binds a function to a property, `@NativeVariable` a variable.
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import {Application} from 'lakutata'
|
|
31
|
+
import {buildNativeLibraryOptions, Library, Native, NativeLibrary, NativeVariable, type Out, type Pointer} from '@lakutata/ffi'
|
|
32
|
+
|
|
33
|
+
@Library({
|
|
34
|
+
names: {darwin: 'libsqlite3.dylib', linux: 'libsqlite3.so.0', win32: 'winsqlite3.dll'},
|
|
35
|
+
declarations: `
|
|
36
|
+
typedef struct sqlite3 sqlite3;
|
|
37
|
+
#define SQLITE_OK 0
|
|
38
|
+
int sqlite3_close(sqlite3 *db);
|
|
39
|
+
`
|
|
40
|
+
})
|
|
41
|
+
export class SQLite extends NativeLibrary {
|
|
42
|
+
@Native('int sqlite3_open(const char *filename, _Out_ sqlite3 **db)')
|
|
43
|
+
public readonly open: (filename: string, db: Out<Pointer>) => number
|
|
44
|
+
|
|
45
|
+
//Runs in a thread of the pool; the error message it gives is freed by sqlite3_free
|
|
46
|
+
@Native('int sqlite3_exec(sqlite3 *db, const char *sql, void *callback, void *context, _Out_ char **error)', {async: true, free: 'sqlite3_free'})
|
|
47
|
+
public readonly exec: (db: Pointer, sql: string, callback: null, context: null, error: Out<string>) => Promise<number>
|
|
48
|
+
|
|
49
|
+
//The function of the declarations named as the property
|
|
50
|
+
@Native()
|
|
51
|
+
public readonly sqlite3_close: (db: Pointer) => number
|
|
52
|
+
|
|
53
|
+
@NativeVariable('extern const char sqlite3_version[]')
|
|
54
|
+
public readonly version: string
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
Application
|
|
58
|
+
.run(() => ({
|
|
59
|
+
id: 'store.app',
|
|
60
|
+
name: 'Store',
|
|
61
|
+
components: {
|
|
62
|
+
sqlite: buildNativeLibraryOptions(SQLite)
|
|
63
|
+
}
|
|
64
|
+
}))
|
|
65
|
+
.onLaunched(async (app: Application): Promise<void> => {
|
|
66
|
+
const sqlite: SQLite = await app.getObject('sqlite')
|
|
67
|
+
const db: Out<Pointer> = [null]
|
|
68
|
+
if (sqlite.open(':memory:', db) !== Number(sqlite.constants.SQLITE_OK)) throw new Error('open failed')
|
|
69
|
+
const error: Out<string> = [null]
|
|
70
|
+
if (await sqlite.exec(db[0]!, 'CREATE TABLE t (id INTEGER)', null, null, error)) console.error(error[0])
|
|
71
|
+
sqlite.sqlite3_close(db[0]!)
|
|
72
|
+
console.log(sqlite.version)
|
|
73
|
+
})
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
- **Where it is found**: the `path` of the configuration (alone, when given), the directories of `search` in the
|
|
77
|
+
configuration and in `@Library`, the directory `native` of the resources of a packaged application, then where the
|
|
78
|
+
system looks for libraries. `c` is the C library on each system (musl included), `m` its mathematical functions.
|
|
79
|
+
- **The values**: numbers; strings for `char *`; bigints for pointers and for every 64-bit integer (`size_t`, `long`,
|
|
80
|
+
`int64_t`…), or numbers with `{int64: 'number'}`; objects for structs and unions, their bitfields by their names; an
|
|
81
|
+
array of one element for an `_Out_` integer or pointer (`Out<T>`).
|
|
82
|
+
- **Callbacks**: a JS function given for a pointer to a function is valid during the call; `callback(type, fn)` makes
|
|
83
|
+
one the library keeps, whose exceptions are `error` events of the component.
|
|
84
|
+
- **Threads**: the asynchronous functions run in the thread pool of the runtime, or in worker threads of the library
|
|
85
|
+
when `threads` is given on `@Library` (or in the configuration). With `threads: 1`, they run one after the other,
|
|
86
|
+
for a library that is not thread-safe; with several, each call goes to the least busy thread. A variadic function can
|
|
87
|
+
be asynchronous there.
|
|
88
|
+
- **Destroyed** with the application: its properties throw, the asynchronous calls running are awaited, its callbacks
|
|
89
|
+
released, the library unloaded. Calls still running after `drainTimeout` keep the library loaded, with its callbacks
|
|
90
|
+
and its memory, since a native call cannot be interrupted.
|
|
91
|
+
|
|
92
|
+
### Without the container
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import {loadNativeLibrary, type NativeLibraryHandle} from '@lakutata/ffi'
|
|
96
|
+
|
|
97
|
+
const libc: NativeLibraryHandle = loadNativeLibrary('c', 'typedef struct { int quot; int rem; } div_t;')
|
|
98
|
+
const div = libc.func<(numerator: number, denominator: number) => {quot: number, rem: number}>('div_t div(int numerator, int denominator)')
|
|
99
|
+
const snprintf = libc.func<(buffer: Buffer, size: number, format: string, ...args: unknown[]) => number>('int snprintf(char *buffer, size_t size, const char *format, ...)')
|
|
100
|
+
console.log(div(17, 5))
|
|
101
|
+
//The types of the extra arguments of a variadic function, by their C names
|
|
102
|
+
const buffer: Buffer = Buffer.alloc(32)
|
|
103
|
+
snprintf(buffer, buffer.length, '%s=%d', 'const char *', 'count', 'int', 42)
|
|
104
|
+
await libc.close()
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Generating the class from the header
|
|
108
|
+
|
|
109
|
+
For a library with many functions, the class is generated from its header by the command line tool of lakutata
|
|
110
|
+
(`@lakutata/cli`), or by `generateNativeLibrary()` of `@lakutata/ffi/generator`:
|
|
111
|
+
|
|
112
|
+
```shell
|
|
113
|
+
lakutata ffi generate /usr/include/sqlite3.h --class-name SQLite3 --out src/native/SQLite3.ts
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The header is run through the preprocessor of the C compiler, the declarations of the library are kept, and the
|
|
117
|
+
functions the library cannot give are left out and listed. Then mark the output parameters `_Out_` and the functions
|
|
118
|
+
that block `{async: true}` in the file generated, as the guide shows: a header does not say which ones they are.
|
|
119
|
+
|
|
120
|
+
### Packaging
|
|
121
|
+
|
|
122
|
+
The bundles, the executables and the installers of Electron made by `lakutata package` carry koffi and its binary for
|
|
123
|
+
the platform. A library shipped with the application goes in the resources, in `native`
|
|
124
|
+
(`"lakutata": {"resources": [{"from": "vendor/lib", "to": "native"}]}` in the package.json). On Alpine, make the
|
|
125
|
+
executables with Bun (`--runtime bun`).
|
|
126
|
+
|
|
127
|
+
## API
|
|
128
|
+
|
|
129
|
+
| Export | What it is |
|
|
130
|
+
|---|---|
|
|
131
|
+
| `NativeLibrary` | The component of a library: its functions and variables on its properties; `func`, `variable`, `callback`, `read`, `write`, `sizeOf`, `offsetOf`, `alloc`, `free`, `errno`, `windowsError`, `constants`, `file`, `pending`, `threadCount`; the `error` event of its callbacks |
|
|
132
|
+
| `buildNativeLibraryOptions`, `NativeLibraryConfig` | Its declaration in the components, and its options: `path`, `search`, `keepLoaded`, `drainTimeout`, `threads` |
|
|
133
|
+
| `Library`, `LibraryOptions` | Class decorator: the library of a `NativeLibrary` subclass: `names`, `search`, `declarations`, `crt`, `threads` |
|
|
134
|
+
| `Native` | Property decorator: a function (a prototype, a declared name, or the name of the property) and its options: `async`, `free`, `int64` |
|
|
135
|
+
| `NativeVariable` | Property decorator: a variable the library exports |
|
|
136
|
+
| `loadNativeLibrary`, `NativeLibraryHandle`, `NativeLibraryOptions` | A library without the container: `func`, `function`, `variable`, `callback`, `declare`, `read`, `write`, `sizeOf`, `offsetOf`, `alloc`, `free`, `errno`, `windowsError`, `threads`, `ready`, `drain`, `close` |
|
|
137
|
+
| `NativeFunctionOptions`, `NativeVariableAccessor`, `NativeCallback`, `LibraryNames`, `Pointer`, `Out` | The options of a function, a variable, a persistent callback (`pointer`, `release()`), the names of a library, a pointer (a bigint), an output parameter |
|
|
138
|
+
| `readCString`, `readWString`, `readBuffer`, `viewBuffer`, `readValue`, `readArray`, `writeValue`, `allocMemory`, `freeMemory`, `sizeOf` | Native memory, with the built-in types (`viewBuffer` does not copy; Electron refuses it) |
|
|
139
|
+
| `lastErrno`, `lastWindowsError` | The errno of the last call (on Windows, the one of the C library given), the error of the Windows API |
|
|
140
|
+
| `generateNativeLibrary`, `defaultCompiler` (`@lakutata/ffi/generator`) | The class of a library generated from its header (its code, its declarations, what was left out), the C compiler run by default |
|
|
141
|
+
|
|
142
|
+
The typings document every declaration, with examples.
|
|
143
|
+
|
|
144
|
+
## Errors
|
|
145
|
+
|
|
146
|
+
| Error | When |
|
|
147
|
+
|---|---|
|
|
148
|
+
| `NativeDeclarationException` | Declarations or a prototype cannot be read (with their line and column: a type not declared, `#if`, a macro with arguments, `long double`…), a function is not in the library, a `va_list` is passed, a class has no `@Library` |
|
|
149
|
+
| `NativeLibraryNotFoundException` | The library cannot be loaded: its message lists each file tried and why |
|
|
150
|
+
| `NativeLibraryClosedException` | A function, a variable or a callback of a closed library is used; a call still running in the threads of a library when it is closed |
|
|
151
|
+
| `NativeMemoryException` | A null pointer or a negative length is given to the memory functions, `viewBuffer` in Electron |
|
|
152
|
+
| `TypeError` (from koffi) | An argument of the wrong type |
|
|
153
|
+
| `RangeError` | A 64-bit integer that is not a safe integer, for a function declared with `{int64: 'number'}` |
|
|
154
|
+
|
|
155
|
+
A C function called with a wrong prototype, or given a wrong pointer, ends the process: no exception can catch it.
|
|
156
|
+
|
|
157
|
+
## See also
|
|
158
|
+
|
|
159
|
+
- The guide on the website: [FFI](https://lakutata.com/guide/FFI).
|
|
160
|
+
- `doc/en/FFI.md` in the `lakutata` package (Chinese version in `doc/zh`): the guide to native libraries.
|
|
161
|
+
- `doc/en/NativeAddons.md` in the `lakutata` package: native addons written in C++ or Rust, for what a library of C
|
|
162
|
+
functions cannot give.
|
|
163
|
+
- [koffi](https://koffi.dev/): the FFI the package is built on.
|
|
164
|
+
- `@lakutata/core` (`lakutata`): components, `Application` and dependency injection.
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# @lakutata/ffi
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 中文
|
|
4
|
+
|
|
5
|
+
[lakutata](https://github.com/lakutata/lakutata) 框架的动态库调用:在 Node.js、Electron 的主进程和 Bun 里调用 `.so`、`.dylib`、`.dll` 文件中的 C 函数,不需要编译任何东西。库用它头文件里的 C 声明来描述(结构体、联合、枚举、typedef、函数指针、原型、`#define`),每个库都是应用的一个组件。它基于 [koffi](https://koffi.dev/)。`lakutata` 包不重新导出这个包:请从 `@lakutata/ffi` 导入。
|
|
6
|
+
|
|
7
|
+
## 安装
|
|
8
|
+
|
|
9
|
+
```shell
|
|
10
|
+
npm install lakutata @lakutata/ffi
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
- koffi 会连同各平台的预编译文件一起安装(每个平台一个包);npm 可能会提示它的安装脚本没有运行:不需要运行它。
|
|
14
|
+
- 需要 Node.js `^22.13.0 || >=24.11.0`、Electron 的主进程或 Bun。它的 peer 依赖 `@lakutata/core` 会随 `lakutata` 一起安装。
|
|
15
|
+
|
|
16
|
+
## 用法
|
|
17
|
+
|
|
18
|
+
### 一个库
|
|
19
|
+
|
|
20
|
+
一个库就是 `NativeLibrary` 的一个子类:`@Library` 给出它的文件名(可以按平台分别写,也可以写一个名字,按各平台给库命名的方式补全)和它的声明,`@Native` 把一个函数绑到一个属性上,`@NativeVariable` 绑定一个变量。
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import {Application} from 'lakutata'
|
|
24
|
+
import {buildNativeLibraryOptions, Library, Native, NativeLibrary, NativeVariable, type Out, type Pointer} from '@lakutata/ffi'
|
|
25
|
+
|
|
26
|
+
@Library({
|
|
27
|
+
names: {darwin: 'libsqlite3.dylib', linux: 'libsqlite3.so.0', win32: 'winsqlite3.dll'},
|
|
28
|
+
declarations: `
|
|
29
|
+
typedef struct sqlite3 sqlite3;
|
|
30
|
+
#define SQLITE_OK 0
|
|
31
|
+
int sqlite3_close(sqlite3 *db);
|
|
32
|
+
`
|
|
33
|
+
})
|
|
34
|
+
export class SQLite extends NativeLibrary {
|
|
35
|
+
@Native('int sqlite3_open(const char *filename, _Out_ sqlite3 **db)')
|
|
36
|
+
public readonly open: (filename: string, db: Out<Pointer>) => number
|
|
37
|
+
|
|
38
|
+
//在线程池里执行;它给出的错误信息由 sqlite3_free 释放
|
|
39
|
+
@Native('int sqlite3_exec(sqlite3 *db, const char *sql, void *callback, void *context, _Out_ char **error)', {async: true, free: 'sqlite3_free'})
|
|
40
|
+
public readonly exec: (db: Pointer, sql: string, callback: null, context: null, error: Out<string>) => Promise<number>
|
|
41
|
+
|
|
42
|
+
//声明里和属性同名的函数
|
|
43
|
+
@Native()
|
|
44
|
+
public readonly sqlite3_close: (db: Pointer) => number
|
|
45
|
+
|
|
46
|
+
@NativeVariable('extern const char sqlite3_version[]')
|
|
47
|
+
public readonly version: string
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
Application
|
|
51
|
+
.run(() => ({
|
|
52
|
+
id: 'store.app',
|
|
53
|
+
name: 'Store',
|
|
54
|
+
components: {
|
|
55
|
+
sqlite: buildNativeLibraryOptions(SQLite)
|
|
56
|
+
}
|
|
57
|
+
}))
|
|
58
|
+
.onLaunched(async (app: Application): Promise<void> => {
|
|
59
|
+
const sqlite: SQLite = await app.getObject('sqlite')
|
|
60
|
+
const db: Out<Pointer> = [null]
|
|
61
|
+
if (sqlite.open(':memory:', db) !== Number(sqlite.constants.SQLITE_OK)) throw new Error('open failed')
|
|
62
|
+
const error: Out<string> = [null]
|
|
63
|
+
if (await sqlite.exec(db[0]!, 'CREATE TABLE t (id INTEGER)', null, null, error)) console.error(error[0])
|
|
64
|
+
sqlite.sqlite3_close(db[0]!)
|
|
65
|
+
console.log(sqlite.version)
|
|
66
|
+
})
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
- **到哪里找库**:配置里的 `path`(给了就只试它),配置和 `@Library` 里 `search` 的目录,打包后应用的资源目录下的 `native` 目录,最后是系统找库的位置。`c` 表示各系统上的 C 标准库(包括 musl),`m` 表示它的数学函数。
|
|
70
|
+
- **值的对应关系**:数字对应 number;`char *` 对应字符串;指针和所有 64 位整数(`size_t`、`long`、`int64_t` 等)对应 bigint,声明时加上 `{int64: 'number'}` 就改为 number;结构体和联合对应对象,位域按名字读写;`_Out_` 的整数或指针用只有一个元素的数组传入(`Out<T>`)。
|
|
71
|
+
- **回调**:给函数指针参数传入的 JS 函数只在这次调用期间有效;`callback(type, fn)` 生成一个库可以保存起来以后再调用的回调,它抛出的异常会成为组件的 `error` 事件。
|
|
72
|
+
- **线程**:异步函数默认在运行时的线程池里执行;在 `@Library`(或配置)里设置 `threads` 后,改在库自己的线程里执行。`threads: 1` 时,异步调用一个接一个执行,适合不是线程安全的库;有多个线程时,每个调用交给最空闲的线程。在这些线程里,可变参数的函数也可以异步调用。
|
|
73
|
+
- **销毁**:随应用一起销毁时,属性开始抛出异常,会等进行中的异步调用结束,回调全部释放,库被卸载。原生调用没法中途打断:过了 `drainTimeout` 还有调用没结束时,库连同它的回调和内存都保留下来。
|
|
74
|
+
|
|
75
|
+
### 不用容器
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import {loadNativeLibrary, type NativeLibraryHandle} from '@lakutata/ffi'
|
|
79
|
+
|
|
80
|
+
const libc: NativeLibraryHandle = loadNativeLibrary('c', 'typedef struct { int quot; int rem; } div_t;')
|
|
81
|
+
const div = libc.func<(numerator: number, denominator: number) => {quot: number, rem: number}>('div_t div(int numerator, int denominator)')
|
|
82
|
+
const snprintf = libc.func<(buffer: Buffer, size: number, format: string, ...args: unknown[]) => number>('int snprintf(char *buffer, size_t size, const char *format, ...)')
|
|
83
|
+
console.log(div(17, 5))
|
|
84
|
+
//可变参数函数的额外参数,前面用 C 类型名写出类型
|
|
85
|
+
const buffer: Buffer = Buffer.alloc(32)
|
|
86
|
+
snprintf(buffer, buffer.length, '%s=%d', 'const char *', 'count', 'int', 42)
|
|
87
|
+
await libc.close()
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 根据头文件生成类
|
|
91
|
+
|
|
92
|
+
函数很多的库,可以用 lakutata 的命令行工具(`@lakutata/cli`)或 `@lakutata/ffi/generator` 的 `generateNativeLibrary()` 根据头文件生成类:
|
|
93
|
+
|
|
94
|
+
```shell
|
|
95
|
+
lakutata ffi generate /usr/include/sqlite3.h --class-name SQLite3 --out src/native/SQLite3.ts
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
头文件先经过 C 编译器的预处理器,保留库自己的声明,库给不了的函数会被去掉并列出来。之后请在生成的文件里把输出参数标成 `_Out_`,把会阻塞的函数声明为 `{async: true}`,做法见指南:头文件看不出是哪些。
|
|
99
|
+
|
|
100
|
+
### 打包
|
|
101
|
+
|
|
102
|
+
`lakutata package` 打出的 bundle、可执行文件和 Electron 安装包都会带上 koffi 和本平台的预编译文件。要和应用一起发布的库放进资源里的 `native` 目录(在 package.json 里写 `"lakutata": {"resources": [{"from": "vendor/lib", "to": "native"}]}`)。在 Alpine 上请用 Bun 打可执行文件(`--runtime bun`)。
|
|
103
|
+
|
|
104
|
+
## API
|
|
105
|
+
|
|
106
|
+
| 导出 | 是什么 |
|
|
107
|
+
|---|---|
|
|
108
|
+
| `NativeLibrary` | 库的组件:函数和变量在它的属性上;`func`、`variable`、`callback`、`read`、`write`、`sizeOf`、`offsetOf`、`alloc`、`free`、`errno`、`windowsError`、`constants`、`file`、`pending`、`threadCount`;回调异常的 `error` 事件 |
|
|
109
|
+
| `buildNativeLibraryOptions`、`NativeLibraryConfig` | 在 `components` 里注册它,以及它的选项:`path`、`search`、`keepLoaded`、`drainTimeout`、`threads` |
|
|
110
|
+
| `Library`、`LibraryOptions` | 类装饰器:`NativeLibrary` 子类的库:`names`、`search`、`declarations`、`crt`、`threads` |
|
|
111
|
+
| `Native` | 属性装饰器:一个函数(原型、声明里的名字,或者属性名)及其选项:`async`、`free`、`int64` |
|
|
112
|
+
| `NativeVariable` | 属性装饰器:库导出的一个变量 |
|
|
113
|
+
| `loadNativeLibrary`、`NativeLibraryHandle`、`NativeLibraryOptions` | 不用容器时的库:`func`、`function`、`variable`、`callback`、`declare`、`read`、`write`、`sizeOf`、`offsetOf`、`alloc`、`free`、`errno`、`windowsError`、`threads`、`ready`、`drain`、`close` |
|
|
114
|
+
| `NativeFunctionOptions`、`NativeVariableAccessor`、`NativeCallback`、`LibraryNames`、`Pointer`、`Out` | 函数的选项、变量、持久回调(`pointer`、`release()`)、库的文件名、指针(bigint)、输出参数 |
|
|
115
|
+
| `readCString`、`readWString`、`readBuffer`、`viewBuffer`、`readValue`、`readArray`、`writeValue`、`allocMemory`、`freeMemory`、`sizeOf` | 用内置类型读写原生内存(`viewBuffer` 不复制;Electron 里不能用) |
|
|
116
|
+
| `lastErrno`、`lastWindowsError` | 上一次调用后的 errno(Windows 上是指定的 C 运行库的 errno),以及 Windows API 的错误 |
|
|
117
|
+
| `generateNativeLibrary`、`defaultCompiler`(`@lakutata/ffi/generator`) | 根据头文件生成库的类(它的代码、声明,以及去掉了哪些),以及默认运行的 C 编译器 |
|
|
118
|
+
|
|
119
|
+
类型声明里有每个导出的说明和示例。
|
|
120
|
+
|
|
121
|
+
## 错误
|
|
122
|
+
|
|
123
|
+
| 错误 | 什么时候 |
|
|
124
|
+
|---|---|
|
|
125
|
+
| `NativeDeclarationException` | 声明或原型读不了(带行号和列号:类型没有声明、`#if`、带参数的宏、`long double` 等)、库里没有这个函数、传了 `va_list`、类上没有 `@Library` |
|
|
126
|
+
| `NativeLibraryNotFoundException` | 库加载不了:消息里列出试过的每个文件和原因 |
|
|
127
|
+
| `NativeLibraryClosedException` | 库关闭后又使用它的函数、变量或回调;库关闭时,它的线程里还没结束的调用 |
|
|
128
|
+
| `NativeMemoryException` | 给内存函数传了空指针或负的长度、在 Electron 里用 `viewBuffer` |
|
|
129
|
+
| `TypeError`(来自 koffi) | 参数类型不对 |
|
|
130
|
+
| `RangeError` | 声明了 `{int64: 'number'}` 的函数遇到超出安全整数范围的 64 位整数 |
|
|
131
|
+
|
|
132
|
+
C 函数的原型写错,或者传了错误的指针,整个进程都会退出,任何异常处理都拦不住。
|
|
133
|
+
|
|
134
|
+
## 另见
|
|
135
|
+
|
|
136
|
+
- 网站上的指南:[FFI](https://lakutata.com/zh/guide/FFI)。
|
|
137
|
+
- `lakutata` 包里的 `doc/zh/FFI.md`(英文版在 `doc/en`):动态库调用指南。
|
|
138
|
+
- `lakutata` 包里的 `doc/zh/NativeAddons.md`:用 C++ 或 Rust 编写的原生插件,用于 C 函数库做不到的情况。
|
|
139
|
+
- [koffi](https://koffi.dev/):这个包所基于的 FFI。
|
|
140
|
+
- `@lakutata/core`(`lakutata`):组件、`Application` 和依赖注入。
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { Component, type ComponentOptions } from '@lakutata/core';
|
|
2
|
+
import type { NativeCallback } from '../lib/library/NativeCallback.js';
|
|
3
|
+
import { type NativeFunctionOptions, type NativeVariableAccessor } from '../lib/library/NativeLibraryHandle.js';
|
|
4
|
+
import type { Pointer } from '../lib/Runtime.js';
|
|
5
|
+
/**
|
|
6
|
+
* The options of a library in the configuration (see {@link buildNativeLibraryOptions}): where it is found, how it is
|
|
7
|
+
* closed
|
|
8
|
+
*/
|
|
9
|
+
export interface NativeLibraryConfig {
|
|
10
|
+
/**
|
|
11
|
+
* The file of the library: the only one tried when given (an alias of the application can start it).
|
|
12
|
+
*/
|
|
13
|
+
path?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Directories tried before the ones of `@Library`, in their order.
|
|
16
|
+
*/
|
|
17
|
+
search?: string[];
|
|
18
|
+
/**
|
|
19
|
+
* Whether the library stays loaded once the component is destroyed.
|
|
20
|
+
* @default false
|
|
21
|
+
*/
|
|
22
|
+
keepLoaded?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* How long the destruction waits for the asynchronous calls running, in milliseconds. Calls still running then
|
|
25
|
+
* keep the library loaded, with its callbacks and its memory (a native call cannot be interrupted).
|
|
26
|
+
* @default 10000
|
|
27
|
+
*/
|
|
28
|
+
drainTimeout?: number;
|
|
29
|
+
/**
|
|
30
|
+
* The worker threads that run the asynchronous functions of the library, replacing the number of `@Library`: 0 for
|
|
31
|
+
* the thread pool of the runtime; 1 runs them one after the other.
|
|
32
|
+
*/
|
|
33
|
+
threads?: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* A native library: a component holding a library loaded with its C declarations (`@Library`), its functions on its
|
|
37
|
+
* properties (`@Native`), its variables (`@NativeVariable`). Write one subclass for each library and register it in the
|
|
38
|
+
* components of the application; it is loaded when it is created, and destroyed with the application: the asynchronous
|
|
39
|
+
* calls running are awaited, its callbacks released, the library unloaded.
|
|
40
|
+
*
|
|
41
|
+
* In a packaged application, the library is also looked for in the directory `native` of the resources (put it there
|
|
42
|
+
* with `lakutata.resources` of the package.json). The exceptions thrown by its persistent callbacks are its `error`
|
|
43
|
+
* events (written to the log of the application when nothing listens to them).
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* import {Application} from 'lakutata'
|
|
47
|
+
* import {buildNativeLibraryOptions, Library, Native, NativeLibrary, type Out, type Pointer} from '@lakutata/ffi'
|
|
48
|
+
*
|
|
49
|
+
* @Library({
|
|
50
|
+
* names: {darwin: 'libsqlite3.dylib', linux: 'libsqlite3.so.0', win32: 'winsqlite3.dll'},
|
|
51
|
+
* declarations: `
|
|
52
|
+
* typedef struct sqlite3 sqlite3;
|
|
53
|
+
* #define SQLITE_OK 0
|
|
54
|
+
* `
|
|
55
|
+
* })
|
|
56
|
+
* export class SQLite extends NativeLibrary {
|
|
57
|
+
* @Native('const char *sqlite3_libversion(void)')
|
|
58
|
+
* public readonly libversion: () => string
|
|
59
|
+
*
|
|
60
|
+
* @Native('int sqlite3_open(const char *filename, _Out_ sqlite3 **db)')
|
|
61
|
+
* public readonly open: (filename: string, db: Out<Pointer>) => number
|
|
62
|
+
*
|
|
63
|
+
* @Native('int sqlite3_close(sqlite3 *db)')
|
|
64
|
+
* public readonly close: (db: Pointer) => number
|
|
65
|
+
* }
|
|
66
|
+
*
|
|
67
|
+
* Application
|
|
68
|
+
* .run(() => ({
|
|
69
|
+
* id: 'store.app',
|
|
70
|
+
* name: 'Store',
|
|
71
|
+
* components: {
|
|
72
|
+
* sqlite: buildNativeLibraryOptions(SQLite)
|
|
73
|
+
* }
|
|
74
|
+
* }))
|
|
75
|
+
* .onLaunched(async (app: Application): Promise<void> => {
|
|
76
|
+
* const sqlite: SQLite = await app.getObject('sqlite')
|
|
77
|
+
* console.log(sqlite.libversion())
|
|
78
|
+
* })
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export declare class NativeLibrary extends Component {
|
|
82
|
+
#private;
|
|
83
|
+
/**
|
|
84
|
+
* The file of the library: the only one tried when given.
|
|
85
|
+
*/
|
|
86
|
+
protected readonly path?: string;
|
|
87
|
+
/**
|
|
88
|
+
* Directories tried before the ones of `@Library`.
|
|
89
|
+
*/
|
|
90
|
+
protected readonly search?: string[];
|
|
91
|
+
/**
|
|
92
|
+
* Whether the library stays loaded once the component is destroyed.
|
|
93
|
+
*/
|
|
94
|
+
protected readonly keepLoaded?: boolean;
|
|
95
|
+
/**
|
|
96
|
+
* How long the destruction waits for the asynchronous calls running, in milliseconds.
|
|
97
|
+
*/
|
|
98
|
+
protected readonly drainTimeout?: number;
|
|
99
|
+
/**
|
|
100
|
+
* The worker threads that run the asynchronous functions of the library.
|
|
101
|
+
*/
|
|
102
|
+
protected readonly threads?: number;
|
|
103
|
+
/**
|
|
104
|
+
* Load the library and bind its functions and variables to their properties.
|
|
105
|
+
* @protected
|
|
106
|
+
*/
|
|
107
|
+
protected init(): Promise<void>;
|
|
108
|
+
/**
|
|
109
|
+
* Close the library: the asynchronous calls running awaited, the callbacks released, the library unloaded (kept,
|
|
110
|
+
* with its callbacks and its memory, when calls still run after `drainTimeout`); its properties throw from then on.
|
|
111
|
+
* @protected
|
|
112
|
+
*/
|
|
113
|
+
protected destroy(): Promise<void>;
|
|
114
|
+
/**
|
|
115
|
+
* The file the library was loaded from.
|
|
116
|
+
*/
|
|
117
|
+
get file(): string;
|
|
118
|
+
/**
|
|
119
|
+
* The asynchronous calls running.
|
|
120
|
+
*/
|
|
121
|
+
get pending(): number;
|
|
122
|
+
/**
|
|
123
|
+
* The worker threads of the library (0: its asynchronous calls run in the thread pool of the runtime).
|
|
124
|
+
*/
|
|
125
|
+
get threadCount(): number;
|
|
126
|
+
/**
|
|
127
|
+
* The constants of the declarations: the values of the enumerations, of the static constants and of the macros
|
|
128
|
+
* whose value is an integer.
|
|
129
|
+
*/
|
|
130
|
+
get constants(): Readonly<Record<string, bigint>>;
|
|
131
|
+
/**
|
|
132
|
+
* A function of the library bound from its prototype, besides the ones of the properties.
|
|
133
|
+
* @param prototype Its C prototype, with the types of the declarations.
|
|
134
|
+
* @param options Whether it is asynchronous, how its strings are freed, how its 64-bit integers are given.
|
|
135
|
+
* @returns The function.
|
|
136
|
+
*/
|
|
137
|
+
func<T extends (...args: any[]) => any = (...args: any[]) => any>(prototype: string, options?: NativeFunctionOptions): T;
|
|
138
|
+
/**
|
|
139
|
+
* A variable the library exports, besides the ones of the properties.
|
|
140
|
+
* @param declaration Its name in the declarations, or its declaration.
|
|
141
|
+
* @returns Its address, and the functions reading and writing its value.
|
|
142
|
+
*/
|
|
143
|
+
variable<T = unknown>(declaration: string): NativeVariableAccessor<T>;
|
|
144
|
+
/**
|
|
145
|
+
* A persistent callback: a JS function the library can call at any time, released by `release()` or when the
|
|
146
|
+
* component is destroyed. Its exceptions are `error` events of the component.
|
|
147
|
+
* @param type The name of a pointer-to-function type of the declarations, or its prototype.
|
|
148
|
+
* @param callback The JS function.
|
|
149
|
+
* @returns The callback, whose `pointer` is given to the library.
|
|
150
|
+
*/
|
|
151
|
+
callback(type: string, callback: (...args: any[]) => any): NativeCallback;
|
|
152
|
+
/**
|
|
153
|
+
* Read native memory as a type of the declarations: a value, or an array of values.
|
|
154
|
+
* @param pointer The address.
|
|
155
|
+
* @param type The type: `int`, `struct timeval`, `char *` (a string).
|
|
156
|
+
* @param count The number of values, for an array.
|
|
157
|
+
* @returns The value, or the array.
|
|
158
|
+
*/
|
|
159
|
+
read<T = unknown>(pointer: Pointer, type: string, count?: number): T;
|
|
160
|
+
/**
|
|
161
|
+
* Write a value to native memory as a type of the declarations.
|
|
162
|
+
* @param pointer The address.
|
|
163
|
+
* @param type The type.
|
|
164
|
+
* @param value The value.
|
|
165
|
+
*/
|
|
166
|
+
write(pointer: Pointer, type: string, value: unknown): void;
|
|
167
|
+
/**
|
|
168
|
+
* The size of a type of the declarations, in bytes.
|
|
169
|
+
* @param type The type.
|
|
170
|
+
*/
|
|
171
|
+
sizeOf(type: string): number;
|
|
172
|
+
/**
|
|
173
|
+
* The offset of a member of a struct of the declarations, in bytes.
|
|
174
|
+
* @param type The struct.
|
|
175
|
+
* @param member The member.
|
|
176
|
+
*/
|
|
177
|
+
offsetOf(type: string, member: string): number;
|
|
178
|
+
/**
|
|
179
|
+
* Allocate native memory for values of a type of the declarations, which the library can keep; freed by `free()`,
|
|
180
|
+
* or when the component is destroyed.
|
|
181
|
+
* @param type The type.
|
|
182
|
+
* @param count The number of values.
|
|
183
|
+
* @returns Its address.
|
|
184
|
+
*/
|
|
185
|
+
alloc(type: string, count?: number): Pointer;
|
|
186
|
+
/**
|
|
187
|
+
* Free memory allocated by `alloc()`.
|
|
188
|
+
* @param pointer Its address.
|
|
189
|
+
*/
|
|
190
|
+
free(pointer: Pointer): void;
|
|
191
|
+
/**
|
|
192
|
+
* The errno of the last call of this thread (on Windows, the one of the C library of `@Library`, ucrtbase.dll by
|
|
193
|
+
* default); with threads, the one of the thread of the last asynchronous call completed.
|
|
194
|
+
*/
|
|
195
|
+
errno(): number;
|
|
196
|
+
/**
|
|
197
|
+
* The last error of the Windows API after the last call of this thread; with threads, the one of the thread of the
|
|
198
|
+
* last asynchronous call completed; undefined on the other systems.
|
|
199
|
+
*/
|
|
200
|
+
windowsError(): number | undefined;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Build the declaration of a library component, for the `components` of an application.
|
|
204
|
+
* @param library The `NativeLibrary` subclass of the library.
|
|
205
|
+
* @param options Where it is found (a file, directories searched first), whether it stays loaded, how long its
|
|
206
|
+
* destruction waits for its asynchronous calls.
|
|
207
|
+
* @returns The component declaration.
|
|
208
|
+
* @example
|
|
209
|
+
* ```typescript
|
|
210
|
+
* import {Application} from 'lakutata'
|
|
211
|
+
* import {buildNativeLibraryOptions, Library, Native, NativeLibrary} from '@lakutata/ffi'
|
|
212
|
+
*
|
|
213
|
+
* @Library({names: 'vendor'})
|
|
214
|
+
* class Vendor extends NativeLibrary {
|
|
215
|
+
* @Native('int vendor_version(void)')
|
|
216
|
+
* public readonly version: () => number
|
|
217
|
+
* }
|
|
218
|
+
*
|
|
219
|
+
* Application.run(() => ({
|
|
220
|
+
* id: 'devices.app',
|
|
221
|
+
* name: 'Devices',
|
|
222
|
+
* components: {
|
|
223
|
+
* //The library shipped with the application: an alias, or a path relative to the working directory
|
|
224
|
+
* vendor: buildNativeLibraryOptions(Vendor, {search: ['@data/native']})
|
|
225
|
+
* }
|
|
226
|
+
* }))
|
|
227
|
+
* ```
|
|
228
|
+
*/
|
|
229
|
+
export declare function buildNativeLibraryOptions(library: typeof NativeLibrary, options?: NativeLibraryConfig): ComponentOptions<NativeLibraryConfig>;
|