rack 0.4.8

A modern Rust library for hosting audio plugins
Documentation
cmake_minimum_required(VERSION 3.15)
project(rack_sys VERSION 0.1.0 LANGUAGES CXX)

# C++20 required for aligned allocation and modern C++ features
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# AudioUnit source files (Apple platforms only)
set(RACK_AU_SOURCES)
if(APPLE)
    set(RACK_AU_SOURCES
        src/rack_au.cpp
        src/au_scanner.cpp
        src/au_instance.cpp
    )
    # Add GUI sources only on macOS (requires AppKit)
    # iOS and visionOS don't have AppKit
    if(NOT CMAKE_SYSTEM_NAME MATCHES "iOS|visionOS")
        list(APPEND RACK_AU_SOURCES src/au_gui.mm)
    endif()
endif()

# Check if VST3 SDK is available
# VST3 is only supported on desktop platforms (macOS, Linux, Windows)
# VST3_SDK_PATH can be overridden by build.rs (e.g., when building from crates.io)
if(NOT DEFINED VST3_SDK_PATH)
    set(VST3_SDK_PATH "${CMAKE_CURRENT_SOURCE_DIR}/external/vst3sdk")
endif()
message(STATUS "VST3 SDK path: ${VST3_SDK_PATH}")
set(HAVE_VST3_SDK FALSE)

# VST3 is not supported on mobile platforms
if(CMAKE_SYSTEM_NAME MATCHES "iOS|tvOS|watchOS|visionOS")
    message(STATUS "VST3 disabled on ${CMAKE_SYSTEM_NAME} (desktop-only format)")
elseif(EXISTS "${VST3_SDK_PATH}/CMakeLists.txt")
    set(HAVE_VST3_SDK TRUE)
    message(STATUS "VST3 SDK found at ${VST3_SDK_PATH}")
else()
    message(WARNING "VST3 SDK not found at ${VST3_SDK_PATH}")
    message(WARNING "VST3 support will be disabled. To enable it:")
    message(WARNING "  cd ${CMAKE_CURRENT_SOURCE_DIR} && git clone --recursive https://github.com/steinbergmedia/vst3sdk.git external/vst3sdk")
endif()

# VST3 source files (cross-platform, only if SDK available)
set(RACK_VST3_SOURCES)
set(VST3_SDK_SOURCES)
if(HAVE_VST3_SDK)
    set(RACK_VST3_SOURCES
        src/vst3_scanner.cpp
        src/vst3_instance.cpp
    )

    # VST3 SDK base sources (required for FUID, FUnknown, etc.)
    set(VST3_SDK_SOURCES
        # Base library - provides FUID, FUnknown, interface IIDs
        ${VST3_SDK_PATH}/public.sdk/source/common/commoniids.cpp
        ${VST3_SDK_PATH}/pluginterfaces/base/funknown.cpp
        ${VST3_SDK_PATH}/pluginterfaces/base/coreiids.cpp
        # String conversion utilities (UTF-16 <-> UTF-8)
        ${VST3_SDK_PATH}/public.sdk/source/common/commonstringconvert.cpp
        ${VST3_SDK_PATH}/public.sdk/source/vst/vstinitiids.cpp
        ${VST3_SDK_PATH}/public.sdk/source/vst/utility/stringconvert.cpp
        # Hosting sources
        ${VST3_SDK_PATH}/public.sdk/source/vst/hosting/module.cpp
        ${VST3_SDK_PATH}/public.sdk/source/vst/hosting/plugprovider.cpp
        ${VST3_SDK_PATH}/public.sdk/source/vst/hosting/hostclasses.cpp
        ${VST3_SDK_PATH}/public.sdk/source/vst/hosting/processdata.cpp
        ${VST3_SDK_PATH}/public.sdk/source/vst/hosting/parameterchanges.cpp
        ${VST3_SDK_PATH}/public.sdk/source/vst/hosting/eventlist.cpp
        ${VST3_SDK_PATH}/public.sdk/source/vst/hosting/connectionproxy.cpp
        ${VST3_SDK_PATH}/public.sdk/source/vst/hosting/pluginterfacesupport.cpp
    )

    # Platform-specific VST3 module loading
    if(APPLE)
        list(APPEND VST3_SDK_SOURCES ${VST3_SDK_PATH}/public.sdk/source/vst/hosting/module_mac.mm)
    elseif(WIN32)
        list(APPEND VST3_SDK_SOURCES ${VST3_SDK_PATH}/public.sdk/source/vst/hosting/module_win32.cpp)
    else()
        list(APPEND VST3_SDK_SOURCES ${VST3_SDK_PATH}/public.sdk/source/vst/hosting/module_linux.cpp)
    endif()
endif()

# Combine all sources
set(RACK_SYS_SOURCES ${RACK_AU_SOURCES} ${RACK_VST3_SOURCES} ${VST3_SDK_SOURCES})

# Validate that we have at least one plugin format
# On docs.rs, allow build to succeed with stub library for documentation
if(NOT RACK_AU_SOURCES AND NOT RACK_VST3_SOURCES)
    if(DOCS_RS_BUILD)
        message(WARNING "No plugin formats available - building stub library for docs.rs")
        # Create a minimal stub source file for docs.rs
        set(RACK_SYS_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/stub.cpp")
    else()
        message(FATAL_ERROR "No plugin formats available! "
            "On macOS/iOS, AudioUnit support should be automatic. "
            "For VST3, clone the SDK: git clone --recursive https://github.com/steinbergmedia/vst3sdk.git external/vst3sdk")
    endif()
endif()

# Build as static library for easy linking with Rust
add_library(rack_sys STATIC ${RACK_SYS_SOURCES})

# Public headers
target_include_directories(rack_sys PUBLIC
    ${CMAKE_CURRENT_SOURCE_DIR}/include
)

# Add VST3 SDK include directory if available
if(HAVE_VST3_SDK)
    target_include_directories(rack_sys PUBLIC
        ${VST3_SDK_PATH}
    )
endif()

# Apple platform-specific settings
if(APPLE)
    # Link required frameworks (common to macOS and iOS)
    target_link_libraries(rack_sys PUBLIC
        "-framework AudioToolbox"
        "-framework CoreAudio"
        "-framework CoreFoundation"
        "-framework CoreAudioKit"
    )

    # Platform-specific UI frameworks
    if(CMAKE_SYSTEM_NAME MATCHES "iOS|visionOS")
        # iOS/visionOS: GUI provided by app extensions (UIKit would go here if needed)
        # target_link_libraries(rack_sys PUBLIC "-framework UIKit")
        message(STATUS "Building for ${CMAKE_SYSTEM_NAME} - GUI disabled (provided by app extensions)")
    else()
        # macOS: Link AppKit for GUI support
        target_link_libraries(rack_sys PUBLIC "-framework AppKit")
        message(STATUS "Building for macOS - GUI enabled")
    endif()

    # Enable ARC (Automatic Reference Counting) for Objective-C++
    # Required for au_gui.mm on macOS
    target_compile_options(rack_sys PRIVATE -fobjc-arc)
endif()

# Linux platform-specific settings (for VST3)
if(UNIX AND NOT APPLE)
    target_link_libraries(rack_sys PUBLIC ${CMAKE_DL_LIBS})
endif()

# Compiler warnings
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
    target_compile_options(rack_sys PRIVATE
        -Wall
        -Wextra
        -Wpedantic
        -Wno-unused-parameter
    )
endif()

# Install library
install(TARGETS rack_sys
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib
)

# Install headers
install(DIRECTORY include/
    DESTINATION include
)

# Optional: Enable AddressSanitizer for debugging
option(ENABLE_ASAN "Enable AddressSanitizer for memory error detection" OFF)
if(ENABLE_ASAN)
    add_compile_options(
        $<$<COMPILE_LANGUAGE:CXX,C>:-fsanitize=address>
        $<$<COMPILE_LANGUAGE:CXX,C>:-fno-optimize-sibling-calls>
        $<$<COMPILE_LANGUAGE:CXX,C>:-fsanitize-address-use-after-scope>
        $<$<COMPILE_LANGUAGE:CXX,C>:-fno-omit-frame-pointer>
        $<$<COMPILE_LANGUAGE:CXX,C>:-g>
    )

    if(CMAKE_GENERATOR STREQUAL "Xcode")
        add_link_options(
            -fsanitize=address
            -fno-optimize-sibling-calls
            -fsanitize-address-use-after-scope
            -fno-omit-frame-pointer
            -g
        )
    else()
        add_link_options(
            $<$<COMPILE_LANGUAGE:CXX,C>:-fsanitize=address>
            $<$<COMPILE_LANGUAGE:CXX,C>:-fno-optimize-sibling-calls>
            $<$<COMPILE_LANGUAGE:CXX,C>:-fsanitize-address-use-after-scope>
            $<$<COMPILE_LANGUAGE:CXX,C>:-fno-omit-frame-pointer>
            $<$<COMPILE_LANGUAGE:CXX,C>:-g>
        )
    endif()

    message(STATUS "AddressSanitizer enabled")
endif()

# Optional: Build test executables
option(BUILD_TESTS "Build test executables" OFF)
if(BUILD_TESTS)
    # Scanner test
    add_executable(rack_sys_test_scanner
        test/test_scanner.cpp
    )
    target_link_libraries(rack_sys_test_scanner PRIVATE rack_sys)

    # Instance test
    add_executable(rack_sys_test_instance
        test/test_instance.cpp
    )
    target_link_libraries(rack_sys_test_instance PRIVATE rack_sys)

    # GUI test
    add_executable(rack_sys_test_gui
        test/test_gui.cpp
    )
    target_link_libraries(rack_sys_test_gui PRIVATE rack_sys)
endif()