@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/bin/node-gyp.js
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
import envPaths from 'env-paths';
|
|
4
4
|
import os from 'os';
|
|
5
5
|
import fs from 'fs';
|
|
6
|
+
import chalk from 'chalk';
|
|
6
7
|
import { Gyp } from '../lib/node-gyp.js';
|
|
7
8
|
import * as log from '../lib/log.js';
|
|
8
9
|
|
|
9
|
-
process.title = '
|
|
10
|
-
|
|
10
|
+
process.title = 'nodejs-mobile-gyp';
|
|
11
11
|
/**
|
|
12
12
|
* 处理并执行选中的命令;
|
|
13
13
|
*/
|
|
@@ -19,21 +19,25 @@ prog.parseArgv(process.argv), prog.devDir = prog.opts.devdir;
|
|
|
19
19
|
if (prog.devDir) prog.devDir = prog.devDir.replace(/^~/, homeDir);
|
|
20
20
|
else if (homeDir) prog.devDir = envPaths('node-gyp', { suffix: '' }).cache;
|
|
21
21
|
else {
|
|
22
|
-
throw new Error(
|
|
23
|
-
|
|
24
|
-
'in either of the environmental variables HOME or USERPROFILE. ' +
|
|
25
|
-
'Overide with: --devdir /path/to/.node-gyp');
|
|
22
|
+
throw new Error('nodejs-mobile-gyp 需要指定用户主目录,请设置环境变量 HOME 或 USERPROFILE;'
|
|
23
|
+
+ '也可用 --devdir /path/to/.node-gyp 覆盖');
|
|
26
24
|
}
|
|
27
25
|
|
|
28
26
|
if (prog.todo.length === 0) {
|
|
27
|
+
const helpArgs = ['help', '-h', '--help'], hasHelp = process.argv.some(a => helpArgs.includes(a)),
|
|
28
|
+
unknown = prog.argv.filter(a => !helpArgs.includes(a));
|
|
29
29
|
if (~process.argv.indexOf('-v') || ~process.argv.indexOf('--version')) log.stdout('v%s', prog.version);
|
|
30
|
-
else log.stdout('%s', prog.usage());
|
|
30
|
+
else if (hasHelp || unknown.length === 0) log.stdout('%s', prog.usage());
|
|
31
|
+
else {
|
|
32
|
+
console.error(`${chalk.red('✗ 未知命令: ')}${chalk.yellow(unknown[0])}`), console.error('');
|
|
33
|
+
console.log(prog.usage()), process.exit(1);
|
|
34
|
+
}
|
|
31
35
|
process.exit(0);
|
|
32
36
|
}
|
|
33
37
|
|
|
34
|
-
log.info('
|
|
35
|
-
|
|
36
|
-
log.info('
|
|
38
|
+
log.info('以 ok 结尾即执行成功', 'ok'), log.verbose('cli', process.argv);
|
|
39
|
+
log.info('使用', 'nodejs-mobile-gyp@%s', prog.version);
|
|
40
|
+
log.info('使用', 'node@%s | %s | %s', process.versions.node, process.platform, process.arch);
|
|
37
41
|
|
|
38
42
|
/**
|
|
39
43
|
* 如果传了 -C/--directory,切换到该目录;
|
|
@@ -42,11 +46,11 @@ const dir = prog.opts.directory;
|
|
|
42
46
|
if (dir) {
|
|
43
47
|
try {
|
|
44
48
|
const stat = fs.statSync(dir);
|
|
45
|
-
if (stat.isDirectory()) log.info('
|
|
46
|
-
else log.warn('
|
|
49
|
+
if (stat.isDirectory()) log.info('切换目录', dir), process.chdir(dir);
|
|
50
|
+
else log.warn('切换目录', dir + ' 不是目录');
|
|
47
51
|
} catch (e) {
|
|
48
|
-
if (e.code === 'ENOENT') log.warn('
|
|
49
|
-
else log.warn('
|
|
52
|
+
if (e.code === 'ENOENT') log.warn('切换目录', dir + ' 不是目录');
|
|
53
|
+
else log.warn('切换目录', '切换目录失败 "%s"', e.message);
|
|
50
54
|
}
|
|
51
55
|
}
|
|
52
56
|
|
|
@@ -55,16 +59,18 @@ if (dir) {
|
|
|
55
59
|
*/
|
|
56
60
|
const errorMessage = () => {
|
|
57
61
|
// 复制自 npm 的 lib/utils/error-handler.js
|
|
58
|
-
log.error('
|
|
59
|
-
log.error('
|
|
60
|
-
log.error('node
|
|
62
|
+
log.error('系统', os.type() + ' ' + os.release());
|
|
63
|
+
log.error('命令', process.argv.map(JSON.stringify).join(' ')), log.error('工作目录', process.cwd());
|
|
64
|
+
log.error('node 版本', process.version), log.error('nodejs-mobile-gyp 版本', 'v' + prog.package.version);
|
|
61
65
|
},
|
|
62
66
|
/**
|
|
63
67
|
* 打印最终诊断信息
|
|
64
68
|
*/
|
|
65
69
|
issueMessage = () => {
|
|
66
70
|
errorMessage();
|
|
67
|
-
log.error('', [
|
|
71
|
+
log.error('', [
|
|
72
|
+
'nodejs-mobile-gyp 构建你的包失败!', '请尝试更新 npm 和/或 nodejs-mobile-gyp;若仍无法解决,请向作者反馈;'
|
|
73
|
+
].join('\n'));
|
|
68
74
|
},
|
|
69
75
|
/**
|
|
70
76
|
* 依次执行队列中的命令
|
|
@@ -82,12 +88,12 @@ const errorMessage = () => {
|
|
|
82
88
|
|
|
83
89
|
if (command.name === 'list') {
|
|
84
90
|
if (args.length) args.forEach((version) => log.stdout(version));
|
|
85
|
-
else log.stdout('尚未安装任何 Node 开发文件;可用 `
|
|
91
|
+
else log.stdout('尚未安装任何 Node 开发文件;可用 `nodejs-mobile-gyp install` 安装指定版本;')
|
|
86
92
|
}
|
|
87
93
|
else if (args.length >= 1) log.stdout(...args.slice(1))
|
|
88
94
|
return run(); // 继续执行队列中的下一条命令
|
|
89
95
|
} catch (err) {
|
|
90
|
-
log.error(command.name + '
|
|
96
|
+
log.error(command.name + ' 命令执行出错'), log.error('堆栈', err.stack), errorMessage(), log.error('not ok');
|
|
91
97
|
return process.exit(1);
|
|
92
98
|
}
|
|
93
99
|
};
|
|
@@ -96,7 +102,7 @@ process.on('exit', code => {
|
|
|
96
102
|
if (!completed && !code) log.error('完成回调未被调用!'), issueMessage(), process.exit(6);
|
|
97
103
|
});
|
|
98
104
|
process.on('uncaughtException', err => {
|
|
99
|
-
log.error('未捕获的异常'), log.error('
|
|
105
|
+
log.error('未捕获的异常'), log.error('堆栈', err.stack), issueMessage(), process.exit(7);
|
|
100
106
|
});
|
|
101
107
|
|
|
102
108
|
run(); // 开始执行给定命令!
|
package/lib/Find-VisualStudio.cs
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
// See accompanying file LICENSE at https://github.com/node4good/windows-autoconf
|
|
4
4
|
|
|
5
5
|
// Usage:
|
|
6
|
-
// powershell -ExecutionPolicy Unrestricted -Command "Add-Type -Path Find-VisualStudio.cs;
|
|
6
|
+
// powershell -ExecutionPolicy Unrestricted -Command "Add-Type -Path Find-VisualStudio.cs;
|
|
7
|
+
// [VisualStudioConfiguration.Main]::PrintJson()"
|
|
7
8
|
// This script needs to be compatible with PowerShell v2 to run on Windows 2008R2 and Windows 7.
|
|
8
9
|
|
|
9
10
|
using System;
|
package/lib/build.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import gracefulFs from 'graceful-fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { glob } from 'glob';
|
|
4
4
|
import * as log from './log.js';
|
|
@@ -7,8 +7,7 @@ import os from 'os';
|
|
|
7
7
|
import { spawnSync } from 'child_process';
|
|
8
8
|
import fsSync from 'fs';
|
|
9
9
|
|
|
10
|
-
const fs = gracefulFs.promises,
|
|
11
|
-
_hostIsWindows = process.platform === 'win32',
|
|
10
|
+
const fs = gracefulFs.promises, _hostIsWindows = process.platform === 'win32',
|
|
12
11
|
// Android 交叉编译即使宿主是 Windows,也必须走 make(make-android 生成器)
|
|
13
12
|
_isAndroidCrossBuild = process.env.npm_config_platform === 'android' || process.env.npm_config_format === 'make-android',
|
|
14
13
|
// win 在此文件中语义为"使用 MSBuild":仅 Windows 宿主且非 Android 交叉编译
|
|
@@ -20,12 +19,11 @@ const fs = gracefulFs.promises,
|
|
|
20
19
|
*/
|
|
21
20
|
findWindowsShellDir = () => {
|
|
22
21
|
if (process.platform !== 'win32') return null;
|
|
23
|
-
const tryShDir =
|
|
22
|
+
const tryShDir = dir => {
|
|
24
23
|
try { return fsSync.existsSync(path.join(dir, 'sh.exe')) ? dir : null } catch { return null }
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const reg = process.env.SystemRoot ? path.join(process.env.SystemRoot, 'System32', 'reg.exe') : 'reg.exe';
|
|
24
|
+
}, toShDir = (gitRoot) => tryShDir(path.join(gitRoot, 'usr', 'bin')),
|
|
25
|
+
// 1) 注册表:Git for Windows 安装时必写,与 PATH 无关(最可靠)
|
|
26
|
+
reg = process.env.SystemRoot ? path.join(process.env.SystemRoot, 'System32', 'reg.exe') : 'reg.exe';
|
|
29
27
|
for (const hive of ['HKLM', 'HKCU']) {
|
|
30
28
|
for (const key of ['SOFTWARE\\GitForWindows', 'SOFTWARE\\WOW6432Node\\GitForWindows']) {
|
|
31
29
|
try {
|
|
@@ -44,8 +42,7 @@ const fs = gracefulFs.promises,
|
|
|
44
42
|
try {
|
|
45
43
|
const gitPath = which.sync('git');
|
|
46
44
|
if (gitPath) {
|
|
47
|
-
const dir = path.resolve(path.dirname(gitPath), '..', 'usr', 'bin');
|
|
48
|
-
const r = tryShDir(dir);
|
|
45
|
+
const dir = path.resolve(path.dirname(gitPath), '..', 'usr', 'bin'), r = tryShDir(dir);
|
|
49
46
|
if (r) return r;
|
|
50
47
|
}
|
|
51
48
|
} catch { }
|
|
@@ -54,16 +51,13 @@ const fs = gracefulFs.promises,
|
|
|
54
51
|
if (!pd) continue;
|
|
55
52
|
try {
|
|
56
53
|
if (fsSync.existsSync(path.join(pd, 'git.exe'))) {
|
|
57
|
-
const dir = path.resolve(pd, '..', 'usr', 'bin');
|
|
58
|
-
const r = tryShDir(dir);
|
|
54
|
+
const dir = path.resolve(pd, '..', 'usr', 'bin'), r = tryShDir(dir);
|
|
59
55
|
if (r) return r;
|
|
60
56
|
}
|
|
61
57
|
} catch { }
|
|
62
58
|
}
|
|
63
59
|
// 4) 全盘符常见位置兜底
|
|
64
|
-
const suffixes = [
|
|
65
|
-
'Program Files\\Git', 'Program Files (x86)\\Git', 'Git', 'msys64',
|
|
66
|
-
];
|
|
60
|
+
const suffixes = ['Program Files\\Git', 'Program Files (x86)\\Git', 'Git', 'msys64'];
|
|
67
61
|
for (const drv of ['C:', 'D:', 'E:', 'F:']) {
|
|
68
62
|
for (const sfx of suffixes) {
|
|
69
63
|
const dir = tryShDir(drv + '\\' + sfx);
|
|
@@ -104,7 +98,7 @@ const fs = gracefulFs.promises,
|
|
|
104
98
|
// 注意:msbuild 的 Condition 字符串相等比较不区分大小写
|
|
105
99
|
const archLower = arch.toLowerCase(), p = archLower === 'x64' ? 'x64' : (archLower === 'arm' ? 'ARM'
|
|
106
100
|
: (archLower === 'arm64' ? 'ARM64' : 'Win32'));
|
|
107
|
-
argv.push('/p:Configuration=' + buildType + ';Platform=' + p)
|
|
101
|
+
argv.push('/p:Configuration=' + buildType + ';Platform=' + p);
|
|
108
102
|
if (jobs) {
|
|
109
103
|
j = parseInt(jobs, 10)
|
|
110
104
|
if (!isNaN(j) && j > 0) argv.push('/m:' + j);
|
|
@@ -134,21 +128,18 @@ const fs = gracefulFs.promises,
|
|
|
134
128
|
const shellDir = findWindowsShellDir();
|
|
135
129
|
if (shellDir) {
|
|
136
130
|
process.env.PATH = `${shellDir};${process.env.PATH}`;
|
|
137
|
-
log.verbose('bin
|
|
138
|
-
} else {
|
|
139
|
-
log.warn('bin shell', 'no sh.exe found; GNU make 的 Unix 命令可能失败;建议安装 Git for Windows');
|
|
131
|
+
log.verbose('bin 环境', `已将 ${shellDir} 加入 PATH,供 make 使用`);
|
|
140
132
|
}
|
|
133
|
+
else log.warn('shell 环境', '未找到 sh.exe;GNU make 的 Unix 命令可能失败;建议安装 Git for Windows');
|
|
141
134
|
}
|
|
142
|
-
process.env.PATH = _hostIsWindows
|
|
143
|
-
? `${buildBinsDir};${process.env.PATH}`
|
|
144
|
-
: `${buildBinsDir}:${process.env.PATH}`;
|
|
135
|
+
process.env.PATH = _hostIsWindows ? `${buildBinsDir};${process.env.PATH}` : `${buildBinsDir}:${process.env.PATH}`;
|
|
145
136
|
await fs.mkdir(buildBinsDir, { recursive: true });
|
|
146
137
|
|
|
147
138
|
if (_hostIsWindows) {
|
|
148
139
|
// Windows 无 python3 名称,且创建符号链接需要管理员权限;改用 .cmd 桥接
|
|
149
140
|
const shimPath = path.join(buildBinsDir, 'python3.cmd');
|
|
150
141
|
await fs.writeFile(shimPath, `@echo off\r\n"${python}" %*\r\n`);
|
|
151
|
-
log.verbose('bin
|
|
142
|
+
log.verbose('bin 垫片', `已创建 python3.cmd 指向 "${python}" 并加入 PATH`);
|
|
152
143
|
} else {
|
|
153
144
|
const symlinkDestination = path.join(buildBinsDir, 'python3');
|
|
154
145
|
try {
|
|
@@ -157,16 +148,15 @@ const fs = gracefulFs.promises,
|
|
|
157
148
|
if (err.code !== 'ENOENT') throw err;
|
|
158
149
|
}
|
|
159
150
|
await fs.symlink(python, symlinkDestination);
|
|
160
|
-
log.verbose('bin
|
|
151
|
+
log.verbose('bin 符号链接', `已在 "${buildBinsDir}" 创建指向 "${python}" 的符号链接并加入 PATH`);
|
|
161
152
|
}
|
|
162
153
|
}
|
|
163
154
|
|
|
164
155
|
const proc = gyp.spawn(command, argv);
|
|
165
156
|
await new Promise((resolve, reject) => proc.on('exit', async (code, signal) => {
|
|
166
157
|
if (buildBinsDir) await fs.rm(buildBinsDir, { recursive: true }); // 清理构建期依赖的符号链接
|
|
167
|
-
|
|
168
|
-
if (
|
|
169
|
-
if (signal) return reject(new Error('`' + command + '` got signal: ' + signal));
|
|
158
|
+
if (code !== 0) return reject(new Error('`' + command + '` 执行失败,退出码: ' + code));
|
|
159
|
+
if (signal) return reject(new Error('`' + command + '` 收到信号: ' + signal));
|
|
170
160
|
resolve();
|
|
171
161
|
}))
|
|
172
162
|
},
|
|
@@ -174,16 +164,16 @@ const fs = gracefulFs.promises,
|
|
|
174
164
|
* 用 node-which 定位 msbuild / make 可执行文件
|
|
175
165
|
*/
|
|
176
166
|
doWhich = async () => {
|
|
177
|
-
// Windows 使用
|
|
167
|
+
// Windows 使用 nodejs-mobile-gyp configure 提供的 msbuild
|
|
178
168
|
if (win) {
|
|
179
|
-
if (!config.variables.msbuild_path) throw new Error('MSBuild 未设置,请先运行 `
|
|
180
|
-
command = config.variables.msbuild_path, log.verbose('
|
|
169
|
+
if (!config.variables.msbuild_path) throw new Error('MSBuild 未设置,请先运行 `nodejs-mobile-gyp configure`');
|
|
170
|
+
command = config.variables.msbuild_path, log.verbose('使用 MSBuild:', command), await doBuild();
|
|
181
171
|
return;
|
|
182
172
|
}
|
|
183
173
|
|
|
184
174
|
// 先确认构建命令在 PATH 中
|
|
185
175
|
const execPath = await which(command);
|
|
186
|
-
log.verbose('`which`
|
|
176
|
+
log.verbose('`which` 成功解析 `' + command + '`', execPath), await doBuild();
|
|
187
177
|
},
|
|
188
178
|
/**
|
|
189
179
|
* Windows 下查找第一个 build/*.sln 文件
|
|
@@ -191,7 +181,7 @@ const fs = gracefulFs.promises,
|
|
|
191
181
|
findSolutionFile = async () => {
|
|
192
182
|
const files = await glob('build/*.sln')
|
|
193
183
|
if (files.length === 0) throw new Error('未找到 *.sln 文件,是否运行过 configure?');
|
|
194
|
-
guessedSolution = files[0], log.verbose('
|
|
184
|
+
guessedSolution = files[0], log.verbose('找到首个解决方案文件', guessedSolution), await doWhich();
|
|
195
185
|
},
|
|
196
186
|
/**
|
|
197
187
|
* 加载 configure 阶段生成的 config.gypi
|
|
@@ -202,7 +192,7 @@ const fs = gracefulFs.promises,
|
|
|
202
192
|
const configPath = path.resolve('build', 'config.gypi');
|
|
203
193
|
data = await fs.readFile(configPath, 'utf8');
|
|
204
194
|
} catch (err) {
|
|
205
|
-
if (err.code === 'ENOENT') throw new Error('请先运行 `
|
|
195
|
+
if (err.code === 'ENOENT') throw new Error('请先运行 `nodejs-mobile-gyp configure`');
|
|
206
196
|
else throw err;
|
|
207
197
|
}
|
|
208
198
|
|
|
@@ -213,13 +203,13 @@ const fs = gracefulFs.promises,
|
|
|
213
203
|
if ('debug' in gyp.opts) buildType = gyp.opts.debug ? 'Debug' : 'Release';
|
|
214
204
|
if (!buildType) buildType = 'Release';
|
|
215
205
|
|
|
216
|
-
log.verbose('
|
|
217
|
-
log.verbose('
|
|
206
|
+
log.verbose('构建类型', buildType), log.verbose('架构', arch), log.verbose('node 开发目录', nodeDir);
|
|
207
|
+
log.verbose('Python', python);
|
|
218
208
|
|
|
219
209
|
win ? await findSolutionFile() : await doWhich();
|
|
220
210
|
};
|
|
221
211
|
await loadConfigGypi();
|
|
222
212
|
};
|
|
223
213
|
|
|
224
|
-
build.usage = '
|
|
214
|
+
build.usage = '调用 `' + (win ? 'msbuild' : 'make') + '` 构建模块';
|
|
225
215
|
export { build };
|
package/lib/clean.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import gracefulFs from 'graceful-fs';
|
|
2
2
|
import * as log from './log.js';
|
|
3
3
|
|
|
4
4
|
const fs = gracefulFs.promises,
|
|
@@ -8,9 +8,9 @@ const fs = gracefulFs.promises,
|
|
|
8
8
|
clean = async (gyp, argv) => {
|
|
9
9
|
const buildDir = 'build';
|
|
10
10
|
|
|
11
|
-
log.verbose('
|
|
11
|
+
log.verbose('清理', '正在删除 "%s" 目录', buildDir);
|
|
12
12
|
await fs.rm(buildDir, { recursive: true, force: true });
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
clean.usage = '
|
|
15
|
+
clean.usage = '删除生成的构建文件与 "out" 目录';
|
|
16
16
|
export { clean };
|
package/lib/configure.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import gracefulFs from 'graceful-fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import * as log from './log.js';
|
|
4
4
|
import os from 'os';
|
|
@@ -30,11 +30,11 @@ const configure = async (gyp, argv) => {
|
|
|
30
30
|
runGyp = async () => {
|
|
31
31
|
if (!~argv.indexOf('-f') && !~argv.indexOf('--format')) {
|
|
32
32
|
if (win) {
|
|
33
|
-
log.verbose('gyp', 'gyp
|
|
33
|
+
log.verbose('gyp', '未指定 gyp 格式,强制使用 "msvs"');
|
|
34
34
|
// 非 Windows 强制使用 make 目标
|
|
35
35
|
argv.push('-f', ('format' in gyp.opts) ? gyp.opts.format : 'msvs');
|
|
36
36
|
} else {
|
|
37
|
-
log.verbose('gyp', 'gyp
|
|
37
|
+
log.verbose('gyp', '未指定 gyp 格式,强制使用 "make"');
|
|
38
38
|
// 非 Windows 强制使用 make 目标
|
|
39
39
|
argv.push('-f', ('format' in gyp.opts) ? gyp.opts.format : 'make');
|
|
40
40
|
}
|
|
@@ -42,7 +42,7 @@ const configure = async (gyp, argv) => {
|
|
|
42
42
|
|
|
43
43
|
configs.forEach(config => argv.push('-I', config)); // 引入所有找到的 .gypi 文件
|
|
44
44
|
// AIX 和 z/OS 需要设置导出文件路径,其中包含链接所需符号
|
|
45
|
-
let nodeExpFile, nodeRootDir, candidates, logprefix = '
|
|
45
|
+
let nodeExpFile, nodeRootDir, candidates, logprefix = '查找导出文件';
|
|
46
46
|
if (process.platform === 'aix' || process.platform === 'os390' || process.platform === 'os400') {
|
|
47
47
|
const ext = process.platform === 'os390' ? 'x' : 'exp';
|
|
48
48
|
nodeRootDir = findNodeDirectory();
|
|
@@ -55,10 +55,10 @@ const configure = async (gyp, argv) => {
|
|
|
55
55
|
'out/Debug/obj.target/libnode', 'lib/libnode'].map(file => file + '.' + ext);
|
|
56
56
|
|
|
57
57
|
nodeExpFile = findAccessibleSync(logprefix, nodeRootDir, candidates);
|
|
58
|
-
if (nodeExpFile !== undefined) log.verbose(logprefix, '
|
|
58
|
+
if (nodeExpFile !== undefined) log.verbose(logprefix, '已找到导出文件: %s', nodeExpFile);
|
|
59
59
|
else {
|
|
60
|
-
const msg = msgFormat('
|
|
61
|
-
log.error(logprefix, '
|
|
60
|
+
const msg = msgFormat('未找到 node.%s 文件,目录: %s', ext, nodeRootDir);
|
|
61
|
+
log.error(logprefix, '未找到导出文件');
|
|
62
62
|
throw new Error(msg);
|
|
63
63
|
}
|
|
64
64
|
}
|
|
@@ -66,14 +66,14 @@ const configure = async (gyp, argv) => {
|
|
|
66
66
|
// z/OS 需要设置 zoslib 头文件目录,其中包含 v8config.h 引用的头文件
|
|
67
67
|
let zoslibIncDir;
|
|
68
68
|
if (process.platform === 'os390') {
|
|
69
|
-
logprefix = "
|
|
69
|
+
logprefix = "查找 zoslib 的 zos-base.h:";
|
|
70
70
|
let msg, zoslibIncPath = process.env.ZOSLIB_INCLUDES;
|
|
71
71
|
if (zoslibIncPath) {
|
|
72
72
|
zoslibIncPath = findAccessibleSync(logprefix, zoslibIncPath, ['zos-base.h']);
|
|
73
73
|
if (zoslibIncPath === undefined) {
|
|
74
|
-
msg = msgFormat('
|
|
75
|
-
'
|
|
76
|
-
'
|
|
74
|
+
msg = msgFormat('在 ZOSLIB_INCLUDES 指定的目录中未找到 zos-base.h 文件: ' +
|
|
75
|
+
'%s; 请将其设为正确路径,或取消设置以便在 ' +
|
|
76
|
+
'%s 中搜索', process.env.ZOSLIB_INCLUDES, nodeRootDir)
|
|
77
77
|
}
|
|
78
78
|
} else {
|
|
79
79
|
candidates = [
|
|
@@ -82,14 +82,14 @@ const configure = async (gyp, argv) => {
|
|
|
82
82
|
]
|
|
83
83
|
zoslibIncPath = findAccessibleSync(logprefix, nodeRootDir, candidates);
|
|
84
84
|
if (zoslibIncPath === undefined) {
|
|
85
|
-
msg = msgFormat('
|
|
86
|
-
'
|
|
87
|
-
|
|
85
|
+
msg = msgFormat('未找到 %s 中列出的任意一项(目录: %s); ' +
|
|
86
|
+
'请设置环境变量 ZOSLIB_INCLUDES 指向包含 zos-base.h 的路径',
|
|
87
|
+
candidates.toString(), nodeRootDir);
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
if (zoslibIncPath !== undefined) {
|
|
91
91
|
zoslibIncDir = path.dirname(zoslibIncPath);
|
|
92
|
-
log.verbose(logprefix, "
|
|
92
|
+
log.verbose(logprefix, "在 %s 中找到 zoslib 的 zos-base.h", zoslibIncDir);
|
|
93
93
|
} else if (release.version.split('.')[0] >= 16) {
|
|
94
94
|
// zoslib 只随 Node v16 及以上发布
|
|
95
95
|
log.error(logprefix, msg);
|
|
@@ -148,7 +148,7 @@ const configure = async (gyp, argv) => {
|
|
|
148
148
|
await new Promise((resolve, reject) => {
|
|
149
149
|
const cp = gyp.spawn(python, argv);
|
|
150
150
|
cp.on('exit', code => {
|
|
151
|
-
if (code !== 0) reject(new Error('`gyp`
|
|
151
|
+
if (code !== 0) reject(new Error('`gyp` 执行失败,退出码: ' + code));
|
|
152
152
|
else resolve(); // 完成
|
|
153
153
|
})
|
|
154
154
|
})
|
|
@@ -158,9 +158,9 @@ const configure = async (gyp, argv) => {
|
|
|
158
158
|
if (!name) return runGyp();
|
|
159
159
|
|
|
160
160
|
const fullPath = path.resolve(name);
|
|
161
|
-
log.verbose(name, '
|
|
161
|
+
log.verbose(name, '正在检查 gypi 文件: %s', fullPath);
|
|
162
162
|
try {
|
|
163
|
-
await fs.stat(fullPath), log.verbose(name, '
|
|
163
|
+
await fs.stat(fullPath), log.verbose(name, '已找到 gypi 文件'), configs.push(fullPath);
|
|
164
164
|
} catch (err) {
|
|
165
165
|
if (err.code !== 'ENOENT') throw err; // ENOENT 时继续检查下一个 gypi 文件名
|
|
166
166
|
}
|
|
@@ -177,10 +177,10 @@ const configure = async (gyp, argv) => {
|
|
|
177
177
|
return findConfigs();
|
|
178
178
|
},
|
|
179
179
|
createBuildDir = async () => {
|
|
180
|
-
log.verbose('build
|
|
180
|
+
log.verbose('build 目录', '正在创建 "build" 目录: %s', buildDir);
|
|
181
181
|
|
|
182
182
|
const isNew = await fs.mkdir(buildDir, { recursive: true });
|
|
183
|
-
log.verbose('build
|
|
183
|
+
log.verbose('build 目录', '"build" 目录是否需要创建?', isNew ? '是' : '否');
|
|
184
184
|
vsInfo = win ? await findVisualStudio(release.semver, gyp.opts['msvs-version']) : null;
|
|
185
185
|
return createConfigFile();
|
|
186
186
|
},
|
|
@@ -191,23 +191,23 @@ const configure = async (gyp, argv) => {
|
|
|
191
191
|
if (gyp.opts.nodedir) {
|
|
192
192
|
// 指定了 --nodedir,用它作为开发文件目录
|
|
193
193
|
nodeDir = gyp.opts.nodedir.replace(/^~/, os.homedir());
|
|
194
|
-
log.verbose('
|
|
194
|
+
log.verbose('获取 node 目录', '使用指定的 --nodedir 开发文件编译: %s', nodeDir);
|
|
195
195
|
} else {
|
|
196
196
|
// 未指定 --nodedir,先确保 Node 依赖已安装
|
|
197
197
|
if ('v' + release.version !== process.version) {
|
|
198
198
|
// 指定了 --target,确定目标版本
|
|
199
|
-
log.verbose('
|
|
199
|
+
log.verbose('获取 node 目录', '按 --target 指定的 node 版本编译: %s', release.version);
|
|
200
200
|
} else {
|
|
201
201
|
// 未指定 --target,使用当前主机 Node 版本
|
|
202
|
-
log.verbose('
|
|
203
|
-
'
|
|
202
|
+
log.verbose('获取 node 目录',
|
|
203
|
+
'未指定 --target 版本,回退到宿主 node 版本: %s', release.version);
|
|
204
204
|
}
|
|
205
205
|
|
|
206
206
|
if (!release.semver) throw new Error('版本号无效: ' + release.version); // 无法用 semver 解析版本字符串
|
|
207
207
|
// 如果指定了 tarball 选项,总是删除并重装 headers 到 devdir,
|
|
208
208
|
// 否则只在不存在时安装
|
|
209
209
|
gyp.opts.ensure = !gyp.opts.tarball, await gyp.commands.install([release.version]);
|
|
210
|
-
log.verbose('
|
|
210
|
+
log.verbose('获取 node 目录', '目标 node 版本已安装:', release.versionDir);
|
|
211
211
|
nodeDir = path.resolve(gyp.devDir, release.versionDir);
|
|
212
212
|
}
|
|
213
213
|
|
|
@@ -216,5 +216,5 @@ const configure = async (gyp, argv) => {
|
|
|
216
216
|
return getNodeDir();
|
|
217
217
|
};
|
|
218
218
|
|
|
219
|
-
configure.usage = '
|
|
219
|
+
configure.usage = '为当前模块生成 ' + (win ? 'MSVC 项目文件' : 'Makefile') + ';';
|
|
220
220
|
export { configure };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import gracefulFs from 'graceful-fs';
|
|
2
2
|
import * as log from './log.js';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
|
|
@@ -25,7 +25,7 @@ const fs = gracefulFs.promises,
|
|
|
25
25
|
try {
|
|
26
26
|
const baseConfigGypi = await fs.readFile(path.resolve(nodeDir, 'include/node/config.gypi'));
|
|
27
27
|
return parseConfigGypi(baseConfigGypi.toString());
|
|
28
|
-
} catch (err) { log.warn('
|
|
28
|
+
} catch (err) { log.warn('读取 config.gypi', err.message) }
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
return JSON.parse(JSON.stringify(process.config)); // 回退到 process.config
|
|
@@ -89,7 +89,7 @@ const fs = gracefulFs.promises,
|
|
|
89
89
|
createConfigGypi = async ({ gyp, buildDir, nodeDir, vsInfo, python }) => {
|
|
90
90
|
const configFilename = 'config.gypi', configPath = path.resolve(buildDir, configFilename);
|
|
91
91
|
|
|
92
|
-
log.verbose('build/' + configFilename, '
|
|
92
|
+
log.verbose('build/' + configFilename, '正在创建配置文件');
|
|
93
93
|
const config = await getCurrentConfigGypi({ gyp, nodeDir, vsInfo, python }),
|
|
94
94
|
// 保证 config.gypi 中的布尔值都转成字符串
|
|
95
95
|
boolsToString = (k, v) => {
|
|
@@ -101,7 +101,7 @@ const fs = gracefulFs.promises,
|
|
|
101
101
|
// 把 config.gypi 写入 build/ 目录
|
|
102
102
|
const prefix = '# Do not edit. File was generated by node-gyp\'s "configure" step',
|
|
103
103
|
json = JSON.stringify(config, boolsToString, 2);
|
|
104
|
-
log.verbose('build/' + configFilename, '
|
|
104
|
+
log.verbose('build/' + configFilename, '正在写出配置文件: %s', configPath);
|
|
105
105
|
await fs.writeFile(configPath, [prefix, json, ''].join('\n'));
|
|
106
106
|
return configPath;
|
|
107
107
|
};
|
package/lib/download.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import path from 'path';
|
|
2
2
|
import { fileURLToPath } from 'url';
|
|
3
3
|
import * as log from './log.js';
|
|
4
4
|
|
|
@@ -13,20 +13,20 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)),
|
|
|
13
13
|
|
|
14
14
|
// 看看上层目录结构,判断当前所处位置
|
|
15
15
|
const npmParentDirectory = path.join(scriptLocation, '../../../..');
|
|
16
|
-
log.verbose('
|
|
17
|
-
log.verbose('
|
|
16
|
+
log.verbose('nodejs-mobile-gyp 根目录', 'npm 上级目录为 ' + path.basename(npmParentDirectory));
|
|
17
|
+
log.verbose('nodejs-mobile-gyp 根目录', '正在查找 node 根目录');
|
|
18
18
|
let nodeRootDir = '';
|
|
19
19
|
if (path.basename(npmParentDirectory) === 'deps') {
|
|
20
20
|
// 处于构建目录中,脚本位于 deps/npm/node_modules/node-gyp/lib
|
|
21
21
|
nodeRootDir = path.join(npmParentDirectory, '..');
|
|
22
|
-
log.verbose('
|
|
22
|
+
log.verbose('nodejs-mobile-gyp 根目录', '在构建目录中,根目录 = ' + nodeRootDir);
|
|
23
23
|
} else if (path.basename(npmParentDirectory) === 'node_modules') {
|
|
24
24
|
// 处于 Node 安装目录中,脚本位于
|
|
25
25
|
// lib/node_modules/npm/node_modules/node-gyp/lib 或
|
|
26
26
|
// node_modules/npm/node_modules/node-gyp/lib(视平台而定)
|
|
27
27
|
if (processObj.platform === 'win32') nodeRootDir = path.join(npmParentDirectory, '..');
|
|
28
28
|
else nodeRootDir = path.join(npmParentDirectory, '../..');
|
|
29
|
-
log.verbose('
|
|
29
|
+
log.verbose('nodejs-mobile-gyp 根目录', '在安装目录中,根目录 = ' + nodeRootDir);
|
|
30
30
|
} else {
|
|
31
31
|
// 无法判断,尝试从 node 可执行文件的位置推断
|
|
32
32
|
const nodeDir = path.dirname(processObj.execPath), directoryUp = path.basename(nodeDir);
|