11cb0ef41Sopenharmony_ci'use strict'
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst { promises: fs } = require('graceful-fs')
41cb0ef41Sopenharmony_ciconst path = require('path')
51cb0ef41Sopenharmony_ciconst log = require('./log')
61cb0ef41Sopenharmony_ciconst os = require('os')
71cb0ef41Sopenharmony_ciconst processRelease = require('./process-release')
81cb0ef41Sopenharmony_ciconst win = process.platform === 'win32'
91cb0ef41Sopenharmony_ciconst findNodeDirectory = require('./find-node-directory')
101cb0ef41Sopenharmony_ciconst { createConfigGypi } = require('./create-config-gypi')
111cb0ef41Sopenharmony_ciconst { format: msgFormat } = require('util')
121cb0ef41Sopenharmony_ciconst { findAccessibleSync } = require('./util')
131cb0ef41Sopenharmony_ciconst { findPython } = require('./find-python')
141cb0ef41Sopenharmony_ciconst { findVisualStudio } = win ? require('./find-visualstudio') : {}
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ciasync function configure (gyp, argv) {
171cb0ef41Sopenharmony_ci  const buildDir = path.resolve('build')
181cb0ef41Sopenharmony_ci  const configNames = ['config.gypi', 'common.gypi']
191cb0ef41Sopenharmony_ci  const configs = []
201cb0ef41Sopenharmony_ci  let nodeDir
211cb0ef41Sopenharmony_ci  const release = processRelease(argv, gyp, process.version, process.release)
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_ci  const python = await findPython(gyp.opts.python)
241cb0ef41Sopenharmony_ci  return getNodeDir()
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ci  async function getNodeDir () {
271cb0ef41Sopenharmony_ci    // 'python' should be set by now
281cb0ef41Sopenharmony_ci    process.env.PYTHON = python
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ci    if (gyp.opts.nodedir) {
311cb0ef41Sopenharmony_ci      // --nodedir was specified. use that for the dev files
321cb0ef41Sopenharmony_ci      nodeDir = gyp.opts.nodedir.replace(/^~/, os.homedir())
331cb0ef41Sopenharmony_ci      log.verbose('get node dir', 'compiling against specified --nodedir dev files: %s', nodeDir)
341cb0ef41Sopenharmony_ci    } else {
351cb0ef41Sopenharmony_ci      // if no --nodedir specified, ensure node dependencies are installed
361cb0ef41Sopenharmony_ci      if ('v' + release.version !== process.version) {
371cb0ef41Sopenharmony_ci        // if --target was given, then determine a target version to compile for
381cb0ef41Sopenharmony_ci        log.verbose('get node dir', 'compiling against --target node version: %s', release.version)
391cb0ef41Sopenharmony_ci      } else {
401cb0ef41Sopenharmony_ci        // if no --target was specified then use the current host node version
411cb0ef41Sopenharmony_ci        log.verbose('get node dir', 'no --target version specified, falling back to host node version: %s', release.version)
421cb0ef41Sopenharmony_ci      }
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ci      if (!release.semver) {
451cb0ef41Sopenharmony_ci        // could not parse the version string with semver
461cb0ef41Sopenharmony_ci        throw new Error('Invalid version number: ' + release.version)
471cb0ef41Sopenharmony_ci      }
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ci      // If the tarball option is set, always remove and reinstall the headers
501cb0ef41Sopenharmony_ci      // into devdir. Otherwise only install if they're not already there.
511cb0ef41Sopenharmony_ci      gyp.opts.ensure = !gyp.opts.tarball
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ci      await gyp.commands.install([release.version])
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci      log.verbose('get node dir', 'target node version installed:', release.versionDir)
561cb0ef41Sopenharmony_ci      nodeDir = path.resolve(gyp.devDir, release.versionDir)
571cb0ef41Sopenharmony_ci    }
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci    return createBuildDir()
601cb0ef41Sopenharmony_ci  }
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci  async function createBuildDir () {
631cb0ef41Sopenharmony_ci    log.verbose('build dir', 'attempting to create "build" dir: %s', buildDir)
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci    const isNew = await fs.mkdir(buildDir, { recursive: true })
661cb0ef41Sopenharmony_ci    log.verbose(
671cb0ef41Sopenharmony_ci      'build dir', '"build" dir needed to be created?', isNew ? 'Yes' : 'No'
681cb0ef41Sopenharmony_ci    )
691cb0ef41Sopenharmony_ci    const vsInfo = win ? await findVisualStudio(release.semver, gyp.opts['msvs-version']) : null
701cb0ef41Sopenharmony_ci    return createConfigFile(vsInfo)
711cb0ef41Sopenharmony_ci  }
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci  async function createConfigFile (vsInfo) {
741cb0ef41Sopenharmony_ci    if (win) {
751cb0ef41Sopenharmony_ci      process.env.GYP_MSVS_VERSION = Math.min(vsInfo.versionYear, 2015)
761cb0ef41Sopenharmony_ci      process.env.GYP_MSVS_OVERRIDE_PATH = vsInfo.path
771cb0ef41Sopenharmony_ci    }
781cb0ef41Sopenharmony_ci    const configPath = await createConfigGypi({ gyp, buildDir, nodeDir, vsInfo, python })
791cb0ef41Sopenharmony_ci    configs.push(configPath)
801cb0ef41Sopenharmony_ci    return findConfigs()
811cb0ef41Sopenharmony_ci  }
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ci  async function findConfigs () {
841cb0ef41Sopenharmony_ci    const name = configNames.shift()
851cb0ef41Sopenharmony_ci    if (!name) {
861cb0ef41Sopenharmony_ci      return runGyp()
871cb0ef41Sopenharmony_ci    }
881cb0ef41Sopenharmony_ci
891cb0ef41Sopenharmony_ci    const fullPath = path.resolve(name)
901cb0ef41Sopenharmony_ci    log.verbose(name, 'checking for gypi file: %s', fullPath)
911cb0ef41Sopenharmony_ci    try {
921cb0ef41Sopenharmony_ci      await fs.stat(fullPath)
931cb0ef41Sopenharmony_ci      log.verbose(name, 'found gypi file')
941cb0ef41Sopenharmony_ci      configs.push(fullPath)
951cb0ef41Sopenharmony_ci    } catch (err) {
961cb0ef41Sopenharmony_ci      // ENOENT will check next gypi filename
971cb0ef41Sopenharmony_ci      if (err.code !== 'ENOENT') {
981cb0ef41Sopenharmony_ci        throw err
991cb0ef41Sopenharmony_ci      }
1001cb0ef41Sopenharmony_ci    }
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_ci    return findConfigs()
1031cb0ef41Sopenharmony_ci  }
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_ci  async function runGyp () {
1061cb0ef41Sopenharmony_ci    if (!~argv.indexOf('-f') && !~argv.indexOf('--format')) {
1071cb0ef41Sopenharmony_ci      if (win) {
1081cb0ef41Sopenharmony_ci        log.verbose('gyp', 'gyp format was not specified; forcing "msvs"')
1091cb0ef41Sopenharmony_ci        // force the 'make' target for non-Windows
1101cb0ef41Sopenharmony_ci        argv.push('-f', 'msvs')
1111cb0ef41Sopenharmony_ci      } else {
1121cb0ef41Sopenharmony_ci        log.verbose('gyp', 'gyp format was not specified; forcing "make"')
1131cb0ef41Sopenharmony_ci        // force the 'make' target for non-Windows
1141cb0ef41Sopenharmony_ci        argv.push('-f', 'make')
1151cb0ef41Sopenharmony_ci      }
1161cb0ef41Sopenharmony_ci    }
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_ci    // include all the ".gypi" files that were found
1191cb0ef41Sopenharmony_ci    configs.forEach(function (config) {
1201cb0ef41Sopenharmony_ci      argv.push('-I', config)
1211cb0ef41Sopenharmony_ci    })
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci    // For AIX and z/OS we need to set up the path to the exports file
1241cb0ef41Sopenharmony_ci    // which contains the symbols needed for linking.
1251cb0ef41Sopenharmony_ci    let nodeExpFile
1261cb0ef41Sopenharmony_ci    let nodeRootDir
1271cb0ef41Sopenharmony_ci    let candidates
1281cb0ef41Sopenharmony_ci    let logprefix = 'find exports file'
1291cb0ef41Sopenharmony_ci    if (process.platform === 'aix' || process.platform === 'os390' || process.platform === 'os400') {
1301cb0ef41Sopenharmony_ci      const ext = process.platform === 'os390' ? 'x' : 'exp'
1311cb0ef41Sopenharmony_ci      nodeRootDir = findNodeDirectory()
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ci      if (process.platform === 'aix' || process.platform === 'os400') {
1341cb0ef41Sopenharmony_ci        candidates = [
1351cb0ef41Sopenharmony_ci          'include/node/node',
1361cb0ef41Sopenharmony_ci          'out/Release/node',
1371cb0ef41Sopenharmony_ci          'out/Debug/node',
1381cb0ef41Sopenharmony_ci          'node'
1391cb0ef41Sopenharmony_ci        ].map(function (file) {
1401cb0ef41Sopenharmony_ci          return file + '.' + ext
1411cb0ef41Sopenharmony_ci        })
1421cb0ef41Sopenharmony_ci      } else {
1431cb0ef41Sopenharmony_ci        candidates = [
1441cb0ef41Sopenharmony_ci          'out/Release/lib.target/libnode',
1451cb0ef41Sopenharmony_ci          'out/Debug/lib.target/libnode',
1461cb0ef41Sopenharmony_ci          'out/Release/obj.target/libnode',
1471cb0ef41Sopenharmony_ci          'out/Debug/obj.target/libnode',
1481cb0ef41Sopenharmony_ci          'lib/libnode'
1491cb0ef41Sopenharmony_ci        ].map(function (file) {
1501cb0ef41Sopenharmony_ci          return file + '.' + ext
1511cb0ef41Sopenharmony_ci        })
1521cb0ef41Sopenharmony_ci      }
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci      nodeExpFile = findAccessibleSync(logprefix, nodeRootDir, candidates)
1551cb0ef41Sopenharmony_ci      if (nodeExpFile !== undefined) {
1561cb0ef41Sopenharmony_ci        log.verbose(logprefix, 'Found exports file: %s', nodeExpFile)
1571cb0ef41Sopenharmony_ci      } else {
1581cb0ef41Sopenharmony_ci        const msg = msgFormat('Could not find node.%s file in %s', ext, nodeRootDir)
1591cb0ef41Sopenharmony_ci        log.error(logprefix, 'Could not find exports file')
1601cb0ef41Sopenharmony_ci        throw new Error(msg)
1611cb0ef41Sopenharmony_ci      }
1621cb0ef41Sopenharmony_ci    }
1631cb0ef41Sopenharmony_ci
1641cb0ef41Sopenharmony_ci    // For z/OS we need to set up the path to zoslib include directory,
1651cb0ef41Sopenharmony_ci    // which contains headers included in v8config.h.
1661cb0ef41Sopenharmony_ci    let zoslibIncDir
1671cb0ef41Sopenharmony_ci    if (process.platform === 'os390') {
1681cb0ef41Sopenharmony_ci      logprefix = "find zoslib's zos-base.h:"
1691cb0ef41Sopenharmony_ci      let msg
1701cb0ef41Sopenharmony_ci      let zoslibIncPath = process.env.ZOSLIB_INCLUDES
1711cb0ef41Sopenharmony_ci      if (zoslibIncPath) {
1721cb0ef41Sopenharmony_ci        zoslibIncPath = findAccessibleSync(logprefix, zoslibIncPath, ['zos-base.h'])
1731cb0ef41Sopenharmony_ci        if (zoslibIncPath === undefined) {
1741cb0ef41Sopenharmony_ci          msg = msgFormat('Could not find zos-base.h file in the directory set ' +
1751cb0ef41Sopenharmony_ci                          'in ZOSLIB_INCLUDES environment variable: %s; set it ' +
1761cb0ef41Sopenharmony_ci                          'to the correct path, or unset it to search %s', process.env.ZOSLIB_INCLUDES, nodeRootDir)
1771cb0ef41Sopenharmony_ci        }
1781cb0ef41Sopenharmony_ci      } else {
1791cb0ef41Sopenharmony_ci        candidates = [
1801cb0ef41Sopenharmony_ci          'include/node/zoslib/zos-base.h',
1811cb0ef41Sopenharmony_ci          'include/zoslib/zos-base.h',
1821cb0ef41Sopenharmony_ci          'zoslib/include/zos-base.h',
1831cb0ef41Sopenharmony_ci          'install/include/node/zoslib/zos-base.h'
1841cb0ef41Sopenharmony_ci        ]
1851cb0ef41Sopenharmony_ci        zoslibIncPath = findAccessibleSync(logprefix, nodeRootDir, candidates)
1861cb0ef41Sopenharmony_ci        if (zoslibIncPath === undefined) {
1871cb0ef41Sopenharmony_ci          msg = msgFormat('Could not find any of %s in directory %s; set ' +
1881cb0ef41Sopenharmony_ci                          'environmant variable ZOSLIB_INCLUDES to the path ' +
1891cb0ef41Sopenharmony_ci                          'that contains zos-base.h', candidates.toString(), nodeRootDir)
1901cb0ef41Sopenharmony_ci        }
1911cb0ef41Sopenharmony_ci      }
1921cb0ef41Sopenharmony_ci      if (zoslibIncPath !== undefined) {
1931cb0ef41Sopenharmony_ci        zoslibIncDir = path.dirname(zoslibIncPath)
1941cb0ef41Sopenharmony_ci        log.verbose(logprefix, "Found zoslib's zos-base.h in: %s", zoslibIncDir)
1951cb0ef41Sopenharmony_ci      } else if (release.version.split('.')[0] >= 16) {
1961cb0ef41Sopenharmony_ci        // zoslib is only shipped in Node v16 and above.
1971cb0ef41Sopenharmony_ci        log.error(logprefix, msg)
1981cb0ef41Sopenharmony_ci        throw new Error(msg)
1991cb0ef41Sopenharmony_ci      }
2001cb0ef41Sopenharmony_ci    }
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_ci    // this logic ported from the old `gyp_addon` python file
2031cb0ef41Sopenharmony_ci    const gypScript = path.resolve(__dirname, '..', 'gyp', 'gyp_main.py')
2041cb0ef41Sopenharmony_ci    const addonGypi = path.resolve(__dirname, '..', 'addon.gypi')
2051cb0ef41Sopenharmony_ci    let commonGypi = path.resolve(nodeDir, 'include/node/common.gypi')
2061cb0ef41Sopenharmony_ci    try {
2071cb0ef41Sopenharmony_ci      await fs.stat(commonGypi)
2081cb0ef41Sopenharmony_ci    } catch (err) {
2091cb0ef41Sopenharmony_ci      commonGypi = path.resolve(nodeDir, 'common.gypi')
2101cb0ef41Sopenharmony_ci    }
2111cb0ef41Sopenharmony_ci
2121cb0ef41Sopenharmony_ci    let outputDir = 'build'
2131cb0ef41Sopenharmony_ci    if (win) {
2141cb0ef41Sopenharmony_ci      // Windows expects an absolute path
2151cb0ef41Sopenharmony_ci      outputDir = buildDir
2161cb0ef41Sopenharmony_ci    }
2171cb0ef41Sopenharmony_ci    const nodeGypDir = path.resolve(__dirname, '..')
2181cb0ef41Sopenharmony_ci
2191cb0ef41Sopenharmony_ci    let nodeLibFile = path.join(nodeDir,
2201cb0ef41Sopenharmony_ci      !gyp.opts.nodedir ? '<(target_arch)' : '$(Configuration)',
2211cb0ef41Sopenharmony_ci      release.name + '.lib')
2221cb0ef41Sopenharmony_ci
2231cb0ef41Sopenharmony_ci    argv.push('-I', addonGypi)
2241cb0ef41Sopenharmony_ci    argv.push('-I', commonGypi)
2251cb0ef41Sopenharmony_ci    argv.push('-Dlibrary=shared_library')
2261cb0ef41Sopenharmony_ci    argv.push('-Dvisibility=default')
2271cb0ef41Sopenharmony_ci    argv.push('-Dnode_root_dir=' + nodeDir)
2281cb0ef41Sopenharmony_ci    if (process.platform === 'aix' || process.platform === 'os390' || process.platform === 'os400') {
2291cb0ef41Sopenharmony_ci      argv.push('-Dnode_exp_file=' + nodeExpFile)
2301cb0ef41Sopenharmony_ci      if (process.platform === 'os390' && zoslibIncDir) {
2311cb0ef41Sopenharmony_ci        argv.push('-Dzoslib_include_dir=' + zoslibIncDir)
2321cb0ef41Sopenharmony_ci      }
2331cb0ef41Sopenharmony_ci    }
2341cb0ef41Sopenharmony_ci    argv.push('-Dnode_gyp_dir=' + nodeGypDir)
2351cb0ef41Sopenharmony_ci
2361cb0ef41Sopenharmony_ci    // Do this to keep Cygwin environments happy, else the unescaped '\' gets eaten up,
2371cb0ef41Sopenharmony_ci    // resulting in bad paths, Ex c:parentFolderfolderanotherFolder instead of c:\parentFolder\folder\anotherFolder
2381cb0ef41Sopenharmony_ci    if (win) {
2391cb0ef41Sopenharmony_ci      nodeLibFile = nodeLibFile.replace(/\\/g, '\\\\')
2401cb0ef41Sopenharmony_ci    }
2411cb0ef41Sopenharmony_ci    argv.push('-Dnode_lib_file=' + nodeLibFile)
2421cb0ef41Sopenharmony_ci    argv.push('-Dmodule_root_dir=' + process.cwd())
2431cb0ef41Sopenharmony_ci    argv.push('-Dnode_engine=' +
2441cb0ef41Sopenharmony_ci        (gyp.opts.node_engine || process.jsEngine || 'v8'))
2451cb0ef41Sopenharmony_ci    argv.push('--depth=.')
2461cb0ef41Sopenharmony_ci    argv.push('--no-parallel')
2471cb0ef41Sopenharmony_ci
2481cb0ef41Sopenharmony_ci    // tell gyp to write the Makefile/Solution files into output_dir
2491cb0ef41Sopenharmony_ci    argv.push('--generator-output', outputDir)
2501cb0ef41Sopenharmony_ci
2511cb0ef41Sopenharmony_ci    // tell make to write its output into the same dir
2521cb0ef41Sopenharmony_ci    argv.push('-Goutput_dir=.')
2531cb0ef41Sopenharmony_ci
2541cb0ef41Sopenharmony_ci    // enforce use of the "binding.gyp" file
2551cb0ef41Sopenharmony_ci    argv.unshift('binding.gyp')
2561cb0ef41Sopenharmony_ci
2571cb0ef41Sopenharmony_ci    // execute `gyp` from the current target nodedir
2581cb0ef41Sopenharmony_ci    argv.unshift(gypScript)
2591cb0ef41Sopenharmony_ci
2601cb0ef41Sopenharmony_ci    // make sure python uses files that came with this particular node package
2611cb0ef41Sopenharmony_ci    const pypath = [path.join(__dirname, '..', 'gyp', 'pylib')]
2621cb0ef41Sopenharmony_ci    if (process.env.PYTHONPATH) {
2631cb0ef41Sopenharmony_ci      pypath.push(process.env.PYTHONPATH)
2641cb0ef41Sopenharmony_ci    }
2651cb0ef41Sopenharmony_ci    process.env.PYTHONPATH = pypath.join(win ? ';' : ':')
2661cb0ef41Sopenharmony_ci
2671cb0ef41Sopenharmony_ci    await new Promise((resolve, reject) => {
2681cb0ef41Sopenharmony_ci      const cp = gyp.spawn(python, argv)
2691cb0ef41Sopenharmony_ci      cp.on('exit', (code) => {
2701cb0ef41Sopenharmony_ci        if (code !== 0) {
2711cb0ef41Sopenharmony_ci          reject(new Error('`gyp` failed with exit code: ' + code))
2721cb0ef41Sopenharmony_ci        } else {
2731cb0ef41Sopenharmony_ci          // we're done
2741cb0ef41Sopenharmony_ci          resolve()
2751cb0ef41Sopenharmony_ci        }
2761cb0ef41Sopenharmony_ci      })
2771cb0ef41Sopenharmony_ci    })
2781cb0ef41Sopenharmony_ci  }
2791cb0ef41Sopenharmony_ci}
2801cb0ef41Sopenharmony_ci
2811cb0ef41Sopenharmony_cimodule.exports = configure
2821cb0ef41Sopenharmony_cimodule.exports.usage = 'Generates ' + (win ? 'MSVC project files' : 'a Makefile') + ' for the current module'
283