Skip to content

Commit

Permalink
feat: add support for locally installed headers
Browse files Browse the repository at this point in the history
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 <midawson@redhat.com>
  • Loading branch information
mhdawson committed Jan 19, 2024
1 parent cff9ac2 commit a5ac175
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 0 deletions.
27 changes: 27 additions & 0 deletions lib/configure.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict'

const { promises: fs } = require('graceful-fs')
const fsSync = require('graceful-fs')
const path = require('path')
const log = require('./log')
const os = require('os')
Expand All @@ -13,6 +14,10 @@ const { findAccessibleSync } = require('./util')
const { findPython } = require('./find-python')
const { findVisualStudio } = win ? require('./find-visualstudio') : {}

const majorRe = /^#define NODE_MAJOR_VERSION (\d+)/m
const minorRe = /^#define NODE_MINOR_VERSION (\d+)/m
const patchRe = /^#define NODE_PATCH_VERSION (\d+)/m

async function configure (gyp, argv) {
const buildDir = path.resolve('build')
const configNames = ['config.gypi', 'common.gypi']
Expand All @@ -27,6 +32,28 @@ async function configure (gyp, argv) {
// 'python' should be set by now
process.env.PYTHON = python

const prefix = process.config.variables.node_prefix
if (!gyp.opts.nodedir &&
process.config.variables.use_prefix_to_find_headers) {
// check if the headers can be found using the prefix specified
// at build time. Use them if they match the version expected
let availVersion
try {
const nodeVersionH = fsSync.readFileSync(path.join(prefix,
'include', 'node', 'node_version.h'), { encoding: 'utf8' })
const major = nodeVersionH.match(majorRe)[1]
const minor = nodeVersionH.match(minorRe)[1]
const patch = nodeVersionH.match(patchRe)[1]
availVersion = major + '.' + minor + '.' + patch
} catch {}
if (availVersion === release.version) {
// ok version matches, use the headers
gyp.opts.nodedir = prefix
log.verbose('using local node headers based on prefix',
'setting nodedir to ' + gyp.opts.nodedir)
}
}

if (gyp.opts.nodedir) {
// --nodedir was specified. use that for the dev files
nodeDir = gyp.opts.nodedir.replace(/^~/, os.homedir())
Expand Down
115 changes: 115 additions & 0 deletions test/test-configure-nodedir.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
'use strict'

const { describe, it } = require('mocha')
const assert = require('assert')
const path = require('path')
const gyp = require('../lib/node-gyp')
const requireInject = require('require-inject')
const semver = require('semver')

const versionSemver = semver.parse(process.version)

const configure = requireInject('../lib/configure', {
'graceful-fs': {
openSync: () => 0,
closeSync: () => {},
existsSync: () => true,
readFileSync: () => '#define NODE_MAJOR_VERSION ' + versionSemver.major + '\n' +
'#define NODE_MINOR_VERSION ' + versionSemver.minor + '\n' +
'#define NODE_PATCH_VERSION ' + versionSemver.patch + '\n',
promises: {
stat: async () => ({}),
mkdir: async () => {},
writeFile: async () => {}
}
}
})

const configure2 = requireInject('../lib/configure', {
'graceful-fs': {
openSync: () => 0,
closeSync: () => {},
existsSync: () => true,
readFileSync: () => '#define NODE_MAJOR_VERSION 8\n' +
'#define NODE_MINOR_VERSION 0\n' +
'#define NODE_PATCH_VERSION 0\n',
promises: {
stat: async () => ({}),
mkdir: async () => {},
writeFile: async () => {}
}
}
})

const SPAWN_RESULT = cb => ({ on: function () { cb() } })

describe('configure-nodedir', function () {
it('configure nodedir with node-gyp command line', function (done) {
const prog = gyp()
prog.parseArgv(['dummy_prog', 'dummy_script', '--nodedir=/usr'])

prog.spawn = function (program, args) {
for (let i = 0; i < args.length; i++) {
if (path.join(path.sep, 'usr', 'include', 'node',
'common.gypi').localeCompare(args[i]) === 0) {
return SPAWN_RESULT(done)
}
};
assert.fail()
}
configure(prog, [], assert.fail)
})

if (process.config.variables.use_prefix_to_find_headers) {
it('use-prefix-to-find-headers build time option - match', function (done) {
const prog = gyp()
prog.parseArgv(['dummy_prog', 'dummy_script'])

prog.spawn = function (program, args) {
for (let i = 0; i < args.length; i++) {
const nodedir = process.config.variables.node_prefix
if (path.join(path.sep, nodedir, 'include', 'node',
'common.gypi').localeCompare(args[i]) === 0) {
return SPAWN_RESULT(done)
}
};
assert.fail()
}
configure(prog, [], assert.fail)
})

it('use-prefix-to-find-headers build time option - no match', function (done) {
const prog = gyp()
prog.parseArgv(['dummy_prog', 'dummy_script'])

prog.spawn = function (program, args) {
for (let i = 0; i < args.length; i++) {
const nodedir = process.config.variables.node_prefix
if (path.join(path.sep, nodedir, 'include', 'node',
'common.gypi').localeCompare(args[i]) === 0) {
assert.fail()
}
};
return SPAWN_RESULT(done)
}
configure2(prog, [], assert.fail)
})

it('use-prefix-to-find-headers build time option, target specified', function (done) {
const prog = gyp()
prog.parseArgv(['dummy_prog', 'dummy_script', '--target=8.0.0'])

prog.spawn = function (program, args) {
for (let i = 0; i < args.length; i++) {
const nodedir = process.config.variables.node_prefix
if (path.join(path.sep, nodedir, 'include', 'node',
'common.gypi').localeCompare(args[i]) === 0) {
assert.fail()
}
};
return SPAWN_RESULT(done)
}
configure(prog, [], assert.fail)
})
}
})
1 change: 1 addition & 0 deletions test/test-configure-python.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const configure = requireInject('../lib/configure', {
'graceful-fs': {
openSync: () => 0,
closeSync: () => {},
existsSync: () => {},
promises: {
stat: async () => ({}),
mkdir: async () => {},
Expand Down

0 comments on commit a5ac175

Please sign in to comment.