Skip to content

Commit dfb3666

Browse files
szegediclaude
andauthored
Fix v3 prebuild naming for Rust builds (#100)
* Fix v3 prebuild naming for Rust builds PR #90 refactored prebuild output naming into a shared prebuildFilename() function, but the v3 code path hardcoded the "node-{abi}.node" prefix, ignoring the baseName parameter. This broke Rust builds which previously preserved the original binary name from build/Release/ (e.g. "process-discovery-napi.node" became "node-napi.node"), causing consumers like libdatadog-nodejs to fail with "Could not find a {name} binary for {platform}". The fix makes prebuildFilename() use baseName in the v3 path, and passes 'node' from the non-Rust call site to preserve backward compatibility there. Test have also been added to cover the functionality. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 6f20997 commit dfb3666

4 files changed

Lines changed: 80 additions & 27 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"rebuild": "node-gyp rebuild",
1212
"prebuild": "node prebuild",
1313
"lint": "eslint .",
14-
"test": "node test"
14+
"test": "node test/naming && node test"
1515
},
1616
"dependencies": {
1717
"node-gyp-build": "^3.9.0"

prebuild/index.js

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const fs = require('fs')
66
const execSync = require('child_process').execSync
77
const semver = require('semver')
88
const { getFilteredNodeTargets } = require('./targets')
9+
const naming = require('./naming')
910

1011
const platform = os.platform()
1112
const arch = process.env.ARCH || os.arch()
@@ -28,35 +29,12 @@ const {
2829
NODE_GYP_BUILD_MAJOR = '3'
2930
} = process.env
3031

31-
// Prebuild directory and filename conventions differ between node-gyp-build v3 and v4:
32-
//
33-
// v3: prebuilds/${platform}${libc}-${arch}/node-${abi}.node
34-
// e.g. prebuilds/linuxglibc-arm64/node-115.node
35-
//
36-
// v4: prebuilds/${platform}-${arch}/${TARGET_NAME}[.musl].node.[napi|abi${N}].node
37-
// e.g. prebuilds/linux-arm64/dd_pprof.node.abi115.node
38-
// prebuilds/linux-arm64/dd_pprof.musl.node.napi.node
39-
//
40-
// When NODE_GYP_BUILD_MAJOR=4, libc is encoded as a filename tag ('musl' only;
41-
// glibc is the default and needs no tag) rather than in the directory name.
42-
4332
function prebuildDir () {
44-
if (NODE_GYP_BUILD_MAJOR === '4') {
45-
return `${DIRECTORY_PATH}/prebuilds/${platform}-${arch}`
46-
}
47-
return `${DIRECTORY_PATH}/prebuilds/${platform}${libc}-${arch}`
33+
return naming.prebuildDir(NODE_GYP_BUILD_MAJOR, DIRECTORY_PATH, platform, arch, libc)
4834
}
4935

5036
function prebuildFilename (abi, baseName) {
51-
if (NODE_GYP_BUILD_MAJOR === '4') {
52-
const libcTag = libc === 'musl' ? '.musl' : ''
53-
const abiTag = abi === 'napi' ? '.napi' : `.abi${abi}`
54-
return `${baseName}${libcTag}.node${abiTag}.node`
55-
}
56-
if (abi === 'napi') {
57-
return 'node-napi.node'
58-
}
59-
return `node-${abi}.node`
37+
return naming.prebuildFilename(NODE_GYP_BUILD_MAJOR, abi, baseName, libc)
6038
}
6139

6240
let alpineVersion
@@ -162,7 +140,8 @@ function prebuildTarget (arch, target) {
162140
fs.copyFileSync(`${DIRECTORY_PATH}/build/Release/${name}`, output)
163141
}
164142
} else {
165-
const output = `${prebuildDir()}/${prebuildFilename(target.abi, TARGET_NAME)}`
143+
const baseName = NODE_GYP_BUILD_MAJOR === '4' ? TARGET_NAME : 'node'
144+
const output = `${prebuildDir()}/${prebuildFilename(target.abi, baseName)}`
166145
const input = NAPI_RS === 'true'
167146
? `${DIRECTORY_PATH}/${TARGET_NAME}.node`
168147
: `${DIRECTORY_PATH}/build/Release/${TARGET_NAME}.node`

prebuild/naming.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
'use strict'
2+
3+
// Prebuild directory and filename conventions differ between node-gyp-build v3 and v4:
4+
//
5+
// v3: prebuilds/${platform}${libc}-${arch}/${baseName}-${abi}.node
6+
// e.g. prebuilds/linuxglibc-arm64/node-115.node
7+
// prebuilds/linuxmusl-x64/process-discovery-napi.node
8+
//
9+
// v4: prebuilds/${platform}-${arch}/${baseName}[.musl].node.[napi|abi${N}].node
10+
// e.g. prebuilds/linux-arm64/dd_pprof.node.abi115.node
11+
// prebuilds/linux-arm64/dd_pprof.musl.node.napi.node
12+
//
13+
// When nodeGypBuildMajor=4, libc is encoded as a filename tag ('musl' only;
14+
// glibc is the default and needs no tag) rather than in the directory name.
15+
16+
function prebuildDir (nodeGypBuildMajor, directoryPath, platform, arch, libc) {
17+
if (nodeGypBuildMajor === '4') {
18+
return `${directoryPath}/prebuilds/${platform}-${arch}`
19+
}
20+
return `${directoryPath}/prebuilds/${platform}${libc}-${arch}`
21+
}
22+
23+
function prebuildFilename (nodeGypBuildMajor, abi, baseName, libc) {
24+
if (nodeGypBuildMajor === '4') {
25+
const libcTag = libc === 'musl' ? '.musl' : ''
26+
const abiTag = abi === 'napi' ? '.napi' : `.abi${abi}`
27+
return `${baseName}${libcTag}.node${abiTag}.node`
28+
}
29+
if (abi === 'napi') {
30+
return `${baseName}-napi.node`
31+
}
32+
return `${baseName}-${abi}.node`
33+
}
34+
35+
module.exports = { prebuildDir, prebuildFilename }

test/naming.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
'use strict'
2+
3+
const { strictEqual } = require('assert')
4+
const { prebuildDir, prebuildFilename } = require('../prebuild/naming')
5+
6+
// --- prebuildDir ---
7+
8+
// v3: directory encodes libc
9+
strictEqual(prebuildDir('3', '.', 'linux', 'x64', 'glibc'), './prebuilds/linuxglibc-x64')
10+
strictEqual(prebuildDir('3', '.', 'linux', 'x64', 'musl'), './prebuilds/linuxmusl-x64')
11+
strictEqual(prebuildDir('3', '.', 'linux', 'arm64', 'glibc'), './prebuilds/linuxglibc-arm64')
12+
strictEqual(prebuildDir('3', '.', 'darwin', 'arm64', ''), './prebuilds/darwin-arm64')
13+
14+
// v4: no libc in directory
15+
strictEqual(prebuildDir('4', '.', 'linux', 'x64', 'glibc'), './prebuilds/linux-x64')
16+
strictEqual(prebuildDir('4', '.', 'linux', 'x64', 'musl'), './prebuilds/linux-x64')
17+
strictEqual(prebuildDir('4', '.', 'darwin', 'arm64', ''), './prebuilds/darwin-arm64')
18+
19+
// --- prebuildFilename ---
20+
21+
// v3 non-Rust (baseName='node'): traditional node-gyp-build convention
22+
strictEqual(prebuildFilename('3', 'napi', 'node', ''), 'node-napi.node')
23+
strictEqual(prebuildFilename('3', '115', 'node', ''), 'node-115.node')
24+
strictEqual(prebuildFilename('3', '127', 'node', 'musl'), 'node-127.node')
25+
26+
// v3 Rust (baseName from build output): preserves original binary name
27+
strictEqual(prebuildFilename('3', 'napi', 'process-discovery', ''), 'process-discovery-napi.node')
28+
strictEqual(prebuildFilename('3', 'napi', 'process-discovery', 'musl'), 'process-discovery-napi.node')
29+
strictEqual(prebuildFilename('3', 'napi', 'crashtracker', ''), 'crashtracker-napi.node')
30+
31+
// v4 non-Rust (baseName=TARGET_NAME): uses target name with libc tag
32+
strictEqual(prebuildFilename('4', 'napi', 'addon', ''), 'addon.node.napi.node')
33+
strictEqual(prebuildFilename('4', '115', 'addon', ''), 'addon.node.abi115.node')
34+
strictEqual(prebuildFilename('4', 'napi', 'addon', 'musl'), 'addon.musl.node.napi.node')
35+
strictEqual(prebuildFilename('4', '115', 'addon', 'musl'), 'addon.musl.node.abi115.node')
36+
37+
// v4 Rust (baseName from build output): uses original name with libc tag
38+
strictEqual(prebuildFilename('4', 'napi', 'dd_pprof', ''), 'dd_pprof.node.napi.node')
39+
strictEqual(prebuildFilename('4', 'napi', 'dd_pprof', 'musl'), 'dd_pprof.musl.node.napi.node')

0 commit comments

Comments
 (0)