@flun/nodejs-mobile-gyp 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/LICENSE +29 -0
  3. package/README.md +252 -0
  4. package/addon.gypi +209 -0
  5. package/bin/node-gyp.js +144 -0
  6. package/gyp/LICENSE +28 -0
  7. package/gyp/README.md +30 -0
  8. package/gyp/data/win/large-pdb-shim.cc +12 -0
  9. package/gyp/gyp +8 -0
  10. package/gyp/gyp.bat +5 -0
  11. package/gyp/gyp_main.py +45 -0
  12. package/gyp/pylib/gyp/MSVSNew.py +365 -0
  13. package/gyp/pylib/gyp/MSVSProject.py +206 -0
  14. package/gyp/pylib/gyp/MSVSSettings.py +1270 -0
  15. package/gyp/pylib/gyp/MSVSToolFile.py +59 -0
  16. package/gyp/pylib/gyp/MSVSUserFile.py +153 -0
  17. package/gyp/pylib/gyp/MSVSUtil.py +271 -0
  18. package/gyp/pylib/gyp/MSVSVersion.py +574 -0
  19. package/gyp/pylib/gyp/__init__.py +692 -0
  20. package/gyp/pylib/gyp/common.py +654 -0
  21. package/gyp/pylib/gyp/easy_xml.py +169 -0
  22. package/gyp/pylib/gyp/flock_tool.py +55 -0
  23. package/gyp/pylib/gyp/generator/__init__.py +0 -0
  24. package/gyp/pylib/gyp/generator/analyzer.py +804 -0
  25. package/gyp/pylib/gyp/generator/android.py +1173 -0
  26. package/gyp/pylib/gyp/generator/cmake.py +1318 -0
  27. package/gyp/pylib/gyp/generator/compile_commands_json.py +123 -0
  28. package/gyp/pylib/gyp/generator/dump_dependency_json.py +103 -0
  29. package/gyp/pylib/gyp/generator/eclipse.py +461 -0
  30. package/gyp/pylib/gyp/generator/gypd.py +89 -0
  31. package/gyp/pylib/gyp/generator/gypsh.py +58 -0
  32. package/gyp/pylib/gyp/generator/make.py +2710 -0
  33. package/gyp/pylib/gyp/generator/msvs.py +3981 -0
  34. package/gyp/pylib/gyp/generator/ninja.py +2933 -0
  35. package/gyp/pylib/gyp/generator/xcode.py +1397 -0
  36. package/gyp/pylib/gyp/input.py +3115 -0
  37. package/gyp/pylib/gyp/mac_tool.py +771 -0
  38. package/gyp/pylib/gyp/msvs_emulation.py +1262 -0
  39. package/gyp/pylib/gyp/ninja_syntax.py +174 -0
  40. package/gyp/pylib/gyp/simple_copy.py +61 -0
  41. package/gyp/pylib/gyp/win_tool.py +373 -0
  42. package/gyp/pylib/gyp/xcode_emulation.py +1935 -0
  43. package/gyp/pylib/gyp/xcode_ninja.py +302 -0
  44. package/gyp/pylib/gyp/xcodeproj_file.py +3198 -0
  45. package/gyp/pylib/gyp/xml_fix.py +65 -0
  46. package/gyp/pylib/packaging/LICENSE +3 -0
  47. package/gyp/pylib/packaging/LICENSE.APACHE +177 -0
  48. package/gyp/pylib/packaging/LICENSE.BSD +23 -0
  49. package/gyp/pylib/packaging/__init__.py +15 -0
  50. package/gyp/pylib/packaging/_elffile.py +108 -0
  51. package/gyp/pylib/packaging/_manylinux.py +252 -0
  52. package/gyp/pylib/packaging/_musllinux.py +83 -0
  53. package/gyp/pylib/packaging/_parser.py +359 -0
  54. package/gyp/pylib/packaging/_structures.py +61 -0
  55. package/gyp/pylib/packaging/_tokenizer.py +192 -0
  56. package/gyp/pylib/packaging/markers.py +252 -0
  57. package/gyp/pylib/packaging/metadata.py +825 -0
  58. package/gyp/pylib/packaging/py.typed +0 -0
  59. package/gyp/pylib/packaging/requirements.py +90 -0
  60. package/gyp/pylib/packaging/specifiers.py +1030 -0
  61. package/gyp/pylib/packaging/tags.py +553 -0
  62. package/gyp/pylib/packaging/utils.py +172 -0
  63. package/gyp/pylib/packaging/version.py +563 -0
  64. package/lib/Find-VisualStudio.cs +250 -0
  65. package/lib/build.js +221 -0
  66. package/lib/clean.js +19 -0
  67. package/lib/configure.js +295 -0
  68. package/lib/create-config-gypi.js +163 -0
  69. package/lib/download.js +44 -0
  70. package/lib/find-node-directory.js +62 -0
  71. package/lib/find-python.js +303 -0
  72. package/lib/find-visualstudio.js +448 -0
  73. package/lib/install.js +419 -0
  74. package/lib/list.js +30 -0
  75. package/lib/log.js +174 -0
  76. package/lib/node-gyp.js +201 -0
  77. package/lib/process-release.js +144 -0
  78. package/lib/rebuild.js +14 -0
  79. package/lib/remove.js +47 -0
  80. package/lib/util.js +83 -0
  81. package/package.json +72 -0
  82. package/src/win_delay_load_hook.cc +39 -0
@@ -0,0 +1,303 @@
1
+ import * as log from './log.js'
2
+ import semver from 'semver'
3
+ import { execFile } from './util.js'
4
+ import os from 'os'
5
+
6
+ const win = process.platform === 'win32'
7
+
8
+ /**
9
+ * 获取当前操作系统用户名(失败时返回 undefined)
10
+ */
11
+ const getOsUserInfo = () => {
12
+ try {
13
+ return os.userInfo().username
14
+ } catch {}
15
+ }
16
+
17
+ const systemDrive = process.env.SystemDrive || 'C:'
18
+ const username = process.env.USERNAME || process.env.USER || getOsUserInfo()
19
+ const localAppData = process.env.LOCALAPPDATA || `${systemDrive}\\${username}\\AppData\\Local`
20
+ const foundLocalAppData = process.env.LOCALAPPDATA || username
21
+ const programFiles = process.env.ProgramW6432 || process.env.ProgramFiles || `${systemDrive}\\Program Files`
22
+ const programFilesX86 = process.env['ProgramFiles(x86)'] || `${programFiles} (x86)`
23
+
24
+ const winDefaultLocationsArray = []
25
+ for (const majorMinor of ['311', '310', '39', '38']) {
26
+ if (foundLocalAppData) {
27
+ winDefaultLocationsArray.push(
28
+ `${localAppData}\\Programs\\Python\\Python${majorMinor}\\python.exe`,
29
+ `${programFiles}\\Python${majorMinor}\\python.exe`,
30
+ `${localAppData}\\Programs\\Python\\Python${majorMinor}-32\\python.exe`,
31
+ `${programFiles}\\Python${majorMinor}-32\\python.exe`,
32
+ `${programFilesX86}\\Python${majorMinor}-32\\python.exe`
33
+ )
34
+ } else {
35
+ winDefaultLocationsArray.push(
36
+ `${programFiles}\\Python${majorMinor}\\python.exe`,
37
+ `${programFiles}\\Python${majorMinor}-32\\python.exe`,
38
+ `${programFilesX86}\\Python${majorMinor}-32\\python.exe`
39
+ )
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Python 查找器:按顺序尝试多种途径定位可用的 Python 3.6+
45
+ */
46
+ class PythonFinder {
47
+ static findPython = (...args) => new PythonFinder(...args).findPython()
48
+
49
+ log = log.withPrefix('find Python')
50
+ argsExecutable = ['-c', 'import sys; print(sys.executable);']
51
+ argsVersion = ['-c', 'import sys; print("%s.%s.%s" % sys.version_info[:3]);']
52
+ semverRange = '>=3.6.0'
53
+
54
+ // 以下可在测试时覆盖:
55
+ execFile = execFile
56
+ env = process.env
57
+ win = win
58
+ pyLauncher = 'py.exe'
59
+ winDefaultLocations = winDefaultLocationsArray
60
+
61
+ constructor (configPython) {
62
+ this.configPython = configPython
63
+ this.errorLog = []
64
+ }
65
+
66
+ // 以 verbose 级别记录日志,同时保存下来,出错时以 error 级别展示,便于诊断
67
+ addLog (message) {
68
+ this.log.verbose(message)
69
+ this.errorLog.push(message)
70
+ }
71
+
72
+ // 依次尝试多种 Python 定位方式。忽略错误,直到找到可用版本
73
+ async findPython () {
74
+ const SKIP = 0
75
+ const FAIL = 1
76
+ const toCheck = (() => {
77
+ if (this.env.NODE_GYP_FORCE_PYTHON) {
78
+ return [{
79
+ before: () => {
80
+ this.addLog(
81
+ 'checking Python explicitly set from NODE_GYP_FORCE_PYTHON')
82
+ this.addLog('- process.env.NODE_GYP_FORCE_PYTHON is ' +
83
+ `"${this.env.NODE_GYP_FORCE_PYTHON}"`)
84
+ },
85
+ check: () => this.checkCommand(this.env.NODE_GYP_FORCE_PYTHON)
86
+ }]
87
+ }
88
+
89
+ const checks = [
90
+ {
91
+ before: () => {
92
+ if (!this.configPython) {
93
+ this.addLog(
94
+ 'Python is not set from command line or npm configuration')
95
+ return SKIP
96
+ }
97
+ this.addLog('checking Python explicitly set from command line or ' +
98
+ 'npm configuration')
99
+ this.addLog('- "--python=" or "npm config get python" is ' +
100
+ `"${this.configPython}"`)
101
+ },
102
+ check: () => this.checkCommand(this.configPython)
103
+ },
104
+ {
105
+ before: () => {
106
+ if (!this.env.PYTHON) {
107
+ this.addLog('Python is not set from environment variable ' +
108
+ 'PYTHON')
109
+ return SKIP
110
+ }
111
+ this.addLog('checking Python explicitly set from environment ' +
112
+ 'variable PYTHON')
113
+ this.addLog(`- process.env.PYTHON is "${this.env.PYTHON}"`)
114
+ },
115
+ check: () => this.checkCommand(this.env.PYTHON)
116
+ }
117
+ ]
118
+
119
+ if (this.win) {
120
+ checks.push({
121
+ before: () => {
122
+ this.addLog(
123
+ 'checking if the py launcher can be used to find Python 3')
124
+ },
125
+ check: () => this.checkPyLauncher()
126
+ })
127
+ }
128
+
129
+ checks.push(...[
130
+ {
131
+ before: () => { this.addLog('checking if "python3" can be used') },
132
+ check: () => this.checkCommand('python3')
133
+ },
134
+ {
135
+ before: () => { this.addLog('checking if "python" can be used') },
136
+ check: () => this.checkCommand('python')
137
+ }
138
+ ])
139
+
140
+ if (this.win) {
141
+ for (let i = 0; i < this.winDefaultLocations.length; ++i) {
142
+ const location = this.winDefaultLocations[i]
143
+ checks.push({
144
+ before: () => this.addLog(`checking if Python is ${location}`),
145
+ check: () => this.checkExecPath(location)
146
+ })
147
+ }
148
+ }
149
+
150
+ return checks
151
+ })()
152
+
153
+ for (const check of toCheck) {
154
+ const before = check.before()
155
+ if (before === SKIP) {
156
+ continue
157
+ }
158
+ if (before === FAIL) {
159
+ return this.fail()
160
+ }
161
+ try {
162
+ return await check.check()
163
+ } catch (err) {
164
+ this.log.silly('runChecks: err = %j', (err && err.stack) || err)
165
+ }
166
+ }
167
+
168
+ return this.fail()
169
+ }
170
+
171
+ // 检查命令是否为可用的 Python。成功则返回结果。
172
+ // Windows 下需在 CMD shell 中运行以支持 BAT/CMD 启动器。
173
+ async checkCommand (command) {
174
+ let exec = command
175
+ let args = this.argsExecutable
176
+ let shell = false
177
+ if (this.win) {
178
+ // 参数需手动加引号
179
+ exec = `"${exec}"`
180
+ args = args.map(a => `"${a}"`)
181
+ shell = true
182
+ }
183
+
184
+ this.log.verbose(`- executing "${command}" to get executable path`)
185
+ // 可能结果:
186
+ // - 报错:不在 PATH、不可执行或执行失败
187
+ // - 乱码:后续版本检查会失败
188
+ // - 可执行文件的绝对路径
189
+ try {
190
+ const execPath = await this.run(exec, args, shell)
191
+ this.addLog(`- executable path is "${execPath}"`)
192
+ return this.checkExecPath(execPath)
193
+ } catch (err) {
194
+ this.addLog(`- "${command}" is not in PATH or produced an error`)
195
+ throw err
196
+ }
197
+ }
198
+
199
+ // 检查 py 启动器是否能找到可用的 Python。成功则返回结果。
200
+ // Windows 上的 Python 发行版默认安装 "py.exe" 启动器,比 python.exe 出现在 PATH 更常见。
201
+ // 因为 py 启动器同时支持 Python 2 和 3,这里显式请求 Python 3:用 "-3" 作为首个参数。
202
+ // 由于 "py.exe -3" 对 execFile 来说不是合法可执行文件,需要用启动器找出真正的 python.exe 路径。
203
+ async checkPyLauncher () {
204
+ this.log.verbose(`- executing "${this.pyLauncher}" to get Python 3 executable path`)
205
+ // 可能结果:与 checkCommand 相同
206
+ try {
207
+ const execPath = await this.run(this.pyLauncher, ['-3', ...this.argsExecutable], false)
208
+ this.addLog(`- executable path is "${execPath}"`)
209
+ return this.checkExecPath(execPath)
210
+ } catch (err) {
211
+ this.addLog(`- "${this.pyLauncher}" is not in PATH or produced an error`)
212
+ throw err
213
+ }
214
+ }
215
+
216
+ // 检查某个 Python 可执行文件版本是否可用。成功则返回结果。
217
+ async checkExecPath (execPath) {
218
+ this.log.verbose(`- executing "${execPath}" to get version`)
219
+ // 可能结果:
220
+ // - 报错:可执行文件无法运行(多半上一步输出了乱码)
221
+ // - 乱码:上一步不知为何输出了可执行文件路径,验证版本时会失败
222
+ // - Python 可执行文件的版本号
223
+ try {
224
+ const version = await this.run(execPath, this.argsVersion, false)
225
+ this.addLog(`- version is "${version}"`)
226
+
227
+ const range = new semver.Range(this.semverRange)
228
+ let valid = false
229
+ try {
230
+ valid = range.test(version)
231
+ } catch (err) {
232
+ this.log.silly('range.test() threw:\n%s', err.stack)
233
+ this.addLog(`- "${execPath}" does not have a valid version`)
234
+ this.addLog('- is it a Python executable?')
235
+ throw err
236
+ }
237
+ if (!valid) {
238
+ this.addLog(`- version is ${version} - should be ${this.semverRange}`)
239
+ this.addLog('- THIS VERSION OF PYTHON IS NOT SUPPORTED')
240
+ throw new Error(`Found unsupported Python version ${version}`)
241
+ }
242
+ return this.succeed(execPath, version)
243
+ } catch (err) {
244
+ this.addLog(`- "${execPath}" could not be run`)
245
+ throw err
246
+ }
247
+ }
248
+
249
+ // 运行可执行文件或 shell 命令,并去除输出两端空白
250
+ async run (exec, args, shell) {
251
+ const env = Object.assign({}, this.env)
252
+ env.TERM = 'dumb'
253
+ const opts = { env, shell }
254
+
255
+ this.log.silly('execFile: exec = %j', exec)
256
+ this.log.silly('execFile: args = %j', args)
257
+ this.log.silly('execFile: opts = %j', opts)
258
+ try {
259
+ const [err, stdout, stderr] = await this.execFile(exec, args, opts)
260
+ this.log.silly('execFile result: err = %j', (err && err.stack) || err)
261
+ this.log.silly('execFile result: stdout = %j', stdout)
262
+ this.log.silly('execFile result: stderr = %j', stderr)
263
+ return stdout.trim()
264
+ } catch (err) {
265
+ this.log.silly('execFile: threw:\n%s', err.stack)
266
+ throw err
267
+ }
268
+ }
269
+
270
+ succeed (execPath, version) {
271
+ this.log.info(`using Python version ${version} found at "${execPath}"`)
272
+ return execPath
273
+ }
274
+
275
+ fail () {
276
+ const errorLog = this.errorLog.join('\n')
277
+
278
+ const pathExample = this.win
279
+ ? 'C:\\Path\\To\\python.exe'
280
+ : '/path/to/pythonexecutable'
281
+ // Windows 80 列控制台,用到 X 标记列之前(含日志前缀共 79 字符,可用 58 字符):
282
+ // X
283
+ const info = [
284
+ '**********************************************************',
285
+ 'You need to install the latest version of Python.',
286
+ 'Node-gyp should be able to find and use Python. If not,',
287
+ 'you can try one of the following options:',
288
+ `- Use the switch --python="${pathExample}"`,
289
+ ' (accepted by both node-gyp and npm)',
290
+ '- Set the environment variable PYTHON',
291
+ '- Set the npm configuration variable python:',
292
+ ` npm config set python "${pathExample}"`,
293
+ 'For more information consult the documentation at:',
294
+ 'https://github.com/nodejs/node-gyp#installation',
295
+ '**********************************************************'
296
+ ].join('\n')
297
+
298
+ this.log.error(`\n${errorLog}\n\n${info}\n`)
299
+ throw new Error('Could not find any Python installation to use')
300
+ }
301
+ }
302
+
303
+ export { PythonFinder }