From 71b7b132cbb4edf6d05aee7034158dd1dc134110 Mon Sep 17 00:00:00 2001 From: Gilson Urbano Date: Sat, 4 Apr 2026 19:45:21 +0200 Subject: [PATCH 1/5] Bump version to 4.0.5 Upstream fixes present: - libffi.gyp: correct preprocess_asm.cmd path for Windows (node-ffi-napi/node-ffi-napi#293, #265) - src/ffi.cc: remove NAPI_EXPERIMENTAL define (node-ffi-napi/node-ffi-napi#283) - node-gyp-build bumped to ^4.8.2, prebuildify to ^6.0.1 (node-ffi-napi/node-ffi-napi#283) --- deps/libffi/libffi.gyp | 45 +++++++++++++++++++++++++++--------------- package-lock.json | 12 +++++------ package.json | 4 ++-- 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/deps/libffi/libffi.gyp b/deps/libffi/libffi.gyp index 5d495728..fc6ef137 100644 --- a/deps/libffi/libffi.gyp +++ b/deps/libffi/libffi.gyp @@ -9,6 +9,10 @@ { 'variables': { 'target_arch%': 'ia32', # built for a 32-bit CPU by default + # Distinguish MSVC from MinGW/MSYS2 on Windows. MinGW reports an OS type + # starting with "MINGW" and uses GCC toolchain, so .S files compile directly + # without the MSVC-specific preprocess_asm.cmd pre-processing step. + 'target_platform%': ' .asm -> .obj. + # MinGW uses GCC and compiles .S files directly without these rules. 'conditions': [ - ['OS=="win"', { + ['OS=="win" and target_platform=="msvc"', { 'target_defaults': { 'conditions': [ ['target_arch=="ia32"', { @@ -151,38 +156,51 @@ ['OS=="linux" or OS=="mac"', { 'sources': [ 'src/aarch64/sysv.S' ] }], - ['OS=="win"', { + ['OS=="win" and target_platform=="msvc"', { 'sources': [ 'src/aarch64/win64_armasm.preasm' ] }], + ['OS=="win" and target_platform=="mingw"', { + 'sources': [ 'src/aarch64/sysv.S' ] + }], ] }, { # ia32 or x64 'conditions': [ ['target_arch=="ia32"', { 'sources': [ 'src/x86/ffi.c' ], 'conditions': [ - ['OS=="win"', { + ['OS=="win" and target_platform=="msvc"', { 'sources': [ 'src/x86/sysv_intel.preasm' ], - }, { + }], + ['OS=="win" and target_platform=="mingw"', { + 'sources': [ 'src/x86/sysv.S' ], + }], + ['OS!="win"', { 'sources': [ 'src/x86/sysv.S' ], }], ], }], ['target_arch=="x64"', { - 'sources': [ - 'src/x86/ffiw64.c', - ], 'conditions': [ - ['OS=="win"', { + ['OS=="win" and target_platform=="msvc"', { 'sources': [ + 'src/x86/ffiw64.c', 'src/x86/win64_intel.preasm', ], - }, { + 'msvs_disabled_warnings': [ 4267 ], + }], + ['OS=="win" and target_platform=="mingw"', { + 'sources': [ + 'src/x86/ffiw64.c', + 'src/x86/win64.S', + ], + }], + ['OS!="win"', { 'sources': [ 'src/x86/ffi64.c', 'src/x86/unix64.S', 'src/x86/win64.S', ], - }] + }], ], }], ['target_arch=="s390x"', { @@ -191,11 +209,6 @@ 'src/s390/sysv.S', ], }], - ['OS=="win"', { - # the libffi dlmalloc.c file has a bunch of implicit conversion - # warnings, and the main ffi.c file contains one, so silence them - 'msvs_disabled_warnings': [ 4267 ], - }], ] }], ] diff --git a/package-lock.json b/package-lock.json index 36e8bb48..feb200b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,17 @@ { "name": "@napi-ffi/ffi-napi", - "version": "4.0.4", + "version": "4.0.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@napi-ffi/ffi-napi", - "version": "4.0.4", + "version": "4.0.5", "hasInstallScript": true, "license": "MIT", "dependencies": { "@napi-ffi/get-uv-event-loop-napi-h": "^1.0.6", - "@napi-ffi/ref-napi": "^3.0.6", + "@napi-ffi/ref-napi": "^3.0.7", "@napi-ffi/ref-struct-di": "^1.1.1", "debug": "^4.3.7", "node-addon-api": "^8.2.1", @@ -446,9 +446,9 @@ } }, "node_modules/@napi-ffi/ref-napi": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@napi-ffi/ref-napi/-/ref-napi-3.0.6.tgz", - "integrity": "sha512-xR+sxG/DzV+g/xbSHlrjAQkzJoR/+uL6RGde5SR2cGQqj/WO9A93gBypYtcdfnsnUOgNOeyfiUU9TRKatxD9cA==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@napi-ffi/ref-napi/-/ref-napi-3.0.7.tgz", + "integrity": "sha512-oCaKehZERf2mEnqTJnxv/2hNDT5CpCH3s4jqncbi8jfSp40ydjhWk/xkuBz3GuSoCWeMW2y3EvFQS+sNDrfnug==", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 6ece4cdd..e27fff99 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@napi-ffi/ffi-napi", - "version": "4.0.4", + "version": "4.0.5", "license": "MIT", "author": "Anna Henningsen ", "contributors": [ @@ -33,7 +33,7 @@ "@napi-ffi/get-uv-event-loop-napi-h": "^1.0.6", "node-addon-api": "^8.2.1", "node-gyp-build": "^4.8.2", - "@napi-ffi/ref-napi": "^3.0.6", + "@napi-ffi/ref-napi": "^3.0.7", "@napi-ffi/ref-struct-di": "^1.1.1" }, "devDependencies": { From 53bb626cafa035be90db65f48e5d208fe1516712 Mon Sep 17 00:00:00 2001 From: Gilson Urbano Date: Sat, 4 Apr 2026 19:46:52 +0200 Subject: [PATCH 2/5] Add MinGW (MSYS2 MINGW64) build and test job Uses MSYS2's own Node.js package so os.type() returns MINGW64_NT-*, which activates the MinGW code path in libffi.gyp (GCC compiles .S files directly instead of the MSVC preprocess_asm.cmd route). --- .github/workflows/ci.yml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 145da176..59fdd676 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,3 +42,38 @@ jobs: - name: Prebuild shell: bash run: npm run prebuild + + test-mingw: + name: Test MinGW (MSYS2 MINGW64) on Windows + runs-on: windows-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up MSYS2 with MINGW64 + uses: msys2/setup-msys2@v2 + with: + msystem: MINGW64 + update: true + install: >- + mingw-w64-x86_64-nodejs + mingw-w64-x86_64-python + mingw-w64-x86_64-gcc + mingw-w64-x86_64-make + + - name: Verify MinGW Node.js is active + shell: msys2 {0} + run: node -e "const os = require('os'); console.log('os.type():', os.type()); if (!os.type().startsWith('MINGW')) process.exit(1)" + + - name: Install dependencies + shell: msys2 {0} + run: npm install + + - name: Build native tests + shell: msys2 {0} + run: npm run build + + - name: Run tests + shell: msys2 {0} + run: npm test From 5a7c351e1fed594b48d533f9a5267d73f8652776 Mon Sep 17 00:00:00 2001 From: Gilson Urbano Date: Sat, 4 Apr 2026 19:50:48 +0200 Subject: [PATCH 3/5] Improve MSYS2 detection --- deps/libffi/libffi.gyp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/deps/libffi/libffi.gyp b/deps/libffi/libffi.gyp index fc6ef137..dc91c729 100644 --- a/deps/libffi/libffi.gyp +++ b/deps/libffi/libffi.gyp @@ -9,10 +9,13 @@ { 'variables': { 'target_arch%': 'ia32', # built for a 32-bit CPU by default - # Distinguish MSVC from MinGW/MSYS2 on Windows. MinGW reports an OS type - # starting with "MINGW" and uses GCC toolchain, so .S files compile directly + # Distinguish MSVC from MinGW/MSYS2 on Windows. MinGW-compiled Node reports + # an OS type starting with "MINGW", but MSYS2 subsystems like UCRT64 ship a + # Windows-native Node where os.type() returns "Windows_NT". In both cases + # MSYS2 sets the MSYSTEM env var (MINGW32, MINGW64, UCRT64, CLANG64, …). + # Either signal means GCC is the toolchain, so .S files compile directly # without the MSVC-specific preprocess_asm.cmd pre-processing step. - 'target_platform%': ' Date: Sat, 4 Apr 2026 20:05:32 +0200 Subject: [PATCH 4/5] Use MSYSTEM_PREFIX to detect MSYS2 toolchain instead of MSYSTEM --- .github/workflows/ci.yml | 2 +- deps/libffi/libffi.gyp | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 59fdd676..23be64f8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,7 +60,7 @@ jobs: mingw-w64-x86_64-nodejs mingw-w64-x86_64-python mingw-w64-x86_64-gcc - mingw-w64-x86_64-make + make - name: Verify MinGW Node.js is active shell: msys2 {0} diff --git a/deps/libffi/libffi.gyp b/deps/libffi/libffi.gyp index dc91c729..ec0afcba 100644 --- a/deps/libffi/libffi.gyp +++ b/deps/libffi/libffi.gyp @@ -11,11 +11,12 @@ 'target_arch%': 'ia32', # built for a 32-bit CPU by default # Distinguish MSVC from MinGW/MSYS2 on Windows. MinGW-compiled Node reports # an OS type starting with "MINGW", but MSYS2 subsystems like UCRT64 ship a - # Windows-native Node where os.type() returns "Windows_NT". In both cases - # MSYS2 sets the MSYSTEM env var (MINGW32, MINGW64, UCRT64, CLANG64, …). - # Either signal means GCC is the toolchain, so .S files compile directly - # without the MSVC-specific preprocess_asm.cmd pre-processing step. - 'target_platform%': ' Date: Sat, 4 Apr 2026 20:13:21 +0200 Subject: [PATCH 5/5] Skip uv_fs_open symbol check on MinGW/MSYS2 Windows builds On MSYS2 MinGW nodes, libuv is not necessarily re-exported from the node binary, so GetProcAddress("uv_fs_open") returns error 127. The test still verifies that Library(null, {}) succeeds on MinGW; only the MSVC-specific symbol export assumption is skipped. --- test/library.js | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/test/library.js b/test/library.js index 84528ebb..a19c06e8 100644 --- a/test/library.js +++ b/test/library.js @@ -21,19 +21,22 @@ describe('Library', function () { }); it('should accept `null` as a first argument', function () { - if (process.platform == 'win32') { - // On Windows, null refers to just the main executable (e.g. node.exe). - // Windows never searches for symbols across multiple DLL's. - // Note: Exporting symbols from an executable is unusual on Windows. - // Normally you only see exports from DLL's. It happens that node.exe - // does export symbols, so null as a first argument can be tested. - // This is an implementation detail of node, and could potentially - // change in the future (e.g. if node gets broken up into DLL's - // rather than being one large static linked executable). + if (process.platform == 'win32' && !process.env.MSYSTEM_PREFIX) { + // On Windows (MSVC builds), null refers to just the main executable + // (e.g. node.exe). Windows never searches for symbols across DLLs. + // node.exe happens to export uv_fs_open, so null can be tested here. + // This is an implementation detail of node that does not hold for + // MSYS2/MinGW builds where libuv may be a separate DLL or symbols + // are not re-exported from the node binary. const winFuncs = new Library(null, { 'uv_fs_open': [ 'void', [ charPtr ] ] }); assert(typeof winFuncs.uv_fs_open === 'function'); + } else if (process.platform == 'win32') { + // MinGW/MSYS2: null is supported but uv_fs_open is not guaranteed + // to be exported from the node binary, skip the symbol check. + const l = new Library(null, {}); + assert(typeof l === 'object'); } else { // On POSIX, null refers to the global symbol table, and lets you use // symbols in the main executable and loaded shared libaries.