diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt index a7dbc06865..0a5a496c85 100644 --- a/src/audio_core/CMakeLists.txt +++ b/src/audio_core/CMakeLists.txt @@ -2,966 +2,295 @@ # SPDX-FileCopyrightText: 2025 citron Emulator Project # SPDX-License-Identifier: GPL-2.0-or-later -cmake_minimum_required(VERSION 3.22) +add_library(audio_core STATIC + adsp/adsp.cpp + adsp/adsp.h + adsp/mailbox.h + adsp/apps/audio_renderer/audio_renderer.cpp + adsp/apps/audio_renderer/audio_renderer.h + adsp/apps/audio_renderer/command_buffer.h + adsp/apps/audio_renderer/command_list_processor.cpp + adsp/apps/audio_renderer/command_list_processor.h + adsp/apps/opus/opus_decoder.cpp + adsp/apps/opus/opus_decoder.h + adsp/apps/opus/opus_decode_object.cpp + adsp/apps/opus/opus_decode_object.h + adsp/apps/opus/opus_multistream_decode_object.cpp + adsp/apps/opus/opus_multistream_decode_object.h + adsp/apps/opus/shared_memory.h + audio_core.cpp + audio_core.h + audio_event.h + audio_event.cpp + audio_render_manager.cpp + audio_render_manager.h + audio_in_manager.cpp + audio_in_manager.h + audio_out_manager.cpp + audio_out_manager.h + audio_manager.cpp + audio_manager.h + audio_system_manager.cpp + audio_system_manager.h + audio_snoop_manager.cpp + audio_snoop_manager.h + common/audio_helpers.h + common/audio_renderer_parameter.h + common/common.h + common/feature_support.h + common/fft.cpp + common/fft.h + common/loudness_calculator.cpp + common/loudness_calculator.h + common/wave_buffer.h + common/workbuffer_allocator.h + device/audio_buffer.h + device/audio_buffer_list.h + device/audio_buffers.h + device/device_session.cpp + device/device_session.h + device/shared_ring_buffer.cpp + device/shared_ring_buffer.h + in/audio_in.cpp + in/audio_in.h + in/audio_in_system.cpp + in/audio_in_system.h + opus/hardware_opus.cpp + opus/hardware_opus.h + opus/decoder_manager.cpp + opus/decoder_manager.h + opus/decoder.cpp + opus/decoder.h + opus/parameters.h + out/audio_out.cpp + out/audio_out.h + out/audio_out_system.cpp + out/audio_out_system.h + precompiled_headers.h + renderer/audio_device.cpp + renderer/audio_device.h + renderer/audio_renderer.h + renderer/audio_renderer.cpp + renderer/behavior/behavior_info.cpp + renderer/behavior/behavior_info.h + renderer/behavior/info_updater.cpp + renderer/behavior/info_updater.h + renderer/command/data_source/adpcm.cpp + renderer/command/data_source/adpcm.h + renderer/command/data_source/decode.cpp + renderer/command/data_source/decode.h + renderer/command/data_source/pcm_float.cpp + renderer/command/data_source/pcm_float.h + renderer/command/data_source/pcm_int16.cpp + renderer/command/data_source/pcm_int16.h + renderer/command/effect/aux_.cpp + renderer/command/effect/aux_.h + renderer/command/effect/biquad_filter.cpp + renderer/command/effect/biquad_filter.h + renderer/command/effect/capture.cpp + renderer/command/effect/capture.h + renderer/command/effect/compressor.cpp + renderer/command/effect/compressor.h + renderer/command/effect/delay.cpp + renderer/command/effect/delay.h + renderer/command/effect/i3dl2_reverb.cpp + renderer/command/effect/i3dl2_reverb.h + renderer/command/effect/light_limiter.cpp + renderer/command/effect/light_limiter.h + renderer/command/effect/limiter.cpp + renderer/command/effect/limiter.h + renderer/command/effect/multi_tap_biquad_filter.cpp + renderer/command/effect/multi_tap_biquad_filter.h + renderer/command/effect/biquad_filter_and_mix.cpp + renderer/command/effect/biquad_filter_and_mix.h + renderer/command/effect/multi_tap_biquad_filter_and_mix.cpp + renderer/command/effect/multi_tap_biquad_filter_and_mix.h + renderer/command/effect/reverb.cpp + renderer/command/effect/reverb.h + renderer/command/mix/clear_mix.cpp + renderer/command/mix/clear_mix.h + renderer/command/mix/copy_mix.cpp + renderer/command/mix/copy_mix.h + renderer/command/mix/depop_for_mix_buffers.cpp + renderer/command/mix/depop_for_mix_buffers.h + renderer/command/mix/depop_prepare.cpp + renderer/command/mix/depop_prepare.h + renderer/command/mix/mix.cpp + renderer/command/mix/mix.h + renderer/command/mix/mix_ramp.cpp + renderer/command/mix/mix_ramp.h + renderer/command/mix/mix_ramp_grouped.cpp + renderer/command/mix/mix_ramp_grouped.h + renderer/command/mix/volume.cpp + renderer/command/mix/volume.h + renderer/command/mix/volume_ramp.cpp + renderer/command/mix/volume_ramp.h + renderer/command/performance/performance.cpp + renderer/command/performance/performance.h + renderer/command/resample/downmix_6ch_to_2ch.cpp + renderer/command/resample/downmix_6ch_to_2ch.h + renderer/command/resample/resample.h + renderer/command/resample/resample.cpp + renderer/command/resample/upsample.cpp + renderer/command/resample/upsample.h + renderer/command/sink/device.cpp + renderer/command/sink/device.h + renderer/command/sink/circular_buffer.cpp + renderer/command/sink/circular_buffer.h + renderer/command/command_buffer.cpp + renderer/command/command_buffer.h + renderer/command/command_generator.cpp + renderer/command/command_generator.h + renderer/command/command_list_header.h + renderer/command/command_processing_time_estimator.cpp + renderer/command/command_processing_time_estimator.h + renderer/command/commands.h + renderer/command/icommand.h + renderer/effect/aux_.cpp + renderer/effect/aux_.h + renderer/effect/biquad_filter.cpp + renderer/effect/biquad_filter.h + renderer/effect/buffer_mixer.cpp + renderer/effect/buffer_mixer.h + renderer/effect/capture.cpp + renderer/effect/capture.h + renderer/effect/compressor.cpp + renderer/effect/compressor.h + renderer/effect/delay.cpp + renderer/effect/delay.h + renderer/effect/effect_context.cpp + renderer/effect/effect_context.h + renderer/effect/effect_info_base.h + renderer/effect/effect_reset.h + renderer/effect/effect_result_state.h + renderer/effect/i3dl2.cpp + renderer/effect/i3dl2.h + renderer/effect/light_limiter.cpp + renderer/effect/light_limiter.h + renderer/effect/limiter.cpp + renderer/effect/limiter.h + renderer/effect/reverb.h + renderer/effect/reverb.cpp + renderer/final_output_recorder/final_output_recorder_buffer.h + renderer/final_output_recorder/final_output_recorder_system.cpp + renderer/final_output_recorder/final_output_recorder_system.h + renderer/mix/mix_context.cpp + renderer/mix/mix_context.h + renderer/mix/mix_info.cpp + renderer/mix/mix_info.h + renderer/memory/address_info.h + renderer/memory/memory_pool_info.cpp + renderer/memory/memory_pool_info.h + renderer/memory/pool_mapper.cpp + renderer/memory/pool_mapper.h + renderer/nodes/bit_array.h + renderer/nodes/edge_matrix.cpp + renderer/nodes/edge_matrix.h + renderer/nodes/node_states.cpp + renderer/nodes/node_states.h + renderer/performance/detail_aspect.cpp + renderer/performance/detail_aspect.h + renderer/performance/entry_aspect.cpp + renderer/performance/entry_aspect.h + renderer/performance/performance_detail.h + renderer/performance/performance_entry.h + renderer/performance/performance_entry_addresses.h + renderer/performance/performance_frame_header.h + renderer/performance/performance_manager.cpp + renderer/performance/performance_manager.h + renderer/sink/circular_buffer_sink_info.cpp + renderer/sink/circular_buffer_sink_info.h + renderer/sink/device_sink_info.cpp + renderer/sink/device_sink_info.h + renderer/sink/sink_context.cpp + renderer/sink/sink_context.h + renderer/sink/sink_info_base.cpp + renderer/sink/sink_info_base.h + renderer/splitter/splitter_context.cpp + renderer/splitter/splitter_context.h + renderer/splitter/splitter_destinations_data.cpp + renderer/splitter/splitter_destinations_data.h + renderer/splitter/splitter_info.cpp + renderer/splitter/splitter_info.h + renderer/system.cpp + renderer/system.h + renderer/system_manager.cpp + renderer/system_manager.h + renderer/upsampler/upsampler_info.h + renderer/upsampler/upsampler_manager.cpp + renderer/upsampler/upsampler_manager.h + renderer/upsampler/upsampler_state.h + renderer/voice/voice_channel_resource.h + renderer/voice/voice_context.cpp + renderer/voice/voice_context.h + renderer/voice/voice_info.cpp + renderer/voice/voice_info.h + renderer/voice/voice_state.h + sink/null_sink.h + sink/sink.h + sink/sink_details.cpp + sink/sink_details.h + sink/sink_stream.cpp + sink/sink_stream.h +) -# Set minimum CMake policy version -set(CMAKE_POLICY_VERSION_MINIMUM 3.5) - -project(citron) - -# Define the build type, defaulting to "Nightly" for development and CI builds. -set(CITRON_BUILD_TYPE "Stable" CACHE STRING "The build type for the emulator (e.g., Stable, Nightly)") - -# For cmake-gui, this creates a dropdown to select the build type. -set_property(CACHE CITRON_BUILD_TYPE PROPERTY STRINGS Stable Nightly) - -# Pass the build type to the C++ source code as a preprocessor definition. -add_definitions("-DCITRON_BUILD_TYPE=\"${CITRON_BUILD_TYPE}\"") - -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules") -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules") - -include(DownloadExternals) -include(CMakeDependentOption) -include(CTest) -include(PGO) - -# Disable Warnings as Errors for MSVC if (MSVC) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W3 /WX-") - # Add specific warning suppressions for Qt6 compatibility - add_compile_options(/wd4996) # Suppress deprecated function warnings - add_compile_options(/wd4267) # Suppress size_t conversion warnings -endif() - -# Check if SDL2::SDL2 target exists; if not, create an alias -if (TARGET SDL2::SDL2-static) - add_library(SDL2::SDL2 ALIAS SDL2::SDL2-static) -elseif (TARGET SDL2::SDL2-shared) - add_library(SDL2::SDL2 ALIAS SDL2::SDL2-shared) -endif() - -# Set bundled sdl2/qt as dependent options. -option(ENABLE_SDL2 "Enable the SDL2 frontend" ON) -CMAKE_DEPENDENT_OPTION(CITRON_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON "ENABLE_SDL2;MSVC" OFF) -CMAKE_DEPENDENT_OPTION(CITRON_USE_EXTERNAL_SDL2 "Compile external SDL2" ON "ENABLE_SDL2;NOT MSVC" OFF) - -cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "NOT ANDROID" OFF) - -option(ENABLE_QT "Enable the Qt frontend" ON) - -option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF) -CMAKE_DEPENDENT_OPTION(CITRON_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSVC}" "ENABLE_QT" OFF) - -set(DEFAULT_ENABLE_WEB_SERVICE ON) -if (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") - set(DEFAULT_ENABLE_WEB_SERVICE OFF) -endif() -option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" "${DEFAULT_ENABLE_WEB_SERVICE}") - -option(CITRON_USE_BUNDLED_FFMPEG "Download/Build bundled FFmpeg" "${WIN32}") - -option(CITRON_USE_EXTERNAL_VULKAN_HEADERS "Use Vulkan-Headers from externals" ON) - -option(CITRON_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES "Use Vulkan-Utility-Libraries from externals" ON) - -option(CITRON_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF) - -option(CITRON_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF) - -option(CITRON_USE_AUTO_UPDATER "Enable automatic updater functionality" OFF) - -option(ENABLE_UNITY_BUILD "Enables the unity build" OFF) - -option(ENABLE_CUBEB "Enables the cubeb audio backend" ON) - -option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF) - -option(CITRON_TESTS "Compile tests" "${BUILD_TESTING}") - -option(CITRON_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON) - -option(CITRON_DOWNLOAD_ANDROID_VVL "Download validation layer binary for android" ON) - -CMAKE_DEPENDENT_OPTION(CITRON_ROOM "Compile LDN room server" ON "NOT ANDROID" OFF) - -CMAKE_DEPENDENT_OPTION(CITRON_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR LINUX" OFF) - -# CITRON_USE_CPM is the primary way to fetch dependencies on Linux and for Clangtron. -# vcpkg is supported primarily for native MSVC and Android builds. -option(CITRON_USE_BUNDLED_VCPKG "Use vcpkg for citron dependencies" "${MSVC}") -option(CITRON_USE_CPM "Use CPM.cmake to fetch dependencies" OFF) - -option(CITRON_CHECK_SUBMODULES "Check if submodules are present" ON) - -option(CITRON_ENABLE_LTO "Enable link-time optimization" OFF) - -option(CITRON_ENABLE_PGO_GENERATE "Build with PGO instrumentation to generate profile data (Stage 1)" OFF) -option(CITRON_ENABLE_PGO_USE "Build using PGO profile data for optimization (Stage 2)" OFF) -set(CITRON_PGO_PROFILE_DIR "${CMAKE_BINARY_DIR}/pgo-profiles" CACHE PATH "Directory to store PGO profile data") - -option(CITRON_DOWNLOAD_TIME_ZONE_DATA "Always download time zone binaries" OFF) - -CMAKE_DEPENDENT_OPTION(CITRON_USE_FASTER_LD "Check if a faster linker is available" ON "NOT WIN32" OFF) - -CMAKE_DEPENDENT_OPTION(USE_SYSTEM_MOLTENVK "Use the system MoltenVK lib (instead of the bundled one)" OFF "APPLE" OFF) - -set(DEFAULT_ENABLE_OPENSSL ON) -if (WIN32 OR APPLE) - set(DEFAULT_ENABLE_OPENSSL OFF) -endif() -option(ENABLE_OPENSSL "Enable OpenSSL backend for ISslConnection" ${DEFAULT_ENABLE_OPENSSL}) - -if (CITRON_USE_BUNDLED_VCPKG) - if (ANDROID) - set(ENV{ANDROID_NDK_HOME} "${ANDROID_NDK}") - list(APPEND VCPKG_MANIFEST_FEATURES "android") - - if (CMAKE_ANDROID_ARCH_ABI STREQUAL "arm64-v8a") - set(VCPKG_TARGET_TRIPLET "arm64-android") - set(PKG_CONFIG_EXECUTABLE "aarch64-none-linux-android-pkg-config" CACHE FILEPATH "" FORCE) - elseif (CMAKE_ANDROID_ARCH_ABI STREQUAL "x86_64") - set(VCPKG_TARGET_TRIPLET "x64-android") - set(PKG_CONFIG_EXECUTABLE "x86_64-none-linux-android-pkg-config" CACHE FILEPATH "" FORCE) - else() - message(FATAL_ERROR "Unsupported Android architecture ${CMAKE_ANDROID_ARCH_ABI}") - endif() - endif() - - if (MSVC) - set(VCPKG_DOWNLOADS_PATH ${PROJECT_SOURCE_DIR}/externals/vcpkg/downloads) - set(NASM_VERSION "2.16.03") - set(NASM_DESTINATION_PATH ${VCPKG_DOWNLOADS_PATH}/nasm-${NASM_VERSION}-win64.zip) - set(NASM_DOWNLOAD_URL "https://www.nasm.us/pub/nasm/releasebuilds/${NASM_VERSION}/win64/nasm-${NASM_VERSION}-win64.zip") - - if (NOT EXISTS ${NASM_DESTINATION_PATH}) - file(DOWNLOAD ${NASM_DOWNLOAD_URL} ${NASM_DESTINATION_PATH} SHOW_PROGRESS STATUS NASM_STATUS) - if (NOT NASM_STATUS EQUAL 0) - message(WARNING "External nasm vcpkg package download from ${NASM_DOWNLOAD_URL} failed with status ${NASM_STATUS}") - endif() - endif() - endif() - - if (CITRON_TESTS) - list(APPEND VCPKG_MANIFEST_FEATURES "citron-tests") - endif() - if (ENABLE_WEB_SERVICE) - list(APPEND VCPKG_MANIFEST_FEATURES "web-service") - endif() - - include(${CMAKE_SOURCE_DIR}/externals/vcpkg/scripts/buildsystems/vcpkg.cmake) -elseif(NOT "$ENV{VCPKG_TOOLCHAIN_FILE}" STREQUAL "") - option(VCPKG_MANIFEST_MODE "") - include("$ENV{VCPKG_TOOLCHAIN_FILE}") -endif() - -option(CITRON_USE_PRECOMPILED_HEADERS "Use Precompiled Headers" ON) - -if (CITRON_USE_PRECOMPILED_HEADERS) - if (MSVC AND CCACHE) - # buildcache does not properly cache PCH files, leading to compilation errors. - # See https://github.com/mbitsnbites/buildcache/discussions/230 - message(WARNING "buildcache does not properly support Precompiled Headers. Disabling PCH") - set(DYNARMIC_USE_PRECOMPILED_HEADERS OFF CACHE BOOL "" FORCE) - set(CITRON_USE_PRECOMPILED_HEADERS OFF CACHE BOOL "" FORCE) - endif() -endif() -if (CITRON_USE_PRECOMPILED_HEADERS) - message(STATUS "Using Precompiled Headers.") - set(CMAKE_PCH_INSTANTIATE_TEMPLATES ON) -endif() - - -# Default to a Release build -get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) -if (NOT IS_MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) - message(STATUS "Defaulting to a Release build") -endif() - -if(EXISTS ${PROJECT_SOURCE_DIR}/hooks/pre-commit AND NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/hooks/pre-commit) - if (EXISTS ${PROJECT_SOURCE_DIR}/.git/) - message(STATUS "Copying pre-commit hook") - file(COPY hooks/pre-commit DESTINATION ${PROJECT_SOURCE_DIR}/.git/hooks) - endif() -endif() - -# Sanity check : Check that all submodules are present -# ======================================================================= - -function(check_submodules_present) - file(READ "${PROJECT_SOURCE_DIR}/.gitmodules" gitmodules) - string(REGEX MATCHALL "path *= *[^ \t\r\n]*" gitmodules ${gitmodules}) - foreach(module ${gitmodules}) - string(REGEX REPLACE "path *= *" "" module ${module}) - if (NOT EXISTS "${PROJECT_SOURCE_DIR}/${module}/.git") - message(FATAL_ERROR "Git submodule ${module} not found. " - "Please run: \ngit submodule update --init --recursive") - endif() - endforeach() -endfunction() - -if(EXISTS ${PROJECT_SOURCE_DIR}/.gitmodules AND CITRON_CHECK_SUBMODULES AND NOT CITRON_USE_CPM) - check_submodules_present() -endif() -configure_file(${PROJECT_SOURCE_DIR}/dist/compatibility_list/compatibility_list.qrc - ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.qrc - COPYONLY) -if (EXISTS ${PROJECT_SOURCE_DIR}/dist/compatibility_list/compatibility_list.json) - configure_file("${PROJECT_SOURCE_DIR}/dist/compatibility_list/compatibility_list.json" - "${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json" - COPYONLY) -endif() -if (ENABLE_COMPATIBILITY_LIST_DOWNLOAD AND NOT EXISTS ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json) - message(STATUS "Downloading compatibility list for citron...") - file(DOWNLOAD - https://api.yuzu-citron-emu.org/gamedb/ - "${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json" SHOW_PROGRESS) -endif() -if (NOT EXISTS ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json) - file(WRITE ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json "") -endif() - -# Detect current compilation architecture and create standard definitions -# ======================================================================= - -include(CheckSymbolExists) -function(detect_architecture symbol arch) - if (NOT DEFINED ARCHITECTURE) - set(CMAKE_REQUIRED_QUIET 1) - check_symbol_exists("${symbol}" "" ARCHITECTURE_${arch}) - unset(CMAKE_REQUIRED_QUIET) - - # The output variable needs to be unique across invocations otherwise - # CMake's crazy scope rules will keep it defined - if (ARCHITECTURE_${arch}) - set(ARCHITECTURE "${arch}" PARENT_SCOPE) - set(ARCHITECTURE_${arch} 1 PARENT_SCOPE) - add_definitions(-DARCHITECTURE_${arch}=1) - endif() - endif() -endfunction() - -if (NOT ENABLE_GENERIC) - if (MSVC) - detect_architecture("_M_AMD64" x86_64) - detect_architecture("_M_IX86" x86) - detect_architecture("_M_ARM" arm) - detect_architecture("_M_ARM64" arm64) - else() - detect_architecture("__x86_64__" x86_64) - detect_architecture("__i386__" x86) - detect_architecture("__arm__" arm) - detect_architecture("__aarch64__" arm64) - endif() -endif() - -if (NOT DEFINED ARCHITECTURE) - set(ARCHITECTURE "GENERIC") - set(ARCHITECTURE_GENERIC 1) - add_definitions(-DARCHITECTURE_GENERIC=1) -endif() -message(STATUS "Target architecture: ${ARCHITECTURE}") - -if (ARCHITECTURE_arm64 AND (ANDROID OR ${CMAKE_SYSTEM_NAME} STREQUAL "Linux")) - set(HAS_NCE 1) - add_definitions(-DHAS_NCE=1) -endif() - -# Configure C++ standard -# =========================== - -# boost asio's concept usage doesn't play nicely with some compilers yet. -add_definitions(-DBOOST_ASIO_DISABLE_CONCEPTS) -if (MSVC) - add_compile_options($<$:/std:c++20>) - - # boost still makes use of deprecated result_of. - add_definitions(-D_HAS_DEPRECATED_RESULT_OF) - - # Enable Link Time Code Generation when PGO or LTO is active. - # Without /GL on compilation units, /LTCG has no effect and slows linking. - if(CITRON_ENABLE_PGO_GENERATE OR CITRON_ENABLE_PGO_USE OR CITRON_ENABLE_LTO) - add_link_options(/LTCG) - endif() + target_compile_options(audio_core PRIVATE + /we4242 # 'identifier': conversion from 'type1' to 'type2', possible loss of data + /we4244 # 'conversion': conversion from 'type1' to 'type2', possible loss of data + /we4245 # 'conversion': conversion from 'type1' to 'type2', signed/unsigned mismatch + /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data + /we4800 # Implicit conversion from 'type' to bool. Possible information loss + /wd2375 # Disable C2375: '__builtin_assume_aligned': redefinition (MSVC 14.44+ issue) + ) else() - set(CMAKE_CXX_STANDARD 20) - set(CMAKE_CXX_STANDARD_REQUIRED ON) + target_compile_options(audio_core PRIVATE + -Werror=conversion + + -Wno-sign-conversion + ) endif() -# Output binaries to bin/ -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) - -if (CITRON_USE_CPM AND CITRON_USE_BUNDLED_QT AND CMAKE_SYSTEM_NAME STREQUAL "Linux") - # Build-tree binaries are the portable deliverable for local Linux CPM builds. - # Keep their loader search path relative to bin/ instead of embedding Qt or - # dependency cache directories from the build host. - set(CMAKE_BUILD_RPATH "$ORIGIN/lib") - set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") - set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) - add_link_options("-Wl,--disable-new-dtags") +target_link_libraries(audio_core PUBLIC common core Opus::opus) +if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) + target_link_libraries(audio_core PRIVATE dynarmic::dynarmic) endif() -# System imported libraries -# ======================================================================= - -# ── CPM (Clangtron / cross-compile builds) ─────────────────────────────────── -# When CITRON_USE_CPM is ON, fetch all dependencies via CPM.cmake at configure -# time instead of requiring git submodules or vcpkg. This must run BEFORE -# find_package() calls so CPM-created targets and Find modules are available. -# Gated behind an option so MSVC/Linux/macOS/Android builds are unaffected. -if (CITRON_USE_CPM) - # Disable vcpkg manifest auto-install — CPM provides all packages - set(VCPKG_MANIFEST_MODE OFF CACHE BOOL "" FORCE) - set(CPM_SOURCE_CACHE "${CMAKE_BINARY_DIR}/_cpm_cache" - CACHE PATH "CPM download cache — point to a shared directory on CI") - option(CPM_USE_LOCAL_PACKAGES "Prefer system find_package over CPM fetch" OFF) - include(${CMAKE_SOURCE_DIR}/CMakeModules/CPM.cmake) - include(${CMAKE_SOURCE_DIR}/CMakeModules/dependencies.cmake) -endif() - -# Enforce the search mode of non-required packages for better and shorter failure messages - -# Find Boost and its components. -# 'process' is optional. The build will continue if it's not found. -if (NOT TARGET Boost::context) - find_package(Boost 1.79.0 REQUIRED COMPONENTS context OPTIONAL_COMPONENTS process) -elseif (TARGET Boost::process) - set(Boost_PROCESS_FOUND TRUE) -else() - set(Boost_PROCESS_FOUND FALSE) -endif() - -# Check if the optional 'process' component was successfully found. -if(Boost_PROCESS_FOUND) - # Note: We'll set this definition later when the core target is created - set(HAS_BOOST_PROCESS_DEFINITION "HAS_BOOST_PROCESS") - message(STATUS "Found optional Boost.Process, enabling advanced debugger pipe.") -else() - # It was not found. This is not an error. - message(STATUS "Optional Boost.Process not found, using socket-based debugger pipe.") -endif() - -# Find the Boost package with our dynamically built list of required components. -if (NOT TARGET Boost::context) - find_package(Boost 1.79.0 REQUIRED ${BOOST_COMPONENTS}) -endif() -if (NOT TARGET enet::enet) - find_package(enet 1.3 MODULE) -endif() -if (NOT TARGET fmt::fmt) - find_package(fmt 9 REQUIRED) -endif() -if (NOT TARGET LLVM::Demangle) - find_package(LLVM 17.0.2 MODULE COMPONENTS Demangle) -endif() -if (NOT TARGET lz4::lz4) - find_package(lz4 REQUIRED) -endif() -if (NOT TARGET nlohmann_json::nlohmann_json) - find_package(nlohmann_json 3.8 REQUIRED) -endif() -if (NOT TARGET Opus::opus) - find_package(Opus 1.3 MODULE) -endif() -find_package(RenderDoc MODULE) -find_package(stb MODULE) -if (NOT TARGET GPUOpen::VulkanMemoryAllocator) - find_package(VulkanMemoryAllocator CONFIG) -endif() -if (NOT TARGET ZLIB::ZLIB) - if (WIN32) - set(ZLIB_USE_STATIC_LIBS ON) - endif() - find_package(ZLIB 1.2 REQUIRED) -endif() -if (NOT TARGET zstd::zstd) - find_package(zstd 1.5 REQUIRED) -endif() - -if (NOT CITRON_USE_EXTERNAL_VULKAN_HEADERS) - find_package(VulkanHeaders 1.3.274 REQUIRED) -endif() - -if (NOT CITRON_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES) - find_package(VulkanUtilityLibraries REQUIRED) -endif() - -if (ENABLE_LIBUSB AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") - find_package(libusb 1.0.24 MODULE) -endif() - -if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) - if (NOT TARGET xbyak::xbyak) - find_package(xbyak 6 CONFIG) - endif() -endif() - -if (ARCHITECTURE_arm64) - if (NOT TARGET merry::oaknut) - find_package(oaknut 2.0.1 CONFIG) - endif() -endif() - -# We create a variable to remember if dynarmic was found -set(CITRON_HAS_DYNARMIC FALSE) - -if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) AND NOT (MSVC AND ARCHITECTURE_arm64)) - if (TARGET dynarmic::dynarmic) - set(dynarmic_FOUND TRUE) - else() - find_package(dynarmic 6.4.0 CONFIG) - endif() - if (dynarmic_FOUND) - message(STATUS "Dynarmic found, enabling dynamic recompilation support.") - set(CITRON_HAS_DYNARMIC TRUE) # Set our variable to TRUE - else() - message(STATUS "Dynarmic not found or disabled for this architecture, skipping.") - endif() -endif() +citron_configure_lto(audio_core) if (ENABLE_CUBEB) - if (NOT TARGET cubeb::cubeb) - find_package(cubeb CONFIG) - endif() -endif() - -if (USE_DISCORD_PRESENCE) - find_package(DiscordRPC MODULE) -endif() - -if (ENABLE_WEB_SERVICE) - if (NOT TARGET cpp-jwt::cpp-jwt) - find_package(cpp-jwt 1.4 CONFIG) - endif() - if (NOT TARGET httplib::httplib) - find_package(httplib 0.12 MODULE COMPONENTS OpenSSL) - endif() -endif() - -if (CITRON_TESTS) - find_package(Catch2 3.0.1 REQUIRED) -endif() - -# boost:asio has functions that require AcceptEx et al -if (MINGW) - find_library(MSWSOCK_LIBRARY mswsock REQUIRED) -endif() - -if(ENABLE_OPENSSL) - if (NOT (TARGET OpenSSL::SSL AND TARGET OpenSSL::Crypto)) - find_package(OpenSSL 1.1.1 REQUIRED) - endif() -endif() - -if (UNIX AND NOT APPLE) - find_package(gamemode 1.7 MODULE) -endif() - -# CPM dependencies are loaded above (before find_package calls). - -add_subdirectory(externals) -# When CPM is ON, discord-rpc and dynarmic/mcl patches are applied post-populate -# inside CMakeModules/dependencies.cmake. Skip the submodule-path patches. -if(USE_DISCORD_PRESENCE AND NOT CITRON_USE_CPM) - message(STATUS "Applying custom patch to submodule's rapidjson for Discord presence...") - - # Define the path to the patch file and the target directory - set(PATCH_FILE "${CMAKE_CURRENT_SOURCE_DIR}/patches/rapidjson-compiler-fix.patch") - set(PATCH_TARGET_DIR "${CMAKE_CURRENT_SOURCE_DIR}/externals/discord-rpc/thirdparty/rapidjson-1.1.0") - - # Check if the target directory exists before trying to patch - if(EXISTS "${PATCH_TARGET_DIR}") - execute_process( - COMMAND git apply --ignore-whitespace "${PATCH_FILE}" - WORKING_DIRECTORY "${PATCH_TARGET_DIR}" - RESULT_VARIABLE PATCH_RESULT - OUTPUT_QUIET - ERROR_QUIET - ) - - if(NOT PATCH_RESULT EQUAL 0) - message(WARNING "Failed to apply rapidjson compiler fix patch! This might be okay if it's already applied.") - endif() - else() - message(WARNING "Could not find rapidjson directory to patch. It may not have been downloaded yet.") - endif() -endif() - -if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT CITRON_USE_CPM) - message(STATUS "Applying custom patch to submodule's mcl for Clang compatibility...") - - set(MCL_PATCH_FILE "${CMAKE_CURRENT_SOURCE_DIR}/patches/mcl_clang_template_fix.patch") - set(MCL_PATCH_TARGET_DIR "${CMAKE_CURRENT_SOURCE_DIR}/externals/dynarmic/externals/mcl") - - if(EXISTS "${MCL_PATCH_TARGET_DIR}") - execute_process( - COMMAND git apply --ignore-whitespace "${MCL_PATCH_FILE}" - WORKING_DIRECTORY "${MCL_PATCH_TARGET_DIR}" - RESULT_VARIABLE MCL_PATCH_RESULT - OUTPUT_QUIET - ERROR_QUIET - ) - - if(NOT MCL_PATCH_RESULT EQUAL 0) - message(WARNING "Failed to apply mcl Clang compatibility patch! This might be okay if it's already applied.") - endif() - else() - message(WARNING "Could not find mcl directory to patch. It may not have been downloaded yet.") - endif() -endif() - -# Apply a patch to stb_image.h to fix a string overflow warning with modern compilers -message(STATUS "Applying custom patch to stb_image.h...") - -set(STB_PATCH_FILE "${CMAKE_CURRENT_SOURCE_DIR}/patches/stb_image-overflow-fix.patch") - -set(STB_PATCH_WORKING_DIR "${CMAKE_CURRENT_SOURCE_DIR}") - -# Check if the file to be patched exists before trying to patch -if(EXISTS "${STB_PATCH_WORKING_DIR}/externals/stb/stb_image.h") - execute_process( - COMMAND git apply -p0 --ignore-whitespace "${STB_PATCH_FILE}" - WORKING_DIRECTORY "${STB_PATCH_WORKING_DIR}" - RESULT_VARIABLE PATCH_RESULT - OUTPUT_QUIET - ERROR_QUIET + target_sources(audio_core PRIVATE + sink/cubeb_sink.cpp + sink/cubeb_sink.h ) - if(NOT PATCH_RESULT EQUAL 0) - message(WARNING "Failed to apply stb_image.h compiler fix patch! This might be okay if it's already applied.") - endif() -else() - message(WARNING "Could not find stb_image.h to patch. It may not have been downloaded yet.") + target_link_libraries(audio_core PRIVATE cubeb::cubeb) + target_compile_definitions(audio_core PRIVATE -DHAVE_CUBEB=1) endif() -# Apply a patch to discord-rpc's CMakeLists.txt to suppress -Wclass-memaccess -# (skipped when CPM is ON — patches applied in CMakeModules/dependencies.cmake) -if(NOT CITRON_USE_CPM) - message(STATUS "Applying custom patch to submodule's discord-rpc CMakeLists.txt...") - - # Define the path to the patch file and the target directory using unique names - set(DISCORD_RPC_PATCH_FILE "${CMAKE_CURRENT_SOURCE_DIR}/patches/discord-rpc-wclass-memaccess-fix.patch") - set(DISCORD_RPC_PATCH_TARGET_DIR "${CMAKE_CURRENT_SOURCE_DIR}/externals/discord-rpc") - - # Check if the target directory exists before trying to patch - if(EXISTS "${DISCORD_RPC_PATCH_TARGET_DIR}") - execute_process( - COMMAND git apply -p0 --ignore-whitespace "${DISCORD_RPC_PATCH_FILE}" - WORKING_DIRECTORY "${DISCORD_RPC_PATCH_TARGET_DIR}" - RESULT_VARIABLE PATCH_RESULT - OUTPUT_QUIET - ERROR_QUIET - ) - - if(NOT PATCH_RESULT EQUAL 0) - message(WARNING "Failed to apply discord-rpc CMakeLists.txt patch! This might be okay if it's already applied.") - endif() - else() - message(WARNING "Could not find discord-rpc directory to patch. It may not have been downloaded yet.") - endif() -endif() - -if (ENABLE_QT AND NOT CITRON_USE_CPM) - if (NOT USE_SYSTEM_QT) - download_qt(6.9.3) - endif() - - if (NOT DEFINED QT_TARGET_PATH) - # Try to find Qt6 installation path (aqtinstall layout: externals/qt//) - # We prioritize llvm-mingw_64 for Clang builds to ensure libc++ compatibility. - if (EXISTS "${CMAKE_BINARY_DIR}/externals/qt/6.9.3/llvm-mingw_64") - set(QT_TARGET_PATH "${CMAKE_BINARY_DIR}/externals/qt/6.9.3/llvm-mingw_64" CACHE PATH "Path to Qt6" FORCE) - elseif (EXISTS "${CMAKE_BINARY_DIR}/externals/qt/6.9.3/mingw_64") - set(QT_TARGET_PATH "${CMAKE_BINARY_DIR}/externals/qt/6.9.3/mingw_64" CACHE PATH "Path to Qt6" FORCE) - elseif (EXISTS "${CMAKE_BINARY_DIR}/externals/qt/6.9.3/msvc2022_64") - set(QT_TARGET_PATH "${CMAKE_BINARY_DIR}/externals/qt/6.9.3/msvc2022_64" CACHE PATH "Path to Qt6" FORCE) - elseif (EXISTS "${CMAKE_BINARY_DIR}/externals/qt/6.9.3/msvc2022_arm64") - set(QT_TARGET_PATH "${CMAKE_BINARY_DIR}/externals/qt/6.9.3/msvc2022_arm64" CACHE PATH "Path to Qt6" FORCE) - elseif (EXISTS "${CMAKE_BINARY_DIR}/externals/qt/6.9.3/msvc2019_64") - set(QT_TARGET_PATH "${CMAKE_BINARY_DIR}/externals/qt/6.9.3/msvc2019_64" CACHE PATH "Path to Qt6" FORCE) - elseif (EXISTS "${CMAKE_BINARY_DIR}/externals/qt/6.8.3/llvm-mingw_64") - set(QT_TARGET_PATH "${CMAKE_BINARY_DIR}/externals/qt/6.8.3/llvm-mingw_64" CACHE PATH "Path to Qt6" FORCE) - elseif (EXISTS "${CMAKE_BINARY_DIR}/externals/qt/6.8.3/msvc2022_64") - set(QT_TARGET_PATH "${CMAKE_BINARY_DIR}/externals/qt/6.8.3/msvc2022_64" CACHE PATH "Path to Qt6" FORCE) - elseif (EXISTS "${CMAKE_BINARY_DIR}/externals/qt/6.8.3/msvc2019_64") - set(QT_TARGET_PATH "${CMAKE_BINARY_DIR}/externals/qt/6.8.3/msvc2019_64" CACHE PATH "Path to Qt6" FORCE) - elseif (EXISTS "${CMAKE_BINARY_DIR}/externals/qt/6.7.3/msvc2019_64") - set(QT_TARGET_PATH "${CMAKE_BINARY_DIR}/externals/qt/6.7.3/msvc2019_64" CACHE PATH "Path to Qt6" FORCE) - endif() - endif() - - if (QT_TARGET_PATH) - # Add Qt path to CMAKE_PREFIX_PATH BEFORE find_package so it's found first - list(APPEND CMAKE_PREFIX_PATH "${QT_TARGET_PATH}") - message(STATUS "Using target Qt at ${QT_TARGET_PATH}") - endif() - - if (NOT DEFINED QT_HOST_PATH) - set(QT_HOST_PATH "${QT_TARGET_PATH}") - endif() - if (QT_HOST_PATH) - message(STATUS "Using host Qt at ${QT_HOST_PATH}") - endif() - - find_package(Qt6 REQUIRED COMPONENTS Widgets Multimedia Concurrent) - - if (UNIX AND NOT APPLE) - find_package(Qt6 REQUIRED COMPONENTS DBus) - endif() - - if (ENABLE_QT_TRANSLATION) - find_package(Qt6 REQUIRED COMPONENTS LinguistTools) - endif() - - # Fallback detection if QT_TARGET_PATH was not found in common bundled locations - if (NOT QT_TARGET_PATH AND Qt6_DIR) - get_filename_component(_tmp_path "${Qt6_DIR}/../../.." ABSOLUTE) - set(QT_TARGET_PATH "${_tmp_path}" CACHE PATH "Path to Qt6" FORCE) - message(STATUS "Resolved QT_TARGET_PATH from Qt6_DIR: ${QT_TARGET_PATH}") - endif() - message(STATUS "Final QT_TARGET_PATH: ${QT_TARGET_PATH}") -endif() - -function(set_citron_qt_components) -# Best practice is to ask for all components at once, so they are from the same version -set(CITRON_QT_COMPONENTS2 Core Widgets Concurrent Network Svg) -if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") -list(APPEND CITRON_QT_COMPONENTS2 DBus GuiPrivate) -endif() -if (CITRON_USE_QT_MULTIMEDIA) -list(APPEND CITRON_QT_COMPONENTS2 Multimedia) - endif() - if (CITRON_USE_QT_WEB_ENGINE) - list(APPEND CITRON_QT_COMPONENTS2 WebEngineCore WebEngineWidgets) - endif() - if (ENABLE_QT_TRANSLATION) - list(APPEND CITRON_QT_COMPONENTS2 LinguistTools) - endif() - set(CITRON_QT_COMPONENTS ${CITRON_QT_COMPONENTS2} PARENT_SCOPE) - endfunction(set_citron_qt_components) - -# find SDL2 exports a bunch of variables that are needed, so its easier to do this outside of the citron_find_package if (ENABLE_SDL2) - if (CITRON_USE_BUNDLED_SDL2) - # Detect toolchain and platform - if (MSVC_VERSION GREATER_EQUAL 1920 AND ARCHITECTURE_x86_64) - set(SDL2_VER "SDL2-2.28.2") - set(SDL2_ARCH_DIR "x64") - elseif (MSVC_VERSION GREATER_EQUAL 1920 AND ARCHITECTURE_arm64) - set(SDL2_VER "SDL2-2.28.2") - set(SDL2_ARCH_DIR "arm64") - else() - message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable CITRON_USE_BUNDLED_SDL2 and provide your own.") - endif() - - if (DEFINED SDL2_VER) - download_bundled_external("sdl2/" ${SDL2_VER} SDL2_PREFIX) - endif() - - set(SDL2_FOUND YES) - set(SDL2_INCLUDE_DIR "${SDL2_PREFIX}/include" CACHE PATH "Path to SDL2 headers") - set(SDL2_LIBRARY "${SDL2_PREFIX}/lib/${SDL2_ARCH_DIR}/SDL2.lib" CACHE PATH "Path to SDL2 library") - set(SDL2MAIN_LIBRARY "${SDL2_PREFIX}/lib/${SDL2_ARCH_DIR}/SDL2main.lib" CACHE PATH "Path to SDL2main library") - set(SDL2_DLL_DIR "${SDL2_PREFIX}/lib/${SDL2_ARCH_DIR}/" CACHE PATH "Path to SDL2.dll") - - add_library(SDL2::SDL2 INTERFACE IMPORTED) - target_link_libraries(SDL2::SDL2 INTERFACE "${SDL2_LIBRARY}" "${SDL2MAIN_LIBRARY}") - target_include_directories(SDL2::SDL2 INTERFACE "${SDL2_INCLUDE_DIR}") - elseif (CITRON_USE_EXTERNAL_SDL2) - message(STATUS "Using SDL2 from externals.") - else() - find_package(SDL2 2.26.4 REQUIRED) - endif() -endif() - -# List of all FFmpeg components required -set(FFmpeg_COMPONENTS - avfilter - swscale - avcodec - avutil) - -if (UNIX AND NOT APPLE AND NOT ANDROID) - find_package(PkgConfig REQUIRED) - pkg_check_modules(LIBVA libva) -endif() -if (NOT CITRON_USE_BUNDLED_FFMPEG) - # Use system installed FFmpeg - find_package(FFmpeg 4.3 REQUIRED QUIET COMPONENTS ${FFmpeg_COMPONENTS}) -endif() - -if(ENABLE_QT) - set_citron_qt_components() - find_package(Qt6 REQUIRED COMPONENTS ${CITRON_QT_COMPONENTS}) - set(QT_MAJOR_VERSION 6) - # Qt6 sets cxx_std_17 and we need to undo that - set_target_properties(Qt6::Platform PROPERTIES INTERFACE_COMPILE_FEATURES "") -endif() - -if (WIN32 AND CITRON_CRASH_DUMPS) - set(BREAKPAD_VER "breakpad-c89f9dd") - download_bundled_external("breakpad/" ${BREAKPAD_VER} BREAKPAD_PREFIX) - - set(BREAKPAD_CLIENT_INCLUDE_DIR "${BREAKPAD_PREFIX}/include") - set(BREAKPAD_CLIENT_LIBRARY "${BREAKPAD_PREFIX}/lib/libbreakpad_client.lib") - - add_library(libbreakpad_client INTERFACE IMPORTED) - target_link_libraries(libbreakpad_client INTERFACE "${BREAKPAD_CLIENT_LIBRARY}") - target_include_directories(libbreakpad_client INTERFACE "${BREAKPAD_CLIENT_INCLUDE_DIR}") -endif() - -# Prefer the -pthread flag on Linux. -set(THREADS_PREFER_PTHREAD_FLAG ON) -find_package(Threads REQUIRED) - -# Platform-specific library requirements -# ====================================== - -if (APPLE) - # Umbrella framework for everything GUI-related - find_library(COCOA_LIBRARY Cocoa) - set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY}) -elseif (WIN32) - # Target Windows 10 - add_definitions(-D_WIN32_WINNT=0x0A00 -DWINVER=0x0A00) - set(PLATFORM_LIBRARIES winmm ws2_32 iphlpapi ole32 shell32) - if (MINGW) - # PSAPI is the Process Status API - set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} uuid psapi imm32 version) - endif() -elseif (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU|SunOS)$") - set(PLATFORM_LIBRARIES rt) -endif() - -# Setup a custom clang-format target (if clang-format can be found) that will run -# against all the src files. This should be used before making a pull request. -# ======================================================================= - -set(CLANG_FORMAT_POSTFIX "-20") -find_program(CLANG_FORMAT - NAMES clang-format${CLANG_FORMAT_POSTFIX} - clang-format - PATHS ${PROJECT_BINARY_DIR}/externals) -# if find_program doesn't find it, try to download from externals -if (NOT CLANG_FORMAT) - if (WIN32 AND NOT CMAKE_CROSSCOMPILING) - message(STATUS "Clang format not found! Downloading...") - set(CLANG_FORMAT "${PROJECT_BINARY_DIR}/externals/clang-format${CLANG_FORMAT_POSTFIX}.exe") - file(DOWNLOAD - https://git.citron-emu.org/citron/ext-windows-bin/-/blob/master/clang-format${CLANG_FORMAT_POSTFIX}.exe - "${CLANG_FORMAT}" SHOW_PROGRESS - STATUS DOWNLOAD_SUCCESS) - if (NOT DOWNLOAD_SUCCESS EQUAL 0) - message(WARNING "Could not download clang format! Disabling the clang format target") - file(REMOVE ${CLANG_FORMAT}) - unset(CLANG_FORMAT) - endif() - else() - message(WARNING "Clang format not found! Disabling the clang format target") - endif() -endif() - -if (CLANG_FORMAT) - set(SRCS ${PROJECT_SOURCE_DIR}/src) - set(CCOMMENT "Running clang format against all the .h and .cpp files in src/") - if (WIN32) - add_custom_target(clang-format - COMMAND powershell.exe -Command "Get-ChildItem '${SRCS}/*' -Include *.cpp,*.h -Recurse | Foreach {&'${CLANG_FORMAT}' -i $_.fullname}" - COMMENT ${CCOMMENT}) - elseif(MINGW) - add_custom_target(clang-format - COMMAND find `cygpath -u ${SRCS}` -iname *.h -o -iname *.cpp | xargs `cygpath -u ${CLANG_FORMAT}` -i - COMMENT ${CCOMMENT}) - else() - add_custom_target(clang-format - COMMAND find ${SRCS} -iname *.h -o -iname *.cpp | xargs ${CLANG_FORMAT} -i - COMMENT ${CCOMMENT}) - endif() - unset(SRCS) - unset(CCOMMENT) -endif() - -# Include source code -# =================== - -# This function should be passed a list of all files in a target. It will automatically generate -# file groups following the directory hierarchy, so that the layout of the files in IDEs matches the -# one in the filesystem. -function(create_target_directory_groups target_name) - # Place any files that aren't in the source list in a separate group so that they don't get in - # the way. - source_group("Other Files" REGULAR_EXPRESSION ".") - - get_target_property(target_sources "${target_name}" SOURCES) - - foreach(file_name IN LISTS target_sources) - get_filename_component(dir_name "${file_name}" PATH) - # Group names use '\' as a separator even though the entire rest of CMake uses '/'... - string(REPLACE "/" "\\" group_name "${dir_name}") - source_group("${group_name}" FILES "${file_name}") - endforeach() -endfunction() - -# Helper function to configure LTO for a target with CachyOS-specific compatibility -function(citron_configure_lto target_name) - if (CITRON_ENABLE_LTO) - set_property(TARGET ${target_name} PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) - - # Detect CachyOS and apply conservative LTO settings only for CachyOS - set(IS_CACHYOS FALSE) - if (EXISTS "/etc/os-release") - file(READ "/etc/os-release" OS_RELEASE_CONTENT) - if (OS_RELEASE_CONTENT MATCHES "ID=cachyos") - set(IS_CACHYOS TRUE) - endif() - endif() - - # Alternative detection via kernel name - if (NOT IS_CACHYOS) - execute_process(COMMAND uname -r OUTPUT_VARIABLE KERNEL_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) - if (KERNEL_VERSION MATCHES "cachyos") - set(IS_CACHYOS TRUE) - endif() - endif() - - # Apply conservative LTO settings only for CachyOS with GCC 15+ - if (IS_CACHYOS AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "15.0") - message(STATUS "Detected CachyOS with GCC ${CMAKE_CXX_COMPILER_VERSION} - using conservative LTO settings for ${target_name}") - target_compile_options(${target_name} PRIVATE "-flto=auto" "-ffat-lto-objects") - target_link_options(${target_name} PRIVATE "-flto=auto" "-ffat-lto-objects") - endif() - endif() -endfunction() - -# Prevent boost from linking against libs when building -if(TARGET Boost::disable_autolinking) - get_target_property(_is_alias Boost::headers ALIASED_TARGET) - if(_is_alias) - target_link_libraries(${_is_alias} INTERFACE Boost::disable_autolinking) - else() - target_link_libraries(Boost::headers INTERFACE Boost::disable_autolinking) - endif() -endif() -# Adjustments for MSVC + Ninja -if (MSVC AND CMAKE_GENERATOR STREQUAL "Ninja") - add_compile_options( - /wd4464 # relative include path contains '..' - /wd4711 # function 'function' selected for automatic inline expansion - /wd4820 # 'bytes' bytes padding added after construct 'member_name' + target_sources(audio_core PRIVATE + sink/sdl2_sink.cpp + sink/sdl2_sink.h ) + + target_link_libraries(audio_core PRIVATE SDL2::SDL2) + target_compile_definitions(audio_core PRIVATE HAVE_SDL2) endif() -if (NOT APPLE AND (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR (CITRON_USE_FASTER_LD AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU"))) - # We will assume that if the compiler is GCC, it will attempt to use ld.bfd by default. - # Try to pick a faster linker. - find_program(LLD lld) - find_program(MOLD mold) - - if (MOLD AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12.1") - message(NOTICE "Selecting mold as linker") - add_link_options("-fuse-ld=mold") - elseif (LLD) - message(NOTICE "Selecting lld as linker") - add_link_options("-fuse-ld=lld") - endif() -endif() - -# Set runtime library to MD/MDd for all configurations -if(MSVC) - set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") - - # Force all projects (including external dependencies) to use the same runtime - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd") - set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MD") - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MDd") - - # Add this to ensure Cubeb uses the same runtime - add_compile_options( - $<$:/MDd> - $<$:/MD> - $<$:/MD> - $<$:/MD> +if (ANDROID) + target_sources(audio_core PRIVATE + sink/oboe_sink.cpp + sink/oboe_sink.h ) + + # FIXME: this port seems broken, it cannot be imported with find_package(oboe REQUIRED) + target_link_libraries(audio_core PRIVATE "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib/liboboe.a") + target_compile_definitions(audio_core PRIVATE HAVE_OBOE) endif() -add_subdirectory(src) - -# Add the compile definition for Dynarmic -if(CITRON_HAS_DYNARMIC) # This variable is set by the find_package call at the top - target_compile_definitions(core PRIVATE USE_DYNARMIC) +if (CITRON_USE_PRECOMPILED_HEADERS) + target_precompile_headers(audio_core PRIVATE precompiled_headers.h) endif() -# Apply the Boost.Process definition to the core target if it was found -if(DEFINED HAS_BOOST_PROCESS_DEFINITION) - target_compile_definitions(core PRIVATE ${HAS_BOOST_PROCESS_DEFINITION}) -endif() - -# Apply PGO configuration to main targets -if(CITRON_ENABLE_PGO_GENERATE OR CITRON_ENABLE_PGO_USE) - if(TARGET citron) - citron_configure_pgo(citron) - endif() - if(TARGET citron-cmd) - citron_configure_pgo(citron-cmd) - endif() - if(TARGET citron-room) - citron_configure_pgo(citron-room) - endif() - - # Print PGO instructions - citron_print_pgo_instructions() -endif() - -# Set citron project or citron-cmd project as default StartUp Project in Visual Studio depending on whether QT is enabled or not -if(ENABLE_QT) - set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT citron) -else() - set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT citron-cmd) -endif() - - -# Installation instructions -# ========================= - -# Install freedesktop.org metadata files, following those specifications: -# https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html -# https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html -# https://specifications.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html -# https://www.freedesktop.org/software/appstream/docs/ -if(ENABLE_QT AND UNIX AND NOT APPLE) - install(FILES "dist/org.citron_emu.citron.desktop" - DESTINATION "share/applications") - install(FILES "dist/citron.svg" - DESTINATION "share/icons/hicolor/scalable/apps" - RENAME "org.citron_emu.citron.svg") - install(FILES "dist/org.citron_emu.citron.xml" - DESTINATION "share/mime/packages") - install(FILES "dist/org.citron_emu.citron.metainfo.xml" - DESTINATION "share/metainfo") -endif() - -# Final linker cleanup for Clang LTO. -# This forcefully removes any stray "-fuse-ld=bfd" flags that may have been -# incorrectly added by other parts of the build system. -if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CITRON_ENABLE_LTO) - message(STATUS "Performing final linker flag cleanup for Clang LTO...") - foreach(target citron citron-cmd citron-room) - if(TARGET ${target}) - get_target_property(link_options ${target} LINK_OPTIONS) - if(link_options) - string(REPLACE "-fuse-ld=bfd" "" link_options "${link_options}") - set_target_properties(${target} PROPERTIES LINK_OPTIONS "${link_options}") - endif() - endif() - endforeach() -endif() -# Generate AppImage build configuration -if (UNIX AND NOT APPLE) - configure_file( - "${CMAKE_CURRENT_SOURCE_DIR}/AppImageBuilder/config.sh.in" - "${CMAKE_CURRENT_BINARY_DIR}/AppImageBuilder/config.sh" - @ONLY - ) -endif() +create_target_directory_groups(audio_core)