1616 release :
1717 runs-on : ${{ matrix.os }}
1818 strategy :
19+ fail-fast : false
1920 matrix :
2021 include :
2122 - os : windows-2022
23+ - os : windows-11-arm
24+ arch : arm64
2225 - os : ubuntu-22.04
2326 - os : ubuntu-22.04-arm
2427 arch : arm64
3639 - name : Setup Rust
3740 uses : dtolnay/rust-toolchain@stable
3841
42+ - name : Add Windows ARM64 target
43+ if : runner.os == 'Windows' && matrix.arch == 'arm64'
44+ shell : pwsh
45+ run : rustup target add aarch64-pc-windows-msvc
46+
3947 - name : Add macOS targets
4048 if : runner.os == 'macOS'
4149 run : |
@@ -74,23 +82,50 @@ jobs:
7482 || sudo apt-get install -y --no-install-recommends libsoup2.4-dev
7583
7684 - name : Setup pnpm
85+ if : runner.os != 'Windows' || matrix.arch != 'arm64'
7786 uses : pnpm/action-setup@v6
7887 with :
7988 version : 10.12.3
8089 run_install : false
8190
91+ - name : Setup pnpm (Windows ARM64)
92+ if : runner.os == 'Windows' && matrix.arch == 'arm64'
93+ shell : pwsh
94+ run : |
95+ $ErrorActionPreference = 'Stop'
96+ corepack enable
97+ corepack prepare pnpm@10.12.3 --activate
98+ node --version
99+ pnpm --version
100+
82101 - name : Get pnpm store directory
102+ if : runner.os != 'Windows' || matrix.arch != 'arm64'
83103 id : pnpm-store
84104 shell : bash
85105 run : echo "path=$(pnpm store path --silent)" >> $GITHUB_OUTPUT
86106
87107 - name : Setup pnpm cache
108+ if : runner.os != 'Windows' || matrix.arch != 'arm64'
88109 uses : actions/cache@v5
89110 with :
90111 path : ${{ steps.pnpm-store.outputs.path }}
91112 key : ${{ runner.os }}-${{ runner.arch }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
92113 restore-keys : ${{ runner.os }}-${{ runner.arch }}-pnpm-store-
93114
115+ - name : Setup LLVM for Windows ARM64
116+ if : runner.os == 'Windows' && matrix.arch == 'arm64'
117+ shell : pwsh
118+ run : |
119+ $ErrorActionPreference = 'Stop'
120+ $llvmRoot = 'C:\Program Files\LLVM'
121+ if (-not (Test-Path $llvmRoot)) {
122+ throw "LLVM not found at $llvmRoot"
123+ }
124+ $llvmBin = Join-Path $llvmRoot 'bin'
125+ "LIBCLANG_PATH=$llvmBin" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
126+ "CLANG_PATH=$(Join-Path $llvmBin 'clang.exe')" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
127+ $llvmBin | Out-File -FilePath $env:GITHUB_PATH -Append -Encoding utf8
128+
94129 - name : Install frontend deps
95130 run : pnpm install --frozen-lockfile
96131
@@ -223,7 +258,16 @@ jobs:
223258
224259 - name : Build Tauri App (Windows)
225260 if : runner.os == 'Windows'
226- run : pnpm tauri build
261+ shell : pwsh
262+ env :
263+ WINDOWS_RELEASE_ARCH : ${{ matrix.arch || 'x86_64' }}
264+ run : |
265+ $ErrorActionPreference = 'Stop'
266+ if ($env:WINDOWS_RELEASE_ARCH -eq 'arm64') {
267+ pnpm tauri build --target aarch64-pc-windows-msvc --bundles msi
268+ } else {
269+ pnpm tauri build
270+ }
227271
228272 - name : Build Tauri App (Linux)
229273 if : runner.os == 'Linux'
@@ -394,50 +438,75 @@ jobs:
394438 - name : Prepare Windows Assets
395439 if : runner.os == 'Windows'
396440 shell : pwsh
441+ env :
442+ WINDOWS_RELEASE_ARCH : ${{ matrix.arch || 'x86_64' }}
397443 run : |
398444 $ErrorActionPreference = 'Stop'
399445 New-Item -ItemType Directory -Force -Path release-assets | Out-Null
400446 $VERSION = $env:GITHUB_REF_NAME # e.g., v3.5.0
447+ $isArm64 = $env:WINDOWS_RELEASE_ARCH -eq 'arm64'
448+ $targetRoot = if ($isArm64) { 'src-tauri/target/aarch64-pc-windows-msvc/release' } else { 'src-tauri/target/release' }
449+ $assetSuffix = if ($isArm64) { '-arm64' } else { '' }
450+
401451 # 仅打包 MSI 安装器 + .sig(用于 Updater)
402- $msi = Get-ChildItem -Path 'src-tauri/target/release/ bundle/msi' -Recurse -Include *.msi -ErrorAction SilentlyContinue | Select-Object -First 1
452+ $msi = Get-ChildItem -Path (Join-Path $targetRoot ' bundle/msi') -Recurse -Include *.msi -ErrorAction SilentlyContinue | Select-Object -First 1
403453 if ($null -eq $msi) {
404454 # 兜底:全局搜索 .msi
405- $msi = Get-ChildItem -Path 'src-tauri/target/release/ bundle' -Recurse -Include *.msi -ErrorAction SilentlyContinue | Select-Object -First 1
455+ $msi = Get-ChildItem -Path (Join-Path $targetRoot ' bundle') -Recurse -Include *.msi -ErrorAction SilentlyContinue | Select-Object -First 1
406456 }
407457 if ($null -ne $msi) {
408- $dest = "CC-Switch-$VERSION-Windows.msi"
458+ $dest = "CC-Switch-$VERSION-Windows$assetSuffix .msi"
409459 Copy-Item $msi.FullName (Join-Path release-assets $dest)
410460 Write-Host "Installer copied: $dest"
411461 $sigPath = "$($msi.FullName).sig"
412462 if (Test-Path $sigPath) {
413463 Copy-Item $sigPath (Join-Path release-assets ("$dest.sig"))
414464 Write-Host "Signature copied: $dest.sig"
465+ } elseif ($isArm64) {
466+ throw "Signature not found for $($msi.Name)"
415467 } else {
416468 Write-Warning "Signature not found for $($msi.Name)"
417469 }
470+ } elseif ($isArm64) {
471+ throw 'No Windows ARM64 MSI installer found'
418472 } else {
419473 Write-Warning 'No Windows MSI installer found'
420474 }
475+
421476 # 绿色版(portable):仅可执行文件打 zip(不参与 Updater)
422- $exeCandidates = @(
423- 'src-tauri/target/release/cc-switch.exe',
424- 'src-tauri/target/x86_64-pc-windows-msvc/release/cc-switch.exe'
425- )
477+ $exeCandidates = if ($isArm64) {
478+ @('src-tauri/target/aarch64-pc-windows-msvc/release/cc-switch.exe')
479+ } else {
480+ @(
481+ 'src-tauri/target/release/cc-switch.exe',
482+ 'src-tauri/target/x86_64-pc-windows-msvc/release/cc-switch.exe'
483+ )
484+ }
426485 $exePath = $exeCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1
427486 if ($null -ne $exePath) {
428487 $portableDir = 'release-assets/CC-Switch-Portable'
429488 New-Item -ItemType Directory -Force -Path $portableDir | Out-Null
430489 Copy-Item $exePath $portableDir
431490 $portableIniPath = Join-Path $portableDir 'portable.ini'
432- $portableContent = @(
433- '# CC Switch portable build marker',
434- 'portable=true'
435- )
491+ $portableContent = if ($isArm64) {
492+ @(
493+ '# CC Switch portable ARM64 build marker',
494+ 'portable=true',
495+ 'arch=arm64'
496+ )
497+ } else {
498+ @(
499+ '# CC Switch portable build marker',
500+ 'portable=true'
501+ )
502+ }
436503 $portableContent | Set-Content -Path $portableIniPath -Encoding UTF8
437- $portableZip = "release-assets/CC-Switch-$VERSION-Windows-Portable.zip"
504+ $portableZip = "release-assets/CC-Switch-$VERSION-Windows$assetSuffix -Portable.zip"
438505 Compress-Archive -Path "$portableDir/*" -DestinationPath $portableZip -Force
439506 Remove-Item -Recurse -Force $portableDir
440- Write-Host "Windows portable zip created: CC-Switch-$VERSION-Windows-Portable.zip"
507+ Write-Host "Windows portable zip created: CC-Switch-$VERSION-Windows$assetSuffix-Portable.zip"
508+ } elseif ($isArm64) {
509+ throw 'Portable ARM64 exe not found'
441510 } else {
442511 Write-Warning 'Portable exe not found'
443512 }
@@ -550,7 +619,8 @@ jobs:
550619 ### 下载
551620
552621 - **macOS**: `CC-Switch-${{ github.ref_name }}-macOS.dmg`(推荐)或 `CC-Switch-${{ github.ref_name }}-macOS.zip`(解压即用)
553- - **Windows**: `CC-Switch-${{ github.ref_name }}-Windows.msi`(安装版)或 `CC-Switch-${{ github.ref_name }}-Windows-Portable.zip`(绿色版)
622+ - **Windows (x86_64)**: `CC-Switch-${{ github.ref_name }}-Windows.msi`(安装版)或 `CC-Switch-${{ github.ref_name }}-Windows-Portable.zip`(绿色版)
623+ - **Windows (ARM64)**: `CC-Switch-${{ github.ref_name }}-Windows-arm64.msi`(安装版)或 `CC-Switch-${{ github.ref_name }}-Windows-arm64-Portable.zip`(绿色版)
554624 - **Linux (x86_64)**: `CC-Switch-${{ github.ref_name }}-Linux-x86_64.AppImage` / `.deb` / `.rpm`
555625 - **Linux (ARM64)**: `CC-Switch-${{ github.ref_name }}-Linux-arm64.AppImage` / `.deb` / `.rpm`
556626
@@ -594,7 +664,8 @@ jobs:
594664 base_url="https://github.com/$REPO/releases/download/$TAG"
595665 # 初始化空平台映射
596666 mac_url=""; mac_sig=""
597- win_url=""; win_sig=""
667+ win_x64_url=""; win_x64_sig=""
668+ win_arm64_url=""; win_arm64_sig=""
598669 linux_x64_url=""; linux_x64_sig=""
599670 linux_arm64_url=""; linux_arm64_sig=""
600671 shopt -s nullglob
@@ -607,12 +678,14 @@ jobs:
607678 *.tar.gz)
608679 # 视为 macOS updater artifact
609680 mac_url="$url"; mac_sig="$sig_content";;
681+ *-Windows-arm64.msi)
682+ win_arm64_url="$url"; win_arm64_sig="$sig_content";;
683+ *-Windows.msi)
684+ win_x64_url="$url"; win_x64_sig="$sig_content";;
610685 *-Linux-arm64.AppImage|*-Linux-arm64.appimage)
611686 linux_arm64_url="$url"; linux_arm64_sig="$sig_content";;
612687 *-Linux-x86_64.AppImage|*-Linux-x86_64.appimage)
613688 linux_x64_url="$url"; linux_x64_sig="$sig_content";;
614- *.msi|*.exe)
615- win_url="$url"; win_sig="$sig_content";;
616689 esac
617690 done
618691 # 构造 JSON(仅包含存在的目标)
@@ -632,9 +705,14 @@ jobs:
632705 first=0
633706 done
634707 fi
635- if [ -n "$win_url" ] && [ -n "$win_sig" ]; then
708+ if [ -n "$win_x64_url" ] && [ -n "$win_x64_sig" ]; then
709+ [ $first -eq 0 ] && echo ','
710+ echo " \"windows-x86_64\": {\"signature\": \"$win_x64_sig\", \"url\": \"$win_x64_url\"}"
711+ first=0
712+ fi
713+ if [ -n "$win_arm64_url" ] && [ -n "$win_arm64_sig" ]; then
636714 [ $first -eq 0 ] && echo ','
637- echo " \"windows-x86_64 \": {\"signature\": \"$win_sig \", \"url\": \"$win_url \"}"
715+ echo " \"windows-aarch64 \": {\"signature\": \"$win_arm64_sig \", \"url\": \"$win_arm64_url \"}"
638716 first=0
639717 fi
640718 if [ -n "$linux_x64_url" ] && [ -n "$linux_x64_sig" ]; then
0 commit comments