@flun/nodejs-mobile-gyp 1.1.3 → 1.2.0
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 +23 -26
- package/LICENSE +9 -4
- package/README.md +291 -229
- package/addon.gypi +1 -1
- package/bin/node-gyp.js +15 -6
- package/gyp/README.md +5 -3
- package/gyp/data/win/large-pdb-shim.cc +1 -1
- package/gyp/gyp +1 -1
- package/gyp/gyp.bat +1 -1
- package/gyp/gyp_main.py +1 -1
- package/gyp/pylib/gyp/MSVSNew.py +1 -1
- package/gyp/pylib/gyp/MSVSProject.py +1 -1
- package/gyp/pylib/gyp/MSVSSettings.py +1 -1
- package/gyp/pylib/gyp/MSVSToolFile.py +1 -1
- package/gyp/pylib/gyp/MSVSUserFile.py +1 -1
- package/gyp/pylib/gyp/MSVSUtil.py +1 -1
- package/gyp/pylib/gyp/MSVSVersion.py +1 -1
- package/gyp/pylib/gyp/__init__.py +1 -1
- package/gyp/pylib/gyp/common.py +1 -1
- package/gyp/pylib/gyp/easy_xml.py +1 -1
- package/gyp/pylib/gyp/flock_tool.py +1 -1
- package/gyp/pylib/gyp/generator/analyzer.py +1 -1
- package/gyp/pylib/gyp/generator/android.py +1 -1
- package/gyp/pylib/gyp/generator/cmake.py +1 -1
- package/gyp/pylib/gyp/generator/compile_commands_json.py +1 -1
- package/gyp/pylib/gyp/generator/dump_dependency_json.py +1 -1
- package/gyp/pylib/gyp/generator/eclipse.py +1 -1
- package/gyp/pylib/gyp/generator/gypd.py +1 -1
- package/gyp/pylib/gyp/generator/gypsh.py +1 -1
- package/gyp/pylib/gyp/generator/make.py +23 -12
- package/gyp/pylib/gyp/generator/msvs.py +3 -3
- package/gyp/pylib/gyp/generator/ninja.py +1 -1
- package/gyp/pylib/gyp/generator/xcode.py +1 -1
- package/gyp/pylib/gyp/input.py +1 -1
- package/gyp/pylib/gyp/mac_tool.py +1 -1
- package/gyp/pylib/gyp/msvs_emulation.py +1 -1
- package/gyp/pylib/gyp/ninja_syntax.py +1 -1
- package/gyp/pylib/gyp/simple_copy.py +1 -1
- package/gyp/pylib/gyp/win_tool.py +1 -1
- package/gyp/pylib/gyp/xcode_emulation.py +5 -5
- package/gyp/pylib/gyp/xcode_ninja.py +1 -1
- package/gyp/pylib/gyp/xcodeproj_file.py +1 -1
- package/gyp/pylib/gyp/xml_fix.py +1 -1
- package/gyp/pylib/packaging/LICENSE +1 -1
- package/gyp/pylib/packaging/LICENSE.APACHE +1 -1
- package/gyp/pylib/packaging/LICENSE.BSD +1 -1
- package/gyp/pylib/packaging/__init__.py +1 -1
- package/gyp/pylib/packaging/_elffile.py +1 -1
- package/gyp/pylib/packaging/_manylinux.py +1 -1
- package/gyp/pylib/packaging/_musllinux.py +1 -1
- package/gyp/pylib/packaging/_parser.py +1 -1
- package/gyp/pylib/packaging/_structures.py +1 -1
- package/gyp/pylib/packaging/_tokenizer.py +1 -1
- package/gyp/pylib/packaging/markers.py +1 -1
- package/gyp/pylib/packaging/metadata.py +1 -1
- package/gyp/pylib/packaging/requirements.py +1 -1
- package/gyp/pylib/packaging/specifiers.py +1 -1
- package/gyp/pylib/packaging/tags.py +1 -1
- package/gyp/pylib/packaging/utils.py +1 -1
- package/gyp/pylib/packaging/version.py +1 -1
- package/lib/Find-VisualStudio.cs +1 -1
- package/lib/build.js +17 -17
- package/lib/clean.js +3 -3
- package/lib/configure.js +21 -18
- package/lib/create-config-gypi.js +9 -9
- package/lib/download.js +4 -4
- package/lib/find-node-directory.js +10 -10
- package/lib/find-python.js +14 -14
- package/lib/find-visualstudio.js +20 -20
- package/lib/install.js +23 -22
- package/lib/list.js +2 -2
- package/lib/log.js +2 -2
- package/lib/node-gyp.js +37 -11
- package/lib/process-release.js +14 -14
- package/lib/rebuild.js +2 -2
- package/lib/remove.js +3 -3
- package/lib/util.js +72 -71
- package/package.json +3 -2
- package/src/win_delay_load_hook.cc +1 -1
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';
|
|
@@ -9,14 +9,14 @@ import fsSync from 'fs';
|
|
|
9
9
|
|
|
10
10
|
const fs = gracefulFs.promises,
|
|
11
11
|
_hostIsWindows = process.platform === 'win32',
|
|
12
|
-
// Android 交叉编译即使宿主是 Windows
|
|
12
|
+
// Android 交叉编译即使宿主是 Windows,也必须走 make(make-android 生成器)
|
|
13
13
|
_isAndroidCrossBuild = process.env.npm_config_platform === 'android' || process.env.npm_config_format === 'make-android',
|
|
14
|
-
// win 在此文件中语义为"使用 MSBuild"
|
|
14
|
+
// win 在此文件中语义为"使用 MSBuild":仅 Windows 宿主且非 Android 交叉编译
|
|
15
15
|
win = _hostIsWindows && !_isAndroidCrossBuild,
|
|
16
16
|
/**
|
|
17
17
|
* Windows 上 GNU make 需要 sh.exe 来执行 Makefile 里的 Unix 命令
|
|
18
|
-
*
|
|
19
|
-
* 避免要求用户额外安装 MSYS2
|
|
18
|
+
* (printf / xargs / rm 等);优先复用 Git for Windows 自带的 usr/bin,
|
|
19
|
+
* 避免要求用户额外安装 MSYS2;通过 "where git" 反推,不硬编码路径;
|
|
20
20
|
*/
|
|
21
21
|
findWindowsShellDir = () => {
|
|
22
22
|
if (process.platform !== 'win32') return null;
|
|
@@ -24,7 +24,7 @@ const fs = gracefulFs.promises,
|
|
|
24
24
|
try { return fsSync.existsSync(path.join(dir, 'sh.exe')) ? dir : null } catch { return null }
|
|
25
25
|
};
|
|
26
26
|
const toShDir = (gitRoot) => tryShDir(path.join(gitRoot, 'usr', 'bin'));
|
|
27
|
-
// 1)
|
|
27
|
+
// 1) 注册表:Git for Windows 安装时必写,与 PATH 无关(最可靠)
|
|
28
28
|
const reg = process.env.SystemRoot ? path.join(process.env.SystemRoot, 'System32', 'reg.exe') : 'reg.exe';
|
|
29
29
|
for (const hive of ['HKLM', 'HKCU']) {
|
|
30
30
|
for (const key of ['SOFTWARE\\GitForWindows', 'SOFTWARE\\WOW6432Node\\GitForWindows']) {
|
|
@@ -40,7 +40,7 @@ const fs = gracefulFs.promises,
|
|
|
40
40
|
} catch { }
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
-
// 2) which.sync
|
|
43
|
+
// 2) which.sync(PATH 中能找到 git 时可用)
|
|
44
44
|
try {
|
|
45
45
|
const gitPath = which.sync('git');
|
|
46
46
|
if (gitPath) {
|
|
@@ -49,7 +49,7 @@ const fs = gracefulFs.promises,
|
|
|
49
49
|
if (r) return r;
|
|
50
50
|
}
|
|
51
51
|
} catch { }
|
|
52
|
-
// 3) PATH 中找 git.exe
|
|
52
|
+
// 3) PATH 中找 git.exe,再反推 ../usr/bin
|
|
53
53
|
for (const pd of (process.env.PATH || '').split(';')) {
|
|
54
54
|
if (!pd) continue;
|
|
55
55
|
try {
|
|
@@ -97,11 +97,11 @@ const fs = gracefulFs.promises,
|
|
|
97
97
|
if (win && !verbose) argv.push('/clp:Verbosity=minimal');
|
|
98
98
|
if (win) argv.push('/nologo'); // Windows 上关闭 Microsoft logo
|
|
99
99
|
|
|
100
|
-
//
|
|
100
|
+
// 指定构建类型,默认 Release
|
|
101
101
|
if (win) {
|
|
102
102
|
// 把 .gypi 配置中的 target_arch 转换为 MSBuild 的 /Platform
|
|
103
|
-
// 因为表示"32 位 Intel"
|
|
104
|
-
//
|
|
103
|
+
// 因为表示"32 位 Intel"的方式很多,默认按此处理
|
|
104
|
+
// 注意:msbuild 的 Condition 字符串相等比较不区分大小写
|
|
105
105
|
const archLower = arch.toLowerCase(), p = archLower === 'x64' ? 'x64' : (archLower === 'arm' ? 'ARM'
|
|
106
106
|
: (archLower === 'arm64' ? 'ARM64' : 'Win32'));
|
|
107
107
|
argv.push('/p:Configuration=' + buildType + ';Platform=' + p)
|
|
@@ -122,13 +122,13 @@ const fs = gracefulFs.promises,
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
if (win) {
|
|
125
|
-
// 用户是否指定了自己的 .sln
|
|
125
|
+
// 用户是否指定了自己的 .sln 文件?
|
|
126
126
|
const hasSln = argv.some(arg => path.extname(arg) === '.sln');
|
|
127
127
|
if (!hasSln) argv.unshift(gyp.opts.solution || guessedSolution);
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
if (!win) {
|
|
131
|
-
//
|
|
131
|
+
// 把构建期依赖的符号链接(如 Python)加入 PATH
|
|
132
132
|
buildBinsDir = path.resolve('build', 'node_gyp_bins');
|
|
133
133
|
if (_hostIsWindows) {
|
|
134
134
|
const shellDir = findWindowsShellDir();
|
|
@@ -136,7 +136,7 @@ const fs = gracefulFs.promises,
|
|
|
136
136
|
process.env.PATH = `${shellDir};${process.env.PATH}`;
|
|
137
137
|
log.verbose('bin shell', `prepended ${shellDir} to PATH for make`);
|
|
138
138
|
} else {
|
|
139
|
-
log.warn('bin shell', 'no sh.exe found; GNU make 的 Unix
|
|
139
|
+
log.warn('bin shell', 'no sh.exe found; GNU make 的 Unix 命令可能失败;建议安装 Git for Windows');
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
process.env.PATH = _hostIsWindows
|
|
@@ -145,7 +145,7 @@ const fs = gracefulFs.promises,
|
|
|
145
145
|
await fs.mkdir(buildBinsDir, { recursive: true });
|
|
146
146
|
|
|
147
147
|
if (_hostIsWindows) {
|
|
148
|
-
// Windows 无 python3
|
|
148
|
+
// Windows 无 python3 名称,且创建符号链接需要管理员权限;改用 .cmd 桥接
|
|
149
149
|
const shimPath = path.join(buildBinsDir, 'python3.cmd');
|
|
150
150
|
await fs.writeFile(shimPath, `@echo off\r\n"${python}" %*\r\n`);
|
|
151
151
|
log.verbose('bin shims', `created python3.cmd shim to "${python}" and added to PATH`);
|
|
@@ -176,7 +176,7 @@ const fs = gracefulFs.promises,
|
|
|
176
176
|
doWhich = async () => {
|
|
177
177
|
// Windows 使用 node-gyp configure 提供的 msbuild
|
|
178
178
|
if (win) {
|
|
179
|
-
if (!config.variables.msbuild_path) throw new Error('MSBuild
|
|
179
|
+
if (!config.variables.msbuild_path) throw new Error('MSBuild 未设置,请先运行 `node-gyp configure`');
|
|
180
180
|
command = config.variables.msbuild_path, log.verbose('using MSBuild:', command), await doBuild();
|
|
181
181
|
return;
|
|
182
182
|
}
|
|
@@ -190,7 +190,7 @@ const fs = gracefulFs.promises,
|
|
|
190
190
|
*/
|
|
191
191
|
findSolutionFile = async () => {
|
|
192
192
|
const files = await glob('build/*.sln')
|
|
193
|
-
if (files.length === 0) throw new Error('未找到 *.sln
|
|
193
|
+
if (files.length === 0) throw new Error('未找到 *.sln 文件,是否运行过 configure?');
|
|
194
194
|
guessedSolution = files[0], log.verbose('found first Solution file', guessedSolution), await doWhich();
|
|
195
195
|
},
|
|
196
196
|
/**
|
package/lib/clean.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import gracefulFs from 'graceful-fs';
|
|
2
2
|
import * as log from './log.js';
|
|
3
3
|
|
|
4
4
|
const fs = gracefulFs.promises,
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* 清理:删除 build 目录
|
|
7
7
|
*/
|
|
8
8
|
clean = async (gyp, argv) => {
|
|
9
9
|
const buildDir = 'build';
|
|
@@ -13,4 +13,4 @@ const fs = gracefulFs.promises,
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
clean.usage = 'Removes any generated build files and the "out" dir';
|
|
16
|
-
export { clean };
|
|
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';
|
|
@@ -10,9 +10,10 @@ import { findAccessibleSync } from './util.js';
|
|
|
10
10
|
import { PythonFinder } from './find-python.js';
|
|
11
11
|
import { fileURLToPath } from 'url';
|
|
12
12
|
|
|
13
|
-
const fs = gracefulFs.promises, win = process.platform === 'win32',
|
|
13
|
+
const fs = gracefulFs.promises, win = process.platform === 'win32',
|
|
14
|
+
__dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
14
15
|
|
|
15
|
-
//
|
|
16
|
+
// 条件加载:仅在 Windows 上需要
|
|
16
17
|
let findVisualStudio = null, nodeDir, vsInfo = null;
|
|
17
18
|
if (win) {
|
|
18
19
|
const { VisualStudioFinder } = await import('./find-visualstudio.js');
|
|
@@ -20,7 +21,7 @@ if (win) {
|
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
|
-
*
|
|
24
|
+
* 生成构建文件(Makefile / MSVC 工程)
|
|
24
25
|
*/
|
|
25
26
|
const configure = async (gyp, argv) => {
|
|
26
27
|
const buildDir = path.resolve('build'), configNames = ['config.gypi', 'common.gypi'], configs = [],
|
|
@@ -40,7 +41,7 @@ const configure = async (gyp, argv) => {
|
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
configs.forEach(config => argv.push('-I', config)); // 引入所有找到的 .gypi 文件
|
|
43
|
-
// AIX 和 z/OS
|
|
44
|
+
// AIX 和 z/OS 需要设置导出文件路径,其中包含链接所需符号
|
|
44
45
|
let nodeExpFile, nodeRootDir, candidates, logprefix = 'find exports file';
|
|
45
46
|
if (process.platform === 'aix' || process.platform === 'os390' || process.platform === 'os400') {
|
|
46
47
|
const ext = process.platform === 'os390' ? 'x' : 'exp';
|
|
@@ -62,7 +63,7 @@ const configure = async (gyp, argv) => {
|
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
// z/OS 需要设置 zoslib
|
|
66
|
+
// z/OS 需要设置 zoslib 头文件目录,其中包含 v8config.h 引用的头文件
|
|
66
67
|
let zoslibIncDir;
|
|
67
68
|
if (process.platform === 'os390') {
|
|
68
69
|
logprefix = "find zoslib's zos-base.h:";
|
|
@@ -110,7 +111,8 @@ const configure = async (gyp, argv) => {
|
|
|
110
111
|
if (win) outputDir = buildDir; // Windows 需要绝对路径
|
|
111
112
|
const nodeGypDir = path.resolve(__dirname, '..');
|
|
112
113
|
|
|
113
|
-
let nodeLibFile = path.join(nodeDir,
|
|
114
|
+
let nodeLibFile = path.join(nodeDir,
|
|
115
|
+
!gyp.opts.nodedir ? '<(target_arch)' : '$(Configuration)', release.name + '.lib');
|
|
114
116
|
|
|
115
117
|
argv.push('-I', addonGypi), argv.push('-I', commonGypi), argv.push('-Dlibrary=shared_library');
|
|
116
118
|
argv.push('-Dvisibility=default'), argv.push('-Dnode_root_dir=' + nodeDir);
|
|
@@ -120,18 +122,18 @@ const configure = async (gyp, argv) => {
|
|
|
120
122
|
}
|
|
121
123
|
argv.push('-Dnode_gyp_dir=' + nodeGypDir);
|
|
122
124
|
|
|
123
|
-
// 这样做是为了让 Cygwin
|
|
124
|
-
//
|
|
125
|
+
// 这样做是为了让 Cygwin 环境正常工作,否则未转义的 '\' 会被吃掉,
|
|
126
|
+
// 导致路径错误,如 c:parentFolderfolderanotherFolder 而非 c:\parentFolder\folder\anotherFolder
|
|
125
127
|
if (win) nodeLibFile = nodeLibFile.replace(/\\/g, '\\\\');
|
|
126
128
|
argv.push('-Dnode_lib_file=' + nodeLibFile), argv.push('-Dmodule_root_dir=' + process.cwd());
|
|
127
129
|
argv.push('-Dnode_engine=' + (gyp.opts.node_engine || process.jsEngine || 'v8'));
|
|
128
130
|
argv.push('--depth=.'), argv.push('--no-parallel');
|
|
129
131
|
argv.push('--generator-output', outputDir); // 告诉 gyp 把 Makefile/Solution 文件写到 output_dir
|
|
130
|
-
// 使用 find-visualstudio 探测到的实际 toolset
|
|
131
|
-
//
|
|
132
|
+
// 使用 find-visualstudio 探测到的实际 toolset(v140/v141/v142/v143/v145...),
|
|
133
|
+
// 不再硬编码,以兼容 VS2013+ 各版本
|
|
132
134
|
if (win) {
|
|
133
135
|
if (vsInfo?.toolset) argv.push('-Gmsvs_toolset=' + vsInfo.toolset);
|
|
134
|
-
else log.warn('gyp', '未能探测到 VS toolset
|
|
136
|
+
else log.warn('gyp', '未能探测到 VS toolset,将使用 gyp 默认值');
|
|
135
137
|
}
|
|
136
138
|
|
|
137
139
|
argv.push('-Goutput_dir=.'); // 告诉 make 把输出写到同一目录
|
|
@@ -187,21 +189,22 @@ const configure = async (gyp, argv) => {
|
|
|
187
189
|
process.env.PYTHON = python;
|
|
188
190
|
|
|
189
191
|
if (gyp.opts.nodedir) {
|
|
190
|
-
// 指定了 --nodedir
|
|
192
|
+
// 指定了 --nodedir,用它作为开发文件目录
|
|
191
193
|
nodeDir = gyp.opts.nodedir.replace(/^~/, os.homedir());
|
|
192
194
|
log.verbose('get node dir', 'compiling against specified --nodedir dev files: %s', nodeDir);
|
|
193
195
|
} else {
|
|
194
|
-
// 未指定 --nodedir
|
|
196
|
+
// 未指定 --nodedir,先确保 Node 依赖已安装
|
|
195
197
|
if ('v' + release.version !== process.version) {
|
|
196
|
-
// 指定了 --target
|
|
198
|
+
// 指定了 --target,确定目标版本
|
|
197
199
|
log.verbose('get node dir', 'compiling against --target node version: %s', release.version);
|
|
198
200
|
} else {
|
|
199
|
-
// 未指定 --target
|
|
200
|
-
log.verbose('get node dir',
|
|
201
|
+
// 未指定 --target,使用当前主机 Node 版本
|
|
202
|
+
log.verbose('get node dir',
|
|
203
|
+
'no --target version specified, falling back to host node version: %s', release.version);
|
|
201
204
|
}
|
|
202
205
|
|
|
203
206
|
if (!release.semver) throw new Error('版本号无效: ' + release.version); // 无法用 semver 解析版本字符串
|
|
204
|
-
// 如果指定了 tarball
|
|
207
|
+
// 如果指定了 tarball 选项,总是删除并重装 headers 到 devdir,
|
|
205
208
|
// 否则只在不存在时安装
|
|
206
209
|
gyp.opts.ensure = !gyp.opts.tarball, await gyp.commands.install([release.version]);
|
|
207
210
|
log.verbose('get node dir', 'target node version installed:', release.versionDir);
|
|
@@ -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
|
|
|
@@ -16,7 +16,7 @@ const fs = gracefulFs.promises,
|
|
|
16
16
|
* 读取基础 config.gypi
|
|
17
17
|
*/
|
|
18
18
|
getBaseConfigGypi = async ({ gyp, nodeDir }) => {
|
|
19
|
-
// 在以下情况优先读取 $nodeDir/include/node/config.gypi
|
|
19
|
+
// 在以下情况优先读取 $nodeDir/include/node/config.gypi:
|
|
20
20
|
// 1. 指定了 --dist-url 或 --nodedir
|
|
21
21
|
// 2. 且没有指定 --force-process-config
|
|
22
22
|
const useCustomHeaders = gyp.opts.nodedir || gyp.opts.disturl || gyp.opts['dist-url'],
|
|
@@ -40,8 +40,8 @@ const fs = gracefulFs.promises,
|
|
|
40
40
|
if (!config.variables) config.variables = {};
|
|
41
41
|
|
|
42
42
|
const defaults = config.target_defaults, variables = config.variables;
|
|
43
|
-
// 不要继承 base config.gypi 的 defaults
|
|
44
|
-
// 否则当 node
|
|
43
|
+
// 不要继承 base config.gypi 的 defaults,
|
|
44
|
+
// 否则当 node 可执行文件在另一台机器编译(lib/include 路径不同)时会出问题
|
|
45
45
|
defaults.cflags = [], defaults.defines = [], defaults.include_dirs = [], defaults.libraries = [];
|
|
46
46
|
|
|
47
47
|
// 设置 default_configuration
|
|
@@ -66,14 +66,14 @@ const fs = gracefulFs.promises,
|
|
|
66
66
|
else log.warn('仅 Visual Studio 2017 15.9 及以上版本支持编译 ARM64 汇编');
|
|
67
67
|
}
|
|
68
68
|
variables.msbuild_path = vsInfo.msBuild;
|
|
69
|
-
// Windows 原生构建走 MSVC
|
|
70
|
-
// 否则 common.gypi 会把 toolset 设为 ClangCL
|
|
71
|
-
//
|
|
69
|
+
// Windows 原生构建走 MSVC 工具集:必须关闭 clang 与 LTO,
|
|
70
|
+
// 否则 common.gypi 会把 toolset 设为 ClangCL,并向 MSVC 链接器传入 Clang 专用参数
|
|
71
|
+
// (-flto=thin、/opt:lldltojobs),导致 MSB8020 或 LNK1117
|
|
72
72
|
if (!gyp.opts.format || gyp.opts.format === 'msvs')
|
|
73
73
|
variables.clang = 0, variables.enable_lto = 'false', variables.enable_thin_lto = 'false', variables.lto_jobs = '';
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
//
|
|
76
|
+
// 把其余未知选项当作变量写入,支持模块自定义 configure 参数,例如:
|
|
77
77
|
// $ node-gyp configure --shared-libxml2
|
|
78
78
|
for (const [k, v] of Object.entries(gyp.opts)) {
|
|
79
79
|
if (k === 'argv' || k in gyp.configDefs) continue;
|
|
@@ -106,4 +106,4 @@ const fs = gracefulFs.promises,
|
|
|
106
106
|
return configPath;
|
|
107
107
|
};
|
|
108
108
|
|
|
109
|
-
export { createConfigGypi, parseConfigGypi, getCurrentConfigGypi }
|
|
109
|
+
export { createConfigGypi, parseConfigGypi, getCurrentConfigGypi }
|
package/lib/download.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
import fetch from 'make-fetch-happen';
|
|
2
2
|
import gracefulFs from 'graceful-fs';
|
|
3
3
|
import * as log from './log.js';
|
|
4
4
|
|
|
5
5
|
const { promises: fs } = gracefulFs,
|
|
6
6
|
/**
|
|
7
|
-
* 读取 CA
|
|
7
|
+
* 读取 CA 证书文件,按证书边界切分为多个证书
|
|
8
8
|
*/
|
|
9
9
|
readCAFile = async filename => {
|
|
10
|
-
// CA
|
|
10
|
+
// CA 文件可能包含多份证书,按证书边界切分; [\S\s]*? 用于匹配包括换行在内的所有内容;
|
|
11
11
|
const ca = await fs.readFile(filename, 'utf8'), re = /(-----BEGIN CERTIFICATE-----[\S\s]*?-----END CERTIFICATE-----)/g;
|
|
12
12
|
return ca.match(re);
|
|
13
13
|
},
|
|
@@ -28,4 +28,4 @@ const { promises: fs } = gracefulFs,
|
|
|
28
28
|
return res;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
export { readCAFile, download }
|
|
31
|
+
export { readCAFile, download }
|
|
@@ -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
|
|
|
@@ -7,33 +7,33 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)),
|
|
|
7
7
|
* 从脚本位置或进程对象推断 Node 根目录
|
|
8
8
|
*/
|
|
9
9
|
findNodeDirectory = (scriptLocation, processObj) => {
|
|
10
|
-
//
|
|
10
|
+
// 未传入时使用默认值,便于回归测试
|
|
11
11
|
if (scriptLocation === undefined) scriptLocation = __dirname;
|
|
12
12
|
if (processObj === undefined) processObj = process;
|
|
13
13
|
|
|
14
|
-
//
|
|
14
|
+
// 看看上层目录结构,判断当前所处位置
|
|
15
15
|
const npmParentDirectory = path.join(scriptLocation, '../../../..');
|
|
16
16
|
log.verbose('node-gyp root', 'npm_parent_directory is ' + path.basename(npmParentDirectory));
|
|
17
17
|
log.verbose('node-gyp root', 'Finding node root directory');
|
|
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
22
|
log.verbose('node-gyp root', 'in build directory, root = ' + nodeRootDir);
|
|
23
23
|
} else if (path.basename(npmParentDirectory) === 'node_modules') {
|
|
24
|
-
// 处于 Node
|
|
24
|
+
// 处于 Node 安装目录中,脚本位于
|
|
25
25
|
// lib/node_modules/npm/node_modules/node-gyp/lib 或
|
|
26
|
-
// node_modules/npm/node_modules/node-gyp/lib
|
|
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
29
|
log.verbose('node-gyp root', 'in install directory, root = ' + nodeRootDir);
|
|
30
30
|
} else {
|
|
31
|
-
//
|
|
31
|
+
// 无法判断,尝试从 node 可执行文件的位置推断
|
|
32
32
|
const nodeDir = path.dirname(processObj.execPath), directoryUp = path.basename(nodeDir);
|
|
33
33
|
if (directoryUp === 'bin') nodeRootDir = path.join(nodeDir, '..');
|
|
34
34
|
else if (directoryUp === 'Release' || directoryUp === 'Debug') {
|
|
35
|
-
// 如果是刚构建的 node
|
|
36
|
-
// Windows
|
|
35
|
+
// 如果是刚构建的 node,且目录结构为仓库结构:
|
|
36
|
+
// Windows 只需上一层,其余平台两层
|
|
37
37
|
if (processObj.platform === 'win32') nodeRootDir = path.join(nodeDir, '..');
|
|
38
38
|
else nodeRootDir = path.join(nodeDir, '../..');
|
|
39
39
|
}
|
|
@@ -42,4 +42,4 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)),
|
|
|
42
42
|
return nodeRootDir;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
export { findNodeDirectory }
|
|
45
|
+
export { findNodeDirectory }
|
package/lib/find-python.js
CHANGED
|
@@ -6,7 +6,7 @@ import fs from 'fs';
|
|
|
6
6
|
|
|
7
7
|
const win = process.platform === 'win32',
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
9
|
+
* 获取当前操作系统用户名(失败时返回 undefined)
|
|
10
10
|
*/
|
|
11
11
|
getOsUserInfo = () => {
|
|
12
12
|
try { return os.userInfo().username } catch { }
|
|
@@ -19,8 +19,8 @@ const win = process.platform === 'win32',
|
|
|
19
19
|
programFilesX86 = process.env['ProgramFiles(x86)'] || `${programFiles} (x86)`,
|
|
20
20
|
systemRoot = process.env.SystemRoot || `${systemDrive}\\Windows`,
|
|
21
21
|
/**
|
|
22
|
-
* 动态扫描 Windows 上所有已安装的 Python
|
|
23
|
-
*
|
|
22
|
+
* 动态扫描 Windows 上所有已安装的 Python,不硬编码版本号;
|
|
23
|
+
* 官方安装器目录命名:3.14 -> Python314,3.9 -> Python39,32 位加 -32 后缀;
|
|
24
24
|
*/
|
|
25
25
|
scanWindowsPythonLocations = () => {
|
|
26
26
|
const results = [], bases = [foundLocalAppData ? `${localAppData}\\Programs\\Python` : null, `${programFiles}\\Python`,
|
|
@@ -40,13 +40,13 @@ const win = process.platform === 'win32',
|
|
|
40
40
|
return results;
|
|
41
41
|
},
|
|
42
42
|
/**
|
|
43
|
-
* py.exe
|
|
44
|
-
* 避免 Gradle / CI 环境下 PATH 不含 C:\Windows
|
|
43
|
+
* py.exe 启动器候选:先试 PATH 中的,再试常见绝对路径,
|
|
44
|
+
* 避免 Gradle / CI 环境下 PATH 不含 C:\Windows 的情况;
|
|
45
45
|
*/
|
|
46
46
|
pyLauncherCandidates = win ? ['py.exe', `${systemRoot}\\py.exe`, `${systemRoot}\\System32\\py.exe`] : [];
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
|
-
* Python
|
|
49
|
+
* Python 查找器:按顺序尝试多种途径定位可用的 Python 3.6+
|
|
50
50
|
*/
|
|
51
51
|
class PythonFinder {
|
|
52
52
|
static findPython = (...args) => new PythonFinder(...args).findPython();
|
|
@@ -66,12 +66,12 @@ class PythonFinder {
|
|
|
66
66
|
this.configPython = configPython, this.errorLog = [];
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
// 以 verbose
|
|
69
|
+
// 以 verbose 级别记录日志,同时保存下来,出错时以 error 级别展示,便于诊断
|
|
70
70
|
addLog(message) {
|
|
71
71
|
this.log.verbose(message), this.errorLog.push(message);
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
// 依次尝试多种 Python
|
|
74
|
+
// 依次尝试多种 Python 定位方式;忽略错误,直到找到可用版本
|
|
75
75
|
async findPython() {
|
|
76
76
|
const SKIP = 0, FAIL = 1,
|
|
77
77
|
toCheck = (() => {
|
|
@@ -158,7 +158,7 @@ class PythonFinder {
|
|
|
158
158
|
return this.fail();
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
-
// 检查命令是否为可用的 Python
|
|
161
|
+
// 检查命令是否为可用的 Python;
|
|
162
162
|
async checkCommand(command) {
|
|
163
163
|
this.log.verbose(`- executing "${command}" to get executable path`);
|
|
164
164
|
try {
|
|
@@ -171,7 +171,7 @@ class PythonFinder {
|
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
// 检查指定 py 启动器是否能找到 Python 3
|
|
174
|
+
// 检查指定 py 启动器是否能找到 Python 3;
|
|
175
175
|
async checkPyLauncher(launcher = this.pyLauncher) {
|
|
176
176
|
this.log.verbose(`- executing "${launcher}" to get Python 3 executable path`);
|
|
177
177
|
try {
|
|
@@ -184,7 +184,7 @@ class PythonFinder {
|
|
|
184
184
|
}
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
-
// 通过 "py -0p" 枚举所有已注册的 Python
|
|
187
|
+
// 通过 "py -0p" 枚举所有已注册的 Python,覆盖非标准安装位置;
|
|
188
188
|
async checkPyList() {
|
|
189
189
|
this.log.verbose('- executing "py -0p" to list registered Pythons');
|
|
190
190
|
let lastErr;
|
|
@@ -213,7 +213,7 @@ class PythonFinder {
|
|
|
213
213
|
throw lastErr || new Error('py -0p returned no usable Python');
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
// 检查某个 Python
|
|
216
|
+
// 检查某个 Python 可执行文件版本是否可用;
|
|
217
217
|
async checkExecPath(execPath) {
|
|
218
218
|
this.log.verbose(`- executing "${execPath}" to get version`);
|
|
219
219
|
try {
|
|
@@ -242,8 +242,8 @@ class PythonFinder {
|
|
|
242
242
|
}
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
-
//
|
|
246
|
-
// 必须显式检查 err
|
|
245
|
+
// 执行外部命令;execFile 包装不 reject,通过 [err, stdout, stderr] 返回结果,
|
|
246
|
+
// 必须显式检查 err,否则失败会被当成"成功但空输出",掩盖真实原因;
|
|
247
247
|
async run(exec, args, shell) {
|
|
248
248
|
const env = Object.assign({}, this.env), opts = { env, shell };
|
|
249
249
|
env.TERM = 'dumb';
|
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';
|
|
@@ -6,7 +6,7 @@ import { regSearchKeys, execFile } from './util.js';
|
|
|
6
6
|
|
|
7
7
|
const path = nodePath.win32, __dirname = nodePath.dirname(fileURLToPath(import.meta.url));
|
|
8
8
|
/**
|
|
9
|
-
* Visual Studio
|
|
9
|
+
* Visual Studio 查找器:定位可用的 VS 安装
|
|
10
10
|
*/
|
|
11
11
|
class VisualStudioFinder {
|
|
12
12
|
static findVisualStudio = (...args) => new VisualStudioFinder(...args).findVisualStudio();
|
|
@@ -17,7 +17,7 @@ class VisualStudioFinder {
|
|
|
17
17
|
this.nodeSemver = nodeSemver, this.configMsvsVersion = configMsvsVersion, this.errorLog = [], this.validVersions = [];
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
// 以 verbose
|
|
20
|
+
// 以 verbose 级别记录日志,同时保存下来,出错时以 error 级别展示,便于诊断
|
|
21
21
|
addLog(message) {
|
|
22
22
|
this.log.verbose(message), this.errorLog.push(message);
|
|
23
23
|
}
|
|
@@ -66,7 +66,7 @@ class VisualStudioFinder {
|
|
|
66
66
|
this.errorLog.push(
|
|
67
67
|
'msvs_version does not match this VS Command Prompt or the', 'installation cannot be used.');
|
|
68
68
|
else if (this.configMsvsVersion) {
|
|
69
|
-
// 指定了 msvs_version 但没找到 VS
|
|
69
|
+
// 指定了 msvs_version 但没找到 VS,输出可接受的版本
|
|
70
70
|
this.errorLog.push('');
|
|
71
71
|
if (this.validVersions) {
|
|
72
72
|
this.errorLog.push('valid versions for msvs_version:');
|
|
@@ -76,7 +76,7 @@ class VisualStudioFinder {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
const errorLog = this.errorLog.join('\n'),
|
|
79
|
-
// Windows 80
|
|
79
|
+
// Windows 80 列控制台,用到 X 标记列之前(含日志前缀共 79 字符,可用 62 字符):
|
|
80
80
|
infoLog = [
|
|
81
81
|
'**************************************************************',
|
|
82
82
|
'You need to install the latest version of Visual Studio',
|
|
@@ -90,7 +90,7 @@ class VisualStudioFinder {
|
|
|
90
90
|
throw new Error('未找到可用的 Visual Studio 安装');
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
// 调用 PowerShell
|
|
93
|
+
// 调用 PowerShell 脚本,获取 Visual Studio 2017 或更新版本的信息
|
|
94
94
|
async findVisualStudio2017OrNewer() {
|
|
95
95
|
const ps = path.join(process.env.SystemRoot, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe'),
|
|
96
96
|
csFile = path.join(__dirname, 'Find-VisualStudio.cs'),
|
|
@@ -102,7 +102,7 @@ class VisualStudioFinder {
|
|
|
102
102
|
return this.parseData(err, stdout, stderr);
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
// 解析 PowerShell
|
|
105
|
+
// 解析 PowerShell 脚本输出,寻找可用的 Visual Studio 2017 或更新版本
|
|
106
106
|
parseData(err, stdout, stderr) {
|
|
107
107
|
this.log.silly('PS stderr = %j', stderr)
|
|
108
108
|
|
|
@@ -149,7 +149,7 @@ class VisualStudioFinder {
|
|
|
149
149
|
return false;
|
|
150
150
|
})
|
|
151
151
|
|
|
152
|
-
//
|
|
152
|
+
// 排序:新版本在前
|
|
153
153
|
vsInfo.sort((a, b) => b.versionYear - a.versionYear)
|
|
154
154
|
|
|
155
155
|
for (let i = 0; i < vsInfo.length; ++i) {
|
|
@@ -182,7 +182,7 @@ class VisualStudioFinder {
|
|
|
182
182
|
return null;
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
//
|
|
185
|
+
// 辅助:解析版本信息
|
|
186
186
|
getVersionInfo(info) {
|
|
187
187
|
const match = /^(\d+)\.(\d+)\./.exec(info.version);
|
|
188
188
|
if (!match) {
|
|
@@ -206,7 +206,7 @@ class VisualStudioFinder {
|
|
|
206
206
|
return existsSync(path);
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
-
//
|
|
209
|
+
// 辅助:解析 MSBuild 信息
|
|
210
210
|
getMSBuild(info, versionYear) {
|
|
211
211
|
const pkg = 'Microsoft.VisualStudio.VC.MSBuild.Base',
|
|
212
212
|
msbuildPath = path.join(info.path, 'MSBuild', 'Current', 'Bin', 'MSBuild.exe'),
|
|
@@ -217,16 +217,16 @@ class VisualStudioFinder {
|
|
|
217
217
|
if (versionYear === 2019) return msbuildPath;
|
|
218
218
|
}
|
|
219
219
|
/**
|
|
220
|
-
* Visual Studio 2022 没有 MSBuild
|
|
221
|
-
* ARM64 上编译的支持从 MSVC 14.32.31326
|
|
222
|
-
* 因此用户设备是 ARM64
|
|
220
|
+
* Visual Studio 2022 没有 MSBuild 包;
|
|
221
|
+
* ARM64 上编译的支持从 MSVC 14.32.31326 起加入,
|
|
222
|
+
* 因此用户设备是 ARM64 时优先使用它;
|
|
223
223
|
*/
|
|
224
224
|
if (process.arch === 'arm64' && this.msBuildPathExists(msbuildPathArm64)) return msbuildPathArm64;
|
|
225
225
|
else if (this.msBuildPathExists(msbuildPath)) return msbuildPath;
|
|
226
226
|
return null;
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
-
//
|
|
229
|
+
// 辅助:解析 toolset 信息
|
|
230
230
|
getToolset(info, versionYear) {
|
|
231
231
|
const pkg = 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', express = 'Microsoft.VisualStudio.WDExpress';
|
|
232
232
|
if (info.packages.indexOf(pkg) !== -1) this.log.silly('- found VC.Tools.x86.x64');
|
|
@@ -241,7 +241,7 @@ class VisualStudioFinder {
|
|
|
241
241
|
return null;
|
|
242
242
|
}
|
|
243
243
|
|
|
244
|
-
//
|
|
244
|
+
// 辅助:解析 Windows SDK 信息
|
|
245
245
|
getSDK(info) {
|
|
246
246
|
const win8SDK = 'Microsoft.VisualStudio.Component.Windows81SDK',
|
|
247
247
|
win10SDKPrefix = 'Microsoft.VisualStudio.Component.Windows10SDK.',
|
|
@@ -291,7 +291,7 @@ class VisualStudioFinder {
|
|
|
291
291
|
return this.findOldVS({ version: '12.0', versionMajor: 12, versionMinor: 0, versionYear: 2013, toolset: 'v120' });
|
|
292
292
|
}
|
|
293
293
|
|
|
294
|
-
//
|
|
294
|
+
// 辅助:VS2013 和 VS2015 的公共代码
|
|
295
295
|
async findOldVS(info) {
|
|
296
296
|
const regVC7 = ['HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7',
|
|
297
297
|
'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7'],
|
|
@@ -322,10 +322,10 @@ class VisualStudioFinder {
|
|
|
322
322
|
}
|
|
323
323
|
}
|
|
324
324
|
|
|
325
|
-
// 找到可用的 Visual Studio
|
|
326
|
-
// - 把它加入 validVersions
|
|
327
|
-
// -
|
|
328
|
-
// - 检查是否匹配 Visual Studio
|
|
325
|
+
// 找到可用的 Visual Studio 后:
|
|
326
|
+
// - 把它加入 validVersions,用于在指定版本未找到时输出;
|
|
327
|
+
// - 检查是否是请求的版本;
|
|
328
|
+
// - 检查是否匹配 Visual Studio 命令提示符;
|
|
329
329
|
checkConfigVersion(versionYear, vsPath) {
|
|
330
330
|
this.validVersions.push(versionYear), this.validVersions.push(vsPath);
|
|
331
331
|
|