diff --git a/apps/electron/electron-builder.yml b/apps/electron/electron-builder.yml index e65ba4b96..e6959365d 100644 --- a/apps/electron/electron-builder.yml +++ b/apps/electron/electron-builder.yml @@ -111,9 +111,7 @@ dmg: width: 540 height: 380 -# ============================================ # Windows 配置 -# ============================================ win: icon: resources/icon.ico fileAssociations: @@ -127,8 +125,9 @@ win: - target: nsis arch: - x64 + - arm64 -# NSIS 安装程序配置 +# NSIS 安装程序配置(x64 + arm64 均使用 NSIS 安装器体验一致) nsis: oneClick: false allowToChangeInstallationDirectory: true diff --git a/apps/electron/scripts/dist.ts b/apps/electron/scripts/dist.ts index 584fbc6a0..d379cf762 100644 --- a/apps/electron/scripts/dist.ts +++ b/apps/electron/scripts/dist.ts @@ -5,16 +5,33 @@ * 功能: * - 分步执行打包流程,每步带计时和状态指示 * - 支持只构建当前架构(--current-arch)加速开发测试 + * - 支持指定目标架构(--arm64 / --x64)覆盖当前架构 + * - 支持跨平台构建(如 macOS 构建 Windows ARM64) * - 支持详细输出模式(--verbose)查看 electron-builder 完整日志 * - 支持跳过代码签名(--no-sign) * - 支持只构建 DMG 或 ZIP(--dmg / --zip) + * - 支持跳过 CLI 编译(--skip-cli),用于跨架构构建时避免 bun build --compile 交叉编译问题 * * 使用: - * bun run scripts/dist.ts # 完整打包(双架构 + DMG + ZIP) + * # 本机构建(按当前系统架构) + * bun run scripts/dist.ts # 完整打包(双架构 + DMG + ZIP) * bun run scripts/dist.ts --current-arch # 只构建当前架构(快速) - * bun run scripts/dist.ts --current-arch --verbose # 当前架构 + 详细日志 - * bun run scripts/dist.ts --current-arch --dmg # 当前架构 + 只构建 DMG + * + * # 显式指定目标架构(覆盖当前架构) + * bun run scripts/dist.ts --arm64 # 只构建 ARM64 + * bun run scripts/dist.ts --x64 # 只构建 x64 + * bun run scripts/dist.ts --arm64 --verbose # ARM64 + 详细日志 + * bun run scripts/dist.ts --x64 --dmg # x64 + 只构建 DMG + * + * # 高级用法 * bun run scripts/dist.ts --no-sign # 跳过代码签名 + * bun run scripts/dist.ts --arm64 --skip-cli # ARM64 交叉构建(x64 主机,跳过 CLI) + * + * # 跨平台构建(在非目标平台构建) + * bun run scripts/dist.ts --win --arm64 # macOS 下构建 Windows ARM64 + * bun run scripts/dist.ts --win --x64 # macOS 下构建 Windows x64 + * bun run scripts/dist.ts --linux --arm64 # macOS 下构建 Linux ARM64 + * bun run scripts/dist.ts --linux --x64 # macOS 下构建 Linux x64 */ import { spawnSync } from 'child_process' @@ -37,6 +54,8 @@ interface DistOptions { noSign: boolean targetFormat: 'all' | 'dmg' | 'zip' | 'dir' platform: 'mac' | 'win' | 'linux' + targetArch: 'arm64' | 'x64' | null // 显式指定目标架构(覆盖当前架构) + skipCli: boolean // 跳过 CLI 编译(跨架构构建时使用) } // ============================================ @@ -134,10 +153,22 @@ function runStep( function parseArgs(): DistOptions { const args = process.argv.slice(2) + + // 检查冲突参数 + const hasTargetArch = args.some(a => a === '--arm64' || a === '--x64') + const hasCurrentArch = args.includes('--current-arch') + + // 优先级:--arm64/--x64 > --current-arch + if (hasTargetArch && hasCurrentArch) { + console.warn(`${color.yellow}[dist] 警告:同时使用 --arm64/--x64 和 --current-arch,忽略 --current-arch${color.reset}`) + } + return { - currentArch: args.includes('--current-arch'), + currentArch: hasCurrentArch && !hasTargetArch, verbose: args.includes('--verbose'), noSign: args.includes('--no-sign'), + skipCli: args.includes('--skip-cli'), + targetArch: args.includes('--arm64') ? 'arm64' : args.includes('--x64') ? 'x64' : null, targetFormat: args.includes('--dmg') ? 'dmg' : args.includes('--zip') @@ -155,16 +186,22 @@ function parseArgs(): DistOptions { function main(): void { const opts = parseArgs() - const arch = process.arch // arm64 或 x64 + const arch = process.arch const results: StepResult[] = [] // 打印配置信息 console.log(`\n${color.bgBlue}${color.bold} Proma 打包工具 ${color.reset}\n`) console.log(` ${color.bold}平台${color.reset}: ${opts.platform}`) - console.log(` ${color.bold}架构${color.reset}: ${opts.currentArch ? arch + ' (仅当前)' : 'arm64 + x64'}`) + const archDisplay = opts.targetArch + ? `${opts.targetArch} (指定)` + : opts.currentArch + ? `${arch} (仅当前)` + : 'arm64 + x64' + console.log(` ${color.bold}架构${color.reset}: ${archDisplay}`) console.log(` ${color.bold}格式${color.reset}: ${opts.targetFormat}`) console.log(` ${color.bold}签名${color.reset}: ${opts.noSign ? '跳过' : '启用'}`) console.log(` ${color.bold}详细日志${color.reset}: ${opts.verbose ? '开启' : '关闭'}`) + console.log(` ${color.bold}跳过 CLI${color.reset}: ${opts.skipCli ? '是' : '否'}`) printSeparator() const totalSteps = 6 @@ -200,8 +237,11 @@ function main(): void { // ── 步骤 4: 编译 proma CLI 二进制 ── step++ printStepStart(step, totalSteps, '编译 proma CLI (bun --compile)') + + // 跨架构构建时跳过 CLI 编译(bun build --compile 不支持交叉编译) + const skipCli = opts.skipCli || (opts.targetArch && opts.targetArch !== arch) results.push( - runStep('编译 proma CLI', 'bun', ['run', 'build:cli'], { verbose: opts.verbose }) + runStep('编译 proma CLI', 'bun', ['run', 'build:cli'], { verbose: opts.verbose, skip: skipCli }) ) printStepResult(results[results.length - 1]) if (!results[results.length - 1].success) return printSummary(results) @@ -220,8 +260,10 @@ function main(): void { const builderArgs = ['electron-builder', `--${opts.platform}`] - // 只构建当前架构 - if (opts.currentArch) { + // 指定目标架构(支持显式指定,用于跨架构构建如 x64 → arm64) + if (opts.targetArch) { + builderArgs.push(`--${opts.targetArch}`) + } else if (opts.currentArch) { builderArgs.push(`--${arch}`) } diff --git a/apps/electron/scripts/download-bun.ts b/apps/electron/scripts/download-bun.ts index 751ce21c1..435289b75 100644 --- a/apps/electron/scripts/download-bun.ts +++ b/apps/electron/scripts/download-bun.ts @@ -4,7 +4,7 @@ * * 功能: * - 从 GitHub releases 下载指定版本的 Bun 二进制文件 - * - 支持所有目标平台(darwin-arm64, darwin-x64, linux-arm64, linux-x64, win32-x64) + * - 支持所有目标平台(darwin-arm64, darwin-x64, linux-arm64, linux-x64, win32-x64, win32-arm64) * - SHA256 校验验证 * - 解压到 vendor/bun/{platform-arch}/ 目录 * @@ -30,6 +30,7 @@ const PLATFORM_ARCH_MAP: Record = { 'darwin-x64': 'darwin-x64', 'linux-arm64': 'linux-aarch64', 'linux-x64': 'linux-x64', + 'win32-arm64': 'windows-aarch64', 'win32-x64': 'windows-x64', } @@ -39,6 +40,7 @@ const TARGET_PLATFORMS: PlatformArch[] = [ 'darwin-x64', 'linux-arm64', 'linux-x64', + 'win32-arm64', 'win32-x64', ] diff --git a/apps/electron/src/main/lib/bun-finder.ts b/apps/electron/src/main/lib/bun-finder.ts index 19b49f9b6..0fb672c38 100644 --- a/apps/electron/src/main/lib/bun-finder.ts +++ b/apps/electron/src/main/lib/bun-finder.ts @@ -12,20 +12,82 @@ * 3. 开发仓库 apps/electron/vendor/bun/{platform-arch}/(dev 用) */ -import { existsSync } from 'fs' +import { existsSync, readFileSync } from 'fs' import { join, dirname } from 'path' import { execSync, spawnSync } from 'child_process' import { app } from 'electron' import type { BunRuntimeStatus, PlatformArch } from '@proma/shared' +// ============================================ +// 工具函数 +// ============================================ + +/** + * 获取原生 CPU 架构(用于检测 Windows ARM64 模拟模式) + * + * 在 Windows ARM64 上运行 x64 进程时: + * - process.arch 返回 'x64'(模拟) + * - OS 提供的原生架构仍是 'ARM64' + * + * @returns Node.js 能识别的架构标识 + */ +function getNativeArch(): 'arm64' | 'x64' | 'unknown' { + try { + // Windows: 通过 WMI 查询原生 CPU 架构 + const wmicOutput = execSync('wmic cpu get Architecture', { + encoding: 'utf-8', + stdio: ['pipe', 'pipe', 'ignore'], + }).trim() + // WMI 返回:0=x86, 9= x64, 12=ARM64 + // 但更可靠的方式是检查 PROCESSOR_PROCESSORID 环境变量 + if (process.env.Processor_Architecture === 'ARM64') { + return 'arm64' + } + if (process.env.Processor_Architecture === 'AMD64') { + return 'x64' + } + // fallback: 从 wmic 输出解析(备用) + if (wmicOutput.includes('ARM64') || wmicOutput.includes('12')) { + return 'arm64' + } + if (wmicOutput.includes('x64') || wmicOutput.includes('9')) { + return 'x64' + } + } catch { + // wmi 失败,fallback 到 process.arch + } + return 'unknown' +} + /** * 获取当前平台架构标识 * + * 在 Windows ARM64 模拟模式下(x64 进程运行在 ARM64 上): + * - process.platform === 'win32' + * - process.arch === 'x64'(模拟) + * - 但实际原生架构是 ARM64 + * + * 优先使用原生架构检测,fallback 到 process.arch + * * @returns 当前系统的平台架构组合 */ export function getCurrentPlatformArch(): PlatformArch { const platform = process.platform as 'darwin' | 'linux' | 'win32' - const arch = process.arch as 'arm64' | 'x64' + + // Windows 特殊处理:检测原生架构 + let arch: 'arm64' | 'x64' + if (platform === 'win32') { + const nativeArch = getNativeArch() + if (nativeArch !== 'unknown') { + arch = nativeArch + } else { + // fallback 到 process.arch(正常模式或 wmi 失败) + arch = process.arch as 'arm64' | 'x64' + } + } else { + // macOS/Linux 直接使用 process.arch + arch = process.arch as 'arm64' | 'x64' + } // 验证支持的组合 const platformArch = `${platform}-${arch}` as PlatformArch @@ -35,6 +97,7 @@ export function getCurrentPlatformArch(): PlatformArch { 'darwin-x64', 'linux-arm64', 'linux-x64', + 'win32-arm64', 'win32-x64', ] diff --git a/packages/shared/package.json b/packages/shared/package.json index 74129f42d..a6d4f18ca 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -1,6 +1,6 @@ { "name": "@proma/shared", - "version": "0.1.41", + "version": "0.1.42", "license": "AGPL-3.0-only", "description": "Shared types, configs and utilities for proma", "type": "module", diff --git a/packages/shared/src/types/runtime.ts b/packages/shared/src/types/runtime.ts index 593b00226..a11c32801 100644 --- a/packages/shared/src/types/runtime.ts +++ b/packages/shared/src/types/runtime.ts @@ -22,6 +22,7 @@ export type PlatformArch = | 'darwin-x64' | 'linux-arm64' | 'linux-x64' + | 'win32-arm64' | 'win32-x64' /**