@flun/nodejs-mobile-gyp 1.1.4 → 1.2.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.
- package/CHANGELOG.md +44 -8
- package/LICENSE +33 -33
- package/README.md +243 -248
- package/bin/node-gyp.js +27 -21
- package/lib/Find-VisualStudio.cs +2 -1
- package/lib/build.js +26 -36
- package/lib/clean.js +3 -3
- package/lib/configure.js +26 -26
- package/lib/create-config-gypi.js +4 -4
- package/lib/download.js +1 -1
- package/lib/find-node-directory.js +5 -5
- package/lib/find-python.js +44 -44
- package/lib/find-visualstudio.js +53 -53
- package/lib/install.js +42 -42
- package/lib/list.js +3 -3
- package/lib/node-gyp.js +31 -5
- package/lib/process-release.js +1 -1
- package/lib/rebuild.js +2 -2
- package/lib/remove.js +6 -6
- package/lib/util.js +72 -72
- package/package.json +9 -9
package/lib/find-python.js
CHANGED
|
@@ -51,7 +51,7 @@ const win = process.platform === 'win32',
|
|
|
51
51
|
class PythonFinder {
|
|
52
52
|
static findPython = (...args) => new PythonFinder(...args).findPython();
|
|
53
53
|
|
|
54
|
-
log = log.withPrefix('
|
|
54
|
+
log = log.withPrefix('查找 Python');
|
|
55
55
|
argsExecutable = ['-c', 'import sys; print(sys.executable);'];
|
|
56
56
|
argsVersion = ['-c', 'import sys; print("%s.%s.%s" % sys.version_info[:3]);'];
|
|
57
57
|
semverRange = '>=3.6.0';
|
|
@@ -78,8 +78,8 @@ class PythonFinder {
|
|
|
78
78
|
if (this.env.NODE_GYP_FORCE_PYTHON) {
|
|
79
79
|
return [{
|
|
80
80
|
before: () => {
|
|
81
|
-
this.addLog('
|
|
82
|
-
this.addLog('- process.env.NODE_GYP_FORCE_PYTHON
|
|
81
|
+
this.addLog('检查是否通过 NODE_GYP_FORCE_PYTHON 显式指定 Python');
|
|
82
|
+
this.addLog('- process.env.NODE_GYP_FORCE_PYTHON 为 ' + `"${this.env.NODE_GYP_FORCE_PYTHON}"`);
|
|
83
83
|
}, check: () => this.checkCommand(this.env.NODE_GYP_FORCE_PYTHON)
|
|
84
84
|
}];
|
|
85
85
|
}
|
|
@@ -87,21 +87,21 @@ class PythonFinder {
|
|
|
87
87
|
{
|
|
88
88
|
before: () => {
|
|
89
89
|
if (!this.configPython) {
|
|
90
|
-
this.addLog('
|
|
90
|
+
this.addLog('未从命令行或 npm 配置指定 Python');
|
|
91
91
|
return SKIP;
|
|
92
92
|
}
|
|
93
|
-
this.addLog('
|
|
94
|
-
this.addLog('- "--python="
|
|
93
|
+
this.addLog('检查是否从命令行或 npm 配置显式指定 Python');
|
|
94
|
+
this.addLog('- "--python=" 或 "npm config get python" 的值为 ' + `"${this.configPython}"`);
|
|
95
95
|
}, check: () => this.checkCommand(this.configPython)
|
|
96
96
|
},
|
|
97
97
|
{
|
|
98
98
|
before: () => {
|
|
99
99
|
if (!this.env.PYTHON) {
|
|
100
|
-
this.addLog('
|
|
100
|
+
this.addLog('未从环境变量 PYTHON 指定 Python');
|
|
101
101
|
return SKIP;
|
|
102
102
|
}
|
|
103
|
-
this.addLog('
|
|
104
|
-
this.addLog(`- process.env.PYTHON
|
|
103
|
+
this.addLog('检查是否从环境变量 PYTHON 显式指定 Python');
|
|
104
|
+
this.addLog(`- process.env.PYTHON 为 "${this.env.PYTHON}"`);
|
|
105
105
|
},
|
|
106
106
|
check: () => this.checkCommand(this.env.PYTHON)
|
|
107
107
|
}
|
|
@@ -110,23 +110,23 @@ class PythonFinder {
|
|
|
110
110
|
if (this.win) {
|
|
111
111
|
for (const launcher of pyLauncherCandidates) {
|
|
112
112
|
checks.push({
|
|
113
|
-
before: () => this.addLog(
|
|
113
|
+
before: () => this.addLog(`检查能否用 "${launcher}" 查找 Python 3`),
|
|
114
114
|
check: () => this.checkPyLauncher(launcher)
|
|
115
115
|
});
|
|
116
116
|
}
|
|
117
117
|
checks.push({
|
|
118
|
-
before: () => this.addLog('
|
|
118
|
+
before: () => this.addLog('通过 "py -0p" 枚举已安装的 Python'),
|
|
119
119
|
check: () => this.checkPyList()
|
|
120
120
|
});
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
checks.push(...[
|
|
124
124
|
{
|
|
125
|
-
before: () => { this.addLog('
|
|
125
|
+
before: () => { this.addLog('检查能否使用 "python3"'); },
|
|
126
126
|
check: () => this.checkCommand('python3')
|
|
127
127
|
},
|
|
128
128
|
{
|
|
129
|
-
before: () => { this.addLog('
|
|
129
|
+
before: () => { this.addLog('检查能否使用 "python"'); },
|
|
130
130
|
check: () => this.checkCommand('python')
|
|
131
131
|
}
|
|
132
132
|
]);
|
|
@@ -135,7 +135,7 @@ class PythonFinder {
|
|
|
135
135
|
for (let i = 0; i < this.winDefaultLocations.length; ++i) {
|
|
136
136
|
const location = this.winDefaultLocations[i];
|
|
137
137
|
checks.push({
|
|
138
|
-
before: () => this.addLog(
|
|
138
|
+
before: () => this.addLog(`检查 Python 是否位于 ${location}`),
|
|
139
139
|
check: () => this.checkExecPath(location)
|
|
140
140
|
});
|
|
141
141
|
}
|
|
@@ -160,33 +160,33 @@ class PythonFinder {
|
|
|
160
160
|
|
|
161
161
|
// 检查命令是否为可用的 Python;
|
|
162
162
|
async checkCommand(command) {
|
|
163
|
-
this.log.verbose(`-
|
|
163
|
+
this.log.verbose(`- 执行 "${command}" 以获取可执行文件路径`);
|
|
164
164
|
try {
|
|
165
165
|
const execPath = await this.run(command, this.argsExecutable, false);
|
|
166
|
-
this.addLog(`-
|
|
166
|
+
this.addLog(`- 可执行文件路径为 "${execPath}"`);
|
|
167
167
|
return this.checkExecPath(execPath);
|
|
168
168
|
} catch (err) {
|
|
169
|
-
this.addLog(`- "${command}"
|
|
169
|
+
this.addLog(`- "${command}" 不在 PATH 中或执行出错`);
|
|
170
170
|
throw err;
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
// 检查指定 py 启动器是否能找到 Python 3;
|
|
175
175
|
async checkPyLauncher(launcher = this.pyLauncher) {
|
|
176
|
-
this.log.verbose(`-
|
|
176
|
+
this.log.verbose(`- 执行 "${launcher}" 以获取 Python 3 可执行文件路径`);
|
|
177
177
|
try {
|
|
178
178
|
const execPath = await this.run(launcher, ['-3', ...this.argsExecutable], false);
|
|
179
|
-
this.addLog(`-
|
|
179
|
+
this.addLog(`- 可执行文件路径为 "${execPath}"`);
|
|
180
180
|
return this.checkExecPath(execPath);
|
|
181
181
|
} catch (err) {
|
|
182
|
-
this.addLog(`- "${launcher}"
|
|
182
|
+
this.addLog(`- "${launcher}" 不在 PATH 中或执行出错`);
|
|
183
183
|
throw err;
|
|
184
184
|
}
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
// 通过 "py -0p" 枚举所有已注册的 Python,覆盖非标准安装位置;
|
|
188
188
|
async checkPyList() {
|
|
189
|
-
this.log.verbose('-
|
|
189
|
+
this.log.verbose('- 执行 "py -0p" 以列出已注册的 Python');
|
|
190
190
|
let lastErr;
|
|
191
191
|
for (const launcher of pyLauncherCandidates) {
|
|
192
192
|
try {
|
|
@@ -196,29 +196,29 @@ class PythonFinder {
|
|
|
196
196
|
const m = line.match(/([A-Za-z]:\\[^\s]+)/);
|
|
197
197
|
if (m && /python\.exe$/i.test(m[1])) paths.push(m[1]);
|
|
198
198
|
}
|
|
199
|
-
this.addLog(`- "py -0p" (via ${launcher})
|
|
199
|
+
this.addLog(`- "py -0p" (via ${launcher}) 找到 ${paths.length} 个路径`);
|
|
200
200
|
for (const p of paths) {
|
|
201
201
|
try {
|
|
202
202
|
return await this.checkExecPath(p);
|
|
203
203
|
} catch (err) {
|
|
204
204
|
lastErr = err;
|
|
205
|
-
this.log.silly('checkPyList:
|
|
205
|
+
this.log.silly('checkPyList: 跳过 %s: %s', p, err.message);
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
} catch (err) {
|
|
209
209
|
lastErr = err;
|
|
210
|
-
this.addLog(`-
|
|
210
|
+
this.addLog(`- 经 "${launcher}" 执行 "py -0p" 失败`);
|
|
211
211
|
}
|
|
212
212
|
}
|
|
213
|
-
throw lastErr || new Error('py -0p
|
|
213
|
+
throw lastErr || new Error('py -0p 未返回可用的 Python');
|
|
214
214
|
}
|
|
215
215
|
|
|
216
216
|
// 检查某个 Python 可执行文件版本是否可用;
|
|
217
217
|
async checkExecPath(execPath) {
|
|
218
|
-
this.log.verbose(`-
|
|
218
|
+
this.log.verbose(`- 执行 "${execPath}" 以获取版本`);
|
|
219
219
|
try {
|
|
220
220
|
const version = await this.run(execPath, this.argsVersion, false);
|
|
221
|
-
this.addLog(`-
|
|
221
|
+
this.addLog(`- 版本为 "${version}"`);
|
|
222
222
|
|
|
223
223
|
const range = new semver.Range(this.semverRange);
|
|
224
224
|
let valid = false;
|
|
@@ -226,18 +226,18 @@ class PythonFinder {
|
|
|
226
226
|
valid = range.test(version);
|
|
227
227
|
} catch (err) {
|
|
228
228
|
this.log.silly('range.test() threw:\n%s', err.stack);
|
|
229
|
-
this.addLog(`- "${execPath}"
|
|
230
|
-
this.addLog('-
|
|
229
|
+
this.addLog(`- "${execPath}" 的版本无效`);
|
|
230
|
+
this.addLog('- 它是不是 Python 可执行文件?');
|
|
231
231
|
throw err;
|
|
232
232
|
}
|
|
233
233
|
if (!valid) {
|
|
234
|
-
this.addLog(`-
|
|
235
|
-
this.addLog('-
|
|
236
|
-
throw new Error(
|
|
234
|
+
this.addLog(`- 版本为 ${version},应为 ${this.semverRange}`);
|
|
235
|
+
this.addLog('- 此版本的 Python 不受支持');
|
|
236
|
+
throw new Error(`不支持的 Python 版本 ${version}`);
|
|
237
237
|
}
|
|
238
238
|
return this.succeed(execPath, version);
|
|
239
239
|
} catch (err) {
|
|
240
|
-
this.addLog(`- "${execPath}"
|
|
240
|
+
this.addLog(`- "${execPath}" 无法运行`);
|
|
241
241
|
throw err;
|
|
242
242
|
}
|
|
243
243
|
}
|
|
@@ -251,9 +251,9 @@ class PythonFinder {
|
|
|
251
251
|
this.log.silly('execFile: args = %j', args);
|
|
252
252
|
this.log.silly('execFile: opts = %j', opts);
|
|
253
253
|
const [err, stdout, stderr] = await this.execFile(exec, args, opts);
|
|
254
|
-
this.log.silly('execFile
|
|
255
|
-
this.log.silly('execFile
|
|
256
|
-
this.log.silly('execFile
|
|
254
|
+
this.log.silly('execFile 结果: 错误 = %j', (err && err.stack) || err);
|
|
255
|
+
this.log.silly('execFile 结果: 标准输出 = %j', stdout);
|
|
256
|
+
this.log.silly('execFile 结果: 标准错误 = %j', stderr);
|
|
257
257
|
if (err) throw err;
|
|
258
258
|
return stdout.trim();
|
|
259
259
|
}
|
|
@@ -268,15 +268,15 @@ class PythonFinder {
|
|
|
268
268
|
pathExample = this.win ? 'C:\\Path\\To\\python.exe' : '/path/to/pythonexecutable',
|
|
269
269
|
info = [
|
|
270
270
|
'**********************************************************',
|
|
271
|
-
'
|
|
272
|
-
'
|
|
273
|
-
'
|
|
274
|
-
`-
|
|
275
|
-
' (
|
|
276
|
-
'-
|
|
277
|
-
'-
|
|
271
|
+
'需要安装最新版本的 Python;',
|
|
272
|
+
'应能自动找到并使用 Python;若找不到,',
|
|
273
|
+
'可尝试以下任一方式:',
|
|
274
|
+
`- 使用 --python="${pathExample}" 开关`,
|
|
275
|
+
' (npm 与本包均接受该参数)',
|
|
276
|
+
'- 设置环境变量 PYTHON',
|
|
277
|
+
'- 设置 npm 配置项 python:',
|
|
278
278
|
` npm config set python "${pathExample}"`,
|
|
279
|
-
'
|
|
279
|
+
'更多说明见文档:',
|
|
280
280
|
'https://github.com/nodejs/node-gyp#installation',
|
|
281
281
|
'**********************************************************'
|
|
282
282
|
].join('\n');
|
package/lib/find-visualstudio.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import * as log from './log.js';
|
|
2
2
|
import { existsSync } from 'fs';
|
|
3
3
|
import nodePath from 'path';
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
@@ -11,7 +11,7 @@ const path = nodePath.win32, __dirname = nodePath.dirname(fileURLToPath(import.m
|
|
|
11
11
|
class VisualStudioFinder {
|
|
12
12
|
static findVisualStudio = (...args) => new VisualStudioFinder(...args).findVisualStudio();
|
|
13
13
|
|
|
14
|
-
log = log.withPrefix('
|
|
14
|
+
log = log.withPrefix('查找 VS');
|
|
15
15
|
regSearchKeys = regSearchKeys;
|
|
16
16
|
constructor(nodeSemver, configMsvsVersion) {
|
|
17
17
|
this.nodeSemver = nodeSemver, this.configMsvsVersion = configMsvsVersion, this.errorLog = [], this.validVersions = [];
|
|
@@ -25,23 +25,23 @@ class VisualStudioFinder {
|
|
|
25
25
|
async findVisualStudio() {
|
|
26
26
|
this.configVersionYear = null, this.configPath = null;
|
|
27
27
|
if (this.configMsvsVersion) {
|
|
28
|
-
this.addLog('
|
|
28
|
+
this.addLog('已从命令行或 npm 配置设置 msvs_version');
|
|
29
29
|
if (this.configMsvsVersion.match(/^\d{4}$/)) {
|
|
30
30
|
this.configVersionYear = parseInt(this.configMsvsVersion, 10);
|
|
31
|
-
this.addLog(`-
|
|
31
|
+
this.addLog(`- 正在查找 Visual Studio ${this.configVersionYear} 版本`);
|
|
32
32
|
} else {
|
|
33
33
|
this.configPath = path.resolve(this.configMsvsVersion);
|
|
34
|
-
this.addLog(`-
|
|
34
|
+
this.addLog(`- 正在查找安装在 "${this.configPath}" 的 Visual Studio`);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
-
else this.addLog('
|
|
37
|
+
else this.addLog('未从命令行或 npm 配置设置 msvs_version');
|
|
38
38
|
|
|
39
39
|
if (process.env.VCINSTALLDIR) {
|
|
40
40
|
this.envVcInstallDir = path.resolve(process.env.VCINSTALLDIR, '..');
|
|
41
|
-
this.addLog('
|
|
41
|
+
this.addLog('运行在 VS 命令提示符中,安装路径为:\n' +
|
|
42
42
|
`"${this.envVcInstallDir}"\n- will only use this version`);
|
|
43
43
|
}
|
|
44
|
-
else this.addLog('VCINSTALLDIR
|
|
44
|
+
else this.addLog('未设置 VCINSTALLDIR,不在 VS 命令提示符中运行');
|
|
45
45
|
|
|
46
46
|
const checks = [
|
|
47
47
|
() => this.findVisualStudio2017OrNewer(), () => this.findVisualStudio2015(), () => this.findVisualStudio2013()
|
|
@@ -56,32 +56,32 @@ class VisualStudioFinder {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
succeed(info) {
|
|
59
|
-
this.log.info(
|
|
60
|
-
`\n"${info.path}"` + '\
|
|
59
|
+
this.log.info(`使用 VS${info.versionYear} (${info.version}),路径:` +
|
|
60
|
+
`\n"${info.path}"` + '\n加 --verbose 可查看详细信息');
|
|
61
61
|
return info;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
fail() {
|
|
65
65
|
if (this.configMsvsVersion && this.envVcInstallDir)
|
|
66
66
|
this.errorLog.push(
|
|
67
|
-
'msvs_version
|
|
67
|
+
'msvs_version 与当前 VS 命令提示符不匹配,或该安装不可用');
|
|
68
68
|
else if (this.configMsvsVersion) {
|
|
69
69
|
// 指定了 msvs_version 但没找到 VS,输出可接受的版本
|
|
70
70
|
this.errorLog.push('');
|
|
71
71
|
if (this.validVersions) {
|
|
72
|
-
this.errorLog.push('
|
|
72
|
+
this.errorLog.push('msvs_version 可用的版本:');
|
|
73
73
|
this.validVersions.forEach(version => this.errorLog.push(`- "${version}"`));
|
|
74
74
|
}
|
|
75
|
-
else this.errorLog.push('
|
|
75
|
+
else this.errorLog.push('未找到 msvs_version 可用的版本');
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
const errorLog = this.errorLog.join('\n'),
|
|
79
79
|
// Windows 80 列控制台,用到 X 标记列之前(含日志前缀共 79 字符,可用 62 字符):
|
|
80
80
|
infoLog = [
|
|
81
81
|
'**************************************************************',
|
|
82
|
-
'
|
|
83
|
-
'
|
|
84
|
-
'
|
|
82
|
+
'需要安装最新版本的 Visual Studio,并包含',
|
|
83
|
+
'"使用 C++ 的桌面开发"工作负载;',
|
|
84
|
+
'更多说明见文档:',
|
|
85
85
|
'https://github.com/nodejs/node-gyp#on-windows',
|
|
86
86
|
'**************************************************************'
|
|
87
87
|
].join('\n');
|
|
@@ -97,23 +97,23 @@ class VisualStudioFinder {
|
|
|
97
97
|
psArgs = ['-ExecutionPolicy', 'Unrestricted', '-NoProfile', '-Command',
|
|
98
98
|
'&{Add-Type -Path \'' + csFile + '\';' + '[VisualStudioConfiguration.Main]::PrintJson()}'];
|
|
99
99
|
|
|
100
|
-
this.log.silly('
|
|
100
|
+
this.log.silly('正在执行', ps, psArgs);
|
|
101
101
|
const [err, stdout, stderr] = await execFile(ps, psArgs, { encoding: 'utf8' });
|
|
102
102
|
return this.parseData(err, stdout, stderr);
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
// 解析 PowerShell 脚本输出,寻找可用的 Visual Studio 2017 或更新版本
|
|
106
106
|
parseData(err, stdout, stderr) {
|
|
107
|
-
this.log.silly('PS
|
|
107
|
+
this.log.silly('PS 标准错误 = %j', stderr)
|
|
108
108
|
|
|
109
109
|
const failPowershell = () => {
|
|
110
|
-
this.addLog(
|
|
111
|
-
|
|
110
|
+
this.addLog(`无法用 PowerShell 找到 Visual Studio 2017 或更新版本,
|
|
111
|
+
可加 '--loglevel silly' 重新运行以获取更多细节`);
|
|
112
112
|
return null;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
if (err) {
|
|
116
|
-
this.log.silly('PS
|
|
116
|
+
this.log.silly('PS 错误 = %j', err && (err.stack || err));
|
|
117
117
|
return failPowershell();
|
|
118
118
|
}
|
|
119
119
|
|
|
@@ -121,12 +121,12 @@ class VisualStudioFinder {
|
|
|
121
121
|
try {
|
|
122
122
|
vsInfo = JSON.parse(stdout);
|
|
123
123
|
} catch (e) {
|
|
124
|
-
this.log.silly('PS
|
|
124
|
+
this.log.silly('PS 标准输出 = %j', stdout), this.log.silly(e);
|
|
125
125
|
return failPowershell();
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
if (!Array.isArray(vsInfo)) {
|
|
129
|
-
this.log.silly('PS
|
|
129
|
+
this.log.silly('PS 标准输出 = %j', stdout);
|
|
130
130
|
return failPowershell();
|
|
131
131
|
}
|
|
132
132
|
|
|
@@ -145,7 +145,7 @@ class VisualStudioFinder {
|
|
|
145
145
|
// 去掉未来版本或版本号解析失败的项
|
|
146
146
|
vsInfo = vsInfo.filter(info => {
|
|
147
147
|
if (info.versionYear) return true;
|
|
148
|
-
this.addLog(
|
|
148
|
+
this.addLog(`在 "${info.path}" 发现未知版本 "${info.version}"`);
|
|
149
149
|
return false;
|
|
150
150
|
})
|
|
151
151
|
|
|
@@ -154,23 +154,23 @@ class VisualStudioFinder {
|
|
|
154
154
|
|
|
155
155
|
for (let i = 0; i < vsInfo.length; ++i) {
|
|
156
156
|
const info = vsInfo[i];
|
|
157
|
-
this.addLog(
|
|
157
|
+
this.addLog(`正在检查 VS${info.versionYear} (${info.version}),发现于:\n"${info.path}"`);
|
|
158
158
|
|
|
159
|
-
if (info.msBuild) this.addLog('-
|
|
159
|
+
if (info.msBuild) this.addLog('- 找到 "Visual Studio C++ 核心功能"');
|
|
160
160
|
else {
|
|
161
|
-
this.addLog('- "Visual Studio C++
|
|
161
|
+
this.addLog('- 缺少 "Visual Studio C++ 核心功能"');
|
|
162
162
|
continue;
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
if (info.toolset) this.addLog(`-
|
|
165
|
+
if (info.toolset) this.addLog(`- 找到 VC++ 工具集: ${info.toolset}`);
|
|
166
166
|
else {
|
|
167
|
-
this.addLog('-
|
|
167
|
+
this.addLog('- 缺少任何 VC++ 工具集');
|
|
168
168
|
continue;
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
if (info.sdk) this.addLog(`-
|
|
171
|
+
if (info.sdk) this.addLog(`- 找到 Windows SDK: ${info.sdk}`);
|
|
172
172
|
else {
|
|
173
|
-
this.addLog('-
|
|
173
|
+
this.addLog('- 缺少任何 Windows SDK');
|
|
174
174
|
continue;
|
|
175
175
|
}
|
|
176
176
|
|
|
@@ -178,7 +178,7 @@ class VisualStudioFinder {
|
|
|
178
178
|
return info
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
this.addLog('
|
|
181
|
+
this.addLog('未找到可用的 Visual Studio 2017 或更新版本');
|
|
182
182
|
return null;
|
|
183
183
|
}
|
|
184
184
|
|
|
@@ -186,16 +186,16 @@ class VisualStudioFinder {
|
|
|
186
186
|
getVersionInfo(info) {
|
|
187
187
|
const match = /^(\d+)\.(\d+)\./.exec(info.version);
|
|
188
188
|
if (!match) {
|
|
189
|
-
this.log.silly('-
|
|
189
|
+
this.log.silly('- 解析版本失败:', info.version);
|
|
190
190
|
return {};
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
this.log.silly('-
|
|
193
|
+
this.log.silly('- 版本匹配 = %j', match);
|
|
194
194
|
const versionMajor = parseInt(match[1], 10), versionMinor = parseInt(match[2], 10),
|
|
195
195
|
VERSION_YEAR = { 15: 2017, 16: 2019, 17: 2022, 18: 2026, }, versionYear = VERSION_YEAR[versionMajor];
|
|
196
196
|
|
|
197
197
|
if (!versionYear) {
|
|
198
|
-
this.log.silly('-
|
|
198
|
+
this.log.silly('- 不支持的版本:', versionMajor);
|
|
199
199
|
return {};
|
|
200
200
|
}
|
|
201
201
|
|
|
@@ -212,7 +212,7 @@ class VisualStudioFinder {
|
|
|
212
212
|
msbuildPath = path.join(info.path, 'MSBuild', 'Current', 'Bin', 'MSBuild.exe'),
|
|
213
213
|
msbuildPathArm64 = path.join(info.path, 'MSBuild', 'Current', 'Bin', 'arm64', 'MSBuild.exe');
|
|
214
214
|
if (info.packages.indexOf(pkg) !== -1) {
|
|
215
|
-
this.log.silly('-
|
|
215
|
+
this.log.silly('- 找到 VC.MSBuild.Base')
|
|
216
216
|
if (versionYear === 2017) return path.join(info.path, 'MSBuild', '15.0', 'Bin', 'MSBuild.exe');
|
|
217
217
|
if (versionYear === 2019) return msbuildPath;
|
|
218
218
|
}
|
|
@@ -229,15 +229,15 @@ class VisualStudioFinder {
|
|
|
229
229
|
// 辅助:解析 toolset 信息
|
|
230
230
|
getToolset(info, versionYear) {
|
|
231
231
|
const pkg = 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', express = 'Microsoft.VisualStudio.WDExpress';
|
|
232
|
-
if (info.packages.indexOf(pkg) !== -1) this.log.silly('-
|
|
233
|
-
else if (info.packages.indexOf(express) !== -1) this.log.silly('-
|
|
232
|
+
if (info.packages.indexOf(pkg) !== -1) this.log.silly('- 找到 VC.Tools.x86.x64');
|
|
233
|
+
else if (info.packages.indexOf(express) !== -1) this.log.silly('- 找到 Visual Studio Express(正在查找工具集)');
|
|
234
234
|
else return null;
|
|
235
235
|
|
|
236
236
|
if (versionYear === 2017) return 'v141'
|
|
237
237
|
else if (versionYear === 2019) return 'v142';
|
|
238
238
|
else if (versionYear === 2022) return 'v143';
|
|
239
239
|
else if (versionYear === 2026) return 'v145';
|
|
240
|
-
this.log.silly('-
|
|
240
|
+
this.log.silly('- versionYear 无效:', versionYear);
|
|
241
241
|
return null;
|
|
242
242
|
}
|
|
243
243
|
|
|
@@ -252,22 +252,22 @@ class VisualStudioFinder {
|
|
|
252
252
|
if (!pkg.startsWith(win10SDKPrefix) && !pkg.startsWith(win11SDKPrefix)) return;
|
|
253
253
|
const parts = pkg.split('.')
|
|
254
254
|
if (parts.length > 5 && parts[5] !== 'Desktop') {
|
|
255
|
-
this.log.silly('-
|
|
255
|
+
this.log.silly('- 忽略非桌面版 Win10/11SDK:', pkg);
|
|
256
256
|
return;
|
|
257
257
|
}
|
|
258
258
|
const foundSdkVer = parseInt(parts[4], 10);
|
|
259
259
|
if (isNaN(foundSdkVer)) {
|
|
260
260
|
// Microsoft.VisualStudio.Component.Windows10SDK.IpOverUsb
|
|
261
|
-
this.log.silly('-
|
|
261
|
+
this.log.silly('- 解析 Win10/11SDK 编号失败:', pkg);
|
|
262
262
|
return;
|
|
263
263
|
}
|
|
264
|
-
this.log.silly('-
|
|
264
|
+
this.log.silly('- 找到 Win10/11SDK:', foundSdkVer);
|
|
265
265
|
Win10or11SDKVer = Math.max(Win10or11SDKVer, foundSdkVer);
|
|
266
266
|
})
|
|
267
267
|
|
|
268
268
|
if (Win10or11SDKVer !== 0) return `10.0.${Win10or11SDKVer}.0`;
|
|
269
269
|
else if (info.packages.indexOf(win8SDK) !== -1) {
|
|
270
|
-
this.log.silly('-
|
|
270
|
+
this.log.silly('- 找到 Win8SDK');
|
|
271
271
|
return '8.1';
|
|
272
272
|
}
|
|
273
273
|
return null;
|
|
@@ -276,7 +276,7 @@ class VisualStudioFinder {
|
|
|
276
276
|
// 查找可用的 Visual Studio 2015
|
|
277
277
|
async findVisualStudio2015() {
|
|
278
278
|
if (this.nodeSemver.major >= 19) {
|
|
279
|
-
this.addLog('
|
|
279
|
+
this.addLog('不查找 VS2015,它只支持到 Node.js 18');
|
|
280
280
|
return null;
|
|
281
281
|
}
|
|
282
282
|
return this.findOldVS({ version: '14.0', versionMajor: 14, versionMinor: 0, versionYear: 2015, toolset: 'v140' });
|
|
@@ -285,7 +285,7 @@ class VisualStudioFinder {
|
|
|
285
285
|
// 查找可用的 Visual Studio 2013
|
|
286
286
|
async findVisualStudio2013() {
|
|
287
287
|
if (this.nodeSemver.major >= 9) {
|
|
288
|
-
this.addLog('
|
|
288
|
+
this.addLog('不查找 VS2013,它只支持到 Node.js 8')
|
|
289
289
|
return null;
|
|
290
290
|
}
|
|
291
291
|
return this.findOldVS({ version: '12.0', versionMajor: 12, versionMinor: 0, versionYear: 2013, toolset: 'v120' });
|
|
@@ -297,27 +297,27 @@ class VisualStudioFinder {
|
|
|
297
297
|
'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7'],
|
|
298
298
|
regMSBuild = 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions';
|
|
299
299
|
|
|
300
|
-
this.addLog(
|
|
300
|
+
this.addLog(`正在查找 Visual Studio ${info.versionYear}`);
|
|
301
301
|
try {
|
|
302
302
|
let res = await this.regSearchKeys(regVC7, info.version, []);
|
|
303
303
|
const msBuildRegOpts = process.arch === 'ia32' ? [] : ['/reg:32'], vsPath = path.resolve(res, '..');
|
|
304
|
-
this.addLog(`-
|
|
304
|
+
this.addLog(`- 发现于 "${vsPath}"`);
|
|
305
305
|
|
|
306
306
|
try {
|
|
307
307
|
res = await this.regSearchKeys([`${regMSBuild}\\${info.version}`], 'MSBuildToolsPath', msBuildRegOpts);
|
|
308
308
|
} catch (err) {
|
|
309
|
-
this.addLog('-
|
|
309
|
+
this.addLog('- 在注册表中未找到此版本的 MSBuild');
|
|
310
310
|
return null;
|
|
311
311
|
}
|
|
312
312
|
|
|
313
313
|
const msBuild = path.join(res, 'MSBuild.exe');
|
|
314
|
-
this.addLog(`- MSBuild
|
|
314
|
+
this.addLog(`- MSBuild 位于 "${msBuild}"`);
|
|
315
315
|
|
|
316
316
|
if (!this.checkConfigVersion(info.versionYear, vsPath)) return null;
|
|
317
317
|
info.path = vsPath, info.msBuild = msBuild, info.sdk = null;
|
|
318
318
|
return info;
|
|
319
319
|
} catch (err) {
|
|
320
|
-
this.addLog('-
|
|
320
|
+
this.addLog('- 未找到');
|
|
321
321
|
return null;
|
|
322
322
|
}
|
|
323
323
|
}
|
|
@@ -330,15 +330,15 @@ class VisualStudioFinder {
|
|
|
330
330
|
this.validVersions.push(versionYear), this.validVersions.push(vsPath);
|
|
331
331
|
|
|
332
332
|
if (this.configVersionYear && this.configVersionYear !== versionYear) {
|
|
333
|
-
this.addLog('- msvs_version
|
|
333
|
+
this.addLog('- msvs_version 与此版本不匹配');
|
|
334
334
|
return false;
|
|
335
335
|
}
|
|
336
336
|
if (this.configPath && path.relative(this.configPath, vsPath) !== '') {
|
|
337
|
-
this.addLog('- msvs_version
|
|
337
|
+
this.addLog('- msvs_version 未指向此安装');
|
|
338
338
|
return false;
|
|
339
339
|
}
|
|
340
340
|
if (this.envVcInstallDir && path.relative(this.envVcInstallDir, vsPath) !== '') {
|
|
341
|
-
this.addLog('-
|
|
341
|
+
this.addLog('- 与当前 Visual Studio 命令提示符不匹配');
|
|
342
342
|
return false;
|
|
343
343
|
}
|
|
344
344
|
|