@flun/nodejs-mobile-gyp 1.0.1 → 1.0.2
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 +56 -36
- package/README.md +256 -252
- package/addon.gypi +13 -1
- package/bin/node-gyp.js +66 -109
- package/gyp/pylib/gyp/MSVSSettings.py +13 -0
- package/lib/build.js +127 -209
- package/lib/clean.js +13 -16
- package/lib/configure.js +183 -265
- package/lib/create-config-gypi.js +102 -156
- package/lib/download.js +29 -42
- package/lib/find-node-directory.js +38 -55
- package/lib/find-python.js +162 -198
- package/lib/find-visualstudio.js +196 -295
- package/lib/install.js +269 -378
- package/lib/list.js +19 -25
- package/lib/log.js +69 -133
- package/lib/node-gyp.js +62 -107
- package/lib/process-release.js +100 -139
- package/lib/rebuild.js +3 -8
- package/lib/remove.js +34 -44
- package/lib/util.js +62 -73
- package/package.json +5 -3
- package/gyp/LICENSE +0 -28
package/addon.gypi
CHANGED
|
@@ -146,6 +146,18 @@
|
|
|
146
146
|
],
|
|
147
147
|
}],
|
|
148
148
|
[ 'OS=="win"', {
|
|
149
|
+
'msvs_settings': {
|
|
150
|
+
'VCCLCompilerTool': {
|
|
151
|
+
# /external:anglebrackets:把 <...> 引用的 Node / V8 头视为外部头,
|
|
152
|
+
# 只对它们抑制警告;下游自己代码(#include "...")不受影响。
|
|
153
|
+
# 警告级别用 ExternalWarningLevel 属性设置,而不是命令行 /external:W0,
|
|
154
|
+
# 避免与 MSBuild 默认的 /external:W3 冲突而产生 D9025。
|
|
155
|
+
'AdditionalOptions': [
|
|
156
|
+
'/external:anglebrackets'
|
|
157
|
+
],
|
|
158
|
+
'ExternalWarningLevel': 'TurnOffAllWarnings'
|
|
159
|
+
}
|
|
160
|
+
},
|
|
149
161
|
'conditions': [
|
|
150
162
|
['node_engine=="chakracore"', {
|
|
151
163
|
'library_dirs': [ '<(node_root_dir)/$(ConfigurationName)' ],
|
|
@@ -154,7 +166,7 @@
|
|
|
154
166
|
['node_with_ltcg=="true"', {
|
|
155
167
|
'msvs_settings': {
|
|
156
168
|
'VCCLCompilerTool': {
|
|
157
|
-
'WholeProgramOptimization': 'true' # /GL, whole program optimization, needed for LTCG
|
|
169
|
+
'WholeProgramOptimization': 'true', # /GL, whole program optimization, needed for LTCG
|
|
158
170
|
},
|
|
159
171
|
'VCLibrarianTool': {
|
|
160
172
|
'AdditionalOptions': [
|
package/bin/node-gyp.js
CHANGED
|
@@ -1,68 +1,51 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import envPaths from 'env-paths'
|
|
4
|
-
import os from 'os'
|
|
5
|
-
import fs from 'fs'
|
|
6
|
-
import { Gyp } from '../lib/node-gyp.js'
|
|
7
|
-
import * as log from '../lib/log.js'
|
|
3
|
+
import envPaths from 'env-paths';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import fs from 'fs';
|
|
6
|
+
import { Gyp } from '../lib/node-gyp.js';
|
|
7
|
+
import * as log from '../lib/log.js';
|
|
8
8
|
|
|
9
|
-
process.title = 'node-gyp'
|
|
9
|
+
process.title = 'node-gyp';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* 处理并执行选中的命令。
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
const prog = new Gyp()
|
|
16
|
-
let completed = false
|
|
17
|
-
prog.parseArgv(process.argv)
|
|
18
|
-
prog.devDir = prog.opts.devdir
|
|
15
|
+
const prog = new Gyp(), homeDir = os.homedir();
|
|
16
|
+
let completed = false;
|
|
17
|
+
prog.parseArgv(process.argv), prog.devDir = prog.opts.devdir;
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
if (prog.devDir
|
|
22
|
-
|
|
23
|
-
} else if (homeDir) {
|
|
24
|
-
prog.devDir = envPaths('node-gyp', { suffix: '' }).cache
|
|
25
|
-
} else {
|
|
19
|
+
if (prog.devDir) prog.devDir = prog.devDir.replace(/^~/, homeDir);
|
|
20
|
+
else if (homeDir) prog.devDir = envPaths('node-gyp', { suffix: '' }).cache;
|
|
21
|
+
else {
|
|
26
22
|
throw new Error(
|
|
27
23
|
"node-gyp requires that the user's home directory is specified " +
|
|
28
24
|
'in either of the environmental variables HOME or USERPROFILE. ' +
|
|
29
|
-
'Overide with: --devdir /path/to/.node-gyp')
|
|
25
|
+
'Overide with: --devdir /path/to/.node-gyp');
|
|
30
26
|
}
|
|
31
27
|
|
|
32
28
|
if (prog.todo.length === 0) {
|
|
33
|
-
if (~process.argv.indexOf('-v') || ~process.argv.indexOf('--version'))
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
log.stdout('%s', prog.usage())
|
|
37
|
-
}
|
|
38
|
-
process.exit(0)
|
|
29
|
+
if (~process.argv.indexOf('-v') || ~process.argv.indexOf('--version')) log.stdout('v%s', prog.version);
|
|
30
|
+
else log.stdout('%s', prog.usage());
|
|
31
|
+
process.exit(0);
|
|
39
32
|
}
|
|
40
33
|
|
|
41
|
-
log.info('it worked if it ends with', 'ok')
|
|
42
|
-
log.
|
|
43
|
-
log.info('using', 'node-gyp@%s', prog.version)
|
|
44
|
-
log.info('using', 'node@%s | %s | %s', process.versions.node, process.platform, process.arch)
|
|
34
|
+
log.info('it worked if it ends with', 'ok'), log.verbose('cli', process.argv), log.info('using', 'node-gyp@%s', prog.version);
|
|
35
|
+
log.info('using', 'node@%s | %s | %s', process.versions.node, process.platform, process.arch);
|
|
45
36
|
|
|
46
37
|
/**
|
|
47
|
-
* 如果传了 -C/--directory
|
|
38
|
+
* 如果传了 -C/--directory,切换到该目录;
|
|
48
39
|
*/
|
|
49
|
-
|
|
50
|
-
const dir = prog.opts.directory
|
|
40
|
+
const dir = prog.opts.directory;
|
|
51
41
|
if (dir) {
|
|
52
42
|
try {
|
|
53
|
-
const stat = fs.statSync(dir)
|
|
54
|
-
if (stat.isDirectory())
|
|
55
|
-
|
|
56
|
-
process.chdir(dir)
|
|
57
|
-
} else {
|
|
58
|
-
log.warn('chdir', dir + ' is not a directory')
|
|
59
|
-
}
|
|
43
|
+
const stat = fs.statSync(dir);
|
|
44
|
+
if (stat.isDirectory()) log.info('chdir', dir), process.chdir(dir);
|
|
45
|
+
else log.warn('chdir', dir + ' 不是目录');
|
|
60
46
|
} catch (e) {
|
|
61
|
-
if (e.code === 'ENOENT')
|
|
62
|
-
|
|
63
|
-
} else {
|
|
64
|
-
log.warn('chdir', 'error during chdir() "%s"', e.message)
|
|
65
|
-
}
|
|
47
|
+
if (e.code === 'ENOENT') log.warn('chdir', dir + ' 不是目录');
|
|
48
|
+
else log.warn('chdir', 'chdir() 出错 "%s"', e.message);
|
|
66
49
|
}
|
|
67
50
|
}
|
|
68
51
|
|
|
@@ -71,74 +54,48 @@ if (dir) {
|
|
|
71
54
|
*/
|
|
72
55
|
const errorMessage = () => {
|
|
73
56
|
// 复制自 npm 的 lib/utils/error-handler.js
|
|
74
|
-
log.error('System', os.type() + ' ' + os.release())
|
|
75
|
-
log.error('command', process.argv
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
try {
|
|
105
|
-
const args = await prog.commands[command.name](command.args) ?? []
|
|
106
|
-
|
|
107
|
-
if (command.name === 'list') {
|
|
108
|
-
if (args.length) {
|
|
109
|
-
args.forEach((version) => log.stdout(version))
|
|
110
|
-
} else {
|
|
111
|
-
log.stdout('No node development files installed. Use `node-gyp install` to install a version.')
|
|
57
|
+
log.error('System', os.type() + ' ' + os.release());
|
|
58
|
+
log.error('command', process.argv.map(JSON.stringify).join(' ')), log.error('cwd', process.cwd());
|
|
59
|
+
log.error('node -v', process.version), log.error('node-gyp -v', 'v' + prog.package.version);
|
|
60
|
+
},
|
|
61
|
+
/**
|
|
62
|
+
* 打印最终诊断信息
|
|
63
|
+
*/
|
|
64
|
+
issueMessage = () => {
|
|
65
|
+
errorMessage();
|
|
66
|
+
log.error('', ['node-gyp 构建你的包失败!', '请尝试更新 npm 和/或 node-gyp;若仍无法解决,请向包作者反馈;'].join('\n'));
|
|
67
|
+
},
|
|
68
|
+
/**
|
|
69
|
+
* 依次执行队列中的命令
|
|
70
|
+
*/
|
|
71
|
+
run = async () => {
|
|
72
|
+
const command = prog.todo.shift()
|
|
73
|
+
if (!command) {
|
|
74
|
+
// 完成!
|
|
75
|
+
completed = true, log.info('ok');
|
|
76
|
+
return;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
const args = await prog.commands[command.name](command.args) ?? [];
|
|
81
|
+
|
|
82
|
+
if (command.name === 'list') {
|
|
83
|
+
if (args.length) args.forEach((version) => log.stdout(version));
|
|
84
|
+
else log.stdout('尚未安装任何 Node 开发文件;可用 `node-gyp install` 安装指定版本;')
|
|
112
85
|
}
|
|
113
|
-
|
|
114
|
-
|
|
86
|
+
else if (args.length >= 1) log.stdout(...args.slice(1))
|
|
87
|
+
return run(); // 继续执行队列中的下一条命令
|
|
88
|
+
} catch (err) {
|
|
89
|
+
log.error(command.name + ' error'), log.error('stack', err.stack), errorMessage(), log.error('not ok');
|
|
90
|
+
return process.exit(1);
|
|
115
91
|
}
|
|
92
|
+
};
|
|
116
93
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
log.error('not ok')
|
|
124
|
-
return process.exit(1)
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
process.on('exit', function (code) {
|
|
129
|
-
if (!completed && !code) {
|
|
130
|
-
log.error('Completion callback never invoked!')
|
|
131
|
-
issueMessage()
|
|
132
|
-
process.exit(6)
|
|
133
|
-
}
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
process.on('uncaughtException', function (err) {
|
|
137
|
-
log.error('UNCAUGHT EXCEPTION')
|
|
138
|
-
log.error('stack', err.stack)
|
|
139
|
-
issueMessage()
|
|
140
|
-
process.exit(7)
|
|
141
|
-
})
|
|
94
|
+
process.on('exit', code => {
|
|
95
|
+
if (!completed && !code) log.error('完成回调未被调用!'), issueMessage(), process.exit(6);
|
|
96
|
+
});
|
|
97
|
+
process.on('uncaughtException', err => {
|
|
98
|
+
log.error('未捕获的异常'), log.error('stack', err.stack), issueMessage(), process.exit(7);
|
|
99
|
+
});
|
|
142
100
|
|
|
143
|
-
// 开始执行给定命令!
|
|
144
|
-
run()
|
|
101
|
+
run(); // 开始执行给定命令!
|
|
@@ -797,6 +797,19 @@ _MSBuildOnly(_compile, "MultiProcessorCompilation", _boolean) # /MP
|
|
|
797
797
|
_MSBuildOnly(_compile, "PreprocessOutputPath", _string) # /Fi
|
|
798
798
|
_MSBuildOnly(_compile, "ProcessorNumber", _integer) # the number of processors
|
|
799
799
|
_MSBuildOnly(_compile, "TrackerLogDirectory", _folder_name)
|
|
800
|
+
_MSBuildOnly(
|
|
801
|
+
_compile,
|
|
802
|
+
"ExternalWarningLevel",
|
|
803
|
+
_Enumeration(
|
|
804
|
+
[
|
|
805
|
+
"TurnOffAllWarnings", # /external:W0
|
|
806
|
+
"Level1", # /external:W1
|
|
807
|
+
"Level2", # /external:W2
|
|
808
|
+
"Level3", # /external:W3
|
|
809
|
+
"Level4", # /external:W4
|
|
810
|
+
]
|
|
811
|
+
),
|
|
812
|
+
) # /external:W
|
|
800
813
|
_MSBuildOnly(_compile, "TreatSpecificWarningsAsErrors", _string_list) # /we
|
|
801
814
|
_MSBuildOnly(_compile, "UseUnicodeForAssemblerListing", _boolean) # /FAu
|
|
802
815
|
|
package/lib/build.js
CHANGED
|
@@ -1,221 +1,139 @@
|
|
|
1
|
-
import gracefulFs from 'graceful-fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import { glob } from 'glob'
|
|
4
|
-
import * as log from './log.js'
|
|
5
|
-
import which from 'which'
|
|
6
|
-
import os from 'os'
|
|
7
|
-
|
|
8
|
-
const fs = gracefulFs.promises
|
|
9
|
-
const win = process.platform === 'win32'
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* 调用 make/msbuild 构建原生模块
|
|
13
|
-
*/
|
|
14
|
-
const build = async (gyp, argv) => {
|
|
15
|
-
let platformMake = 'make'
|
|
16
|
-
if (process.platform === 'aix') {
|
|
17
|
-
platformMake = 'gmake'
|
|
18
|
-
} else if (process.platform === 'os400') {
|
|
19
|
-
platformMake = 'gmake'
|
|
20
|
-
} else if (process.platform.indexOf('bsd') !== -1) {
|
|
21
|
-
platformMake = 'gmake'
|
|
22
|
-
} else if (win && argv.length > 0) {
|
|
23
|
-
argv = argv.map(function (target) {
|
|
24
|
-
return '/t:' + target
|
|
25
|
-
})
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const makeCommand = gyp.opts.make || process.env.MAKE || platformMake
|
|
29
|
-
let command = win ? 'msbuild' : makeCommand
|
|
30
|
-
const jobs = gyp.opts.jobs || process.env.JOBS
|
|
31
|
-
let buildType
|
|
32
|
-
let config
|
|
33
|
-
let arch
|
|
34
|
-
let nodeDir
|
|
35
|
-
let guessedSolution
|
|
36
|
-
let python
|
|
37
|
-
let buildBinsDir
|
|
38
|
-
|
|
39
|
-
await loadConfigGypi()
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* 加载 configure 阶段生成的 config.gypi
|
|
43
|
-
*/
|
|
44
|
-
async function loadConfigGypi () {
|
|
45
|
-
let data
|
|
46
|
-
try {
|
|
47
|
-
const configPath = path.resolve('build', 'config.gypi')
|
|
48
|
-
data = await fs.readFile(configPath, 'utf8')
|
|
49
|
-
} catch (err) {
|
|
50
|
-
if (err.code === 'ENOENT') {
|
|
51
|
-
throw new Error('You must run `node-gyp configure` first!')
|
|
52
|
-
} else {
|
|
53
|
-
throw err
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
config = JSON.parse(data.replace(/#.+\n/, ''))
|
|
58
|
-
|
|
59
|
-
// 从 config 中取出 arch、buildType、nodeDir
|
|
60
|
-
buildType = config.target_defaults.default_configuration
|
|
61
|
-
arch = config.variables.target_arch
|
|
62
|
-
nodeDir = config.variables.nodedir
|
|
63
|
-
python = config.variables.python
|
|
64
|
-
|
|
65
|
-
if ('debug' in gyp.opts) {
|
|
66
|
-
buildType = gyp.opts.debug ? 'Debug' : 'Release'
|
|
67
|
-
}
|
|
68
|
-
if (!buildType) {
|
|
69
|
-
buildType = 'Release'
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
log.verbose('build type', buildType)
|
|
73
|
-
log.verbose('architecture', arch)
|
|
74
|
-
log.verbose('node dev dir', nodeDir)
|
|
75
|
-
log.verbose('python', python)
|
|
76
|
-
|
|
77
|
-
if (win) {
|
|
78
|
-
await findSolutionFile()
|
|
79
|
-
} else {
|
|
80
|
-
await doWhich()
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Windows 下查找第一个 build/*.sln 文件
|
|
86
|
-
*/
|
|
87
|
-
async function findSolutionFile () {
|
|
88
|
-
const files = await glob('build/*.sln')
|
|
89
|
-
if (files.length === 0) {
|
|
90
|
-
throw new Error('Could not find *.sln file. Did you run "configure"?')
|
|
91
|
-
}
|
|
92
|
-
guessedSolution = files[0]
|
|
93
|
-
log.verbose('found first Solution file', guessedSolution)
|
|
94
|
-
await doWhich()
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* 用 node-which 定位 msbuild / make 可执行文件
|
|
99
|
-
*/
|
|
100
|
-
async function doWhich () {
|
|
101
|
-
// Windows 使用 node-gyp configure 提供的 msbuild
|
|
102
|
-
if (win) {
|
|
103
|
-
if (!config.variables.msbuild_path) {
|
|
104
|
-
throw new Error('MSBuild is not set, please run `node-gyp configure`.')
|
|
105
|
-
}
|
|
106
|
-
command = config.variables.msbuild_path
|
|
107
|
-
log.verbose('using MSBuild:', command)
|
|
108
|
-
await doBuild()
|
|
109
|
-
return
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// 先确认构建命令在 PATH 中
|
|
113
|
-
const execPath = await which(command)
|
|
114
|
-
log.verbose('`which` succeeded for `' + command + '`', execPath)
|
|
115
|
-
await doBuild()
|
|
116
|
-
}
|
|
117
|
-
|
|
1
|
+
import gracefulFs from 'graceful-fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { glob } from 'glob';
|
|
4
|
+
import * as log from './log.js';
|
|
5
|
+
import which from 'which';
|
|
6
|
+
import os from 'os';
|
|
7
|
+
|
|
8
|
+
const fs = gracefulFs.promises, win = process.platform === 'win32',
|
|
118
9
|
/**
|
|
119
|
-
*
|
|
10
|
+
* 调用 make/msbuild 构建原生模块
|
|
120
11
|
*/
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
//
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
: (archLower === 'arm'
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
argv.push('/m:' + j)
|
|
155
|
-
} else if (jobs.toUpperCase() === 'MAX') {
|
|
156
|
-
argv.push('/m:' + os.cpus().length)
|
|
12
|
+
build = async (gyp, argv) => {
|
|
13
|
+
let platformMake = 'make';
|
|
14
|
+
|
|
15
|
+
if (['aix', 'os400'].includes(process.platform) || process.platform.includes('bsd')) platformMake = 'gmake';
|
|
16
|
+
else if (win && argv.length > 0) argv = argv.map(target => '/t:' + target);
|
|
17
|
+
|
|
18
|
+
const makeCommand = gyp.opts.make || process.env.MAKE || platformMake, jobs = gyp.opts.jobs || process.env.JOBS;
|
|
19
|
+
let command = win ? 'msbuild' : makeCommand, buildType, config, arch, nodeDir, guessedSolution, python, buildBinsDir;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 真正启动子进程并编译模块
|
|
23
|
+
*/
|
|
24
|
+
const doBuild = async () => {
|
|
25
|
+
// 启用 verbose 构建
|
|
26
|
+
const verbose = log.logger.isVisible('verbose');
|
|
27
|
+
let j;
|
|
28
|
+
|
|
29
|
+
if (!win && verbose) argv.push('V=1');
|
|
30
|
+
if (win && !verbose) argv.push('/clp:Verbosity=minimal');
|
|
31
|
+
if (win) argv.push('/nologo'); // Windows 上关闭 Microsoft logo
|
|
32
|
+
|
|
33
|
+
// 指定构建类型,默认 Release
|
|
34
|
+
if (win) {
|
|
35
|
+
// 把 .gypi 配置中的 target_arch 转换为 MSBuild 的 /Platform
|
|
36
|
+
// 因为表示"32 位 Intel"的方式很多,默认按此处理
|
|
37
|
+
// 注意:msbuild 的 Condition 字符串相等比较不区分大小写
|
|
38
|
+
const archLower = arch.toLowerCase(), p = archLower === 'x64' ? 'x64' : (archLower === 'arm' ? 'ARM'
|
|
39
|
+
: (archLower === 'arm64' ? 'ARM64' : 'Win32'));
|
|
40
|
+
argv.push('/p:Configuration=' + buildType + ';Platform=' + p)
|
|
41
|
+
if (jobs) {
|
|
42
|
+
j = parseInt(jobs, 10)
|
|
43
|
+
if (!isNaN(j) && j > 0) argv.push('/m:' + j);
|
|
44
|
+
else if (jobs.toUpperCase() === 'MAX') argv.push('/m:' + os.cpus().length);
|
|
157
45
|
}
|
|
158
46
|
}
|
|
159
|
-
} else {
|
|
160
|
-
argv.push('BUILDTYPE=' + buildType)
|
|
161
47
|
// 调用 build 目录下的 Makefile
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
argv.push('--jobs')
|
|
168
|
-
argv.push(j)
|
|
169
|
-
} else if (jobs.toUpperCase() === 'MAX') {
|
|
170
|
-
argv.push('--jobs')
|
|
171
|
-
argv.push(os.cpus().length)
|
|
48
|
+
else {
|
|
49
|
+
argv.push('BUILDTYPE=' + buildType), argv.push('-C'), argv.push('build');
|
|
50
|
+
if (jobs) {
|
|
51
|
+
j = parseInt(jobs, 10);
|
|
52
|
+
if (!isNaN(j) && j > 0) argv.push('--jobs'), argv.push(j);
|
|
53
|
+
else if (jobs.toUpperCase() === 'MAX') argv.push('--jobs'), argv.push(os.cpus().length);
|
|
172
54
|
}
|
|
173
55
|
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
if (win) {
|
|
177
|
-
// 用户是否指定了自己的 .sln 文件?
|
|
178
|
-
const hasSln = argv.some(function (arg) {
|
|
179
|
-
return path.extname(arg) === '.sln'
|
|
180
|
-
})
|
|
181
|
-
if (!hasSln) {
|
|
182
|
-
argv.unshift(gyp.opts.solution || guessedSolution)
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (!win) {
|
|
187
|
-
// 把构建期依赖的符号链接(如 Python)加入 PATH
|
|
188
|
-
buildBinsDir = path.resolve('build', 'node_gyp_bins')
|
|
189
|
-
process.env.PATH = `${buildBinsDir}:${process.env.PATH}`
|
|
190
|
-
await fs.mkdir(buildBinsDir, { recursive: true })
|
|
191
|
-
const symlinkDestination = path.join(buildBinsDir, 'python3')
|
|
192
|
-
try {
|
|
193
|
-
await fs.unlink(symlinkDestination)
|
|
194
|
-
} catch (err) {
|
|
195
|
-
if (err.code !== 'ENOENT') throw err
|
|
196
|
-
}
|
|
197
|
-
await fs.symlink(python, symlinkDestination)
|
|
198
|
-
log.verbose('bin symlinks', `created symlink to "${python}" in "${buildBinsDir}" and added to PATH`)
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const proc = gyp.spawn(command, argv)
|
|
202
|
-
await new Promise((resolve, reject) => proc.on('exit', async (code, signal) => {
|
|
203
|
-
if (buildBinsDir) {
|
|
204
|
-
// 清理构建期依赖的符号链接:
|
|
205
|
-
await fs.rm(buildBinsDir, { recursive: true })
|
|
206
|
-
}
|
|
207
56
|
|
|
208
|
-
if (
|
|
209
|
-
|
|
57
|
+
if (win) {
|
|
58
|
+
// 用户是否指定了自己的 .sln 文件?
|
|
59
|
+
const hasSln = argv.some(arg => path.extname(arg) === '.sln');
|
|
60
|
+
if (!hasSln) argv.unshift(gyp.opts.solution || guessedSolution);
|
|
210
61
|
}
|
|
211
|
-
|
|
212
|
-
|
|
62
|
+
|
|
63
|
+
if (!win) {
|
|
64
|
+
// 把构建期依赖的符号链接(如 Python)加入 PATH
|
|
65
|
+
buildBinsDir = path.resolve('build', 'node_gyp_bins');
|
|
66
|
+
process.env.PATH = `${buildBinsDir}:${process.env.PATH}`;
|
|
67
|
+
await fs.mkdir(buildBinsDir, { recursive: true });
|
|
68
|
+
const symlinkDestination = path.join(buildBinsDir, 'python3');
|
|
69
|
+
try {
|
|
70
|
+
await fs.unlink(symlinkDestination);
|
|
71
|
+
} catch (err) {
|
|
72
|
+
if (err.code !== 'ENOENT') throw err;
|
|
73
|
+
}
|
|
74
|
+
await fs.symlink(python, symlinkDestination);
|
|
75
|
+
log.verbose('bin symlinks', `created symlink to "${python}" in "${buildBinsDir}" and added to PATH`);
|
|
213
76
|
}
|
|
214
|
-
resolve()
|
|
215
|
-
}))
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
77
|
|
|
219
|
-
|
|
78
|
+
const proc = gyp.spawn(command, argv);
|
|
79
|
+
await new Promise((resolve, reject) => proc.on('exit', async (code, signal) => {
|
|
80
|
+
if (buildBinsDir) await fs.rm(buildBinsDir, { recursive: true }); // 清理构建期依赖的符号链接
|
|
81
|
+
|
|
82
|
+
if (code !== 0) return reject(new Error('`' + command + '` failed with exit code: ' + code));
|
|
83
|
+
if (signal) return reject(new Error('`' + command + '` got signal: ' + signal));
|
|
84
|
+
resolve();
|
|
85
|
+
}))
|
|
86
|
+
},
|
|
87
|
+
/**
|
|
88
|
+
* 用 node-which 定位 msbuild / make 可执行文件
|
|
89
|
+
*/
|
|
90
|
+
doWhich = async () => {
|
|
91
|
+
// Windows 使用 node-gyp configure 提供的 msbuild
|
|
92
|
+
if (win) {
|
|
93
|
+
if (!config.variables.msbuild_path) throw new Error('MSBuild 未设置,请先运行 `node-gyp configure`');
|
|
94
|
+
command = config.variables.msbuild_path, log.verbose('using MSBuild:', command), await doBuild();
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// 先确认构建命令在 PATH 中
|
|
99
|
+
const execPath = await which(command);
|
|
100
|
+
log.verbose('`which` succeeded for `' + command + '`', execPath), await doBuild();
|
|
101
|
+
},
|
|
102
|
+
/**
|
|
103
|
+
* Windows 下查找第一个 build/*.sln 文件
|
|
104
|
+
*/
|
|
105
|
+
findSolutionFile = async () => {
|
|
106
|
+
const files = await glob('build/*.sln')
|
|
107
|
+
if (files.length === 0) throw new Error('未找到 *.sln 文件,是否运行过 configure?');
|
|
108
|
+
guessedSolution = files[0], log.verbose('found first Solution file', guessedSolution), await doWhich();
|
|
109
|
+
},
|
|
110
|
+
/**
|
|
111
|
+
* 加载 configure 阶段生成的 config.gypi
|
|
112
|
+
*/
|
|
113
|
+
loadConfigGypi = async () => {
|
|
114
|
+
let data;
|
|
115
|
+
try {
|
|
116
|
+
const configPath = path.resolve('build', 'config.gypi');
|
|
117
|
+
data = await fs.readFile(configPath, 'utf8');
|
|
118
|
+
} catch (err) {
|
|
119
|
+
if (err.code === 'ENOENT') throw new Error('请先运行 `node-gyp configure`');
|
|
120
|
+
else throw err;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// 从 config 中取出 arch、buildType、nodeDir
|
|
124
|
+
config = JSON.parse(data.replace(/#.+\n/, '')), buildType = config.target_defaults.default_configuration;
|
|
125
|
+
arch = config.variables.target_arch, nodeDir = config.variables.nodedir, python = config.variables.python;
|
|
126
|
+
|
|
127
|
+
if ('debug' in gyp.opts) buildType = gyp.opts.debug ? 'Debug' : 'Release';
|
|
128
|
+
if (!buildType) buildType = 'Release';
|
|
129
|
+
|
|
130
|
+
log.verbose('build type', buildType), log.verbose('architecture', arch), log.verbose('node dev dir', nodeDir);
|
|
131
|
+
log.verbose('python', python);
|
|
132
|
+
|
|
133
|
+
win ? await findSolutionFile() : await doWhich();
|
|
134
|
+
};
|
|
135
|
+
await loadConfigGypi();
|
|
136
|
+
};
|
|
220
137
|
|
|
221
|
-
|
|
138
|
+
build.usage = 'Invokes `' + (win ? 'msbuild' : 'make') + '` and builds the module';
|
|
139
|
+
export { build };
|
package/lib/clean.js
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
|
-
import gracefulFs from 'graceful-fs'
|
|
2
|
-
import * as log from './log.js'
|
|
1
|
+
import gracefulFs from 'graceful-fs';
|
|
2
|
+
import * as log from './log.js';
|
|
3
3
|
|
|
4
|
-
const fs = gracefulFs.promises
|
|
4
|
+
const fs = gracefulFs.promises,
|
|
5
|
+
/**
|
|
6
|
+
* 清理:删除 build 目录
|
|
7
|
+
*/
|
|
8
|
+
clean = async (gyp, argv) => {
|
|
9
|
+
const buildDir = 'build';
|
|
5
10
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const clean = async (gyp, argv) => {
|
|
10
|
-
// 删除 build 目录
|
|
11
|
-
const buildDir = 'build'
|
|
11
|
+
log.verbose('clean', 'removing "%s" directory', buildDir);
|
|
12
|
+
await fs.rm(buildDir, { recursive: true, force: true });
|
|
13
|
+
}
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
clean.usage = 'Removes any generated build files and the "out" dir'
|
|
18
|
-
|
|
19
|
-
export { clean }
|
|
15
|
+
clean.usage = 'Removes any generated build files and the "out" dir';
|
|
16
|
+
export { clean };
|