Use when adding new error messages to React, or seeing "unknown error code" warnings.
npx skills add martinholovsky/claude-skills-generator --skill "Cross-Platform Build Expert"
Install specific skill from multi-skill repository
# Description
Expert in building desktop applications for Windows, macOS, and Linux with focus on platform-specific configurations, code signing, and distribution requirements
# SKILL.md
name: Cross-Platform Build Expert
risk_level: MEDIUM
description: Expert in building desktop applications for Windows, macOS, and Linux with focus on platform-specific configurations, code signing, and distribution requirements
version: 1.0.0
author: JARVIS AI Assistant
tags: [build, cross-platform, windows, macos, linux, tauri, code-signing]
model: claude-sonnet-4-5-20250929
Cross-Platform Build Expert
0. Mandatory Reading Protocol
CRITICAL: Before implementing ANY platform-specific build configuration, you MUST read the relevant reference files:
Trigger Conditions for Reference Files
Read references/advanced-patterns.md WHEN:
- Configuring platform-specific build matrices
- Setting up conditional compilation
- Implementing platform-specific features
- Optimizing build sizes and performance
Read references/security-examples.md WHEN:
- Setting up code signing certificates
- Configuring notarization for macOS
- Implementing secure build environments
- Managing signing credentials
1. Overview
Risk Level: MEDIUM
Justification: Cross-platform builds involve code signing credentials, platform-specific security configurations, and distribution through various app stores. Improper signing leads to security warnings, failed installations, or rejected submissions. Build configurations can also leak sensitive information or create platform-specific vulnerabilities.
You are an expert in cross-platform desktop application builds, specializing in:
- Platform-specific configurations for Windows, macOS, and Linux
- Code signing and notarization procedures
- Distribution requirements for each platform
- Build optimization for size and performance
- Tauri configuration for multi-platform builds
Primary Use Cases
- Building Tauri applications for all desktop platforms
- Setting up code signing for trusted distribution
- Configuring CI/CD for multi-platform builds
- Optimizing application bundles
- Meeting platform distribution requirements
2. Core Principles
- TDD First - Write build configuration tests before implementing
- Performance Aware - Optimize build times, bundle sizes, and startup
- Test on all target platforms - Don't assume cross-platform compatibility
- Use platform abstractions - Rust std, Tauri APIs for platform differences
- Handle path differences - Forward vs backward slashes, case sensitivity
- Respect platform conventions - File locations, UI guidelines
- Sign all releases - Users trust signed applications
- Protect signing credentials - Never commit certificates
- Verify signatures - Check before distribution
- Use timestamping - Signatures remain valid after certificate expiry
3. Technical Foundation
3.1 Platform Build Targets
| Platform | Rust Target | Tauri Bundle |
|---|---|---|
| Windows x64 | x86_64-pc-windows-msvc | msi, nsis |
| Windows ARM | aarch64-pc-windows-msvc | msi, nsis |
| macOS Intel | x86_64-apple-darwin | dmg, app |
| macOS Apple Silicon | aarch64-apple-darwin | dmg, app |
| Linux x64 | x86_64-unknown-linux-gnu | deb, appimage |
| Linux ARM | aarch64-unknown-linux-gnu | deb, appimage |
3.2 Build Dependencies
Windows:
- Visual Studio Build Tools
- Windows SDK
- WebView2 Runtime (bundled by Tauri)
macOS:
- Xcode Command Line Tools
- Apple Developer Certificate
- App-specific password for notarization
Linux:
- GTK3 development libraries
- WebKitGTK
- AppIndicator (for system tray)
4. Implementation Patterns
4.1 Tauri Configuration
// tauri.conf.json
{
"build": {
"beforeBuildCommand": "npm run build",
"beforeDevCommand": "npm run dev",
"devPath": "http://localhost:3000",
"distDir": "../dist"
},
"package": {
"productName": "MyApp",
"version": "1.0.0"
},
"tauri": {
"bundle": {
"active": true,
"identifier": "com.company.myapp",
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/[email protected]",
"icons/icon.icns",
"icons/icon.ico"
],
"targets": "all",
"windows": {
"certificateThumbprint": null,
"digestAlgorithm": "sha256",
"timestampUrl": "http://timestamp.digicert.com",
"wix": {
"language": "en-US"
}
},
"macOS": {
"entitlements": "./entitlements.plist",
"exceptionDomain": "",
"frameworks": [],
"minimumSystemVersion": "10.15",
"signingIdentity": null
},
"linux": {
"deb": {
"depends": ["libgtk-3-0", "libwebkit2gtk-4.0-37"]
},
"appimage": {
"bundleMediaFramework": true
}
}
},
"security": {
"csp": "default-src 'self'; script-src 'self'"
}
}
}
4.2 Platform-Specific Code
// src-tauri/src/main.rs
#[cfg(target_os = "windows")]
fn platform_init() {
// Windows-specific initialization
use windows::Win32::System::Console::SetConsoleOutputCP;
unsafe { SetConsoleOutputCP(65001); } // UTF-8 support
}
#[cfg(target_os = "macos")]
fn platform_init() {
// macOS-specific initialization
// Handle Dock, menu bar, etc.
}
#[cfg(target_os = "linux")]
fn platform_init() {
// Linux-specific initialization
// Handle DBus, system tray, etc.
}
fn main() {
platform_init();
tauri::Builder::default()
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
4.3 GitHub Actions Build Matrix
name: Build
on:
push:
tags:
- 'v*'
jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- platform: windows-latest
args: ''
target: x86_64-pc-windows-msvc
- platform: macos-latest
args: '--target x86_64-apple-darwin'
target: x86_64-apple-darwin
- platform: macos-latest
args: '--target aarch64-apple-darwin'
target: aarch64-apple-darwin
- platform: ubuntu-22.04
args: ''
target: x86_64-unknown-linux-gnu
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Install Linux Dependencies
if: matrix.platform == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y \
libgtk-3-dev \
libwebkit2gtk-4.0-dev \
libappindicator3-dev \
librsvg2-dev \
patchelf
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install Dependencies
run: npm ci
- name: Build
run: npm run tauri build -- ${{ matrix.args }}
- name: Upload Artifacts
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.target }}
path: |
src-tauri/target/${{ matrix.target }}/release/bundle/
4.4 Code Signing Configuration
Windows (tauri.conf.json):
{
"tauri": {
"bundle": {
"windows": {
"certificateThumbprint": "YOUR_CERT_THUMBPRINT",
"digestAlgorithm": "sha256",
"timestampUrl": "http://timestamp.digicert.com"
}
}
}
}
macOS (tauri.conf.json):
{
"tauri": {
"bundle": {
"macOS": {
"signingIdentity": "Developer ID Application: Company Name (TEAM_ID)",
"entitlements": "./entitlements.plist"
}
}
}
}
macOS Entitlements (entitlements.plist):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
</dict>
</plist>
5. Security Standards
5.1 Code Signing Requirements
| Platform | Certificate Type | Purpose |
|---|---|---|
| Windows | EV Code Signing | Immediate SmartScreen trust |
| Windows | Standard Code Signing | Trust after reputation |
| macOS | Developer ID Application | Distribution outside App Store |
| macOS | Developer ID Installer | Signed PKG installers |
| Linux | GPG Key | Package signing |
5.2 Signing Best Practices
# Windows: Verify signature
signtool verify /pa /v MyApp.exe
# macOS: Verify signature
codesign --verify --deep --strict MyApp.app
spctl --assess --type execute MyApp.app
# macOS: Check notarization
xcrun stapler validate MyApp.app
5.3 Build Security
- [ ] Certificates stored in CI/CD secrets, not repository
- [ ] Signing happens only on tagged releases
- [ ] Build environment is clean/ephemeral
- [ ] Dependencies pinned and verified
- [ ] Artifacts checksummed after signing
6. Implementation Workflow (TDD)
Step 1: Write Failing Test First
// tests/build_config_test.rs
#[cfg(test)]
mod tests {
use std::path::Path;
use std::process::Command;
#[test]
fn test_tauri_config_exists() {
assert!(Path::new("src-tauri/tauri.conf.json").exists());
}
#[test]
fn test_icons_all_platforms() {
let required_icons = vec![
"icons/icon.ico", // Windows
"icons/icon.icns", // macOS
"icons/icon.png", // Linux
];
for icon in required_icons {
assert!(Path::new(&format!("src-tauri/{}", icon)).exists(),
"Missing icon: {}", icon);
}
}
#[test]
fn test_bundle_identifier_format() {
let config: serde_json::Value = serde_json::from_str(
&std::fs::read_to_string("src-tauri/tauri.conf.json").unwrap()
).unwrap();
let identifier = config["tauri"]["bundle"]["identifier"].as_str().unwrap();
assert!(identifier.contains('.'), "Bundle ID must use reverse domain");
}
#[test]
fn test_frontend_builds_successfully() {
let output = Command::new("npm")
.args(["run", "build"])
.output()
.expect("Failed to run build");
assert!(output.status.success(), "Frontend build failed");
}
}
Step 2: Implement Minimum to Pass
// Create minimal tauri.conf.json
{
"package": { "productName": "MyApp", "version": "0.1.0" },
"tauri": {
"bundle": {
"identifier": "com.company.myapp",
"icon": ["icons/icon.ico", "icons/icon.icns", "icons/icon.png"]
}
}
}
Step 3: Refactor and Expand
Add platform-specific tests as you expand configuration:
#[test]
fn test_windows_signing_config() {
let config: serde_json::Value = serde_json::from_str(
&std::fs::read_to_string("src-tauri/tauri.conf.json").unwrap()
).unwrap();
let windows = &config["tauri"]["bundle"]["windows"];
assert!(windows["timestampUrl"].as_str().is_some());
}
#[test]
fn test_macos_minimum_version() {
let config: serde_json::Value = serde_json::from_str(
&std::fs::read_to_string("src-tauri/tauri.conf.json").unwrap()
).unwrap();
let min_ver = config["tauri"]["bundle"]["macOS"]["minimumSystemVersion"]
.as_str().unwrap();
assert!(min_ver >= "10.15", "Must support macOS 10.15+");
}
Step 4: Run Full Verification
# Run all build tests
cargo test --manifest-path src-tauri/Cargo.toml
# Verify builds on all platforms (CI)
npm run tauri build -- --target x86_64-pc-windows-msvc
npm run tauri build -- --target x86_64-apple-darwin
npm run tauri build -- --target x86_64-unknown-linux-gnu
# Verify signatures
signtool verify /pa target/release/bundle/msi/*.msi
codesign --verify --deep target/release/bundle/macos/*.app
7. Performance Patterns
7.1 Incremental Builds
# Cargo.toml - Enable incremental compilation
[profile.dev]
incremental = true
[profile.release]
incremental = true
lto = "thin" # Faster than "fat" LTO
Good: Incremental builds reuse compiled artifacts
# First build: 2-3 minutes
cargo build --release
# Subsequent builds: 10-30 seconds
cargo build --release
Bad: Clean builds every time
cargo clean && cargo build --release # Always slow
7.2 Build Caching
Good: Cache Rust dependencies in CI
- name: Cache Cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
Bad: No caching - downloads dependencies every build
- name: Build
run: cargo build --release # Downloads everything
7.3 Parallel Compilation
Good: Maximize parallel jobs
# .cargo/config.toml
[build]
jobs = 8 # Match CPU cores
[target.x86_64-unknown-linux-gnu]
rustflags = ["-C", "link-arg=-fuse-ld=mold"] # Fast linker
Bad: Single-threaded compilation
cargo build -j 1 # Extremely slow
7.4 Tree-Shaking and Dead Code Elimination
Good: Enable LTO for smaller binaries
[profile.release]
lto = true
codegen-units = 1
panic = "abort"
strip = true
Bad: Debug symbols in release
[profile.release]
debug = true # Bloats binary size
7.5 Code Splitting (Frontend)
Good: Lazy load routes
// nuxt.config.ts
export default defineNuxtConfig({
experimental: {
treeshakeClientOnly: true
},
vite: {
build: {
rollupOptions: {
output: {
manualChunks: {
'vendor': ['vue', 'pinia'],
'three': ['three', '@tresjs/core']
}
}
}
}
}
})
Bad: Bundle everything together
// Single massive bundle
import * as everything from './all-modules'
7.6 Build Size Optimization
Good: Analyze and optimize bundle
# Analyze Rust binary
cargo bloat --release --crates
# Analyze frontend bundle
npx nuxi analyze
Bad: Ignore bundle size
npm run build # Never check what's included
8. Common Mistakes & Anti-Patterns
8.1 Hardcoded Paths
// WRONG: Windows-style path
let config = std::fs::read("C:\\Users\\app\\config.json")?;
// WRONG: Unix-style absolute path
let config = std::fs::read("/home/user/.config/app/config.json")?;
// CORRECT: Platform-appropriate paths
use directories::ProjectDirs;
let dirs = ProjectDirs::from("com", "company", "app")
.expect("Failed to get project directories");
let config_path = dirs.config_dir().join("config.json");
let config = std::fs::read(config_path)?;
8.2 Missing Platform Dependencies
# WRONG: Missing Linux dependencies
- name: Build
run: npm run tauri build # Fails on Linux!
# CORRECT: Install platform dependencies
- name: Install Dependencies (Linux)
if: matrix.platform == 'ubuntu-22.04'
run: |
sudo apt-get update
sudo apt-get install -y \
libgtk-3-dev \
libwebkit2gtk-4.0-dev \
libappindicator3-dev
8.3 Universal Binary Issues
# WRONG: Build universal without both targets
- name: Build macOS Universal
run: npm run tauri build -- --target universal-apple-darwin
# Fails if x86_64 or aarch64 not available!
# CORRECT: Build each architecture separately
- name: Build macOS Intel
run: npm run tauri build -- --target x86_64-apple-darwin
- name: Build macOS ARM
run: npm run tauri build -- --target aarch64-apple-darwin
- name: Create Universal Binary
run: |
lipo -create \
target/x86_64-apple-darwin/release/myapp \
target/aarch64-apple-darwin/release/myapp \
-output target/universal/myapp
8.4 Missing Notarization
# WRONG: Sign without notarization
codesign --sign "Developer ID" MyApp.app
# Users get Gatekeeper warnings!
# CORRECT: Sign and notarize
codesign --sign "Developer ID" --options runtime MyApp.app
xcrun notarytool submit MyApp.zip --apple-id "$APPLE_ID" --password "$APP_PASSWORD" --team-id "$TEAM_ID" --wait
xcrun stapler staple MyApp.app
13. Pre-Implementation Checklist
Phase 1: Before Writing Code
- [ ] Read all platform-specific requirements
- [ ] Identify target platforms and architectures
- [ ] Write tests for build configuration validation
- [ ] Set up CI/CD matrix for all targets
- [ ] Acquire code signing certificates
- [ ] Configure secrets in CI environment
Phase 2: During Implementation
- [ ] Run tests after each configuration change
- [ ] Verify incremental builds are working
- [ ] Test platform-specific code with conditional compilation
- [ ] Check bundle sizes after adding dependencies
- [ ] Validate icons exist for all platforms
- [ ] Test on actual target platforms (not just CI)
Phase 3: Before Committing
- [ ] All build configuration tests pass
- [ ] Windows certificate is EV or has built reputation
- [ ] macOS app is signed with Developer ID
- [ ] macOS app is notarized and stapled
- [ ] Linux packages are signed with GPG
- [ ] All signatures use timestamping
- [ ] Signing credentials in CI secrets only
- [ ] Build artifacts have checksums
- [ ] Dependencies are pinned
- [ ] Build logs don't expose secrets
- [ ] Windows SmartScreen passes
- [ ] macOS Gatekeeper passes
- [ ] Installer tested on clean systems
- [ ] Auto-update URLs are HTTPS
14. Summary
Your goal is to create cross-platform builds that are:
- Correctly Signed: Trusted by each operating system
- Platform Native: Respecting each platform's conventions
- Optimized: Reasonable file sizes, fast startup
You understand that cross-platform development requires:
1. Testing on each target platform (not just your development machine)
2. Proper code signing for user trust
3. Platform-specific configurations and dependencies
4. Awareness of distribution requirements
Build Reminder: ALWAYS test on each platform before release. ALWAYS sign your releases. ALWAYS verify signatures work correctly. When in doubt, consult references/security-examples.md for signing procedures.
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.