Skip to content

Commit 3298731

Browse files
mhdawsonlukekarrys
andauthored
src: add support for locally installed headers (#2964)
Some linux distros allow headers to be installed through tools like rpm. If the runtime sets process.config.variables.use_prefix_to_find_headers, look for matching headers based on the directory set for the prefix in process.config.variables.prefix Signed-off-by: Michael Dawson <[email protected]> Co-authored-by: Luke Karrys <[email protected]>
1 parent 7705a22 commit 3298731

File tree

3 files changed

+151
-1
lines changed

3 files changed

+151
-1
lines changed

lib/configure.js

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict'
22

3-
const { promises: fs } = require('graceful-fs')
3+
const { promises: fs, readFileSync } = require('graceful-fs')
44
const path = require('path')
55
const log = require('./log')
66
const os = require('os')
@@ -13,6 +13,10 @@ const { findAccessibleSync } = require('./util')
1313
const { findPython } = require('./find-python')
1414
const { findVisualStudio } = win ? require('./find-visualstudio') : {}
1515

16+
const majorRe = /^#define NODE_MAJOR_VERSION (\d+)/m
17+
const minorRe = /^#define NODE_MINOR_VERSION (\d+)/m
18+
const patchRe = /^#define NODE_PATCH_VERSION (\d+)/m
19+
1620
async function configure (gyp, argv) {
1721
const buildDir = path.resolve('build')
1822
const configNames = ['config.gypi', 'common.gypi']
@@ -27,6 +31,28 @@ async function configure (gyp, argv) {
2731
// 'python' should be set by now
2832
process.env.PYTHON = python
2933

34+
if (!gyp.opts.nodedir &&
35+
process.config.variables.use_prefix_to_find_headers) {
36+
// check if the headers can be found using the prefix specified
37+
// at build time. Use them if they match the version expected
38+
const prefix = process.config.variables.node_prefix
39+
let availVersion
40+
try {
41+
const nodeVersionH = readFileSync(path.join(prefix,
42+
'include', 'node', 'node_version.h'), { encoding: 'utf8' })
43+
const major = nodeVersionH.match(majorRe)[1]
44+
const minor = nodeVersionH.match(minorRe)[1]
45+
const patch = nodeVersionH.match(patchRe)[1]
46+
availVersion = major + '.' + minor + '.' + patch
47+
} catch {}
48+
if (availVersion === release.version) {
49+
// ok version matches, use the headers
50+
gyp.opts.nodedir = prefix
51+
log.verbose('using local node headers based on prefix',
52+
'setting nodedir to ' + gyp.opts.nodedir)
53+
}
54+
}
55+
3056
if (gyp.opts.nodedir) {
3157
// --nodedir was specified. use that for the dev files
3258
nodeDir = gyp.opts.nodedir.replace(/^~/, os.homedir())

test/test-configure-nodedir.js

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
'use strict'
2+
3+
const { describe, it } = require('mocha')
4+
const assert = require('assert')
5+
const path = require('path')
6+
const os = require('os')
7+
const gyp = require('../lib/node-gyp')
8+
const requireInject = require('require-inject')
9+
const semver = require('semver')
10+
11+
const versionSemver = semver.parse(process.version)
12+
13+
const configure = requireInject('../lib/configure', {
14+
'graceful-fs': {
15+
openSync: () => 0,
16+
closeSync: () => {},
17+
existsSync: () => true,
18+
readFileSync: () => '#define NODE_MAJOR_VERSION ' + versionSemver.major + '\n' +
19+
'#define NODE_MINOR_VERSION ' + versionSemver.minor + '\n' +
20+
'#define NODE_PATCH_VERSION ' + versionSemver.patch + '\n',
21+
promises: {
22+
stat: async () => ({}),
23+
mkdir: async () => {},
24+
writeFile: async () => {}
25+
}
26+
}
27+
})
28+
29+
const configure2 = requireInject('../lib/configure', {
30+
'graceful-fs': {
31+
openSync: () => 0,
32+
closeSync: () => {},
33+
existsSync: () => true,
34+
readFileSync: () => '#define NODE_MAJOR_VERSION 8\n' +
35+
'#define NODE_MINOR_VERSION 0\n' +
36+
'#define NODE_PATCH_VERSION 0\n',
37+
promises: {
38+
stat: async () => ({}),
39+
mkdir: async () => {},
40+
writeFile: async () => {}
41+
}
42+
}
43+
})
44+
45+
const SPAWN_RESULT = cb => ({ on: function () { cb() } })
46+
47+
const driveLetter = os.platform() === 'win32' ? `${process.cwd().split(path.sep)[0]}` : ''
48+
function checkTargetPath (target, value) {
49+
let targetPath = path.join(path.sep, target, 'include',
50+
'node', 'common.gypi')
51+
if (process.platform === 'win32') {
52+
targetPath = driveLetter + targetPath
53+
}
54+
55+
return targetPath.localeCompare(value) === 0
56+
}
57+
58+
describe('configure-nodedir', function () {
59+
it('configure nodedir with node-gyp command line', function (done) {
60+
const prog = gyp()
61+
prog.parseArgv(['dummy_prog', 'dummy_script', '--nodedir=' + path.sep + 'usr'])
62+
63+
prog.spawn = function (program, args) {
64+
for (let i = 0; i < args.length; i++) {
65+
if (checkTargetPath('usr', args[i])) {
66+
return SPAWN_RESULT(done)
67+
}
68+
};
69+
assert.fail()
70+
}
71+
configure(prog, [], assert.fail)
72+
})
73+
74+
if (process.config.variables.use_prefix_to_find_headers) {
75+
it('use-prefix-to-find-headers build time option - match', function (done) {
76+
const prog = gyp()
77+
prog.parseArgv(['dummy_prog', 'dummy_script'])
78+
79+
prog.spawn = function (program, args) {
80+
for (let i = 0; i < args.length; i++) {
81+
const nodedir = process.config.variables.node_prefix
82+
if (checkTargetPath(nodedir, args[i])) {
83+
return SPAWN_RESULT(done)
84+
}
85+
};
86+
assert.fail()
87+
}
88+
configure(prog, [], assert.fail)
89+
})
90+
91+
it('use-prefix-to-find-headers build time option - no match', function (done) {
92+
const prog = gyp()
93+
prog.parseArgv(['dummy_prog', 'dummy_script'])
94+
95+
prog.spawn = function (program, args) {
96+
for (let i = 0; i < args.length; i++) {
97+
const nodedir = process.config.variables.node_prefix
98+
if (checkTargetPath(nodedir, args[i])) {
99+
assert.fail()
100+
}
101+
};
102+
return SPAWN_RESULT(done)
103+
}
104+
configure2(prog, [], assert.fail)
105+
})
106+
107+
it('use-prefix-to-find-headers build time option, target specified', function (done) {
108+
const prog = gyp()
109+
prog.parseArgv(['dummy_prog', 'dummy_script', '--target=8.0.0'])
110+
111+
prog.spawn = function (program, args) {
112+
for (let i = 0; i < args.length; i++) {
113+
const nodedir = process.config.variables.node_prefix
114+
if (checkTargetPath(nodedir, args[i])) {
115+
assert.fail()
116+
}
117+
};
118+
return SPAWN_RESULT(done)
119+
}
120+
configure(prog, [], assert.fail)
121+
})
122+
}
123+
})

test/test-configure-python.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const configure = requireInject('../lib/configure', {
1111
'graceful-fs': {
1212
openSync: () => 0,
1313
closeSync: () => {},
14+
existsSync: () => {},
1415
promises: {
1516
stat: async () => ({}),
1617
mkdir: async () => {},

0 commit comments

Comments
 (0)