xtc/CMakeLists.txt

200 lines
8.7 KiB
CMake

cmake_minimum_required(VERSION 3.25)
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS include/xtc/xtc_version.h)
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/include/xtc/xtc_version.h" version_line REGEX "^#define XTC_VERSION_STRING")
string(REGEX MATCH "[0-9]+[.][0-9]+[.][0-9]+" XTC_VERSION "${version_line}")
project(xtc VERSION ${XTC_VERSION} LANGUAGES C)
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
message(FATAL_ERROR "Use an out-of-source build: cmake -S . -B build")
endif()
include(GNUInstallDirs)
include(CTest)
find_package(Threads REQUIRED)
find_package(Python3 3.12 REQUIRED COMPONENTS Interpreter)
find_package(PkgConfig QUIET)
option(XTC_WITH_JACK "Discover the optional JACK backend" ON)
option(XTC_WITH_LADSPA "Enable LADSPA when its system header is available" ON)
option(XTC_BUILD_GUI "Build the FLTK application when FLTK is available" ON)
option(XTC_ENABLE_LIVE_TESTS "Register tests requiring an existing JACK server" OFF)
option(XTC_BUILD_JUCE "Build optional externally supplied JUCE examples" OFF)
option(XTC_BUILD_STEINBERG "Build optional externally supplied Steinberg examples" OFF)
option(XTC_SANITIZE "Enable address and undefined-behavior sanitizers" OFF)
option(XTC_REPRODUCIBLE "Remove source/build paths from optimized release artifacts" OFF)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Keep project warnings/assertions local; external SDKs control their own flags.
function(xtc_warnings target)
target_compile_options(${target} PRIVATE -Wall -Wextra -Wpedantic -UNDEBUG
"$<$<COMPILE_LANGUAGE:C>:-Wconversion;-Wshadow>")
endfunction()
if(XTC_SANITIZE)
add_compile_options(-fsanitize=address,undefined -fno-omit-frame-pointer)
add_link_options(-fsanitize=address,undefined)
endif()
if(XTC_REPRODUCIBLE)
add_compile_options("-ffile-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}=."
"-ffile-prefix-map=${CMAKE_CURRENT_BINARY_DIR}=build" -g0)
endif()
if(XTC_WITH_JACK AND PkgConfig_FOUND)
pkg_check_modules(JACK QUIET IMPORTED_TARGET jack)
endif()
add_library(xtc-core STATIC
src/plugin/module_path.c
src/midi/file.c
src/midi/output.c
src/project/crossfade.c
src/control/tempo.c
src/project/chain_tools.c
src/project/chain_preset.c
src/mixer/track_fx.c
src/audio/sample.c
src/persistence/collect.c
src/audio/normalize.c
src/project/sections.c
src/project/editing.c
src/audio/export.c
src/plugin/builtin.c
src/settings/settings.c
src/control/model.c
src/audio/waveform.c
src/plugin/ladspa.c
src/plugin/host.c
src/plugin/modern.c
src/native/processor.c
src/audio/recovery.c
src/dsp/ramp.c
src/native/native.c
src/mixer/model.c
src/mixer/render.c
src/project/history.c
src/midi/model.c
src/midi/instrument.c
src/audio/wave.c
src/audio/arrangement.c
src/audio/recorder.c
src/core/xtc.c
src/project/project.c
src/persistence/project_file.c
src/graph/graph.c
src/dsp/gain.c
src/engine/offline_engine.c
src/engine/realtime.c
src/backend/jack_backend.c
)
set_target_properties(xtc-core PROPERTIES OUTPUT_NAME xtc)
xtc_warnings(xtc-core)
add_library(xtc::core ALIAS xtc-core)
target_include_directories(xtc-core PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>" "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
target_include_directories(xtc-core SYSTEM PRIVATE third_party/clap/include third_party/vst3)
target_link_libraries(xtc-core PUBLIC m ${CMAKE_DL_LIBS} Threads::Threads)
if(JACK_FOUND AND XTC_WITH_JACK)
target_compile_definitions(xtc-core PRIVATE XTC_HAVE_JACK)
target_link_libraries(xtc-core PUBLIC PkgConfig::JACK)
endif()
include(CheckIncludeFile)
check_include_file(ladspa.h XTC_HAVE_LADSPA_HEADER)
if(XTC_HAVE_LADSPA_HEADER AND XTC_WITH_LADSPA)
set(XTC_LADSPA_AVAILABLE TRUE)
endif()
if(NOT XTC_WITH_LADSPA)
target_compile_definitions(xtc-core PRIVATE XTC_DISABLE_LADSPA)
endif()
function(xtc_executable name source)
add_executable(${name} ${source} ${ARGN})
target_link_libraries(${name} PRIVATE xtc-core)
xtc_warnings(${name})
endfunction()
xtc_executable(xtc-check src/main.c)
xtc_executable(native-gain examples/native_gain.c)
xtc_executable(quality-preview-render examples/quality_preview.c)
set_target_properties(quality-preview-render PROPERTIES OUTPUT_NAME xtc-quality-preview)
xtc_executable(builtin-preview-render examples/builtin_preview.c)
set_target_properties(builtin-preview-render PROPERTIES OUTPUT_NAME xtc-builtin-preview)
foreach(preview quality builtin)
add_custom_target(${preview}-preview
COMMAND ${preview}-preview-render "${CMAKE_CURRENT_BINARY_DIR}/${preview}"
DEPENDS ${preview}-preview-render VERBATIM)
endforeach()
include(cmake/Tests.cmake)
include(cmake/Gui.cmake)
include(cmake/Developer.cmake)
include(cmake/Install.cmake)
if(XTC_BUILD_STEINBERG)
enable_language(CXX)
add_subdirectory(examples/steinberg steinberg-sdk)
xtc_executable(steinberg-render examples/steinberg/render.c)
add_custom_target(steinberg-sdk DEPENDS xtc-sdk-examples validator)
if(BUILD_TESTING)
xtc_executable(test_steinberg_sdk tests/integration/test_steinberg_sdk.c)
set(steinberg_bundle "$<PATH:GET_PARENT_PATH,$<PATH:GET_PARENT_PATH,$<TARGET_FILE_DIR:xtc-sdk-examples>>>")
xtc_test(steinberg-sdk test_steinberg_sdk "${steinberg_bundle}")
add_test(NAME steinberg-validator COMMAND $<TARGET_FILE:validator> "${steinberg_bundle}")
set_tests_properties(steinberg-sdk steinberg-validator PROPERTIES LABELS sdk)
endif()
endif()
if(XTC_BUILD_JUCE)
if(BUILD_TESTING)
find_program(XTC_XVFB_RUN xvfb-run REQUIRED)
endif()
enable_language(CXX)
add_subdirectory(examples/juce juce)
add_custom_target(juce-examples DEPENDS xtc-juce-render XtcJuceSynth_VST3 XtcJuceSynth_Standalone)
if(BUILD_TESTING)
xtc_executable(test_juce_plugin tests/integration/test_juce_plugin.c)
add_test(NAME juce-c-host COMMAND ${XTC_XVFB_RUN} -a $<TARGET_FILE:test_juce_plugin>
"$<PATH:GET_PARENT_PATH,$<PATH:GET_PARENT_PATH,$<TARGET_FILE_DIR:XtcJuceSynth_VST3>>>")
add_test(NAME juce-files-editor COMMAND ${XTC_XVFB_RUN} -a ${Python3_EXECUTABLE}
"${CMAKE_CURRENT_SOURCE_DIR}/tests/integration/test_juce_examples.py" $<TARGET_FILE:xtc-juce-render>)
set_tests_properties(juce-c-host juce-files-editor PROPERTIES LABELS sdk)
endif()
endif()
if(BUILD_TESTING)
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" USES_TERMINAL)
get_property(xtc_build_targets DIRECTORY PROPERTY BUILDSYSTEM_TARGETS)
foreach(binary IN LISTS xtc_build_targets)
get_target_property(kind ${binary} TYPE)
if(kind MATCHES "^(EXECUTABLE|MODULE_LIBRARY|STATIC_LIBRARY)$" AND NOT binary STREQUAL capture_screenshots)
add_dependencies(check ${binary})
endif()
endforeach()
if(XTC_BUILD_JUCE)
add_dependencies(check xtc-juce-render XtcJuceSynth_VST3 XtcJuceSynth_Standalone)
endif()
if(XTC_BUILD_STEINBERG)
add_dependencies(check xtc-sdk-examples validator)
endif()
get_property(xtc_tests DIRECTORY PROPERTY TESTS)
foreach(name IN LISTS xtc_tests)
if(NOT TARGET test-${name} AND NOT name STREQUAL steinberg-sdk)
add_custom_target(test-${name} COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -R "^${name}$"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" USES_TERMINAL)
foreach(binary IN LISTS xtc_build_targets)
get_target_property(kind ${binary} TYPE)
if(kind MATCHES "^(EXECUTABLE|MODULE_LIBRARY|STATIC_LIBRARY)$" AND NOT binary STREQUAL capture_screenshots)
add_dependencies(test-${name} ${binary})
endif()
endforeach()
endif()
endforeach()
endif()
if(BUILD_TESTING)
include(cmake/Variants.cmake)
# Historical workflow names retained as CMake target aliases.
add_custom_target(test-builtins DEPENDS test-builtin)
if(XTC_BUILD_JUCE)
add_custom_target(test-juce COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -R "juce"
DEPENDS xtc-juce-render XtcJuceSynth_VST3 XtcJuceSynth_Standalone test_juce_plugin USES_TERMINAL)
endif()
if(XTC_BUILD_STEINBERG)
add_custom_target(test-steinberg-sdk COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -R steinberg
DEPENDS xtc-sdk-examples validator test_steinberg_sdk steinberg-render USES_TERMINAL)
endif()
endif()