Claude
Skills
Sign in
Back

cross-platform-builds

Included with Lifetime
$97 forever

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.

Cloud & DevOps

What this skill does


# 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://a

Related in Cloud & DevOps