925 lines
23 KiB
Markdown
925 lines
23 KiB
Markdown
---
|
|
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
|