11cb0ef41Sopenharmony_ci'use strict'
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst fs = require('graceful-fs').promises
41cb0ef41Sopenharmony_ciconst path = require('path')
51cb0ef41Sopenharmony_ciconst { glob } = require('glob')
61cb0ef41Sopenharmony_ciconst log = require('./log')
71cb0ef41Sopenharmony_ciconst which = require('which')
81cb0ef41Sopenharmony_ciconst win = process.platform === 'win32'
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ciasync function build (gyp, argv) {
111cb0ef41Sopenharmony_ci  let platformMake = 'make'
121cb0ef41Sopenharmony_ci  if (process.platform === 'aix') {
131cb0ef41Sopenharmony_ci    platformMake = 'gmake'
141cb0ef41Sopenharmony_ci  } else if (process.platform === 'os400') {
151cb0ef41Sopenharmony_ci    platformMake = 'gmake'
161cb0ef41Sopenharmony_ci  } else if (process.platform.indexOf('bsd') !== -1) {
171cb0ef41Sopenharmony_ci    platformMake = 'gmake'
181cb0ef41Sopenharmony_ci  } else if (win && argv.length > 0) {
191cb0ef41Sopenharmony_ci    argv = argv.map(function (target) {
201cb0ef41Sopenharmony_ci      return '/t:' + target
211cb0ef41Sopenharmony_ci    })
221cb0ef41Sopenharmony_ci  }
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ci  const makeCommand = gyp.opts.make || process.env.MAKE || platformMake
251cb0ef41Sopenharmony_ci  let command = win ? 'msbuild' : makeCommand
261cb0ef41Sopenharmony_ci  const jobs = gyp.opts.jobs || process.env.JOBS
271cb0ef41Sopenharmony_ci  let buildType
281cb0ef41Sopenharmony_ci  let config
291cb0ef41Sopenharmony_ci  let arch
301cb0ef41Sopenharmony_ci  let nodeDir
311cb0ef41Sopenharmony_ci  let guessedSolution
321cb0ef41Sopenharmony_ci  let python
331cb0ef41Sopenharmony_ci  let buildBinsDir
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci  await loadConfigGypi()
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci  /**
381cb0ef41Sopenharmony_ci   * Load the "config.gypi" file that was generated during "configure".
391cb0ef41Sopenharmony_ci   */
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ci  async function loadConfigGypi () {
421cb0ef41Sopenharmony_ci    let data
431cb0ef41Sopenharmony_ci    try {
441cb0ef41Sopenharmony_ci      const configPath = path.resolve('build', 'config.gypi')
451cb0ef41Sopenharmony_ci      data = await fs.readFile(configPath, 'utf8')
461cb0ef41Sopenharmony_ci    } catch (err) {
471cb0ef41Sopenharmony_ci      if (err.code === 'ENOENT') {
481cb0ef41Sopenharmony_ci        throw new Error('You must run `node-gyp configure` first!')
491cb0ef41Sopenharmony_ci      } else {
501cb0ef41Sopenharmony_ci        throw err
511cb0ef41Sopenharmony_ci      }
521cb0ef41Sopenharmony_ci    }
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ci    config = JSON.parse(data.replace(/#.+\n/, ''))
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci    // get the 'arch', 'buildType', and 'nodeDir' vars from the config
571cb0ef41Sopenharmony_ci    buildType = config.target_defaults.default_configuration
581cb0ef41Sopenharmony_ci    arch = config.variables.target_arch
591cb0ef41Sopenharmony_ci    nodeDir = config.variables.nodedir
601cb0ef41Sopenharmony_ci    python = config.variables.python
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci    if ('debug' in gyp.opts) {
631cb0ef41Sopenharmony_ci      buildType = gyp.opts.debug ? 'Debug' : 'Release'
641cb0ef41Sopenharmony_ci    }
651cb0ef41Sopenharmony_ci    if (!buildType) {
661cb0ef41Sopenharmony_ci      buildType = 'Release'
671cb0ef41Sopenharmony_ci    }
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_ci    log.verbose('build type', buildType)
701cb0ef41Sopenharmony_ci    log.verbose('architecture', arch)
711cb0ef41Sopenharmony_ci    log.verbose('node dev dir', nodeDir)
721cb0ef41Sopenharmony_ci    log.verbose('python', python)
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ci    if (win) {
751cb0ef41Sopenharmony_ci      await findSolutionFile()
761cb0ef41Sopenharmony_ci    } else {
771cb0ef41Sopenharmony_ci      await doWhich()
781cb0ef41Sopenharmony_ci    }
791cb0ef41Sopenharmony_ci  }
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci  /**
821cb0ef41Sopenharmony_ci   * On Windows, find the first build/*.sln file.
831cb0ef41Sopenharmony_ci   */
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_ci  async function findSolutionFile () {
861cb0ef41Sopenharmony_ci    const files = await glob('build/*.sln')
871cb0ef41Sopenharmony_ci    if (files.length === 0) {
881cb0ef41Sopenharmony_ci      throw new Error('Could not find *.sln file. Did you run "configure"?')
891cb0ef41Sopenharmony_ci    }
901cb0ef41Sopenharmony_ci    guessedSolution = files[0]
911cb0ef41Sopenharmony_ci    log.verbose('found first Solution file', guessedSolution)
921cb0ef41Sopenharmony_ci    await doWhich()
931cb0ef41Sopenharmony_ci  }
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_ci  /**
961cb0ef41Sopenharmony_ci   * Uses node-which to locate the msbuild / make executable.
971cb0ef41Sopenharmony_ci   */
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ci  async function doWhich () {
1001cb0ef41Sopenharmony_ci    // On Windows use msbuild provided by node-gyp configure
1011cb0ef41Sopenharmony_ci    if (win) {
1021cb0ef41Sopenharmony_ci      if (!config.variables.msbuild_path) {
1031cb0ef41Sopenharmony_ci        throw new Error('MSBuild is not set, please run `node-gyp configure`.')
1041cb0ef41Sopenharmony_ci      }
1051cb0ef41Sopenharmony_ci      command = config.variables.msbuild_path
1061cb0ef41Sopenharmony_ci      log.verbose('using MSBuild:', command)
1071cb0ef41Sopenharmony_ci      await doBuild()
1081cb0ef41Sopenharmony_ci      return
1091cb0ef41Sopenharmony_ci    }
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ci    // First make sure we have the build command in the PATH
1121cb0ef41Sopenharmony_ci    const execPath = await which(command)
1131cb0ef41Sopenharmony_ci    log.verbose('`which` succeeded for `' + command + '`', execPath)
1141cb0ef41Sopenharmony_ci    await doBuild()
1151cb0ef41Sopenharmony_ci  }
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci  /**
1181cb0ef41Sopenharmony_ci   * Actually spawn the process and compile the module.
1191cb0ef41Sopenharmony_ci   */
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_ci  async function doBuild () {
1221cb0ef41Sopenharmony_ci    // Enable Verbose build
1231cb0ef41Sopenharmony_ci    const verbose = log.logger.isVisible('verbose')
1241cb0ef41Sopenharmony_ci    let j
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci    if (!win && verbose) {
1271cb0ef41Sopenharmony_ci      argv.push('V=1')
1281cb0ef41Sopenharmony_ci    }
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_ci    if (win && !verbose) {
1311cb0ef41Sopenharmony_ci      argv.push('/clp:Verbosity=minimal')
1321cb0ef41Sopenharmony_ci    }
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci    if (win) {
1351cb0ef41Sopenharmony_ci      // Turn off the Microsoft logo on Windows
1361cb0ef41Sopenharmony_ci      argv.push('/nologo')
1371cb0ef41Sopenharmony_ci    }
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_ci    // Specify the build type, Release by default
1401cb0ef41Sopenharmony_ci    if (win) {
1411cb0ef41Sopenharmony_ci      // Convert .gypi config target_arch to MSBuild /Platform
1421cb0ef41Sopenharmony_ci      // Since there are many ways to state '32-bit Intel', default to it.
1431cb0ef41Sopenharmony_ci      // N.B. msbuild's Condition string equality tests are case-insensitive.
1441cb0ef41Sopenharmony_ci      const archLower = arch.toLowerCase()
1451cb0ef41Sopenharmony_ci      const p = archLower === 'x64'
1461cb0ef41Sopenharmony_ci        ? 'x64'
1471cb0ef41Sopenharmony_ci        : (archLower === 'arm'
1481cb0ef41Sopenharmony_ci            ? 'ARM'
1491cb0ef41Sopenharmony_ci            : (archLower === 'arm64' ? 'ARM64' : 'Win32'))
1501cb0ef41Sopenharmony_ci      argv.push('/p:Configuration=' + buildType + ';Platform=' + p)
1511cb0ef41Sopenharmony_ci      if (jobs) {
1521cb0ef41Sopenharmony_ci        j = parseInt(jobs, 10)
1531cb0ef41Sopenharmony_ci        if (!isNaN(j) && j > 0) {
1541cb0ef41Sopenharmony_ci          argv.push('/m:' + j)
1551cb0ef41Sopenharmony_ci        } else if (jobs.toUpperCase() === 'MAX') {
1561cb0ef41Sopenharmony_ci          argv.push('/m:' + require('os').cpus().length)
1571cb0ef41Sopenharmony_ci        }
1581cb0ef41Sopenharmony_ci      }
1591cb0ef41Sopenharmony_ci    } else {
1601cb0ef41Sopenharmony_ci      argv.push('BUILDTYPE=' + buildType)
1611cb0ef41Sopenharmony_ci      // Invoke the Makefile in the 'build' dir.
1621cb0ef41Sopenharmony_ci      argv.push('-C')
1631cb0ef41Sopenharmony_ci      argv.push('build')
1641cb0ef41Sopenharmony_ci      if (jobs) {
1651cb0ef41Sopenharmony_ci        j = parseInt(jobs, 10)
1661cb0ef41Sopenharmony_ci        if (!isNaN(j) && j > 0) {
1671cb0ef41Sopenharmony_ci          argv.push('--jobs')
1681cb0ef41Sopenharmony_ci          argv.push(j)
1691cb0ef41Sopenharmony_ci        } else if (jobs.toUpperCase() === 'MAX') {
1701cb0ef41Sopenharmony_ci          argv.push('--jobs')
1711cb0ef41Sopenharmony_ci          argv.push(require('os').cpus().length)
1721cb0ef41Sopenharmony_ci        }
1731cb0ef41Sopenharmony_ci      }
1741cb0ef41Sopenharmony_ci    }
1751cb0ef41Sopenharmony_ci
1761cb0ef41Sopenharmony_ci    if (win) {
1771cb0ef41Sopenharmony_ci      // did the user specify their own .sln file?
1781cb0ef41Sopenharmony_ci      const hasSln = argv.some(function (arg) {
1791cb0ef41Sopenharmony_ci        return path.extname(arg) === '.sln'
1801cb0ef41Sopenharmony_ci      })
1811cb0ef41Sopenharmony_ci      if (!hasSln) {
1821cb0ef41Sopenharmony_ci        argv.unshift(gyp.opts.solution || guessedSolution)
1831cb0ef41Sopenharmony_ci      }
1841cb0ef41Sopenharmony_ci    }
1851cb0ef41Sopenharmony_ci
1861cb0ef41Sopenharmony_ci    if (!win) {
1871cb0ef41Sopenharmony_ci      // Add build-time dependency symlinks (such as Python) to PATH
1881cb0ef41Sopenharmony_ci      buildBinsDir = path.resolve('build', 'node_gyp_bins')
1891cb0ef41Sopenharmony_ci      process.env.PATH = `${buildBinsDir}:${process.env.PATH}`
1901cb0ef41Sopenharmony_ci      await fs.mkdir(buildBinsDir, { recursive: true })
1911cb0ef41Sopenharmony_ci      const symlinkDestination = path.join(buildBinsDir, 'python3')
1921cb0ef41Sopenharmony_ci      try {
1931cb0ef41Sopenharmony_ci        await fs.unlink(symlinkDestination)
1941cb0ef41Sopenharmony_ci      } catch (err) {
1951cb0ef41Sopenharmony_ci        if (err.code !== 'ENOENT') throw err
1961cb0ef41Sopenharmony_ci      }
1971cb0ef41Sopenharmony_ci      await fs.symlink(python, symlinkDestination)
1981cb0ef41Sopenharmony_ci      log.verbose('bin symlinks', `created symlink to "${python}" in "${buildBinsDir}" and added to PATH`)
1991cb0ef41Sopenharmony_ci    }
2001cb0ef41Sopenharmony_ci
2011cb0ef41Sopenharmony_ci    const proc = gyp.spawn(command, argv)
2021cb0ef41Sopenharmony_ci    await new Promise((resolve, reject) => proc.on('exit', async (code, signal) => {
2031cb0ef41Sopenharmony_ci      if (buildBinsDir) {
2041cb0ef41Sopenharmony_ci        // Clean up the build-time dependency symlinks:
2051cb0ef41Sopenharmony_ci        await fs.rm(buildBinsDir, { recursive: true })
2061cb0ef41Sopenharmony_ci      }
2071cb0ef41Sopenharmony_ci
2081cb0ef41Sopenharmony_ci      if (code !== 0) {
2091cb0ef41Sopenharmony_ci        return reject(new Error('`' + command + '` failed with exit code: ' + code))
2101cb0ef41Sopenharmony_ci      }
2111cb0ef41Sopenharmony_ci      if (signal) {
2121cb0ef41Sopenharmony_ci        return reject(new Error('`' + command + '` got signal: ' + signal))
2131cb0ef41Sopenharmony_ci      }
2141cb0ef41Sopenharmony_ci      resolve()
2151cb0ef41Sopenharmony_ci    }))
2161cb0ef41Sopenharmony_ci  }
2171cb0ef41Sopenharmony_ci}
2181cb0ef41Sopenharmony_ci
2191cb0ef41Sopenharmony_cimodule.exports = build
2201cb0ef41Sopenharmony_cimodule.exports.usage = 'Invokes `' + (win ? 'msbuild' : 'make') + '` and builds the module'
221