@napi-rs/cli 3.0.0-alpha.94 → 3.0.0-alpha.96
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/dist/api/__tests__/create-npm-dirs.spec.d.ts +1 -0
- package/dist/cli.js +110 -60
- package/dist/index.cjs +110 -60
- package/dist/index.js +110 -60
- package/dist/utils/config.d.ts +4 -0
- package/dist/utils/target.d.ts +1 -1
- package/package.json +2 -2
- package/src/api/__tests__/create-npm-dirs.spec.ts +210 -0
- package/src/api/build.ts +140 -76
- package/src/api/create-npm-dirs.ts +10 -9
- package/src/api/templates/js-binding.ts +29 -19
- package/src/utils/config.ts +4 -0
- package/src/utils/target.ts +1 -1
package/dist/utils/config.d.ts
CHANGED
|
@@ -95,6 +95,10 @@ export interface CommonPackageJsonFields {
|
|
|
95
95
|
author?: string;
|
|
96
96
|
authors?: string[];
|
|
97
97
|
license?: string;
|
|
98
|
+
cpu?: string[];
|
|
99
|
+
os?: string[];
|
|
100
|
+
libc?: string[];
|
|
101
|
+
files?: string[];
|
|
98
102
|
repository?: any;
|
|
99
103
|
homepage?: any;
|
|
100
104
|
engines?: Record<string, string>;
|
package/dist/utils/target.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@napi-rs/cli",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.96",
|
|
4
4
|
"description": "Cli tools for napi-rs",
|
|
5
5
|
"author": "LongYinan <lynweklm@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/napi-rs/napi-rs",
|
|
@@ -132,5 +132,5 @@
|
|
|
132
132
|
"e2e/**/*.spec.ts"
|
|
133
133
|
]
|
|
134
134
|
},
|
|
135
|
-
"gitHead": "
|
|
135
|
+
"gitHead": "f2e838cf992f437a861cdd3108e32b3ab523e464"
|
|
136
136
|
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs'
|
|
2
|
+
import { mkdir, readFile, rm, writeFile } from 'node:fs/promises'
|
|
3
|
+
import { tmpdir } from 'node:os'
|
|
4
|
+
import { join } from 'node:path'
|
|
5
|
+
|
|
6
|
+
import ava, { TestFn } from 'ava'
|
|
7
|
+
|
|
8
|
+
import { createNpmDirs } from '../create-npm-dirs.js'
|
|
9
|
+
|
|
10
|
+
const test = ava as TestFn<{
|
|
11
|
+
tmpDir: string
|
|
12
|
+
packageJsonPath: string
|
|
13
|
+
}>
|
|
14
|
+
|
|
15
|
+
test.beforeEach(async (t) => {
|
|
16
|
+
// Create a unique temp directory for tests
|
|
17
|
+
const timestamp = Date.now()
|
|
18
|
+
const random = Math.random().toString(36).substring(7)
|
|
19
|
+
const tmpDir = join(
|
|
20
|
+
tmpdir(),
|
|
21
|
+
'napi-rs-test',
|
|
22
|
+
`create-npm-dirs-${timestamp}-${random}`,
|
|
23
|
+
)
|
|
24
|
+
const packageJsonPath = join(tmpDir, 'package.json')
|
|
25
|
+
|
|
26
|
+
// Create the directory
|
|
27
|
+
await mkdir(tmpDir, { recursive: true })
|
|
28
|
+
|
|
29
|
+
t.context = { tmpDir, packageJsonPath }
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test.afterEach.always(async (t) => {
|
|
33
|
+
// Clean up any created directories
|
|
34
|
+
if (existsSync(t.context.tmpDir)) {
|
|
35
|
+
await rm(t.context.tmpDir, { recursive: true, force: true })
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
test('should omit exports fields from publishConfig in scoped packages', async (t) => {
|
|
40
|
+
const { tmpDir, packageJsonPath } = t.context
|
|
41
|
+
|
|
42
|
+
// Create a package.json with publishConfig that includes exports field
|
|
43
|
+
const packageJson = {
|
|
44
|
+
name: 'test-package',
|
|
45
|
+
version: '1.0.0',
|
|
46
|
+
publishConfig: {
|
|
47
|
+
registry: 'https://custom-registry.com',
|
|
48
|
+
access: 'public',
|
|
49
|
+
exports: {
|
|
50
|
+
'.': './dist/index.js',
|
|
51
|
+
'./package.json': './package.json',
|
|
52
|
+
},
|
|
53
|
+
tag: 'beta',
|
|
54
|
+
},
|
|
55
|
+
napi: {
|
|
56
|
+
binaryName: 'test-package',
|
|
57
|
+
targets: ['x86_64-unknown-linux-gnu'],
|
|
58
|
+
},
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2))
|
|
62
|
+
|
|
63
|
+
await createNpmDirs({
|
|
64
|
+
cwd: tmpDir,
|
|
65
|
+
packageJsonPath: 'package.json',
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
// Check that the scoped package directory was created
|
|
69
|
+
const scopedDir = join(tmpDir, 'npm', 'linux-x64-gnu')
|
|
70
|
+
t.true(existsSync(scopedDir))
|
|
71
|
+
|
|
72
|
+
// Read the generated package.json for the scoped package
|
|
73
|
+
const scopedPackageJsonPath = join(scopedDir, 'package.json')
|
|
74
|
+
t.true(existsSync(scopedPackageJsonPath))
|
|
75
|
+
|
|
76
|
+
const scopedPackageJson = JSON.parse(
|
|
77
|
+
await readFile(scopedPackageJsonPath, 'utf-8'),
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
// Verify that publishConfig only contains registry and access, not exports
|
|
81
|
+
t.truthy(scopedPackageJson.publishConfig)
|
|
82
|
+
t.is(scopedPackageJson.publishConfig.registry, 'https://custom-registry.com')
|
|
83
|
+
t.is(scopedPackageJson.publishConfig.access, 'public')
|
|
84
|
+
t.is(scopedPackageJson.publishConfig.exports, undefined)
|
|
85
|
+
t.is(scopedPackageJson.publishConfig.tag, undefined)
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
test('should handle package without publishConfig', async (t) => {
|
|
89
|
+
const { tmpDir, packageJsonPath } = t.context
|
|
90
|
+
|
|
91
|
+
// Create a package.json without publishConfig
|
|
92
|
+
const packageJson = {
|
|
93
|
+
name: 'test-package-no-config',
|
|
94
|
+
version: '1.0.0',
|
|
95
|
+
napi: {
|
|
96
|
+
binaryName: 'test-package-no-config',
|
|
97
|
+
targets: ['x86_64-unknown-linux-gnu'],
|
|
98
|
+
},
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2))
|
|
102
|
+
|
|
103
|
+
await createNpmDirs({
|
|
104
|
+
cwd: tmpDir,
|
|
105
|
+
packageJsonPath: 'package.json',
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
// Check that the scoped package directory was created
|
|
109
|
+
const scopedDir = join(tmpDir, 'npm', 'linux-x64-gnu')
|
|
110
|
+
t.true(existsSync(scopedDir))
|
|
111
|
+
|
|
112
|
+
// Read the generated package.json for the scoped package
|
|
113
|
+
const scopedPackageJsonPath = join(scopedDir, 'package.json')
|
|
114
|
+
const scopedPackageJson = JSON.parse(
|
|
115
|
+
await readFile(scopedPackageJsonPath, 'utf-8'),
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
// Verify that publishConfig is not present when not in source
|
|
119
|
+
t.is(scopedPackageJson.publishConfig, undefined)
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
test('should preserve only registry and access in publishConfig', async (t) => {
|
|
123
|
+
const { tmpDir, packageJsonPath } = t.context
|
|
124
|
+
|
|
125
|
+
// Create a package.json with minimal publishConfig
|
|
126
|
+
const packageJson = {
|
|
127
|
+
name: 'test-package-minimal',
|
|
128
|
+
version: '1.0.0',
|
|
129
|
+
publishConfig: {
|
|
130
|
+
registry: 'https://npm.company.com',
|
|
131
|
+
access: 'restricted',
|
|
132
|
+
},
|
|
133
|
+
napi: {
|
|
134
|
+
binaryName: 'test-package-minimal',
|
|
135
|
+
targets: ['aarch64-apple-darwin'],
|
|
136
|
+
},
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2))
|
|
140
|
+
|
|
141
|
+
await createNpmDirs({
|
|
142
|
+
cwd: tmpDir,
|
|
143
|
+
packageJsonPath: 'package.json',
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
// Check that the scoped package directory was created
|
|
147
|
+
const scopedDir = join(tmpDir, 'npm', 'darwin-arm64')
|
|
148
|
+
t.true(existsSync(scopedDir))
|
|
149
|
+
|
|
150
|
+
// Read the generated package.json for the scoped package
|
|
151
|
+
const scopedPackageJsonPath = join(scopedDir, 'package.json')
|
|
152
|
+
const scopedPackageJson = JSON.parse(
|
|
153
|
+
await readFile(scopedPackageJsonPath, 'utf-8'),
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
// Verify that publishConfig contains exactly registry and access
|
|
157
|
+
t.truthy(scopedPackageJson.publishConfig)
|
|
158
|
+
t.is(scopedPackageJson.publishConfig.registry, 'https://npm.company.com')
|
|
159
|
+
t.is(scopedPackageJson.publishConfig.access, 'restricted')
|
|
160
|
+
t.is(Object.keys(scopedPackageJson.publishConfig).length, 2)
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
test('should handle WASM targets correctly with publishConfig', async (t) => {
|
|
164
|
+
const { tmpDir, packageJsonPath } = t.context
|
|
165
|
+
|
|
166
|
+
// Create a package.json for WASM target
|
|
167
|
+
const packageJson = {
|
|
168
|
+
name: 'test-wasm-package',
|
|
169
|
+
version: '1.0.0',
|
|
170
|
+
publishConfig: {
|
|
171
|
+
registry: 'https://wasm-registry.com',
|
|
172
|
+
access: 'public',
|
|
173
|
+
exports: './wasm.js',
|
|
174
|
+
browser: './browser.js',
|
|
175
|
+
},
|
|
176
|
+
napi: {
|
|
177
|
+
binaryName: 'test-wasm-package',
|
|
178
|
+
targets: ['wasm32-wasi-preview1-threads'],
|
|
179
|
+
},
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2))
|
|
183
|
+
|
|
184
|
+
await createNpmDirs({
|
|
185
|
+
cwd: tmpDir,
|
|
186
|
+
packageJsonPath: 'package.json',
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
// Check that the scoped package directory was created
|
|
190
|
+
const scopedDir = join(tmpDir, 'npm', 'wasm32-wasi')
|
|
191
|
+
t.true(existsSync(scopedDir))
|
|
192
|
+
|
|
193
|
+
// Read the generated package.json for the scoped package
|
|
194
|
+
const scopedPackageJsonPath = join(scopedDir, 'package.json')
|
|
195
|
+
const scopedPackageJson = JSON.parse(
|
|
196
|
+
await readFile(scopedPackageJsonPath, 'utf-8'),
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
// Verify that publishConfig is correctly filtered for WASM too
|
|
200
|
+
t.truthy(scopedPackageJson.publishConfig)
|
|
201
|
+
t.is(scopedPackageJson.publishConfig.registry, 'https://wasm-registry.com')
|
|
202
|
+
t.is(scopedPackageJson.publishConfig.access, 'public')
|
|
203
|
+
t.is(scopedPackageJson.publishConfig.exports, undefined)
|
|
204
|
+
t.is(scopedPackageJson.publishConfig.browser, undefined)
|
|
205
|
+
|
|
206
|
+
// Verify WASM-specific fields are set correctly
|
|
207
|
+
t.truthy(scopedPackageJson.main)
|
|
208
|
+
t.truthy(scopedPackageJson.browser)
|
|
209
|
+
t.truthy(scopedPackageJson.dependencies)
|
|
210
|
+
})
|
package/src/api/build.ts
CHANGED
|
@@ -514,86 +514,15 @@ class Builder {
|
|
|
514
514
|
}
|
|
515
515
|
|
|
516
516
|
if (this.target.platform === 'android') {
|
|
517
|
-
|
|
518
|
-
if (!ANDROID_NDK_LATEST_HOME) {
|
|
519
|
-
debug.warn(
|
|
520
|
-
`${colors.red(
|
|
521
|
-
'ANDROID_NDK_LATEST_HOME',
|
|
522
|
-
)} environment variable is missing`,
|
|
523
|
-
)
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
const targetArch = this.target.arch === 'arm' ? 'armv7a' : 'aarch64'
|
|
527
|
-
const targetPlatform =
|
|
528
|
-
this.target.arch === 'arm' ? 'androideabi24' : 'android24'
|
|
529
|
-
const hostPlatform =
|
|
530
|
-
process.platform === 'darwin'
|
|
531
|
-
? 'darwin'
|
|
532
|
-
: process.platform === 'win32'
|
|
533
|
-
? 'windows'
|
|
534
|
-
: 'linux'
|
|
535
|
-
Object.assign(this.envs, {
|
|
536
|
-
CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-android24-clang`,
|
|
537
|
-
CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-androideabi24-clang`,
|
|
538
|
-
TARGET_CC: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang`,
|
|
539
|
-
TARGET_CXX: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/${targetArch}-linux-${targetPlatform}-clang++`,
|
|
540
|
-
TARGET_AR: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/llvm-ar`,
|
|
541
|
-
TARGET_RANLIB: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin/llvm-ranlib`,
|
|
542
|
-
ANDROID_NDK: ANDROID_NDK_LATEST_HOME,
|
|
543
|
-
PATH: `${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/${hostPlatform}-x86_64/bin:${process.env.PATH}`,
|
|
544
|
-
})
|
|
517
|
+
this.setAndroidEnv()
|
|
545
518
|
}
|
|
546
|
-
// END LINKER
|
|
547
519
|
|
|
548
520
|
if (this.target.platform === 'wasi') {
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
'..',
|
|
552
|
-
'lib',
|
|
553
|
-
'wasm32-wasi-threads',
|
|
554
|
-
)
|
|
555
|
-
this.envs.EMNAPI_LINK_DIR = emnapi
|
|
556
|
-
this.envs.SETJMP_LINK_DIR = setjmpLib
|
|
557
|
-
const { WASI_SDK_PATH } = process.env
|
|
521
|
+
this.setWasiEnv()
|
|
522
|
+
}
|
|
558
523
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
WASI_SDK_PATH,
|
|
562
|
-
'bin',
|
|
563
|
-
'wasm-ld',
|
|
564
|
-
)
|
|
565
|
-
this.envs.CARGO_TARGET_WASM32_WASIP1_LINKER = join(
|
|
566
|
-
WASI_SDK_PATH,
|
|
567
|
-
'bin',
|
|
568
|
-
'wasm-ld',
|
|
569
|
-
)
|
|
570
|
-
this.envs.CARGO_TARGET_WASM32_WASIP1_THREADS_LINKER = join(
|
|
571
|
-
WASI_SDK_PATH,
|
|
572
|
-
'bin',
|
|
573
|
-
'wasm-ld',
|
|
574
|
-
)
|
|
575
|
-
this.envs.CARGO_TARGET_WASM32_WASIP2_LINKER = join(
|
|
576
|
-
WASI_SDK_PATH,
|
|
577
|
-
'bin',
|
|
578
|
-
'wasm-ld',
|
|
579
|
-
)
|
|
580
|
-
this.setEnvIfNotExists('CC', join(WASI_SDK_PATH, 'bin', 'clang'))
|
|
581
|
-
this.setEnvIfNotExists('CXX', join(WASI_SDK_PATH, 'bin', 'clang++'))
|
|
582
|
-
this.setEnvIfNotExists('AR', join(WASI_SDK_PATH, 'bin', 'ar'))
|
|
583
|
-
this.setEnvIfNotExists('RANLIB', join(WASI_SDK_PATH, 'bin', 'ranlib'))
|
|
584
|
-
this.setEnvIfNotExists(
|
|
585
|
-
'CFLAGS',
|
|
586
|
-
`--target=wasm32-wasi-threads --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot -pthread -mllvm -wasm-enable-sjlj -I${setjmpInclude}`,
|
|
587
|
-
)
|
|
588
|
-
this.setEnvIfNotExists(
|
|
589
|
-
'CXXFLAGS',
|
|
590
|
-
`--target=wasm32-wasi-threads --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot -pthread -mllvm -wasm-enable-sjlj -I${setjmpInclude}`,
|
|
591
|
-
)
|
|
592
|
-
this.setEnvIfNotExists(
|
|
593
|
-
`LDFLAGS`,
|
|
594
|
-
`-fuse-ld=${WASI_SDK_PATH}/bin/wasm-ld --target=wasm32-wasi-threads`,
|
|
595
|
-
)
|
|
596
|
-
}
|
|
524
|
+
if (this.target.abi === 'ohos') {
|
|
525
|
+
this.setOpenHarmonyEnv()
|
|
597
526
|
}
|
|
598
527
|
|
|
599
528
|
debug('Set envs: ')
|
|
@@ -618,6 +547,141 @@ class Builder {
|
|
|
618
547
|
})
|
|
619
548
|
}
|
|
620
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
|
+
|
|
621
685
|
private setFeatures() {
|
|
622
686
|
const args = []
|
|
623
687
|
if (this.options.allFeatures && this.options.noDefaultFeatures) {
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
pick,
|
|
14
14
|
writeFileAsync as rawWriteFileAsync,
|
|
15
15
|
Target,
|
|
16
|
+
type CommonPackageJsonFields,
|
|
16
17
|
} from '../utils/index.js'
|
|
17
18
|
|
|
18
19
|
const debug = debugFactory('create-npm-dirs')
|
|
@@ -65,7 +66,7 @@ export async function createNpmDirs(userOptions: CreateNpmDirsOptions) {
|
|
|
65
66
|
target.arch === 'wasm32'
|
|
66
67
|
? `${binaryName}.${target.platformArchABI}.wasm`
|
|
67
68
|
: `${binaryName}.${target.platformArchABI}.node`
|
|
68
|
-
const scopedPackageJson = {
|
|
69
|
+
const scopedPackageJson: CommonPackageJsonFields = {
|
|
69
70
|
name: `${packageName}-${target.platformArchABI}`,
|
|
70
71
|
version: packageJson.version,
|
|
71
72
|
cpu: target.arch !== 'universal' ? [target.arch] : undefined,
|
|
@@ -80,22 +81,25 @@ export async function createNpmDirs(userOptions: CreateNpmDirsOptions) {
|
|
|
80
81
|
'homepage',
|
|
81
82
|
'license',
|
|
82
83
|
'engines',
|
|
83
|
-
'publishConfig',
|
|
84
84
|
'repository',
|
|
85
85
|
'bugs',
|
|
86
86
|
),
|
|
87
87
|
}
|
|
88
|
+
if (packageJson.publishConfig) {
|
|
89
|
+
scopedPackageJson.publishConfig = pick(
|
|
90
|
+
packageJson.publishConfig,
|
|
91
|
+
'registry',
|
|
92
|
+
'access',
|
|
93
|
+
)
|
|
94
|
+
}
|
|
88
95
|
if (target.arch !== 'wasm32') {
|
|
89
|
-
// @ts-expect-error
|
|
90
96
|
scopedPackageJson.os = [target.platform]
|
|
91
97
|
} else {
|
|
92
98
|
const entry = `${binaryName}.wasi.cjs`
|
|
93
99
|
scopedPackageJson.main = entry
|
|
94
|
-
// @ts-expect-error
|
|
95
100
|
scopedPackageJson.browser = `${binaryName}.wasi-browser.js`
|
|
96
|
-
scopedPackageJson.files
|
|
101
|
+
scopedPackageJson.files?.push(
|
|
97
102
|
entry,
|
|
98
|
-
// @ts-expect-error
|
|
99
103
|
scopedPackageJson.browser,
|
|
100
104
|
`wasi-worker.mjs`,
|
|
101
105
|
`wasi-worker-browser.mjs`,
|
|
@@ -121,17 +125,14 @@ export async function createNpmDirs(userOptions: CreateNpmDirsOptions) {
|
|
|
121
125
|
const wasmRuntime = await fetch(
|
|
122
126
|
`https://registry.npmjs.org/@napi-rs/wasm-runtime`,
|
|
123
127
|
).then((res) => res.json() as Promise<PackageMeta>)
|
|
124
|
-
// @ts-expect-error
|
|
125
128
|
scopedPackageJson.dependencies = {
|
|
126
129
|
'@napi-rs/wasm-runtime': `^${wasmRuntime['dist-tags'].latest}`,
|
|
127
130
|
}
|
|
128
131
|
}
|
|
129
132
|
|
|
130
133
|
if (target.abi === 'gnu') {
|
|
131
|
-
// @ts-expect-error
|
|
132
134
|
scopedPackageJson.libc = ['glibc']
|
|
133
135
|
} else if (target.abi === 'musl') {
|
|
134
|
-
// @ts-expect-error
|
|
135
136
|
scopedPackageJson.libc = ['musl']
|
|
136
137
|
}
|
|
137
138
|
|
|
@@ -38,17 +38,19 @@ const bindingHeader = `// prettier-ignore
|
|
|
38
38
|
`
|
|
39
39
|
|
|
40
40
|
function createCommonBinding(localName: string, pkgName: string): string {
|
|
41
|
-
function requireTuple(tuple: string) {
|
|
41
|
+
function requireTuple(tuple: string, identSize = 8) {
|
|
42
|
+
const identLow = ' '.repeat(identSize - 2)
|
|
43
|
+
const ident = ' '.repeat(identSize)
|
|
42
44
|
return `try {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
45
|
+
${ident}return require('./${localName}.${tuple}.node')
|
|
46
|
+
${identLow}} catch (e) {
|
|
47
|
+
${ident}loadErrors.push(e)
|
|
48
|
+
${identLow}}
|
|
49
|
+
${identLow}try {
|
|
50
|
+
${ident}return require('${pkgName}-${tuple}')
|
|
51
|
+
${identLow}} catch (e) {
|
|
52
|
+
${ident}loadErrors.push(e)
|
|
53
|
+
${identLow}}
|
|
52
54
|
`
|
|
53
55
|
}
|
|
54
56
|
|
|
@@ -70,6 +72,8 @@ const isMusl = () => {
|
|
|
70
72
|
return musl
|
|
71
73
|
}
|
|
72
74
|
|
|
75
|
+
const isOpenHarmony = process.platform === 'openharmony'
|
|
76
|
+
|
|
73
77
|
const isFileMusl = (f) => f.includes('libc.musl-') || f.includes('ld-musl-')
|
|
74
78
|
|
|
75
79
|
const isMuslFromFilesystem = () => {
|
|
@@ -135,7 +139,7 @@ function requireNative() {
|
|
|
135
139
|
loadErrors.push(new Error(\`Unsupported architecture on Windows: \${process.arch}\`))
|
|
136
140
|
}
|
|
137
141
|
} else if (process.platform === 'darwin') {
|
|
138
|
-
${requireTuple('darwin-universal')}
|
|
142
|
+
${requireTuple('darwin-universal', 6)}
|
|
139
143
|
if (process.arch === 'x64') {
|
|
140
144
|
${requireTuple('darwin-x64')}
|
|
141
145
|
} else if (process.arch === 'arm64') {
|
|
@@ -154,27 +158,33 @@ function requireNative() {
|
|
|
154
158
|
} else if (process.platform === 'linux') {
|
|
155
159
|
if (process.arch === 'x64') {
|
|
156
160
|
if (isMusl()) {
|
|
157
|
-
${requireTuple('linux-x64-musl')}
|
|
161
|
+
${requireTuple('linux-x64-musl', 8)}
|
|
162
|
+
} else if (isOpenHarmony) {
|
|
163
|
+
${requireTuple('linux-x64-ohos', 8)}
|
|
158
164
|
} else {
|
|
159
|
-
${requireTuple('linux-x64-gnu')}
|
|
165
|
+
${requireTuple('linux-x64-gnu', 8)}
|
|
160
166
|
}
|
|
161
167
|
} else if (process.arch === 'arm64') {
|
|
162
168
|
if (isMusl()) {
|
|
163
|
-
${requireTuple('linux-arm64-musl')}
|
|
169
|
+
${requireTuple('linux-arm64-musl', 8)}
|
|
170
|
+
} else if (isOpenHarmony) {
|
|
171
|
+
${requireTuple('linux-arm64-ohos', 8)}
|
|
164
172
|
} else {
|
|
165
|
-
${requireTuple('linux-arm64-gnu')}
|
|
173
|
+
${requireTuple('linux-arm64-gnu', 8)}
|
|
166
174
|
}
|
|
167
175
|
} else if (process.arch === 'arm') {
|
|
168
176
|
if (isMusl()) {
|
|
169
|
-
${requireTuple('linux-arm-musleabihf')}
|
|
177
|
+
${requireTuple('linux-arm-musleabihf', 8)}
|
|
178
|
+
} else if (isOpenHarmony) {
|
|
179
|
+
${requireTuple('linux-arm-ohos', 8)}
|
|
170
180
|
} else {
|
|
171
|
-
${requireTuple('linux-arm-gnueabihf')}
|
|
181
|
+
${requireTuple('linux-arm-gnueabihf', 8)}
|
|
172
182
|
}
|
|
173
183
|
} else if (process.arch === 'riscv64') {
|
|
174
184
|
if (isMusl()) {
|
|
175
|
-
${requireTuple('linux-riscv64-musl')}
|
|
185
|
+
${requireTuple('linux-riscv64-musl', 8)}
|
|
176
186
|
} else {
|
|
177
|
-
${requireTuple('linux-riscv64-gnu')}
|
|
187
|
+
${requireTuple('linux-riscv64-gnu', 8)}
|
|
178
188
|
}
|
|
179
189
|
} else if (process.arch === 'ppc64') {
|
|
180
190
|
${requireTuple('linux-ppc64-gnu')}
|
package/src/utils/config.ts
CHANGED
|
@@ -115,6 +115,10 @@ export interface CommonPackageJsonFields {
|
|
|
115
115
|
author?: string
|
|
116
116
|
authors?: string[]
|
|
117
117
|
license?: string
|
|
118
|
+
cpu?: string[]
|
|
119
|
+
os?: string[]
|
|
120
|
+
libc?: string[]
|
|
121
|
+
files?: string[]
|
|
118
122
|
repository?: any
|
|
119
123
|
homepage?: any
|
|
120
124
|
engines?: Record<string, string>
|
package/src/utils/target.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { execSync } from 'node:child_process'
|
|
2
2
|
|
|
3
|
-
export type Platform = NodeJS.Platform | 'wasm' | 'wasi'
|
|
3
|
+
export type Platform = NodeJS.Platform | 'wasm' | 'wasi' | 'ohos'
|
|
4
4
|
|
|
5
5
|
export const UNIVERSAL_TARGETS = {
|
|
6
6
|
'universal-apple-darwin': ['aarch64-apple-darwin', 'x86_64-apple-darwin'],
|