Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
build.js231 linesDownload Raw Back to lib
1'use strict'
2
3const gracefulFs = require('graceful-fs')
4const fs = gracefulFs.promises
5const path = require('path')
6const { glob } = require('tinyglobby')
7const log = require('./log')
8const which = require('which')
9const win = process.platform === 'win32'
10
11async function build (gyp, argv) {
12  let platformMake = 'make'
13  if (process.platform === 'aix') {
14    platformMake = 'gmake'
15  } else if (process.platform === 'os400') {
16    platformMake = 'gmake'
17  } else if (process.platform.indexOf('bsd') !== -1) {
18    platformMake = 'gmake'
19  } else if (win && argv.length > 0) {
20    argv = argv.map(function (target) {
21      return '/t:' + target
22    })
23  }
24
25  const makeCommand = gyp.opts.make || process.env.MAKE || platformMake
26  let command = win ? 'msbuild' : makeCommand
27  const jobs = gyp.opts.jobs || process.env.JOBS
28  let buildType
29  let config
30  let arch
31  let nodeDir
32  let guessedSolution
33  let python
34  let buildBinsDir
35
36  await loadConfigGypi()
37
38  /**
39   * Load the "config.gypi" file that was generated during "configure".
40   */
41
42  async function loadConfigGypi () {
43    let data
44    try {
45      const configPath = path.resolve('build', 'config.gypi')
46      data = await fs.readFile(configPath, 'utf8')
47    } catch (err) {
48      if (err.code === 'ENOENT') {
49        throw new Error('You must run `node-gyp configure` first!')
50      } else {
51        throw err
52      }
53    }
54
55    config = JSON.parse(data.replace(/#.+\n/, ''))
56
57    // get the 'arch', 'buildType', and 'nodeDir' vars from the config
58    buildType = config.target_defaults.default_configuration
59    arch = config.variables.target_arch
60    nodeDir = config.variables.nodedir
61    python = config.variables.python
62
63    if ('debug' in gyp.opts) {
64      buildType = gyp.opts.debug ? 'Debug' : 'Release'
65    }
66    if (!buildType) {
67      buildType = 'Release'
68    }
69
70    log.verbose('build type', buildType)
71    log.verbose('architecture', arch)
72    log.verbose('node dev dir', nodeDir)
73    log.verbose('python', python)
74
75    if (win) {
76      await findSolutionFile()
77    } else {
78      await doWhich()
79    }
80  }
81
82  /**
83   * On Windows, find the first build/*.sln file.
84   */
85
86  async function findSolutionFile () {
87    const files = await glob('build/*.sln', { expandDirectories: false })
88    if (files.length === 0) {
89      if (gracefulFs.existsSync('build/Makefile') ||
90          (await glob('build/*.mk', { expandDirectories: false })).length !== 0) {
91        command = makeCommand
92        await doWhich(false)
93        return
94      } else {
95        throw new Error('Could not find *.sln file or Makefile. Did you run "configure"?')
96      }
97    }
98    guessedSolution = files[0]
99    log.verbose('found first Solution file', guessedSolution)
100    await doWhich(true)
101  }
102
103  /**
104   * Uses node-which to locate the msbuild / make executable.
105   */
106
107  async function doWhich (msvs) {
108    // On Windows use msbuild provided by node-gyp configure
109    if (msvs) {
110      if (!config.variables.msbuild_path) {
111        throw new Error('MSBuild is not set, please run `node-gyp configure`.')
112      }
113      command = config.variables.msbuild_path
114      log.verbose('using MSBuild:', command)
115      await doBuild(msvs)
116      return
117    }
118
119    // First make sure we have the build command in the PATH
120    const execPath = await which(command)
121    log.verbose('`which` succeeded for `' + command + '`', execPath)
122    await doBuild(msvs)
123  }
124
125  /**
126   * Actually spawn the process and compile the module.
127   */
128
129  async function doBuild (msvs) {
130    // Enable Verbose build
131    const verbose = log.logger.isVisible('verbose')
132    let j
133
134    if (!msvs && verbose) {
135      argv.push('V=1')
136    }
137
138    if (msvs && !verbose) {
139      argv.push('/clp:Verbosity=minimal')
140    }
141
142    if (msvs) {
143      // Turn off the Microsoft logo on Windows
144      argv.push('/nologo')
145      // No lingering msbuild processes and open file handles
146      argv.push('/nodeReuse:false')
147    }
148
149    // Specify the build type, Release by default
150    if (msvs) {
151      // Convert .gypi config target_arch to MSBuild /Platform
152      // Since there are many ways to state '32-bit Intel', default to it.
153      // N.B. msbuild's Condition string equality tests are case-insensitive.
154      const archLower = arch.toLowerCase()
155      const p = archLower === 'x64'
156        ? 'x64'
157        : (archLower === 'arm'
158            ? 'ARM'
159            : (archLower === 'arm64' ? 'ARM64' : 'Win32'))
160      argv.push('/p:Configuration=' + buildType + ';Platform=' + p)
161      if (jobs) {
162        j = parseInt(jobs, 10)
163        if (!isNaN(j) && j > 0) {
164          argv.push('/m:' + j)
165        } else if (jobs.toUpperCase() === 'MAX') {
166          argv.push('/m:' + require('os').availableParallelism())
167        }
168      }
169    } else {
170      argv.push('BUILDTYPE=' + buildType)
171      // Invoke the Makefile in the 'build' dir.
172      argv.push('-C')
173      argv.push('build')
174      if (jobs) {
175        j = parseInt(jobs, 10)
176        if (!isNaN(j) && j > 0) {
177          argv.push('--jobs')
178          argv.push(j)
179        } else if (jobs.toUpperCase() === 'MAX') {
180          argv.push('--jobs')
181          argv.push(require('os').availableParallelism())
182        }
183      }
184    }
185
186    if (msvs) {
187      // did the user specify their own .sln file?
188      const hasSln = argv.some(function (arg) {
189        return path.extname(arg) === '.sln'
190      })
191      if (!hasSln) {
192        argv.unshift(gyp.opts.solution || guessedSolution)
193      }
194    }
195
196    if (!win) {
197      // Add build-time dependency symlinks (such as Python) to PATH
198      buildBinsDir = path.resolve('build', 'node_gyp_bins')
199      process.env.PATH = `${buildBinsDir}:${process.env.PATH}`
200      await fs.mkdir(buildBinsDir, { recursive: true })
201      const symlinkDestination = path.join(buildBinsDir, 'python3')
202      try {
203        await fs.unlink(symlinkDestination)
204      } catch (err) {
205        if (err.code !== 'ENOENT') throw err
206      }
207      await fs.symlink(python, symlinkDestination)
208      log.verbose('bin symlinks', `created symlink to "${python}" in "${buildBinsDir}" and added to PATH`)
209    }
210
211    const proc = gyp.spawn(command, argv)
212    await new Promise((resolve, reject) => proc.on('exit', async (code, signal) => {
213      if (buildBinsDir) {
214        // Clean up the build-time dependency symlinks:
215        await fs.rm(buildBinsDir, { recursive: true, maxRetries: 3 })
216      }
217
218      if (code !== 0) {
219        return reject(new Error('`' + command + '` failed with exit code: ' + code))
220      }
221      if (signal) {
222        return reject(new Error('`' + command + '` got signal: ' + signal))
223      }
224      resolve()
225    }))
226  }
227}
228
229module.exports = build
230module.exports.usage = 'Invokes `' + (win ? 'msbuild' : 'make') + '` and builds the module'
231 
codekingpro/portable-devtools · Team Ai