UNPKG

@napi-rs/cli

Version:
1,395 lines (1,339 loc) 530 kB
import { createRequire } from "node:module"; import { Cli, Command, Option } from "clipanion"; import path, { dirname, isAbsolute, join, parse, resolve } from "node:path"; import * as colors from "colorette"; import { underline, yellow } from "colorette"; import rawDebug from "debug"; import { access, copyFile, mkdir, readFile, readdir, rename, stat, unlink, writeFile } from "node:fs/promises"; import { exec, execSync, spawn, spawnSync } from "node:child_process"; import fs, { existsSync, mkdirSync, promises, rmSync, statSync } from "node:fs"; import { isNil, merge, omit, omitBy, pick, sortBy } from "es-toolkit"; import { createHash } from "node:crypto"; import { homedir } from "node:os"; import { parse as parse$1 } from "semver"; import { dump, load } from "js-yaml"; import * as typanion from "typanion"; import { Octokit } from "@octokit/rest"; import { checkbox, confirm, input, select } from "@inquirer/prompts"; //#region src/def/artifacts.ts var BaseArtifactsCommand = class extends Command { static paths = [["artifacts"]]; static usage = Command.Usage({ description: "Copy artifacts from Github Actions into npm packages and ready to publish" }); cwd = Option.String("--cwd", process.cwd(), { description: "The working directory of where napi command will be executed in, all other paths options are relative to this path" }); configPath = Option.String("--config-path,-c", { description: "Path to `napi` config json file" }); packageJsonPath = Option.String("--package-json-path", "package.json", { description: "Path to `package.json`" }); outputDir = Option.String("--output-dir,-o,-d", "./artifacts", { description: "Path to the folder where all built `.node` files put, same as `--output-dir` of build command" }); npmDir = Option.String("--npm-dir", "npm", { description: "Path to the folder where the npm packages put" }); buildOutputDir = Option.String("--build-output-dir", { description: "Path to the build output dir, only needed when targets contains `wasm32-wasi-*`" }); getOptions() { return { cwd: this.cwd, configPath: this.configPath, packageJsonPath: this.packageJsonPath, outputDir: this.outputDir, npmDir: this.npmDir, buildOutputDir: this.buildOutputDir }; } }; function applyDefaultArtifactsOptions(options) { return { cwd: process.cwd(), packageJsonPath: "package.json", outputDir: "./artifacts", npmDir: "npm", ...options }; } //#endregion //#region src/utils/log.ts rawDebug.formatters.i = (v) => { return colors.green(v); }; const debugFactory = (namespace) => { const debug$10 = rawDebug(`napi:${namespace}`); debug$10.info = (...args) => console.error(colors.black(colors.bgGreen(" INFO ")), ...args); debug$10.warn = (...args) => console.error(colors.black(colors.bgYellow(" WARNING ")), ...args); debug$10.error = (...args) => console.error(colors.white(colors.bgRed(" ERROR ")), ...args.map((arg) => arg instanceof Error ? arg.stack ?? arg.message : arg)); return debug$10; }; const debug$9 = debugFactory("utils"); //#endregion //#region package.json var name = "@napi-rs/cli"; var version$1 = "3.4.1"; var description = "Cli tools for napi-rs"; var author = "LongYinan <lynweklm@gmail.com>"; var homepage = "https://github.com/napi-rs/napi-rs"; var license = "MIT"; var type = "module"; var engines = { "node": ">= 16" }; var bin = { "napi": "./dist/cli.js", "napi-raw": "./cli.mjs" }; var main = "./dist/index.cjs"; var module = "./dist/index.js"; var types = "./dist/index.d.ts"; var exports = { ".": { "import": "./dist/index.js", "require": "./dist/index.cjs" }, "./package.json": "./package.json" }; var files = [ "dist", "src", "!__tests__" ]; var keywords = [ "cli", "rust", "napi", "n-api", "node-api", "node-addon", "neon" ]; var maintainers = [{ "name": "LongYinan", "email": "lynweklm@gmail.com", "homepage": "https://github.com/Brooooooklyn" }, { "name": "forehalo", "homepage": "https://github.com/forehalo" }]; var repository = { "type": "git", "url": "git+https://github.com/napi-rs/napi-rs.git" }; var publishConfig = { "registry": "https://registry.npmjs.org/", "access": "public" }; var bugs = { "url": "https://github.com/napi-rs/napi-rs/issues" }; var dependencies = { "@inquirer/prompts": "^7.8.4", "@napi-rs/cross-toolchain": "^1.0.3", "@napi-rs/wasm-tools": "^1.0.1", "@octokit/rest": "^22.0.0", "clipanion": "^4.0.0-rc.4", "colorette": "^2.0.20", "debug": "^4.4.1", "emnapi": "^1.5.0", "es-toolkit": "^1.39.10", "js-yaml": "^4.1.0", "semver": "^7.7.2", "typanion": "^3.14.0" }; var devDependencies = { "@emnapi/runtime": "^1.5.0", "@oxc-node/core": "^0.0.32", "@std/toml": "npm:@jsr/std__toml@^1.0.10", "@types/debug": "^4.1.12", "@types/inquirer": "^9.0.9", "@types/js-yaml": "^4.0.9", "@types/node": "^24.3.1", "@types/semver": "^7.7.1", "ava": "^6.4.1", "empathic": "^2.0.0", "env-paths": "^3.0.0", "prettier": "^3.6.2", "tsdown": "^0.15.0", "tslib": "^2.8.1", "typescript": "^5.9.2" }; var peerDependencies = { "@emnapi/runtime": "^1.5.0" }; var peerDependenciesMeta = { "@emnapi/runtime": { "optional": true }, "emnapi": { "optional": true } }; var funding = { "type": "github", "url": "https://github.com/sponsors/Brooooooklyn" }; var scripts = { "codegen": "node --import @oxc-node/core/register ./codegen/index.ts", "build": "tsdown", "test": "node --import @oxc-node/core/register ../node_modules/ava/entrypoints/cli.mjs" }; var ava = { "extensions": { "ts": "module" }, "timeout": "2m", "workerThreads": false, "files": ["**/__tests__/**/*.spec.ts", "e2e/**/*.spec.ts"] }; var package_default = { name, version: version$1, description, author, homepage, license, type, engines, bin, main, module, types, exports, files, keywords, maintainers, repository, publishConfig, bugs, dependencies, devDependencies, peerDependencies, peerDependenciesMeta, funding, scripts, ava }; //#endregion //#region src/utils/misc.ts const readFileAsync = readFile; const writeFileAsync = writeFile; const unlinkAsync = unlink; const copyFileAsync = copyFile; const mkdirAsync = mkdir; const statAsync = stat; const readdirAsync = readdir; function fileExists(path$1) { return access(path$1).then(() => true, () => false); } async function dirExistsAsync(path$1) { try { return (await statAsync(path$1)).isDirectory(); } catch { return false; } } function pick$1(o, ...keys) { return keys.reduce((acc, key) => { acc[key] = o[key]; return acc; }, {}); } async function updatePackageJson(path$1, partial) { if (!await fileExists(path$1)) { debug$9(`File not exists ${path$1}`); return; } const old = JSON.parse(await readFileAsync(path$1, "utf8")); await writeFileAsync(path$1, JSON.stringify({ ...old, ...partial }, null, 2)); } const CLI_VERSION = package_default.version; //#endregion //#region src/utils/target.ts const SUB_SYSTEMS = new Set(["android", "ohos"]); const AVAILABLE_TARGETS = [ "aarch64-apple-darwin", "aarch64-linux-android", "aarch64-unknown-linux-gnu", "aarch64-unknown-linux-musl", "aarch64-unknown-linux-ohos", "aarch64-pc-windows-msvc", "x86_64-apple-darwin", "x86_64-pc-windows-msvc", "x86_64-pc-windows-gnu", "x86_64-unknown-linux-gnu", "x86_64-unknown-linux-musl", "x86_64-unknown-linux-ohos", "x86_64-unknown-freebsd", "i686-pc-windows-msvc", "armv7-unknown-linux-gnueabihf", "armv7-unknown-linux-musleabihf", "armv7-linux-androideabi", "universal-apple-darwin", "loongarch64-unknown-linux-gnu", "riscv64gc-unknown-linux-gnu", "powerpc64le-unknown-linux-gnu", "s390x-unknown-linux-gnu", "wasm32-wasi-preview1-threads", "wasm32-wasip1-threads" ]; const DEFAULT_TARGETS = [ "x86_64-apple-darwin", "aarch64-apple-darwin", "x86_64-pc-windows-msvc", "x86_64-unknown-linux-gnu" ]; const TARGET_LINKER = { "aarch64-unknown-linux-musl": "aarch64-linux-musl-gcc", "loongarch64-unknown-linux-gnu": "loongarch64-linux-gnu-gcc-13", "riscv64gc-unknown-linux-gnu": "riscv64-linux-gnu-gcc", "powerpc64le-unknown-linux-gnu": "powerpc64le-linux-gnu-gcc", "s390x-unknown-linux-gnu": "s390x-linux-gnu-gcc" }; const CpuToNodeArch = { x86_64: "x64", aarch64: "arm64", i686: "ia32", armv7: "arm", loongarch64: "loong64", riscv64gc: "riscv64", powerpc64le: "ppc64" }; const SysToNodePlatform = { linux: "linux", freebsd: "freebsd", darwin: "darwin", windows: "win32", ohos: "openharmony" }; const UniArchsByPlatform = { darwin: ["x64", "arm64"] }; /** * A triple is a specific format for specifying a target architecture. * Triples may be referred to as a target triple which is the architecture for the artifact produced, and the host triple which is the architecture that the compiler is running on. * The general format of the triple is `<arch><sub>-<vendor>-<sys>-<abi>` where: * - `arch` = The base CPU architecture, for example `x86_64`, `i686`, `arm`, `thumb`, `mips`, etc. * - `sub` = The CPU sub-architecture, for example `arm` has `v7`, `v7s`, `v5te`, etc. * - `vendor` = The vendor, for example `unknown`, `apple`, `pc`, `nvidia`, etc. * - `sys` = The system name, for example `linux`, `windows`, `darwin`, etc. none is typically used for bare-metal without an OS. * - `abi` = The ABI, for example `gnu`, `android`, `eabi`, etc. */ function parseTriple(rawTriple) { if (rawTriple === "wasm32-wasi" || rawTriple === "wasm32-wasi-preview1-threads" || rawTriple.startsWith("wasm32-wasip")) return { triple: rawTriple, platformArchABI: "wasm32-wasi", platform: "wasi", arch: "wasm32", abi: "wasi" }; const triples = (rawTriple.endsWith("eabi") ? `${rawTriple.slice(0, -4)}-eabi` : rawTriple).split("-"); let cpu; let sys; let abi = null; if (triples.length === 2) [cpu, sys] = triples; else [cpu, , sys, abi = null] = triples; if (abi && SUB_SYSTEMS.has(abi)) { sys = abi; abi = null; } const platform = SysToNodePlatform[sys] ?? sys; const arch = CpuToNodeArch[cpu] ?? cpu; return { triple: rawTriple, platformArchABI: abi ? `${platform}-${arch}-${abi}` : `${platform}-${arch}`, platform, arch, abi }; } function getSystemDefaultTarget() { const host = execSync(`rustc -vV`, { env: process.env }).toString("utf8").split("\n").find((line) => line.startsWith("host: ")); const triple = host === null || host === void 0 ? void 0 : host.slice(6); if (!triple) throw new TypeError(`Can not parse target triple from host`); return parseTriple(triple); } function getTargetLinker(target) { return TARGET_LINKER[target]; } function targetToEnvVar(target) { return target.replace(/-/g, "_").toUpperCase(); } //#endregion //#region src/utils/version.ts let NapiVersion = /* @__PURE__ */ function(NapiVersion$1) { NapiVersion$1[NapiVersion$1["Napi1"] = 1] = "Napi1"; NapiVersion$1[NapiVersion$1["Napi2"] = 2] = "Napi2"; NapiVersion$1[NapiVersion$1["Napi3"] = 3] = "Napi3"; NapiVersion$1[NapiVersion$1["Napi4"] = 4] = "Napi4"; NapiVersion$1[NapiVersion$1["Napi5"] = 5] = "Napi5"; NapiVersion$1[NapiVersion$1["Napi6"] = 6] = "Napi6"; NapiVersion$1[NapiVersion$1["Napi7"] = 7] = "Napi7"; NapiVersion$1[NapiVersion$1["Napi8"] = 8] = "Napi8"; NapiVersion$1[NapiVersion$1["Napi9"] = 9] = "Napi9"; return NapiVersion$1; }({}); const NAPI_VERSION_MATRIX = new Map([ [NapiVersion.Napi1, "8.6.0 | 9.0.0 | 10.0.0"], [NapiVersion.Napi2, "8.10.0 | 9.3.0 | 10.0.0"], [NapiVersion.Napi3, "6.14.2 | 8.11.2 | 9.11.0 | 10.0.0"], [NapiVersion.Napi4, "10.16.0 | 11.8.0 | 12.0.0"], [NapiVersion.Napi5, "10.17.0 | 12.11.0 | 13.0.0"], [NapiVersion.Napi6, "10.20.0 | 12.17.0 | 14.0.0"], [NapiVersion.Napi7, "10.23.0 | 12.19.0 | 14.12.0 | 15.0.0"], [NapiVersion.Napi8, "12.22.0 | 14.17.0 | 15.12.0 | 16.0.0"], [NapiVersion.Napi9, "18.17.0 | 20.3.0 | 21.1.0"] ]); function parseNodeVersion(v) { const matches = v.match(/v?([0-9]+)\.([0-9]+)\.([0-9]+)/i); if (!matches) throw new Error("Unknown node version number: " + v); const [, major, minor, patch] = matches; return { major: parseInt(major), minor: parseInt(minor), patch: parseInt(patch) }; } function requiredNodeVersions(napiVersion) { const requirement = NAPI_VERSION_MATRIX.get(napiVersion); if (!requirement) return [parseNodeVersion("10.0.0")]; return requirement.split("|").map(parseNodeVersion); } function toEngineRequirement(versions) { const requirements = []; versions.forEach((v, i) => { let req = ""; if (i !== 0) { const lastVersion = versions[i - 1]; req += `< ${lastVersion.major + 1}`; } req += `${i === 0 ? "" : " || "}>= ${v.major}.${v.minor}.${v.patch}`; requirements.push(req); }); return requirements.join(" "); } function napiEngineRequirement(napiVersion) { return toEngineRequirement(requiredNodeVersions(napiVersion)); } //#endregion //#region src/utils/metadata.ts async function parseMetadata(manifestPath) { if (!fs.existsSync(manifestPath)) throw new Error(`No crate found in manifest: ${manifestPath}`); const childProcess = spawn("cargo", [ "metadata", "--manifest-path", manifestPath, "--format-version", "1" ], { stdio: "pipe" }); let stdout = ""; let stderr = ""; let status = 0; childProcess.stdout.on("data", (data) => { stdout += data; }); childProcess.stderr.on("data", (data) => { stderr += data; }); await new Promise((resolve$1) => { childProcess.on("close", (code) => { status = code ?? 0; resolve$1(); }); }); if (status !== 0) { const simpleMessage = `cargo metadata exited with code ${status}`; throw new Error(`${simpleMessage} and error message:\n\n${stderr}`, { cause: new Error(simpleMessage) }); } try { return JSON.parse(stdout); } catch (e) { throw new Error("Failed to parse cargo metadata JSON", { cause: e }); } } //#endregion //#region src/utils/config.ts async function readNapiConfig(path$1, configPath) { if (configPath && !await fileExists(configPath)) throw new Error(`NAPI-RS config not found at ${configPath}`); if (!await fileExists(path$1)) throw new Error(`package.json not found at ${path$1}`); const content = await readFileAsync(path$1, "utf8"); let pkgJson; try { pkgJson = JSON.parse(content); } catch (e) { throw new Error(`Failed to parse package.json at ${path$1}`, { cause: e }); } let separatedConfig; if (configPath) { const configContent = await readFileAsync(configPath, "utf8"); try { separatedConfig = JSON.parse(configContent); } catch (e) { throw new Error(`Failed to parse NAPI-RS config at ${configPath}`, { cause: e }); } } const userNapiConfig = pkgJson.napi ?? {}; if (pkgJson.napi && separatedConfig) { const pkgJsonPath = underline(path$1); const configPathUnderline = underline(configPath); console.warn(yellow(`Both napi field in ${pkgJsonPath} and [NAPI-RS config](${configPathUnderline}) file are found, the NAPI-RS config file will be used.`)); Object.assign(userNapiConfig, separatedConfig); } const napiConfig = merge({ binaryName: "index", packageName: pkgJson.name, targets: [], packageJson: pkgJson, npmClient: "npm" }, omit(userNapiConfig, ["targets"])); let targets = userNapiConfig.targets ?? []; if (userNapiConfig === null || userNapiConfig === void 0 ? void 0 : userNapiConfig.name) { console.warn(yellow(`[DEPRECATED] napi.name is deprecated, use napi.binaryName instead.`)); napiConfig.binaryName = userNapiConfig.name; } if (!targets.length) { var _userNapiConfig$tripl, _userNapiConfig$tripl2; let deprecatedWarned = false; const warning = yellow(`[DEPRECATED] napi.triples is deprecated, use napi.targets instead.`); if ((_userNapiConfig$tripl = userNapiConfig.triples) === null || _userNapiConfig$tripl === void 0 ? void 0 : _userNapiConfig$tripl.defaults) { deprecatedWarned = true; console.warn(warning); targets = targets.concat(DEFAULT_TARGETS); } if ((_userNapiConfig$tripl2 = userNapiConfig.triples) === null || _userNapiConfig$tripl2 === void 0 || (_userNapiConfig$tripl2 = _userNapiConfig$tripl2.additional) === null || _userNapiConfig$tripl2 === void 0 ? void 0 : _userNapiConfig$tripl2.length) { targets = targets.concat(userNapiConfig.triples.additional); if (!deprecatedWarned) console.warn(warning); } } if (new Set(targets).size !== targets.length) { const duplicateTarget = targets.find((target, index) => targets.indexOf(target) !== index); throw new Error(`Duplicate targets are not allowed: ${duplicateTarget}`); } napiConfig.targets = targets.map(parseTriple); return napiConfig; } //#endregion //#region src/utils/cargo.ts function tryInstallCargoBinary(name$1, bin$1) { if (detectCargoBinary(bin$1)) { debug$9("Cargo binary already installed: %s", name$1); return; } try { debug$9("Installing cargo binary: %s", name$1); execSync(`cargo install ${name$1}`, { stdio: "inherit" }); } catch (e) { throw new Error(`Failed to install cargo binary: ${name$1}`, { cause: e }); } } function detectCargoBinary(bin$1) { debug$9("Detecting cargo binary: %s", bin$1); try { execSync(`cargo help ${bin$1}`, { stdio: "ignore" }); debug$9("Cargo binary detected: %s", bin$1); return true; } catch { debug$9("Cargo binary not detected: %s", bin$1); return false; } } //#endregion //#region src/utils/typegen.ts const TOP_LEVEL_NAMESPACE = "__TOP_LEVEL_MODULE__"; const DEFAULT_TYPE_DEF_HEADER = `/* auto-generated by NAPI-RS */ /* eslint-disable */ `; var TypeDefKind = /* @__PURE__ */ function(TypeDefKind$1) { TypeDefKind$1["Const"] = "const"; TypeDefKind$1["Enum"] = "enum"; TypeDefKind$1["StringEnum"] = "string_enum"; TypeDefKind$1["Interface"] = "interface"; TypeDefKind$1["Type"] = "type"; TypeDefKind$1["Fn"] = "fn"; TypeDefKind$1["Struct"] = "struct"; TypeDefKind$1["Extends"] = "extends"; TypeDefKind$1["Impl"] = "impl"; return TypeDefKind$1; }(TypeDefKind || {}); function prettyPrint(line, constEnum, ident, ambient = false) { let s = line.js_doc ?? ""; switch (line.kind) { case TypeDefKind.Interface: s += `export interface ${line.name} {\n${line.def}\n}`; break; case TypeDefKind.Type: s += `export type ${line.name} = \n${line.def}`; break; case TypeDefKind.Enum: const enumName = constEnum ? "const enum" : "enum"; s += `${exportDeclare(ambient)} ${enumName} ${line.name} {\n${line.def}\n}`; break; case TypeDefKind.StringEnum: if (constEnum) s += `${exportDeclare(ambient)} const enum ${line.name} {\n${line.def}\n}`; else s += `export type ${line.name} = ${line.def.replaceAll(/.*=/g, "").replaceAll(",", "|")};`; break; case TypeDefKind.Struct: const extendsDef = line.extends ? ` extends ${line.extends}` : ""; if (line.extends) { const genericMatch = line.extends.match(/Iterator<(.+)>$/); if (genericMatch) { const [T, TResult, TNext] = genericMatch[1].split(",").map((p) => p.trim()); line.def = line.def + `\nnext(value?: ${TNext}): IteratorResult<${T}, ${TResult}>`; } } s += `${exportDeclare(ambient)} class ${line.name}${extendsDef} {\n${line.def}\n}`; if (line.original_name && line.original_name !== line.name) s += `\nexport type ${line.original_name} = ${line.name}`; break; case TypeDefKind.Fn: s += `${exportDeclare(ambient)} ${line.def}`; break; default: s += line.def; } return correctStringIdent(s, ident); } function exportDeclare(ambient) { if (ambient) return "export"; return "export declare"; } async function processTypeDef(intermediateTypeFile, constEnum) { const exports$1 = []; const defs = await readIntermediateTypeFile(intermediateTypeFile); const groupedDefs = preprocessTypeDef(defs); return { dts: sortBy(Array.from(groupedDefs), [([namespace]) => namespace]).map(([namespace, defs$1]) => { if (namespace === TOP_LEVEL_NAMESPACE) return defs$1.map((def) => { switch (def.kind) { case TypeDefKind.Const: case TypeDefKind.Enum: case TypeDefKind.StringEnum: case TypeDefKind.Fn: case TypeDefKind.Struct: exports$1.push(def.name); if (def.original_name && def.original_name !== def.name) exports$1.push(def.original_name); break; default: break; } return prettyPrint(def, constEnum, 0); }).join("\n\n"); else { exports$1.push(namespace); let declaration = ""; declaration += `export declare namespace ${namespace} {\n`; for (const def of defs$1) declaration += prettyPrint(def, constEnum, 2, true) + "\n"; declaration += "}"; return declaration; } }).join("\n\n") + "\n", exports: exports$1 }; } async function readIntermediateTypeFile(file) { return (await readFileAsync(file, "utf8")).split("\n").filter(Boolean).map((line) => { line = line.trim(); const parsed = JSON.parse(line); if (parsed.js_doc) parsed.js_doc = parsed.js_doc.replace(/\\n/g, "\n"); if (parsed.def) parsed.def = parsed.def.replace(/\\n/g, "\n"); return parsed; }).sort((a, b) => { if (a.kind === TypeDefKind.Struct) { if (b.kind === TypeDefKind.Struct) return a.name.localeCompare(b.name); return -1; } else if (b.kind === TypeDefKind.Struct) return 1; else return a.name.localeCompare(b.name); }); } function preprocessTypeDef(defs) { const namespaceGrouped = /* @__PURE__ */ new Map(); const classDefs = /* @__PURE__ */ new Map(); for (const def of defs) { const namespace = def.js_mod ?? TOP_LEVEL_NAMESPACE; if (!namespaceGrouped.has(namespace)) namespaceGrouped.set(namespace, []); const group = namespaceGrouped.get(namespace); if (def.kind === TypeDefKind.Struct) { group.push(def); classDefs.set(def.name, def); } else if (def.kind === TypeDefKind.Extends) { const classDef = classDefs.get(def.name); if (classDef) classDef.extends = def.def; } else if (def.kind === TypeDefKind.Impl) { const classDef = classDefs.get(def.name); if (classDef) { if (classDef.def) classDef.def += "\n"; classDef.def += def.def; if (classDef.def) classDef.def = classDef.def.replace(/\\n/g, "\n"); } } else group.push(def); } return namespaceGrouped; } function correctStringIdent(src, ident) { let bracketDepth = 0; return src.split("\n").map((line) => { line = line.trim(); if (line === "") return ""; const isInMultilineComment = line.startsWith("*"); const isClosingBracket = line.endsWith("}"); const isOpeningBracket = line.endsWith("{"); const isTypeDeclaration = line.endsWith("="); const isTypeVariant = line.startsWith("|"); let rightIndent = ident; if ((isOpeningBracket || isTypeDeclaration) && !isInMultilineComment) { bracketDepth += 1; rightIndent += (bracketDepth - 1) * 2; } else { if (isClosingBracket && bracketDepth > 0 && !isInMultilineComment && !isTypeVariant) bracketDepth -= 1; rightIndent += bracketDepth * 2; } if (isInMultilineComment) rightIndent += 1; return `${" ".repeat(rightIndent)}${line}`; }).join("\n"); } //#endregion //#region src/utils/read-config.ts async function readConfig(options) { const resolvePath = (...paths) => resolve(options.cwd, ...paths); return await readNapiConfig(resolvePath(options.packageJsonPath ?? "package.json"), options.configPath ? resolvePath(options.configPath) : void 0); } //#endregion //#region src/api/artifacts.ts const debug$8 = debugFactory("artifacts"); async function collectArtifacts(userOptions) { const options = applyDefaultArtifactsOptions(userOptions); const resolvePath = (...paths) => resolve(options.cwd, ...paths); const packageJsonPath = resolvePath(options.packageJsonPath); const { targets, binaryName, packageName } = await readNapiConfig(packageJsonPath, options.configPath ? resolvePath(options.configPath) : void 0); const distDirs = targets.map((platform) => join(options.cwd, options.npmDir, platform.platformArchABI)); const universalSourceBins = new Set(targets.filter((platform) => platform.arch === "universal").flatMap((p) => { var _UniArchsByPlatform$p; return (_UniArchsByPlatform$p = UniArchsByPlatform[p.platform]) === null || _UniArchsByPlatform$p === void 0 ? void 0 : _UniArchsByPlatform$p.map((a) => `${p.platform}-${a}`); }).filter(Boolean)); await collectNodeBinaries(join(options.cwd, options.outputDir)).then((output) => Promise.all(output.map(async (filePath) => { debug$8.info(`Read [${colors.yellowBright(filePath)}]`); const sourceContent = await readFileAsync(filePath); const parsedName = parse(filePath); const terms = parsedName.name.split("."); const platformArchABI = terms.pop(); const _binaryName = terms.join("."); if (_binaryName !== binaryName) { debug$8.warn(`[${_binaryName}] is not matched with [${binaryName}], skip`); return; } const dir$1 = distDirs.find((dir$2) => dir$2.includes(platformArchABI)); if (!dir$1 && universalSourceBins.has(platformArchABI)) { debug$8.warn(`[${platformArchABI}] has no dist dir but it is source bin for universal arch, skip`); return; } if (!dir$1) throw new Error(`No dist dir found for ${filePath}`); const distFilePath = join(dir$1, parsedName.base); debug$8.info(`Write file content to [${colors.yellowBright(distFilePath)}]`); await writeFileAsync(distFilePath, sourceContent); const distFilePathLocal = join(parse(packageJsonPath).dir, parsedName.base); debug$8.info(`Write file content to [${colors.yellowBright(distFilePathLocal)}]`); await writeFileAsync(distFilePathLocal, sourceContent); }))); const wasiTarget = targets.find((t) => t.platform === "wasi"); if (wasiTarget) { const wasiDir = join(options.cwd, options.npmDir, wasiTarget.platformArchABI); const cjsFile = join(options.buildOutputDir ?? options.cwd, `${binaryName}.wasi.cjs`); const workerFile = join(options.buildOutputDir ?? options.cwd, `wasi-worker.mjs`); const browserEntry = join(options.buildOutputDir ?? options.cwd, `${binaryName}.wasi-browser.js`); const browserWorkerFile = join(options.buildOutputDir ?? options.cwd, `wasi-worker-browser.mjs`); debug$8.info(`Move wasi binding file [${colors.yellowBright(cjsFile)}] to [${colors.yellowBright(wasiDir)}]`); await writeFileAsync(join(wasiDir, `${binaryName}.wasi.cjs`), await readFileAsync(cjsFile)); debug$8.info(`Move wasi worker file [${colors.yellowBright(workerFile)}] to [${colors.yellowBright(wasiDir)}]`); await writeFileAsync(join(wasiDir, `wasi-worker.mjs`), await readFileAsync(workerFile)); debug$8.info(`Move wasi browser entry file [${colors.yellowBright(browserEntry)}] to [${colors.yellowBright(wasiDir)}]`); await writeFileAsync(join(wasiDir, `${binaryName}.wasi-browser.js`), (await readFileAsync(browserEntry, "utf8")).replace(`new URL('./wasi-worker-browser.mjs', import.meta.url)`, `new URL('${packageName}-wasm32-wasi/wasi-worker-browser.mjs', import.meta.url)`)); debug$8.info(`Move wasi browser worker file [${colors.yellowBright(browserWorkerFile)}] to [${colors.yellowBright(wasiDir)}]`); await writeFileAsync(join(wasiDir, `wasi-worker-browser.mjs`), await readFileAsync(browserWorkerFile)); } } async function collectNodeBinaries(root) { const files$1 = await readdirAsync(root, { withFileTypes: true }); const nodeBinaries = files$1.filter((file) => file.isFile() && (file.name.endsWith(".node") || file.name.endsWith(".wasm"))).map((file) => join(root, file.name)); const dirs = files$1.filter((file) => file.isDirectory()); for (const dir$1 of dirs) if (dir$1.name !== "node_modules") nodeBinaries.push(...await collectNodeBinaries(join(root, dir$1.name))); return nodeBinaries; } //#endregion //#region src/api/templates/js-binding.ts function createCjsBinding(localName, pkgName, idents, packageVersion) { return `${bindingHeader} ${createCommonBinding(localName, pkgName, packageVersion)} module.exports = nativeBinding ${idents.map((ident) => `module.exports.${ident} = nativeBinding.${ident}`).join("\n")} `; } function createEsmBinding(localName, pkgName, idents, packageVersion) { return `${bindingHeader} import { createRequire } from 'node:module' const require = createRequire(import.meta.url) const __dirname = new URL('.', import.meta.url).pathname ${createCommonBinding(localName, pkgName, packageVersion)} const { ${idents.join(", ")} } = nativeBinding ${idents.map((ident) => `export { ${ident} }`).join("\n")} `; } const bindingHeader = `// prettier-ignore /* eslint-disable */ // @ts-nocheck /* auto-generated by NAPI-RS */ `; function createCommonBinding(localName, pkgName, packageVersion) { function requireTuple(tuple, identSize = 8) { const identLow = " ".repeat(identSize - 2); const ident = " ".repeat(identSize); const versionCheck = packageVersion ? ` ${identLow}try { ${ident}const binding = require('${pkgName}-${tuple}') ${ident}const bindingPackageVersion = require('${pkgName}-${tuple}/package.json').version ${ident}if (bindingPackageVersion !== '${packageVersion}' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') { ${ident} throw new Error(\`Native binding package version mismatch, expected ${packageVersion} but got \${bindingPackageVersion}. You can reinstall dependencies to fix this issue.\`) ${ident}} ${ident}return binding ${identLow}} catch (e) { ${ident}loadErrors.push(e) ${identLow}}` : ` ${identLow}try { ${ident}return require('${pkgName}-${tuple}') ${identLow}} catch (e) { ${ident}loadErrors.push(e) ${identLow}}`; return `try { ${ident}return require('./${localName}.${tuple}.node') ${identLow}} catch (e) { ${ident}loadErrors.push(e) ${identLow}}${versionCheck}`; } return `const { readFileSync } = require('node:fs') let nativeBinding = null const loadErrors = [] const isMusl = () => { let musl = false if (process.platform === 'linux') { musl = isMuslFromFilesystem() if (musl === null) { musl = isMuslFromReport() } if (musl === null) { musl = isMuslFromChildProcess() } } return musl } const isFileMusl = (f) => f.includes('libc.musl-') || f.includes('ld-musl-') const isMuslFromFilesystem = () => { try { return readFileSync('/usr/bin/ldd', 'utf-8').includes('musl') } catch { return null } } const isMuslFromReport = () => { let report = null if (typeof process.report?.getReport === 'function') { process.report.excludeNetwork = true report = process.report.getReport() } if (!report) { return null } if (report.header && report.header.glibcVersionRuntime) { return false } if (Array.isArray(report.sharedObjects)) { if (report.sharedObjects.some(isFileMusl)) { return true } } return false } const isMuslFromChildProcess = () => { try { return require('child_process').execSync('ldd --version', { encoding: 'utf8' }).includes('musl') } catch (e) { // If we reach this case, we don't know if the system is musl or not, so is better to just fallback to false return false } } function requireNative() { if (process.env.NAPI_RS_NATIVE_LIBRARY_PATH) { try { return require(process.env.NAPI_RS_NATIVE_LIBRARY_PATH); } catch (err) { loadErrors.push(err) } } else if (process.platform === 'android') { if (process.arch === 'arm64') { ${requireTuple("android-arm64")} } else if (process.arch === 'arm') { ${requireTuple("android-arm-eabi")} } else { loadErrors.push(new Error(\`Unsupported architecture on Android \${process.arch}\`)) } } else if (process.platform === 'win32') { if (process.arch === 'x64') { if (process.config?.variables?.shlib_suffix === 'dll.a' || process.config?.variables?.node_target_type === 'shared_library') { ${requireTuple("win32-x64-gnu")} } else { ${requireTuple("win32-x64-msvc")} } } else if (process.arch === 'ia32') { ${requireTuple("win32-ia32-msvc")} } else if (process.arch === 'arm64') { ${requireTuple("win32-arm64-msvc")} } else { loadErrors.push(new Error(\`Unsupported architecture on Windows: \${process.arch}\`)) } } else if (process.platform === 'darwin') { ${requireTuple("darwin-universal", 6)} if (process.arch === 'x64') { ${requireTuple("darwin-x64")} } else if (process.arch === 'arm64') { ${requireTuple("darwin-arm64")} } else { loadErrors.push(new Error(\`Unsupported architecture on macOS: \${process.arch}\`)) } } else if (process.platform === 'freebsd') { if (process.arch === 'x64') { ${requireTuple("freebsd-x64")} } else if (process.arch === 'arm64') { ${requireTuple("freebsd-arm64")} } else { loadErrors.push(new Error(\`Unsupported architecture on FreeBSD: \${process.arch}\`)) } } else if (process.platform === 'linux') { if (process.arch === 'x64') { if (isMusl()) { ${requireTuple("linux-x64-musl", 10)} } else { ${requireTuple("linux-x64-gnu", 10)} } } else if (process.arch === 'arm64') { if (isMusl()) { ${requireTuple("linux-arm64-musl", 10)} } else { ${requireTuple("linux-arm64-gnu", 10)} } } else if (process.arch === 'arm') { if (isMusl()) { ${requireTuple("linux-arm-musleabihf", 10)} } else { ${requireTuple("linux-arm-gnueabihf", 10)} } } else if (process.arch === 'loong64') { if (isMusl()) { ${requireTuple("linux-loong64-musl", 10)} } else { ${requireTuple("linux-loong64-gnu", 10)} } } else if (process.arch === 'riscv64') { if (isMusl()) { ${requireTuple("linux-riscv64-musl", 10)} } else { ${requireTuple("linux-riscv64-gnu", 10)} } } else if (process.arch === 'ppc64') { ${requireTuple("linux-ppc64-gnu")} } else if (process.arch === 's390x') { ${requireTuple("linux-s390x-gnu")} } else { loadErrors.push(new Error(\`Unsupported architecture on Linux: \${process.arch}\`)) } } else if (process.platform === 'openharmony') { if (process.arch === 'arm64') { ${requireTuple("openharmony-arm64")} } else if (process.arch === 'x64') { ${requireTuple("openharmony-x64")} } else if (process.arch === 'arm') { ${requireTuple("openharmony-arm")} } else { loadErrors.push(new Error(\`Unsupported architecture on OpenHarmony: \${process.arch}\`)) } } else { loadErrors.push(new Error(\`Unsupported OS: \${process.platform}, architecture: \${process.arch}\`)) } } nativeBinding = requireNative() if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) { let wasiBinding = null let wasiBindingError = null try { wasiBinding = require('./${localName}.wasi.cjs') nativeBinding = wasiBinding } catch (err) { if (process.env.NAPI_RS_FORCE_WASI) { wasiBindingError = err } } if (!nativeBinding) { try { wasiBinding = require('${pkgName}-wasm32-wasi') nativeBinding = wasiBinding } catch (err) { if (process.env.NAPI_RS_FORCE_WASI) { wasiBindingError.cause = err loadErrors.push(err) } } } if (process.env.NAPI_RS_FORCE_WASI === 'error' && !wasiBinding) { const error = new Error('WASI binding not found and NAPI_RS_FORCE_WASI is set to error') error.cause = wasiBindingError throw error } } if (!nativeBinding) { if (loadErrors.length > 0) { throw new Error( \`Cannot find native binding. \` + \`npm has a bug related to optional dependencies (https://github.com/npm/cli/issues/4828). \` + 'Please try \`npm i\` again after removing both package-lock.json and node_modules directory.', { cause: loadErrors.reduce((err, cur) => { cur.cause = err return cur }), }, ) } throw new Error(\`Failed to load native binding\`) } `; } //#endregion //#region src/api/templates/load-wasi-template.ts const createWasiBrowserBinding = (wasiFilename, initialMemory = 4e3, maximumMemory = 65536, fs$1 = false, asyncInit = false, buffer = false) => { return `import { createOnMessage as __wasmCreateOnMessageForFsProxy, getDefaultContext as __emnapiGetDefaultContext, ${asyncInit ? `instantiateNapiModule as __emnapiInstantiateNapiModule` : `instantiateNapiModuleSync as __emnapiInstantiateNapiModuleSync`}, WASI as __WASI, } from '@napi-rs/wasm-runtime' ${fs$1 ? buffer ? `import { memfs, Buffer } from '@napi-rs/wasm-runtime/fs'` : `import { memfs } from '@napi-rs/wasm-runtime/fs'` : ""} ${buffer && !fs$1 ? `import { Buffer } from 'buffer'` : ""} ${fs$1 ? ` export const { fs: __fs, vol: __volume } = memfs() const __wasi = new __WASI({ version: 'preview1', fs: __fs, preopens: { '/': '/', }, })` : ` const __wasi = new __WASI({ version: 'preview1', })`} const __wasmUrl = new URL('./${wasiFilename}.wasm', import.meta.url).href const __emnapiContext = __emnapiGetDefaultContext() ${buffer ? "__emnapiContext.feature.Buffer = Buffer" : ""} const __sharedMemory = new WebAssembly.Memory({ initial: ${initialMemory}, maximum: ${maximumMemory}, shared: true, }) const __wasmFile = await fetch(__wasmUrl).then((res) => res.arrayBuffer()) const { instance: __napiInstance, module: __wasiModule, napiModule: __napiModule, } = ${asyncInit ? `await __emnapiInstantiateNapiModule` : `__emnapiInstantiateNapiModuleSync`}(__wasmFile, { context: __emnapiContext, asyncWorkPoolSize: 4, wasi: __wasi, onCreateWorker() { const worker = new Worker(new URL('./wasi-worker-browser.mjs', import.meta.url), { type: 'module', }) ${fs$1 ? ` worker.addEventListener('message', __wasmCreateOnMessageForFsProxy(__fs))\n` : ""} return worker }, overwriteImports(importObject) { importObject.env = { ...importObject.env, ...importObject.napi, ...importObject.emnapi, memory: __sharedMemory, } return importObject }, beforeInit({ instance }) { for (const name of Object.keys(instance.exports)) { if (name.startsWith('__napi_register__')) { instance.exports[name]() } } }, }) `; }; const createWasiBinding = (wasmFileName, packageName, initialMemory = 4e3, maximumMemory = 65536) => `/* eslint-disable */ /* prettier-ignore */ /* auto-generated by NAPI-RS */ const __nodeFs = require('node:fs') const __nodePath = require('node:path') const { WASI: __nodeWASI } = require('node:wasi') const { Worker } = require('node:worker_threads') const { createOnMessage: __wasmCreateOnMessageForFsProxy, getDefaultContext: __emnapiGetDefaultContext, instantiateNapiModuleSync: __emnapiInstantiateNapiModuleSync, } = require('@napi-rs/wasm-runtime') const __rootDir = __nodePath.parse(process.cwd()).root const __wasi = new __nodeWASI({ version: 'preview1', env: process.env, preopens: { [__rootDir]: __rootDir, } }) const __emnapiContext = __emnapiGetDefaultContext() const __sharedMemory = new WebAssembly.Memory({ initial: ${initialMemory}, maximum: ${maximumMemory}, shared: true, }) let __wasmFilePath = __nodePath.join(__dirname, '${wasmFileName}.wasm') const __wasmDebugFilePath = __nodePath.join(__dirname, '${wasmFileName}.debug.wasm') if (__nodeFs.existsSync(__wasmDebugFilePath)) { __wasmFilePath = __wasmDebugFilePath } else if (!__nodeFs.existsSync(__wasmFilePath)) { try { __wasmFilePath = __nodePath.resolve('${packageName}-wasm32-wasi') } catch { throw new Error('Cannot find ${wasmFileName}.wasm file, and ${packageName}-wasm32-wasi package is not installed.') } } const { instance: __napiInstance, module: __wasiModule, napiModule: __napiModule } = __emnapiInstantiateNapiModuleSync(__nodeFs.readFileSync(__wasmFilePath), { context: __emnapiContext, asyncWorkPoolSize: (function() { const threadsSizeFromEnv = Number(process.env.NAPI_RS_ASYNC_WORK_POOL_SIZE ?? process.env.UV_THREADPOOL_SIZE) // NaN > 0 is false if (threadsSizeFromEnv > 0) { return threadsSizeFromEnv } else { return 4 } })(), reuseWorker: true, wasi: __wasi, onCreateWorker() { const worker = new Worker(__nodePath.join(__dirname, 'wasi-worker.mjs'), { env: process.env, }) worker.onmessage = ({ data }) => { __wasmCreateOnMessageForFsProxy(__nodeFs)(data) } // The main thread of Node.js waits for all the active handles before exiting. // But Rust threads are never waited without \`thread::join\`. // So here we hack the code of Node.js to prevent the workers from being referenced (active). // According to https://github.com/nodejs/node/blob/19e0d472728c79d418b74bddff588bea70a403d0/lib/internal/worker.js#L415, // a worker is consist of two handles: kPublicPort and kHandle. { const kPublicPort = Object.getOwnPropertySymbols(worker).find(s => s.toString().includes("kPublicPort") ); if (kPublicPort) { worker[kPublicPort].ref = () => {}; } const kHandle = Object.getOwnPropertySymbols(worker).find(s => s.toString().includes("kHandle") ); if (kHandle) { worker[kHandle].ref = () => {}; } worker.unref(); } return worker }, overwriteImports(importObject) { importObject.env = { ...importObject.env, ...importObject.napi, ...importObject.emnapi, memory: __sharedMemory, } return importObject }, beforeInit({ instance }) { for (const name of Object.keys(instance.exports)) { if (name.startsWith('__napi_register__')) { instance.exports[name]() } } }, }) `; //#endregion //#region src/api/templates/wasi-worker-template.ts const WASI_WORKER_TEMPLATE = `import fs from "node:fs"; import { createRequire } from "node:module"; import { parse } from "node:path"; import { WASI } from "node:wasi"; import { parentPort, Worker } from "node:worker_threads"; const require = createRequire(import.meta.url); const { instantiateNapiModuleSync, MessageHandler, getDefaultContext } = require("@napi-rs/wasm-runtime"); if (parentPort) { parentPort.on("message", (data) => { globalThis.onmessage({ data }); }); } Object.assign(globalThis, { self: globalThis, require, Worker, importScripts: function (f) { ;(0, eval)(fs.readFileSync(f, "utf8") + "//# sourceURL=" + f); }, postMessage: function (msg) { if (parentPort) { parentPort.postMessage(msg); } }, }); const emnapiContext = getDefaultContext(); const __rootDir = parse(process.cwd()).root; const handler = new MessageHandler({ onLoad({ wasmModule, wasmMemory }) { const wasi = new WASI({ version: 'preview1', env: process.env, preopens: { [__rootDir]: __rootDir, }, }); return instantiateNapiModuleSync(wasmModule, { childThread: true, wasi, context: emnapiContext, overwriteImports(importObject) { importObject.env = { ...importObject.env, ...importObject.napi, ...importObject.emnapi, memory: wasmMemory }; }, }); }, }); globalThis.onmessage = function (e) { handler.handle(e); }; `; const createWasiBrowserWorkerBinding = (fs$1) => { return `${fs$1 ? `import { instantiateNapiModuleSync, MessageHandler, WASI, createFsProxy } from '@napi-rs/wasm-runtime' import { memfsExported as __memfsExported } from '@napi-rs/wasm-runtime/fs' const fs = createFsProxy(__memfsExported)` : `import { instantiateNapiModuleSync, MessageHandler, WASI } from '@napi-rs/wasm-runtime'`} const handler = new MessageHandler({ onLoad({ wasmModule, wasmMemory }) { ${fs$1 ? `const wasi = new WASI({ fs, preopens: { '/': '/', }, print: function () { // eslint-disable-next-line no-console console.log.apply(console, arguments) }, printErr: function() { // eslint-disable-next-line no-console console.error.apply(console, arguments) }, })` : `const wasi = new WASI({ print: function () { // eslint-disable-next-line no-console console.log.apply(console, arguments) }, printErr: function() { // eslint-disable-next-line no-console console.error.apply(console, arguments) }, })`} return instantiateNapiModuleSync(wasmModule, { childThread: true, wasi, overwriteImports(importObject) { importObject.env = { ...importObject.env, ...importObject.napi, ...importObject.emnapi, memory: wasmMemory, } }, }) }, }) globalThis.onmessage = function (e) { handler.handle(e) } `; }; //#endregion //#region src/api/build.ts const debug$7 = debugFactory("build"); const require = createRequire(import.meta.url); async function buildProject(rawOptions) { debug$7("napi build command receive options: %O", rawOptions); const options = { dtsCache: true, ...rawOptions, cwd: rawOptions.cwd ?? process.cwd() }; const resolvePath = (...paths) => resolve(options.cwd, ...paths); const manifestPath = resolvePath(options.manifestPath ?? "Cargo.toml"); const metadata = await parseMetadata(manifestPath); const crate = metadata.packages.find((p) => { if (options.package) return p.name === options.package; else return p.manifest_path === manifestPath; }); if (!crate) throw new Error("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."); const config = await readNapiConfig(resolvePath(options.packageJsonPath ?? "package.json"), options.configPath ? resolvePath(options.configPath) : void 0); return new Builder(metadata, crate, config, options).build(); } var Builder = class { args = []; envs = {}; outputs = []; target; crateDir; outputDir; targetDir; enableTypeDef = false; constructor(metadata, crate, config, options) { this.metadata = metadata; this.crate = crate; this.config = config; this.options = options; this.target = options.target ? parseTriple(options.target) : process.env.CARGO_BUILD_TARGET ? parseTriple(process.env.CARGO_BUILD_TARGET) : getSystemDefaultTarget(); this.crateDir = parse(crate.manifest_path).dir; this.outputDir = resolve(this.options.cwd, options.outputDir ?? this.crateDir); this.targetDir = options.targetDir ?? process.env.CARGO_BUILD_TARGET_DIR ?? metadata.target_directory; this.enableTypeDef = this.crate.dependencies.some((dep) => dep.name === "napi-derive" && (dep.uses_default_features || dep.features.includes("type-def"))); if (!this.enableTypeDef) { const requirementWarning = "`napi-derive` crate is not used or `type-def` feature is not enabled for `napi-derive` crate"; debug$7.warn(`${requirementWarning}. Will skip binding generation for \`.node\`, \`.wasi\` and \`.d.ts\` files.`); if (this.options.dts || this.options.dtsHeader || this.config.dtsHeader || this.config.dtsHeaderFile) debug$7.warn(`${requirementWarning}. \`dts\` related options are enabled but will be ignored.`); } } get cdyLibName() { var _this$crate$targets$f; return (_this$crate$targets$f = this.crate.targets.find((t) => t.crate_types.includes("cdylib"))) === null || _this$crate$targets$f === void 0 ? void 0 : _this$crate$targets$f.name; } get binName() { var _this$crate$targets$f2; return this.options.bin ?? (this.cdyLibName ? null : (_this$crate$targets$f2 = this.crate.targets.find((t) => t.crate_types.includes("bin"))) === null || _this$crate$targets$f2 === void 0 ? void 0 : _this$crate$targets$f2.name); } build() { if (!this.cdyLibName) { const warning = "Missing `crate-type = [\"cdylib\"]` in [lib] config. The build result will not be available as node addon."; if (this.binName) debug$7.warn(warning); else throw new Error(warning); } return this.pickBinary().setPackage().setFeatures().setTarget().pickCrossToolchain().setEnvs().setBypassArgs().exec(); } pickCrossToolchain() { if (!this.options.useNapiCross) return this; if (this.options.useCross) debug$7.warn("You are trying to use both `--cross` and `--use-napi-cross` options, `--use-cross` will be ignored."); if (this.options.crossCompile) debug$7.warn("You are trying to use both `--cross-compile` and `--use-napi-cross` options, `--cross-compile` will be ignored."); try { var _process$env$TARGET_C, _process$env$CC, _process$env$CXX, _process$env$TARGET_C2; const { version: version$2, download } = require("@napi-rs/cross-toolchain"); const alias = { "s390x-unknown-linux-gnu": "s390x-ibm-linux-gnu" }; const toolchainPath = join(homedir(), ".napi-rs", "cross-toolchain", version$2, this.target.triple); mkdirSync(toolchainPath, { recursive: true }); if (existsSync(join(toolchainPath, "package.json"))) debug$7(`Toolchain ${toolchainPath} exists, skip extracting`); else download(process.arch, this.target.triple).unpack(toolchainPath); const upperCaseTarget = targetToEnvVar(this.target.triple); const crossTargetName = alias[this.target.triple] ?? this.target.triple; const linkerEnv = `CARGO_TARGET_${upperCaseTarget}_LINKER`; this.setEnvIfNotExists(linkerEnv, join(toolchainPath, "bin", `${crossTargetName}-gcc`)); this.setEnvIfNotExists("TARGET_SYSROOT", join(toolchainPath, crossTargetName, "sysroot")); this.setEnvIfNotExists("TARGET_AR", join(toolchainPath, "bin", `${crossTargetName}-ar`)); this.setEnvIfNotExists("TARGET_RANLIB", join(toolchainPath, "bin", `${crossTargetName}-ranlib`)); this.setEnvIfNotExists("TARGET_READELF", join(toolchainPath, "bin", `${crossTargetName}-readelf`)); this.setEnvIfNotExists("TARGET_C_INCLUDE_PATH", join(toolchainPath, crossTargetName, "sysroot", "usr", "include/")); this.setEnvIfNotExists("TARGET_CC", join(toolchainPath, "bin", `${crossTargetName}-gcc`)); this.setEnvIfNotExists("TARGET_CXX", join(toolchainPath, "bin", `${crossTargetName}-g++`)); this.setEnvIfNotExists("BINDGEN_EXTRA_CLANG_ARGS", `--sysroot=${this.envs.TARGET_SYSROOT}}`); if (((_process$env$TARGET_C = process.env.TARGET_CC) === null || _process$env$TARGET_C === void 0 ? void 0 : _process$env$TARGET_C.startsWith("clang")) || ((_process$env$CC = process.env.CC) === null || _process$env$CC === void 0 ? void 0 : _process$env$CC.startsWith("clang")) && !process.env.TARGET_CC) { const TARG