koffi 1.3.5 → 1.3.8
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/CMakeLists.txt +1 -1
- package/ChangeLog.md +36 -0
- package/benchmark/atoi_koffi.js +3 -4
- package/benchmark/atoi_napi.js +2 -3
- package/benchmark/atoi_node_ffi.js +3 -4
- package/benchmark/raylib_cc.cc +3 -4
- package/benchmark/raylib_cc.js +31 -0
- package/benchmark/raylib_koffi.js +8 -9
- package/benchmark/raylib_node_ffi.js +4 -5
- package/benchmark/raylib_node_raylib.js +4 -5
- package/build/qemu/1.3.8/koffi_darwin_arm64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_linux_arm32hf.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_openbsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_win32_arm64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_win32_x64.tar.gz +0 -0
- package/doc/_static/perf_linux_20220627.png +0 -0
- package/doc/_static/perf_linux_20220628.png +0 -0
- package/doc/_static/perf_windows_20220627.png +0 -0
- package/doc/_static/perf_windows_20220628.png +0 -0
- package/doc/benchmarks.md +78 -58
- package/doc/benchmarks.xlsx +0 -0
- package/doc/conf.py +1 -1
- package/doc/contribute.md +8 -11
- package/doc/dist/html/_sources/benchmarks.md.txt +78 -58
- package/doc/dist/html/_sources/contribute.md.txt +8 -11
- package/doc/dist/html/_sources/functions.md.txt +9 -8
- package/doc/dist/html/_sources/index.rst.txt +3 -0
- package/doc/dist/html/_sources/platforms.md.txt +17 -5
- package/doc/dist/html/_sources/start.md.txt +14 -3
- package/doc/dist/html/_sources/types.md.txt +15 -11
- package/doc/dist/html/_static/basic.css +12 -14
- package/doc/dist/html/_static/perf_linux_20220627.png +0 -0
- package/doc/dist/html/_static/perf_linux_20220628.png +0 -0
- package/doc/dist/html/_static/perf_windows_20220627.png +0 -0
- package/doc/dist/html/_static/perf_windows_20220628.png +0 -0
- package/doc/dist/html/benchmarks.html +148 -159
- package/doc/dist/html/changes.html +44 -2
- package/doc/dist/html/contribute.html +30 -33
- package/doc/dist/html/functions.html +19 -18
- package/doc/dist/html/genindex.html +2 -2
- package/doc/dist/html/index.html +19 -10
- package/doc/dist/html/memory.html +2 -2
- package/doc/dist/html/objects.inv +0 -0
- package/doc/dist/html/platforms.html +44 -10
- package/doc/dist/html/search.html +2 -2
- package/doc/dist/html/searchindex.js +1 -1
- package/doc/dist/html/start.html +25 -12
- package/doc/dist/html/types.html +31 -11
- package/doc/functions.md +9 -8
- package/doc/index.rst +3 -0
- package/doc/platforms.md +17 -5
- package/doc/start.md +14 -3
- package/doc/types.md +15 -11
- package/package.json +7 -4
- package/qemu/qemu.js +30 -19
- package/qemu/registry/machines.json +19 -19
- package/qemu/registry/sha256sum.txt +5 -5
- package/src/abi_arm32.cc +9 -2
- package/src/abi_arm32_fwd.S +7 -7
- package/src/abi_arm64.cc +9 -2
- package/src/abi_arm64_fwd.S +11 -7
- package/src/abi_arm64_fwd.asm +7 -7
- package/src/abi_riscv64.cc +9 -2
- package/src/abi_riscv64_fwd.S +11 -11
- package/src/abi_x64_sysv.cc +9 -2
- package/src/abi_x64_sysv_fwd.S +11 -11
- package/src/abi_x64_win.cc +9 -2
- package/src/abi_x64_win_fwd.asm +7 -7
- package/src/abi_x86.cc +9 -2
- package/src/abi_x86_fwd.S +3 -0
- package/src/abi_x86_fwd.asm +3 -0
- package/src/call.cc +20 -10
- package/src/ffi.cc +17 -8
- package/src/ffi.hh +4 -3
- package/src/util.cc +1 -1
- package/test/async.js +1 -1
- package/test/callbacks.js +25 -2
- package/test/misc.c +57 -2
- package/test/raylib.js +4 -4
- package/test/sqlite.js +5 -5
- package/test/sync.js +22 -7
- package/build/qemu/1.3.5/koffi_darwin_arm64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_linux_arm32hf.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_openbsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_win32_arm64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_win32_x64.tar.gz +0 -0
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Benchmarks
|
|
2
2
|
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
3
5
|
Here is a quick overview of the execution time of Koffi calls on three benchmarks, where it is compared to a theoretical ideal FFI implementation (approximated with pre-compiled static N-API glue code):
|
|
4
6
|
|
|
5
7
|
- The first benchmark is based on `rand()` calls
|
|
@@ -8,14 +10,18 @@ Here is a quick overview of the execution time of Koffi calls on three benchmark
|
|
|
8
10
|
|
|
9
11
|
<table style="margin: 0 auto;">
|
|
10
12
|
<tr>
|
|
11
|
-
<td><a href="_static/
|
|
12
|
-
<td><a href="_static/
|
|
13
|
+
<td><a href="_static/perf_linux_20220628.png" target="_blank"><img src="_static/perf_linux_20220628.png" alt="Linux performance" style="width: 350px;"/></a></td>
|
|
14
|
+
<td><a href="_static/perf_windows_20220628.png" target="_blank"><img src="_static/perf_windows_20220628.png" alt="Windows performance" style="width: 350px;"/></a></td>
|
|
13
15
|
</tr>
|
|
14
16
|
</table>
|
|
15
17
|
|
|
16
18
|
These results are detailed and explained below, and compared to node-ffi/node-ffi-napi.
|
|
17
19
|
|
|
18
|
-
##
|
|
20
|
+
## Linux x86_64
|
|
21
|
+
|
|
22
|
+
The results presented below were measured on my x86_64 Linux machine (Intel® Core™ i5-4460).
|
|
23
|
+
|
|
24
|
+
### rand results
|
|
19
25
|
|
|
20
26
|
This test is based around repeated calls to a simple standard C function atoi, and has three implementations:
|
|
21
27
|
|
|
@@ -23,95 +29,109 @@ This test is based around repeated calls to a simple standard C function atoi, a
|
|
|
23
29
|
- the second one calls atoi through Koffi
|
|
24
30
|
- the third one uses the official Node.js FFI implementation, node-ffi-napi
|
|
25
31
|
|
|
32
|
+
Benchmark | Iteration time | Relative performance | Overhead
|
|
33
|
+
------------- | -------------- | -------------------- | --------
|
|
34
|
+
rand_napi | 644 ns | x1.00 | (ref)
|
|
35
|
+
rand_koffi | 950 ns | x0.68 | +48%
|
|
36
|
+
rand_node_ffi | 30350 ns | x0.02 | +4613%
|
|
37
|
+
|
|
26
38
|
Because rand is a pretty small function, the FFI overhead is clearly visible.
|
|
27
39
|
|
|
28
|
-
###
|
|
40
|
+
### atoi results
|
|
29
41
|
|
|
30
|
-
|
|
42
|
+
This test is similar to the rand one, but it is based on atoi, which takes a string parameter. Javascript (V8) to C string conversion is relatively slow and heavy.
|
|
31
43
|
|
|
32
|
-
Benchmark |
|
|
33
|
-
------------- |
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
44
|
+
Benchmark | Iteration time | Relative performance | Overhead
|
|
45
|
+
------------- | -------------- | -------------------- | --------
|
|
46
|
+
atoi_napi | 1104 ns | x1.00 | (ref)
|
|
47
|
+
atoi_koffi | 1778 ns | x0.62 | +61%
|
|
48
|
+
atoi_node_ffi | 125300 ns | x0.009 | +11250%
|
|
37
49
|
|
|
38
|
-
|
|
50
|
+
Because atoi is a pretty small function, the FFI overhead is clearly visible.
|
|
39
51
|
|
|
40
|
-
|
|
52
|
+
### Raylib results
|
|
53
|
+
|
|
54
|
+
This benchmark uses the CPU-based image drawing functions in Raylib. The calls are much heavier than in the atoi benchmark, thus the FFI overhead is reduced. In this implementation, Koffi is compared to:
|
|
41
55
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
rand_napi | 20000000 | 2.10s | (baseline) | (baseline)
|
|
45
|
-
rand_koffi | 20000000 | 3.87s | x0.54 | +84%
|
|
46
|
-
rand_node_ffi | 20000000 | 87.84s | x0.02 | +4100%
|
|
56
|
+
- Baseline: Full C++ version of the code (no JS)
|
|
57
|
+
- [node-raylib](https://github.com/RobLoach/node-raylib): This is a native wrapper implemented with N-API
|
|
47
58
|
|
|
48
|
-
|
|
59
|
+
Benchmark | Iteration time | Relative performance | Overhead
|
|
60
|
+
------------------ | -------------- | -------------------- | --------
|
|
61
|
+
raylib_cc | 215.7 µs | x1.20 | -17%
|
|
62
|
+
raylib_node_raylib | 258.9 µs | x1.00 | (ref)
|
|
63
|
+
raylib_koffi | 311.6 µs | x0.83 | +20%
|
|
64
|
+
raylib_node_ffi | 928.4 µs | x0.28 | +259%
|
|
49
65
|
|
|
50
|
-
|
|
66
|
+
## Windows x86_64
|
|
51
67
|
|
|
52
|
-
|
|
68
|
+
The results presented below were measured on my x86_64 Windows machine (Intel® Core™ i5-4460).
|
|
69
|
+
|
|
70
|
+
### rand results
|
|
53
71
|
|
|
54
|
-
|
|
72
|
+
This test is based around repeated calls to a simple standard C function atoi, and has three implementations:
|
|
55
73
|
|
|
56
|
-
|
|
74
|
+
- the first one is the reference, it calls atoi through an N-API module, and is close to the theoretical limit of a perfect (no overhead) Node.js > C FFI implementation (pre-compiled static glue code)
|
|
75
|
+
- the second one calls atoi through Koffi
|
|
76
|
+
- the third one uses the official Node.js FFI implementation, node-ffi-napi
|
|
57
77
|
|
|
58
|
-
Benchmark |
|
|
59
|
-
------------- |
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
78
|
+
Benchmark | Iteration time | Relative performance | Overhead
|
|
79
|
+
------------- | -------------- | -------------------- | --------
|
|
80
|
+
rand_napi | 965 ns | x1.00 | (ref)
|
|
81
|
+
rand_koffi | 1248 ns | x0.77 | +29%
|
|
82
|
+
rand_node_ffi | 41500 ns | x0.02 | +4203%
|
|
63
83
|
|
|
64
|
-
|
|
84
|
+
Because rand is a pretty small function, the FFI overhead is clearly visible.
|
|
65
85
|
|
|
66
|
-
|
|
86
|
+
### atoi results
|
|
67
87
|
|
|
68
|
-
|
|
69
|
-
------------- | ---------- | ----------- | -------------------- | ----------
|
|
70
|
-
atoi_napi | 20000000 | 2.97s | (baseline) | (baseline)
|
|
71
|
-
atoi_koffi | 20000000 | 5.91s | x0.50 | +99%
|
|
72
|
-
atoi_node_ffi | 20000000 | 479.34s | x0.006 | +16000%
|
|
88
|
+
This test is similar to the rand one, but it is based on atoi, which takes a string parameter. Javascript (V8) to C string conversion is relatively slow and heavy.
|
|
73
89
|
|
|
74
|
-
|
|
90
|
+
The results below were measured on my x86_64 Windows machine (Intel® Core™ i5-4460):
|
|
75
91
|
|
|
76
|
-
|
|
92
|
+
Benchmark | Iteration time | Relative performance | Overhead
|
|
93
|
+
------------- | -------------- | -------------------- | --------
|
|
94
|
+
atoi_napi | 1393 ns | x1.00 | (ref)
|
|
95
|
+
atoi_koffi | 2246 ns | x0.62 | +61%
|
|
96
|
+
atoi_node_ffi | 157550 ns | x0.009 | +11210%
|
|
77
97
|
|
|
78
|
-
|
|
79
|
-
- [node-raylib](https://github.com/RobLoach/node-raylib): This is a native wrapper implemented with N-API
|
|
98
|
+
Because atoi is a pretty small function, the FFI overhead is clearly visible.
|
|
80
99
|
|
|
81
|
-
###
|
|
100
|
+
### Raylib results
|
|
82
101
|
|
|
83
|
-
The
|
|
102
|
+
This benchmark uses the CPU-based image drawing functions in Raylib. The calls are much heavier than in the atoi benchmark, thus the FFI overhead is reduced. In this implementation, Koffi is compared to:
|
|
84
103
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
raylib_cc | 100 | 9.31s | x1.17 | -15%
|
|
88
|
-
raylib_node_raylib | 100 | 10.90s | (baseline) | (baseline)
|
|
89
|
-
raylib_koffi | 100 | 12.86s | x0.84 | +18%
|
|
90
|
-
raylib_node_ffi | 100 | 35.76s | x0.30 | +228%
|
|
104
|
+
- [node-raylib](https://github.com/RobLoach/node-raylib) (baseline): This is a native wrapper implemented with N-API
|
|
105
|
+
- raylib_cc: C++ implementation of the benchmark, without any Javascript
|
|
91
106
|
|
|
92
|
-
|
|
107
|
+
Benchmark | Iteration time | Relative performance | Overhead
|
|
108
|
+
------------------ | -------------- | -------------------- | --------
|
|
109
|
+
raylib_cc | 211.8 µs | x1.25 | -20%
|
|
110
|
+
raylib_node_raylib | 264.4 µs | x1.00 | (ref)
|
|
111
|
+
raylib_koffi | 318.9 µs | x0.83 | +21%
|
|
112
|
+
raylib_node_ffi | 1146.2 µs | x0.23 | +334%
|
|
93
113
|
|
|
94
|
-
|
|
114
|
+
Please note that in order to get fair numbers for raylib_node_raylib, it was recompiled with clang-cl before running the benchmark with the following commands:
|
|
95
115
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
raylib_node_ffi | 100 | 44.63s | x0.27 | +270%
|
|
116
|
+
```batch
|
|
117
|
+
cd node_modules\raylib
|
|
118
|
+
rmdir /S /Q bin build
|
|
119
|
+
npx cmake-js compile -t ClangCL
|
|
120
|
+
```
|
|
102
121
|
|
|
103
122
|
## Running benchmarks
|
|
104
123
|
|
|
105
124
|
Open a console, go to `koffi/benchmark` and run `../../cnoke/cnoke.js` (or `node ..\..\cnoke\cnoke.js` on Windows) before doing anything else.
|
|
106
125
|
|
|
126
|
+
Please note that all benchmark results are made with Clang-built binaries.
|
|
127
|
+
|
|
107
128
|
```sh
|
|
108
129
|
cd koffi/benchmark
|
|
109
|
-
node ../../cnoke/cnoke.js
|
|
130
|
+
node ../../cnoke/cnoke.js --prefer-clang
|
|
110
131
|
```
|
|
111
132
|
|
|
112
|
-
Once
|
|
133
|
+
Once everything is built and ready, run:
|
|
113
134
|
|
|
114
135
|
```sh
|
|
115
|
-
node
|
|
116
|
-
node ./atoi_koffi.js
|
|
136
|
+
node benchmark.js
|
|
117
137
|
```
|
|
@@ -69,7 +69,7 @@ Note that the machine disk content may change each time the machine runs, so the
|
|
|
69
69
|
And now you can run the tests with:
|
|
70
70
|
|
|
71
71
|
```sh
|
|
72
|
-
node qemu.js # Several options are available, use --help
|
|
72
|
+
node qemu.js test # Several options are available, use --help
|
|
73
73
|
```
|
|
74
74
|
|
|
75
75
|
And be patient, this can be pretty slow for emulated machines. The Linux machines have and use ccache to build Koffi, so subsequent build steps will get much more tolerable.
|
|
@@ -78,8 +78,8 @@ By default, machines are started and stopped for each test. But you can start th
|
|
|
78
78
|
|
|
79
79
|
```sh
|
|
80
80
|
node qemu.js start # Start the machines
|
|
81
|
-
node qemu.js # Test (without shutting down)
|
|
82
|
-
node qemu.js # Test again
|
|
81
|
+
node qemu.js test # Test (without shutting down)
|
|
82
|
+
node qemu.js test # Test again
|
|
83
83
|
node qemu.js stop # Stop everything
|
|
84
84
|
```
|
|
85
85
|
|
|
@@ -109,18 +109,15 @@ node qemu.js info debian_x64
|
|
|
109
109
|
|
|
110
110
|
## Todo list
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
The following features and improvements are planned, not necessarily in that order:
|
|
113
113
|
|
|
114
|
-
-
|
|
115
|
-
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
- Optimize passing of structs and arrays, with separate HFA-specific helper functions
|
|
114
|
+
- Provide better ways to automatically deal with caller/heap-allocated memory (strings, etc.)
|
|
115
|
+
- Optimize passing of structs and arrays (avoid setting named properties one by one? separate HFA-specific helper functions?)
|
|
116
|
+
- Automate Windows/AArch64 (qemu) and macOS/AArch64 (how? ... thanks Apple) tests
|
|
117
|
+
- Create a real-world example, using several libraries (Raylib, SQLite, libsodium) to illustrate various C API styles
|
|
120
118
|
- Add simple struct type parser
|
|
121
119
|
- Add more ways to manually encode and decode various types to and from byte arrays
|
|
122
120
|
- Add support for unions
|
|
123
|
-
- Provide better ways to automatically deal with caller/heap-allocated memory (strings, etc.)
|
|
124
121
|
- Port Koffi to PowerPC (POWER9+) ABI
|
|
125
122
|
- Fix assembly unwind and CFI directives for better debugging experience
|
|
126
123
|
|
|
@@ -19,8 +19,8 @@ You can use the returned object to load C functions from the library. To do so,
|
|
|
19
19
|
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.
|
|
20
20
|
|
|
21
21
|
```js
|
|
22
|
-
const printf = lib.func('printf', 'int', ['
|
|
23
|
-
const atoi = lib.func('atoi', 'int', ['
|
|
22
|
+
const printf = lib.func('printf', 'int', ['str', '...']);
|
|
23
|
+
const atoi = lib.func('atoi', 'int', ['str']);
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
Koffi automatically tries mangled names for non-standard x86 calling conventions. See the section [on standard calls](#synchronous-calls) for more information on this subject.
|
|
@@ -31,7 +31,7 @@ If you prefer, you can declare functions using simple C-like prototype strings,
|
|
|
31
31
|
|
|
32
32
|
```js
|
|
33
33
|
const printf = lib.func('int printf(const char *fmt, ...)');
|
|
34
|
-
const atoi = lib.func('int atoi(
|
|
34
|
+
const atoi = lib.func('int atoi(str)'); // The parameter name is not used by Koffi, and optional
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
You can use `()` or `(void)` for functions that take no argument.
|
|
@@ -58,8 +58,8 @@ const koffi = require('koffi');
|
|
|
58
58
|
const lib = koffi.load('user32.dll');
|
|
59
59
|
|
|
60
60
|
// The following two declarations are equivalent, and use Stdcall
|
|
61
|
-
const MessageBoxA_1 = lib.stdcall('MessageBoxA', 'int', ['void *', '
|
|
62
|
-
const MessageBoxA_2 = lib.func('int __stdcall MessageBoxA(void *hwnd,
|
|
61
|
+
const MessageBoxA_1 = lib.stdcall('MessageBoxA', 'int', ['void *', 'str', 'str', 'uint']);
|
|
62
|
+
const MessageBoxA_2 = lib.func('int __stdcall MessageBoxA(void *hwnd, str text, str caption, uint type)');
|
|
63
63
|
```
|
|
64
64
|
|
|
65
65
|
## Asynchronous calls
|
|
@@ -95,10 +95,10 @@ Variadic functions are declared with an ellipsis as the last argument.
|
|
|
95
95
|
In order to call a variadic function, you must provide two Javascript arguments for each additional C parameter, the first one is the expected type and the second one is the value.
|
|
96
96
|
|
|
97
97
|
```js
|
|
98
|
-
const printf = lib.func('printf', 'int', ['
|
|
98
|
+
const printf = lib.func('printf', 'int', ['str', '...']);
|
|
99
99
|
|
|
100
100
|
// The variadic arguments are: 6 (int), 8.5 (double), 'THE END' (const char *)
|
|
101
|
-
printf('Integer %d, double %g,
|
|
101
|
+
printf('Integer %d, double %g, str %s', 'int', 6, 'double', 8.5, 'str', 'THE END');
|
|
102
102
|
```
|
|
103
103
|
|
|
104
104
|
On x86 platforms, only the Cdecl convention can be used for variadic functions.
|
|
@@ -159,7 +159,8 @@ const lib = koffi.load('sqlite.so');
|
|
|
159
159
|
const sqlite3_db = koffi.handle('sqlite3_db');
|
|
160
160
|
|
|
161
161
|
// Use koffi.out() on a pointer to copy out (from C to JS) after the call
|
|
162
|
-
const sqlite3_open_v2 = lib.func('sqlite3_open_v2', 'int', ['
|
|
162
|
+
const sqlite3_open_v2 = lib.func('sqlite3_open_v2', 'int', ['str', koffi.out(koffi.pointer(sqlite3_db)), 'int', 'str']);
|
|
163
|
+
const sqlite3_close_v2 = lib.func('sqlite3_close_v2', 'int', [sqlite3_db]);
|
|
163
164
|
|
|
164
165
|
const SQLITE_OPEN_READWRITE = 0x2;
|
|
165
166
|
const SQLITE_OPEN_CREATE = 0x4;
|
|
@@ -11,6 +11,9 @@ Koffi is a **fast and easy-to-use C FFI module for Node.js**, featuring:
|
|
|
11
11
|
* Javascript functions can be used as C callbacks (since 1.2.0)
|
|
12
12
|
* Well-tested code base for :ref:`popular OS/architecture combinations<Supported platforms>`
|
|
13
13
|
|
|
14
|
+
|
|
15
|
+
Koffi requires a recent `Node.js <https://nodejs.org/>`_ version with N-API version 8 support, see :ref:`this page<Node.js>` for more information.
|
|
16
|
+
|
|
14
17
|
Table of contents
|
|
15
18
|
-----------------
|
|
16
19
|
|
|
@@ -1,4 +1,18 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Requirements
|
|
2
|
+
|
|
3
|
+
## Node.js
|
|
4
|
+
|
|
5
|
+
Koffi requires a recent [Node.js](https://nodejs.org/) version with [N-API](https://nodejs.org/api/n-api.html) version 8 support:
|
|
6
|
+
|
|
7
|
+
- Node < 12.22.0 is not supported
|
|
8
|
+
- _Node 12.x_: Node 12.22.0 or newer
|
|
9
|
+
- _Node 14.x_: Node 14.17.0 or newer
|
|
10
|
+
- _Node 15.x_: Node 15.12.0 or newer
|
|
11
|
+
- Node 16.0.0 or later versions
|
|
12
|
+
|
|
13
|
+
Use [NVM](https://github.com/nvm-sh/nvm) to install more recent Node versions on older Linux distributions.
|
|
14
|
+
|
|
15
|
+
## Supported platforms
|
|
2
16
|
|
|
3
17
|
The following combinations of OS and architectures __are officially supported and tested__ at the moment:
|
|
4
18
|
|
|
@@ -10,10 +24,8 @@ ARM32 LE [^2] | ⬜️ *N/A* | ✅ Yes | ⬜️ *N/A* | 🟨 Probab
|
|
|
10
24
|
ARM64 (AArch64) LE | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | 🟨 Probably
|
|
11
25
|
RISC-V 64 [^3] | ⬜️ *N/A* | ✅ Yes | ⬜️ *N/A* | 🟨 Probably | 🟨 Probably
|
|
12
26
|
|
|
13
|
-
For all fully supported platforms (green check marks), a prebuilt binary is included in the NPM package which means you can install Koffi without a C++ compiler.
|
|
14
|
-
|
|
15
|
-
Node 12 or later is required, earlier versions are not supported. Use [NVM](https://github.com/nvm-sh/nvm) to install recent Node versions on older Linux distributions.
|
|
16
|
-
|
|
17
27
|
[^1]: The following call conventions are supported for forward calls: cdecl, stdcall, MS fastcall, thiscall. Only cdecl and stdcall can be used for C to JS callbacks.
|
|
18
28
|
[^2]: The prebuilt binary uses the hard float ABI and expects a VFP coprocessor. Build from source to use Koffi with a different ABI (softfp, soft).
|
|
19
29
|
[^3]: The prebuilt binary uses the LP64D (double-precision float) ABI. The LP64 ABI is supported in theory if you build Koffi from source (untested), the LP64F ABI is not supported.
|
|
30
|
+
|
|
31
|
+
For all fully supported platforms (green check marks), a prebuilt binary is included in the NPM package which means you can install Koffi without a C++ compiler.
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Quick start
|
|
2
2
|
|
|
3
|
+
## Install Koffi
|
|
4
|
+
|
|
3
5
|
You can install Koffi with npm:
|
|
4
6
|
|
|
5
7
|
```sh
|
|
@@ -71,7 +73,7 @@ printf('Local time: %02d:%02d:%02d\n', 'int', now.tm_hour, 'int', now.tm_min, 'i
|
|
|
71
73
|
|
|
72
74
|
This is a small example targeting the Win32 API, using `MessageBox()` to show a *Hello World!* message to the user.
|
|
73
75
|
|
|
74
|
-
It illustrates the use of the x86 stdcall calling convention.
|
|
76
|
+
It illustrates the use of the x86 stdcall calling convention, and the use of UTF-8 and UTF-16 string arguments.
|
|
75
77
|
|
|
76
78
|
```js
|
|
77
79
|
const koffi = require('koffi');
|
|
@@ -80,10 +82,19 @@ const koffi = require('koffi');
|
|
|
80
82
|
const lib = koffi.load('user32.dll');
|
|
81
83
|
|
|
82
84
|
// Declare constants
|
|
85
|
+
const MB_OK = 0x0;
|
|
86
|
+
const MB_YESNO = 0x4;
|
|
87
|
+
const MB_ICONQUESTION = 0x20;
|
|
83
88
|
const MB_ICONINFORMATION = 0x40;
|
|
89
|
+
const IDOK = 1;
|
|
90
|
+
const IDYES = 6;
|
|
91
|
+
const IDNO = 7;
|
|
84
92
|
|
|
85
93
|
// Find functions
|
|
86
|
-
const MessageBoxA = lib.stdcall('MessageBoxA', 'int', ['void *', '
|
|
94
|
+
const MessageBoxA = lib.stdcall('MessageBoxA', 'int', ['void *', 'str', 'str', 'uint']);
|
|
95
|
+
const MessageBoxW = lib.stdcall('MessageBoxW', 'int', ['void *', 'str16', 'str16', 'uint']);
|
|
87
96
|
|
|
88
|
-
MessageBoxA(null, '
|
|
97
|
+
let ret = MessageBoxA(null, 'Do you want another message box?', 'Koffi', MB_YESNO | MB_ICONQUESTION);
|
|
98
|
+
if (ret == IDYES)
|
|
99
|
+
MessageBoxW(null, 'Hello World!', 'Koffi', MB_ICONINFORMATION);
|
|
89
100
|
```
|
|
@@ -46,14 +46,18 @@ Koffi also accepts BigInt values when converting from JS to C integers. If the v
|
|
|
46
46
|
|
|
47
47
|
Koffi defines a few more types that can change size depending on the OS and the architecture:
|
|
48
48
|
|
|
49
|
-
JS type | C type
|
|
50
|
-
---------------- |
|
|
51
|
-
Boolean | bool
|
|
52
|
-
Number (integer) | long
|
|
53
|
-
Number (integer) | ulong
|
|
54
|
-
Number (integer) | unsigned long
|
|
55
|
-
|
|
56
|
-
|
|
49
|
+
JS type | C type | Signedness | Note
|
|
50
|
+
---------------- | ---------------- | ---------- | ------------------------------------------------
|
|
51
|
+
Boolean | bool | | Usually one byte
|
|
52
|
+
Number (integer) | long | Signed | 4 or 8 bytes depending on platform (LP64, LLP64)
|
|
53
|
+
Number (integer) | ulong | Unsigned | 4 or 8 bytes depending on platform (LP64, LLP64)
|
|
54
|
+
Number (integer) | unsigned long | Unsigned | 4 or 8 bytes depending on platform (LP64, LLP64)
|
|
55
|
+
Number (integer) | intptr | Signed | 4 or 8 bytes depending on register width
|
|
56
|
+
Number (integer) | intptr_t | Signed | 4 or 8 bytes depending on register width
|
|
57
|
+
Number (integer) | uintptr | Unsigned | 4 or 8 bytes depending on register width
|
|
58
|
+
Number (integer) | uintptr_t | Unsigned | 4 or 8 bytes depending on register width
|
|
59
|
+
String | str (string) | | JS strings are converted to and from UTF-8
|
|
60
|
+
String | str16 (string16) | | JS strings are converted to and from UTF-16 (LE)
|
|
57
61
|
|
|
58
62
|
Primitive types can be specified by name (in a string) or through `koffi.types`:
|
|
59
63
|
|
|
@@ -87,7 +91,7 @@ typedef struct A {
|
|
|
87
91
|
const A = koffi.struct('A', {
|
|
88
92
|
a: 'int',
|
|
89
93
|
b: 'char',
|
|
90
|
-
c: '
|
|
94
|
+
c: 'str',
|
|
91
95
|
d: koffi.struct({
|
|
92
96
|
d1: 'double',
|
|
93
97
|
d2: 'double'
|
|
@@ -270,11 +274,11 @@ const koffi = require('koffi');
|
|
|
270
274
|
const lib = koffi.load('./handles.so');
|
|
271
275
|
|
|
272
276
|
const Concat = koffi.handle('Concat');
|
|
273
|
-
const ConcatNewOut = lib.func('bool ConcatNewOut(Concat *out)');
|
|
274
277
|
const ConcatNew = lib.func('Concat ConcatNew()');
|
|
275
278
|
const ConcatFree = lib.func('void ConcatFree(Concat c)');
|
|
276
279
|
const ConcatAppend = lib.func('bool ConcatAppend(Concat c, const char *frag)');
|
|
277
280
|
const ConcatBuild = lib.func('const char *ConcatBuild(Concat c)');
|
|
281
|
+
const ConcatNewOut = lib.func('bool ConcatNewOut(_Out_ Concat out)');
|
|
278
282
|
|
|
279
283
|
let c = ConcatNew();
|
|
280
284
|
if (!c) {
|
|
@@ -385,7 +389,7 @@ const WIN32_FIND_DATA = koffi.struct('WIN32_FIND_DATA', {
|
|
|
385
389
|
wFinderFlags: 'ushort' // Obsolete. Do not use
|
|
386
390
|
});
|
|
387
391
|
|
|
388
|
-
const FindFirstFile = lib.func('HANDLE __stdcall FindFirstFileW(
|
|
392
|
+
const FindFirstFile = lib.func('HANDLE __stdcall FindFirstFileW(str16 path, _Out_ WIN32_FIND_DATA *data)');
|
|
389
393
|
const FindNextFile = lib.func('bool __stdcall FindNextFileW(HANDLE h, _Out_ WIN32_FIND_DATA *data)');
|
|
390
394
|
const FindClose = lib.func('bool __stdcall FindClose(HANDLE h)');
|
|
391
395
|
const GetLastError = lib.func('uint GetLastError()');
|
|
@@ -237,16 +237,6 @@ a.headerlink {
|
|
|
237
237
|
visibility: hidden;
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
-
a.brackets:before,
|
|
241
|
-
span.brackets > a:before{
|
|
242
|
-
content: "[";
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
a.brackets:after,
|
|
246
|
-
span.brackets > a:after {
|
|
247
|
-
content: "]";
|
|
248
|
-
}
|
|
249
|
-
|
|
250
240
|
h1:hover > a.headerlink,
|
|
251
241
|
h2:hover > a.headerlink,
|
|
252
242
|
h3:hover > a.headerlink,
|
|
@@ -334,14 +324,18 @@ aside.sidebar {
|
|
|
334
324
|
p.sidebar-title {
|
|
335
325
|
font-weight: bold;
|
|
336
326
|
}
|
|
327
|
+
nav.contents,
|
|
328
|
+
aside.topic,
|
|
337
329
|
|
|
338
|
-
div.admonition, div.topic,
|
|
330
|
+
div.admonition, div.topic, blockquote {
|
|
339
331
|
clear: left;
|
|
340
332
|
}
|
|
341
333
|
|
|
342
334
|
/* -- topics ---------------------------------------------------------------- */
|
|
335
|
+
nav.contents,
|
|
336
|
+
aside.topic,
|
|
343
337
|
|
|
344
|
-
div.topic
|
|
338
|
+
div.topic {
|
|
345
339
|
border: 1px solid #ccc;
|
|
346
340
|
padding: 7px;
|
|
347
341
|
margin: 10px 0 10px 0;
|
|
@@ -379,16 +373,20 @@ div.body p.centered {
|
|
|
379
373
|
|
|
380
374
|
div.sidebar > :last-child,
|
|
381
375
|
aside.sidebar > :last-child,
|
|
382
|
-
|
|
376
|
+
nav.contents > :last-child,
|
|
383
377
|
aside.topic > :last-child,
|
|
378
|
+
|
|
379
|
+
div.topic > :last-child,
|
|
384
380
|
div.admonition > :last-child {
|
|
385
381
|
margin-bottom: 0;
|
|
386
382
|
}
|
|
387
383
|
|
|
388
384
|
div.sidebar::after,
|
|
389
385
|
aside.sidebar::after,
|
|
390
|
-
|
|
386
|
+
nav.contents::after,
|
|
391
387
|
aside.topic::after,
|
|
388
|
+
|
|
389
|
+
div.topic::after,
|
|
392
390
|
div.admonition::after,
|
|
393
391
|
blockquote::after {
|
|
394
392
|
display: block;
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|