Initial commit
This commit is contained in:
924
skills/cross-platform-builds/SKILL.md
Normal file
924
skills/cross-platform-builds/SKILL.md
Normal file
@@ -0,0 +1,924 @@
|
||||
---
|
||||
name: cross-platform-builds
|
||||
description: Comprehensive guide to building JUCE plugins for macOS, Windows, and Linux with CMake, code signing, notarization, and CI/CD. Use when configuring builds, setting up CI/CD pipelines, troubleshooting cross-platform compilation, implementing code signing, or creating installers for multiple platforms.
|
||||
allowed-tools: Read, Grep, Glob
|
||||
---
|
||||
|
||||
# Cross-Platform Builds for JUCE Plugins
|
||||
|
||||
Comprehensive guide to building JUCE audio plugins across macOS, Windows, and Linux with proper configuration, code signing, and continuous integration.
|
||||
|
||||
## Overview
|
||||
|
||||
JUCE audio plugins must be built for multiple platforms and plugin formats:
|
||||
- **macOS**: VST3, AU (Audio Unit), AAX
|
||||
- **Windows**: VST3, AAX
|
||||
- **Linux**: VST3
|
||||
|
||||
Each platform has specific requirements for build tools, code signing, and packaging. This skill covers:
|
||||
1. CMake configuration for all platforms and formats
|
||||
2. Platform-specific build instructions
|
||||
3. Code signing and notarization
|
||||
4. Continuous integration setup
|
||||
5. Reproducible builds
|
||||
|
||||
---
|
||||
|
||||
## 1. CMake Configuration
|
||||
|
||||
### Root CMakeLists.txt Structure
|
||||
|
||||
```cmake
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
project(MyPlugin VERSION 1.0.0)
|
||||
|
||||
# C++17 minimum for JUCE 7+
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# Export compile_commands.json for IDEs
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
# Add JUCE
|
||||
add_subdirectory(JUCE)
|
||||
|
||||
# Plugin formats to build
|
||||
set(PLUGIN_FORMATS VST3 AU Standalone)
|
||||
|
||||
# Add AAX if PACE SDK is available
|
||||
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/SDKs/AAX")
|
||||
list(APPEND PLUGIN_FORMATS AAX)
|
||||
juce_set_aax_sdk_path("${CMAKE_CURRENT_SOURCE_DIR}/SDKs/AAX")
|
||||
endif()
|
||||
|
||||
# Define the plugin
|
||||
juce_add_plugin(MyPlugin
|
||||
COMPANY_NAME "YourCompany"
|
||||
PLUGIN_MANUFACTURER_CODE Manu # 4-character code
|
||||
PLUGIN_CODE Plug # 4-character code (unique!)
|
||||
FORMATS ${PLUGIN_FORMATS}
|
||||
PRODUCT_NAME "MyPlugin"
|
||||
|
||||
# Bundle IDs
|
||||
BUNDLE_ID com.yourcompany.myplugin
|
||||
|
||||
# Plugin characteristics
|
||||
IS_SYNTH FALSE
|
||||
NEEDS_MIDI_INPUT FALSE
|
||||
NEEDS_MIDI_OUTPUT FALSE
|
||||
IS_MIDI_EFFECT FALSE
|
||||
EDITOR_WANTS_KEYBOARD_FOCUS FALSE
|
||||
|
||||
# Copy plugin to system folder after build
|
||||
COPY_PLUGIN_AFTER_BUILD TRUE
|
||||
|
||||
# VST3 category
|
||||
VST3_CATEGORIES Fx
|
||||
|
||||
# AU type (aufx = effect, aumu = instrument)
|
||||
AU_MAIN_TYPE kAudioUnitType_Effect
|
||||
)
|
||||
|
||||
# Source files
|
||||
target_sources(MyPlugin PRIVATE
|
||||
Source/PluginProcessor.cpp
|
||||
Source/PluginEditor.cpp
|
||||
Source/DSP/Filter.cpp
|
||||
Source/DSP/Modulation.cpp
|
||||
)
|
||||
|
||||
# Public compile definitions
|
||||
target_compile_definitions(MyPlugin PUBLIC
|
||||
JUCE_WEB_BROWSER=0
|
||||
JUCE_USE_CURL=0
|
||||
JUCE_VST3_CAN_REPLACE_VST2=0
|
||||
JUCE_DISPLAY_SPLASH_SCREEN=0 # Commercial license only!
|
||||
)
|
||||
|
||||
# Link JUCE modules
|
||||
target_link_libraries(MyPlugin PRIVATE
|
||||
juce::juce_audio_utils
|
||||
juce::juce_dsp
|
||||
juce::juce_recommended_config_flags
|
||||
juce::juce_recommended_lto_flags
|
||||
juce::juce_recommended_warning_flags
|
||||
)
|
||||
|
||||
# Platform-specific settings
|
||||
if(APPLE)
|
||||
# macOS deployment target
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13" CACHE STRING "Minimum macOS version")
|
||||
|
||||
# Universal binary (Apple Silicon + Intel)
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "macOS architectures")
|
||||
|
||||
# Hardened runtime for notarization
|
||||
target_compile_options(MyPlugin PUBLIC
|
||||
-Wall -Wextra -Wpedantic
|
||||
)
|
||||
elseif(WIN32)
|
||||
# Static runtime for standalone distribution
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
|
||||
# Windows-specific definitions
|
||||
target_compile_definitions(MyPlugin PRIVATE
|
||||
_CRT_SECURE_NO_WARNINGS
|
||||
)
|
||||
elseif(UNIX)
|
||||
# Linux-specific flags
|
||||
target_compile_options(MyPlugin PRIVATE
|
||||
-Wall -Wextra
|
||||
)
|
||||
|
||||
# Link against ALSA, JACK, etc.
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(ALSA REQUIRED alsa)
|
||||
target_link_libraries(MyPlugin PRIVATE ${ALSA_LIBRARIES})
|
||||
endif()
|
||||
|
||||
# Tests (optional)
|
||||
option(BUILD_TESTS "Build unit tests" ON)
|
||||
if(BUILD_TESTS)
|
||||
enable_testing()
|
||||
add_subdirectory(Tests)
|
||||
endif()
|
||||
```
|
||||
|
||||
### Key Configuration Options
|
||||
|
||||
#### Plugin Codes
|
||||
```cmake
|
||||
PLUGIN_MANUFACTURER_CODE Manu # Your unique 4-character manufacturer ID
|
||||
PLUGIN_CODE Plug # Unique 4-character plugin ID
|
||||
```
|
||||
|
||||
**Important**: Register manufacturer code at [Steinberg](https://www.steinberg.net/en/company/developers.html) to avoid conflicts.
|
||||
|
||||
#### Bundle Identifiers
|
||||
```cmake
|
||||
BUNDLE_ID com.yourcompany.myplugin # Reverse domain notation
|
||||
```
|
||||
|
||||
Must be unique and consistent across versions for AU validation.
|
||||
|
||||
#### Plugin Characteristics
|
||||
```cmake
|
||||
IS_SYNTH TRUE # Instrument vs effect
|
||||
NEEDS_MIDI_INPUT TRUE # Accept MIDI input
|
||||
NEEDS_MIDI_OUTPUT FALSE # Send MIDI output
|
||||
IS_MIDI_EFFECT FALSE # MIDI-only processing (no audio)
|
||||
```
|
||||
|
||||
#### VST3 Categories
|
||||
```cmake
|
||||
VST3_CATEGORIES Fx # Effect
|
||||
VST3_CATEGORIES Instrument # Instrument
|
||||
VST3_CATEGORIES Fx Dynamics # Multiple categories
|
||||
```
|
||||
|
||||
Available categories: `Fx`, `Instrument`, `Analyzer`, `Delay`, `Distortion`, `Dynamics`, `EQ`, `Filter`, `Mastering`, `Modulation`, `Restoration`, `Reverb`, `Spatial`, `Synth`, `Tools`
|
||||
|
||||
#### AU Types
|
||||
```cmake
|
||||
AU_MAIN_TYPE kAudioUnitType_Effect # Effect
|
||||
AU_MAIN_TYPE kAudioUnitType_MusicDevice # Instrument
|
||||
AU_MAIN_TYPE kAudioUnitType_MIDIProcessor # MIDI effect
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. macOS Builds
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. **Xcode** (latest version recommended)
|
||||
```bash
|
||||
xcode-select --install
|
||||
```
|
||||
|
||||
2. **CMake** (3.22+)
|
||||
```bash
|
||||
brew install cmake
|
||||
```
|
||||
|
||||
3. **Developer ID Certificate** (for distribution)
|
||||
- Enroll in Apple Developer Program ($99/year)
|
||||
- Create "Developer ID Application" certificate in Xcode
|
||||
|
||||
### Building
|
||||
|
||||
```bash
|
||||
# Configure
|
||||
cmake -B build-mac -G Xcode \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.13 \
|
||||
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64"
|
||||
|
||||
# Build all formats
|
||||
cmake --build build-mac --config Release --parallel
|
||||
|
||||
# Or build with Xcode
|
||||
open build-mac/MyPlugin.xcodeproj
|
||||
```
|
||||
|
||||
### Universal Binaries (Apple Silicon + Intel)
|
||||
|
||||
```cmake
|
||||
# In CMakeLists.txt
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64")
|
||||
```
|
||||
|
||||
Or at build time:
|
||||
```bash
|
||||
cmake -B build-mac -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64"
|
||||
```
|
||||
|
||||
Verify architectures:
|
||||
```bash
|
||||
lipo -info build-mac/MyPlugin_artefacts/Release/VST3/MyPlugin.vst3/Contents/MacOS/MyPlugin
|
||||
|
||||
# Output: Architectures in the fat file: MyPlugin are: x86_64 arm64
|
||||
```
|
||||
|
||||
### Code Signing
|
||||
|
||||
#### Manual Signing
|
||||
```bash
|
||||
# Sign VST3
|
||||
codesign --force \
|
||||
--sign "Developer ID Application: Your Name (TEAM_ID)" \
|
||||
--options runtime \
|
||||
--entitlements Resources/Entitlements.plist \
|
||||
--timestamp \
|
||||
--deep \
|
||||
MyPlugin.vst3
|
||||
|
||||
# Sign AU
|
||||
codesign --force \
|
||||
--sign "Developer ID Application: Your Name (TEAM_ID)" \
|
||||
--options runtime \
|
||||
--timestamp \
|
||||
--deep \
|
||||
MyPlugin.component
|
||||
|
||||
# Verify signature
|
||||
codesign --verify --deep --strict --verbose=2 MyPlugin.vst3
|
||||
```
|
||||
|
||||
#### Entitlements File (Resources/Entitlements.plist)
|
||||
```xml
|
||||
<?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>
|
||||
<!-- Allow JIT for DSP optimization -->
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
|
||||
<!-- Allow loading unsigned plugins (for VST3 presets, etc.) -->
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
|
||||
<!-- For networked plugins (optional) -->
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
#### Automated Signing in CMake
|
||||
```cmake
|
||||
# Add to CMakeLists.txt
|
||||
if(APPLE AND CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
set(CODESIGN_IDENTITY "Developer ID Application: Your Name")
|
||||
|
||||
add_custom_command(TARGET MyPlugin POST_BUILD
|
||||
COMMAND codesign --force
|
||||
--sign "${CODESIGN_IDENTITY}"
|
||||
--options runtime
|
||||
--entitlements "${CMAKE_SOURCE_DIR}/Resources/Entitlements.plist"
|
||||
--timestamp
|
||||
$<TARGET_BUNDLE_DIR:MyPlugin>
|
||||
COMMENT "Code signing ${TARGET}"
|
||||
)
|
||||
endif()
|
||||
```
|
||||
|
||||
### Notarization
|
||||
|
||||
Required for macOS 10.15+ (Catalina and later).
|
||||
|
||||
#### Setup
|
||||
1. Create app-specific password at [appleid.apple.com](https://appleid.apple.com)
|
||||
2. Store credentials in keychain:
|
||||
```bash
|
||||
xcrun notarytool store-credentials "notary-profile" \
|
||||
--apple-id "developer@example.com" \
|
||||
--team-id "TEAM_ID" \
|
||||
--password "xxxx-xxxx-xxxx-xxxx"
|
||||
```
|
||||
|
||||
#### Notarize Plugin
|
||||
```bash
|
||||
# 1. Create ZIP for notarization
|
||||
ditto -c -k --keepParent MyPlugin.vst3 MyPlugin-vst3.zip
|
||||
|
||||
# 2. Submit to notary service
|
||||
xcrun notarytool submit MyPlugin-vst3.zip \
|
||||
--keychain-profile "notary-profile" \
|
||||
--wait
|
||||
|
||||
# 3. If successful, staple the ticket
|
||||
xcrun stapler staple MyPlugin.vst3
|
||||
|
||||
# 4. Verify
|
||||
spctl -a -vvv -t install MyPlugin.vst3
|
||||
xcrun stapler validate MyPlugin.vst3
|
||||
```
|
||||
|
||||
#### Troubleshooting Notarization
|
||||
|
||||
Check submission status:
|
||||
```bash
|
||||
xcrun notarytool info <submission-id> --keychain-profile "notary-profile"
|
||||
```
|
||||
|
||||
View detailed log:
|
||||
```bash
|
||||
xcrun notarytool log <submission-id> --keychain-profile "notary-profile"
|
||||
```
|
||||
|
||||
Common issues:
|
||||
- **Missing entitlements**: Add to Entitlements.plist
|
||||
- **Unsigned nested binaries**: Sign all frameworks before parent bundle
|
||||
- **Invalid bundle structure**: Verify with `pkgutil --check-signature`
|
||||
|
||||
### AU Validation
|
||||
|
||||
```bash
|
||||
# Validate AU (required for App Store distribution)
|
||||
auval -v aufx Plug Manu
|
||||
|
||||
# Output should end with "PASSED"
|
||||
```
|
||||
|
||||
Fix common AU validation errors:
|
||||
- **"Could not open component"**: Check bundle ID and AU type
|
||||
- **"Plugin crash"**: Debug in Xcode, check for exceptions in initialization
|
||||
- **"Latency reporting"**: Implement `getTailLengthSeconds()` correctly
|
||||
|
||||
---
|
||||
|
||||
## 3. Windows Builds
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. **Visual Studio 2022** (Community, Professional, or Enterprise)
|
||||
- Install "Desktop development with C++" workload
|
||||
- Includes Windows 10 SDK
|
||||
|
||||
2. **CMake** (3.22+)
|
||||
```powershell
|
||||
# Via Chocolatey
|
||||
choco install cmake
|
||||
|
||||
# Or download from cmake.org
|
||||
```
|
||||
|
||||
3. **Code Signing Certificate** (optional, for distribution)
|
||||
- EV or standard code signing certificate
|
||||
- From vendors: DigiCert, Sectigo, GlobalSign
|
||||
|
||||
### Building
|
||||
|
||||
```powershell
|
||||
# Configure for Visual Studio 2022
|
||||
cmake -B build-win -G "Visual Studio 17 2022" -A x64
|
||||
|
||||
# Build Release
|
||||
cmake --build build-win --config Release --parallel
|
||||
|
||||
# Or open in Visual Studio
|
||||
start build-win/MyPlugin.sln
|
||||
```
|
||||
|
||||
### MSVC Runtime Linking
|
||||
|
||||
**Static Runtime** (recommended for plugins):
|
||||
```cmake
|
||||
# Statically link MSVC runtime (no DLL dependencies)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
```
|
||||
|
||||
**Dynamic Runtime** (smaller binary, requires MSVC redistributable):
|
||||
```cmake
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
||||
```
|
||||
|
||||
### Code Signing
|
||||
|
||||
#### Manual Signing with signtool
|
||||
```powershell
|
||||
# Sign with PFX file
|
||||
signtool sign /f certificate.pfx /p <password> `
|
||||
/tr http://timestamp.digicert.com `
|
||||
/td sha256 /fd sha256 `
|
||||
MyPlugin.vst3
|
||||
|
||||
# Sign with certificate store
|
||||
signtool sign /n "Your Company Name" `
|
||||
/tr http://timestamp.digicert.com `
|
||||
/td sha256 /fd sha256 `
|
||||
MyPlugin.vst3
|
||||
|
||||
# Verify signature
|
||||
signtool verify /pa /v MyPlugin.vst3
|
||||
```
|
||||
|
||||
#### Automated Signing in CMake
|
||||
```cmake
|
||||
if(WIN32 AND CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
find_program(SIGNTOOL_EXECUTABLE signtool
|
||||
PATHS "C:/Program Files (x86)/Windows Kits/10/bin/*/x64"
|
||||
)
|
||||
|
||||
if(SIGNTOOL_EXECUTABLE)
|
||||
add_custom_command(TARGET MyPlugin POST_BUILD
|
||||
COMMAND ${SIGNTOOL_EXECUTABLE} sign
|
||||
/f "${CMAKE_SOURCE_DIR}/certificate.pfx"
|
||||
/p "$ENV{CERT_PASSWORD}"
|
||||
/tr http://timestamp.digicert.com
|
||||
/td sha256 /fd sha256
|
||||
$<TARGET_FILE:MyPlugin>
|
||||
COMMENT "Code signing ${TARGET}"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
```
|
||||
|
||||
### Visual Studio Configuration
|
||||
|
||||
#### Optimization Settings
|
||||
```cmake
|
||||
if(MSVC)
|
||||
# Enable whole program optimization (Release)
|
||||
target_compile_options(MyPlugin PRIVATE
|
||||
$<$<CONFIG:Release>:/GL> # Whole program optimization
|
||||
/MP # Multi-processor compilation
|
||||
)
|
||||
|
||||
target_link_options(MyPlugin PRIVATE
|
||||
$<$<CONFIG:Release>:/LTCG> # Link-time code generation
|
||||
)
|
||||
endif()
|
||||
```
|
||||
|
||||
#### Suppress Warnings
|
||||
```cmake
|
||||
target_compile_definitions(MyPlugin PRIVATE
|
||||
_CRT_SECURE_NO_WARNINGS # Disable CRT security warnings
|
||||
NOMINMAX # Prevent min/max macros
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Linux Builds
|
||||
|
||||
### Prerequisites
|
||||
|
||||
**Ubuntu/Debian:**
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
build-essential \
|
||||
cmake \
|
||||
libasound2-dev \
|
||||
libjack-jackd2-dev \
|
||||
libfreetype6-dev \
|
||||
libx11-dev \
|
||||
libxrandr-dev \
|
||||
libxinerama-dev \
|
||||
libxcursor-dev \
|
||||
libgl1-mesa-dev \
|
||||
libcurl4-openssl-dev
|
||||
```
|
||||
|
||||
**Fedora/RHEL:**
|
||||
```bash
|
||||
sudo dnf install -y \
|
||||
gcc-c++ \
|
||||
cmake \
|
||||
alsa-lib-devel \
|
||||
jack-audio-connection-kit-devel \
|
||||
freetype-devel \
|
||||
libX11-devel \
|
||||
libXrandr-devel \
|
||||
libXinerama-devel \
|
||||
libXcursor-devel \
|
||||
mesa-libGL-devel \
|
||||
libcurl-devel
|
||||
```
|
||||
|
||||
### Building
|
||||
|
||||
```bash
|
||||
# Configure
|
||||
cmake -B build-linux -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
# Build
|
||||
cmake --build build-linux --config Release --parallel
|
||||
|
||||
# Install to system (optional)
|
||||
sudo cmake --install build-linux
|
||||
```
|
||||
|
||||
### Packaging
|
||||
|
||||
#### Create .tar.gz
|
||||
```bash
|
||||
tar -czf MyPlugin-1.0.0-Linux-x86_64.tar.gz \
|
||||
-C build-linux/MyPlugin_artefacts/Release/VST3 \
|
||||
MyPlugin.vst3
|
||||
```
|
||||
|
||||
#### Create .deb Package
|
||||
```bash
|
||||
# Install packaging tools
|
||||
sudo apt-get install checkinstall
|
||||
|
||||
# Create .deb
|
||||
sudo checkinstall \
|
||||
--pkgname=myplugin \
|
||||
--pkgversion=1.0.0 \
|
||||
--pkgrelease=1 \
|
||||
--pkggroup=sound \
|
||||
--maintainer="you@example.com" \
|
||||
cmake --install build-linux
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. AAX Format (Pro Tools)
|
||||
|
||||
### Prerequisites
|
||||
|
||||
1. **AAX SDK** (requires iLok account)
|
||||
- Sign up at [developer.avid.com](https://developer.avid.com)
|
||||
- Download AAX SDK
|
||||
- Extract to `SDKs/AAX/`
|
||||
|
||||
2. **PACE Licensing** (for distribution)
|
||||
- Create account at [paceap.com](https://www.paceap.com)
|
||||
- Use PACE Eden for signing (replaces codesign for AAX)
|
||||
|
||||
### CMake Configuration
|
||||
|
||||
```cmake
|
||||
# Set AAX SDK path
|
||||
juce_set_aax_sdk_path("${CMAKE_CURRENT_SOURCE_DIR}/SDKs/AAX")
|
||||
|
||||
# Add AAX to plugin formats
|
||||
set(PLUGIN_FORMATS VST3 AU AAX Standalone)
|
||||
```
|
||||
|
||||
### Building AAX
|
||||
|
||||
```bash
|
||||
# macOS
|
||||
cmake -B build-mac -DAAX_SDK_PATH=SDKs/AAX
|
||||
cmake --build build-mac --config Release
|
||||
|
||||
# Windows
|
||||
cmake -B build-win -DAAX_SDK_PATH=SDKs/AAX
|
||||
cmake --build build-win --config Release
|
||||
```
|
||||
|
||||
### AAX Signing with PACE Eden
|
||||
|
||||
AAX plugins **must** be signed with PACE Eden (not regular codesign).
|
||||
|
||||
```bash
|
||||
# Sign AAX (macOS/Windows)
|
||||
wraptool sign \
|
||||
--account <your-pace-account> \
|
||||
--password <password> \
|
||||
--signid <signid> \
|
||||
--in MyPlugin.aaxplugin \
|
||||
--out MyPlugin-signed.aaxplugin
|
||||
|
||||
# Verify
|
||||
wraptool verify --verbose MyPlugin-signed.aaxplugin
|
||||
```
|
||||
|
||||
**Note**: Keep AAX signing credentials secure. Never commit to version control.
|
||||
|
||||
---
|
||||
|
||||
## 6. Continuous Integration
|
||||
|
||||
### GitHub Actions Workflow
|
||||
|
||||
**.github/workflows/build.yml:**
|
||||
```yaml
|
||||
name: Build Plugin
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: macOS
|
||||
os: macos-latest
|
||||
cmake_args: -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64"
|
||||
|
||||
- name: Windows
|
||||
os: windows-latest
|
||||
cmake_args: -G "Visual Studio 17 2022" -A x64
|
||||
|
||||
- name: Linux
|
||||
os: ubuntu-latest
|
||||
cmake_args: ""
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install Linux dependencies
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libasound2-dev libjack-jackd2-dev \
|
||||
libfreetype6-dev libx11-dev libxrandr-dev libxinerama-dev \
|
||||
libxcursor-dev libgl1-mesa-dev
|
||||
|
||||
- name: Configure
|
||||
run: cmake -B build ${{ matrix.cmake_args }} -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build --config Release --parallel
|
||||
|
||||
- name: Test
|
||||
run: ctest --test-dir build -C Release --output-on-failure
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ matrix.name }}
|
||||
path: |
|
||||
build/*_artefacts/Release/VST3/*.vst3
|
||||
build/*_artefacts/Release/AU/*.component
|
||||
```
|
||||
|
||||
### Secrets for Code Signing
|
||||
|
||||
Store signing credentials in GitHub Secrets:
|
||||
|
||||
1. Go to repository **Settings → Secrets → Actions**
|
||||
2. Add secrets:
|
||||
- `MACOS_CERTIFICATE_BASE64`: Base64-encoded .p12 file
|
||||
- `MACOS_CERTIFICATE_PASSWORD`: Certificate password
|
||||
- `APPLE_ID`: Apple ID for notarization
|
||||
- `APPLE_TEAM_ID`: Developer team ID
|
||||
- `APPLE_APP_PASSWORD`: App-specific password
|
||||
- `WINDOWS_CERTIFICATE_BASE64`: Base64-encoded .pfx file
|
||||
- `WINDOWS_CERTIFICATE_PASSWORD`: Certificate password
|
||||
|
||||
### Automated Code Signing in CI
|
||||
|
||||
**macOS:**
|
||||
```yaml
|
||||
- name: Import Certificate
|
||||
env:
|
||||
CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE_BASE64 }}
|
||||
CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }}
|
||||
run: |
|
||||
echo $CERTIFICATE_BASE64 | base64 --decode > certificate.p12
|
||||
security create-keychain -p temp build.keychain
|
||||
security import certificate.p12 -k build.keychain -P $CERTIFICATE_PASSWORD -T /usr/bin/codesign
|
||||
security set-keychain-settings -lut 21600 build.keychain
|
||||
security unlock-keychain -p temp build.keychain
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k temp build.keychain
|
||||
|
||||
- name: Sign and Notarize
|
||||
env:
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
APPLE_APP_PASSWORD: ${{ secrets.APPLE_APP_PASSWORD }}
|
||||
run: |
|
||||
codesign --force --sign "Developer ID Application" --options runtime MyPlugin.vst3
|
||||
xcrun notarytool submit MyPlugin.vst3.zip --apple-id $APPLE_ID --team-id $APPLE_TEAM_ID --password $APPLE_APP_PASSWORD --wait
|
||||
xcrun stapler staple MyPlugin.vst3
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```yaml
|
||||
- name: Import Certificate
|
||||
env:
|
||||
CERTIFICATE_BASE64: ${{ secrets.WINDOWS_CERTIFICATE_BASE64 }}
|
||||
CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
|
||||
run: |
|
||||
[System.Convert]::FromBase64String($env:CERTIFICATE_BASE64) | Set-Content -Path certificate.pfx -Encoding Byte
|
||||
certutil -importpfx -p $env:CERTIFICATE_PASSWORD certificate.pfx
|
||||
|
||||
- name: Sign Binary
|
||||
run: |
|
||||
signtool sign /f certificate.pfx /p $env:CERTIFICATE_PASSWORD /tr http://timestamp.digicert.com /td sha256 /fd sha256 MyPlugin.vst3
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Reproducible Builds
|
||||
|
||||
### Deterministic Builds
|
||||
|
||||
Ensure builds are reproducible across machines:
|
||||
|
||||
1. **Pin JUCE version** (use git submodule or specific release)
|
||||
```bash
|
||||
git submodule add https://github.com/juce-framework/JUCE.git
|
||||
cd JUCE && git checkout 7.0.9
|
||||
```
|
||||
|
||||
2. **Lock dependency versions** (CMake FetchContent)
|
||||
```cmake
|
||||
FetchContent_Declare(
|
||||
googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG v1.14.0 # Specific version
|
||||
)
|
||||
```
|
||||
|
||||
3. **Document toolchain versions** (README.md)
|
||||
```markdown
|
||||
Build Requirements:
|
||||
- CMake 3.22+
|
||||
- JUCE 7.0.9
|
||||
- macOS: Xcode 14.3+
|
||||
- Windows: Visual Studio 2022
|
||||
- Linux: GCC 11+ or Clang 14+
|
||||
```
|
||||
|
||||
4. **Disable timestamp embedding**
|
||||
```cmake
|
||||
# Remove __DATE__ and __TIME__ macros
|
||||
target_compile_definitions(MyPlugin PRIVATE
|
||||
NO_BUILD_TIMESTAMP=1
|
||||
)
|
||||
```
|
||||
|
||||
### Build Verification
|
||||
|
||||
Generate checksums for reproducibility:
|
||||
```bash
|
||||
# macOS/Linux
|
||||
shasum -a 256 MyPlugin.vst3 > checksums.txt
|
||||
|
||||
# Windows
|
||||
certutil -hashfile MyPlugin.vst3 SHA256 >> checksums.txt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Troubleshooting
|
||||
|
||||
### Common Build Errors
|
||||
|
||||
#### "JUCE modules not found"
|
||||
```
|
||||
Solution:
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
#### "Symbol not found" (macOS)
|
||||
```
|
||||
Solution:
|
||||
- Check deployment target matches minimum system requirement
|
||||
- Verify all symbols are available in target SDK
|
||||
- Use `nm` to inspect missing symbols:
|
||||
nm -gU MyPlugin.vst3/Contents/MacOS/MyPlugin | grep <symbol>
|
||||
```
|
||||
|
||||
#### "Unresolved external symbol" (Windows)
|
||||
```
|
||||
Solution:
|
||||
- Ensure all .cpp files are in CMakeLists.txt
|
||||
- Check library linking order
|
||||
- Verify static/dynamic runtime consistency (/MT vs /MD)
|
||||
```
|
||||
|
||||
#### "Undefined reference" (Linux)
|
||||
```
|
||||
Solution:
|
||||
- Install missing libraries (libasound2-dev, etc.)
|
||||
- Add libraries to target_link_libraries()
|
||||
- Check pkg-config: pkg-config --libs alsa
|
||||
```
|
||||
|
||||
### Plugin Doesn't Load in DAW
|
||||
|
||||
**macOS:**
|
||||
1. Check signing: `codesign --verify --deep --strict MyPlugin.vst3`
|
||||
2. Verify notarization: `spctl -a -vvv -t install MyPlugin.vst3`
|
||||
3. Check Gatekeeper: `xattr -l MyPlugin.vst3` (remove quarantine if needed)
|
||||
4. AU validation: `auval -v aufx Plug Manu`
|
||||
|
||||
**Windows:**
|
||||
1. Check dependencies: Use [Dependency Walker](http://www.dependencywalker.com/)
|
||||
2. Verify signature: `signtool verify /pa MyPlugin.vst3`
|
||||
3. Check registry (for VST3): `Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\VST3`
|
||||
|
||||
**Linux:**
|
||||
1. Check shared library dependencies: `ldd MyPlugin.vst3`
|
||||
2. Verify VST3 path: `~/.vst3/` or `/usr/lib/vst3/`
|
||||
3. Check permissions: `chmod 755 MyPlugin.vst3`
|
||||
|
||||
---
|
||||
|
||||
## 9. Best Practices
|
||||
|
||||
### Version Management
|
||||
|
||||
```cmake
|
||||
project(MyPlugin VERSION 1.2.3)
|
||||
|
||||
# Access in code
|
||||
target_compile_definitions(MyPlugin PRIVATE
|
||||
PLUGIN_VERSION="${CMAKE_PROJECT_VERSION}"
|
||||
)
|
||||
```
|
||||
|
||||
### Conditional Compilation
|
||||
|
||||
```cpp
|
||||
#if JUCE_MAC
|
||||
// macOS-specific code
|
||||
#elif JUCE_WINDOWS
|
||||
// Windows-specific code
|
||||
#elif JUCE_LINUX
|
||||
// Linux-specific code
|
||||
#endif
|
||||
|
||||
#if JUCE_DEBUG
|
||||
// Debug-only code
|
||||
#endif
|
||||
```
|
||||
|
||||
### Minimize Plugin Size
|
||||
|
||||
- **Strip symbols** in Release builds
|
||||
- **Enable LTO** (link-time optimization)
|
||||
- **Remove unused JUCE modules**
|
||||
- **Compress resources** (images, fonts)
|
||||
|
||||
### Cross-Platform File Paths
|
||||
|
||||
```cpp
|
||||
// Use JUCE File class for portability
|
||||
juce::File presetFolder = juce::File::getSpecialLocation(
|
||||
juce::File::userApplicationDataDirectory
|
||||
).getChildFile("MyPlugin").getChildFile("Presets");
|
||||
|
||||
// Not hardcoded paths like:
|
||||
// "C:\\Users\\...\\Presets" ❌
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
**Key Takeaways:**
|
||||
|
||||
1. **Use CMake** for cross-platform builds - single configuration for all platforms
|
||||
2. **Code signing is essential** for distribution (macOS requires notarization)
|
||||
3. **Test on all platforms** - behavior can differ (especially AU vs VST3)
|
||||
4. **Automate in CI/CD** - GitHub Actions, GitLab CI, or Jenkins
|
||||
5. **Reproducible builds** - pin dependency versions, document toolchain
|
||||
|
||||
**Platform Checklist:**
|
||||
|
||||
- [ ] macOS: Universal binary (arm64 + x86_64)
|
||||
- [ ] macOS: Code signed with Developer ID
|
||||
- [ ] macOS: Notarized (10.15+ requirement)
|
||||
- [ ] macOS: AU validation passes (`auval`)
|
||||
- [ ] Windows: Code signed (recommended)
|
||||
- [ ] Windows: Static runtime linked (/MT)
|
||||
- [ ] Linux: Dependencies documented
|
||||
- [ ] All: Tested in major DAWs on each platform
|
||||
|
||||
---
|
||||
|
||||
**Related Resources:**
|
||||
- `/release-build` command - Automated release workflow
|
||||
- BUILD_GUIDE.md - Detailed build procedures
|
||||
- RELEASE_CHECKLIST.md - Pre-release validation steps
|
||||
- @build-engineer - CI/CD and build automation expert
|
||||
Reference in New Issue
Block a user