diff --git a/lib/create-config-gypi.js b/lib/create-config-gypi.js index d471da5169..77149bdf62 100644 --- a/lib/create-config-gypi.js +++ b/lib/create-config-gypi.js @@ -47,6 +47,17 @@ async function getCurrentConfigGypi ({ gyp, nodeDir, vsInfo, python }) { const defaults = config.target_defaults const variables = config.variables + // When node itself is an Android build (e.g. Termux), process.config + // reports OS "android". gyp then enables Android-only branches (like the + // one referencing android_ndk_path in node's common.gypi) that only exist + // for NDK cross-compiles. Building a local addon on Android is a native + // build, not an NDK one, so normalize OS to linux. Honor custom headers + // (--nodedir/--dist-url): those may intentionally target Android via NDK. + if (process.platform === 'android' && variables.OS === 'android' && + !(gyp.opts.nodedir || gyp.opts.disturl || gyp.opts['dist-url'])) { + variables.OS = 'linux' + } + // don't inherit the "defaults" from the base config.gypi. // doing so could cause problems in cases where the `node` executable was // compiled on a different machine (with different lib/include paths) than diff --git a/test/test-create-config-gypi.js b/test/test-create-config-gypi.js index 602fd3d678..e75975549a 100644 --- a/test/test-create-config-gypi.js +++ b/test/test-create-config-gypi.js @@ -71,6 +71,55 @@ describe('create-config-gypi', function () { } }) + it('config.gypi normalizes OS to linux when running on Android (e.g. Termux)', async function () { + const prog = gyp() + prog.parseArgv([]) + + const originalPlatform = process.platform + const originalOS = process.config.variables.OS + Object.defineProperty(process, 'platform', { value: 'android' }) + // node built for Android reports OS "android" in process.config + let canStubOS = true + try { + Object.defineProperty(process.config.variables, 'OS', { value: 'android', configurable: true }) + } catch { + // process.config.variables is not extensible on some node builds + canStubOS = false + } + try { + const config = await getCurrentConfigGypi({ gyp: prog, vsInfo: {} }) + // a local addon build on Android is native, not an NDK cross-compile + if (canStubOS) { + assert.strictEqual(config.variables.OS, 'linux') + } else { + assert.ok(config.variables) + } + } finally { + if (canStubOS) { + Object.defineProperty(process.config.variables, 'OS', { value: originalOS, configurable: true }) + } + Object.defineProperty(process, 'platform', { value: originalPlatform }) + } + }) + + it('config.gypi keeps OS from custom headers when using --nodedir on Android', async function () { + const nodeDir = path.join(__dirname, 'fixtures', 'nodedir') + + const prog = gyp() + prog.parseArgv(['_', '_', `--nodedir=${nodeDir}`]) + + const originalPlatform = process.platform + Object.defineProperty(process, 'platform', { value: 'android' }) + try { + const config = await getCurrentConfigGypi({ gyp: prog, nodeDir, vsInfo: {} }) + // explicit custom headers may intentionally target Android via NDK: + // OS must come from the custom config.gypi, not process.config + assert.strictEqual(config.variables.OS, undefined) + } finally { + Object.defineProperty(process, 'platform', { value: originalPlatform }) + } + }) + it('config.gypi parsing', function () { const str = "# Some comments\n{'variables': {'multiline': 'A'\n'B'}}" const config = parseConfigGypi(str)