koffi 0.9.48 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CMakeLists.txt +12 -11
  2. package/README.md +152 -91
  3. package/build/qemu/1.0.2/koffi_darwin_x64.tar.gz +0 -0
  4. package/build/qemu/1.0.2/koffi_freebsd_arm64.tar.gz +0 -0
  5. package/build/qemu/1.0.2/koffi_freebsd_ia32.tar.gz +0 -0
  6. package/build/qemu/1.0.2/koffi_freebsd_x64.tar.gz +0 -0
  7. package/build/qemu/1.0.2/koffi_linux_arm.tar.gz +0 -0
  8. package/build/qemu/1.0.2/koffi_linux_arm64.tar.gz +0 -0
  9. package/build/qemu/1.0.2/koffi_linux_ia32.tar.gz +0 -0
  10. package/build/qemu/1.0.2/koffi_linux_x64.tar.gz +0 -0
  11. package/build/qemu/1.0.2/koffi_win32_ia32.tar.gz +0 -0
  12. package/build/qemu/1.0.2/koffi_win32_x64.tar.gz +0 -0
  13. package/package.json +8 -4
  14. package/qemu/qemu.js +794 -0
  15. package/qemu/registry/machines.json +415 -0
  16. package/qemu/registry/sha256sum.txt +45 -0
  17. package/src/{call_arm32.cc → abi_arm32.cc} +76 -50
  18. package/src/{call_arm32_fwd.S → abi_arm32_fwd.S} +0 -0
  19. package/src/{call_arm64.cc → abi_arm64.cc} +79 -51
  20. package/src/{call_arm64_fwd.S → abi_arm64_fwd.S} +0 -0
  21. package/src/{call_x64_sysv.cc → abi_x64_sysv.cc} +77 -49
  22. package/src/{call_x64_sysv_fwd.S → abi_x64_sysv_fwd.S} +0 -0
  23. package/src/{call_x64_win.cc → abi_x64_win.cc} +71 -47
  24. package/src/{call_x64_win_fwd.asm → abi_x64_win_fwd.asm} +0 -0
  25. package/src/{call_x86.cc → abi_x86.cc} +74 -56
  26. package/src/{call_x86_fwd.S → abi_x86_fwd.S} +0 -0
  27. package/src/{call_x86_fwd.asm → abi_x86_fwd.asm} +0 -0
  28. package/src/call.cc +228 -0
  29. package/src/call.hh +96 -4
  30. package/src/ffi.cc +8 -3
  31. package/src/ffi.hh +2 -0
  32. package/src/util.cc +11 -157
  33. package/src/util.hh +0 -91
  34. package/test/CMakeLists.txt +1 -0
  35. package/test/misc.c +289 -0
  36. package/test/misc.def +3 -0
  37. package/test/misc.js +180 -0
  38. package/test/raylib.js +165 -0
  39. package/test/sqlite.js +104 -0
  40. package/build/qemu/0.9.48/koffi_darwin_x64.tar.gz +0 -0
  41. package/build/qemu/0.9.48/koffi_freebsd_arm64.tar.gz +0 -0
  42. package/build/qemu/0.9.48/koffi_freebsd_ia32.tar.gz +0 -0
  43. package/build/qemu/0.9.48/koffi_freebsd_x64.tar.gz +0 -0
  44. package/build/qemu/0.9.48/koffi_linux_arm.tar.gz +0 -0
  45. package/build/qemu/0.9.48/koffi_linux_arm64.tar.gz +0 -0
  46. package/build/qemu/0.9.48/koffi_linux_ia32.tar.gz +0 -0
  47. package/build/qemu/0.9.48/koffi_linux_x64.tar.gz +0 -0
  48. package/build/qemu/0.9.48/koffi_win32_ia32.tar.gz +0 -0
  49. package/build/qemu/0.9.48/koffi_win32_x64.tar.gz +0 -0
package/CMakeLists.txt CHANGED
@@ -24,11 +24,12 @@ endif()
24
24
  # ---- Koffi ----
25
25
 
26
26
  set(KOFFI_SRC
27
- src/call_arm32.cc
28
- src/call_arm64.cc
29
- src/call_x64_sysv.cc
30
- src/call_x64_win.cc
31
- src/call_x86.cc
27
+ src/call.cc
28
+ src/abi_arm32.cc
29
+ src/abi_arm64.cc
30
+ src/abi_x64_sysv.cc
31
+ src/abi_x64_win.cc
32
+ src/abi_x86.cc
32
33
  src/ffi.cc
33
34
  src/parser.cc
34
35
  src/util.cc
@@ -36,19 +37,19 @@ set(KOFFI_SRC
36
37
  )
37
38
  if(CMAKE_SIZEOF_VOID_P EQUAL 8)
38
39
  if(WIN32)
39
- list(APPEND KOFFI_SRC src/call_x64_win_fwd.asm)
40
+ list(APPEND KOFFI_SRC src/abi_x64_win_fwd.asm)
40
41
  elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64")
41
- list(APPEND KOFFI_SRC src/call_arm64_fwd.S)
42
+ list(APPEND KOFFI_SRC src/abi_arm64_fwd.S)
42
43
  else()
43
- list(APPEND KOFFI_SRC src/call_x64_sysv_fwd.S)
44
+ list(APPEND KOFFI_SRC src/abi_x64_sysv_fwd.S)
44
45
  endif()
45
46
  elseif(CMAKE_SIZEOF_VOID_P EQUAL 4)
46
47
  if(WIN32)
47
- list(APPEND KOFFI_SRC src/call_x86_fwd.asm)
48
+ list(APPEND KOFFI_SRC src/abi_x86_fwd.asm)
48
49
  elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i[3456]86|x86|AMD64")
49
- list(APPEND KOFFI_SRC src/call_x86_fwd.S)
50
+ list(APPEND KOFFI_SRC src/abi_x86_fwd.S)
50
51
  elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "armv[678]l")
51
- list(APPEND KOFFI_SRC src/call_arm32_fwd.S)
52
+ list(APPEND KOFFI_SRC src/abi_arm32_fwd.S)
52
53
  endif()
53
54
  endif()
54
55
 
package/README.md CHANGED
@@ -1,18 +1,23 @@
1
1
  # Table of contents
2
2
 
3
3
  - [Introduction](#introduction)
4
+ - [Get started](#get-started)
4
5
  - [Benchmarks](#benchmarks)
5
6
  * [atoi results](#atoi-results)
6
7
  * [Raylib results](#raylib-results)
7
- - [Installation](#installation)
8
+ - [Tests](#tests)
9
+ - [Compilation](#compilation)
8
10
  * [Windows](#windows)
9
11
  * [Other platforms](#other-platforms)
10
- - [Get started](#get-started)
11
- - [Tests](#tests)
12
12
 
13
13
  # Introduction
14
14
 
15
- Koffi is a fast and easy-to-use FFI module for Node.js, with support for complex data types such as structs.
15
+ Koffi is a fast and easy-to-use FFI module for Node.js, with support for primitive and aggregate data types (structs), both by reference (pointer) and by value.
16
+
17
+ After the release of version 1.0, the following features are planned:
18
+
19
+ * 1.1: C to JS callbacks
20
+ * 1.2: Support fixed array types
16
21
 
17
22
  The following platforms __are officially supported and tested__ at the moment:
18
23
 
@@ -40,105 +45,67 @@ OpenBSD | ARM64 Little Endian | 🟧 | 🟥
40
45
 
41
46
  This is still in development, bugs are to expected. More tests will come in the near future.
42
47
 
43
- # Benchmarks
44
-
45
- In order to run it, go to `koffi/benchmark` and run `../../cnoke/cnoke.js` (or `node ..\..\cnoke\cnoke.js` on Windows) before doing anything else.
46
-
47
- Once this is done, you can execute each implementation, e.g. `build/atoi_cc` or `./atoi_koffi.js`. You can optionally define a custom number of iterations, e.g. `./atoi_koffi.js 10000000`.
48
-
49
- ## atoi results
50
-
51
- This test is based around repeated calls to a simple standard C function atoi, and has three implementations:
52
- - 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.
53
- - the second one calls atoi through Koffi
54
- - the third one uses the official Node.js FFI implementation, node-ffi-napi
55
-
56
- Because atoi is a small call, the FFI overhead is clearly visible.
57
-
58
- ### Linux
59
-
60
- The results below were measured on my x86_64 Linux machine (AMD® Ryzen™ 7 5800H 16G):
61
-
62
- Benchmark | Iterations | Total time | Overhead
63
- ------------- | ---------- | ----------- | ----------
64
- atoi_napi | 20000000 | 1.10s | (baseline)
65
- atoi_koffi | 20000000 | 1.91s | x1.73
66
- atoi_node_ffi | 20000000 | 640.49s | x582
67
-
68
- ### Windows
69
-
70
- The results below were measured on my x86_64 Windows machine (AMD® Ryzen™ 7 5800H 16G):
71
-
72
- Benchmark | Iterations | Total time | Overhead
73
- ------------- | ---------- | ----------- | ----------
74
- atoi_napi | 20000000 | 1.94s | (baseline)
75
- atoi_koffi | 20000000 | 3.15s | x1.62
76
- atoi_node_ffi | 20000000 | 640.49s | x242
77
-
78
- ## Raylib results
79
-
80
- 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 implemenetation, the baseline is a full C++ version of the code.
81
-
82
- ### Linux
83
-
84
- The results below were measured on my x86_64 Linux machine (AMD® Ryzen™ 7 5800H 16G):
48
+ # Get started
85
49
 
86
- Benchmark | Iterations | Total time | Overhead
87
- --------------- | ---------- | ----------- | ----------
88
- raylib_cc | 100 | 4.14s | (baseline)
89
- raylib_koffi | 100 | 6.25s | x1.51
90
- raylib_node_ffi | 100 | 27.13s | x6.55
50
+ Once you have installed koffi with `npm install koffi`, you can start by loading it this way:
91
51
 
92
- ### Windows
52
+ ```js
53
+ const koffi = require('koffi');
54
+ ```
93
55
 
94
- The results below were measured on my x86_64 Windows machine (AMD® Ryzen™ 7 5800H 16G):
56
+ Below you can find three examples:
95
57
 
96
- Benchmark | Iterations | Total time | Overhead
97
- --------------- | ---------- | ----------- | ----------
98
- raylib_cc | 100 | 8.39s | (baseline)
99
- raylib_koffi | 100 | 11.51s | x1.37
100
- raylib_node_ffi | 100 | 31.47s | x3.8
58
+ * The first one runs on Linux. The functions are declared with the C-like prototype language.
59
+ * The second one runs on Windows, and uses the node-ffi like syntax to declare functions.
60
+ * The third one is more complex and uses Raylib to animate "Hello World" in a window.
101
61
 
102
- # Installation
62
+ ## Small Linux example
103
63
 
104
- ## Windows
64
+ ```js
65
+ const koffi = require('koffi');
66
+ const lib = koffi.load('libc.so.6');
105
67
 
106
- First, make sure the following dependencies are met:
68
+ // Declare types
69
+ const timeval = koffi.struct('timeval', {
70
+ tv_sec: 'unsigned int',
71
+ tv_usec: 'unsigned int'
72
+ });
73
+ const timezone = koffi.struct('timezone', {
74
+ tz_minuteswest: 'int',
75
+ tz_dsttime: 'int'
76
+ });
107
77
 
108
- * The "Desktop development with C++" workload from [Visual Studio 2022 or 2019](https://visualstudio.microsoft.com/downloads/) or the "C++ build tools" workload from the [Build Tools](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022), with the default optional components.
109
- * [CMake meta build system](https://cmake.org/)
110
- * [Node 16 LTS](https://nodejs.org/), but a newer version should work too
78
+ // Declare functions
79
+ const gettimeofday = lib.func('int gettimeofday(_Out_ timeval *tv, _Out_ timezone *tz)');
80
+ const printf = lib.func('int printf(const char *format, ...)');
111
81
 
112
- Once this is done, run this command from the project root:
82
+ let tv = {};
83
+ let tz = {};
84
+ gettimeofday(tv, tz);
113
85
 
114
- ```sh
115
- npm install koffi
86
+ printf('Hello World!, it is: %d\n', 'int', tv.tv_sec);
87
+ console.log(tz);
116
88
  ```
117
89
 
118
- ## Other platforms
119
-
120
- Make sure the following dependencies are met:
90
+ ## Small Windows example
121
91
 
122
- * `gcc` and `g++` >= 8.3 or newer
123
- * GNU Make 3.81 or newer
124
- * [CMake meta build system](https://cmake.org/)
92
+ ```js
93
+ const koffi = require('koffi');
94
+ const lib = koffi.load('user32.dll');
125
95
 
126
- Once these dependencies are met, simply run the follow command:
96
+ const MessageBoxA = lib.stdcall('MessageBoxA', 'int', ['void *', 'string', 'string', 'uint']);
97
+ const MB_ICONINFORMATION = 0x40;
127
98
 
128
- ```sh
129
- npm install koffi
99
+ MessageBoxA(null, 'Hello', 'Foobar', MB_ICONINFORMATION);
130
100
  ```
131
101
 
132
- # Get started
133
-
134
- This section assumes you know how to build C shared libraries.
135
-
136
102
  ## Raylib example
137
103
 
138
- This examples illustrates how to use Koffi with a Raylib shared library:
104
+ This section assumes you know how to build C shared libraries, such as Raylib. You may need to fix the URL to the library before you can do anything.
139
105
 
140
106
  ```js
141
107
  const koffi = require('koffi');
108
+ let lib = koffi.load('raylib.dll'); // Fix path if needed
142
109
 
143
110
  const Color = koffi.struct('Color', {
144
111
  r: 'uchar',
@@ -192,9 +159,6 @@ const Font = koffi.struct('Font', {
192
159
  glyphs: koffi.pointer(GlyphInfo)
193
160
  });
194
161
 
195
- // Fix the path to Raylib DLL if needed
196
- let lib = koffi.load('build/raylib' + koffi.extension);
197
-
198
162
  // Classic function declaration
199
163
  const InitWindow = lib.func('InitWindow', 'void', ['int', 'int', 'string']);
200
164
  const SetTargetFPS = lib.func('SetTargetFPS', 'void', ['int']);
@@ -245,19 +209,84 @@ while (!WindowShouldClose()) {
245
209
 
246
210
  ```
247
211
 
248
- ## Win32 stdcall example
212
+ # Extra features
249
213
 
250
- ```js
251
- const koffi = require('koffi');
214
+ ## Variadic functions
252
215
 
253
- let lib = koffi.load('user32.dll');
216
+ Variadic functions are declared with an ellipsis as the last argument.
254
217
 
255
- const MessageBoxA = lib.stdcall('MessageBoxA', 'int', ['void *', 'string', 'string', 'uint']);
256
- const MB_ICONINFORMATION = 0x40;
218
+ In order to call a variadic function, you must provide two Javascript arguments for each C parameter,
219
+ the first one is the expected type and the second one is the value.
257
220
 
258
- MessageBoxA(null, 'Hello', 'Foobar', MB_ICONINFORMATION);
221
+ ```js
222
+ const printf = lib.func('printf', 'int', ['string', '...']);
223
+
224
+ printf('Integer %d, double %g, string %s', 'int', 6, 'double', 8.5, 'string', 'THE END');
259
225
  ```
260
226
 
227
+ ## Callbacks
228
+
229
+ Koffi does not yet support passing JS functions as callbacks. This is planned for version 1.1.
230
+
231
+ # Benchmarks
232
+
233
+ In order to run it, go to `koffi/benchmark` and run `../../cnoke/cnoke.js` (or `node ..\..\cnoke\cnoke.js` on Windows) before doing anything else.
234
+
235
+ Once this is done, you can execute each implementation, e.g. `build/atoi_cc` or `./atoi_koffi.js`. You can optionally define a custom number of iterations, e.g. `./atoi_koffi.js 10000000`.
236
+
237
+ ## atoi results
238
+
239
+ This test is based around repeated calls to a simple standard C function atoi, and has three implementations:
240
+ - 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.
241
+ - the second one calls atoi through Koffi
242
+ - the third one uses the official Node.js FFI implementation, node-ffi-napi
243
+
244
+ Because atoi is a small call, the FFI overhead is clearly visible.
245
+
246
+ ### Linux
247
+
248
+ The results below were measured on my x86_64 Linux machine (AMD® Ryzen™ 7 5800H 16G):
249
+
250
+ Benchmark | Iterations | Total time | Overhead
251
+ ------------- | ---------- | ----------- | ----------
252
+ atoi_napi | 20000000 | 1.10s | (baseline)
253
+ atoi_koffi | 20000000 | 1.91s | x1.73
254
+ atoi_node_ffi | 20000000 | 640.49s | x582
255
+
256
+ ### Windows
257
+
258
+ The results below were measured on my x86_64 Windows machine (AMD® Ryzen™ 7 5800H 16G):
259
+
260
+ Benchmark | Iterations | Total time | Overhead
261
+ ------------- | ---------- | ----------- | ----------
262
+ atoi_napi | 20000000 | 1.94s | (baseline)
263
+ atoi_koffi | 20000000 | 3.15s | x1.62
264
+ atoi_node_ffi | 20000000 | 640.49s | x242
265
+
266
+ ## Raylib results
267
+
268
+ 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 implemenetation, the baseline is a full C++ version of the code.
269
+
270
+ ### Linux
271
+
272
+ The results below were measured on my x86_64 Linux machine (AMD® Ryzen™ 7 5800H 16G):
273
+
274
+ Benchmark | Iterations | Total time | Overhead
275
+ --------------- | ---------- | ----------- | ----------
276
+ raylib_cc | 100 | 4.14s | (baseline)
277
+ raylib_koffi | 100 | 6.25s | x1.51
278
+ raylib_node_ffi | 100 | 27.13s | x6.55
279
+
280
+ ### Windows
281
+
282
+ The results below were measured on my x86_64 Windows machine (AMD® Ryzen™ 7 5800H 16G):
283
+
284
+ Benchmark | Iterations | Total time | Overhead
285
+ --------------- | ---------- | ----------- | ----------
286
+ raylib_cc | 100 | 8.39s | (baseline)
287
+ raylib_koffi | 100 | 11.51s | x1.37
288
+ raylib_node_ffi | 100 | 31.47s | x3.8
289
+
261
290
  # Tests
262
291
 
263
292
  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.
@@ -314,3 +343,35 @@ Each machine is configured to run a VNC server available locally, which you can
314
343
  ```sh
315
344
  node qemu.js info debian_x64
316
345
  ```
346
+
347
+ # Compilation
348
+
349
+ 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.
350
+
351
+ ## Windows
352
+
353
+ First, make sure the following dependencies are met:
354
+
355
+ * The "Desktop development with C++" workload from [Visual Studio 2022 or 2019](https://visualstudio.microsoft.com/downloads/) or the "C++ build tools" workload from the [Build Tools](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022), with the default optional components.
356
+ * [CMake meta build system](https://cmake.org/)
357
+ * [Node 16 LTS](https://nodejs.org/), but a newer version should work too
358
+
359
+ Once this is done, run this command from the project root:
360
+
361
+ ```sh
362
+ npm install koffi
363
+ ```
364
+
365
+ ## Other platforms
366
+
367
+ Make sure the following dependencies are met:
368
+
369
+ * `gcc` and `g++` >= 8.3 or newer
370
+ * GNU Make 3.81 or newer
371
+ * [CMake meta build system](https://cmake.org/)
372
+
373
+ Once these dependencies are met, simply run the follow command:
374
+
375
+ ```sh
376
+ npm install koffi
377
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "0.9.48",
3
+ "version": "1.0.2",
4
4
  "description": "Fast and simple FFI (foreign function interface) for Node.js",
5
5
  "keywords": [
6
6
  "foreign",
@@ -40,10 +40,14 @@
40
40
  "benchmark/CMakeLists.txt",
41
41
  "benchmark/atoi_*",
42
42
  "benchmark/raylib_*",
43
+ "qemu/qemu.js",
44
+ "qemu/registry",
43
45
  "test/CMakeLists.txt",
44
- "test/test.js",
45
- "test/registry",
46
- "test/tests",
46
+ "test/misc.c",
47
+ "test/misc.def",
48
+ "test/misc.js",
49
+ "test/raylib.js",
50
+ "test/sqlite.js",
47
51
  "vendor",
48
52
  "LICENSE.txt",
49
53
  "README.md",