Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src: add support for locally installed headers #2964

Merged
merged 7 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion lib/configure.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict'

const { promises: fs } = require('graceful-fs')
const { promises: fs, readFileSync } = require('graceful-fs')
const path = require('path')
const log = require('./log')
const os = require('os')
Expand All @@ -13,6 +13,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 +31,28 @@ async function configure (gyp, argv) {
// 'python' should be set by now
process.env.PYTHON = python

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
const prefix = process.config.variables.node_prefix
let availVersion
try {
const nodeVersionH = 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
123 changes: 123 additions & 0 deletions test/test-configure-nodedir.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
'use strict'

const { describe, it } = require('mocha')
const assert = require('assert')
const path = require('path')
const os = require('os')
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() } })

const driveLetter = os.platform() === 'win32' ? `${process.cwd().split(path.sep)[0]}` : ''
function checkTargetPath (target, value) {
let targetPath = path.join(path.sep, target, 'include',
'node', 'common.gypi')
if (process.platform === 'win32') {
targetPath = driveLetter + targetPath
}

return targetPath.localeCompare(value) === 0
}

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

prog.spawn = function (program, args) {
for (let i = 0; i < args.length; i++) {
if (checkTargetPath('usr', args[i])) {
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 (checkTargetPath(nodedir, args[i])) {
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 (checkTargetPath(nodedir, args[i])) {
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 (checkTargetPath(nodedir, args[i])) {
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