@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.
- package/CHANGELOG.md +36 -0
- package/LICENSE +29 -0
- package/README.md +252 -0
- package/addon.gypi +209 -0
- package/bin/node-gyp.js +144 -0
- package/gyp/LICENSE +28 -0
- package/gyp/README.md +30 -0
- package/gyp/data/win/large-pdb-shim.cc +12 -0
- package/gyp/gyp +8 -0
- package/gyp/gyp.bat +5 -0
- package/gyp/gyp_main.py +45 -0
- package/gyp/pylib/gyp/MSVSNew.py +365 -0
- package/gyp/pylib/gyp/MSVSProject.py +206 -0
- package/gyp/pylib/gyp/MSVSSettings.py +1270 -0
- package/gyp/pylib/gyp/MSVSToolFile.py +59 -0
- package/gyp/pylib/gyp/MSVSUserFile.py +153 -0
- package/gyp/pylib/gyp/MSVSUtil.py +271 -0
- package/gyp/pylib/gyp/MSVSVersion.py +574 -0
- package/gyp/pylib/gyp/__init__.py +692 -0
- package/gyp/pylib/gyp/common.py +654 -0
- package/gyp/pylib/gyp/easy_xml.py +169 -0
- package/gyp/pylib/gyp/flock_tool.py +55 -0
- package/gyp/pylib/gyp/generator/__init__.py +0 -0
- package/gyp/pylib/gyp/generator/analyzer.py +804 -0
- package/gyp/pylib/gyp/generator/android.py +1173 -0
- package/gyp/pylib/gyp/generator/cmake.py +1318 -0
- package/gyp/pylib/gyp/generator/compile_commands_json.py +123 -0
- package/gyp/pylib/gyp/generator/dump_dependency_json.py +103 -0
- package/gyp/pylib/gyp/generator/eclipse.py +461 -0
- package/gyp/pylib/gyp/generator/gypd.py +89 -0
- package/gyp/pylib/gyp/generator/gypsh.py +58 -0
- package/gyp/pylib/gyp/generator/make.py +2710 -0
- package/gyp/pylib/gyp/generator/msvs.py +3981 -0
- package/gyp/pylib/gyp/generator/ninja.py +2933 -0
- package/gyp/pylib/gyp/generator/xcode.py +1397 -0
- package/gyp/pylib/gyp/input.py +3115 -0
- package/gyp/pylib/gyp/mac_tool.py +771 -0
- package/gyp/pylib/gyp/msvs_emulation.py +1262 -0
- package/gyp/pylib/gyp/ninja_syntax.py +174 -0
- package/gyp/pylib/gyp/simple_copy.py +61 -0
- package/gyp/pylib/gyp/win_tool.py +373 -0
- package/gyp/pylib/gyp/xcode_emulation.py +1935 -0
- package/gyp/pylib/gyp/xcode_ninja.py +302 -0
- package/gyp/pylib/gyp/xcodeproj_file.py +3198 -0
- package/gyp/pylib/gyp/xml_fix.py +65 -0
- package/gyp/pylib/packaging/LICENSE +3 -0
- package/gyp/pylib/packaging/LICENSE.APACHE +177 -0
- package/gyp/pylib/packaging/LICENSE.BSD +23 -0
- package/gyp/pylib/packaging/__init__.py +15 -0
- package/gyp/pylib/packaging/_elffile.py +108 -0
- package/gyp/pylib/packaging/_manylinux.py +252 -0
- package/gyp/pylib/packaging/_musllinux.py +83 -0
- package/gyp/pylib/packaging/_parser.py +359 -0
- package/gyp/pylib/packaging/_structures.py +61 -0
- package/gyp/pylib/packaging/_tokenizer.py +192 -0
- package/gyp/pylib/packaging/markers.py +252 -0
- package/gyp/pylib/packaging/metadata.py +825 -0
- package/gyp/pylib/packaging/py.typed +0 -0
- package/gyp/pylib/packaging/requirements.py +90 -0
- package/gyp/pylib/packaging/specifiers.py +1030 -0
- package/gyp/pylib/packaging/tags.py +553 -0
- package/gyp/pylib/packaging/utils.py +172 -0
- package/gyp/pylib/packaging/version.py +563 -0
- package/lib/Find-VisualStudio.cs +250 -0
- package/lib/build.js +221 -0
- package/lib/clean.js +19 -0
- package/lib/configure.js +295 -0
- package/lib/create-config-gypi.js +163 -0
- package/lib/download.js +44 -0
- package/lib/find-node-directory.js +62 -0
- package/lib/find-python.js +303 -0
- package/lib/find-visualstudio.js +448 -0
- package/lib/install.js +419 -0
- package/lib/list.js +30 -0
- package/lib/log.js +174 -0
- package/lib/node-gyp.js +201 -0
- package/lib/process-release.js +144 -0
- package/lib/rebuild.js +14 -0
- package/lib/remove.js +47 -0
- package/lib/util.js +83 -0
- package/package.json +72 -0
- package/src/win_delay_load_hook.cc +39 -0
package/lib/node-gyp.js
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import nopt from 'nopt'
|
|
3
|
+
import * as log from './log.js'
|
|
4
|
+
import childProcess from 'child_process'
|
|
5
|
+
import { EventEmitter } from 'events'
|
|
6
|
+
import { readFileSync } from 'fs'
|
|
7
|
+
import { fileURLToPath } from 'url'
|
|
8
|
+
|
|
9
|
+
import { build } from './build.js'
|
|
10
|
+
import { clean } from './clean.js'
|
|
11
|
+
import { configure } from './configure.js'
|
|
12
|
+
import { rebuild } from './rebuild.js'
|
|
13
|
+
import { install } from './install.js'
|
|
14
|
+
import { list } from './list.js'
|
|
15
|
+
import { remove } from './remove.js'
|
|
16
|
+
|
|
17
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
18
|
+
|
|
19
|
+
// 命令名到实现函数的静态映射(ESM 不支持动态 require)
|
|
20
|
+
const commandModules = {
|
|
21
|
+
build,
|
|
22
|
+
clean,
|
|
23
|
+
configure,
|
|
24
|
+
rebuild,
|
|
25
|
+
install,
|
|
26
|
+
list,
|
|
27
|
+
remove
|
|
28
|
+
}
|
|
29
|
+
const commands = Object.keys(commandModules)
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* node-gyp 主类:解析参数、分发命令、生成 usage
|
|
33
|
+
*/
|
|
34
|
+
class Gyp extends EventEmitter {
|
|
35
|
+
/**
|
|
36
|
+
* 导出 package.json 内容
|
|
37
|
+
*/
|
|
38
|
+
package = JSON.parse(readFileSync(path.resolve(__dirname, '../package.json'), 'utf8'))
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* nopt 配置定义
|
|
42
|
+
*/
|
|
43
|
+
configDefs = {
|
|
44
|
+
help: Boolean, // 各处
|
|
45
|
+
arch: String, // 'configure'
|
|
46
|
+
cafile: String, // 'install'
|
|
47
|
+
debug: Boolean, // 'build'
|
|
48
|
+
directory: String, // bin
|
|
49
|
+
make: String, // 'build'
|
|
50
|
+
'msvs-version': String, // 'configure'
|
|
51
|
+
ensure: Boolean, // 'install'
|
|
52
|
+
solution: String, // 'build'(仅 Windows)
|
|
53
|
+
proxy: String, // 'install'
|
|
54
|
+
noproxy: String, // 'install'
|
|
55
|
+
devdir: String, // 各处
|
|
56
|
+
nodedir: String, // 'configure'
|
|
57
|
+
loglevel: String, // 各处
|
|
58
|
+
python: String, // 'configure'
|
|
59
|
+
'dist-url': String, // 'install'
|
|
60
|
+
tarball: String, // 'install'
|
|
61
|
+
jobs: String, // 'build'
|
|
62
|
+
thin: String, // 'configure'
|
|
63
|
+
'force-process-config': Boolean // 'configure'
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* nopt 简写
|
|
68
|
+
*/
|
|
69
|
+
shorthands = {
|
|
70
|
+
release: '--no-debug',
|
|
71
|
+
C: '--directory',
|
|
72
|
+
debug: '--debug',
|
|
73
|
+
j: '--jobs',
|
|
74
|
+
silly: '--loglevel=silly',
|
|
75
|
+
verbose: '--loglevel=verbose',
|
|
76
|
+
silent: '--loglevel=silent'
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 暴露命令别名供 bin 文件使用
|
|
81
|
+
*/
|
|
82
|
+
aliases = {
|
|
83
|
+
ls: 'list',
|
|
84
|
+
rm: 'remove'
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
constructor (...args) {
|
|
88
|
+
super(...args)
|
|
89
|
+
|
|
90
|
+
this.devDir = ''
|
|
91
|
+
|
|
92
|
+
this.commands = commands.reduce((acc, command) => {
|
|
93
|
+
acc[command] = (argv) => commandModules[command](this, argv)
|
|
94
|
+
return acc
|
|
95
|
+
}, {})
|
|
96
|
+
|
|
97
|
+
Object.defineProperty(this, 'version', {
|
|
98
|
+
enumerable: true,
|
|
99
|
+
get: function () { return this.package.version }
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* 解析传入的 argv 数组,设置 'opts'、'argv' 和 'command' 属性
|
|
105
|
+
*/
|
|
106
|
+
parseArgv (argv) {
|
|
107
|
+
this.opts = nopt(this.configDefs, this.shorthands, argv)
|
|
108
|
+
this.argv = this.opts.argv.remain.slice()
|
|
109
|
+
|
|
110
|
+
const commands = this.todo = []
|
|
111
|
+
|
|
112
|
+
// 创建一份把别名映射后的 argv 副本
|
|
113
|
+
argv = this.argv.map((arg) => {
|
|
114
|
+
// 是别名吗?
|
|
115
|
+
if (arg in this.aliases) {
|
|
116
|
+
arg = this.aliases[arg]
|
|
117
|
+
}
|
|
118
|
+
return arg
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
// 把映射后的参数处理成 "command" 对象(name 和 args 属性)
|
|
122
|
+
argv.slice().forEach((arg) => {
|
|
123
|
+
if (arg in this.commands) {
|
|
124
|
+
const args = argv.splice(0, argv.indexOf(arg))
|
|
125
|
+
argv.shift()
|
|
126
|
+
if (commands.length > 0) {
|
|
127
|
+
commands[commands.length - 1].args = args
|
|
128
|
+
}
|
|
129
|
+
commands.push({ name: arg, args: [] })
|
|
130
|
+
}
|
|
131
|
+
})
|
|
132
|
+
if (commands.length > 0) {
|
|
133
|
+
commands[commands.length - 1].args = argv.splice(0)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// 支持从 npm 继承配置环境变量
|
|
137
|
+
const npmConfigPrefix = 'npm_config_'
|
|
138
|
+
Object.keys(process.env).forEach((name) => {
|
|
139
|
+
if (name.indexOf(npmConfigPrefix) !== 0) {
|
|
140
|
+
return
|
|
141
|
+
}
|
|
142
|
+
const val = process.env[name]
|
|
143
|
+
if (name === npmConfigPrefix + 'loglevel') {
|
|
144
|
+
log.logger.level = val
|
|
145
|
+
} else {
|
|
146
|
+
// 把用户定义的选项加入配置
|
|
147
|
+
name = name.substring(npmConfigPrefix.length)
|
|
148
|
+
// gyp@741b7f1 遇到零长度选项会死循环,确保过滤掉
|
|
149
|
+
if (name) {
|
|
150
|
+
// 把 force_process_config 这类名字转成 force-process-config
|
|
151
|
+
if (name.includes('_')) {
|
|
152
|
+
name = name.replace(/_/g, '-')
|
|
153
|
+
}
|
|
154
|
+
this.opts[name] = val
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
if (this.opts.loglevel) {
|
|
160
|
+
log.logger.level = this.opts.loglevel
|
|
161
|
+
}
|
|
162
|
+
log.resume()
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* 启动子进程并发出 'spawn' 事件
|
|
167
|
+
*/
|
|
168
|
+
spawn (command, args, opts) {
|
|
169
|
+
if (!opts) {
|
|
170
|
+
opts = {}
|
|
171
|
+
}
|
|
172
|
+
if (!opts.silent && !opts.stdio) {
|
|
173
|
+
opts.stdio = [0, 1, 2]
|
|
174
|
+
}
|
|
175
|
+
const cp = childProcess.spawn(command, args, opts)
|
|
176
|
+
log.info('spawn', command)
|
|
177
|
+
log.info('spawn args', args)
|
|
178
|
+
return cp
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* 返回 node-gyp 的用法说明
|
|
183
|
+
*/
|
|
184
|
+
usage () {
|
|
185
|
+
return [
|
|
186
|
+
'',
|
|
187
|
+
' Usage: node-gyp <command> [options]',
|
|
188
|
+
'',
|
|
189
|
+
' where <command> is one of:',
|
|
190
|
+
commands.map((c) => ' - ' + c + ' - ' + commandModules[c].usage).join('\n'),
|
|
191
|
+
'',
|
|
192
|
+
'node-gyp@' + this.version + ' ' + path.resolve(__dirname, '..'),
|
|
193
|
+
'node@' + process.versions.node
|
|
194
|
+
].join('\n')
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const createGyp = () => new Gyp()
|
|
199
|
+
|
|
200
|
+
export default createGyp
|
|
201
|
+
export { Gyp }
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/* eslint-disable n/no-deprecated-api */
|
|
2
|
+
|
|
3
|
+
import semver from 'semver'
|
|
4
|
+
import url from 'url'
|
|
5
|
+
import path from 'path'
|
|
6
|
+
import * as log from './log.js'
|
|
7
|
+
|
|
8
|
+
// 开始发布 -headers.tar.gz 的版本
|
|
9
|
+
const headersTarballRange = '>= 3.0.0 || ~0.12.10 || ~0.10.42'
|
|
10
|
+
const bitsre = /\/win-(x86|x64|arm64)\//
|
|
11
|
+
const bitsreV3 = /\/win-(x86|ia32|x64)\// // io.js v3.x.x 里用的是 "ia32",本应是 "x86"
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 归一化路径:统一分隔符为 /
|
|
15
|
+
*/
|
|
16
|
+
const normalizePath = (p) => path.normalize(p).replace(/\\/g, '/')
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 根据名称、基础 URL、架构、主版本号解析 lib 下载地址
|
|
20
|
+
*/
|
|
21
|
+
const resolveLibUrl = (name, defaultUrl, arch, versionMajor) => {
|
|
22
|
+
const base = url.resolve(defaultUrl, './')
|
|
23
|
+
const hasLibUrl = bitsre.test(defaultUrl) || (versionMajor === 3 && bitsreV3.test(defaultUrl))
|
|
24
|
+
|
|
25
|
+
if (!hasLibUrl) {
|
|
26
|
+
// 假设传入的是 baseUrl
|
|
27
|
+
if (versionMajor >= 1) {
|
|
28
|
+
return url.resolve(base, 'win-' + arch + '/' + name + '.lib')
|
|
29
|
+
}
|
|
30
|
+
// io.js@1.0.0 之前,32 位 node.lib 在根目录,64 位在 /x64/
|
|
31
|
+
return url.resolve(base, (arch === 'x86' ? '' : arch + '/') + name + '.lib')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 否则传入的已经是 .lib 地址,只需保证架构正确
|
|
35
|
+
return defaultUrl.replace(versionMajor === 3 ? bitsreV3 : bitsre, '/win-' + arch + '/')
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 负责确定下载 URL、本地目录和文件名。
|
|
40
|
+
* 输入来自命令行开关(--target、--dist-url)、process.version 和 process.release。
|
|
41
|
+
*/
|
|
42
|
+
const processRelease = (argv, gyp, defaultVersion, defaultRelease) => {
|
|
43
|
+
let version = (semver.valid(argv[0]) && argv[0]) || gyp.opts.target || defaultVersion
|
|
44
|
+
const versionSemver = semver.parse(version)
|
|
45
|
+
let overrideDistUrl = gyp.opts['dist-url'] || gyp.opts.disturl
|
|
46
|
+
let isNamedForLegacyIojs
|
|
47
|
+
let name
|
|
48
|
+
let distBaseUrl
|
|
49
|
+
let baseUrl
|
|
50
|
+
let libUrl32
|
|
51
|
+
let libUrl64
|
|
52
|
+
let libUrlArm64
|
|
53
|
+
let tarballUrl
|
|
54
|
+
let canGetHeaders
|
|
55
|
+
|
|
56
|
+
if (!versionSemver) {
|
|
57
|
+
// 不是合法 semver,只能原样返回 version
|
|
58
|
+
return { version }
|
|
59
|
+
}
|
|
60
|
+
// 把 version 拍平为字符串
|
|
61
|
+
version = versionSemver.version
|
|
62
|
+
|
|
63
|
+
// defaultVersion 来自 process.version,应当是合法 semver
|
|
64
|
+
const isDefaultVersion = version === semver.parse(defaultVersion).version
|
|
65
|
+
|
|
66
|
+
// 用了 --target=x.y.z 就不能用 process.release
|
|
67
|
+
if (!isDefaultVersion) {
|
|
68
|
+
defaultRelease = null
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (defaultRelease) {
|
|
72
|
+
// v3 起有 process.release
|
|
73
|
+
name = defaultRelease.name.replace(/io\.js/, 'iojs') // 去掉 '.' 以便目录命名
|
|
74
|
+
} else {
|
|
75
|
+
// 老版本 Node 或自定义 --target
|
|
76
|
+
// semver.satisfies() 不支持预发布标签,因此直接判断主版本
|
|
77
|
+
isNamedForLegacyIojs = versionSemver.major >= 1 && versionSemver.major < 4
|
|
78
|
+
// isNamedForLegacyIojs 是为了支持 Electron < 4(特别是 Electron 3)
|
|
79
|
+
// 早期逻辑用它保证 iojs 版本下载 "iojs",Node 版本下载 "node"。
|
|
80
|
+
// 但该逻辑过宽,导致 electron@3 的发布物命名为 "iojs" 才能让 node-gyp 正常工作。
|
|
81
|
+
// Electron@3 EOL 之后(2019 年底)应移除这个 hack。
|
|
82
|
+
name = isNamedForLegacyIojs ? 'iojs' : 'node'
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// 检查 nvm.sh 标准镜像环境变量
|
|
86
|
+
if (!overrideDistUrl && process.env.NODEJS_ORG_MIRROR) {
|
|
87
|
+
overrideDistUrl = process.env.NODEJS_ORG_MIRROR
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (overrideDistUrl) {
|
|
91
|
+
log.verbose('download', 'using dist-url', overrideDistUrl)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (overrideDistUrl) {
|
|
95
|
+
distBaseUrl = overrideDistUrl.replace(/\/+$/, '')
|
|
96
|
+
} else {
|
|
97
|
+
distBaseUrl = 'https://nodejs.org/dist'
|
|
98
|
+
}
|
|
99
|
+
distBaseUrl += '/v' + version + '/'
|
|
100
|
+
|
|
101
|
+
// 新式:基于 process.release,大部分数据已有
|
|
102
|
+
if (defaultRelease && defaultRelease.headersUrl && !overrideDistUrl) {
|
|
103
|
+
baseUrl = url.resolve(defaultRelease.headersUrl, './')
|
|
104
|
+
libUrl32 = resolveLibUrl(name, defaultRelease.libUrl || baseUrl || distBaseUrl, 'x86', versionSemver.major)
|
|
105
|
+
libUrl64 = resolveLibUrl(name, defaultRelease.libUrl || baseUrl || distBaseUrl, 'x64', versionSemver.major)
|
|
106
|
+
libUrlArm64 = resolveLibUrl(name, defaultRelease.libUrl || baseUrl || distBaseUrl, 'arm64', versionSemver.major)
|
|
107
|
+
tarballUrl = defaultRelease.headersUrl
|
|
108
|
+
} else {
|
|
109
|
+
// 没有 process.release 的老版本,需要做很多假设;
|
|
110
|
+
// 另外 --target=x.y.z 时也无法使用当前 process.release
|
|
111
|
+
baseUrl = distBaseUrl
|
|
112
|
+
libUrl32 = resolveLibUrl(name, baseUrl, 'x86', versionSemver.major)
|
|
113
|
+
libUrl64 = resolveLibUrl(name, baseUrl, 'x64', versionSemver.major)
|
|
114
|
+
libUrlArm64 = resolveLibUrl(name, baseUrl, 'arm64', versionSemver.major)
|
|
115
|
+
|
|
116
|
+
// 大胆假设:任何版本号 >3.0.0 的版本,其 dist 目录都有 *-headers.tar.gz
|
|
117
|
+
canGetHeaders = semver.satisfies(versionSemver, headersTarballRange)
|
|
118
|
+
tarballUrl = url.resolve(baseUrl, name + '-v' + version + (canGetHeaders ? '-headers' : '') + '.tar.gz')
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
version,
|
|
123
|
+
semver: versionSemver,
|
|
124
|
+
name,
|
|
125
|
+
baseUrl,
|
|
126
|
+
tarballUrl,
|
|
127
|
+
shasumsUrl: url.resolve(baseUrl, 'SHASUMS256.txt'),
|
|
128
|
+
versionDir: (name !== 'node' ? name + '-' : '') + version,
|
|
129
|
+
ia32: {
|
|
130
|
+
libUrl: libUrl32,
|
|
131
|
+
libPath: normalizePath(path.relative(url.parse(baseUrl).path, url.parse(libUrl32).path))
|
|
132
|
+
},
|
|
133
|
+
x64: {
|
|
134
|
+
libUrl: libUrl64,
|
|
135
|
+
libPath: normalizePath(path.relative(url.parse(baseUrl).path, url.parse(libUrl64).path))
|
|
136
|
+
},
|
|
137
|
+
arm64: {
|
|
138
|
+
libUrl: libUrlArm64,
|
|
139
|
+
libPath: normalizePath(path.relative(url.parse(baseUrl).path, url.parse(libUrlArm64).path))
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export { processRelease }
|
package/lib/rebuild.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 依次执行 clean、configure、build
|
|
3
|
+
*/
|
|
4
|
+
const rebuild = async (gyp, argv) => {
|
|
5
|
+
gyp.todo.push(
|
|
6
|
+
{ name: 'clean', args: [] }
|
|
7
|
+
, { name: 'configure', args: argv }
|
|
8
|
+
, { name: 'build', args: [] }
|
|
9
|
+
)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
rebuild.usage = 'Runs "clean", "configure" and "build" all at once'
|
|
13
|
+
|
|
14
|
+
export { rebuild }
|
package/lib/remove.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import gracefulFs from 'graceful-fs'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import * as log from './log.js'
|
|
4
|
+
import semver from 'semver'
|
|
5
|
+
|
|
6
|
+
const fs = gracefulFs.promises
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 删除指定版本的 Node 开发文件
|
|
10
|
+
*/
|
|
11
|
+
const remove = async (gyp, argv) => {
|
|
12
|
+
const devDir = gyp.devDir
|
|
13
|
+
log.verbose('remove', 'using node-gyp dir:', devDir)
|
|
14
|
+
|
|
15
|
+
// 获取用户指定的版本号
|
|
16
|
+
let version = argv[0] || gyp.opts.target
|
|
17
|
+
log.verbose('remove', 'removing target version:', version)
|
|
18
|
+
|
|
19
|
+
if (!version) {
|
|
20
|
+
throw new Error('You must specify a version number to remove. Ex: "' + process.version + '"')
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const versionSemver = semver.parse(version)
|
|
24
|
+
if (versionSemver) {
|
|
25
|
+
// 把版本数组拍平为字符串
|
|
26
|
+
version = versionSemver.version
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const versionPath = path.resolve(gyp.devDir, version)
|
|
30
|
+
log.verbose('remove', 'removing development files for version:', version)
|
|
31
|
+
|
|
32
|
+
// 先检查是否安装过
|
|
33
|
+
try {
|
|
34
|
+
await fs.stat(versionPath)
|
|
35
|
+
} catch (err) {
|
|
36
|
+
if (err.code === 'ENOENT') {
|
|
37
|
+
return 'version was already uninstalled: ' + version
|
|
38
|
+
}
|
|
39
|
+
throw err
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
await fs.rm(versionPath, { recursive: true, force: true })
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
remove.usage = 'Removes the node development files for the specified version'
|
|
46
|
+
|
|
47
|
+
export { remove }
|
package/lib/util.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import cp from 'child_process'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import gracefulFs from 'graceful-fs'
|
|
4
|
+
import * as log from './log.js'
|
|
5
|
+
|
|
6
|
+
const { openSync, closeSync } = gracefulFs
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 执行外部命令并返回 [err, stdout, stderr]
|
|
10
|
+
*/
|
|
11
|
+
const execFile = async (...args) => new Promise((resolve) => {
|
|
12
|
+
const child = cp.execFile(...args, (...a) => resolve(a))
|
|
13
|
+
child.stdin.end()
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 读取 Windows 注册表指定键的值
|
|
18
|
+
*/
|
|
19
|
+
const regGetValue = async (key, value, addOpts) => {
|
|
20
|
+
const outReValue = value.replace(/\W/g, '.')
|
|
21
|
+
const outRe = new RegExp(`^\\s+${outReValue}\\s+REG_\\w+\\s+(\\S.*)$`, 'im')
|
|
22
|
+
const reg = path.join(process.env.SystemRoot, 'System32', 'reg.exe')
|
|
23
|
+
const regArgs = ['query', key, '/v', value].concat(addOpts)
|
|
24
|
+
|
|
25
|
+
log.silly('reg', 'running', reg, regArgs)
|
|
26
|
+
const [err, stdout, stderr] = await execFile(reg, regArgs, { encoding: 'utf8' })
|
|
27
|
+
|
|
28
|
+
log.silly('reg', 'reg.exe stdout = %j', stdout)
|
|
29
|
+
if (err || stderr.trim() !== '') {
|
|
30
|
+
log.silly('reg', 'reg.exe err = %j', err && (err.stack || err))
|
|
31
|
+
log.silly('reg', 'reg.exe stderr = %j', stderr)
|
|
32
|
+
if (err) {
|
|
33
|
+
throw err
|
|
34
|
+
}
|
|
35
|
+
throw new Error(stderr)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const result = outRe.exec(stdout)
|
|
39
|
+
if (!result) {
|
|
40
|
+
log.silly('reg', 'error parsing stdout')
|
|
41
|
+
throw new Error('Could not parse output of reg.exe')
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
log.silly('reg', 'found: %j', result[1])
|
|
45
|
+
return result[1]
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 依次搜索多个注册表键,返回第一个可读的值
|
|
50
|
+
*/
|
|
51
|
+
const regSearchKeys = async (keys, value, addOpts) => {
|
|
52
|
+
for (const key of keys) {
|
|
53
|
+
try {
|
|
54
|
+
return await regGetValue(key, value, addOpts)
|
|
55
|
+
} catch {
|
|
56
|
+
continue
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* 返回候选列表中第一个当前用户可读的文件或目录,都不存在则返回 undefined
|
|
63
|
+
*/
|
|
64
|
+
const findAccessibleSync = (logprefix, dir, candidates) => {
|
|
65
|
+
for (let next = 0; next < candidates.length; next++) {
|
|
66
|
+
const candidate = path.resolve(dir, candidates[next])
|
|
67
|
+
let fd
|
|
68
|
+
try {
|
|
69
|
+
fd = openSync(candidate, 'r')
|
|
70
|
+
} catch (e) {
|
|
71
|
+
// 该候选文件不存在或不可读,继续检查下一个
|
|
72
|
+
log.silly(logprefix, 'Could not open %s: %s', candidate, e.message)
|
|
73
|
+
continue
|
|
74
|
+
}
|
|
75
|
+
closeSync(fd)
|
|
76
|
+
log.silly(logprefix, 'Found readable %s', candidate)
|
|
77
|
+
return candidate
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return undefined
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export { execFile, regGetValue, regSearchKeys, findAccessibleSync }
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@flun/nodejs-mobile-gyp",
|
|
3
|
+
"description": "Node.js for Mobile Apps native addon build tool (flun fork)",
|
|
4
|
+
"keywords": [
|
|
5
|
+
"nodejs-mobile",
|
|
6
|
+
"native",
|
|
7
|
+
"addon",
|
|
8
|
+
"module",
|
|
9
|
+
"c",
|
|
10
|
+
"c++",
|
|
11
|
+
"bindings",
|
|
12
|
+
"gyp"
|
|
13
|
+
],
|
|
14
|
+
"version": "1.0.1",
|
|
15
|
+
"installVersion": 11,
|
|
16
|
+
"author": "flun <open@flun.top>",
|
|
17
|
+
"bin": "./bin/node-gyp.js",
|
|
18
|
+
"main": "./lib/node-gyp.js",
|
|
19
|
+
"files": [
|
|
20
|
+
"bin/",
|
|
21
|
+
"gyp/gyp",
|
|
22
|
+
"gyp/gyp.bat",
|
|
23
|
+
"gyp/gyp_main.py",
|
|
24
|
+
"gyp/LICENSE",
|
|
25
|
+
"gyp/pylib/gyp/",
|
|
26
|
+
"gyp/pylib/packaging/",
|
|
27
|
+
"gyp/data/",
|
|
28
|
+
"!gyp/pylib/gyp/__pycache__/",
|
|
29
|
+
"!gyp/pylib/gyp/generator/__pycache__/",
|
|
30
|
+
"!gyp/pylib/gyp/**/*_test.py",
|
|
31
|
+
"!gyp/pylib/packaging/__pycache__/",
|
|
32
|
+
"lib/",
|
|
33
|
+
"src/",
|
|
34
|
+
"addon.gypi",
|
|
35
|
+
"README.md",
|
|
36
|
+
"CHANGELOG.md",
|
|
37
|
+
"LICENSE"
|
|
38
|
+
],
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"env-paths": "^4.0.0",
|
|
41
|
+
"exponential-backoff": "^3.1.3",
|
|
42
|
+
"glob": "^13.0.6",
|
|
43
|
+
"graceful-fs": "^4.2.11",
|
|
44
|
+
"make-fetch-happen": "^16.0.1",
|
|
45
|
+
"nopt": "^10.0.1",
|
|
46
|
+
"proc-log": "^7.0.0",
|
|
47
|
+
"semver": "^7.8.5",
|
|
48
|
+
"tar": "^7.5.22",
|
|
49
|
+
"which": "^7.0.0"
|
|
50
|
+
},
|
|
51
|
+
"allowScripts": {
|
|
52
|
+
"node": true
|
|
53
|
+
},
|
|
54
|
+
"engines": {
|
|
55
|
+
"node": ">=18.0.0"
|
|
56
|
+
},
|
|
57
|
+
"homepage": "https://github.com/OpenFlun/nodejs-mobile-gyp",
|
|
58
|
+
"repository": {
|
|
59
|
+
"type": "git",
|
|
60
|
+
"url": "git+https://github.com/OpenFlun/nodejs-mobile-gyp.git"
|
|
61
|
+
},
|
|
62
|
+
"gitee": "https://gitee.com/OpenFlun/nodejs-mobile-gyp.git",
|
|
63
|
+
"bugs": {
|
|
64
|
+
"url": "https://github.com/OpenFlun/nodejs-mobile-gyp/issues"
|
|
65
|
+
},
|
|
66
|
+
"license": "ISC",
|
|
67
|
+
"type": "module",
|
|
68
|
+
"publishConfig": {
|
|
69
|
+
"access": "public",
|
|
70
|
+
"registry": "https://registry.npmjs.org/"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* When this file is linked to a DLL, it sets up a delay-load hook that
|
|
3
|
+
* intervenes when the DLL is trying to load the host executable
|
|
4
|
+
* dynamically. Instead of trying to locate the .exe file it'll just
|
|
5
|
+
* return a handle to the process image.
|
|
6
|
+
*
|
|
7
|
+
* This allows compiled addons to work when the host executable is renamed.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#ifdef _MSC_VER
|
|
11
|
+
|
|
12
|
+
#pragma managed(push, off)
|
|
13
|
+
|
|
14
|
+
#ifndef WIN32_LEAN_AND_MEAN
|
|
15
|
+
#define WIN32_LEAN_AND_MEAN
|
|
16
|
+
#endif
|
|
17
|
+
|
|
18
|
+
#include <windows.h>
|
|
19
|
+
|
|
20
|
+
#include <delayimp.h>
|
|
21
|
+
#include <string.h>
|
|
22
|
+
|
|
23
|
+
static FARPROC WINAPI load_exe_hook(unsigned int event, DelayLoadInfo* info) {
|
|
24
|
+
HMODULE m;
|
|
25
|
+
if (event != dliNotePreLoadLibrary)
|
|
26
|
+
return NULL;
|
|
27
|
+
|
|
28
|
+
if (_stricmp(info->szDll, HOST_BINARY) != 0)
|
|
29
|
+
return NULL;
|
|
30
|
+
|
|
31
|
+
m = GetModuleHandle(NULL);
|
|
32
|
+
return (FARPROC) m;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
decltype(__pfnDliNotifyHook2) __pfnDliNotifyHook2 = load_exe_hook;
|
|
36
|
+
|
|
37
|
+
#pragma managed(pop)
|
|
38
|
+
|
|
39
|
+
#endif
|