koffi 2.15.1 → 2.15.2-beta.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 (35) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/build/koffi/darwin_arm64/koffi.node +0 -0
  3. package/build/koffi/darwin_x64/koffi.node +0 -0
  4. package/build/koffi/freebsd_arm64/koffi.node +0 -0
  5. package/build/koffi/freebsd_ia32/koffi.node +0 -0
  6. package/build/koffi/freebsd_x64/koffi.node +0 -0
  7. package/build/koffi/linux_arm64/koffi.node +0 -0
  8. package/build/koffi/linux_armhf/koffi.node +0 -0
  9. package/build/koffi/linux_ia32/koffi.node +0 -0
  10. package/build/koffi/linux_loong64/koffi.node +0 -0
  11. package/build/koffi/linux_riscv64d/koffi.node +0 -0
  12. package/build/koffi/linux_x64/koffi.node +0 -0
  13. package/build/koffi/musl_arm64/koffi.node +0 -0
  14. package/build/koffi/musl_x64/koffi.node +0 -0
  15. package/build/koffi/openbsd_ia32/koffi.node +0 -0
  16. package/build/koffi/openbsd_x64/koffi.node +0 -0
  17. package/build/koffi/win32_arm64/koffi.exp +0 -0
  18. package/build/koffi/win32_arm64/koffi.lib +0 -0
  19. package/build/koffi/win32_arm64/koffi.node +0 -0
  20. package/build/koffi/win32_ia32/koffi.exp +0 -0
  21. package/build/koffi/win32_ia32/koffi.lib +0 -0
  22. package/build/koffi/win32_ia32/koffi.node +0 -0
  23. package/build/koffi/win32_x64/koffi.exp +0 -0
  24. package/build/koffi/win32_x64/koffi.lib +0 -0
  25. package/build/koffi/win32_x64/koffi.node +0 -0
  26. package/index.js +11 -14
  27. package/indirect.js +11 -14
  28. package/package.json +3 -3
  29. package/src/cnoke/assets/FindCNoke.cmake +27 -16
  30. package/src/cnoke/assets/toolchains.json +126 -0
  31. package/src/cnoke/cnoke.js +27 -33
  32. package/src/cnoke/src/builder.js +122 -63
  33. package/src/cnoke/src/tools.js +1 -5
  34. package/src/koffi/CMakeLists.txt +1 -1
  35. package/src/koffi/src/init.js +1 -0
package/CHANGELOG.md CHANGED
@@ -7,6 +7,14 @@
7
7
 
8
8
  ### Koffi 2.15
9
9
 
10
+ #### Koffi 2.15.2
11
+
12
+ *Released on 2026-03-08*
13
+
14
+ - Fix build problems on Android/Termux
15
+ - Fix failing indirect loading caused by missing path test
16
+ - Use Clang to build Linux ARM64 prebuild
17
+
10
18
  #### Koffi 2.15.1
11
19
 
12
20
  *Released on 2025-01-24*
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
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/index.js CHANGED
@@ -4,9 +4,9 @@ var __commonJS = (cb, mod3) => function __require() {
4
4
  return mod3 || (0, cb[__getOwnPropNames(cb)[0]])((mod3 = { exports: {} }).exports, mod3), mod3.exports;
5
5
  };
6
6
 
7
- // bin/Koffi/package/src/cnoke/src/tools.js
7
+ // ../../../bin/Koffi/package/src/cnoke/src/tools.js
8
8
  var require_tools = __commonJS({
9
- "bin/Koffi/package/src/cnoke/src/tools.js"(exports2, module2) {
9
+ "../../../bin/Koffi/package/src/cnoke/src/tools.js"(exports2, module2) {
10
10
  "use strict";
11
11
  var crypto = require("crypto");
12
12
  var fs2 = require("fs");
@@ -345,11 +345,7 @@ var require_tools = __commonJS({
345
345
  }
346
346
  function unlink_recursive(path3) {
347
347
  try {
348
- if (fs2.rmSync != null) {
349
- fs2.rmSync(path3, { recursive: true, maxRetries: process.platform == "win32" ? 3 : 0 });
350
- } else {
351
- fs2.rmdirSync(path3, { recursive: true, maxRetries: process.platform == "win32" ? 3 : 0 });
352
- }
348
+ fs2.rmSync(path3, { recursive: true, maxRetries: process.platform == "win32" ? 3 : 0 });
353
349
  } catch (err) {
354
350
  if (err.code !== "ENOENT")
355
351
  throw err;
@@ -397,12 +393,12 @@ var require_tools = __commonJS({
397
393
  }
398
394
  });
399
395
 
400
- // bin/Koffi/package/src/koffi/package.json
396
+ // ../../../bin/Koffi/package/src/koffi/package.json
401
397
  var require_package = __commonJS({
402
- "bin/Koffi/package/src/koffi/package.json"(exports2, module2) {
398
+ "../../../bin/Koffi/package/src/koffi/package.json"(exports2, module2) {
403
399
  module2.exports = {
404
400
  name: "koffi",
405
- version: "2.15.1",
401
+ version: "2.15.2-beta.2",
406
402
  description: "Fast and simple C FFI (foreign function interface) for Node.js",
407
403
  keywords: [
408
404
  "foreign",
@@ -434,7 +430,7 @@ var require_package = __commonJS({
434
430
  license: "MIT",
435
431
  cnoke: {
436
432
  api: "../../vendor/node-api-headers",
437
- output: "../../bin/Koffi/{{ platform }}_{{ arch }}",
433
+ output: "../../bin/Koffi/{{ toolchain }}",
438
434
  node: 16,
439
435
  napi: 8,
440
436
  require: "./index.js"
@@ -444,9 +440,9 @@ var require_package = __commonJS({
444
440
  }
445
441
  });
446
442
 
447
- // bin/Koffi/package/src/koffi/src/init.js
443
+ // ../../../bin/Koffi/package/src/koffi/src/init.js
448
444
  var require_init = __commonJS({
449
- "bin/Koffi/package/src/koffi/src/init.js"(exports, module) {
445
+ "../../../bin/Koffi/package/src/koffi/src/init.js"(exports, module) {
450
446
  var fs = require("fs");
451
447
  var path = require("path");
452
448
  var util = require("util");
@@ -477,6 +473,7 @@ var require_init = __commonJS({
477
473
  triplets.push(musl);
478
474
  }
479
475
  let filenames = roots.flatMap((root) => triplets.flatMap((triplet3) => [
476
+ `${root}/koffi/build/koffi/${triplet3}/koffi.node`,
480
477
  `${root}/build/koffi/${triplet3}/koffi.node`,
481
478
  `${root}/koffi/${triplet3}/koffi.node`,
482
479
  `${root}/node_modules/koffi/build/koffi/${triplet3}/koffi.node`,
@@ -529,7 +526,7 @@ var require_init = __commonJS({
529
526
  }
530
527
  });
531
528
 
532
- // bin/Koffi/package/src/koffi/index.js
529
+ // ../../../bin/Koffi/package/src/koffi/index.js
533
530
  var { detect: detect2, init: init2 } = require_init();
534
531
  var triplet2 = detect2();
535
532
  var native2 = null;
package/indirect.js CHANGED
@@ -4,9 +4,9 @@ var __commonJS = (cb, mod3) => function __require() {
4
4
  return mod3 || (0, cb[__getOwnPropNames(cb)[0]])((mod3 = { exports: {} }).exports, mod3), mod3.exports;
5
5
  };
6
6
 
7
- // bin/Koffi/package/src/cnoke/src/tools.js
7
+ // ../../../bin/Koffi/package/src/cnoke/src/tools.js
8
8
  var require_tools = __commonJS({
9
- "bin/Koffi/package/src/cnoke/src/tools.js"(exports2, module2) {
9
+ "../../../bin/Koffi/package/src/cnoke/src/tools.js"(exports2, module2) {
10
10
  "use strict";
11
11
  var crypto = require("crypto");
12
12
  var fs2 = require("fs");
@@ -345,11 +345,7 @@ var require_tools = __commonJS({
345
345
  }
346
346
  function unlink_recursive(path3) {
347
347
  try {
348
- if (fs2.rmSync != null) {
349
- fs2.rmSync(path3, { recursive: true, maxRetries: process.platform == "win32" ? 3 : 0 });
350
- } else {
351
- fs2.rmdirSync(path3, { recursive: true, maxRetries: process.platform == "win32" ? 3 : 0 });
352
- }
348
+ fs2.rmSync(path3, { recursive: true, maxRetries: process.platform == "win32" ? 3 : 0 });
353
349
  } catch (err) {
354
350
  if (err.code !== "ENOENT")
355
351
  throw err;
@@ -397,12 +393,12 @@ var require_tools = __commonJS({
397
393
  }
398
394
  });
399
395
 
400
- // bin/Koffi/package/src/koffi/package.json
396
+ // ../../../bin/Koffi/package/src/koffi/package.json
401
397
  var require_package = __commonJS({
402
- "bin/Koffi/package/src/koffi/package.json"(exports2, module2) {
398
+ "../../../bin/Koffi/package/src/koffi/package.json"(exports2, module2) {
403
399
  module2.exports = {
404
400
  name: "koffi",
405
- version: "2.15.1",
401
+ version: "2.15.2-beta.2",
406
402
  description: "Fast and simple C FFI (foreign function interface) for Node.js",
407
403
  keywords: [
408
404
  "foreign",
@@ -434,7 +430,7 @@ var require_package = __commonJS({
434
430
  license: "MIT",
435
431
  cnoke: {
436
432
  api: "../../vendor/node-api-headers",
437
- output: "../../bin/Koffi/{{ platform }}_{{ arch }}",
433
+ output: "../../bin/Koffi/{{ toolchain }}",
438
434
  node: 16,
439
435
  napi: 8,
440
436
  require: "./index.js"
@@ -444,9 +440,9 @@ var require_package = __commonJS({
444
440
  }
445
441
  });
446
442
 
447
- // bin/Koffi/package/src/koffi/src/init.js
443
+ // ../../../bin/Koffi/package/src/koffi/src/init.js
448
444
  var require_init = __commonJS({
449
- "bin/Koffi/package/src/koffi/src/init.js"(exports, module) {
445
+ "../../../bin/Koffi/package/src/koffi/src/init.js"(exports, module) {
450
446
  var fs = require("fs");
451
447
  var path = require("path");
452
448
  var util = require("util");
@@ -477,6 +473,7 @@ var require_init = __commonJS({
477
473
  triplets.push(musl);
478
474
  }
479
475
  let filenames = roots.flatMap((root) => triplets.flatMap((triplet3) => [
476
+ `${root}/koffi/build/koffi/${triplet3}/koffi.node`,
480
477
  `${root}/build/koffi/${triplet3}/koffi.node`,
481
478
  `${root}/koffi/${triplet3}/koffi.node`,
482
479
  `${root}/node_modules/koffi/build/koffi/${triplet3}/koffi.node`,
@@ -529,7 +526,7 @@ var require_init = __commonJS({
529
526
  }
530
527
  });
531
528
 
532
- // bin/Koffi/package/src/koffi/indirect.js
529
+ // ../../../bin/Koffi/package/src/koffi/indirect.js
533
530
  var { detect: detect2, init: init2 } = require_init();
534
531
  var triplet2 = detect2();
535
532
  var mod2 = init2(triplet2, null);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "2.15.1",
3
+ "version": "2.15.2-beta.2",
4
4
  "description": "Fast and simple C FFI (foreign function interface) for Node.js",
5
5
  "keywords": [
6
6
  "foreign",
@@ -24,12 +24,12 @@
24
24
  "main": "./index.js",
25
25
  "types": "./index.d.ts",
26
26
  "scripts": {
27
- "install": "node src/cnoke/cnoke.js -p . -d src/koffi --prebuild"
27
+ "install": "node src/cnoke/cnoke.js -P . -D src/koffi --prebuild"
28
28
  },
29
29
  "license": "MIT",
30
30
  "cnoke": {
31
31
  "api": "../../vendor/node-api-headers",
32
- "output": "build/koffi/{{ platform }}_{{ arch }}",
32
+ "output": "build/koffi/{{ toolchain }}",
33
33
  "node": 16,
34
34
  "napi": 8,
35
35
  "require": "./index.js"
@@ -8,22 +8,6 @@ else()
8
8
  set(USE_UNITY_BUILDS OFF CACHE BOOL "Use single-TU builds (aka. Unity builds)")
9
9
  endif()
10
10
 
11
- if(NODE_JS_LINK_DEF)
12
- set(NODE_JS_LINK_LIB "${CMAKE_CURRENT_BINARY_DIR}/node.lib")
13
- if (MSVC)
14
- add_custom_command(OUTPUT node.lib
15
- COMMAND ${CMAKE_AR} ${CMAKE_STATIC_LINKER_FLAGS}
16
- /def:${NODE_JS_LINK_DEF} /out:${NODE_JS_LINK_LIB}
17
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
18
- MAIN_DEPENDENCY ${NODE_JS_LINK_DEF})
19
- else()
20
- add_custom_command(OUTPUT node.lib
21
- COMMAND ${CMAKE_DLLTOOL} -d ${NODE_JS_LINK_DEF} -l ${NODE_JS_LINK_LIB}
22
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
23
- MAIN_DEPENDENCY ${NODE_JS_LINK_DEF})
24
- endif()
25
- endif()
26
-
27
11
  function(add_node_addon)
28
12
  cmake_parse_arguments(ARG "" "NAME" "SOURCES" ${ARGN})
29
13
  add_library(${ARG_NAME} SHARED ${ARG_SOURCES} ${NODE_JS_SOURCES})
@@ -45,6 +29,33 @@ function(target_link_node TARGET)
45
29
  endif()
46
30
  endfunction()
47
31
 
32
+ if(WIN32)
33
+ function(create_import_lib OUTPUT SRC)
34
+ if (MSVC)
35
+ add_custom_command(OUTPUT ${OUTPUT}
36
+ COMMAND ${CMAKE_AR} ${CMAKE_STATIC_LINKER_FLAGS}
37
+ /def:${SRC} /out:"${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT}"
38
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
39
+ MAIN_DEPENDENCY ${SRC})
40
+ elseif(DEFINED NODE_JS_DLLTOOL_MACHINE)
41
+ add_custom_command(OUTPUT ${OUTPUT}
42
+ COMMAND ${CMAKE_DLLTOOL} -d ${SRC} -l "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT}" -m ${NODE_JS_DLLTOOL_MACHINE}
43
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
44
+ MAIN_DEPENDENCY ${SRC})
45
+ else()
46
+ add_custom_command(OUTPUT ${OUTPUT}
47
+ COMMAND ${CMAKE_DLLTOOL} -d ${SRC} -l "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT}"
48
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
49
+ MAIN_DEPENDENCY ${SRC})
50
+ endif()
51
+ endfunction()
52
+ endif()
53
+
54
+ if(NODE_JS_LINK_DEF)
55
+ create_import_lib(node.lib ${NODE_JS_LINK_DEF})
56
+ set(NODE_JS_LINK_LIB "${CMAKE_CURRENT_BINARY_DIR}/node.lib")
57
+ endif()
58
+
48
59
  if(USE_UNITY_BUILDS)
49
60
  function(enable_unity_build TARGET)
50
61
  cmake_parse_arguments(ARG "" "" "EXCLUDE" ${ARGN})
@@ -0,0 +1,126 @@
1
+ {
2
+ "linux_ia32": {
3
+ "system": "Linux",
4
+ "processor": "i386",
5
+ "triplet": "i686-linux-gnu",
6
+ "sysroot": "../../tools/cross/sysroots/debian_i386"
7
+ },
8
+ "linux_x64": {
9
+ "system": "Linux",
10
+ "processor": "x86_64",
11
+ "triplet": "x86_64-linux-gnu",
12
+ "sysroot": "../../tools/cross/sysroots/debian_x64"
13
+ },
14
+ "linux_armhf": {
15
+ "system": "Linux",
16
+ "processor": "arm",
17
+ "triplet": "arm-linux-gnueabihf",
18
+ "sysroot": "../../tools/cross/sysroots/debian_arm32"
19
+ },
20
+ "linux_arm64": {
21
+ "system": "Linux",
22
+ "processor": "aarch64",
23
+ "triplet": "aarch64-linux-gnu",
24
+ "sysroot": "../../tools/cross/sysroots/debian_arm64"
25
+ },
26
+ "linux_riscv64d": {
27
+ "system": "Linux",
28
+ "processor": "riscv64",
29
+ "triplet": "riscv64-linux-gnu",
30
+ "sysroot": "../../tools/cross/sysroots/debian_riscv64"
31
+ },
32
+ "linux_loong64": {
33
+ "system": "Linux",
34
+ "processor": "loongarch64",
35
+ "triplet": "loongarch64-linux-gnu",
36
+ "sysroot": "../../tools/cross/sysroots/debian_loong64"
37
+ },
38
+
39
+ "win32_ia32": {
40
+ "system": "Windows",
41
+ "processor": "X86",
42
+ "lib": "win-x86",
43
+ "flags": ["-DNODE_JS_LINK_FLAGS=/DELAYLOAD:node.exe;/SAFESEH:NO", "-A", "Win32"],
44
+
45
+ "triplet": "i386-pc-windows-msvc",
46
+ "linux": {
47
+ "sysroot": "../../tools/cross/sysroots/windows_i386",
48
+ "flags": ["-DNODE_JS_LINK_FLAGS=-Wl,/DELAYLOAD:node.exe,/SAFESEH:NO", "-DNODE_JS_DLLTOOL_MACHINE=i386"],
49
+ "variables": {
50
+ "CMAKE_DLLTOOL": "llvm-dlltool",
51
+ "CMAKE_RC_COMPILER": "llvm-rc",
52
+ "CMAKE_C_FLAGS": "-Xmicrosoft-windows-sys-root {{ sysroot }}",
53
+ "CMAKE_CXX_FLAGS": "-Xmicrosoft-windows-sys-root {{ sysroot }}",
54
+ "CMAKE_EXE_LINKER_FLAGS": "-Wl,-libpath:{{ sysroot }}/VC/Tools/MSVC/Current/lib/x86_64,-libpath:{{ sysroot }}/Kits/10/Lib/Current/ucrt/x86_64,-libpath:{{ sysroot }}/Kits/10/Lib/Current/um/x86_64 -ldelayimp",
55
+ "CMAKE_STATIC_LINKER_FLAGS": "-Wl,-libpath:{{ sysroot }}/VC/Tools/MSVC/Current/lib/x86_64,-libpath:{{ sysroot }}/Kits/10/Lib/Current/ucrt/x86_64,-libpath:{{ sysroot }}/Kits/10/Lib/Current/um/x86_64 -ldelayimp",
56
+ "CMAKE_SHARED_LINKER_FLAGS": "-Wl,-libpath:{{ sysroot }}/VC/Tools/MSVC/Current/lib/x86_64,-libpath:{{ sysroot }}/Kits/10/Lib/Current/ucrt/x86_64,-libpath:{{ sysroot }}/Kits/10/Lib/Current/um/x86_64 -ldelayimp"
57
+ }
58
+ }
59
+ },
60
+ "win32_x64": {
61
+ "system": "Windows",
62
+ "processor": "AMD64",
63
+ "lib": "win-x64",
64
+ "flags": ["-DNODE_JS_LINK_FLAGS=/DELAYLOAD:node.exe"],
65
+
66
+ "triplet": "x86_64-pc-windows-msvc",
67
+ "linux": {
68
+ "sysroot": "../../tools/cross/sysroots/windows_x64",
69
+ "flags": ["-DNODE_JS_LINK_FLAGS=-Wl,/DELAYLOAD:node.exe", "-DNODE_JS_DLLTOOL_MACHINE=i386:x86-64"],
70
+ "variables": {
71
+ "CMAKE_DLLTOOL": "llvm-dlltool",
72
+ "CMAKE_RC_COMPILER": "llvm-rc",
73
+ "CMAKE_C_FLAGS": "-Xmicrosoft-windows-sys-root {{ sysroot }}",
74
+ "CMAKE_CXX_FLAGS": "-Xmicrosoft-windows-sys-root {{ sysroot }}",
75
+ "CMAKE_EXE_LINKER_FLAGS": "-Wl,-libpath:{{ sysroot }}/VC/Tools/MSVC/Current/lib/x86_64,-libpath:{{ sysroot }}/Kits/10/Lib/Current/ucrt/x86_64,-libpath:{{ sysroot }}/Kits/10/Lib/Current/um/x86_64 -ldelayimp",
76
+ "CMAKE_STATIC_LINKER_FLAGS": "-Wl,-libpath:{{ sysroot }}/VC/Tools/MSVC/Current/lib/x86_64,-libpath:{{ sysroot }}/Kits/10/Lib/Current/ucrt/x86_64,-libpath:{{ sysroot }}/Kits/10/Lib/Current/um/x86_64 -ldelayimp",
77
+ "CMAKE_SHARED_LINKER_FLAGS": "-Wl,-libpath:{{ sysroot }}/VC/Tools/MSVC/Current/lib/x86_64,-libpath:{{ sysroot }}/Kits/10/Lib/Current/ucrt/x86_64,-libpath:{{ sysroot }}/Kits/10/Lib/Current/um/x86_64 -ldelayimp"
78
+ }
79
+ }
80
+ },
81
+ "win32_arm64": {
82
+ "system": "Windows",
83
+ "processor": "ARM64",
84
+ "lib": "win-arm64",
85
+ "flags": ["-DNODE_JS_LINK_FLAGS=/DELAYLOAD:node.exe;/SAFESEH:NO", "-A", "ARM64"],
86
+
87
+ "triplet": "aarch64-pc-windows-msvc",
88
+ "linux": {
89
+ "sysroot": "../../tools/cross/sysroots/windows_arm64",
90
+ "flags": ["-DNODE_JS_LINK_FLAGS=-Wl,/DELAYLOAD:node.exe,/SAFESEH:NO", "-DNODE_JS_DLLTOOL_MACHINE=arm64"],
91
+ "variables": {
92
+ "CMAKE_DLLTOOL": "llvm-dlltool",
93
+ "CMAKE_RC_COMPILER": "llvm-rc",
94
+ "CMAKE_C_FLAGS": "-Xmicrosoft-windows-sys-root {{ sysroot }}",
95
+ "CMAKE_CXX_FLAGS": "-Xmicrosoft-windows-sys-root {{ sysroot }}",
96
+ "CMAKE_EXE_LINKER_FLAGS": "-Wl,-libpath:{{ sysroot }}/VC/Tools/MSVC/Current/lib/aarch64,-libpath:{{ sysroot }}/Kits/10/Lib/Current/ucrt/aarch64,-libpath:{{ sysroot }}/Kits/10/Lib/Current/um/aarch64 -ldelayimp",
97
+ "CMAKE_STATIC_LINKER_FLAGS": "-Wl,-libpath:{{ sysroot }}/VC/Tools/MSVC/Current/lib/aarch64,-libpath:{{ sysroot }}/Kits/10/Lib/Current/ucrt/aarch64,-libpath:{{ sysroot }}/Kits/10/Lib/Current/um/aarch64 -ldelayimp",
98
+ "CMAKE_SHARED_LINKER_FLAGS": "-Wl,-libpath:{{ sysroot }}/VC/Tools/MSVC/Current/lib/aarch64,-libpath:{{ sysroot }}/Kits/10/Lib/Current/ucrt/aarch64,-libpath:{{ sysroot }}/Kits/10/Lib/Current/um/aarch64 -ldelayimp"
99
+ }
100
+ }
101
+ },
102
+
103
+ "darwin_x64": {
104
+ "system": "Darwin",
105
+ "processor": "x86_64",
106
+ "flags": ["-DNODE_JS_LINK_FLAGS=-undefined;dynamic_lookup", "-DCMAKE_OSX_ARCHITECTURES=x86_64"]
107
+ },
108
+ "darwin_arm64": {
109
+ "system": "Darwin",
110
+ "processor": "arm64",
111
+ "flags": ["-DNODE_JS_LINK_FLAGS=-undefined;dynamic_lookup", "-DCMAKE_OSX_ARCHITECTURES=arm64"]
112
+ },
113
+
114
+ "freebsd_x64": {
115
+ "system": "FreeBSD",
116
+ "processor": "amd64",
117
+ "triplet": "x86_64-unknown-freebsd",
118
+ "sysroot": "../../tools/cross/sysroots/freebsd_x64"
119
+ },
120
+ "freebsd_arm64": {
121
+ "system": "FreeBSD",
122
+ "processor": "arm64",
123
+ "triplet": "aarch64-unknown-freebsd",
124
+ "sysroot": "../../tools/cross/sysroots/freebsd_arm64"
125
+ }
126
+ }
@@ -53,41 +53,36 @@ async function main() {
53
53
  if (arg == '--help') {
54
54
  print_usage();
55
55
  return;
56
- } else if (arg == '-d' || arg == '--directory') {
56
+ } else if (arg == '-D' || arg == '--directory') {
57
57
  if (value == null)
58
58
  throw new Error(`Missing value for ${arg}`);
59
59
 
60
60
  config.project_dir = fs.realpathSync(value);
61
- } else if (arg == '-p' || arg == '--package') {
61
+ } else if (arg == '-P' || arg == '--package') {
62
62
  if (value == null)
63
63
  throw new Error(`Missing value for ${arg}`);
64
64
 
65
65
  config.package_dir = fs.realpathSync(value);
66
- } else if (arg == '-O' || arg == '--out') {
66
+ } else if (arg == '-O' || arg == '--output') {
67
67
  if (value == null)
68
68
  throw new Error(`Missing value for ${arg}`);
69
69
 
70
70
  config.output_directory = value;
71
- } else if ((command == 'build' || command == 'configure') && (arg == '-v' || arg == '--runtime-version')) {
71
+ } else if ((command == 'build' || command == 'configure') && arg == '--runtime') {
72
72
  if (value == null)
73
73
  throw new Error(`Missing value for ${arg}`);
74
74
  if (!value.match(/^[0-9]+\.[0-9]+\.[0-9]+$/))
75
75
  throw new Error(`Malformed runtime version '${value}'`);
76
76
 
77
77
  config.runtime_version = value;
78
- } else if ((command == 'build' || command == 'configure') && (arg == '-a' || arg == '--arch')) {
79
- if (value == null)
80
- throw new Error(`Missing value for ${arg}`);
81
-
82
- config.arch = value;
83
- } else if ((command == 'build' || command == 'configure') && (arg == '-t' || arg == '--toolset')) {
78
+ } else if ((command == 'build' || command == 'configure') && arg == '--clang') {
79
+ config.prefer_clang = true;
80
+ } else if ((command == 'build' || command == 'configure') && (arg == '-t' || arg == '--toolchain')) {
84
81
  if (value == null)
85
82
  throw new Error(`Missing value for ${arg}`);
86
83
 
87
- config.toolset = value;
88
- } else if ((command == 'build' || command == 'configure') && (arg == '-C' || arg == '--prefer-clang')) {
89
- config.prefer_clang = true;
90
- } else if ((command == 'build' || command == 'configure') && (arg == '-B' || arg == '--config')) {
84
+ config.toolchain = value;
85
+ } else if ((command == 'build' || command == 'configure') && (arg == '-c' || arg == '--config')) {
91
86
  if (value == null)
92
87
  throw new Error(`Missing value for ${arg}`);
93
88
 
@@ -100,17 +95,19 @@ async function main() {
100
95
  throw new Error(`Unknown value '${value}' for ${arg}`);
101
96
  } break;
102
97
  }
103
- } else if ((command == 'build' || command == 'configure') && (arg == '-D' || arg == '--debug')) {
98
+ } else if ((command == 'build' || command == 'configure') && arg == '--debug') {
104
99
  config.mode = 'Debug';
105
- } else if (command == 'build' && arg == '--verbose') {
106
- config.verbose = true;
100
+ } else if ((command == 'build' || command == 'configure') && arg == '--release') {
101
+ config.mode = 'Release';
107
102
  } else if (command == 'build' && arg == '--prebuild') {
108
103
  config.prebuild = true;
109
- } else if (command == 'build' && (arg == '-T' || arg == '--target')) {
104
+ } else if (command == 'build' && arg == '--target') {
110
105
  if (value == null)
111
106
  throw new Error(`Missing value for ${arg}`);
112
107
 
113
108
  config.targets = [value];
109
+ } else if (command == 'build' && (arg == '-v' || arg == '--verbose')) {
110
+ config.verbose = true;
114
111
  } else {
115
112
  if (arg[0] == '-') {
116
113
  throw new Error(`Unexpected argument '${arg}'`);
@@ -141,30 +138,27 @@ Commands:
141
138
 
142
139
  Options:
143
140
 
144
- -d, --directory <DIR> Change source directory
141
+ -D, --directory <DIR> Change source directory
145
142
  (default: current working directory)
146
- -p, --package <DIR> Change package directory
143
+ -P, --package <DIR> Change package directory
147
144
  (default: current working directory)
148
-
149
- -O, --out <DIR> Set explicit output directory
145
+ -O, --output <DIR> Set explicit output directory
150
146
  (default: ./build)
151
147
 
152
- -B, --config <CONFIG> Change build type: RelWithDebInfo, Debug, Release
148
+ -c, --config <CONFIG> Change build type: RelWithDebInfo, Debug, Release
153
149
  (default: ${cnoke.DefaultOptions.mode})
154
- -D, --debug Shortcut for --config Debug
150
+ --debug Shortcut for --config Debug
151
+ --release Shortcut for --config Release
155
152
 
156
- --prebuild Use prebuilt binary if available
157
-
158
- -a, --arch <ARCH> Change architecture and ABI
159
- (default: ${cnoke.determine_arch()})
160
- -v, --runtime-version <VERSION> Change node version
153
+ -t, --toolchain <TOOLCHAIN> Cross-compile for specific platform
154
+ --runtime <VERSION> Change node version
161
155
  (default: ${process.version})
162
- -t, --toolset <TOOLSET> Change default CMake toolset
163
- -C, --prefer-clang Use Clang instead of default CMake compiler
156
+ --clang Use Clang instead of default CMake compiler
164
157
 
165
- -T, --target <TARGET> Only build the specified target
158
+ --prebuild Use prebuilt binary if available
159
+ --target <TARGET> Only build the specified target
166
160
 
167
- --verbose Show build commands while building
161
+ -v, --verbose Show build commands while building
168
162
 
169
163
  The ARCH value is similar to process.arch, with the following differences:
170
164
 
@@ -8,6 +8,7 @@ const os = require('os');
8
8
  const path = require('path');
9
9
  const { spawnSync } = require('child_process');
10
10
  const tools = require('./tools.js');
11
+ const TOOLCHAINS = require('../assets/toolchains.json');
11
12
 
12
13
  const DefaultOptions = {
13
14
  mode: 'RelWithDebInfo'
@@ -16,6 +17,8 @@ const DefaultOptions = {
16
17
  function Builder(config = {}) {
17
18
  let self = this;
18
19
 
20
+ let host = `${process.platform}_${tools.determine_arch()}`;
21
+
19
22
  let app_dir = config.app_dir;
20
23
  let project_dir = config.project_dir;
21
24
  let package_dir = config.package_dir;
@@ -32,8 +35,7 @@ function Builder(config = {}) {
32
35
  package_dir = package_dir.replace(/\\/g, '/');
33
36
 
34
37
  let runtime_version = config.runtime_version;
35
- let arch = config.arch;
36
- let toolset = config.toolset || null;
38
+ let toolchain = config.toolchain || null;
37
39
  let prefer_clang = config.prefer_clang || false;
38
40
  let mode = config.mode || DefaultOptions.mode;
39
41
  let targets = config.targets || [];
@@ -44,8 +46,9 @@ function Builder(config = {}) {
44
46
  runtime_version = process.version;
45
47
  if (runtime_version.startsWith('v'))
46
48
  runtime_version = runtime_version.substr(1);
47
- if (arch == null)
48
- arch = tools.determine_arch();
49
+
50
+ if (toolchain != null && !Object.hasOwn(TOOLCHAINS, toolchain))
51
+ throw new Error(`Unknown cross-compilation toolchain '${toolchain}'`);
49
52
 
50
53
  let options = null;
51
54
 
@@ -64,7 +67,7 @@ function Builder(config = {}) {
64
67
  }
65
68
  }
66
69
  build_dir = build_dir.replace(/\\/g, '/');
67
- work_dir = build_dir + `/v${runtime_version}_${arch}/${mode}`;
70
+ work_dir = build_dir + `/v${runtime_version}_${toolchain ?? 'native'}/${mode}`;
68
71
  output_dir = work_dir + '/Output';
69
72
 
70
73
  let cmake_bin = null;
@@ -78,7 +81,7 @@ function Builder(config = {}) {
78
81
  check_compatibility();
79
82
 
80
83
  console.log(`>> Node: ${runtime_version}`);
81
- console.log(`>> Target: ${process.platform}_${arch}`);
84
+ console.log(`>> Toolchain: ${toolchain ?? 'native'}`);
82
85
 
83
86
  // Prepare build directory
84
87
  fs.mkdirSync(build_dir, { recursive: true, mode: 0o755 });
@@ -103,77 +106,46 @@ function Builder(config = {}) {
103
106
  args.push(`-DNODE_JS_INCLUDE_DIRS=${work_dir}/headers/include/node`);
104
107
  } else {
105
108
  console.log(`>> Using local node-api headers`);
106
- args.push(`-DNODE_JS_INCLUDE_DIRS=${options.api}/include`);
109
+
110
+ let api_dir = expand_path(options.api, project_dir);
111
+ args.push(`-DNODE_JS_INCLUDE_DIRS=${api_dir}/include`);
107
112
  }
108
113
 
109
114
  args.push(`-DCMAKE_MODULE_PATH=${app_dir}/assets`);
110
115
 
111
- let win32 = (process.platform == 'win32');
112
- let msvc = (process.platform == 'win32' && process.env.MSYSTEM == null);
113
- let darwin = (process.platform == 'darwin');
116
+ let win32 = (toolchain ?? host).startsWith('win32_');
117
+ let mingw = (process.platform == 'win32' && process.env.MSYSTEM != null);
114
118
 
115
119
  // Handle Node import library on Windows
116
120
  if (win32) {
117
- if (msvc) {
118
- if (options.api == null) {
119
- let dirname;
120
- switch (arch) {
121
- case 'ia32': { dirname = 'win-x86'; } break;
122
- case 'x64': { dirname = 'win-x64'; } break;
123
- case 'arm64': { dirname = 'win-arm64'; } break;
124
-
125
- default: {
126
- throw new Error(`Unsupported architecture '${arch}' for Node on Windows`);
127
- } break;
128
- }
121
+ if (mingw) {
122
+ args.push(`-DNODE_JS_LINK_LIB=node.dll`);
123
+ } else {
124
+ let info = TOOLCHAINS[toolchain ?? host];
129
125
 
130
- let destname = `${cache_dir}/node_v${runtime_version}_${arch}.lib`;
126
+ if (options.api == null) {
127
+ let destname = `${cache_dir}/node_v${runtime_version}_${toolchain ?? host}.lib`;
131
128
 
132
129
  if (!fs.existsSync(destname)) {
133
130
  fs.mkdirSync(cache_dir, { recursive: true, mode: 0o755 });
134
131
 
135
- let url = `https://nodejs.org/dist/v${runtime_version}/${dirname}/node.lib`;
132
+ let url = `https://nodejs.org/dist/v${runtime_version}/${info.lib}/node.lib`;
136
133
  await tools.download_http(url, destname);
137
134
  }
138
135
 
139
136
  fs.copyFileSync(destname, work_dir + '/node.lib');
140
137
  args.push(`-DNODE_JS_LINK_LIB=${work_dir}/node.lib`);
141
138
  } else {
142
- args.push(`-DNODE_JS_LINK_DEF=${options.api}/def/node_api.def`);
143
- }
144
-
145
- switch (arch) {
146
- case 'ia32': {
147
- args.push('-DNODE_JS_LINK_FLAGS=/DELAYLOAD:node.exe;/SAFESEH:NO');
148
- args.push('-A', 'Win32');
149
- } break;
150
- case 'arm64': {
151
- args.push('-DNODE_JS_LINK_FLAGS=/DELAYLOAD:node.exe;/SAFESEH:NO');
152
- args.push('-A', 'ARM64');
153
- } break;
154
- case 'x64': {
155
- args.push('-DNODE_JS_LINK_FLAGS=/DELAYLOAD:node.exe');
156
- args.push('-A', 'x64');
157
- } break;
139
+ let api_dir = expand_path(options.api, project_dir);
140
+ args.push(`-DNODE_JS_LINK_DEF=${api_dir}/def/node_api.def`);
158
141
  }
159
-
160
- fs.copyFileSync(`${app_dir}/assets/win_delay_hook.c`, work_dir + '/win_delay_hook.c');
161
- args.push(`-DNODE_JS_SOURCES=${work_dir}/win_delay_hook.c`);
162
- } else {
163
- args.push(`-DNODE_JS_LINK_LIB=node.dll`);
164
142
  }
165
- }
166
-
167
- if (darwin) {
168
- args.push('-DNODE_JS_LINK_FLAGS=-undefined;dynamic_lookup');
169
143
 
170
- switch (arch) {
171
- case 'arm64': { args.push('-DCMAKE_OSX_ARCHITECTURES=arm64'); } break;
172
- case 'x64': { args.push('-DCMAKE_OSX_ARCHITECTURES=x86_64'); } break;
173
- }
144
+ fs.copyFileSync(`${app_dir}/assets/win_delay_hook.c`, work_dir + '/win_delay_hook.c');
145
+ args.push(`-DNODE_JS_SOURCES=${work_dir}/win_delay_hook.c`);
174
146
  }
175
147
 
176
- if (!msvc) {
148
+ if (process.platform != 'win32' || mingw) {
177
149
  if (spawnSync('ninja', ['--version']).status === 0) {
178
150
  args.push('-G', 'Ninja');
179
151
  } else if (process.platform == 'win32') {
@@ -186,16 +158,89 @@ function Builder(config = {}) {
186
158
  args.push('-DCMAKE_CXX_COMPILER_LAUNCHER=ccache');
187
159
  }
188
160
  }
161
+
162
+ // Handle toolchain flags and cross-compilation
163
+ {
164
+ let info = TOOLCHAINS[toolchain ?? host];
165
+
166
+ if (info != null) {
167
+ if (Object.hasOwn(info, process.platform))
168
+ info = Object.assign({}, info, info[process.platform]);
169
+
170
+ if (info.flags != null)
171
+ args.push(...info.flags);
172
+ }
173
+
174
+ if (toolchain == null && process.arch == 'ia32') {
175
+ let proc = spawnSync('uname', ['-m']);
176
+ let machine = (proc.stdout ?? '').toString('utf-8').trim();
177
+
178
+ if (machine == 'x86_64') {
179
+ // Compiler probably does not default to 32-bit... just force it
180
+ args.push('-DCMAKE_ASM_FLAGS=-m32', '-DCMAKE_C_FLAGS=-m32', '-DCMAKE_CXX_FLAGS=-m32');
181
+ }
182
+ }
183
+
184
+ if (toolchain != null && info.triplet != null) {
185
+ let values = [
186
+ ['CMAKE_SYSTEM_NAME', info.system],
187
+ ['CMAKE_SYSTEM_PROCESSOR', info.processor]
188
+ ];
189
+ let sysroot = null;
190
+
191
+ // Switch to Clang automatically if the GCC cross-compiler does not exist
192
+ if (process.platform != 'win32' && !prefer_clang) {
193
+ let binary = info.triplet + '-gcc';
194
+
195
+ if (spawnSync(binary, ['-v']).status !== 0)
196
+ prefer_clang = true;
197
+ }
198
+
199
+ if (prefer_clang) {
200
+ values.push(['CMAKE_ASM_COMPILER_TARGET', info.triplet]);
201
+ values.push(['CMAKE_C_COMPILER_TARGET', info.triplet]);
202
+ values.push(['CMAKE_CXX_COMPILER_TARGET', info.triplet]);
203
+
204
+ values.push(['CMAKE_EXE_LINKER_FLAGS', '-fuse-ld=lld']);
205
+ values.push(['CMAKE_SHARED_LINKER_FLAGS', '-fuse-ld=lld']);
206
+ values.push(['CMAKE_STATIC_LINKER_FLAGS', '-fuse-ld=lld']);
207
+ } else if (process.platform != 'win32') {
208
+ values.push(['CMAKE_ASM_COMPILER', info.triplet + '-gcc']);
209
+ values.push(['CMAKE_C_COMPILER', info.triplet + '-gcc']);
210
+ values.push(['CMAKE_CXX_COMPILER', info.triplet + '-g++']);
211
+ }
212
+
213
+ if (info.sysroot != null) {
214
+ sysroot = expand_path(info.sysroot, __dirname + '/..');
215
+ if (!fs.existsSync(sysroot))
216
+ throw new Error(`Cross-compilation sysroot '${sysroot}' does not exist`);
217
+
218
+ values.push(['CMAKE_SYSROOT', sysroot]);
219
+ }
220
+
221
+ if (info.variables != null) {
222
+ for (let key in info.variables) {
223
+ let value = expand_string(info.variables[key], { sysroot: sysroot });
224
+ values.push([key, value]);
225
+ }
226
+ }
227
+
228
+ let filename = `${work_dir}/toolchain.cmake`;
229
+ let text = values.map(pair => `set(${pair[0]} "${pair[1]}")`).join('\n');
230
+
231
+ fs.writeFileSync(filename, text);
232
+ args.push(`-DCMAKE_TOOLCHAIN_FILE=${filename}`);
233
+ }
234
+ }
235
+
189
236
  if (prefer_clang) {
190
- if (msvc) {
237
+ if (process.platform == 'win32' && !mingw) {
191
238
  args.push('-T', 'ClangCL');
192
239
  } else {
193
240
  args.push('-DCMAKE_C_COMPILER=clang');
194
241
  args.push('-DCMAKE_CXX_COMPILER=clang++');
195
242
  }
196
243
  }
197
- if (toolset != null)
198
- args.push('-T', toolset);
199
244
 
200
245
  args.push(`-DCMAKE_BUILD_TYPE=${mode}`);
201
246
  for (let type of ['ARCHIVE', 'RUNTIME', 'LIBRARY']) {
@@ -231,8 +276,9 @@ function Builder(config = {}) {
231
276
  await self.configure();
232
277
 
233
278
  // In case Make gets used
279
+ // os.cpus() returns [] on Android (no /proc/cpuinfo access), so fall back to 1
234
280
  if (process.env.MAKEFLAGS == null)
235
- process.env.MAKEFLAGS = '-j' + os.cpus().length;
281
+ process.env.MAKEFLAGS = '-j' + (os.cpus().length || 1);
236
282
 
237
283
  let args = [
238
284
  '--build', work_dir,
@@ -423,22 +469,35 @@ function Builder(config = {}) {
423
469
  return options;
424
470
  }
425
471
 
426
- function expand_path(str, root_dir) {
472
+ function expand_string(str, values = {}) {
427
473
  let expanded = str.replace(/{{ *([a-zA-Z_][a-zA-Z_0-9]*) *}}/g, (match, p1) => {
428
474
  switch (p1) {
429
475
  case 'version': {
430
476
  let options = read_cnoke_options();
431
477
  return options.version || '';
432
478
  } break;
433
- case 'platform': return process.platform;
434
- case 'arch': return arch;
435
479
 
436
- default: return match;
480
+ case 'toolchain': return toolchain ?? host;
481
+
482
+ default: {
483
+ if (Object.hasOwn(values, p1)) {
484
+ return values[p1];
485
+ } else {
486
+ return match;
487
+ }
488
+ } break;
437
489
  }
438
490
  });
439
491
 
492
+ return expanded;
493
+ }
494
+
495
+ function expand_path(str, root) {
496
+ let expanded = expand_string(str);
497
+
440
498
  if (!tools.path_is_absolute(expanded))
441
- expanded = path.join(root_dir, expanded);
499
+ expanded = path.join(root, expanded);
500
+ expanded = path.normalize(expanded);
442
501
 
443
502
  return expanded;
444
503
  }
@@ -351,11 +351,7 @@ function decode_elf_header(buf) {
351
351
 
352
352
  function unlink_recursive(path) {
353
353
  try {
354
- if (fs.rmSync != null) {
355
- fs.rmSync(path, { recursive: true, maxRetries: process.platform == 'win32' ? 3 : 0 });
356
- } else {
357
- fs.rmdirSync(path, { recursive: true, maxRetries: process.platform == 'win32' ? 3 : 0 });
358
- }
354
+ fs.rmSync(path, { recursive: true, maxRetries: process.platform == 'win32' ? 3 : 0 });
359
355
  } catch (err) {
360
356
  if (err.code !== 'ENOENT')
361
357
  throw err;
@@ -1,7 +1,7 @@
1
1
  # SPDX-License-Identifier: MIT
2
2
  # SPDX-FileCopyrightText: 2025 Niels Martignène <niels.martignene@protonmail.com>
3
3
 
4
- cmake_minimum_required(VERSION 3.6)
4
+ cmake_minimum_required(VERSION 3.10)
5
5
  cmake_policy(SET CMP0091 NEW)
6
6
 
7
7
  if(NOT NODE_JS_INCLUDE_DIRS)
@@ -38,6 +38,7 @@ function init(triplet, native) {
38
38
  }
39
39
 
40
40
  let filenames = roots.flatMap(root => triplets.flatMap(triplet => [
41
+ `${root}/koffi/build/koffi/${triplet}/koffi.node`,
41
42
  `${root}/build/koffi/${triplet}/koffi.node`,
42
43
  `${root}/koffi/${triplet}/koffi.node`,
43
44
  `${root}/node_modules/koffi/build/koffi/${triplet}/koffi.node`,