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.
Files changed (106) hide show
  1. package/CMakeLists.txt +1 -1
  2. package/ChangeLog.md +36 -0
  3. package/benchmark/atoi_koffi.js +3 -4
  4. package/benchmark/atoi_napi.js +2 -3
  5. package/benchmark/atoi_node_ffi.js +3 -4
  6. package/benchmark/raylib_cc.cc +3 -4
  7. package/benchmark/raylib_cc.js +31 -0
  8. package/benchmark/raylib_koffi.js +8 -9
  9. package/benchmark/raylib_node_ffi.js +4 -5
  10. package/benchmark/raylib_node_raylib.js +4 -5
  11. package/build/qemu/1.3.8/koffi_darwin_arm64.tar.gz +0 -0
  12. package/build/qemu/1.3.8/koffi_darwin_x64.tar.gz +0 -0
  13. package/build/qemu/1.3.8/koffi_freebsd_arm64.tar.gz +0 -0
  14. package/build/qemu/1.3.8/koffi_freebsd_ia32.tar.gz +0 -0
  15. package/build/qemu/1.3.8/koffi_freebsd_x64.tar.gz +0 -0
  16. package/build/qemu/1.3.8/koffi_linux_arm32hf.tar.gz +0 -0
  17. package/build/qemu/1.3.8/koffi_linux_arm64.tar.gz +0 -0
  18. package/build/qemu/1.3.8/koffi_linux_ia32.tar.gz +0 -0
  19. package/build/qemu/1.3.8/koffi_linux_riscv64hf64.tar.gz +0 -0
  20. package/build/qemu/1.3.8/koffi_linux_x64.tar.gz +0 -0
  21. package/build/qemu/1.3.8/koffi_openbsd_ia32.tar.gz +0 -0
  22. package/build/qemu/1.3.8/koffi_openbsd_x64.tar.gz +0 -0
  23. package/build/qemu/1.3.8/koffi_win32_arm64.tar.gz +0 -0
  24. package/build/qemu/1.3.8/koffi_win32_ia32.tar.gz +0 -0
  25. package/build/qemu/1.3.8/koffi_win32_x64.tar.gz +0 -0
  26. package/doc/_static/perf_linux_20220627.png +0 -0
  27. package/doc/_static/perf_linux_20220628.png +0 -0
  28. package/doc/_static/perf_windows_20220627.png +0 -0
  29. package/doc/_static/perf_windows_20220628.png +0 -0
  30. package/doc/benchmarks.md +78 -58
  31. package/doc/benchmarks.xlsx +0 -0
  32. package/doc/conf.py +1 -1
  33. package/doc/contribute.md +8 -11
  34. package/doc/dist/html/_sources/benchmarks.md.txt +78 -58
  35. package/doc/dist/html/_sources/contribute.md.txt +8 -11
  36. package/doc/dist/html/_sources/functions.md.txt +9 -8
  37. package/doc/dist/html/_sources/index.rst.txt +3 -0
  38. package/doc/dist/html/_sources/platforms.md.txt +17 -5
  39. package/doc/dist/html/_sources/start.md.txt +14 -3
  40. package/doc/dist/html/_sources/types.md.txt +15 -11
  41. package/doc/dist/html/_static/basic.css +12 -14
  42. package/doc/dist/html/_static/perf_linux_20220627.png +0 -0
  43. package/doc/dist/html/_static/perf_linux_20220628.png +0 -0
  44. package/doc/dist/html/_static/perf_windows_20220627.png +0 -0
  45. package/doc/dist/html/_static/perf_windows_20220628.png +0 -0
  46. package/doc/dist/html/benchmarks.html +148 -159
  47. package/doc/dist/html/changes.html +44 -2
  48. package/doc/dist/html/contribute.html +30 -33
  49. package/doc/dist/html/functions.html +19 -18
  50. package/doc/dist/html/genindex.html +2 -2
  51. package/doc/dist/html/index.html +19 -10
  52. package/doc/dist/html/memory.html +2 -2
  53. package/doc/dist/html/objects.inv +0 -0
  54. package/doc/dist/html/platforms.html +44 -10
  55. package/doc/dist/html/search.html +2 -2
  56. package/doc/dist/html/searchindex.js +1 -1
  57. package/doc/dist/html/start.html +25 -12
  58. package/doc/dist/html/types.html +31 -11
  59. package/doc/functions.md +9 -8
  60. package/doc/index.rst +3 -0
  61. package/doc/platforms.md +17 -5
  62. package/doc/start.md +14 -3
  63. package/doc/types.md +15 -11
  64. package/package.json +7 -4
  65. package/qemu/qemu.js +30 -19
  66. package/qemu/registry/machines.json +19 -19
  67. package/qemu/registry/sha256sum.txt +5 -5
  68. package/src/abi_arm32.cc +9 -2
  69. package/src/abi_arm32_fwd.S +7 -7
  70. package/src/abi_arm64.cc +9 -2
  71. package/src/abi_arm64_fwd.S +11 -7
  72. package/src/abi_arm64_fwd.asm +7 -7
  73. package/src/abi_riscv64.cc +9 -2
  74. package/src/abi_riscv64_fwd.S +11 -11
  75. package/src/abi_x64_sysv.cc +9 -2
  76. package/src/abi_x64_sysv_fwd.S +11 -11
  77. package/src/abi_x64_win.cc +9 -2
  78. package/src/abi_x64_win_fwd.asm +7 -7
  79. package/src/abi_x86.cc +9 -2
  80. package/src/abi_x86_fwd.S +3 -0
  81. package/src/abi_x86_fwd.asm +3 -0
  82. package/src/call.cc +20 -10
  83. package/src/ffi.cc +17 -8
  84. package/src/ffi.hh +4 -3
  85. package/src/util.cc +1 -1
  86. package/test/async.js +1 -1
  87. package/test/callbacks.js +25 -2
  88. package/test/misc.c +57 -2
  89. package/test/raylib.js +4 -4
  90. package/test/sqlite.js +5 -5
  91. package/test/sync.js +22 -7
  92. package/build/qemu/1.3.5/koffi_darwin_arm64.tar.gz +0 -0
  93. package/build/qemu/1.3.5/koffi_darwin_x64.tar.gz +0 -0
  94. package/build/qemu/1.3.5/koffi_freebsd_arm64.tar.gz +0 -0
  95. package/build/qemu/1.3.5/koffi_freebsd_ia32.tar.gz +0 -0
  96. package/build/qemu/1.3.5/koffi_freebsd_x64.tar.gz +0 -0
  97. package/build/qemu/1.3.5/koffi_linux_arm32hf.tar.gz +0 -0
  98. package/build/qemu/1.3.5/koffi_linux_arm64.tar.gz +0 -0
  99. package/build/qemu/1.3.5/koffi_linux_ia32.tar.gz +0 -0
  100. package/build/qemu/1.3.5/koffi_linux_riscv64hf64.tar.gz +0 -0
  101. package/build/qemu/1.3.5/koffi_linux_x64.tar.gz +0 -0
  102. package/build/qemu/1.3.5/koffi_openbsd_ia32.tar.gz +0 -0
  103. package/build/qemu/1.3.5/koffi_openbsd_x64.tar.gz +0 -0
  104. package/build/qemu/1.3.5/koffi_win32_arm64.tar.gz +0 -0
  105. package/build/qemu/1.3.5/koffi_win32_ia32.tar.gz +0 -0
  106. 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/perf_linux_20220623_2.png" target="_blank"><img src="_static/perf_linux_20220623_2.png" alt="Linux performance" style="width: 350px;"/></a></td>
12
- <td><a href="_static/perf_windows_20220623_2.png" target="_blank"><img src="_static/perf_windows_20220623_2.png" alt="Windows performance" style="width: 350px;"/></a></td>
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
- ## rand results
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
- ### Linux x86_64
40
+ ### atoi results
29
41
 
30
- The results below were measured on my x86_64 Linux machine (AMD® Ryzen™ 7 4700U):
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 | Iterations | Total time | Relative performance | Overhead
33
- ------------- | ---------- | ----------- | -------------------- | ----------
34
- rand_napi | 20000000 | 1.44s | (baseline) | (baseline)
35
- rand_koffi | 20000000 | 2.60s | x0.55 | +81%
36
- rand_node_ffi | 20000000 | 107.58s | x0.01 | +7400%
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
- ### Windows x86_64
50
+ Because atoi is a pretty small function, the FFI overhead is clearly visible.
39
51
 
40
- The results below were measured on my x86_64 Windows machine (Intel® Core™ i5-4460):
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
- Benchmark | Iterations | Total time | Relative performance | Overhead
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
- ## atoi results
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
- 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.
66
+ ## Windows x86_64
51
67
 
52
- Because rand is a pretty small function, the FFI overhead is clearly visible.
68
+ The results presented below were measured on my x86_64 Windows machine (Intel® Core™ i5-4460).
69
+
70
+ ### rand results
53
71
 
54
- ### Linux x86_64
72
+ This test is based around repeated calls to a simple standard C function atoi, and has three implementations:
55
73
 
56
- The results below were measured on my x86_64 Linux machine (AMD® Ryzen™ 7 4700U):
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 | Iterations | Total time | Relative performance | Overhead
59
- ------------- | ---------- | ----------- | -------------------- | ----------
60
- atoi_napi | 20000000 | 2.97s | (baseline) | (baseline)
61
- atoi_koffi | 20000000 | 5.07s | x0.58 | +71%
62
- atoi_node_ffi | 20000000 | 693.16s | x0.005 | +23000%
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
- ### Windows x86_64
84
+ Because rand is a pretty small function, the FFI overhead is clearly visible.
65
85
 
66
- The results below were measured on my x86_64 Windows machine (Intel® Core™ i5-4460):
86
+ ### atoi results
67
87
 
68
- Benchmark | Iterations | Total time | Relative performance | Overhead
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
- ## Raylib results
90
+ The results below were measured on my x86_64 Windows machine (Intel® Core™ i5-4460):
75
91
 
76
- 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:
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
- - Baseline: Full C++ version of the code (no JS)
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
- ### Linux x86_64
100
+ ### Raylib results
82
101
 
83
- The results below were measured on my x86_64 Linux machine (AMD® Ryzen™ 7 4700U):
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
- Benchmark | Iterations | Total time | Relative performance | Overhead
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
- ### Windows x86_64
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
- The results below were measured on my x86_64 Windows machine (Intel® Core™ i5-4460):
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
- Benchmark | Iterations | Total time | Relative performance | Overhead
97
- --------------- | ---------- | ----------- | -------------------- | ----------
98
- raylib_cc | 100 | 10.67s | x1.17 | -12%
99
- raylib_node_raylib | 100 | 12.05s | (baseline) | (baseline)
100
- raylib_koffi | 100 | 14.84s | x0.81 | +23%
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 this is done, you can execute each implementation, e.g. `build/raylib_cc` or `node ./atoi_koffi.js`. You can optionally define a custom number of iterations, e.g. `node ./atoi_koffi.js 10000000`.
133
+ Once everything is built and ready, run:
113
134
 
114
135
  ```sh
115
- node ./atoi_napi.js
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
- After the release of version 1.3.0, the current priorities for the next major release are:
112
+ The following features and improvements are planned, not necessarily in that order:
113
113
 
114
- - Automate Windows/AArch64 (qemu) and macOS/AArch64 (how?) tests and builds
115
- - Create a real-world example, using several libraries (Raylib, SQLite, libsodium) to illustrate how to work with various C API styles
116
-
117
- The following features are also planned eventually, not necessarily in that order:
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', ['string', '...']);
23
- const atoi = lib.func('atoi', 'int', ['string']);
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(string)'); // The parameter name is not used by Koffi, and optional
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 *', 'string', 'string', 'uint']);
62
- const MessageBoxA_2 = lib.func('int __stdcall MessageBoxA(void *hwnd, string text, string caption, uint type)');
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', ['string', '...']);
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, string %s', 'int', 6, 'double', 8.5, 'string', 'THE END');
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', ['string', koffi.out(koffi.pointer(sqlite3_db)), 'int', 'string']);
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
- # Supported platforms
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 *', 'string', 'string', 'uint']);
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, 'Hello World!', 'Koffi', MB_ICONINFORMATION);
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 | 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
- String | string | | JS strings are converted to and from UTF-8
56
- String | string16 | | JS strings are converted to and from UTF-16 (LE)
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: 'string',
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(string16 path, _Out_ WIN32_FIND_DATA *data)');
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, aside.topic, blockquote {
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, aside.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
- div.topic > :last-child,
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
- div.topic::after,
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;