Complete guide for building Paddle Decoder on macOS.
Required for compiling:
xcode-select --installClick "Install" in the dialog that appears.
Verify installation:
xcode-select -p
# Should output: /Library/Developer/CommandLineToolscurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/envVerify installation:
rustc --version
cargo --version/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"macOS includes Core Audio, but for better compatibility:
brew install portaudiocd /path/to/paddle_decoder_cross_platformcargo build --releaseFirst build takes 3-5 minutes. Subsequent builds are faster.
target/release/paddle_decodercargo run --release./target/release/paddle_decoderSee "Creating .app Bundle" section below.
Cause: macOS Gatekeeper blocking unsigned application
Solution:
- Right-click (or Control-click) the app
- Select "Open"
- Click "Open" in the dialog
- App will be added to exceptions
Or via Terminal:
xattr -cr target/release/paddle_decoder
./target/release/paddle_decoderCheck USB device:
system_profiler SPUSBDataType | grep -A 10 "16c0"Check MIDI devices:
# Install coreutils if needed:
brew install coreutils
# No built-in MIDI list command on macOS
# Use the app to check - it will list available MIDI portsCheck Audio MIDI Setup:
- Open "Audio MIDI Setup" (in Applications/Utilities)
- Window β Show MIDI Studio
- Should see Digispark device
Permissions: macOS may ask for MIDI access permission:
- Click "OK" when prompted
- Or: System Preferences β Security & Privacy β Privacy β Automation
Check System Sound Settings:
- System Preferences β Sound
- Output tab
- Select correct output device
- Adjust volume
Check app isn't muted:
# Open Sound settings and check per-app volumeBuild native ARM64 version:
Check your Mac's architecture:
uname -m
# arm64 = Apple Silicon
# x86_64 = IntelFor Apple Silicon, build with:
# Already builds native ARM64 by default on M1/M2/M3
cargo build --release
# To explicitly target ARM64:
rustup target add aarch64-apple-darwin
cargo build --release --target aarch64-apple-darwinBinary will be at:
target/aarch64-apple-darwin/release/paddle_decoderApplication automatically supports high-DPI Retina displays.
Follows macOS system appearance (dark/light mode).
Standard macOS shortcuts work:
- Cmd+Q: Quit
- Cmd+W: Close window
- Cmd+M: Minimize
Create a proper macOS application:
mkdir -p PaddleDecoder.app/Contents/MacOS
mkdir -p PaddleDecoder.app/Contents/Resourcescp target/release/paddle_decoder PaddleDecoder.app/Contents/MacOS/Create PaddleDecoder.app/Contents/Info.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>CFBundleName</key>
<string>Paddle Decoder</string>
<key>CFBundleDisplayName</key>
<string>Paddle Decoder</string>
<key>CFBundleIdentifier</key>
<string>com.amateurradio.paddledecoder</string>
<key>CFBundleVersion</key>
<string>1.0.0</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleExecutable</key>
<string>paddle_decoder</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>LSMinimumSystemVersion</key>
<string>10.13</string>
</dict>
</plist>chmod +x PaddleDecoder.app/Contents/MacOS/paddle_decoderopen PaddleDecoder.appOr drag to Applications folder!
Create test_macos.sh:
#!/bin/bash
echo "=== macOS System Test ==="
echo ""
# 1. Check Rust
echo "1. Checking Rust..."
if command -v rustc >/dev/null 2>&1; then
echo " β Rust installed: $(rustc --version)"
else
echo " β Rust not found"
echo " Install from: https://rustup.rs"
exit 1
fi
# 2. Check Xcode tools
echo "2. Checking Xcode Command Line Tools..."
if xcode-select -p >/dev/null 2>&1; then
echo " β Xcode tools installed"
else
echo " β Xcode tools not found"
echo " Run: xcode-select --install"
exit 1
fi
# 3. Check Digispark
echo "3. Checking Digispark..."
if system_profiler SPUSBDataType 2>/dev/null | grep -q "16c0"; then
echo " β Digispark connected"
else
echo " β Digispark not found - plug it in"
fi
# 4. Check audio
echo "4. Checking audio..."
if system_profiler SPAudioDataType >/dev/null 2>&1; then
echo " β Audio devices available"
else
echo " β No audio devices"
fi
# 5. Check architecture
echo "5. System architecture: $(uname -m)"
if [ "$(uname -m)" = "arm64" ]; then
echo " β Apple Silicon detected - will build native ARM64"
elif [ "$(uname -m)" = "x86_64" ]; then
echo " β Intel Mac detected"
fi
echo ""
echo "=== Test complete ==="Make executable and run:
chmod +x test_macos.sh
./test_macos.sh# Add targets
rustup target add x86_64-apple-darwin
rustup target add aarch64-apple-darwin
# Build both
cargo build --release --target x86_64-apple-darwin
cargo build --release --target aarch64-apple-darwin
# Create universal binary
lipo -create \
target/x86_64-apple-darwin/release/paddle_decoder \
target/aarch64-apple-darwin/release/paddle_decoder \
-output paddle_decoder_universal
# Verify
lipo -info paddle_decoder_universal
# Should show: x86_64 arm64For distribution outside App Store:
# Check if you have a Developer ID
security find-identity -v -p codesigning
# Sign the app
codesign --force --deep --sign "Developer ID Application: Your Name" \
PaddleDecoder.app
# Verify
codesign -v PaddleDecoder.app
spctl -a -v PaddleDecoder.appCreate a distributable DMG:
# Install create-dmg
brew install create-dmg
# Create DMG
create-dmg \
--volname "Paddle Decoder" \
--window-pos 200 120 \
--window-size 600 400 \
--icon-size 100 \
--app-drop-link 450 185 \
PaddleDecoder.dmg \
PaddleDecoder.appcd /path/to/paddle_decoder_cross_platform
cargo run --releaseOr open the .app bundle you created!
73! π»