koffi 2.9.1 → 2.10.0
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/CHANGELOG.md +61 -48
- package/build/koffi/darwin_arm64/koffi.node +0 -0
- package/build/koffi/darwin_x64/koffi.node +0 -0
- package/build/koffi/freebsd_arm64/koffi.node +0 -0
- package/build/koffi/freebsd_ia32/koffi.node +0 -0
- package/build/koffi/freebsd_x64/koffi.node +0 -0
- package/build/koffi/linux_arm32/koffi.node +0 -0
- package/build/koffi/linux_arm64/koffi.node +0 -0
- package/build/koffi/linux_ia32/koffi.node +0 -0
- package/build/koffi/linux_riscv64/koffi.node +0 -0
- package/build/koffi/linux_x64/koffi.node +0 -0
- package/build/koffi/musl_x64/koffi.node +0 -0
- package/build/koffi/openbsd_ia32/koffi.node +0 -0
- package/build/koffi/openbsd_x64/koffi.node +0 -0
- package/build/koffi/win32_arm64/koffi.node +0 -0
- package/build/koffi/win32_ia32/koffi.node +0 -0
- package/build/koffi/win32_x64/koffi.node +0 -0
- package/doc/README.md +27 -0
- package/doc/assets.ini +19 -0
- package/doc/develop.sh +14 -0
- package/doc/flaat/flaat.css +25 -0
- package/doc/flaat/flaat.js +150 -0
- package/doc/flaat/normal.css +335 -0
- package/doc/flaat/print.css +30 -0
- package/doc/flaat/small.css +101 -0
- package/doc/{benchmarks.md → pages/benchmarks.md} +14 -18
- package/doc/{callbacks.md → pages/callbacks.md} +27 -36
- package/doc/{contribute.md → pages/contribute.md} +10 -12
- package/doc/{functions.md → pages/functions.md} +29 -34
- package/doc/pages/index.md +20 -0
- package/doc/{input.md → pages/input.md} +28 -33
- package/doc/{migration.md → pages/migration.md} +7 -10
- package/doc/{misc.md → pages/misc.md} +54 -23
- package/doc/{output.md → pages/output.md} +17 -20
- package/doc/{packaging.md → pages/packaging.md} +19 -12
- package/doc/{platforms.md → pages/platforms.md} +25 -11
- package/doc/{pointers.md → pages/pointers.md} +13 -16
- package/doc/{start.md → pages/start.md} +12 -14
- package/doc/{unions.md → pages/unions.md} +5 -7
- package/doc/{variables.md → pages/variables.md} +7 -11
- package/doc/pages.ini +89 -0
- package/doc/static/koffi.css +21 -0
- package/doc/static/koffi.js +21 -0
- package/doc/static/koffi.png +0 -0
- package/doc/static/logo.webp +0 -0
- package/doc/static/print.css +22 -0
- package/doc/templates/page.html +48 -0
- package/index.js +2 -2
- package/indirect.js +2 -2
- package/package.json +2 -2
- package/src/koffi/CMakeLists.txt +6 -0
- package/src/koffi/examples/yao-pkg/README.md +17 -0
- package/src/koffi/examples/yao-pkg/index.js +2 -0
- package/src/koffi/examples/yao-pkg/package.json +22 -0
- package/src/koffi/src/call.cc +2 -0
- package/src/koffi/src/ffi.cc +40 -4
- package/src/koffi/src/util.cc +1 -1
- package/doc/Makefile +0 -20
- package/doc/benchmarks.xlsx +0 -0
- package/doc/changelog.md +0 -5
- package/doc/conf.py +0 -118
- package/doc/index.rst +0 -47
- package/doc/make.bat +0 -35
- package/doc/poetry.lock +0 -521
- package/doc/pyproject.toml +0 -19
- package/doc/static/bench_linux.png +0 -0
- package/doc/static/bench_windows.png +0 -0
- package/doc/static/custom.css +0 -70
- package/doc/static/node_c.webp +0 -0
- package/doc/static/opensans/LICENSE.txt +0 -202
- package/doc/static/opensans/OpenSans.css +0 -39
- package/doc/static/opensans/OpenSans_v17_Latin_Bold.woff +0 -0
- package/doc/static/opensans/OpenSans_v17_Latin_Bold.woff2 +0 -0
- package/doc/static/opensans/OpenSans_v17_Latin_BoldItalic.woff +0 -0
- package/doc/static/opensans/OpenSans_v17_Latin_BoldItalic.woff2 +0 -0
- package/doc/static/opensans/OpenSans_v17_Latin_Italic.woff +0 -0
- package/doc/static/opensans/OpenSans_v17_Latin_Italic.woff2 +0 -0
- package/doc/static/opensans/OpenSans_v17_Latin_Regular.woff +0 -0
- package/doc/static/opensans/OpenSans_v17_Latin_Regular.woff2 +0 -0
- package/doc/static/perf_linux_20220623.png +0 -0
- package/doc/static/perf_linux_20220623_2.png +0 -0
- package/doc/static/perf_linux_20220627.png +0 -0
- package/doc/static/perf_linux_20220628.png +0 -0
- package/doc/static/perf_linux_20220812.png +0 -0
- package/doc/static/perf_windows_20220623.png +0 -0
- package/doc/static/perf_windows_20220623_2.png +0 -0
- package/doc/static/perf_windows_20220627.png +0 -0
- package/doc/static/perf_windows_20220628.png +0 -0
- package/doc/static/perf_windows_20220812.png +0 -0
- package/doc/templates/badges.html +0 -7
- package/doc/templates/logo.html +0 -3
- /package/doc/static/{perf_linux_20231028.png → perf_linux.png} +0 -0
- /package/doc/static/{perf_windows_20231028.png → perf_windows.png} +0 -0
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
## Bugs and feature requests
|
|
1
|
+
# Bugs and feature requests
|
|
4
2
|
|
|
5
3
|
Use the official repository for bugs, ideas and features requests: https://github.com/Koromix/koffi
|
|
6
4
|
|
|
7
5
|
Please note that the source code is not in this repository, instead it lives in a monorepo: https://github.com/Koromix/rygel/ (in the *src/koffi* subdirectory).
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
# Build from source
|
|
10
8
|
|
|
11
9
|
We provide prebuilt binaries, packaged in the NPM archive, so in most cases it should be as simple as `npm install koffi`. If you want to hack Koffi or use a specific platform, follow the instructions below.
|
|
12
10
|
|
|
@@ -19,7 +17,7 @@ cd rygel
|
|
|
19
17
|
|
|
20
18
|
As said before, this is a monorepository containg multiple projects, hence the name.
|
|
21
19
|
|
|
22
|
-
|
|
20
|
+
## Windows
|
|
23
21
|
|
|
24
22
|
First, make sure the following dependencies are met:
|
|
25
23
|
|
|
@@ -34,7 +32,7 @@ cd src/koffi
|
|
|
34
32
|
node ../cnoke/cnoke.js
|
|
35
33
|
```
|
|
36
34
|
|
|
37
|
-
|
|
35
|
+
## Other platforms
|
|
38
36
|
|
|
39
37
|
Make sure the following dependencies are met:
|
|
40
38
|
|
|
@@ -50,9 +48,9 @@ cd src/koffi
|
|
|
50
48
|
node ../cnoke/cnoke.js
|
|
51
49
|
```
|
|
52
50
|
|
|
53
|
-
|
|
51
|
+
# Run tests
|
|
54
52
|
|
|
55
|
-
|
|
53
|
+
## On your machine
|
|
56
54
|
|
|
57
55
|
Once Koffi is built, you can build the tests and run them with the following commands:
|
|
58
56
|
|
|
@@ -63,7 +61,7 @@ node ../../cnoke/cnoke.js
|
|
|
63
61
|
node test.js
|
|
64
62
|
```
|
|
65
63
|
|
|
66
|
-
|
|
64
|
+
## On virtual machines
|
|
67
65
|
|
|
68
66
|
Koffi is tested on multiple architectures using emulated (accelerated when possible) QEMU machines. First, you need to install qemu packages, such as `qemu-system` (or even `qemu-system-gui`) on Ubuntu.
|
|
69
67
|
|
|
@@ -121,12 +119,12 @@ Each machine is configured to run a VNC server available locally, which you can
|
|
|
121
119
|
node qemu.js info debian_x64
|
|
122
120
|
```
|
|
123
121
|
|
|
124
|
-
|
|
122
|
+
# Making a release
|
|
125
123
|
|
|
126
124
|
First, you must update the code in three steps:
|
|
127
125
|
|
|
128
126
|
- Change the version numbers in `package.json` (version and stable for stable releases)
|
|
129
|
-
- Add an entry to `CHANGELOG
|
|
127
|
+
- Add an entry to `CHANGELOG` to summarize the changes since last release
|
|
130
128
|
- Commit theses changes with the message *Bump Koffi to X.Y.Z*
|
|
131
129
|
|
|
132
130
|
Once this is done, you can publish a new release with the following commands:
|
|
@@ -141,7 +139,7 @@ npm publish
|
|
|
141
139
|
|
|
142
140
|
Some platforms are emulated so this can take a few minutes until the pre-built binaries are ready. Go grab a cup of coffee, come back and execute the `npm publish` command!
|
|
143
141
|
|
|
144
|
-
|
|
142
|
+
# Code style
|
|
145
143
|
|
|
146
144
|
Koffi is programmed in a mix of C++ and assembly code (architecture-specific code). It uses [node-addon-api](https://github.com/nodejs/node-addon-api) (C++ N-API wrapper) to interact with Node.js.
|
|
147
145
|
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
## Loading libraries
|
|
1
|
+
# Loading libraries
|
|
4
2
|
|
|
5
3
|
To declare functions, start by loading the shared library with `koffi.load(filename)`.
|
|
6
4
|
|
|
@@ -15,11 +13,10 @@ This library will be automatically unloaded once all references to it are gone (
|
|
|
15
13
|
|
|
16
14
|
Starting with *Koffi 2.3.20*, you can explicitly unload a library by calling `lib.unload()`. Any attempt to find or call a function from this library after unloading it will crash.
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
On some platforms (such as with the [musl C library on Linux](https://wiki.musl-libc.org/functional-differences-from-glibc.html#Unloading-libraries)), shared libraries cannot be unloaded, so the library will remain loaded and memory mapped after the call to `lib.unload()`.
|
|
20
|
-
```
|
|
16
|
+
> [!NOTE]
|
|
17
|
+
> On some platforms (such as with the [musl C library on Linux](https://wiki.musl-libc.org/functional-differences-from-glibc.html#Unloading-libraries)), shared libraries cannot be unloaded, so the library will remain loaded and memory mapped after the call to `lib.unload()`.
|
|
21
18
|
|
|
22
|
-
|
|
19
|
+
# Loading options
|
|
23
20
|
|
|
24
21
|
*New in Koffi 2.6, changed in Koffi 2.8.2 and Koffi 2.8.6*
|
|
25
22
|
|
|
@@ -37,16 +34,16 @@ const lib = koffi.load('/path/to/shared/library.so', options);
|
|
|
37
34
|
|
|
38
35
|
More options may be added if needed.
|
|
39
36
|
|
|
40
|
-
|
|
37
|
+
# Function definitions
|
|
41
38
|
|
|
42
|
-
|
|
39
|
+
## Definition syntax
|
|
43
40
|
|
|
44
41
|
Use the object returned by `koffi.load()` to load C functions from the library. To do so, you can use two syntaxes:
|
|
45
42
|
|
|
46
43
|
- The classic syntax, inspired by node-ffi
|
|
47
44
|
- C-like prototypes
|
|
48
45
|
|
|
49
|
-
|
|
46
|
+
### Classic syntax
|
|
50
47
|
|
|
51
48
|
To declare a function, you need to specify its non-mangled name, its return type, and its parameters. Use an ellipsis as the last parameter for variadic functions.
|
|
52
49
|
|
|
@@ -57,7 +54,7 @@ const atoi = lib.func('atoi', 'int', ['str']);
|
|
|
57
54
|
|
|
58
55
|
Koffi automatically tries mangled names for non-standard x86 calling conventions. See the section on [calling conventions](#calling-conventions) for more information on this subject.
|
|
59
56
|
|
|
60
|
-
|
|
57
|
+
### C-like prototypes
|
|
61
58
|
|
|
62
59
|
If you prefer, you can declare functions using simple C-like prototype strings, as shown below:
|
|
63
60
|
|
|
@@ -68,7 +65,7 @@ const atoi = lib.func('int atoi(str)'); // The parameter name is not used by Kof
|
|
|
68
65
|
|
|
69
66
|
You can use `()` or `(void)` for functions that take no argument.
|
|
70
67
|
|
|
71
|
-
|
|
68
|
+
## Variadic functions
|
|
72
69
|
|
|
73
70
|
Variadic functions are declared with an ellipsis as the last argument.
|
|
74
71
|
|
|
@@ -83,7 +80,7 @@ printf('Integer %d, double %g, str %s', 'int', 6, 'double', 8.5, 'str', 'THE END
|
|
|
83
80
|
|
|
84
81
|
On x86 platforms, only the Cdecl convention can be used for variadic functions.
|
|
85
82
|
|
|
86
|
-
|
|
83
|
+
## Calling conventions
|
|
87
84
|
|
|
88
85
|
*Changed in Koffi 2.7*
|
|
89
86
|
|
|
@@ -100,11 +97,10 @@ Most architectures only support one procedure call standard per process. The 32-
|
|
|
100
97
|
|
|
101
98
|
You can safely use these on non-x86 platforms, they are simply ignored.
|
|
102
99
|
|
|
103
|
-
|
|
104
|
-
Support for specifying the convention as the first argument of the classic form was introduced in Koffi 2.7.
|
|
105
|
-
|
|
106
|
-
In earlier versions, you had to use `koffi.stdcall()` and similar functions. These functions are still supported but deprecated, and will be removed in Koffi 3.0.
|
|
107
|
-
```
|
|
100
|
+
> [!NOTE]
|
|
101
|
+
> Support for specifying the convention as the first argument of the classic form was introduced in Koffi 2.7.
|
|
102
|
+
>
|
|
103
|
+
> In earlier versions, you had to use `koffi.stdcall()` and similar functions. These functions are still supported but deprecated, and will be removed in Koffi 3.0.
|
|
108
104
|
|
|
109
105
|
Below you can find a small example showing how to use a non-default calling convention, with the two syntaxes:
|
|
110
106
|
|
|
@@ -119,9 +115,9 @@ const MessageBoxA_1 = lib.func('__stdcall', 'MessageBoxA', 'int', ['void *', 'st
|
|
|
119
115
|
const MessageBoxA_2 = lib.func('int __stdcall MessageBoxA(void *hwnd, str text, str caption, uint type)');
|
|
120
116
|
```
|
|
121
117
|
|
|
122
|
-
|
|
118
|
+
# Call types
|
|
123
119
|
|
|
124
|
-
|
|
120
|
+
## Synchronous calls
|
|
125
121
|
|
|
126
122
|
Once a native function has been declared, you can simply call it as you would any other JS function.
|
|
127
123
|
|
|
@@ -132,7 +128,7 @@ let value = atoi('1257');
|
|
|
132
128
|
console.log(value);
|
|
133
129
|
```
|
|
134
130
|
|
|
135
|
-
For [variadic functions](functions
|
|
131
|
+
For [variadic functions](functions#variadic-functions), you msut specificy the type and the value for each additional argument.
|
|
136
132
|
|
|
137
133
|
```js
|
|
138
134
|
const printf = lib.func('printf', 'int', ['str', '...']);
|
|
@@ -141,7 +137,7 @@ const printf = lib.func('printf', 'int', ['str', '...']);
|
|
|
141
137
|
printf('Integer %d, double %g, str %s', 'int', 6, 'double', 8.5, 'str', 'THE END');
|
|
142
138
|
```
|
|
143
139
|
|
|
144
|
-
|
|
140
|
+
## Asynchronous calls
|
|
145
141
|
|
|
146
142
|
You can issue asynchronous calls by calling the function through its async member. In this case, you need to provide a callback function as the last argument, with `(err, res)` parameters.
|
|
147
143
|
|
|
@@ -169,13 +165,12 @@ You can easily convert this callback-style async function to a promise-based ver
|
|
|
169
165
|
|
|
170
166
|
Variadic functions cannot be called asynchronously.
|
|
171
167
|
|
|
172
|
-
|
|
173
|
-
Asynchronous functions run on worker threads. You need to deal with thread safety issues if you share data between threads.
|
|
174
|
-
|
|
175
|
-
Callbacks must be called from the main thread, or more precisely from the same thread as the V8 intepreter. Calling a callback from another thread is undefined behavior, and will likely lead to a crash or a big mess. You've been warned!
|
|
176
|
-
```
|
|
168
|
+
> [!WARNING]
|
|
169
|
+
> Asynchronous functions run on worker threads. You need to deal with thread safety issues if you share data between threads.
|
|
170
|
+
>
|
|
171
|
+
> Callbacks must be called from the main thread, or more precisely from the same thread as the V8 intepreter. Calling a callback from another thread is undefined behavior, and will likely lead to a crash or a big mess. You've been warned!
|
|
177
172
|
|
|
178
|
-
|
|
173
|
+
# Function pointers
|
|
179
174
|
|
|
180
175
|
*New in Koffi 2.4*
|
|
181
176
|
|
|
@@ -204,7 +199,7 @@ BinaryIntFunc *GetBinaryIntFunction(const char *type)
|
|
|
204
199
|
}
|
|
205
200
|
```
|
|
206
201
|
|
|
207
|
-
|
|
202
|
+
## Call pointer directly
|
|
208
203
|
|
|
209
204
|
Use `koffi.call(ptr, type, ...)` to call a function pointer. The first two arguments are the pointer itself and the type of the function you are trying to call (declared with `koffi.proto()` as shown below), and the remaining arguments are used for the call.
|
|
210
205
|
|
|
@@ -223,7 +218,7 @@ let delta = koffi.call(substract_ptr, BinaryIntFunc, 100, 58);
|
|
|
223
218
|
console.log(sum, delta); // Prints 9 and 42
|
|
224
219
|
```
|
|
225
220
|
|
|
226
|
-
|
|
221
|
+
## Decode pointer to function
|
|
227
222
|
|
|
228
223
|
Use `koffi.decode(ptr, type)` to get back a JS function, which you can then use like any other Koffi function.
|
|
229
224
|
|
|
@@ -244,12 +239,12 @@ let delta = substract(100, 58);
|
|
|
244
239
|
console.log(sum, delta); // Prints 9 and 42
|
|
245
240
|
```
|
|
246
241
|
|
|
247
|
-
|
|
242
|
+
# Conversion of parameters
|
|
248
243
|
|
|
249
244
|
By default, Koffi will only forward and translate arguments from Javascript to C. However, many C functions use pointer arguments for output values, or input/output values.
|
|
250
245
|
|
|
251
246
|
Among other thing, in the the following pages you will learn more about:
|
|
252
247
|
|
|
253
|
-
- How Koffi translates [input parameters](input
|
|
254
|
-
- How you can [define and use pointers](pointers
|
|
255
|
-
- How to deal with [output parameters](output
|
|
248
|
+
- How Koffi translates [input parameters](input) to C
|
|
249
|
+
- How you can [define and use pointers](pointers)
|
|
250
|
+
- How to deal with [output parameters](output)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Koffi
|
|
2
|
+
|
|
3
|
+
Koffi is a **fast and easy-to-use C FFI module for Node.js**, featuring:
|
|
4
|
+
|
|
5
|
+
* Low-overhead and fast performance (see [benchmarks](benchmarks))
|
|
6
|
+
* Support for primitive and aggregate data types (structs and fixed-size arrays), both by reference (pointer) and by value
|
|
7
|
+
* Javascript functions can be used as C callbacks (since 1.2.0)
|
|
8
|
+
* Well-tested code base for [popular OS/architecture combinations](platforms)
|
|
9
|
+
|
|
10
|
+
Koffi requires a recent [Node.js](https://nodejs.org/) version with N-API version 8 support, see [this page](platforms) for more information.
|
|
11
|
+
|
|
12
|
+
The source code is available here: https://github.com/Koromix/rygel/ (in the *src/koffi* subdirectory).
|
|
13
|
+
|
|
14
|
+
New releases are frequent, look at the [changelog](changelog) for more information.
|
|
15
|
+
|
|
16
|
+
# License
|
|
17
|
+
|
|
18
|
+
This program is free software: you can redistribute it and/or modify it under the terms of the **MIT License**.
|
|
19
|
+
|
|
20
|
+
Find more information here: https://choosealicense.com/licenses/mit/
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Primitive types
|
|
2
2
|
|
|
3
|
-
##
|
|
4
|
-
|
|
5
|
-
### Standard types
|
|
3
|
+
## Standard types
|
|
6
4
|
|
|
7
5
|
While the C standard allows for variation in the size of most integer types, Koffi enforces the same definition for most primitive types, listed below:
|
|
8
6
|
|
|
@@ -59,7 +57,7 @@ let struct1 = koffi.struct({ dummy: 'long' });
|
|
|
59
57
|
let struct2 = koffi.struct({ dummy: koffi.types.long });
|
|
60
58
|
```
|
|
61
59
|
|
|
62
|
-
|
|
60
|
+
## Endian-sensitive integers
|
|
63
61
|
|
|
64
62
|
*New in Koffi 2.1*
|
|
65
63
|
|
|
@@ -80,9 +78,9 @@ int64_be, int64_be_t | 8 | Signed | Big Endian
|
|
|
80
78
|
uint64_le, uint64_le_t | 8 | Unsigned | Little Endian
|
|
81
79
|
uint64_be, uint64_be_t | 8 | Unsigned | Big Endian
|
|
82
80
|
|
|
83
|
-
|
|
81
|
+
# Struct types
|
|
84
82
|
|
|
85
|
-
|
|
83
|
+
## Struct definition
|
|
86
84
|
|
|
87
85
|
Koffi converts JS objects to C structs, and vice-versa.
|
|
88
86
|
|
|
@@ -141,23 +139,22 @@ const Function1 = lib.func('A Function(A value)');
|
|
|
141
139
|
const Function2 = lib.func('Function', A, [A]);
|
|
142
140
|
```
|
|
143
141
|
|
|
144
|
-
|
|
142
|
+
## Opaque types
|
|
145
143
|
|
|
146
144
|
Many C libraries use some kind of object-oriented API, with a pair of functions dedicated to create and delete objects. An obvious example of this can be found in stdio.h, with the opaque `FILE *` pointer. You can open and close files with `fopen()` and `fclose()`, and manipule the opaque pointer with other functions such as `fread()` or `ftell()`.
|
|
147
145
|
|
|
148
|
-
In Koffi, you can manage this with opaque types. Declare the opaque type with `koffi.opaque(name)`, and use a pointer to this type either as a return type or some kind of [output parameter](output
|
|
149
|
-
|
|
150
|
-
```{note}
|
|
151
|
-
Opaque types **have changed in version 2.0, and again in version 2.1**.
|
|
152
|
-
|
|
153
|
-
In Koffi 1.x, opaque handles were defined in a way that made them usable directly as parameter and return types, obscuring the underlying pointer.
|
|
154
|
-
|
|
155
|
-
Now, you must use them through a pointer, and use an array for output parameters. This is shown in the example below (look for the call to `ConcatNewOut` in the JS part), and is described in the section on [output parameters](output.md).
|
|
146
|
+
In Koffi, you can manage this with opaque types. Declare the opaque type with `koffi.opaque(name)`, and use a pointer to this type either as a return type or some kind of [output parameter](output) (with a double pointer).
|
|
156
147
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
148
|
+
> [!NOTE]
|
|
149
|
+
> Opaque types **have changed in version 2.0, and again in version 2.1**.
|
|
150
|
+
>
|
|
151
|
+
> In Koffi 1.x, opaque handles were defined in a way that made them usable directly as parameter and return types, obscuring the underlying pointer.
|
|
152
|
+
>
|
|
153
|
+
> Now, you must use them through a pointer, and use an array for output parameters. This is shown in the example below (look for the call to `ConcatNewOut` in the JS part), and is described in the section on [output parameters](output).
|
|
154
|
+
>
|
|
155
|
+
> In addition to this, you should use `koffi.opaque()` (introduced in Koffi 2.1) instead of `koffi.handle()` which is deprecated, and will be removed eventually in Koffi 3.0.
|
|
156
|
+
>
|
|
157
|
+
> Consult the [migration guide](migration) for more information.
|
|
161
158
|
|
|
162
159
|
The full example below implements an iterative string builder (concatenator) in C, and uses it from Javascript to output a mix of Hello World and FizzBuzz. The builder is hidden behind an opaque type, and is created and destroyed using a pair of C functions: `ConcatNew` (or `ConcatNewOut`) and `ConcatFree`.
|
|
163
160
|
|
|
@@ -335,9 +332,9 @@ try {
|
|
|
335
332
|
}
|
|
336
333
|
```
|
|
337
334
|
|
|
338
|
-
|
|
335
|
+
# Array types
|
|
339
336
|
|
|
340
|
-
|
|
337
|
+
## Fixed-size C arrays
|
|
341
338
|
|
|
342
339
|
*Changed in Koffi 2.7.1*
|
|
343
340
|
|
|
@@ -381,11 +378,10 @@ const StructType = koffi.struct('StructType', {
|
|
|
381
378
|
});
|
|
382
379
|
```
|
|
383
380
|
|
|
384
|
-
|
|
385
|
-
The short C-like syntax was introduced in Koffi 2.7.1, use `koffi.array()` for older versions.
|
|
386
|
-
```
|
|
381
|
+
> [!NOTE]
|
|
382
|
+
> The short C-like syntax was introduced in Koffi 2.7.1, use `koffi.array()` for older versions.
|
|
387
383
|
|
|
388
|
-
|
|
384
|
+
## Fixed-size string buffers
|
|
389
385
|
|
|
390
386
|
*Changed in Koffi 2.9.0*
|
|
391
387
|
|
|
@@ -395,16 +391,15 @@ Koffi can also convert JS strings to fixed-sized arrays in the following cases:
|
|
|
395
391
|
- **char16 (or char16_t) arrays** are filled with the UTF-16 encoded string, truncated if needed. The buffer is always NUL-terminated.
|
|
396
392
|
- **char32 (or char32_t) arrays** are filled with the UTF-32 encoded string, truncated if needed. The buffer is always NUL-terminated.
|
|
397
393
|
|
|
398
|
-
|
|
399
|
-
Support for UTF-32 and wchar_t (wide) strings was introduced in Koffi 2.9.0.
|
|
400
|
-
```
|
|
394
|
+
> [!NOTE]
|
|
395
|
+
> Support for UTF-32 and wchar_t (wide) strings was introduced in Koffi 2.9.0.
|
|
401
396
|
|
|
402
397
|
The reverse case is also true, Koffi can convert a C fixed-size buffer to a JS string. This happens by default for char, char16_t and char32_t arrays, but you can also explicitly ask for this with the `String` array hint (e.g. `koffi.array('char', 8, 'String')`).
|
|
403
398
|
|
|
404
|
-
|
|
399
|
+
## Dynamic arrays (pointers)
|
|
405
400
|
|
|
406
|
-
In C, dynamically-sized arrays are usually passed around as pointers. Read more about [array pointers](pointers
|
|
401
|
+
In C, dynamically-sized arrays are usually passed around as pointers. Read more about [array pointers](pointers#dynamic-arrays) in the relevant section.
|
|
407
402
|
|
|
408
|
-
|
|
403
|
+
# Union types
|
|
409
404
|
|
|
410
|
-
The declaration and use of [
|
|
405
|
+
The declaration and use of [union types](unions) will be explained in a later section, they are only briefly mentioned here if you need them.
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
## Koffi 1.x to 2.x
|
|
1
|
+
# Koffi 1.x to 2.x
|
|
4
2
|
|
|
5
3
|
The API was changed in 2.x in a few ways, in order to reduce some excessively "magic" behavior and reduce the syntax differences between C and the C-like prototypes.
|
|
6
4
|
|
|
@@ -10,7 +8,7 @@ You may need to change your code if you use:
|
|
|
10
8
|
- Opaque types
|
|
11
9
|
- `koffi.introspect()`
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
## Callback type changes
|
|
14
12
|
|
|
15
13
|
In Koffi 1.x, callbacks were defined in a way that made them usable directly as parameter and return types, obscuring the underlying pointer. Now, you must use them through a pointer: `void CallIt(CallbackType func)` in Koffi 1.x becomes `void CallIt(CallbackType *func)` in version 2.0 and newer.
|
|
16
14
|
|
|
@@ -61,13 +59,12 @@ let ret = TransferToJS('Niels', 27, (str, age) => {
|
|
|
61
59
|
console.log(ret);
|
|
62
60
|
```
|
|
63
61
|
|
|
64
|
-
Koffi 1.x only supported [transient callbacks](callbacks
|
|
62
|
+
Koffi 1.x only supported [transient callbacks](callbacks#javascript-callbacks), you must use Koffi 2.x for registered callbacks.
|
|
65
63
|
|
|
66
|
-
|
|
67
|
-
The function `koffi.proto()` was introduced in Koffi 2.4, it was called `koffi.callback()` in earlier versions.
|
|
68
|
-
```
|
|
64
|
+
> [!NOTE]
|
|
65
|
+
> The function `koffi.proto()` was introduced in Koffi 2.4, it was called `koffi.callback()` in earlier versions.
|
|
69
66
|
|
|
70
|
-
|
|
67
|
+
## Opaque type changes
|
|
71
68
|
|
|
72
69
|
In Koffi 1.x, opaque handles were defined in a way that made them usable directly as parameter and return types, obscuring the underlying pointer. Now, in Koffi 2.0, you must use them through a pointer, and use an array for output parameters.
|
|
73
70
|
|
|
@@ -145,7 +142,7 @@ db = ptr[0];
|
|
|
145
142
|
sqlite3_close_v2(db);
|
|
146
143
|
```
|
|
147
144
|
|
|
148
|
-
|
|
145
|
+
## New koffi.introspect()
|
|
149
146
|
|
|
150
147
|
In Koffi 1.x, `koffi.introspect()` would only work with struct types, and return the object passed to `koffi.struct()` to initialize the type. Now this function works with all types.
|
|
151
148
|
|
|
@@ -1,20 +1,17 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Types
|
|
2
2
|
|
|
3
|
-
##
|
|
4
|
-
|
|
5
|
-
### Introspection
|
|
3
|
+
## Introspection
|
|
6
4
|
|
|
7
5
|
*New in Koffi 2.0: `koffi.resolve()`, new in Koffi 2.2: `koffi.offsetof()`*
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
The value returned by `introspect()` has **changed in version 2.0 and in version 2.2**.
|
|
11
|
-
|
|
12
|
-
In Koffi 1.x, it could only be used with struct types and returned the object passed to koffi.struct() with the member names and types.
|
|
13
|
-
|
|
14
|
-
Starting in Koffi 2.2, each record member is exposed as an object containing the name, the type and the offset within the record.
|
|
15
|
-
|
|
16
|
-
Consult the [migration guide](migration
|
|
17
|
-
```
|
|
7
|
+
> [!NOTE]
|
|
8
|
+
> The value returned by `introspect()` has **changed in version 2.0 and in version 2.2**.
|
|
9
|
+
>
|
|
10
|
+
> In Koffi 1.x, it could only be used with struct types and returned the object passed to koffi.struct() with the member names and types.
|
|
11
|
+
>
|
|
12
|
+
> Starting in Koffi 2.2, each record member is exposed as an object containing the name, the type and the offset within the record.
|
|
13
|
+
>
|
|
14
|
+
> Consult the [migration guide](migration) for more information.
|
|
18
15
|
|
|
19
16
|
Use `koffi.introspect(type)` to get detailed information about a type: name, primitive, size, alignment, members (record types), reference type (array, pointer) and length (array).
|
|
20
17
|
|
|
@@ -56,15 +53,50 @@ console.log(koffi.sizeof('long'));
|
|
|
56
53
|
console.log(koffi.sizeof(koffi.types.long));
|
|
57
54
|
```
|
|
58
55
|
|
|
59
|
-
|
|
56
|
+
## Aliases
|
|
60
57
|
|
|
61
58
|
*New in Koffi 2.0*
|
|
62
59
|
|
|
63
60
|
You can alias a type with `koffi.alias(name, type)`. Aliased types are completely equivalent.
|
|
64
61
|
|
|
65
|
-
##
|
|
62
|
+
## Circular references
|
|
63
|
+
|
|
64
|
+
*New in Koffi 2.10.0*
|
|
65
|
+
|
|
66
|
+
In some cases, composite types can point to each other and thus depend on each other. This can also happen when a function takes a pointer to a struct that also contains a function pointer.
|
|
67
|
+
|
|
68
|
+
To deal with this, you can create an opaque type and redefine it later to a concrete struct or union type, as shown below.
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
const Type1 = koffi.opaque('Type1');
|
|
72
|
+
|
|
73
|
+
const Type2 = koffi.struct('Type2', {
|
|
74
|
+
ptr: 'Type1 *',
|
|
75
|
+
i: 'int'
|
|
76
|
+
});
|
|
66
77
|
|
|
67
|
-
|
|
78
|
+
// Redefine Type1 to a concrete type
|
|
79
|
+
koffi.struct(Type1, {
|
|
80
|
+
ptr: 'Type2 *',
|
|
81
|
+
f: 'float'
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
> [!NOTE]
|
|
86
|
+
> You must use a proper type object when you redefine the type. If you only have the name, use `koffi.resolve()` to get a type object from a type string.
|
|
87
|
+
>
|
|
88
|
+
> ```js
|
|
89
|
+
> const MyType = koffi.opaque('MyType');
|
|
90
|
+
>
|
|
91
|
+
> // This does not work, you must use the MyType object and not a type string
|
|
92
|
+
> koffi.struct('MyType', {
|
|
93
|
+
> ptr: 'Type2 *',
|
|
94
|
+
> f: 'float'
|
|
95
|
+
> });
|
|
96
|
+
|
|
97
|
+
# Settings
|
|
98
|
+
|
|
99
|
+
## Memory usage
|
|
68
100
|
|
|
69
101
|
For synchronous/normal calls, Koffi uses two preallocated memory blocks:
|
|
70
102
|
|
|
@@ -84,7 +116,7 @@ The same is true for asynchronous calls. When an asynchronous call is made, Koff
|
|
|
84
116
|
|
|
85
117
|
There cannot be more than `max_async_calls` running at the same time.
|
|
86
118
|
|
|
87
|
-
|
|
119
|
+
## Default settings
|
|
88
120
|
|
|
89
121
|
Setting | Default | Description
|
|
90
122
|
-------------------- | ------- | -----------------------------------------------
|
|
@@ -96,13 +128,13 @@ resident_async_pools | 2 | Number of resident pools for asynchronous calls
|
|
|
96
128
|
max_async_calls | 64 | Maximum number of ongoing asynchronous calls
|
|
97
129
|
max_type_size | 64 MiB | Maximum size of Koffi types (for arrays and structs)
|
|
98
130
|
|
|
99
|
-
|
|
131
|
+
# Usage statistics
|
|
100
132
|
|
|
101
133
|
*New in Koffi 2.3.2*
|
|
102
134
|
|
|
103
135
|
You can use `koffi.stats()` to get a few statistics related to Koffi.
|
|
104
136
|
|
|
105
|
-
|
|
137
|
+
# POSIX error codes
|
|
106
138
|
|
|
107
139
|
*New in Koffi 2.3.14*
|
|
108
140
|
|
|
@@ -126,7 +158,7 @@ assert.equal(koffi.errno(), koffi.os.errno.EBADF);
|
|
|
126
158
|
console.log('close() with invalid FD is POSIX compliant!');
|
|
127
159
|
```
|
|
128
160
|
|
|
129
|
-
|
|
161
|
+
# Reset internal state
|
|
130
162
|
|
|
131
163
|
*New in Koffi 2.5.19*
|
|
132
164
|
|
|
@@ -137,6 +169,5 @@ You can use `koffi.reset()` to clear some Koffi internal state such as:
|
|
|
137
169
|
|
|
138
170
|
This function is mainly intended for test code, when you execute the same code over and over and you need to reuse type names.
|
|
139
171
|
|
|
140
|
-
|
|
141
|
-
Trying to use a function or a type that was initially defined before the reset is undefined behavior and will likely lead to a crash!
|
|
142
|
-
```
|
|
172
|
+
> [!WARNING]
|
|
173
|
+
> Trying to use a function or a type that was initially defined before the reset is undefined behavior and will likely lead to a crash!
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
# Output
|
|
2
|
-
|
|
3
|
-
## Output and input/output
|
|
1
|
+
# Output and input/output
|
|
4
2
|
|
|
5
3
|
For simplicity, and because Javascript only has value semantics for primitive types, Koffi can marshal out (or in/out) multiple types of parameters:
|
|
6
4
|
|
|
7
|
-
- [Structs](input
|
|
8
|
-
- [Unions](unions
|
|
9
|
-
- [Opaque types](input
|
|
5
|
+
- [Structs](input#struct-types) (to/from JS objects)
|
|
6
|
+
- [Unions](unions)
|
|
7
|
+
- [Opaque types](input#opaque-types)
|
|
10
8
|
- String buffers
|
|
11
9
|
|
|
12
10
|
In order to change an argument from input-only to output or input/output, use the following functions:
|
|
@@ -19,7 +17,7 @@ The same can be done when declaring a function with a C-like prototype string, w
|
|
|
19
17
|
- `_Out_` for output parameters
|
|
20
18
|
- `_Inout_` for dual input/output parameters
|
|
21
19
|
|
|
22
|
-
|
|
20
|
+
## Primitive value
|
|
23
21
|
|
|
24
22
|
This Windows example enumerate all Chrome windows along with their PID and their title. The `GetWindowThreadProcessId()` function illustrates how to get a primitive value from an output argument.
|
|
25
23
|
|
|
@@ -75,7 +73,7 @@ for (let hwnd = null;;) {
|
|
|
75
73
|
}
|
|
76
74
|
```
|
|
77
75
|
|
|
78
|
-
|
|
76
|
+
## Struct example
|
|
79
77
|
|
|
80
78
|
This example calls the POSIX function `gettimeofday()`, and uses the prototype-like syntax.
|
|
81
79
|
|
|
@@ -103,7 +101,7 @@ gettimeofday(tv, null);
|
|
|
103
101
|
console.log(tv);
|
|
104
102
|
```
|
|
105
103
|
|
|
106
|
-
|
|
104
|
+
## Opaque type example
|
|
107
105
|
|
|
108
106
|
This example opens an in-memory SQLite database, and uses the node-ffi-style function declaration syntax.
|
|
109
107
|
|
|
@@ -130,7 +128,7 @@ let db = out[0];
|
|
|
130
128
|
sqlite3_close_v2(db);
|
|
131
129
|
```
|
|
132
130
|
|
|
133
|
-
|
|
131
|
+
## String buffer example
|
|
134
132
|
|
|
135
133
|
*New in Koffi 2.2*
|
|
136
134
|
|
|
@@ -168,17 +166,16 @@ ConcatToBuffer(str1, str2, out);
|
|
|
168
166
|
console.log(out[0]);
|
|
169
167
|
```
|
|
170
168
|
|
|
171
|
-
|
|
169
|
+
# Output buffers
|
|
172
170
|
|
|
173
171
|
In most cases, you can use buffers and typed arrays to provide output buffers. This works as long as the buffer only gets used while the native C function is being called. See [transient pointers](#transient-pointers) below for an example.
|
|
174
172
|
|
|
175
|
-
|
|
176
|
-
It is unsafe to keep the pointer around in the native code, or to change the contents outside of the function call where it is provided.
|
|
177
|
-
|
|
178
|
-
If you need to provide a pointer that will be kept around, allocate memory with [koffi.alloc()](#stable-pointers) instead.
|
|
179
|
-
```
|
|
173
|
+
> [!WARNING]
|
|
174
|
+
> It is unsafe to keep the pointer around in the native code, or to change the contents outside of the function call where it is provided.
|
|
175
|
+
>
|
|
176
|
+
> If you need to provide a pointer that will be kept around, allocate memory with [koffi.alloc()](#stable-pointers) instead.
|
|
180
177
|
|
|
181
|
-
|
|
178
|
+
## Transient pointers
|
|
182
179
|
|
|
183
180
|
*New in Koffi 2.3*
|
|
184
181
|
|
|
@@ -220,9 +217,9 @@ console.log(vec1); // { x: 3, y: 2, z: 1 }
|
|
|
220
217
|
console.log(vec2); // { x: 1, y: 2, z: 3 }
|
|
221
218
|
```
|
|
222
219
|
|
|
223
|
-
See [decoding variables](variables
|
|
220
|
+
See [decoding variables](variables#decode-to-js-values) for more information about the decode function.
|
|
224
221
|
|
|
225
|
-
|
|
222
|
+
## Stable pointers
|
|
226
223
|
|
|
227
224
|
*New in Koffi 2.8*
|
|
228
225
|
|
|
@@ -230,7 +227,7 @@ In some cases, the native code may need to change the output buffer at a later t
|
|
|
230
227
|
|
|
231
228
|
In this case, it is **not safe to use buffers or typed arrays**!
|
|
232
229
|
|
|
233
|
-
However, you can use `koffi.alloc(type, len)` to allocate memory and get a pointer that won't move, and can be safely used at any time by the native code. Use [koffi.decode()](variables
|
|
230
|
+
However, you can use `koffi.alloc(type, len)` to allocate memory and get a pointer that won't move, and can be safely used at any time by the native code. Use [koffi.decode()](variables#decode-to-js-values) to read data from the pointer when needed.
|
|
234
231
|
|
|
235
232
|
The example below sets up some memory to be used as an output buffer where a concatenation function appends a string on each call.
|
|
236
233
|
|