While developing ClipVault , a cross-platform clipboard manager, I went through the full gauntlet from code-style checks to multi-platform compilation. This article documents the complete solution set, from Biome CI check failures to Rust cross-platform linking errors.
Project Background
Tech stack : Tauri 2.0 + React + Rust
Target platforms : Windows (x86/x64/ARM64) + macOS (Intel/Apple Silicon) + Linux (x64/ARM64)
CI/CD : GitHub Actions
Pitfall One: Biome CI Version Mismatch and Code Style Symptom GitHub Actions errors out when running biome ci .:
Notice : The configuration schema version does not match the CLI version 2 .4 .6 Expected : 2 .4 .6 , Found: 2 .2 .6
Along with a pile of code-style errors:
Error: The properties are not sorted. (CSS properties not sorted)
Error: The object properties are not sorted by key. (object keys not sorted)
Error: Provide an explicit type attribute for the button element. (button missing a type attribute)
Cause Analysis
Version mismatch : local Biome version (2.2.6) doesn’t match the CI environment (2.4.6)
Strict rules : Biome enables strict rules like useSortedProperties and useSortedKeys by default
dist directory : the build output directory was mistakenly included in the check scope
Solution 1. Unify the version { "$schema" : "https://biomejs.dev/schemas/2.4.6/schema.json" }
pnpm add -D @biomejs/biome@2.4.6
2. Exclude files that shouldn’t be checked { "files" : { "includes" : [ "**" , "!package.json" , "!.release-it.ts" , "!dist/**" , "!scripts/auto-fix.js" ] } }
3. Auto-fix code style pnpm biome check --write --unsafe .
Key Config { "$schema" : "https://biomejs.dev/schemas/2.4.6/schema.json" , "assist" : { "actions" : { "source" : { "organizeImports" : "on" , "useSortedAttributes" : "on" , "useSortedKeys" : "on" , "useSortedProperties" : "on" } } } , "files" : { "includes" : [ "**" , "!package.json" , "!.release-it.ts" , "!dist/**" ] } }
Symptom The Linux build errors out:
error: linking with `cc` failed: exit status: 1 rust-lld: error: cannot open /FORCE:MULTIPLE: No such file or directory collect2: error: ld returned 1 exit status
Cause Analysis /FORCE:MULTIPLE is a Windows MSVC linker-specific option used to forcibly allow multiple definitions. When that option is mistakenly passed to Linux’s ld linker, the build fails.
Wrong Configuration [build] rustflags = ["-C" , "link-arg=/FORCE:MULTIPLE" , "-C" , "prefer-dynamic" ]
Solution Use Cargo’s conditional target configuration to apply the option only under the Windows target:
[target.x86_64-pc-windows-msvc] rustflags = ["-C" , "link-arg=/FORCE:MULTIPLE" ][target.i686-pc-windows-msvc] rustflags = ["-C" , "link-arg=/FORCE:MULTIPLE" ][target.aarch64-pc-windows-msvc] rustflags = ["-C" , "link-arg=/FORCE:MULTIPLE" ][target.aarch64-unknown-linux-gnu] linker = "aarch64-linux-gnu-gcc"
Pitfall Three: LTO Conflicts with Dynamic Linking Symptom macOS and Linux builds error out:
error: cannot prefer dynamic linking when performing LTO note: only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO
Cause Analysis prefer-dynamic (preferring dynamic linking) conflicts with lto = true (link-time optimization):
Fat LTO (lto = true) requires static linking
Dynamic linking produces dynamic library dependencies
Solution Option 1: Use Thin LTO (recommended) [profile.release] strip = true lto = "thin" opt-level = 3
Option 2: Fully disable LTO [profile.release] strip = true
Final Configuration [profile.release] strip = true lto = "thin" opt-level = 3
Pitfall Four: apt Source Configuration for Ubuntu ARM64 Cross-Compilation Symptom apt installation fails during Linux ARM64 cross-compilation:
E: Failed to fetch https:// security.ubuntu.com/ubuntu/ dists/jammy/m ain/binary-arm64/ Packages 404 Not Found E: Failed to fetch https:// security.ubuntu.com/ubuntu/ dists/jammy-updates/m ain/binary-arm64/ Packages 404 Not Found
Cause Analysis Ubuntu 22.04’s default sources archive.ubuntu.com and security.ubuntu.com contain only x86_64 architecture packages. ARM64 architecture packages are hosted on ports.ubuntu.com.
Solution 1. Switch the apt sources to ports.ubuntu.com - name: Install ARM cross-compile dependencies if: matrix.target == 'aarch64-unknown-linux-gnu' run: | sudo dpkg --add-architecture arm64 # Key: switch apt sources to ports.ubuntu.com (supports ARM64) sudo sed -i 's|http://archive.ubuntu.com/ubuntu/|http://ports.ubuntu.com/ubuntu-ports/|g' /etc/apt/sources.list sudo sed -i 's|http://security.ubuntu.com/ubuntu/|http://ports.ubuntu.com/ubuntu-ports/|g' /etc/apt/sources.list sudo apt-get update || true sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu sudo apt-get install -y libwebkit2gtk-4.1-dev:arm64 libappindicator3-dev:arm64 librsvg2-dev:arm64 patchelf || true
- name: Setup ARM cross-compile env if: matrix.target == 'aarch64-unknown-linux-gnu' run: | echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV echo "CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc" >> $GITHUB_ENV echo "CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++" >> $GITHUB_ENV echo "PKG_CONFIG_SYSROOT_DIR=/usr/aarch64-linux-gnu" >> $GITHUB_ENV echo "PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig" >> $GITHUB_ENV echo "PKG_CONFIG_ALLOW_CROSS=1" >> $GITHUB_ENV
3. Cargo configuration [target.aarch64-unknown-linux-gnu] linker = "aarch64-linux-gnu-gcc"
Full Configuration Reference .github/workflows/release.yml name: Release CI on: push: tags: - "v*" jobs: build-app: permissions: contents: write strategy: fail-fast: false matrix: include: - platform: "macos-latest" target: "aarch64-apple-darwin" - platform: "macos-latest" target: "x86_64-apple-darwin" - platform: "windows-latest" target: "x86_64-pc-windows-msvc" - platform: "windows-latest" target: "i686-pc-windows-msvc" - platform: "windows-latest" target: "aarch64-pc-windows-msvc" - platform: "ubuntu-22.04" target: "x86_64-unknown-linux-gnu" - platform: "ubuntu-22.04" target: "aarch64-unknown-linux-gnu" runs-on: ${{ matrix.platform }} steps: - uses: actions/checkout@v4 - name: Setup node uses: actions/setup-node@v4 with: node-version: 20 - uses: pnpm/action-setup@v3 with: version: latest - name: Install Rust uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.target }} - name: Install dependencies (ubuntu only) if: matrix.platform == 'ubuntu-22.04' run: | sudo apt-get update sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf - name: Install ARM cross-compile dependencies if: matrix.target == 'aarch64-unknown-linux-gnu' run: | sudo dpkg --add-architecture arm64 # Switch apt sources to ports.ubuntu.com sudo sed -i 's|http://archive.ubuntu.com/ubuntu/|http://ports.ubuntu.com/ubuntu-ports/|g' /etc/apt/sources.list sudo sed -i 's|http://security.ubuntu.com/ubuntu/|http://ports.ubuntu.com/ubuntu-ports/|g' /etc/apt/sources.list sudo apt-get update || true sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu sudo apt-get install -y libwebkit2gtk-4.1-dev:arm64 libappindicator3-dev:arm64 librsvg2-dev:arm64 patchelf || true - name: Rust cache uses: swatinem/rust-cache@v2 with: workspaces: src-tauri/target key: ${{ matrix.target }} - name: Setup ARM cross-compile env if: matrix.target == 'aarch64-unknown-linux-gnu' run: | echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV echo "CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc" >> $GITHUB_ENV echo "CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++" >> $GITHUB_ENV echo "PKG_CONFIG_SYSROOT_DIR=/usr/aarch64-linux-gnu" >> $GITHUB_ENV echo "PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig" >> $GITHUB_ENV echo "PKG_CONFIG_ALLOW_CROSS=1" >> $GITHUB_ENV - name: Build the app uses: tauri-apps/tauri-action@v0 env: CI: false GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} with: tagName: ${{ github.ref_name }} releaseName: "ClipVault ${{ github.ref_name }} " releaseDraft: false prerelease: false args: --target ${{ matrix.target }}
.cargo/config.toml [target.x86_64-pc-windows-msvc] rustflags = ["-C" , "link-arg=/FORCE:MULTIPLE" ][target.i686-pc-windows-msvc] rustflags = ["-C" , "link-arg=/FORCE:MULTIPLE" ][target.aarch64-pc-windows-msvc] rustflags = ["-C" , "link-arg=/FORCE:MULTIPLE" ][target.aarch64-unknown-linux-gnu] linker = "aarch64-linux-gnu-gcc" [target.aarch64-apple-darwin] linker = "clang" rustflags = ["-C" , "link-arg=-arch" , "-C" , "link-arg=arm64" ][target.x86_64-apple-darwin] linker = "clang" rustflags = ["-C" , "link-arg=-arch" , "-C" , "link-arg=x86_64" ][profile.release] strip = true lto = "thin" opt-level = 3
Build Matrix Summary
Platform
Architecture
Rust Target
Special Config
Windows
x86_64
x86_64-pc-windows-msvc
/FORCE:MULTIPLE
Windows
x86
i686-pc-windows-msvc
/FORCE:MULTIPLE
Windows
ARM64
aarch64-pc-windows-msvc
/FORCE:MULTIPLE
macOS
Intel
x86_64-apple-darwin
clang + arch flag
macOS
Apple Silicon
aarch64-apple-darwin
clang + arch flag
Linux
x86_64
x86_64-unknown-linux-gnu
default config
Linux
ARM64
aarch64-unknown-linux-gnu
ports.ubuntu.com + cross toolchain
Summary The core points of Tauri cross-platform builds:
Code style : keep Biome/Prettier versions consistent and exclude the build output directory
Linker config : use Cargo’s conditional target configuration to avoid applying Windows-only options to other platforms
LTO strategy : use thin LTO to balance build speed and binary optimization
Cross-compilation : Ubuntu ARM64 needs to switch to the ports.ubuntu.com source
For the complete code, see the ClipVault GitHub repository .
This article is based on hands-on experience with Tauri 2.0 + GitHub Actions, and I hope it helps more developers avoid these pitfalls.
评论
0 条评论