Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions apps/electron/electron-builder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,7 @@ dmg:
width: 540
height: 380

# ============================================
# Windows 配置
# ============================================
win:
icon: resources/icon.ico
fileAssociations:
Expand All @@ -127,8 +125,9 @@ win:
- target: nsis
arch:
- x64
- arm64

# NSIS 安装程序配置
# NSIS 安装程序配置(x64 + arm64 均使用 NSIS 安装器体验一致)
nsis:
oneClick: false
allowToChangeInstallationDirectory: true
Expand Down
60 changes: 51 additions & 9 deletions apps/electron/scripts/dist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -37,6 +54,8 @@ interface DistOptions {
noSign: boolean
targetFormat: 'all' | 'dmg' | 'zip' | 'dir'
platform: 'mac' | 'win' | 'linux'
targetArch: 'arm64' | 'x64' | null // 显式指定目标架构(覆盖当前架构)
skipCli: boolean // 跳过 CLI 编译(跨架构构建时使用)
}

// ============================================
Expand Down Expand Up @@ -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')
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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}`)
}

Expand Down
4 changes: 3 additions & 1 deletion apps/electron/scripts/download-bun.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}/ 目录
*
Expand All @@ -30,6 +30,7 @@ const PLATFORM_ARCH_MAP: Record<PlatformArch, string> = {
'darwin-x64': 'darwin-x64',
'linux-arm64': 'linux-aarch64',
'linux-x64': 'linux-x64',
'win32-arm64': 'windows-aarch64',
'win32-x64': 'windows-x64',
}

Expand All @@ -39,6 +40,7 @@ const TARGET_PLATFORMS: PlatformArch[] = [
'darwin-x64',
'linux-arm64',
'linux-x64',
'win32-arm64',
'win32-x64',
]

Expand Down
67 changes: 65 additions & 2 deletions apps/electron/src/main/lib/bun-finder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -35,6 +97,7 @@ export function getCurrentPlatformArch(): PlatformArch {
'darwin-x64',
'linux-arm64',
'linux-x64',
'win32-arm64',
'win32-x64',
]

Expand Down
2 changes: 1 addition & 1 deletion packages/shared/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
1 change: 1 addition & 0 deletions packages/shared/src/types/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export type PlatformArch =
| 'darwin-x64'
| 'linux-arm64'
| 'linux-x64'
| 'win32-arm64'
| 'win32-x64'

/**
Expand Down