koffi 1.3.12 → 2.0.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/CMakeLists.txt +7 -2
- package/ChangeLog.md +42 -16
- package/README.md +6 -0
- package/build/qemu/2.0.0/koffi_darwin_arm64.tar.gz +0 -0
- package/build/qemu/2.0.0/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/2.0.0/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/2.0.0/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/2.0.0/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/2.0.0/koffi_linux_arm32hf.tar.gz +0 -0
- package/build/qemu/2.0.0/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/2.0.0/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/2.0.0/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/build/qemu/2.0.0/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/2.0.0/koffi_openbsd_ia32.tar.gz +0 -0
- package/build/qemu/2.0.0/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/2.0.0/koffi_win32_arm64.tar.gz +0 -0
- package/build/qemu/2.0.0/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/2.0.0/koffi_win32_x64.tar.gz +0 -0
- package/doc/benchmarks.md +2 -2
- package/doc/changes.md +156 -1
- package/doc/contribute.md +0 -1
- package/doc/dist/doctrees/changes.doctree +0 -0
- package/doc/dist/doctrees/environment.pickle +0 -0
- package/doc/dist/doctrees/functions.doctree +0 -0
- package/doc/dist/doctrees/types.doctree +0 -0
- package/doc/dist/html/_sources/changes.md.txt +156 -1
- package/doc/dist/html/_sources/functions.md.txt +8 -4
- package/doc/dist/html/_sources/types.md.txt +9 -0
- package/doc/dist/html/benchmarks.html +1 -1
- package/doc/dist/html/changes.html +226 -14
- package/doc/dist/html/contribute.html +1 -1
- package/doc/dist/html/functions.html +15 -12
- package/doc/dist/html/genindex.html +1 -1
- package/doc/dist/html/index.html +6 -16
- package/doc/dist/html/memory.html +3 -3
- package/doc/dist/html/objects.inv +0 -0
- package/doc/dist/html/platforms.html +1 -1
- package/doc/dist/html/search.html +1 -1
- package/doc/dist/html/searchindex.js +1 -1
- package/doc/dist/html/start.html +1 -1
- package/doc/dist/html/types.html +11 -3
- package/doc/functions.md +137 -13
- package/doc/types.md +35 -10
- package/package.json +1 -1
- package/qemu/registry/machines.json +5 -5
- package/qemu/registry/sha256sum.txt +16 -16
- package/src/abi_arm32.cc +90 -18
- package/src/abi_arm32_fwd.S +121 -57
- package/src/abi_arm64.cc +90 -18
- package/src/abi_arm64_fwd.S +96 -0
- package/src/abi_arm64_fwd.asm +128 -0
- package/src/abi_riscv64.cc +88 -18
- package/src/abi_riscv64_fwd.S +96 -0
- package/src/abi_x64_sysv.cc +93 -21
- package/src/abi_x64_sysv_fwd.S +96 -0
- package/src/abi_x64_win.cc +88 -18
- package/src/abi_x64_win_fwd.asm +128 -0
- package/src/abi_x86.cc +93 -18
- package/src/abi_x86_fwd.S +96 -0
- package/src/abi_x86_fwd.asm +128 -0
- package/src/call.cc +97 -63
- package/src/call.hh +2 -1
- package/src/ffi.cc +452 -140
- package/src/ffi.hh +23 -9
- package/src/parser.cc +18 -41
- package/src/util.cc +117 -27
- package/src/util.hh +3 -2
- package/test/callbacks.js +54 -8
- package/test/misc.c +29 -14
- package/test/raylib.js +1 -1
- package/test/sqlite.js +24 -16
- package/test/sync.js +41 -31
- package/vendor/libcc/libcc.cc +18 -5
- package/vendor/libcc/libcc.hh +70 -23
- package/build/qemu/1.3.12/koffi_darwin_arm64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_linux_arm32hf.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_openbsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_win32_arm64.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.3.12/koffi_win32_x64.tar.gz +0 -0
package/CMakeLists.txt
CHANGED
|
@@ -113,8 +113,13 @@ endif()
|
|
|
113
113
|
if(NOT MSVC OR CMAKE_C_COMPILER_ID MATCHES "[Cc]lang")
|
|
114
114
|
# Restore C/C++ compiler sanity
|
|
115
115
|
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
if(NOT MSVC)
|
|
117
|
+
target_compile_options(koffi PRIVATE -fno-exceptions -fno-strict-aliasing -fwrapv
|
|
118
|
+
-fno-delete-null-pointer-checks)
|
|
119
|
+
else()
|
|
120
|
+
target_compile_options(koffi PRIVATE -fno-strict-aliasing /clang:-fwrapv
|
|
121
|
+
-fno-delete-null-pointer-checks)
|
|
122
|
+
endif()
|
|
118
123
|
|
|
119
124
|
check_cxx_compiler_flag(-fno-finite-loops use_no_finite_loops)
|
|
120
125
|
if(use_no_finite_loops)
|
package/ChangeLog.md
CHANGED
|
@@ -1,18 +1,44 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## History
|
|
4
|
+
|
|
5
|
+
### Koffi 2.0.0
|
|
6
|
+
|
|
7
|
+
**Major new features:**
|
|
8
|
+
|
|
9
|
+
- Add disposable types for automatic disposal of C values (such as heap-allocated strings)
|
|
10
|
+
- Add support for registered callbacks, that can be called after the initial FFI call
|
|
11
|
+
- Support named pointer types
|
|
12
|
+
- Support complex type specifications outside of prototype parser
|
|
13
|
+
|
|
14
|
+
**Minor new features:**
|
|
15
|
+
|
|
16
|
+
- Support type aliases with `koffi.alias()`
|
|
17
|
+
- Add `koffi.resolve()` to resolve type strings
|
|
18
|
+
- Expose all primitive type aliases in `koffi.types`
|
|
19
|
+
- Correctly pass exceptions thrown in JS callbacks
|
|
20
|
+
|
|
21
|
+
**Breaking API changes:**
|
|
22
|
+
|
|
23
|
+
- Change handling of callback types, which must be used through pointers
|
|
24
|
+
- Change handling of opaque handles, which must be used through pointers
|
|
25
|
+
- Support all types in `koffi.introspect(type)`
|
|
26
|
+
|
|
27
|
+
Consult the [migration guide](changes.md#migration-guide) for more information.
|
|
28
|
+
|
|
29
|
+
### Koffi 1.3.12
|
|
4
30
|
|
|
5
31
|
**Main fixes:**
|
|
6
32
|
|
|
7
33
|
- Fix support for Yarn package manager
|
|
8
34
|
|
|
9
|
-
|
|
35
|
+
### Koffi 1.3.11
|
|
10
36
|
|
|
11
37
|
**Main fixes:**
|
|
12
38
|
|
|
13
39
|
- Fix broken parsing of `void *` when used for first parameter
|
|
14
40
|
|
|
15
|
-
|
|
41
|
+
### Koffi 1.3.10
|
|
16
42
|
|
|
17
43
|
**Main fixes:**
|
|
18
44
|
|
|
@@ -24,13 +50,13 @@
|
|
|
24
50
|
|
|
25
51
|
- Various documentation fixes and improvements
|
|
26
52
|
|
|
27
|
-
|
|
53
|
+
### Koffi 1.3.9
|
|
28
54
|
|
|
29
55
|
**Main fixes:**
|
|
30
56
|
|
|
31
57
|
- Fix prebuild compatibility with Electron on Windows x64
|
|
32
58
|
|
|
33
|
-
|
|
59
|
+
### Koffi 1.3.8
|
|
34
60
|
|
|
35
61
|
**Main changes:**
|
|
36
62
|
|
|
@@ -41,7 +67,7 @@
|
|
|
41
67
|
|
|
42
68
|
- Fix and harmonize a few error messages
|
|
43
69
|
|
|
44
|
-
|
|
70
|
+
### Koffi 1.3.7
|
|
45
71
|
|
|
46
72
|
**Main fixes:**
|
|
47
73
|
|
|
@@ -54,7 +80,7 @@
|
|
|
54
80
|
- Add str/str16 type aliases for string/string16
|
|
55
81
|
- Various documentation fixes and improvements
|
|
56
82
|
|
|
57
|
-
|
|
83
|
+
### Koffi 1.3.6
|
|
58
84
|
|
|
59
85
|
**Main fixes:**
|
|
60
86
|
|
|
@@ -66,7 +92,7 @@
|
|
|
66
92
|
- Prebuild with Clang for Windows x64 and Linux x64 binaries
|
|
67
93
|
- Various documentation improvements
|
|
68
94
|
|
|
69
|
-
|
|
95
|
+
### Koffi 1.3.5
|
|
70
96
|
|
|
71
97
|
**Main changes:**
|
|
72
98
|
|
|
@@ -78,13 +104,13 @@
|
|
|
78
104
|
- Reduce default async memory stack and heap size
|
|
79
105
|
- Various documentation improvements
|
|
80
106
|
|
|
81
|
-
|
|
107
|
+
### Koffi 1.3.4
|
|
82
108
|
|
|
83
109
|
**Main fixes:**
|
|
84
110
|
|
|
85
111
|
- Fix possible OpenBSD i386 crash with `(void)` functions
|
|
86
112
|
|
|
87
|
-
|
|
113
|
+
### Koffi 1.3.3
|
|
88
114
|
|
|
89
115
|
**Main fixes:**
|
|
90
116
|
|
|
@@ -96,20 +122,20 @@
|
|
|
96
122
|
- Disable unsafe compiler optimizations
|
|
97
123
|
- Various documentation improvements
|
|
98
124
|
|
|
99
|
-
|
|
125
|
+
### Koffi 1.3.2
|
|
100
126
|
|
|
101
127
|
**Main fixes:**
|
|
102
128
|
|
|
103
129
|
- Support compilation in C++14 mode (graceful degradation)
|
|
104
130
|
- Support older toolchains on Linux (tested on Debian 9)
|
|
105
131
|
|
|
106
|
-
|
|
132
|
+
### Koffi 1.3.1
|
|
107
133
|
|
|
108
134
|
**Main fixes:**
|
|
109
135
|
|
|
110
136
|
- The prebuilt binary is tested when Koffi is installed, and a rebuild happens if it fails to load
|
|
111
137
|
|
|
112
|
-
|
|
138
|
+
### Koffi 1.3.0
|
|
113
139
|
|
|
114
140
|
**Major changes:**
|
|
115
141
|
|
|
@@ -125,19 +151,19 @@
|
|
|
125
151
|
- Detect floating-point ABI before using prebuilt binaries (ARM32, RISC-V)
|
|
126
152
|
- Forbid duplicate member names in struct types
|
|
127
153
|
|
|
128
|
-
|
|
154
|
+
### Koffi 1.2.4
|
|
129
155
|
|
|
130
156
|
**New features:**
|
|
131
157
|
|
|
132
158
|
- Windows ARM64 is now supported
|
|
133
159
|
|
|
134
|
-
|
|
160
|
+
### Koffi 1.2.3
|
|
135
161
|
|
|
136
162
|
**New features:**
|
|
137
163
|
|
|
138
164
|
- A prebuilt binary for macOS ARM64 (M1) is now included
|
|
139
165
|
|
|
140
|
-
|
|
166
|
+
### Koffi 1.2.1
|
|
141
167
|
|
|
142
168
|
This entry documents changes since version 1.1.0.
|
|
143
169
|
|
package/README.md
CHANGED
|
@@ -23,6 +23,12 @@ RISC-V 64 [^3] | ⬜️ *N/A* | ✅ Yes | ⬜️ *N/A* | 🟨 Probab
|
|
|
23
23
|
|
|
24
24
|
Go to the web site for more information: https://koffi.dev/
|
|
25
25
|
|
|
26
|
+
# Project history
|
|
27
|
+
|
|
28
|
+
You can consult the [changelog](https://koffi.dev/changes) on the official website.
|
|
29
|
+
|
|
30
|
+
Major version increments can include breaking API changes, use the [migration guide](https://koffi.dev/changes#migration-guide) for more information.
|
|
31
|
+
|
|
26
32
|
# License
|
|
27
33
|
|
|
28
34
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/doc/benchmarks.md
CHANGED
|
@@ -10,8 +10,8 @@ Here is a quick overview of the execution time of Koffi calls on three benchmark
|
|
|
10
10
|
|
|
11
11
|
<table style="margin: 0 auto;">
|
|
12
12
|
<tr>
|
|
13
|
-
<td><a href="
|
|
14
|
-
<td><a href="
|
|
13
|
+
<td><a href="static/perf_linux_20220628.png" target="_blank"><img src="static/perf_linux_20220628.png" alt="Linux x86_64 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 x86_64 performance" style="width: 350px;"/></a></td>
|
|
15
15
|
</tr>
|
|
16
16
|
</table>
|
|
17
17
|
|
package/doc/changes.md
CHANGED
|
@@ -1,2 +1,157 @@
|
|
|
1
1
|
```{include} ../ChangeLog.md
|
|
2
|
-
```
|
|
2
|
+
```
|
|
3
|
+
|
|
4
|
+
## Migration guide
|
|
5
|
+
|
|
6
|
+
### Koffi 1.x to 2.x
|
|
7
|
+
|
|
8
|
+
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.
|
|
9
|
+
|
|
10
|
+
You may need to change your code if you use:
|
|
11
|
+
|
|
12
|
+
- Callback functions
|
|
13
|
+
- Opaque handles
|
|
14
|
+
- `koffi.introspect()`
|
|
15
|
+
|
|
16
|
+
#### Callback types
|
|
17
|
+
|
|
18
|
+
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.
|
|
19
|
+
|
|
20
|
+
Given the following C code:
|
|
21
|
+
|
|
22
|
+
```c
|
|
23
|
+
#include <string.h>
|
|
24
|
+
|
|
25
|
+
int TransferToJS(const char *name, int age, int (*cb)(const char *str, int age))
|
|
26
|
+
{
|
|
27
|
+
char buf[64];
|
|
28
|
+
snprintf(buf, sizeof(buf), "Hello %s!", str);
|
|
29
|
+
return cb(buf, age);
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The two versions below illustrate the API difference between Koffi 1.x and Koffi 2.x:
|
|
34
|
+
|
|
35
|
+
```js
|
|
36
|
+
// Koffi 1.x
|
|
37
|
+
|
|
38
|
+
const TransferCallback = koffi.callback('int TransferCallback(const char *str, int age)');
|
|
39
|
+
|
|
40
|
+
const TransferToJS = lib.func('TransferToJS', 'int', ['str', 'int', TransferCallback]);
|
|
41
|
+
// Equivalent to: const TransferToJS = lib.func('int TransferToJS(str s, int x, TransferCallback cb)');
|
|
42
|
+
|
|
43
|
+
let ret = TransferToJS('Niels', 27, (str, age) => {
|
|
44
|
+
console.log(str);
|
|
45
|
+
console.log('Your age is:', age);
|
|
46
|
+
return 42;
|
|
47
|
+
});
|
|
48
|
+
console.log(ret);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
// Koffi 2.x
|
|
53
|
+
|
|
54
|
+
const TransferCallback = koffi.callback('int TransferCallback(const char *str, int age)');
|
|
55
|
+
|
|
56
|
+
const TransferToJS = lib.func('TransferToJS', 'int', ['str', 'int', koffi.pointer(TransferCallback)]);
|
|
57
|
+
// Equivalent to: const TransferToJS = lib.func('int TransferToJS(str s, int x, TransferCallback *cb)');
|
|
58
|
+
|
|
59
|
+
let ret = TransferToJS('Niels', 27, (str, age) => {
|
|
60
|
+
console.log(str);
|
|
61
|
+
console.log('Your age is:', age);
|
|
62
|
+
return 42;
|
|
63
|
+
});
|
|
64
|
+
console.log(ret);
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Koffi 1.x only supported [transient callbacks](functions.md#javascript-callbacks), you must use Koffi 2.x for registered callbacks.
|
|
68
|
+
|
|
69
|
+
#### Opaque handles
|
|
70
|
+
|
|
71
|
+
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, you must use them through a pointer, and use an array for output parameters.
|
|
72
|
+
|
|
73
|
+
For functions that return handles or pass them by parameter:
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
// Koffi 1.x
|
|
77
|
+
|
|
78
|
+
const FILE = koffi.handle('FILE');
|
|
79
|
+
const fopen = lib.func('FILE fopen(const char *path, const char *mode)');
|
|
80
|
+
const fclose = lib.func('int fclose(FILE stream)');
|
|
81
|
+
|
|
82
|
+
let fp = fopen('touch', 'wb');
|
|
83
|
+
if (!fp)
|
|
84
|
+
throw new Error('Failed to open file');
|
|
85
|
+
fclose(fp);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```js
|
|
89
|
+
// Koffi 2.x
|
|
90
|
+
|
|
91
|
+
const FILE = koffi.handle('FILE');
|
|
92
|
+
const fopen = lib.func('FILE *fopen(const char *path, const char *mode)');
|
|
93
|
+
const fclose = lib.func('int fclose(FILE *stream)');
|
|
94
|
+
|
|
95
|
+
let fp = fopen('touch', 'wb');
|
|
96
|
+
if (!fp)
|
|
97
|
+
throw new Error('Failed to open file');
|
|
98
|
+
fclose(fp);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
For functions that set opaque handles through output parameters (such as `sqlite3_open_v2`), you must now use a single element array as shown below:
|
|
102
|
+
|
|
103
|
+
```js
|
|
104
|
+
// Koffi 1.x
|
|
105
|
+
|
|
106
|
+
const sqlite3_db = koffi.handle('sqlite3_db');
|
|
107
|
+
|
|
108
|
+
const sqlite3_open_v2 = lib.func('sqlite3_open_v2', 'int', ['str', koffi.out(sqlite3_db), 'int', 'str']);
|
|
109
|
+
const sqlite3_close_v2 = lib.func('sqlite3_close_v2', 'int', [sqlite3_db]);
|
|
110
|
+
|
|
111
|
+
const SQLITE_OPEN_READWRITE = 0x2;
|
|
112
|
+
const SQLITE_OPEN_CREATE = 0x4;
|
|
113
|
+
|
|
114
|
+
let db = {};
|
|
115
|
+
|
|
116
|
+
if (sqlite3_open_v2(':memory:', db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, null) != 0)
|
|
117
|
+
throw new Error('Failed to open database');
|
|
118
|
+
|
|
119
|
+
sqlite3_close_v2(db);
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
```js
|
|
123
|
+
// Koffi 2.x
|
|
124
|
+
|
|
125
|
+
const sqlite3_db = koffi.handle('sqlite3_db');
|
|
126
|
+
|
|
127
|
+
const sqlite3_open_v2 = lib.func('sqlite3_open_v2', 'int', ['str', koffi.out(koffi.pointer(sqlite3_db, 2)), 'int', 'str']);
|
|
128
|
+
const sqlite3_close_v2 = lib.func('sqlite3_close_v2', 'int', [koffi.pointer(sqlite3_db)]);
|
|
129
|
+
|
|
130
|
+
const SQLITE_OPEN_READWRITE = 0x2;
|
|
131
|
+
const SQLITE_OPEN_CREATE = 0x4;
|
|
132
|
+
|
|
133
|
+
let db = null;
|
|
134
|
+
|
|
135
|
+
let ptr = [null];
|
|
136
|
+
if (sqlite3_open_v2(':memory:', ptr, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, null) != 0)
|
|
137
|
+
throw new Error('Failed to open database');
|
|
138
|
+
db = ptr[0];
|
|
139
|
+
|
|
140
|
+
sqlite3_close_v2(db);
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
#### koffi.introspect()
|
|
144
|
+
|
|
145
|
+
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.
|
|
146
|
+
|
|
147
|
+
You can still get the list of struct members:
|
|
148
|
+
|
|
149
|
+
```js
|
|
150
|
+
const StructType = koffi.struct('StructType', { dummy: 'int' });
|
|
151
|
+
|
|
152
|
+
// Koffi 1.x
|
|
153
|
+
let members = koffi.introspect(StructType);
|
|
154
|
+
|
|
155
|
+
// Koffi 2.x
|
|
156
|
+
let members = koffi.introspect(StructType).members;
|
|
157
|
+
```
|
package/doc/contribute.md
CHANGED
|
@@ -111,7 +111,6 @@ node qemu.js info debian_x64
|
|
|
111
111
|
|
|
112
112
|
The following features and improvements are planned, not necessarily in that order:
|
|
113
113
|
|
|
114
|
-
- Provide better ways to automatically deal with caller/heap-allocated memory (strings, etc.)
|
|
115
114
|
- Optimize passing of structs and arrays (avoid setting named properties one by one? separate HFA-specific helper functions?)
|
|
116
115
|
- Automate Windows/AArch64 (qemu) and macOS/AArch64 (how? ... thanks Apple) tests
|
|
117
116
|
- Create a real-world example, using several libraries (Raylib, SQLite, libsodium) to illustrate various C API styles
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,2 +1,157 @@
|
|
|
1
1
|
```{include} ../ChangeLog.md
|
|
2
|
-
```
|
|
2
|
+
```
|
|
3
|
+
|
|
4
|
+
## Migration guide
|
|
5
|
+
|
|
6
|
+
### Koffi 1.x to 2.x
|
|
7
|
+
|
|
8
|
+
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.
|
|
9
|
+
|
|
10
|
+
You may need to change your code if you use:
|
|
11
|
+
|
|
12
|
+
- Callback functions
|
|
13
|
+
- Opaque handles
|
|
14
|
+
- `koffi.introspect()`
|
|
15
|
+
|
|
16
|
+
#### Callback types
|
|
17
|
+
|
|
18
|
+
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.
|
|
19
|
+
|
|
20
|
+
Given the following C code:
|
|
21
|
+
|
|
22
|
+
```c
|
|
23
|
+
#include <string.h>
|
|
24
|
+
|
|
25
|
+
int TransferToJS(const char *name, int age, int (*cb)(const char *str, int age))
|
|
26
|
+
{
|
|
27
|
+
char buf[64];
|
|
28
|
+
snprintf(buf, sizeof(buf), "Hello %s!", str);
|
|
29
|
+
return cb(buf, age);
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The two versions below illustrate the API difference between Koffi 1.x and Koffi 2.x:
|
|
34
|
+
|
|
35
|
+
```js
|
|
36
|
+
// Koffi 1.x
|
|
37
|
+
|
|
38
|
+
const TransferCallback = koffi.callback('int TransferCallback(const char *str, int age)');
|
|
39
|
+
|
|
40
|
+
const TransferToJS = lib.func('TransferToJS', 'int', ['str', 'int', TransferCallback]);
|
|
41
|
+
// Equivalent to: const TransferToJS = lib.func('int TransferToJS(str s, int x, TransferCallback cb)');
|
|
42
|
+
|
|
43
|
+
let ret = TransferToJS('Niels', 27, (str, age) => {
|
|
44
|
+
console.log(str);
|
|
45
|
+
console.log('Your age is:', age);
|
|
46
|
+
return 42;
|
|
47
|
+
});
|
|
48
|
+
console.log(ret);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
// Koffi 2.x
|
|
53
|
+
|
|
54
|
+
const TransferCallback = koffi.callback('int TransferCallback(const char *str, int age)');
|
|
55
|
+
|
|
56
|
+
const TransferToJS = lib.func('TransferToJS', 'int', ['str', 'int', koffi.pointer(TransferCallback)]);
|
|
57
|
+
// Equivalent to: const TransferToJS = lib.func('int TransferToJS(str s, int x, TransferCallback *cb)');
|
|
58
|
+
|
|
59
|
+
let ret = TransferToJS('Niels', 27, (str, age) => {
|
|
60
|
+
console.log(str);
|
|
61
|
+
console.log('Your age is:', age);
|
|
62
|
+
return 42;
|
|
63
|
+
});
|
|
64
|
+
console.log(ret);
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Koffi 1.x only supported [transient callbacks](functions.md#javascript-callbacks), you must use Koffi 2.x for registered callbacks.
|
|
68
|
+
|
|
69
|
+
#### Opaque handles
|
|
70
|
+
|
|
71
|
+
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, you must use them through a pointer, and use an array for output parameters.
|
|
72
|
+
|
|
73
|
+
For functions that return handles or pass them by parameter:
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
// Koffi 1.x
|
|
77
|
+
|
|
78
|
+
const FILE = koffi.handle('FILE');
|
|
79
|
+
const fopen = lib.func('FILE fopen(const char *path, const char *mode)');
|
|
80
|
+
const fclose = lib.func('int fclose(FILE stream)');
|
|
81
|
+
|
|
82
|
+
let fp = fopen('touch', 'wb');
|
|
83
|
+
if (!fp)
|
|
84
|
+
throw new Error('Failed to open file');
|
|
85
|
+
fclose(fp);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```js
|
|
89
|
+
// Koffi 2.x
|
|
90
|
+
|
|
91
|
+
const FILE = koffi.handle('FILE');
|
|
92
|
+
const fopen = lib.func('FILE *fopen(const char *path, const char *mode)');
|
|
93
|
+
const fclose = lib.func('int fclose(FILE *stream)');
|
|
94
|
+
|
|
95
|
+
let fp = fopen('touch', 'wb');
|
|
96
|
+
if (!fp)
|
|
97
|
+
throw new Error('Failed to open file');
|
|
98
|
+
fclose(fp);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
For functions that set opaque handles through output parameters (such as `sqlite3_open_v2`), you must now use a single element array as shown below:
|
|
102
|
+
|
|
103
|
+
```js
|
|
104
|
+
// Koffi 1.x
|
|
105
|
+
|
|
106
|
+
const sqlite3_db = koffi.handle('sqlite3_db');
|
|
107
|
+
|
|
108
|
+
const sqlite3_open_v2 = lib.func('sqlite3_open_v2', 'int', ['str', koffi.out(sqlite3_db), 'int', 'str']);
|
|
109
|
+
const sqlite3_close_v2 = lib.func('sqlite3_close_v2', 'int', [sqlite3_db]);
|
|
110
|
+
|
|
111
|
+
const SQLITE_OPEN_READWRITE = 0x2;
|
|
112
|
+
const SQLITE_OPEN_CREATE = 0x4;
|
|
113
|
+
|
|
114
|
+
let db = {};
|
|
115
|
+
|
|
116
|
+
if (sqlite3_open_v2(':memory:', db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, null) != 0)
|
|
117
|
+
throw new Error('Failed to open database');
|
|
118
|
+
|
|
119
|
+
sqlite3_close_v2(db);
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
```js
|
|
123
|
+
// Koffi 2.x
|
|
124
|
+
|
|
125
|
+
const sqlite3_db = koffi.handle('sqlite3_db');
|
|
126
|
+
|
|
127
|
+
const sqlite3_open_v2 = lib.func('sqlite3_open_v2', 'int', ['str', koffi.out(koffi.pointer(sqlite3_db, 2)), 'int', 'str']);
|
|
128
|
+
const sqlite3_close_v2 = lib.func('sqlite3_close_v2', 'int', [koffi.pointer(sqlite3_db)]);
|
|
129
|
+
|
|
130
|
+
const SQLITE_OPEN_READWRITE = 0x2;
|
|
131
|
+
const SQLITE_OPEN_CREATE = 0x4;
|
|
132
|
+
|
|
133
|
+
let db = null;
|
|
134
|
+
|
|
135
|
+
let ptr = [null];
|
|
136
|
+
if (sqlite3_open_v2(':memory:', ptr, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, null) != 0)
|
|
137
|
+
throw new Error('Failed to open database');
|
|
138
|
+
db = ptr[0];
|
|
139
|
+
|
|
140
|
+
sqlite3_close_v2(db);
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
#### koffi.introspect()
|
|
144
|
+
|
|
145
|
+
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.
|
|
146
|
+
|
|
147
|
+
You can still get the list of struct members:
|
|
148
|
+
|
|
149
|
+
```js
|
|
150
|
+
const StructType = koffi.struct('StructType', { dummy: 'int' });
|
|
151
|
+
|
|
152
|
+
// Koffi 1.x
|
|
153
|
+
let members = koffi.introspect(StructType);
|
|
154
|
+
|
|
155
|
+
// Koffi 2.x
|
|
156
|
+
let members = koffi.introspect(StructType).members;
|
|
157
|
+
```
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Functions
|
|
2
2
|
|
|
3
3
|
## Function definitions
|
|
4
4
|
|
|
@@ -158,7 +158,7 @@ This example opens an in-memory SQLite database, and uses the node-ffi-style fun
|
|
|
158
158
|
|
|
159
159
|
```js
|
|
160
160
|
const koffi = require('koffi');
|
|
161
|
-
const lib = koffi.load('
|
|
161
|
+
const lib = koffi.load('sqlite3.so');
|
|
162
162
|
|
|
163
163
|
const sqlite3_db = koffi.handle('sqlite3_db');
|
|
164
164
|
|
|
@@ -169,9 +169,11 @@ const sqlite3_close_v2 = lib.func('sqlite3_close_v2', 'int', [koffi.pointer(sqli
|
|
|
169
169
|
const SQLITE_OPEN_READWRITE = 0x2;
|
|
170
170
|
const SQLITE_OPEN_CREATE = 0x4;
|
|
171
171
|
|
|
172
|
-
let
|
|
173
|
-
if (sqlite3_open_v2(':memory:',
|
|
172
|
+
let out = [null];
|
|
173
|
+
if (sqlite3_open_v2(':memory:', out, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, null) != 0)
|
|
174
174
|
throw new Error('Failed to open database');
|
|
175
|
+
let db = out[0];
|
|
176
|
+
|
|
175
177
|
sqlite3_close_v2(db);
|
|
176
178
|
```
|
|
177
179
|
|
|
@@ -246,6 +248,8 @@ Callbacks **have changed in version 2.0**.
|
|
|
246
248
|
In Koffi 1.x, callbacks were defined in a way that made them usable directly as parameter and return types, obscuring the underlying pointer.
|
|
247
249
|
|
|
248
250
|
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.
|
|
251
|
+
|
|
252
|
+
Consult the [migration guide](changes.md) for more information.
|
|
249
253
|
```
|
|
250
254
|
|
|
251
255
|
Koffi only uses predefined static trampolines, and does not need to generate code at runtime, which makes it compatible with platforms with hardened W^X migitations (such as PaX mprotect). However, this imposes some restrictions on the maximum number of callbacks, and their duration.
|
|
@@ -154,6 +154,8 @@ Opaque handles **have changed in version 2.0**.
|
|
|
154
154
|
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.
|
|
155
155
|
|
|
156
156
|
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](functions.md#output-parameters).
|
|
157
|
+
|
|
158
|
+
Consult the [migration guide](changes.md) for more information.
|
|
157
159
|
```
|
|
158
160
|
|
|
159
161
|
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 handle, and is created and destroyed using a pair of C functions: `ConcatNew` (or `ConcatNewOut`) and `ConcatFree`.
|
|
@@ -520,11 +522,14 @@ Koffi exposes three functions to explore type information:
|
|
|
520
522
|
- `koffi.sizeof(type)` to get the size of a type
|
|
521
523
|
- `koffi.alignof(type)` to get the alignment of a type
|
|
522
524
|
- `koffi.introspect(type)` to get the definition of a type in an object containing: name, primitive, size, alignment, members (structs), reference (array, pointer) and length (array)
|
|
525
|
+
- `koffi.resolve(type)` to get the resolved type object from a type string
|
|
523
526
|
|
|
524
527
|
```{note}
|
|
525
528
|
The value returned by `introspect()` has **changed in version 2.0**.
|
|
526
529
|
|
|
527
530
|
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.
|
|
531
|
+
|
|
532
|
+
Consult the [migration guide](changes.md) for more information.
|
|
528
533
|
```
|
|
529
534
|
|
|
530
535
|
Just like before, you can refer to primitive types by their name or through `koffi.types`:
|
|
@@ -534,3 +539,7 @@ Just like before, you can refer to primitive types by their name or through `kof
|
|
|
534
539
|
console.log(koffi.sizeof('long'));
|
|
535
540
|
console.log(koffi.sizeof(koffi.types.long));
|
|
536
541
|
```
|
|
542
|
+
|
|
543
|
+
## Type aliasing
|
|
544
|
+
|
|
545
|
+
You can alias a type with `koffi.alias(name, type)`. Aliased types are completely equivalent.
|
|
@@ -165,7 +165,7 @@
|
|
|
165
165
|
<li class="toctree-l1"><a class="reference internal" href="platforms">Requirements</a></li>
|
|
166
166
|
<li class="toctree-l1"><a class="reference internal" href="start">Quick start</a></li>
|
|
167
167
|
<li class="toctree-l1"><a class="reference internal" href="types">Data types</a></li>
|
|
168
|
-
<li class="toctree-l1"><a class="reference internal" href="functions">
|
|
168
|
+
<li class="toctree-l1"><a class="reference internal" href="functions">Functions</a></li>
|
|
169
169
|
<li class="toctree-l1"><a class="reference internal" href="memory">Memory usage</a></li>
|
|
170
170
|
<li class="toctree-l1 current current-page"><a class="current reference internal" href="#">Benchmarks</a></li>
|
|
171
171
|
<li class="toctree-l1"><a class="reference internal" href="contribute">Contributing</a></li>
|