@napi-rs/cli 3.0.0-alpha.1 → 3.0.0-alpha.100
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/cli.mjs +1 -1
- package/dist/api/__tests__/create-npm-dirs.spec.d.ts +1 -0
- package/dist/api/__tests__/new.spec.d.ts +1 -0
- package/dist/api/build.d.ts +2 -2
- package/dist/api/create-npm-dirs.d.ts +5 -0
- package/dist/api/templates/index.d.ts +0 -7
- package/dist/api/templates/js-binding.d.ts +2 -1
- package/dist/api/templates/load-wasi-template.d.ts +2 -0
- package/dist/api/templates/wasi-worker-template.d.ts +2 -0
- package/dist/cli.js +3961 -14
- package/dist/def/artifacts.d.ts +21 -1
- package/dist/def/build.d.ts +167 -4
- package/dist/def/create-npm-dirs.d.ts +10 -0
- package/dist/def/new.d.ts +25 -7
- package/dist/def/pre-publish.d.ts +21 -2
- package/dist/def/rename.d.ts +16 -6
- package/dist/def/universalize.d.ts +10 -0
- package/dist/def/version.d.ts +10 -0
- package/dist/index.cjs +10142 -20524
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3711 -29
- package/dist/utils/__tests__/config.spec.d.ts +1 -0
- package/dist/utils/config.d.ts +70 -6
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/metadata.d.ts +13 -1
- package/dist/utils/misc.d.ts +3 -3
- package/dist/utils/read-config.d.ts +7 -0
- package/dist/utils/target.d.ts +9 -6
- package/dist/utils/typegen.d.ts +4 -1
- package/dist/utils/version.d.ts +2 -1
- package/package.json +60 -24
- package/src/api/__tests__/create-npm-dirs.spec.ts +210 -0
- package/src/api/__tests__/new.spec.ts +429 -0
- package/src/api/artifacts.ts +83 -8
- package/src/api/build.ts +682 -134
- package/src/api/create-npm-dirs.ts +64 -13
- package/src/api/new.ts +389 -125
- package/src/api/pre-publish.ts +27 -16
- package/src/api/rename.ts +103 -17
- package/src/api/templates/index.ts +0 -7
- package/src/api/templates/js-binding.ts +212 -107
- package/src/api/templates/load-wasi-template.ts +216 -0
- package/src/api/templates/wasi-worker-template.ts +122 -0
- package/src/api/universalize.ts +13 -8
- package/src/api/version.ts +5 -2
- package/src/commands/artifacts.ts +2 -2
- package/src/commands/build.ts +1 -1
- package/src/commands/new.ts +46 -49
- package/src/def/artifacts.ts +22 -3
- package/src/def/build.ts +83 -8
- package/src/def/create-npm-dirs.ts +9 -0
- package/src/def/new.ts +28 -3
- package/src/def/pre-publish.ts +24 -3
- package/src/def/rename.ts +11 -2
- package/src/def/universalize.ts +9 -0
- package/src/def/version.ts +9 -0
- package/src/index.ts +2 -0
- package/src/utils/__tests__/__fixtures__/napi_type_def +130 -130
- package/src/utils/__tests__/__snapshots__/config.spec.ts.md +97 -0
- package/src/utils/__tests__/__snapshots__/config.spec.ts.snap +0 -0
- package/src/utils/__tests__/__snapshots__/target.spec.ts.md +56 -0
- package/src/utils/__tests__/__snapshots__/target.spec.ts.snap +0 -0
- package/src/utils/__tests__/__snapshots__/typegen.spec.ts.md +703 -164
- package/src/utils/__tests__/__snapshots__/typegen.spec.ts.snap +0 -0
- package/src/utils/__tests__/__snapshots__/version.spec.ts.md +9 -8
- package/src/utils/__tests__/__snapshots__/version.spec.ts.snap +0 -0
- package/src/utils/__tests__/config.spec.ts +81 -0
- package/src/utils/__tests__/typegen.spec.ts +19 -4
- package/src/utils/cargo.ts +2 -2
- package/src/utils/config.ts +147 -13
- package/src/utils/index.ts +1 -1
- package/src/utils/log.ts +1 -1
- package/src/utils/metadata.ts +52 -14
- package/src/utils/misc.ts +21 -7
- package/src/utils/read-config.ts +20 -0
- package/src/utils/target.ts +53 -9
- package/src/utils/typegen.ts +100 -40
- package/src/utils/version.ts +11 -9
- package/dist/api/artifacts.js +0 -50
- package/dist/api/build.js +0 -404
- package/dist/api/create-npm-dirs.js +0 -63
- package/dist/api/new.js +0 -154
- package/dist/api/pre-publish.js +0 -157
- package/dist/api/rename.js +0 -28
- package/dist/api/templates/.gitignore.d.ts +0 -1
- package/dist/api/templates/.gitignore.js +0 -198
- package/dist/api/templates/.npmignore.d.ts +0 -1
- package/dist/api/templates/.npmignore.js +0 -14
- package/dist/api/templates/build.rs.d.ts +0 -1
- package/dist/api/templates/build.rs.js +0 -4
- package/dist/api/templates/cargo.toml.d.ts +0 -6
- package/dist/api/templates/cargo.toml.js +0 -25
- package/dist/api/templates/ci-template.d.ts +0 -1
- package/dist/api/templates/ci-template.js +0 -566
- package/dist/api/templates/ci.yml.d.ts +0 -1
- package/dist/api/templates/ci.yml.js +0 -92
- package/dist/api/templates/index.js +0 -8
- package/dist/api/templates/js-binding.js +0 -124
- package/dist/api/templates/lib.rs.d.ts +0 -1
- package/dist/api/templates/lib.rs.js +0 -10
- package/dist/api/templates/package.json.d.ts +0 -8
- package/dist/api/templates/package.json.js +0 -30
- package/dist/api/universalize.js +0 -38
- package/dist/api/version.js +0 -16
- package/dist/commands/artifacts.js +0 -19
- package/dist/commands/build.js +0 -34
- package/dist/commands/create-npm-dirs.js +0 -7
- package/dist/commands/help.js +0 -12
- package/dist/commands/new.js +0 -112
- package/dist/commands/pre-publish.js +0 -8
- package/dist/commands/rename.js +0 -7
- package/dist/commands/universalize.js +0 -7
- package/dist/commands/version.js +0 -7
- package/dist/def/artifacts.js +0 -38
- package/dist/def/build.js +0 -105
- package/dist/def/commands/artifacts.d.ts +0 -15
- package/dist/def/commands/artifacts.js +0 -29
- package/dist/def/commands/build.d.ts +0 -53
- package/dist/def/commands/build.js +0 -105
- package/dist/def/commands/create-npm-dirs.d.ts +0 -15
- package/dist/def/commands/create-npm-dirs.js +0 -29
- package/dist/def/commands/new.d.ts +0 -27
- package/dist/def/commands/new.js +0 -53
- package/dist/def/commands/pre-publish.d.ts +0 -23
- package/dist/def/commands/pre-publish.js +0 -45
- package/dist/def/commands/rename.d.ts +0 -25
- package/dist/def/commands/rename.js +0 -49
- package/dist/def/commands/universalize.d.ts +0 -13
- package/dist/def/commands/universalize.js +0 -25
- package/dist/def/commands/version.d.ts +0 -13
- package/dist/def/commands/version.js +0 -25
- package/dist/def/create-npm-dirs.js +0 -38
- package/dist/def/new.js +0 -66
- package/dist/def/options/artifacts.d.ts +0 -35
- package/dist/def/options/artifacts.js +0 -11
- package/dist/def/options/build.d.ts +0 -97
- package/dist/def/options/build.js +0 -3
- package/dist/def/options/create-npm-dirs.d.ts +0 -35
- package/dist/def/options/create-npm-dirs.js +0 -11
- package/dist/def/options/new.d.ts +0 -79
- package/dist/def/options/new.js +0 -15
- package/dist/def/options/pre-publish.d.ts +0 -65
- package/dist/def/options/pre-publish.js +0 -13
- package/dist/def/options/rename.d.ts +0 -75
- package/dist/def/options/rename.js +0 -11
- package/dist/def/options/universalize.d.ts +0 -28
- package/dist/def/options/universalize.js +0 -10
- package/dist/def/options/version.d.ts +0 -28
- package/dist/def/options/version.js +0 -10
- package/dist/def/pre-publish.js +0 -56
- package/dist/def/rename.js +0 -58
- package/dist/def/universalize.js +0 -33
- package/dist/def/version.js +0 -33
- package/dist/utils/__tests__/target.spec.js +0 -10
- package/dist/utils/__tests__/typegen.spec.js +0 -37
- package/dist/utils/__tests__/version.spec.js +0 -5
- package/dist/utils/cargo.js +0 -33
- package/dist/utils/ci.d.ts +0 -11
- package/dist/utils/ci.js +0 -86
- package/dist/utils/config.js +0 -42
- package/dist/utils/index.js +0 -9
- package/dist/utils/log.js +0 -14
- package/dist/utils/metadata.js +0 -19
- package/dist/utils/misc.js +0 -35
- package/dist/utils/target.js +0 -109
- package/dist/utils/typegen.js +0 -158
- package/dist/utils/version.js +0 -59
- package/src/api/templates/.gitignore.ts +0 -198
- package/src/api/templates/.npmignore.ts +0 -14
- package/src/api/templates/build.rs.ts +0 -4
- package/src/api/templates/cargo.toml.ts +0 -35
- package/src/api/templates/ci-template.ts +0 -566
- package/src/api/templates/ci.yml.ts +0 -116
- package/src/api/templates/lib.rs.ts +0 -10
- package/src/api/templates/package.json.ts +0 -44
- package/src/utils/ci.ts +0 -102
package/src/api/build.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import { spawn } from 'child_process'
|
|
2
|
-
import { createHash } from 'crypto'
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { spawn } from 'node:child_process'
|
|
2
|
+
import { createHash } from 'node:crypto'
|
|
3
|
+
import { existsSync, mkdirSync, rmSync } from 'node:fs'
|
|
4
|
+
import { createRequire } from 'node:module'
|
|
5
|
+
import { homedir } from 'node:os'
|
|
6
|
+
import { parse, join, resolve } from 'node:path'
|
|
5
7
|
|
|
6
8
|
import * as colors from 'colorette'
|
|
9
|
+
import { include as setjmpInclude, lib as setjmpLib } from 'wasm-sjlj'
|
|
7
10
|
|
|
8
11
|
import { BuildOptions as RawBuildOptions } from '../def/build.js'
|
|
9
12
|
import {
|
|
@@ -20,39 +23,52 @@ import {
|
|
|
20
23
|
parseMetadata,
|
|
21
24
|
parseTriple,
|
|
22
25
|
processTypeDef,
|
|
26
|
+
readFileAsync,
|
|
23
27
|
readNapiConfig,
|
|
24
28
|
Target,
|
|
25
29
|
targetToEnvVar,
|
|
26
30
|
tryInstallCargoBinary,
|
|
27
31
|
unlinkAsync,
|
|
28
32
|
writeFileAsync,
|
|
33
|
+
dirExistsAsync,
|
|
34
|
+
readdirAsync,
|
|
35
|
+
CargoWorkspaceMetadata,
|
|
29
36
|
} from '../utils/index.js'
|
|
30
37
|
|
|
31
|
-
import {
|
|
38
|
+
import { createCjsBinding, createEsmBinding } from './templates/index.js'
|
|
39
|
+
import {
|
|
40
|
+
createWasiBinding,
|
|
41
|
+
createWasiBrowserBinding,
|
|
42
|
+
} from './templates/load-wasi-template.js'
|
|
43
|
+
import {
|
|
44
|
+
createWasiBrowserWorkerBinding,
|
|
45
|
+
WASI_WORKER_TEMPLATE,
|
|
46
|
+
} from './templates/wasi-worker-template.js'
|
|
32
47
|
|
|
33
48
|
const debug = debugFactory('build')
|
|
49
|
+
const require = createRequire(import.meta.url)
|
|
34
50
|
|
|
35
|
-
type OutputKind = 'js' | 'dts' | 'node' | 'exe'
|
|
36
|
-
type Output = {
|
|
37
|
-
kind: OutputKind
|
|
38
|
-
path: string
|
|
39
|
-
}
|
|
51
|
+
type OutputKind = 'js' | 'dts' | 'node' | 'exe' | 'wasm'
|
|
52
|
+
type Output = { kind: OutputKind; path: string }
|
|
40
53
|
|
|
41
|
-
type BuildOptions = RawBuildOptions & {
|
|
42
|
-
|
|
43
|
-
}
|
|
54
|
+
type BuildOptions = RawBuildOptions & { cargoOptions?: string[] }
|
|
55
|
+
type ParsedBuildOptions = Omit<BuildOptions, 'cwd'> & { cwd: string }
|
|
44
56
|
|
|
45
|
-
export async function buildProject(
|
|
46
|
-
debug('napi build command receive options: %O',
|
|
57
|
+
export async function buildProject(rawOptions: BuildOptions) {
|
|
58
|
+
debug('napi build command receive options: %O', rawOptions)
|
|
47
59
|
|
|
48
|
-
const
|
|
60
|
+
const options: ParsedBuildOptions = {
|
|
61
|
+
dtsCache: true,
|
|
62
|
+
...rawOptions,
|
|
63
|
+
cwd: rawOptions.cwd ?? process.cwd(),
|
|
64
|
+
}
|
|
49
65
|
|
|
50
|
-
const resolvePath = (...paths: string[]) => resolve(cwd, ...paths)
|
|
66
|
+
const resolvePath = (...paths: string[]) => resolve(options.cwd, ...paths)
|
|
51
67
|
|
|
52
68
|
const manifestPath = resolvePath(options.manifestPath ?? 'Cargo.toml')
|
|
53
|
-
const metadata = parseMetadata(manifestPath)
|
|
69
|
+
const metadata = await parseMetadata(manifestPath)
|
|
54
70
|
|
|
55
|
-
const
|
|
71
|
+
const crate = metadata.packages.find((p) => {
|
|
56
72
|
// package with given name
|
|
57
73
|
if (options.package) {
|
|
58
74
|
return p.name === options.package
|
|
@@ -61,33 +77,20 @@ export async function buildProject(options: BuildOptions) {
|
|
|
61
77
|
}
|
|
62
78
|
})
|
|
63
79
|
|
|
64
|
-
if (!
|
|
80
|
+
if (!crate) {
|
|
65
81
|
throw new Error(
|
|
66
82
|
'Unable to find crate to build. It seems you are trying to build a crate in a workspace, try using `--package` option to specify the package to build.',
|
|
67
83
|
)
|
|
68
84
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const builder = new Builder(
|
|
73
|
-
options,
|
|
74
|
-
pkg,
|
|
75
|
-
cwd,
|
|
76
|
-
options.target
|
|
77
|
-
? parseTriple(options.target)
|
|
78
|
-
: process.env.CARGO_BUILD_TARGET
|
|
79
|
-
? parseTriple(process.env.CARGO_BUILD_TARGET)
|
|
80
|
-
: getSystemDefaultTarget(),
|
|
81
|
-
crateDir,
|
|
82
|
-
resolvePath(options.outputDir ?? crateDir),
|
|
83
|
-
options.targetDir ??
|
|
84
|
-
process.env.CARGO_BUILD_TARGET_DIR ??
|
|
85
|
-
metadata.target_directory,
|
|
86
|
-
await readNapiConfig(
|
|
87
|
-
resolvePath(options.packageJsonPath ?? 'package.json'),
|
|
85
|
+
const config = await readNapiConfig(
|
|
86
|
+
resolvePath(
|
|
87
|
+
options.configPath ?? options.packageJsonPath ?? 'package.json',
|
|
88
88
|
),
|
|
89
|
+
options.configPath ? resolvePath(options.configPath) : undefined,
|
|
89
90
|
)
|
|
90
91
|
|
|
92
|
+
const builder = new Builder(metadata, crate, config, options)
|
|
93
|
+
|
|
91
94
|
return builder.build()
|
|
92
95
|
}
|
|
93
96
|
|
|
@@ -96,16 +99,57 @@ class Builder {
|
|
|
96
99
|
private readonly envs: Record<string, string> = {}
|
|
97
100
|
private readonly outputs: Output[] = []
|
|
98
101
|
|
|
102
|
+
private readonly target: Target
|
|
103
|
+
private readonly crateDir: string
|
|
104
|
+
private readonly outputDir: string
|
|
105
|
+
private readonly targetDir: string
|
|
106
|
+
private readonly enableTypeDef: boolean = false
|
|
107
|
+
|
|
99
108
|
constructor(
|
|
100
|
-
private readonly
|
|
109
|
+
private readonly metadata: CargoWorkspaceMetadata,
|
|
101
110
|
private readonly crate: Crate,
|
|
102
|
-
private readonly cwd: string,
|
|
103
|
-
private readonly target: Target,
|
|
104
|
-
private readonly crateDir: string,
|
|
105
|
-
private readonly outputDir: string,
|
|
106
|
-
private readonly targetDir: string,
|
|
107
111
|
private readonly config: NapiConfig,
|
|
108
|
-
|
|
112
|
+
private readonly options: ParsedBuildOptions,
|
|
113
|
+
) {
|
|
114
|
+
this.target = options.target
|
|
115
|
+
? parseTriple(options.target)
|
|
116
|
+
: process.env.CARGO_BUILD_TARGET
|
|
117
|
+
? parseTriple(process.env.CARGO_BUILD_TARGET)
|
|
118
|
+
: getSystemDefaultTarget()
|
|
119
|
+
this.crateDir = parse(crate.manifest_path).dir
|
|
120
|
+
this.outputDir = resolve(
|
|
121
|
+
this.options.cwd,
|
|
122
|
+
options.outputDir ?? this.crateDir,
|
|
123
|
+
)
|
|
124
|
+
this.targetDir =
|
|
125
|
+
options.targetDir ??
|
|
126
|
+
process.env.CARGO_BUILD_TARGET_DIR ??
|
|
127
|
+
metadata.target_directory
|
|
128
|
+
this.enableTypeDef = this.crate.dependencies.some(
|
|
129
|
+
(dep) =>
|
|
130
|
+
dep.name === 'napi-derive' &&
|
|
131
|
+
(dep.uses_default_features || dep.features.includes('type-def')),
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
if (!this.enableTypeDef) {
|
|
135
|
+
const requirementWarning =
|
|
136
|
+
'`napi-derive` crate is not used or `type-def` feature is not enabled for `napi-derive` crate'
|
|
137
|
+
debug.warn(
|
|
138
|
+
`${requirementWarning}. Will skip binding generation for \`.node\`, \`.wasi\` and \`.d.ts\` files.`,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
if (
|
|
142
|
+
this.options.dts ||
|
|
143
|
+
this.options.dtsHeader ||
|
|
144
|
+
this.config.dtsHeader ||
|
|
145
|
+
this.config.dtsHeaderFile
|
|
146
|
+
) {
|
|
147
|
+
debug.warn(
|
|
148
|
+
`${requirementWarning}. \`dts\` related options are enabled but will be ignored.`,
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
109
153
|
|
|
110
154
|
get cdyLibName() {
|
|
111
155
|
return this.crate.targets.find((t) => t.crate_types.includes('cdylib'))
|
|
@@ -138,25 +182,151 @@ class Builder {
|
|
|
138
182
|
.setPackage()
|
|
139
183
|
.setFeatures()
|
|
140
184
|
.setTarget()
|
|
185
|
+
.pickCrossToolchain()
|
|
141
186
|
.setEnvs()
|
|
142
187
|
.setBypassArgs()
|
|
143
188
|
.exec()
|
|
144
189
|
}
|
|
145
190
|
|
|
191
|
+
private pickCrossToolchain() {
|
|
192
|
+
if (!this.options.useNapiCross) {
|
|
193
|
+
return this
|
|
194
|
+
}
|
|
195
|
+
if (this.options.useCross) {
|
|
196
|
+
debug.warn(
|
|
197
|
+
'You are trying to use both `--cross` and `--use-napi-cross` options, `--use-cross` will be ignored.',
|
|
198
|
+
)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (this.options.crossCompile) {
|
|
202
|
+
debug.warn(
|
|
203
|
+
'You are trying to use both `--cross-compile` and `--use-napi-cross` options, `--cross-compile` will be ignored.',
|
|
204
|
+
)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
try {
|
|
208
|
+
const { version, download } = require('@napi-rs/cross-toolchain')
|
|
209
|
+
|
|
210
|
+
const alias: Record<string, string> = {
|
|
211
|
+
's390x-unknown-linux-gnu': 's390x-ibm-linux-gnu',
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const toolchainPath = join(
|
|
215
|
+
homedir(),
|
|
216
|
+
'.napi-rs',
|
|
217
|
+
'cross-toolchain',
|
|
218
|
+
version,
|
|
219
|
+
this.target.triple,
|
|
220
|
+
)
|
|
221
|
+
mkdirSync(toolchainPath, { recursive: true })
|
|
222
|
+
if (existsSync(join(toolchainPath, 'package.json'))) {
|
|
223
|
+
debug(`Toolchain ${toolchainPath} exists, skip extracting`)
|
|
224
|
+
} else {
|
|
225
|
+
const tarArchive = download(process.arch, this.target.triple)
|
|
226
|
+
tarArchive.unpack(toolchainPath)
|
|
227
|
+
}
|
|
228
|
+
const upperCaseTarget = targetToEnvVar(this.target.triple)
|
|
229
|
+
const crossTargetName = alias[this.target.triple] ?? this.target.triple
|
|
230
|
+
const linkerEnv = `CARGO_TARGET_${upperCaseTarget}_LINKER`
|
|
231
|
+
this.envs[linkerEnv] = join(
|
|
232
|
+
toolchainPath,
|
|
233
|
+
'bin',
|
|
234
|
+
`${crossTargetName}-gcc`,
|
|
235
|
+
)
|
|
236
|
+
if (!process.env.TARGET_SYSROOT) {
|
|
237
|
+
this.envs[`TARGET_SYSROOT`] = join(
|
|
238
|
+
toolchainPath,
|
|
239
|
+
crossTargetName,
|
|
240
|
+
'sysroot',
|
|
241
|
+
)
|
|
242
|
+
}
|
|
243
|
+
if (!process.env.TARGET_AR) {
|
|
244
|
+
this.envs[`TARGET_AR`] = join(
|
|
245
|
+
toolchainPath,
|
|
246
|
+
'bin',
|
|
247
|
+
`${crossTargetName}-ar`,
|
|
248
|
+
)
|
|
249
|
+
}
|
|
250
|
+
if (!process.env.TARGET_RANLIB) {
|
|
251
|
+
this.envs[`TARGET_RANLIB`] = join(
|
|
252
|
+
toolchainPath,
|
|
253
|
+
'bin',
|
|
254
|
+
`${crossTargetName}-ranlib`,
|
|
255
|
+
)
|
|
256
|
+
}
|
|
257
|
+
if (!process.env.TARGET_READELF) {
|
|
258
|
+
this.envs[`TARGET_READELF`] = join(
|
|
259
|
+
toolchainPath,
|
|
260
|
+
'bin',
|
|
261
|
+
`${crossTargetName}-readelf`,
|
|
262
|
+
)
|
|
263
|
+
}
|
|
264
|
+
if (!process.env.TARGET_C_INCLUDE_PATH) {
|
|
265
|
+
this.envs[`TARGET_C_INCLUDE_PATH`] = join(
|
|
266
|
+
toolchainPath,
|
|
267
|
+
crossTargetName,
|
|
268
|
+
'sysroot',
|
|
269
|
+
'usr',
|
|
270
|
+
'include/',
|
|
271
|
+
)
|
|
272
|
+
}
|
|
273
|
+
if (!process.env.TARGET_CC) {
|
|
274
|
+
this.envs[`TARGET_CC`] = join(
|
|
275
|
+
toolchainPath,
|
|
276
|
+
'bin',
|
|
277
|
+
`${crossTargetName}-gcc`,
|
|
278
|
+
)
|
|
279
|
+
}
|
|
280
|
+
if (!process.env.TARGET_CXX) {
|
|
281
|
+
this.envs[`TARGET_CXX`] = join(
|
|
282
|
+
toolchainPath,
|
|
283
|
+
'bin',
|
|
284
|
+
`${crossTargetName}-g++`,
|
|
285
|
+
)
|
|
286
|
+
}
|
|
287
|
+
if (
|
|
288
|
+
process.env.TARGET_CC?.startsWith('clang') ||
|
|
289
|
+
(process.env.CC?.startsWith('clang') && !process.env.TARGET_CC)
|
|
290
|
+
) {
|
|
291
|
+
const TARGET_CFLAGS = process.env.TARGET_CFLAGS ?? ''
|
|
292
|
+
this.envs.TARGET_CFLAGS = `--sysroot=${this.envs.TARGET_SYSROOT} --gcc-toolchain=${toolchainPath} ${TARGET_CFLAGS}`
|
|
293
|
+
}
|
|
294
|
+
if (
|
|
295
|
+
(process.env.CXX?.startsWith('clang++') && !process.env.TARGET_CXX) ||
|
|
296
|
+
process.env.TARGET_CXX?.startsWith('clang++')
|
|
297
|
+
) {
|
|
298
|
+
const TARGET_CXXFLAGS = process.env.TARGET_CXXFLAGS ?? ''
|
|
299
|
+
this.envs.TARGET_CXXFLAGS = `--sysroot=${this.envs.TARGET_SYSROOT} --gcc-toolchain=${toolchainPath} ${TARGET_CXXFLAGS}`
|
|
300
|
+
}
|
|
301
|
+
this.envs.PATH = this.envs.PATH
|
|
302
|
+
? `${toolchainPath}/bin:${this.envs.PATH}:${process.env.PATH}`
|
|
303
|
+
: `${toolchainPath}/bin:${process.env.PATH}`
|
|
304
|
+
} catch (e) {
|
|
305
|
+
debug.warn('Pick cross toolchain failed', e as Error)
|
|
306
|
+
// ignore, do nothing
|
|
307
|
+
}
|
|
308
|
+
return this
|
|
309
|
+
}
|
|
310
|
+
|
|
146
311
|
private exec() {
|
|
147
312
|
debug(`Start building crate: ${this.crate.name}`)
|
|
148
313
|
debug(' %i', `cargo ${this.args.join(' ')}`)
|
|
149
314
|
|
|
150
315
|
const controller = new AbortController()
|
|
151
316
|
|
|
317
|
+
const watch = this.options.watch
|
|
152
318
|
const buildTask = new Promise<void>((resolve, reject) => {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
319
|
+
if (this.options.useCross && this.options.crossCompile) {
|
|
320
|
+
throw new Error(
|
|
321
|
+
'`--use-cross` and `--cross-compile` can not be used together',
|
|
322
|
+
)
|
|
323
|
+
}
|
|
324
|
+
const command =
|
|
325
|
+
process.env.CARGO ?? (this.options.useCross ? 'cross' : 'cargo')
|
|
326
|
+
const buildProcess = spawn(command, this.args, {
|
|
327
|
+
env: { ...process.env, ...this.envs },
|
|
328
|
+
stdio: watch ? ['inherit', 'inherit', 'pipe'] : 'inherit',
|
|
329
|
+
cwd: this.options.cwd,
|
|
160
330
|
signal: controller.signal,
|
|
161
331
|
})
|
|
162
332
|
|
|
@@ -170,11 +340,16 @@ class Builder {
|
|
|
170
340
|
})
|
|
171
341
|
|
|
172
342
|
buildProcess.once('error', (e) => {
|
|
173
|
-
reject(
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
343
|
+
reject(new Error(`Build failed with error: ${e.message}`, { cause: e }))
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
// watch mode only, they are piped through stderr
|
|
347
|
+
buildProcess.stderr?.on('data', (data) => {
|
|
348
|
+
const output = data.toString()
|
|
349
|
+
console.error(output)
|
|
350
|
+
if (/Finished\s(`dev`|`release`)/.test(output)) {
|
|
351
|
+
this.postBuild().catch(() => {})
|
|
352
|
+
}
|
|
178
353
|
})
|
|
179
354
|
})
|
|
180
355
|
|
|
@@ -205,6 +380,7 @@ class Builder {
|
|
|
205
380
|
this.crateDir,
|
|
206
381
|
'--',
|
|
207
382
|
'cargo',
|
|
383
|
+
'build',
|
|
208
384
|
)
|
|
209
385
|
set = true
|
|
210
386
|
}
|
|
@@ -295,9 +471,12 @@ class Builder {
|
|
|
295
471
|
}
|
|
296
472
|
|
|
297
473
|
private setEnvs() {
|
|
298
|
-
//
|
|
299
|
-
|
|
300
|
-
|
|
474
|
+
// TYPE DEF
|
|
475
|
+
if (this.enableTypeDef) {
|
|
476
|
+
this.envs.NAPI_TYPE_DEF_TMP_FOLDER =
|
|
477
|
+
this.generateIntermediateTypeDefFolder()
|
|
478
|
+
this.setForceBuildEnvs(this.envs.NAPI_TYPE_DEF_TMP_FOLDER)
|
|
479
|
+
}
|
|
301
480
|
|
|
302
481
|
// RUSTFLAGS
|
|
303
482
|
let rustflags =
|
|
@@ -320,39 +499,31 @@ class Builder {
|
|
|
320
499
|
// END RUSTFLAGS
|
|
321
500
|
|
|
322
501
|
// LINKER
|
|
323
|
-
const linker =
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
502
|
+
const linker = this.options.crossCompile
|
|
503
|
+
? void 0
|
|
504
|
+
: getTargetLinker(this.target.triple)
|
|
505
|
+
// TODO:
|
|
506
|
+
// directly set CARGO_TARGET_<target>_LINKER will cover .cargo/config.toml
|
|
507
|
+
// will detect by cargo config when it becomes stable
|
|
508
|
+
// see: https://github.com/rust-lang/cargo/issues/9301
|
|
509
|
+
const linkerEnv = `CARGO_TARGET_${targetToEnvVar(
|
|
510
|
+
this.target.triple,
|
|
511
|
+
)}_LINKER`
|
|
512
|
+
if (linker && !process.env[linkerEnv] && !this.envs[linkerEnv]) {
|
|
513
|
+
this.envs[linkerEnv] = linker
|
|
330
514
|
}
|
|
331
515
|
|
|
332
516
|
if (this.target.platform === 'android') {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
debug.warn(
|
|
336
|
-
`${colors.red(
|
|
337
|
-
'ANDROID_NDK_LATEST_HOME',
|
|
338
|
-
)} environment variable is missing`,
|
|
339
|
-
)
|
|
340
|
-
}
|
|
517
|
+
this.setAndroidEnv()
|
|
518
|
+
}
|
|
341
519
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
CC: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang`,
|
|
349
|
-
CXX: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang++`,
|
|
350
|
-
AR: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ar`,
|
|
351
|
-
ANDROID_NDK: ANDROID_NDK_LATEST_HOME,
|
|
352
|
-
PATH: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin:${process.env.PATH}`,
|
|
353
|
-
})
|
|
520
|
+
if (this.target.platform === 'wasi') {
|
|
521
|
+
this.setWasiEnv()
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
if (this.target.platform === 'openharmony') {
|
|
525
|
+
this.setOpenHarmonyEnv()
|
|
354
526
|
}
|
|
355
|
-
// END LINKER
|
|
356
527
|
|
|
357
528
|
debug('Set envs: ')
|
|
358
529
|
Object.entries(this.envs).forEach(([k, v]) => {
|
|
@@ -362,13 +533,168 @@ class Builder {
|
|
|
362
533
|
return this
|
|
363
534
|
}
|
|
364
535
|
|
|
536
|
+
private setForceBuildEnvs(typeDefTmpFolder: string) {
|
|
537
|
+
// dynamically check all napi-rs deps and set `NAPI_FORCE_BUILD_{uppercase(snake_case(name))} = timestamp`
|
|
538
|
+
this.metadata.packages.forEach((crate) => {
|
|
539
|
+
if (
|
|
540
|
+
crate.dependencies.some((d) => d.name === 'napi-derive') &&
|
|
541
|
+
!existsSync(join(typeDefTmpFolder, crate.name))
|
|
542
|
+
) {
|
|
543
|
+
this.envs[
|
|
544
|
+
`NAPI_FORCE_BUILD_${crate.name.replace(/-/g, '_').toUpperCase()}`
|
|
545
|
+
] = Date.now().toString()
|
|
546
|
+
}
|
|
547
|
+
})
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
private setAndroidEnv() {
|
|
551
|
+
const { ANDROID_NDK_LATEST_HOME } = process.env
|
|
552
|
+
if (!ANDROID_NDK_LATEST_HOME) {
|
|
553
|
+
debug.warn(
|
|
554
|
+
`${colors.red(
|
|
555
|
+
'ANDROID_NDK_LATEST_HOME',
|
|
556
|
+
)} environment variable is missing`,
|
|
557
|
+
)
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// skip cross compile setup if host is android
|
|
561
|
+
if (process.platform === 'android') {
|
|
562
|
+
return
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
const targetArch = this.target.arch === 'arm' ? 'armv7a' : 'aarch64'
|
|
566
|
+
const targetPlatform =
|
|
567
|
+
this.target.arch === 'arm' ? 'androideabi24' : 'android24'
|
|
568
|
+
const hostPlatform =
|
|
569
|
+
process.platform === 'darwin'
|
|
570
|
+
? 'darwin'
|
|
571
|
+
: process.platform === 'win32'
|
|
572
|
+
? 'windows'
|
|
573
|
+
: 'linux'
|
|
574
|
+
Object.assign(this.envs, {
|
|
575
|
+
CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-android24-clang`,
|
|
576
|
+
CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-androideabi24-clang`,
|
|
577
|
+
TARGET_CC: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang`,
|
|
578
|
+
TARGET_CXX: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang++`,
|
|
579
|
+
TARGET_AR: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/llvm-ar`,
|
|
580
|
+
TARGET_RANLIB: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/llvm-ranlib`,
|
|
581
|
+
ANDROID_NDK: ANDROID_NDK_LATEST_HOME,
|
|
582
|
+
PATH: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin${process.platform === 'win32' ? ';' : ':'}${process.env.PATH}`,
|
|
583
|
+
})
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
private setWasiEnv() {
|
|
587
|
+
const emnapi = join(
|
|
588
|
+
require.resolve('emnapi'),
|
|
589
|
+
'..',
|
|
590
|
+
'lib',
|
|
591
|
+
'wasm32-wasi-threads',
|
|
592
|
+
)
|
|
593
|
+
this.envs.EMNAPI_LINK_DIR = emnapi
|
|
594
|
+
this.envs.SETJMP_LINK_DIR = setjmpLib
|
|
595
|
+
const { WASI_SDK_PATH } = process.env
|
|
596
|
+
|
|
597
|
+
if (WASI_SDK_PATH && existsSync(WASI_SDK_PATH)) {
|
|
598
|
+
this.envs.CARGO_TARGET_WASM32_WASI_PREVIEW1_THREADS_LINKER = join(
|
|
599
|
+
WASI_SDK_PATH,
|
|
600
|
+
'bin',
|
|
601
|
+
'wasm-ld',
|
|
602
|
+
)
|
|
603
|
+
this.envs.CARGO_TARGET_WASM32_WASIP1_LINKER = join(
|
|
604
|
+
WASI_SDK_PATH,
|
|
605
|
+
'bin',
|
|
606
|
+
'wasm-ld',
|
|
607
|
+
)
|
|
608
|
+
this.envs.CARGO_TARGET_WASM32_WASIP1_THREADS_LINKER = join(
|
|
609
|
+
WASI_SDK_PATH,
|
|
610
|
+
'bin',
|
|
611
|
+
'wasm-ld',
|
|
612
|
+
)
|
|
613
|
+
this.envs.CARGO_TARGET_WASM32_WASIP2_LINKER = join(
|
|
614
|
+
WASI_SDK_PATH,
|
|
615
|
+
'bin',
|
|
616
|
+
'wasm-ld',
|
|
617
|
+
)
|
|
618
|
+
this.setEnvIfNotExists('TARGET_CC', join(WASI_SDK_PATH, 'bin', 'clang'))
|
|
619
|
+
this.setEnvIfNotExists(
|
|
620
|
+
'TARGET_CXX',
|
|
621
|
+
join(WASI_SDK_PATH, 'bin', 'clang++'),
|
|
622
|
+
)
|
|
623
|
+
this.setEnvIfNotExists('TARGET_AR', join(WASI_SDK_PATH, 'bin', 'ar'))
|
|
624
|
+
this.setEnvIfNotExists(
|
|
625
|
+
'TARGET_RANLIB',
|
|
626
|
+
join(WASI_SDK_PATH, 'bin', 'ranlib'),
|
|
627
|
+
)
|
|
628
|
+
this.setEnvIfNotExists(
|
|
629
|
+
'TARGET_CFLAGS',
|
|
630
|
+
`--target=wasm32-wasi-threads --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot -pthread -mllvm -wasm-enable-sjlj -I${setjmpInclude}`,
|
|
631
|
+
)
|
|
632
|
+
this.setEnvIfNotExists(
|
|
633
|
+
'TARGET_CXXFLAGS',
|
|
634
|
+
`--target=wasm32-wasi-threads --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot -pthread -mllvm -wasm-enable-sjlj -I${setjmpInclude}`,
|
|
635
|
+
)
|
|
636
|
+
this.setEnvIfNotExists(
|
|
637
|
+
`TARGET_LDFLAGS`,
|
|
638
|
+
`-fuse-ld=${WASI_SDK_PATH}/bin/wasm-ld --target=wasm32-wasi-threads`,
|
|
639
|
+
)
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
private setOpenHarmonyEnv() {
|
|
644
|
+
const { OHOS_SDK_PATH, OHOS_SDK_NATIVE } = process.env
|
|
645
|
+
const ndkPath = OHOS_SDK_PATH
|
|
646
|
+
? `${OHOS_SDK_NATIVE}/native`
|
|
647
|
+
: OHOS_SDK_NATIVE
|
|
648
|
+
// @ts-expect-error
|
|
649
|
+
if (!ndkPath && process.platform !== 'openharmony') {
|
|
650
|
+
debug.warn(
|
|
651
|
+
`${colors.red('OHOS_SDK_PATH')} or ${colors.red('OHOS_SDK_NATIVE')} environment variable is missing`,
|
|
652
|
+
)
|
|
653
|
+
return
|
|
654
|
+
}
|
|
655
|
+
const linkerName = `CARGO_TARGET_${this.target.triple.toUpperCase().replace(/-/g, '_')}_LINKER`
|
|
656
|
+
const ranPath = `${ndkPath}/llvm/bin/llvm-ranlib`
|
|
657
|
+
const arPath = `${ndkPath}/llvm/bin/llvm-ar`
|
|
658
|
+
const ccPath = `${ndkPath}/llvm/bin/${this.target.triple}-clang`
|
|
659
|
+
const cxxPath = `${ndkPath}/llvm/bin/${this.target.triple}-clang++`
|
|
660
|
+
const asPath = `${ndkPath}/llvm/bin/llvm-as`
|
|
661
|
+
const ldPath = `${ndkPath}/llvm/bin/ld.lld`
|
|
662
|
+
const stripPath = `${ndkPath}/llvm/bin/llvm-strip`
|
|
663
|
+
const objDumpPath = `${ndkPath}/llvm/bin/llvm-objdump`
|
|
664
|
+
const objCopyPath = `${ndkPath}/llvm/bin/llvm-objcopy`
|
|
665
|
+
const nmPath = `${ndkPath}/llvm/bin/llvm-nm`
|
|
666
|
+
const binPath = `${ndkPath}/llvm/bin`
|
|
667
|
+
const libPath = `${ndkPath}/llvm/lib`
|
|
668
|
+
|
|
669
|
+
this.setEnvIfNotExists('LIBCLANG_PATH', libPath)
|
|
670
|
+
this.setEnvIfNotExists('DEP_ATOMIC', 'clang_rt.builtins')
|
|
671
|
+
this.setEnvIfNotExists(linkerName, ccPath)
|
|
672
|
+
this.setEnvIfNotExists('TARGET_CC', ccPath)
|
|
673
|
+
this.setEnvIfNotExists('TARGET_CXX', cxxPath)
|
|
674
|
+
this.setEnvIfNotExists('TARGET_AR', arPath)
|
|
675
|
+
this.setEnvIfNotExists('TARGET_RANLIB', ranPath)
|
|
676
|
+
this.setEnvIfNotExists('TARGET_AS', asPath)
|
|
677
|
+
this.setEnvIfNotExists('TARGET_LD', ldPath)
|
|
678
|
+
this.setEnvIfNotExists('TARGET_STRIP', stripPath)
|
|
679
|
+
this.setEnvIfNotExists('TARGET_OBJDUMP', objDumpPath)
|
|
680
|
+
this.setEnvIfNotExists('TARGET_OBJCOPY', objCopyPath)
|
|
681
|
+
this.setEnvIfNotExists('TARGET_NM', nmPath)
|
|
682
|
+
this.envs.PATH = `${binPath}${process.platform === 'win32' ? ';' : ':'}${process.env.PATH}`
|
|
683
|
+
}
|
|
684
|
+
|
|
365
685
|
private setFeatures() {
|
|
366
686
|
const args = []
|
|
687
|
+
if (this.options.allFeatures && this.options.noDefaultFeatures) {
|
|
688
|
+
throw new Error(
|
|
689
|
+
'Cannot specify --all-features and --no-default-features together',
|
|
690
|
+
)
|
|
691
|
+
}
|
|
367
692
|
if (this.options.allFeatures) {
|
|
368
693
|
args.push('--all-features')
|
|
369
694
|
} else if (this.options.noDefaultFeatures) {
|
|
370
695
|
args.push('--no-default-features')
|
|
371
|
-
}
|
|
696
|
+
}
|
|
697
|
+
if (this.options.features) {
|
|
372
698
|
args.push('--features', ...this.options.features)
|
|
373
699
|
}
|
|
374
700
|
|
|
@@ -392,6 +718,14 @@ class Builder {
|
|
|
392
718
|
this.args.push('--target-dir', this.options.targetDir)
|
|
393
719
|
}
|
|
394
720
|
|
|
721
|
+
if (this.options.profile) {
|
|
722
|
+
this.args.push('--profile', this.options.profile)
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
if (this.options.manifestPath) {
|
|
726
|
+
this.args.push('--manifest-path', this.options.manifestPath)
|
|
727
|
+
}
|
|
728
|
+
|
|
395
729
|
if (this.options.cargoOptions?.length) {
|
|
396
730
|
this.args.push(...this.options.cargoOptions)
|
|
397
731
|
}
|
|
@@ -399,15 +733,25 @@ class Builder {
|
|
|
399
733
|
return this
|
|
400
734
|
}
|
|
401
735
|
|
|
402
|
-
private
|
|
403
|
-
|
|
404
|
-
|
|
736
|
+
private generateIntermediateTypeDefFolder() {
|
|
737
|
+
let folder = join(
|
|
738
|
+
this.targetDir,
|
|
739
|
+
'napi-rs',
|
|
405
740
|
`${this.crate.name}-${createHash('sha256')
|
|
406
741
|
.update(this.crate.manifest_path)
|
|
407
742
|
.update(CLI_VERSION)
|
|
408
743
|
.digest('hex')
|
|
409
|
-
.substring(0, 8)}
|
|
744
|
+
.substring(0, 8)}`,
|
|
410
745
|
)
|
|
746
|
+
|
|
747
|
+
if (!this.options.dtsCache) {
|
|
748
|
+
rmSync(folder, { recursive: true, force: true })
|
|
749
|
+
folder += `_${Date.now()}`
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
mkdirAsync(folder, { recursive: true })
|
|
753
|
+
|
|
754
|
+
return folder
|
|
411
755
|
}
|
|
412
756
|
|
|
413
757
|
private async postBuild() {
|
|
@@ -422,30 +766,39 @@ class Builder {
|
|
|
422
766
|
})
|
|
423
767
|
}
|
|
424
768
|
|
|
425
|
-
await this.copyArtifact()
|
|
769
|
+
const wasmBinaryName = await this.copyArtifact()
|
|
426
770
|
|
|
427
771
|
// only for cdylib
|
|
428
772
|
if (this.cdyLibName) {
|
|
429
|
-
await this.generateTypeDef()
|
|
430
|
-
await this.writeJsBinding()
|
|
773
|
+
const idents = await this.generateTypeDef()
|
|
774
|
+
const jsOutput = await this.writeJsBinding(idents)
|
|
775
|
+
const wasmBindingsOutput = await this.writeWasiBinding(
|
|
776
|
+
wasmBinaryName,
|
|
777
|
+
idents,
|
|
778
|
+
)
|
|
779
|
+
if (jsOutput) {
|
|
780
|
+
this.outputs.push(jsOutput)
|
|
781
|
+
}
|
|
782
|
+
if (wasmBindingsOutput) {
|
|
783
|
+
this.outputs.push(...wasmBindingsOutput)
|
|
784
|
+
}
|
|
431
785
|
}
|
|
432
786
|
|
|
433
787
|
return this.outputs
|
|
434
788
|
}
|
|
435
789
|
|
|
436
790
|
private async copyArtifact() {
|
|
437
|
-
const [srcName, destName] = this.getArtifactNames()
|
|
791
|
+
const [srcName, destName, wasmBinaryName] = this.getArtifactNames()
|
|
438
792
|
if (!srcName || !destName) {
|
|
439
793
|
return
|
|
440
794
|
}
|
|
441
795
|
|
|
442
|
-
const
|
|
443
|
-
this.
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
srcName,
|
|
447
|
-
)
|
|
796
|
+
const profile =
|
|
797
|
+
this.options.profile ?? (this.options.release ? 'release' : 'debug')
|
|
798
|
+
const src = join(this.targetDir, this.target.triple, profile, srcName)
|
|
799
|
+
debug(`Copy artifact from: [${src}]`)
|
|
448
800
|
const dest = join(this.outputDir, destName)
|
|
801
|
+
const isWasm = dest.endsWith('.wasm')
|
|
449
802
|
|
|
450
803
|
try {
|
|
451
804
|
if (await fileExists(dest)) {
|
|
@@ -454,28 +807,65 @@ class Builder {
|
|
|
454
807
|
}
|
|
455
808
|
debug('Copy artifact to:')
|
|
456
809
|
debug(' %i', dest)
|
|
457
|
-
|
|
810
|
+
if (isWasm) {
|
|
811
|
+
const { ModuleConfig } = await import('@napi-rs/wasm-tools')
|
|
812
|
+
debug('Generate debug wasm module')
|
|
813
|
+
try {
|
|
814
|
+
const debugWasmModule = new ModuleConfig()
|
|
815
|
+
.generateDwarf(true)
|
|
816
|
+
.generateNameSection(true)
|
|
817
|
+
.generateProducersSection(true)
|
|
818
|
+
.preserveCodeTransform(true)
|
|
819
|
+
.strictValidate(false)
|
|
820
|
+
.parse(await readFileAsync(src))
|
|
821
|
+
const debugWasmBinary = debugWasmModule.emitWasm(true)
|
|
822
|
+
await writeFileAsync(
|
|
823
|
+
dest.replace(/\.wasm$/, '.debug.wasm'),
|
|
824
|
+
debugWasmBinary,
|
|
825
|
+
)
|
|
826
|
+
debug('Generate release wasm module')
|
|
827
|
+
const releaseWasmModule = new ModuleConfig()
|
|
828
|
+
.generateDwarf(false)
|
|
829
|
+
.generateNameSection(false)
|
|
830
|
+
.generateProducersSection(false)
|
|
831
|
+
.preserveCodeTransform(false)
|
|
832
|
+
.strictValidate(false)
|
|
833
|
+
.onlyStableFeatures(false)
|
|
834
|
+
.parse(debugWasmBinary)
|
|
835
|
+
const releaseWasmBinary = releaseWasmModule.emitWasm(false)
|
|
836
|
+
await writeFileAsync(dest, releaseWasmBinary)
|
|
837
|
+
} catch (e) {
|
|
838
|
+
debug.warn(
|
|
839
|
+
`Failed to generate debug wasm module: ${(e as any).message ?? e}`,
|
|
840
|
+
)
|
|
841
|
+
await copyFileAsync(src, dest)
|
|
842
|
+
}
|
|
843
|
+
} else {
|
|
844
|
+
await copyFileAsync(src, dest)
|
|
845
|
+
}
|
|
458
846
|
this.outputs.push({
|
|
459
|
-
kind: dest.endsWith('.node') ? 'node' : 'exe',
|
|
847
|
+
kind: dest.endsWith('.node') ? 'node' : isWasm ? 'wasm' : 'exe',
|
|
460
848
|
path: dest,
|
|
461
849
|
})
|
|
850
|
+
return wasmBinaryName ? join(this.outputDir, wasmBinaryName) : null
|
|
462
851
|
} catch (e) {
|
|
463
|
-
throw new Error('Failed to copy artifact', {
|
|
464
|
-
cause: e,
|
|
465
|
-
})
|
|
852
|
+
throw new Error('Failed to copy artifact', { cause: e })
|
|
466
853
|
}
|
|
467
854
|
}
|
|
468
855
|
|
|
469
856
|
private getArtifactNames() {
|
|
470
857
|
if (this.cdyLibName) {
|
|
471
858
|
const cdyLib = this.cdyLibName.replace(/-/g, '_')
|
|
859
|
+
const wasiTarget = this.config.targets.find((t) => t.platform === 'wasi')
|
|
472
860
|
|
|
473
861
|
const srcName =
|
|
474
862
|
this.target.platform === 'darwin'
|
|
475
863
|
? `lib${cdyLib}.dylib`
|
|
476
864
|
: this.target.platform === 'win32'
|
|
477
|
-
|
|
478
|
-
|
|
865
|
+
? `${cdyLib}.dll`
|
|
866
|
+
: this.target.platform === 'wasi' || this.target.platform === 'wasm'
|
|
867
|
+
? `${cdyLib}.wasm`
|
|
868
|
+
: `lib${cdyLib}.so`
|
|
479
869
|
|
|
480
870
|
let destName = this.config.binaryName
|
|
481
871
|
// add platform suffix to binary name
|
|
@@ -484,9 +874,19 @@ class Builder {
|
|
|
484
874
|
if (this.options.platform) {
|
|
485
875
|
destName += `.${this.target.platformArchABI}`
|
|
486
876
|
}
|
|
487
|
-
|
|
877
|
+
if (srcName.endsWith('.wasm')) {
|
|
878
|
+
destName += '.wasm'
|
|
879
|
+
} else {
|
|
880
|
+
destName += '.node'
|
|
881
|
+
}
|
|
488
882
|
|
|
489
|
-
return [
|
|
883
|
+
return [
|
|
884
|
+
srcName,
|
|
885
|
+
destName,
|
|
886
|
+
wasiTarget
|
|
887
|
+
? `${this.config.binaryName}.${wasiTarget.platformArchABI}.wasm`
|
|
888
|
+
: null,
|
|
889
|
+
]
|
|
490
890
|
} else if (this.binName) {
|
|
491
891
|
const srcName =
|
|
492
892
|
this.target.platform === 'win32' ? `${this.binName}.exe` : this.binName
|
|
@@ -498,52 +898,200 @@ class Builder {
|
|
|
498
898
|
}
|
|
499
899
|
|
|
500
900
|
private async generateTypeDef() {
|
|
501
|
-
|
|
502
|
-
|
|
901
|
+
const typeDefDir = this.envs.NAPI_TYPE_DEF_TMP_FOLDER
|
|
902
|
+
if (!this.enableTypeDef || !(await dirExistsAsync(typeDefDir))) {
|
|
903
|
+
return []
|
|
503
904
|
}
|
|
504
905
|
|
|
505
906
|
const dest = join(this.outputDir, this.options.dts ?? 'index.d.ts')
|
|
506
907
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
908
|
+
let header = ''
|
|
909
|
+
let dts = ''
|
|
910
|
+
let exports: string[] = []
|
|
911
|
+
|
|
912
|
+
if (!this.options.noDtsHeader) {
|
|
913
|
+
const dtsHeader = this.options.dtsHeader ?? this.config.dtsHeader
|
|
914
|
+
// `dtsHeaderFile` in config > `dtsHeader` in cli flag > `dtsHeader` in config
|
|
915
|
+
if (this.config.dtsHeaderFile) {
|
|
916
|
+
try {
|
|
917
|
+
header = await readFileAsync(
|
|
918
|
+
join(this.options.cwd, this.config.dtsHeaderFile),
|
|
919
|
+
'utf-8',
|
|
920
|
+
)
|
|
921
|
+
} catch (e) {
|
|
922
|
+
debug.warn(
|
|
923
|
+
`Failed to read dts header file ${this.config.dtsHeaderFile}`,
|
|
924
|
+
e,
|
|
925
|
+
)
|
|
926
|
+
}
|
|
927
|
+
} else if (dtsHeader) {
|
|
928
|
+
header = dtsHeader
|
|
929
|
+
} else {
|
|
930
|
+
header = DEFAULT_TYPE_DEF_HEADER
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
const files = await readdirAsync(typeDefDir, { withFileTypes: true })
|
|
935
|
+
|
|
936
|
+
if (!files.length) {
|
|
937
|
+
debug('No type def files found. Skip generating dts file.')
|
|
938
|
+
return []
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
for (const file of files) {
|
|
942
|
+
if (!file.isFile()) {
|
|
943
|
+
continue
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
const { dts: fileDts, exports: fileExports } = await processTypeDef(
|
|
947
|
+
join(typeDefDir, file.name),
|
|
948
|
+
this.options.constEnum ?? this.config.constEnum ?? true,
|
|
949
|
+
)
|
|
950
|
+
|
|
951
|
+
dts += fileDts
|
|
952
|
+
exports.push(...fileExports)
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
if (dts.indexOf('ExternalObject<') > -1) {
|
|
956
|
+
header += `
|
|
957
|
+
export declare class ExternalObject<T> {
|
|
958
|
+
readonly '': {
|
|
959
|
+
readonly '': unique symbol
|
|
960
|
+
[K: symbol]: T
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
`
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
if (dts.indexOf('TypedArray') > -1) {
|
|
967
|
+
header += `
|
|
968
|
+
export type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array
|
|
969
|
+
`
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
dts = header + dts
|
|
513
973
|
|
|
514
974
|
try {
|
|
515
975
|
debug('Writing type def to:')
|
|
516
976
|
debug(' %i', dest)
|
|
517
977
|
await writeFileAsync(dest, dts, 'utf-8')
|
|
518
|
-
this.outputs.push({
|
|
519
|
-
kind: 'dts',
|
|
520
|
-
path: dest,
|
|
521
|
-
})
|
|
978
|
+
this.outputs.push({ kind: 'dts', path: dest })
|
|
522
979
|
} catch (e) {
|
|
523
980
|
debug.error('Failed to write type def file')
|
|
524
981
|
debug.error(e as Error)
|
|
525
982
|
}
|
|
983
|
+
|
|
984
|
+
return exports
|
|
526
985
|
}
|
|
527
986
|
|
|
528
|
-
private async writeJsBinding() {
|
|
529
|
-
if (
|
|
987
|
+
private async writeJsBinding(idents: string[]) {
|
|
988
|
+
if (
|
|
989
|
+
!this.options.platform ||
|
|
990
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
991
|
+
this.options.noJsBinding ||
|
|
992
|
+
idents.length === 0
|
|
993
|
+
) {
|
|
530
994
|
return
|
|
531
995
|
}
|
|
532
996
|
|
|
533
|
-
const
|
|
997
|
+
const name = this.options.jsBinding ?? 'index.js'
|
|
534
998
|
|
|
535
|
-
const
|
|
999
|
+
const createBinding = this.options.esm ? createEsmBinding : createCjsBinding
|
|
1000
|
+
const binding = createBinding(
|
|
1001
|
+
this.config.binaryName,
|
|
1002
|
+
this.config.packageName,
|
|
1003
|
+
idents,
|
|
1004
|
+
)
|
|
536
1005
|
|
|
537
1006
|
try {
|
|
1007
|
+
const dest = join(this.outputDir, name)
|
|
538
1008
|
debug('Writing js binding to:')
|
|
539
1009
|
debug(' %i', dest)
|
|
540
|
-
await writeFileAsync(dest,
|
|
541
|
-
|
|
542
|
-
kind: 'js',
|
|
543
|
-
path: dest,
|
|
544
|
-
})
|
|
1010
|
+
await writeFileAsync(dest, binding, 'utf-8')
|
|
1011
|
+
return { kind: 'js', path: dest } satisfies Output
|
|
545
1012
|
} catch (e) {
|
|
546
1013
|
throw new Error('Failed to write js binding file', { cause: e })
|
|
547
1014
|
}
|
|
548
1015
|
}
|
|
1016
|
+
|
|
1017
|
+
private async writeWasiBinding(
|
|
1018
|
+
distFileName: string | undefined | null,
|
|
1019
|
+
idents: string[],
|
|
1020
|
+
) {
|
|
1021
|
+
if (distFileName) {
|
|
1022
|
+
const { name, dir } = parse(distFileName)
|
|
1023
|
+
const bindingPath = join(dir, `${this.config.binaryName}.wasi.cjs`)
|
|
1024
|
+
const browserBindingPath = join(
|
|
1025
|
+
dir,
|
|
1026
|
+
`${this.config.binaryName}.wasi-browser.js`,
|
|
1027
|
+
)
|
|
1028
|
+
const workerPath = join(dir, 'wasi-worker.mjs')
|
|
1029
|
+
const browserWorkerPath = join(dir, 'wasi-worker-browser.mjs')
|
|
1030
|
+
const browserEntryPath = join(dir, 'browser.js')
|
|
1031
|
+
const exportsCode =
|
|
1032
|
+
`module.exports = __napiModule.exports\n` +
|
|
1033
|
+
idents
|
|
1034
|
+
.map(
|
|
1035
|
+
(ident) =>
|
|
1036
|
+
`module.exports.${ident} = __napiModule.exports.${ident}`,
|
|
1037
|
+
)
|
|
1038
|
+
.join('\n')
|
|
1039
|
+
await writeFileAsync(
|
|
1040
|
+
bindingPath,
|
|
1041
|
+
createWasiBinding(
|
|
1042
|
+
name,
|
|
1043
|
+
this.config.packageName,
|
|
1044
|
+
this.config.wasm?.initialMemory,
|
|
1045
|
+
this.config.wasm?.maximumMemory,
|
|
1046
|
+
) +
|
|
1047
|
+
exportsCode +
|
|
1048
|
+
'\n',
|
|
1049
|
+
'utf8',
|
|
1050
|
+
)
|
|
1051
|
+
await writeFileAsync(
|
|
1052
|
+
browserBindingPath,
|
|
1053
|
+
createWasiBrowserBinding(
|
|
1054
|
+
name,
|
|
1055
|
+
this.config.wasm?.initialMemory,
|
|
1056
|
+
this.config.wasm?.maximumMemory,
|
|
1057
|
+
this.config.wasm?.browser?.fs,
|
|
1058
|
+
this.config.wasm?.browser?.asyncInit,
|
|
1059
|
+
this.config.wasm?.browser?.buffer,
|
|
1060
|
+
) +
|
|
1061
|
+
`export default __napiModule.exports\n` +
|
|
1062
|
+
idents
|
|
1063
|
+
.map(
|
|
1064
|
+
(ident) =>
|
|
1065
|
+
`export const ${ident} = __napiModule.exports.${ident}`,
|
|
1066
|
+
)
|
|
1067
|
+
.join('\n') +
|
|
1068
|
+
'\n',
|
|
1069
|
+
'utf8',
|
|
1070
|
+
)
|
|
1071
|
+
await writeFileAsync(workerPath, WASI_WORKER_TEMPLATE, 'utf8')
|
|
1072
|
+
await writeFileAsync(
|
|
1073
|
+
browserWorkerPath,
|
|
1074
|
+
createWasiBrowserWorkerBinding(this.config.wasm?.browser?.fs ?? false),
|
|
1075
|
+
'utf8',
|
|
1076
|
+
)
|
|
1077
|
+
await writeFileAsync(
|
|
1078
|
+
browserEntryPath,
|
|
1079
|
+
`export * from '${this.config.packageName}-wasm32-wasi'\n`,
|
|
1080
|
+
)
|
|
1081
|
+
return [
|
|
1082
|
+
{ kind: 'js', path: bindingPath },
|
|
1083
|
+
{ kind: 'js', path: browserBindingPath },
|
|
1084
|
+
{ kind: 'js', path: workerPath },
|
|
1085
|
+
{ kind: 'js', path: browserWorkerPath },
|
|
1086
|
+
{ kind: 'js', path: browserEntryPath },
|
|
1087
|
+
] satisfies Output[]
|
|
1088
|
+
}
|
|
1089
|
+
return []
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
private setEnvIfNotExists(env: string, value: string) {
|
|
1093
|
+
if (!process.env[env]) {
|
|
1094
|
+
this.envs[env] = value
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
549
1097
|
}
|