cmake_minimum_required(VERSION 3.20)

# Automobili Lamborghini: Recompiled - a static-recompilation PC port built on
# N64ModernRuntime (ultramodern + librecomp) with the RT64 renderer.
#
# See BUILDING.md for the supported build sequence. In short:
#
#   # 1. Recompile the game code from YOUR ROM (produces RecompiledFuncs/):
#   python3 scripts/gen_syms_toml.py
#   ./lib/N64ModernRuntime/librecomp/N64Recomp/N64Recomp lamborghini.us.toml
#
#   # 2. Configure + build (Linux example; MinGW/Windows details in BUILDING.md):
#   cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
#   cmake --build build --target lamborghini_modern -j
#
# The ROM path in lamborghini.us.toml is cwd-relative. The patch matrix is in
# patches/README.md. RecompiledFuncs/ is regenerated from the supplied ROM.

project(lamborghini_modern VERSION 0.11.0 LANGUAGES C CXX)

# Python applies the dependency patches and generates mod and test inputs.
find_program(LAMBO_PYTHON_EXECUTABLE NAMES python python3 REQUIRED)
execute_process(COMMAND ${LAMBO_PYTHON_EXECUTABLE} -c
    "import sys; sys.exit(0 if sys.version_info >= (3, 11) else 1)"
    RESULT_VARIABLE LAMBO_PYTHON_VERSION_RESULT)
if(NOT LAMBO_PYTHON_VERSION_RESULT EQUAL 0)
    message(FATAL_ERROR "Python 3.11 or newer is required; set LAMBO_PYTHON_EXECUTABLE")
endif()
include(cmake/Patches.cmake)

if(ANDROID)
    include(cmake/Android.cmake)
endif()

include(CTest)
# RT64 vendors zstd, whose long-running upstream tests otherwise inherit
# BUILD_TESTING=ON. Keep the port's default suite focused on its own tests;
# dependency maintainers can still opt in with -DZSTD_BUILD_TESTS=ON.
option(ZSTD_BUILD_TESTS "Build the vendored zstd test suite" OFF)
find_package(Threads REQUIRED)

set(CMAKE_C_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

set(N64MR ${CMAKE_CURRENT_SOURCE_DIR}/lib/N64ModernRuntime)

# --- RT64 renderer boundary; see patches/README.md ---
# recomp/lib/rt64 is a pinned git submodule; RT64 is always compiled in and is the
# default presenter at runtime (LAMBO_HEADLESS=1 is the harness knob that keeps the
# headless swrender, the RDRAM-framebuffer measurement instrument for the port-vs-ares
# harness). Wiring mirrors Zelda64Recomp's CMakeLists.txt (the de-facto template).
if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/lib/rt64/CMakeLists.txt)
    message(FATAL_ERROR "lib/rt64 submodule is missing. Initialise it first:\n"
        "  git submodule update --init --recursive")
endif()

if(BUILD_TESTING)
    add_executable(lambo_rain_tests tests/test_rain.cpp src/lambo_rain.cpp)
    target_include_directories(lambo_rain_tests PRIVATE src tests lib/rt64/include)
    add_test(NAME lambo_rain_geometry COMMAND lambo_rain_tests)
    add_executable(lambo_rain_runtime_tests tests/test_rain_runtime.cpp
        src/lambo_rain.cpp src/lambo_rain_runtime.cpp src/lambo_mod_gameplay.cpp)
    target_include_directories(lambo_rain_runtime_tests PRIVATE src tests lib/rt64/include
        ${N64MR}/N64Recomp/include ${N64MR}/librecomp/include
        ${N64MR}/ultramodern/include ${N64MR}/thirdparty)
    add_test(NAME lambo_rain_producers COMMAND lambo_rain_runtime_tests)
    add_executable(lambo_rain_benchmark EXCLUDE_FROM_ALL tests/benchmark_rain.cpp
        src/lambo_rain.cpp src/lambo_rain_runtime.cpp src/lambo_mod_gameplay.cpp)
    target_include_directories(lambo_rain_benchmark PRIVATE src tests lib/rt64/include
        ${N64MR}/N64Recomp/include ${N64MR}/librecomp/include
        ${N64MR}/ultramodern/include ${N64MR}/thirdparty)
    target_compile_options(lambo_rain_benchmark PRIVATE -O2)
    add_executable(lambo_hud_hash_padding_tests tests/test_hud_hash_padding.cpp)
    target_include_directories(lambo_hud_hash_padding_tests PRIVATE
        lib/rt64/src lib/rt64/src/contrib)
    add_test(NAME lambo_hud_hash_padding COMMAND lambo_hud_hash_padding_tests)
    add_executable(lambo_hud_texture_walk_tests tests/test_hud_texture_walk.cpp
        src/lambo_graphics_task.cpp src/lambo_hud_texture_bounds.cpp src/lambo_fog_widescreen.cpp)
    target_include_directories(lambo_hud_texture_walk_tests PRIVATE src
        ${N64MR}/ultramodern/include ${N64MR}/thirdparty)
    add_test(NAME lambo_hud_texture_walk COMMAND lambo_hud_texture_walk_tests)
    add_executable(lambo_fog_benchmark EXCLUDE_FROM_ALL
        tests/benchmark_fog.cpp src/lambo_fog_widescreen.cpp)
    target_include_directories(lambo_fog_benchmark PRIVATE src
        ${N64MR}/ultramodern/include ${N64MR}/thirdparty)
    add_executable(lambo_hud_savestate_tests tests/test_hud_savestate.cpp
        src/lambo_graphics_task.cpp src/lambo_hud_texture_bounds.cpp
        src/lambo_fog_widescreen.cpp src/lambo_savestate.c
        src/lambo_savestate_io.cpp)
    target_include_directories(lambo_hud_savestate_tests PRIVATE src
        ${N64MR}/N64Recomp/include ${N64MR}/ultramodern/include ${N64MR}/thirdparty)
    target_compile_definitions(lambo_hud_savestate_tests PRIVATE
        LAMBO_SAVESTATE_IO_TESTING=1)
    target_link_libraries(lambo_hud_savestate_tests PRIVATE Threads::Threads)


    add_executable(lambo_mod_api_tests tests/test_mod_api.cpp src/lambo_mod_api.cpp)
    target_include_directories(lambo_mod_api_tests PRIVATE src
        ${N64MR}/N64Recomp/include ${N64MR}/librecomp/include ${N64MR}/ultramodern/include)
    add_test(NAME lambo_mod_logging COMMAND lambo_mod_api_tests)

    add_executable(lambo_mod_game_tests tests/test_mod_game.cpp tests/mod_data_symbol_writer.cpp
        src/lambo_mod_game.cpp src/lambo_mod_storage.cpp)
    target_include_directories(lambo_mod_game_tests PRIVATE src include
        ${N64MR}/N64Recomp/include ${N64MR}/librecomp/include
        ${N64MR}/ultramodern/include ${N64MR}/thirdparty)
    add_test(NAME lambo_mod_game_api COMMAND lambo_mod_game_tests)
    target_compile_options(lambo_mod_game_tests PRIVATE -O2)

    add_library(lambo_mod_native_smoke SHARED tests/mods/smoke/native.cpp)
    target_include_directories(lambo_mod_native_smoke PRIVATE ${N64MR}/N64Recomp/include)
    set_target_properties(lambo_mod_native_smoke PROPERTIES PREFIX ""
        ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/mod-smoke
        RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/mod-smoke
        LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/mod-smoke)
    add_library(lambo_mod_native_bad_api SHARED tests/mods/smoke/native.cpp)
    target_include_directories(lambo_mod_native_bad_api PRIVATE ${N64MR}/N64Recomp/include)
    target_compile_definitions(lambo_mod_native_bad_api PRIVATE LAMBO_SMOKE_API_VERSION=999)
    set_target_properties(lambo_mod_native_bad_api PROPERTIES PREFIX ""
        OUTPUT_NAME lambo_mod_native_smoke
        ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/mod-smoke/bad-api
        RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/mod-smoke/bad-api
        LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/mod-smoke/bad-api)
    add_executable(lambo_mod_gameplay_tests tests/test_mod_gameplay.cpp src/lambo_mod_gameplay.cpp)
    target_include_directories(lambo_mod_gameplay_tests PRIVATE src
        ${N64MR}/N64Recomp/include ${N64MR}/librecomp/include ${N64MR}/ultramodern/include)
    add_test(NAME lambo_mod_gameplay_bridge COMMAND lambo_mod_gameplay_tests)

    add_executable(lambo_vi_context_tests tests/test_vi_context.cpp src/lambo_vi.cpp)
    target_include_directories(lambo_vi_context_tests PRIVATE src)
    add_test(NAME lambo_vi_context COMMAND lambo_vi_context_tests)

    add_executable(lambo_rt_sun_tests tests/test_rt_sun.cpp
        src/lambo_rt_shadows.cpp src/lambo_log.cpp)
    target_include_directories(lambo_rt_sun_tests PRIVATE src lib/rt64/src)
    target_link_libraries(lambo_rt_sun_tests PRIVATE Threads::Threads)
    add_test(NAME lambo_rt_sun_tasks COMMAND lambo_rt_sun_tests)
    add_test(NAME lambo_rt_sun_tasks_no_capture COMMAND lambo_rt_sun_tests --no-capture)
    add_executable(lambo_rt_production_logging_tests tests/test_rt_production_logging.cpp
        src/lambo_rt_production.cpp)
    target_include_directories(lambo_rt_production_logging_tests PRIVATE src lib/rt64/include
        lib/rt64/src lib/rt64/src/contrib lib/rt64/src/contrib/hlslpp/include
        lib/rt64/src/contrib/plume lib/rt64/src/contrib/imgui)
    target_link_libraries(lambo_rt_production_logging_tests PRIVATE Threads::Threads)
    add_test(NAME lambo_rt_production_logging COMMAND lambo_rt_production_logging_tests)
    add_executable(lambo_rt_material_tests tests/test_rt_material.cpp)
    target_include_directories(lambo_rt_material_tests PRIVATE src)
    add_test(NAME lambo_rt_material_policy COMMAND lambo_rt_material_tests)
    add_executable(lambo_rt_admission_tests tests/test_rt_admission.cpp
        src/lambo_rt_admission.cpp src/lambo_rt_shadows.cpp src/lambo_log.cpp)
    target_include_directories(lambo_rt_admission_tests PRIVATE src lib/rt64/src)
    target_link_libraries(lambo_rt_admission_tests PRIVATE Threads::Threads)
    add_test(NAME lambo_rt_admission_policy COMMAND lambo_rt_admission_tests)
    add_executable(lambo_rt_shadow_cache_tests tests/test_rt_shadow_cache.cpp
        lib/rt64/src/render/rt64_sun_shadow_cache.cpp)
    target_include_directories(lambo_rt_shadow_cache_tests PRIVATE lib/rt64/src)
    add_test(NAME lambo_rt_shadow_cache COMMAND lambo_rt_shadow_cache_tests)
    add_executable(lambo_rt_lap_window_tests tests/test_rt_lap_window.cpp)
    target_include_directories(lambo_rt_lap_window_tests PRIVATE src)
    add_test(NAME lambo_rt_lap_window COMMAND lambo_rt_lap_window_tests)
    add_executable(lambo_rt_binding_tests tests/test_rt_binding.cpp)
    target_include_directories(lambo_rt_binding_tests PRIVATE src)
    add_test(NAME lambo_rt_workload_binding COMMAND lambo_rt_binding_tests)

    add_executable(lambo_rt_evidence_scope_tests tests/test_rt_evidence_scope.cpp
        lib/rt64/src/rhi/rt64_render_hooks.cpp)
    target_include_directories(lambo_rt_evidence_scope_tests PRIVATE
        lib/rt64/src lib/rt64/src/contrib/plume)
    target_link_libraries(lambo_rt_evidence_scope_tests PRIVATE Threads::Threads)
    add_test(NAME lambo_rt_evidence_scope COMMAND lambo_rt_evidence_scope_tests)

    # Links the production lambo_mods.cpp against test fakes for the runtime
    # mod API (tests/fakes); production builds use the submodule headers.
    add_executable(lambo_mods_rtz_tests tests/test_mods_rtz.cpp src/lambo_mods.cpp src/lambo_mod_gameplay.cpp)
    target_include_directories(lambo_mods_rtz_tests PRIVATE src tests/fakes
        ${N64MR}/N64Recomp/include ${N64MR}/librecomp/include ${N64MR}/ultramodern/include)
    target_link_libraries(lambo_mods_rtz_tests PRIVATE Threads::Threads)
    add_test(NAME lambo_mods_rtz_container COMMAND lambo_mods_rtz_tests)

    # Window-free: the driver tests stub sys.platform and ctypes.WinDLL, so
    # this runs wherever python does, matching unittest discovery. Gating it
    # on WIN32 would silently drop it from the Linux CTest run.
    add_test(NAME lambo_drive_input
        COMMAND ${LAMBO_PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_drive_input.py)
    set(MOD_MENU_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/lib/RecompFrontend/recompui/src/composites/ui_mod_menu.cpp)
    add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mod_menu_refresh_methods.inl
        COMMAND ${LAMBO_PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tests/extract_mod_menu_methods.py
            ${MOD_MENU_SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/mod_menu_refresh_methods.inl
        DEPENDS tests/extract_mod_menu_methods.py ${MOD_MENU_SOURCE}
        VERBATIM)
    add_executable(lambo_mod_menu_refresh_tests tests/test_mod_menu_refresh.cpp
        ${CMAKE_CURRENT_BINARY_DIR}/mod_menu_refresh_methods.inl)
    target_include_directories(lambo_mod_menu_refresh_tests PRIVATE
        ${CMAKE_CURRENT_BINARY_DIR} ${N64MR}/N64Recomp/include
        $<TARGET_PROPERTY:librecomp,INTERFACE_INCLUDE_DIRECTORIES>
        $<TARGET_PROPERTY:miniz,INTERFACE_INCLUDE_DIRECTORIES>)
    target_compile_definitions(lambo_mod_menu_refresh_tests PRIVATE NOMINMAX MINIZ_STATIC_DEFINE)
    add_test(NAME lambo_mod_menu_refresh COMMAND lambo_mod_menu_refresh_tests)

    if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/RecompiledFuncs/funcs.h")
        file(GLOB ROM_RECOMP_SOURCES CONFIGURE_DEPENDS RecompiledFuncs/funcs_*.c)
        add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/player_record_funcs.c
            COMMAND ${LAMBO_PYTHON_EXECUTABLE}
                ${CMAKE_CURRENT_SOURCE_DIR}/tests/extract_player_record_funcs.py
                ${CMAKE_CURRENT_SOURCE_DIR}/RecompiledFuncs
                ${CMAKE_CURRENT_BINARY_DIR}/player_record_funcs.c
            DEPENDS tests/extract_player_record_funcs.py ${ROM_RECOMP_SOURCES}
            VERBATIM)
        add_executable(lambo_player_records_tests
            tests/test_player_records.cpp
            ${CMAKE_CURRENT_BINARY_DIR}/player_record_funcs.c
            src/lambo_player_name.cpp src/lambo_log.cpp)
        target_include_directories(lambo_player_records_tests PRIVATE
            src RecompiledFuncs ${N64MR}/N64Recomp/include
            ${N64MR}/ultramodern/include ${N64MR}/thirdparty)
        target_link_libraries(lambo_player_records_tests PRIVATE Threads::Threads)
        add_test(NAME lambo_player_records COMMAND lambo_player_records_tests)
        add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/race_field_funcs.c
            COMMAND ${LAMBO_PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tests/extract_race_field_funcs.py
                ${CMAKE_CURRENT_SOURCE_DIR}/RecompiledFuncs ${CMAKE_CURRENT_BINARY_DIR}/race_field_funcs.c
            DEPENDS tests/extract_race_field_funcs.py ${ROM_RECOMP_SOURCES} VERBATIM)
        add_executable(lambo_race_field_tests tests/test_race_field.cpp tests/test_ai_speed_limits.cpp src/lambo_race_field.cpp
            ${CMAKE_CURRENT_BINARY_DIR}/race_field_funcs.c)
        target_include_directories(lambo_race_field_tests PRIVATE src RecompiledFuncs
            ${N64MR}/N64Recomp/include ${N64MR}/ultramodern/include ${N64MR}/thirdparty)
        add_test(NAME lambo_race_field COMMAND lambo_race_field_tests)


        add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/cheat_funcs.c
            COMMAND ${LAMBO_PYTHON_EXECUTABLE}
                ${CMAKE_CURRENT_SOURCE_DIR}/tests/extract_cheat_funcs.py
                ${CMAKE_CURRENT_SOURCE_DIR}/RecompiledFuncs
                ${CMAKE_CURRENT_BINARY_DIR}/cheat_funcs.c
            DEPENDS tests/extract_cheat_funcs.py ${ROM_RECOMP_SOURCES}
            VERBATIM)
        add_executable(lambo_cheat_tests tests/test_cheats.cpp
            ${CMAKE_CURRENT_BINARY_DIR}/cheat_funcs.c
            src/lambo_cheats.cpp src/lambo_cheats_runtime.cpp)
        target_include_directories(lambo_cheat_tests PRIVATE src RecompiledFuncs
            ${N64MR}/N64Recomp/include)
        add_test(NAME lambo_cheats COMMAND lambo_cheat_tests)

    endif()

    add_executable(lambo_config_tests
        tests/test_live_config.cpp
        src/lambo_config.cpp
        src/lambo_player_name.cpp
        src/lambo_log.cpp
    )
    target_include_directories(lambo_config_tests PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
        ${N64MR}/ultramodern/include
        ${N64MR}/N64Recomp/include
        ${N64MR}/thirdparty
    )
    target_link_libraries(lambo_config_tests PRIVATE Threads::Threads)
    add_test(NAME lambo_config_live_updates COMMAND lambo_config_tests)

    add_executable(lambo_hud_blue_bar_tests tests/test_hud_blue_bar.cpp src/lambo_hud.cpp)
    target_include_directories(lambo_hud_blue_bar_tests PRIVATE src
        ${N64MR}/ultramodern/include ${N64MR}/N64Recomp/include ${N64MR}/thirdparty)
    add_test(NAME lambo_hud_blue_bar COMMAND lambo_hud_blue_bar_tests)

    add_executable(lambo_car_card_tests tests/test_car_card.cpp src/lambo_car_card.cpp)
    target_include_directories(lambo_car_card_tests PRIVATE src
        ${N64MR}/ultramodern/include ${N64MR}/N64Recomp/include ${N64MR}/thirdparty)
    add_test(NAME lambo_car_card COMMAND lambo_car_card_tests)

    # Opt-in measurement; deliberately excluded from CTest and the normal build.
    add_executable(lambo_config_benchmark EXCLUDE_FROM_ALL
        tests/benchmark_config.cpp src/lambo_config.cpp
        src/lambo_player_name.cpp src/lambo_log.cpp)
    target_include_directories(lambo_config_benchmark PRIVATE src
        ${N64MR}/ultramodern/include ${N64MR}/N64Recomp/include ${N64MR}/thirdparty)
    target_link_libraries(lambo_config_benchmark PRIVATE Threads::Threads)

    add_executable(lambo_log_tests
        tests/test_lambo_log.cpp
        src/lambo_log.cpp
    )
    target_include_directories(lambo_log_tests PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
    )
    target_link_libraries(lambo_log_tests PRIVATE Threads::Threads)
    add_test(NAME lambo_logging_policy COMMAND lambo_log_tests)

    add_executable(lambo_portable_paths_tests
        tests/test_portable_paths.cpp
    )
    target_include_directories(lambo_portable_paths_tests PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
    )
    add_test(NAME lambo_portable_paths COMMAND lambo_portable_paths_tests)

    add_executable(lambo_rom_path_tests tests/test_rom_path.cpp)
    target_include_directories(lambo_rom_path_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
    add_test(NAME lambo_rom_path COMMAND lambo_rom_path_tests)

    add_executable(lambo_launcher_menu_tests tests/test_launcher_menu.cpp)
    target_include_directories(lambo_launcher_menu_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
    add_test(NAME lambo_launcher_menu COMMAND lambo_launcher_menu_tests)

    add_executable(lambo_reset_tests tests/test_reset.c src/lambo_reset.c)
    target_include_directories(lambo_reset_tests PRIVATE src ${N64MR}/N64Recomp/include)
    add_test(NAME lambo_reset COMMAND lambo_reset_tests)

    add_executable(lambo_reset_observation_tests tests/test_reset_observation.cpp)
    target_include_directories(lambo_reset_observation_tests PRIVATE src)
    add_test(NAME lambo_reset_observation COMMAND lambo_reset_observation_tests)

    add_executable(lambo_camera_projection_tests
        tests/test_camera_projection.cpp
    )
    target_include_directories(lambo_camera_projection_tests PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
    )
    add_test(NAME lambo_camera_projection_policy COMMAND lambo_camera_projection_tests)

    add_executable(lambo_camera_runtime_tests
        tests/test_camera_runtime.cpp src/lambo_camera.cpp)
    target_include_directories(lambo_camera_runtime_tests PRIVATE src
        ${N64MR}/N64Recomp/include ${N64MR}/ultramodern/include ${N64MR}/thirdparty)
    add_test(NAME lambo_camera_runtime COMMAND lambo_camera_runtime_tests)

    add_executable(lambo_sky_projection_tests tests/test_sky_projection.cpp)
    target_include_directories(lambo_sky_projection_tests PRIVATE
        src lib/rt64/src)
    add_test(NAME lambo_sky_projection COMMAND lambo_sky_projection_tests)

    add_executable(lambo_sky_panorama_tests
        tests/test_sky_panorama.cpp src/lambo_sky_widescreen.cpp)
    target_include_directories(lambo_sky_panorama_tests PRIVATE
        src lib/rt64/include ${N64MR}/N64Recomp/include
        ${N64MR}/librecomp/include ${N64MR}/ultramodern/include
        ${N64MR}/thirdparty)
    add_test(NAME lambo_sky_panorama COMMAND lambo_sky_panorama_tests)

    add_executable(lambo_no_lod_policy_tests
        tests/test_no_lod_policy.cpp
        src/lambo_no_lod_policy.cpp
    )
    target_include_directories(lambo_no_lod_policy_tests PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
    )
    add_test(NAME lambo_no_lod_policy COMMAND lambo_no_lod_policy_tests)

    add_executable(lambo_no_lod_row_benchmark EXCLUDE_FROM_ALL
        tests/benchmark_no_lod_row.cpp src/lambo_no_lod_policy.cpp)
    target_include_directories(lambo_no_lod_row_benchmark PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
    )

    add_executable(lambo_track_patch_tests
        tests/test_track_patch.cpp
        src/lambo_track_patch.cpp
        src/lambo_log.cpp
    )
    target_include_directories(lambo_track_patch_tests PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
        ${N64MR}/N64Recomp/include
    )
    target_link_libraries(lambo_track_patch_tests PRIVATE Threads::Threads)
    add_test(NAME lambo_track_patch_safety COMMAND lambo_track_patch_tests)

    add_executable(lambo_interpolation_tags_tests
        tests/test_interpolation_tags.cpp
        src/lambo_interpolation.cpp
    )
    target_include_directories(lambo_interpolation_tags_tests PRIVATE
        ${N64MR}/N64Recomp/include
        ${CMAKE_CURRENT_SOURCE_DIR}/lib/rt64/include
    )
    add_test(NAME lambo_interpolation_tags COMMAND lambo_interpolation_tags_tests)

    add_executable(lambo_rt64_angular_velocity_tests
        tests/test_rt64_angular_velocity.cpp
        lib/rt64/src/hle/rt64_rigid_body.cpp
        lib/rt64/src/common/rt64_math.cpp
    )
    target_include_directories(lambo_rt64_angular_velocity_tests PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/lib/rt64/include
        ${CMAKE_CURRENT_SOURCE_DIR}/lib/rt64/src
        ${CMAKE_CURRENT_SOURCE_DIR}/lib/rt64/src/contrib/hlslpp/include
    )
    if(WIN32)
        target_compile_definitions(lambo_rt64_angular_velocity_tests PRIVATE NOMINMAX)
    endif()
    add_test(NAME lambo_rt64_angular_velocity_finite COMMAND lambo_rt64_angular_velocity_tests)

    add_executable(lambo_controller_pak_tests
        tests/test_controller_pak.c
        src/libultra_stubs.c
        src/lambo_pak_io.c
        src/lambo_pak_storage.cpp
        src/lambo_log.cpp
    )
    target_include_directories(lambo_controller_pak_tests PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
        ${N64MR}/N64Recomp/include
    )
    target_link_libraries(lambo_controller_pak_tests PRIVATE Threads::Threads)
    add_test(NAME lambo_controller_pak_identity COMMAND lambo_controller_pak_tests)

    add_executable(lambo_controller_pak_io_tests
        tests/test_pak_io.c
        src/lambo_pak_io.c
    )
    target_include_directories(lambo_controller_pak_io_tests PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
    )
    add_test(NAME lambo_controller_pak_emulator_formats COMMAND lambo_controller_pak_io_tests)

    add_executable(lambo_controller_pak_storage_tests
        tests/test_pak_storage.cpp
        src/lambo_pak_storage.cpp
        src/lambo_pak_io.c
        src/lambo_log.cpp
    )
    target_include_directories(lambo_controller_pak_storage_tests PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
    )
    target_compile_definitions(lambo_controller_pak_storage_tests PRIVATE
        LAMBO_PAK_STORAGE_TESTING=1
    )
    target_link_libraries(lambo_controller_pak_storage_tests PRIVATE Threads::Threads)
    add_test(NAME lambo_controller_pak_batched_storage COMMAND lambo_controller_pak_storage_tests)

    add_executable(lambo_crash_symbols_tests
        tests/test_crash_symbols.cpp
        src/lambo_crash.cpp
        src/lambo_log.cpp
    )
    target_include_directories(lambo_crash_symbols_tests PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
        ${N64MR}/N64Recomp/include
        ${N64MR}/librecomp/include
        ${N64MR}/ultramodern/include
    )
    target_link_libraries(lambo_crash_symbols_tests PRIVATE Threads::Threads)
    if(WIN32)
        target_link_libraries(lambo_crash_symbols_tests PRIVATE dbghelp)
    endif()
    add_test(NAME lambo_crash_symbols
        COMMAND lambo_crash_symbols_tests
            ${CMAKE_CURRENT_SOURCE_DIR}/lamborghini.syms.toml)

    add_executable(lambo_startup_tests
        tests/test_startup.cpp
        src/lambo_startup.cpp
    )
    target_include_directories(lambo_startup_tests PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
    )
    add_test(NAME lambo_startup_state_machine COMMAND lambo_startup_tests)

    if(WIN32)
        add_executable(lambo_rdram_allocation_tests
            tests/test_rdram_allocation.cpp
            ${N64MR}/librecomp/src/rdram_memory.cpp
        )
        target_include_directories(lambo_rdram_allocation_tests PRIVATE
            ${N64MR}/librecomp/include
        )
        target_compile_definitions(lambo_rdram_allocation_tests PRIVATE NOMINMAX)
        add_test(NAME lambo_windows_rdram_reservation COMMAND lambo_rdram_allocation_tests)
    endif()

    add_executable(lambo_input_gate_tests
        tests/test_input_gate.cpp
        src/lambo_input_gate.cpp
    )
    target_include_directories(lambo_input_gate_tests PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
    )
    add_test(NAME lambo_input_capture_gate COMMAND lambo_input_gate_tests)

    add_executable(lambo_window_resize_tests
        tests/test_window_resize.cpp
        src/lambo_window_resize.cpp
    )
    target_include_directories(lambo_window_resize_tests PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
    )
    add_test(NAME lambo_window_resize COMMAND lambo_window_resize_tests)

    add_executable(lambo_driving_assists_tests tests/test_driving_assists.cpp src/lambo_driving_assists.cpp)
    target_include_directories(lambo_driving_assists_tests PRIVATE src)
    add_test(NAME lambo_input_driving_assists COMMAND lambo_driving_assists_tests)

    add_executable(lambo_main_loop_idle_tests tests/test_main_loop_idle.cpp src/lambo_main_loop_idle.cpp)
    target_include_directories(lambo_main_loop_idle_tests PRIVATE src
        ${N64MR}/ultramodern/include
        ${N64MR}/thirdparty
        ${N64MR}/thirdparty/concurrentqueue)
    add_test(NAME lambo_main_loop_idle COMMAND lambo_main_loop_idle_tests)

    add_executable(lambo_stall_report_tests tests/test_stall_report.cpp src/lambo_stall_report.cpp)
    target_include_directories(lambo_stall_report_tests PRIVATE src)
    add_test(NAME lambo_stall_report COMMAND lambo_stall_report_tests)

    # dp_pacing.hpp is added by patches/0001.
    add_executable(lambo_dp_completion_pacing_tests tests/test_dp_completion_pacing.cpp)
    target_include_directories(lambo_dp_completion_pacing_tests PRIVATE ${N64MR}/ultramodern/include)
    add_test(NAME lambo_dp_completion_pacing COMMAND lambo_dp_completion_pacing_tests)

    add_executable(lambo_input_replay_tests
        tests/test_lambo_replay.cpp
        src/lambo_replay.cpp
        src/lambo_file.cpp
    )
    target_include_directories(lambo_input_replay_tests PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
        ${N64MR}/thirdparty
    )
    add_test(NAME lambo_input_record_replay COMMAND lambo_input_replay_tests)

    add_executable(lambo_controls_tests
        tests/test_controls.cpp
        src/controls/lambo_controls.cpp
        src/lambo_config.cpp
        src/lambo_log.cpp
        src/lambo_file.cpp
    )
    target_include_directories(lambo_controls_tests PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
        ${N64MR}/ultramodern/include
        ${N64MR}/thirdparty
    )
    add_test(NAME lambo_controls_domain_and_persistence COMMAND lambo_controls_tests)

    add_executable(lambo_controls_capture_tests
        tests/test_controls_capture.cpp
        src/controls/lambo_controls.cpp
        src/lambo_config.cpp
        src/lambo_log.cpp
        src/lambo_file.cpp
    )
    target_include_directories(lambo_controls_capture_tests PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
        ${N64MR}/ultramodern/include
        ${N64MR}/thirdparty
    )
    add_test(NAME lambo_controls_capture_state_machine COMMAND lambo_controls_capture_tests)


    add_executable(lambo_analog_throttle_tests
        tests/test_analog_throttle.cpp
        src/lambo_analog_throttle.cpp
        src/lambo_log.cpp
    )
    target_include_directories(lambo_analog_throttle_tests PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
        ${N64MR}/N64Recomp/include
    )
    target_link_libraries(lambo_analog_throttle_tests PRIVATE Threads::Threads)
    add_test(NAME lambo_analog_throttle_bridge COMMAND lambo_analog_throttle_tests)

    add_executable(lambo_analog_brake_tests
        tests/test_analog_brake.cpp
        src/lambo_analog_brake.cpp
        src/lambo_log.cpp
    )
    target_include_directories(lambo_analog_brake_tests PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
        ${N64MR}/N64Recomp/include
    )
    target_link_libraries(lambo_analog_brake_tests PRIVATE Threads::Threads)
    add_test(NAME lambo_analog_brake_bridge COMMAND lambo_analog_brake_tests)

    add_executable(lambo_steering_tests
        tests/test_steering.cpp
        src/lambo_steering.cpp
    )
    target_include_directories(lambo_steering_tests PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
        ${N64MR}/N64Recomp/include
    )
    add_test(NAME lambo_steering_response COMMAND lambo_steering_tests)

    add_executable(lambo_replay_runtime_tests
        tests/test_lambo_replay_runtime.cpp
        src/lambo_driving_assists.cpp
        src/lambo_driving_assists_runtime.cpp
        src/lambo_replay_runtime.cpp
        src/lambo_replay.cpp
        src/lambo_file.cpp
        src/lambo_analog_throttle.cpp
        src/lambo_analog_brake.cpp
        src/lambo_input_gate.cpp
        src/lambo_log.cpp
    )
    target_include_directories(lambo_replay_runtime_tests PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
        ${N64MR}/N64Recomp/include
        ${N64MR}/thirdparty
    )
    target_link_libraries(lambo_replay_runtime_tests PRIVATE Threads::Threads)
    add_executable(lambo_harness_report_tests tests/test_harness_report.cpp
        src/lambo_harness_report.cpp src/lambo_file.cpp src/lambo_log.cpp)
    target_include_directories(lambo_harness_report_tests PRIVATE src ${N64MR}/thirdparty)
    target_link_libraries(lambo_harness_report_tests PRIVATE Threads::Threads)
    add_test(NAME lambo_harness_report COMMAND lambo_harness_report_tests)

    add_test(NAME lambo_replay_runtime_capture COMMAND lambo_replay_runtime_tests)
    foreach(case complete stay invalid load overwrite)
        add_test(NAME lambo_replay_runtime_${case} COMMAND lambo_replay_runtime_tests ${case})
    endforeach()




    add_test(NAME lambo_hud_blue_bar_rom
        COMMAND ${LAMBO_PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_hud_blue_bar_rom.py)
    add_test(NAME lambo_car_card_rom
        COMMAND ${LAMBO_PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_car_card_rom.py)
    add_test(NAME lambo_frontend_assets
        COMMAND ${LAMBO_PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_frontend_assets.py ${CMAKE_CURRENT_SOURCE_DIR})
    add_test(NAME lambo_quit_path
        COMMAND ${LAMBO_PYTHON_EXECUTABLE}
            ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_quit_path.py
            ${CMAKE_CURRENT_SOURCE_DIR}
    )
    add_test(NAME lambo_frontend_frame_pump_wiring
        COMMAND ${LAMBO_PYTHON_EXECUTABLE}
            ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_frame_pump_wiring.py
            ${CMAKE_CURRENT_SOURCE_DIR}
    )
    add_test(NAME lambo_game_scenario_runner
        COMMAND ${LAMBO_PYTHON_EXECUTABLE}
            ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_game_scenario.py
    )
    add_test(NAME lambo_hud_savestate
        COMMAND ${LAMBO_PYTHON_EXECUTABLE}
            ${CMAKE_CURRENT_SOURCE_DIR}/tests/hud_savestate_process.py
            $<TARGET_FILE:lambo_hud_savestate_tests>)
    add_test(NAME lambo_hud_rt64_contract
        COMMAND ${LAMBO_PYTHON_EXECUTABLE}
            ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_hud_rt64_contract.py)
    add_test(NAME lambo_rt_task_capture
        COMMAND ${LAMBO_PYTHON_EXECUTABLE}
            ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_rt_task_capture.py
    )
    add_test(NAME lambo_rt_alpha_capture
        COMMAND ${LAMBO_PYTHON_EXECUTABLE}
            ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_rt_alpha_capture.py
    )
    add_test(NAME lambo_prompt_back_action
        COMMAND ${LAMBO_PYTHON_EXECUTABLE}
            -m tests.test_prompt_back_action
    )
    add_test(NAME lambo_native_menu_retired
        COMMAND ${LAMBO_PYTHON_EXECUTABLE} -m tests.test_native_menu_retired
    )
    add_test(NAME lambo_reset_rom
        COMMAND ${LAMBO_PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_reset_rom.py)
    add_test(NAME lambo_track_lab_codec
        COMMAND ${LAMBO_PYTHON_EXECUTABLE}
            -m unittest tests.test_track_lab
    )
    add_test(NAME lambo_track_patch_python_interop
        COMMAND ${LAMBO_PYTHON_EXECUTABLE}
            -m tests.test_track_patch_interop
            $<TARGET_FILE:lambo_track_patch_tests>
    )
    set_tests_properties(
        lambo_track_lab_codec
        lambo_track_patch_python_interop
        lambo_prompt_back_action
        lambo_native_menu_retired
        PROPERTIES WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
    )
endif()

# RecompFrontend owns RmlUi, its SDL backend, fonts and SVG support.
set(BUILD_SHARED_LIBS OFF)
set(RMLUI_TESTS OFF CACHE BOOL "" FORCE)
set(RMLUI_SAMPLES OFF CACHE BOOL "" FORCE)

# lambo_config.cpp coalesces graphics.json persistence on a portable std::thread.
# Keep every executable that compiles it explicitly linked to the platform thread
# implementation; relying on a transitive SDL/runtime dependency breaks test
# targets and older Linux toolchains.
foreach(lambo_config_thread_target
        lambo_config_tests
        lambo_controls_tests
        lambo_controls_capture_tests
        lamborghini_modern)
    if(TARGET ${lambo_config_thread_target})
        target_link_libraries(${lambo_config_thread_target} PRIVATE Threads::Threads)
    endif()
endforeach()
set(RT64_STATIC TRUE)
if(WIN32)
    # Windows native build: RT64 uses its D3D12 backend + a plain Win32 window
    # (HWND handed over via SDL_GetWindowWMInfo in create_window_stub), so no SDL
    # Vulkan surface. SDL2 comes from rt64's own bundled Windows deps â€” the same
    # tree rt64's CMake points itself at (mupen64plus-win32-deps/SDL2-2.26.3).
    set(SDL2_WIN32_DEPS ${CMAKE_CURRENT_SOURCE_DIR}/lib/rt64/src/contrib/mupen64plus-win32-deps/SDL2-2.26.3)
    set(SDL2_INCLUDE_DIRS ${SDL2_WIN32_DEPS}/include)
    set(SDL2_LIBRARIES SDL2 SDL2main)
    link_directories(${SDL2_WIN32_DEPS}/lib/x64)
    # MinGW's bundled d3d12.h is years behind the D3D12 SDK: plume needs
    # D3D12_HEAP_TYPE_GPU_UPLOAD and D3D12MemAlloc needs <dxguids.h> (its own
    # MinGW support path). Microsoft's DirectX-Headers package is
    # the official fix and supports MinGW; put its d3d12.h AHEAD of the MinGW
    # system header and link the GUID definitions library everywhere.
    include(FetchContent)
    FetchContent_Declare(DirectX-Headers
        GIT_REPOSITORY https://github.com/microsoft/DirectX-Headers
        GIT_TAG v1.614.1
        GIT_SHALLOW TRUE)
    FetchContent_MakeAvailable(DirectX-Headers)
    include_directories(BEFORE
        ${directx-headers_SOURCE_DIR}/include
        ${directx-headers_SOURCE_DIR}/include/directx
        ${directx-headers_SOURCE_DIR}/include/dxguids)
else()
    set(RT64_SDL_WINDOW_VULKAN TRUE) # non-Windows: RT64 expects an SDL window + Vulkan surface
    # rt64's vendored nativefiledialog-extended defaults to the GTK3 backend; this
    # box (WSL Ubuntu 24.04) has no libgtk-3-dev but does have dbus-1, so use the
    # xdg-desktop-portal backend instead.
    set(NFD_PORTAL ON CACHE BOOL "" FORCE)
endif()
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib/rt64 ${CMAKE_BINARY_DIR}/rt64)
include(cmake/RayTracing.cmake)

if(BUILD_TESTING)
    add_executable(lambo_rt64_scene_matching_tests
        tests/test_rt64_scene_matching.cpp src/lambo_interpolation.cpp)
    target_link_libraries(lambo_rt64_scene_matching_tests PRIVATE rt64)
    target_compile_definitions(lambo_rt64_scene_matching_tests PRIVATE HLSL_CPU)
    target_include_directories(lambo_rt64_scene_matching_tests PRIVATE
        lib/rt64/include lib/rt64/src lib/rt64/src/contrib
        lib/rt64/src/contrib/hlslpp/include lib/rt64/src/contrib/plume
        lib/rt64/src/contrib/imgui
        ${N64MR}/N64Recomp/include
    )
    if(WIN32)
        target_compile_definitions(lambo_rt64_scene_matching_tests PRIVATE NOMINMAX)
    endif()
    add_test(NAME lambo_rt64_scene_matching COMMAND lambo_rt64_scene_matching_tests)

    add_executable(lambo_rt64_texture_table_tests tests/test_rt64_texture_table.cpp)
    target_link_libraries(lambo_rt64_texture_table_tests PRIVATE rt64)
    target_include_directories(lambo_rt64_texture_table_tests PRIVATE
        lib/rt64/include lib/rt64/src lib/rt64/src/contrib
        lib/rt64/src/contrib/hlslpp/include lib/rt64/src/contrib/plume
    )
    if(WIN32)
        target_compile_definitions(lambo_rt64_texture_table_tests PRIVATE NOMINMAX)
    endif()
    add_test(NAME lambo_rt64_texture_table_without_descriptor_indexing
        COMMAND lambo_rt64_texture_table_tests)
endif()
# SDL2main owns the Windows entry point, but this project provides its own
# WinMain wrapper so it can build as a GUI executable while still accepting
# normal command-line arguments. RT64's bundled CMake adds SDL2main to its
# direct link list; remove only that transitive entry-point library while
# retaining SDL2 for the renderer and input backends.
if(WIN32 AND TARGET rt64)
    get_target_property(RT64_LINK_LIBRARIES rt64 LINK_LIBRARIES)
    list(REMOVE_ITEM RT64_LINK_LIBRARIES SDL2main)
    set_target_properties(rt64 PROPERTIES LINK_LIBRARIES "${RT64_LINK_LIBRARIES}")
    get_target_property(RT64_INTERFACE_LINK_LIBRARIES rt64 INTERFACE_LINK_LIBRARIES)
    list(REMOVE_ITEM RT64_INTERFACE_LINK_LIBRARIES SDL2main)
    set_target_properties(rt64 PROPERTIES
        INTERFACE_LINK_LIBRARIES "${RT64_INTERFACE_LINK_LIBRARIES}")
endif()
# Generated shader headers land in the rt64 binary dir (Zelda64Recomp does the same).
target_include_directories(rt64 PRIVATE ${CMAKE_BINARY_DIR}/rt64/src)
if(WIN32)
    # GUID definitions for GCC's __uuidof emulation (see the DirectX-Headers
    # block above). Scoped per-target: a global link_libraries() leaks into
    # zstd's install-export set and breaks the CMake generate step.
    target_link_libraries(plume PRIVATE DirectX-Guids)
    # dwmapi (imgui_impl_win32) + d3dcompiler (imgui_impl_dx12's D3DCompile):
    # both are pulled in via #pragma comment(lib,...) which only MSVC honours;
    # MinGW needs the explicit link.
    target_link_libraries(rt64 DirectX-Guids dwmapi d3dcompiler)
    if(NOT MSVC)
        # MinGW: force-include the __mingw_uuidof compat header into every C++
        # TU of the D3D12-touching targets (why: see the header itself).
        set(DX12_UUID_COMPAT ${CMAKE_CURRENT_SOURCE_DIR}/src/mingw_dx12_uuid_compat.h)
        foreach(dx12_target plume rt64)
            target_compile_options(${dx12_target} PRIVATE
                $<$<COMPILE_LANGUAGE:CXX>:-include${DX12_UUID_COMPAT}>)
        endforeach()
    endif()
endif()
if(NOT WIN32)
    find_package(SDL2 REQUIRED)
endif()

if(BUILD_TESTING)
    # Each audio test links the real sink against its own SDL fakes.
    function(lambo_add_audio_test stem test_name)
        set(target lambo_audio_${stem}_tests)
        add_executable(${target}
            tests/test_audio_${stem}.cpp
            src/lambo_audio.cpp
            src/lambo_log.cpp
        )
        target_include_directories(${target} PRIVATE
            ${CMAKE_CURRENT_SOURCE_DIR}/src
            ${N64MR}/ultramodern/include
            ${N64MR}/librecomp/include
            ${N64MR}/N64Recomp/include
            ${N64MR}/thirdparty
            ${N64MR}/thirdparty/concurrentqueue
            ${SDL2_INCLUDE_DIRS}
        )
        target_compile_definitions(${target} PRIVATE
            SDL_MAIN_HANDLED
            LAMBO_AUDIO_RETRY_INTERVAL_MS=0
        )
        target_link_libraries(${target} PRIVATE Threads::Threads)
        add_test(NAME ${test_name} COMMAND ${target})
    endfunction()
    lambo_add_audio_test(recovery lambo_audio_recovers_from_device_failures)
    lambo_add_audio_test(locking lambo_audio_lock_scopes)

    add_executable(lambo_frame_pump_tests tests/test_frame_pump.cpp)
    target_include_directories(lambo_frame_pump_tests PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
    )
    add_test(NAME lambo_frontend_frame_pump_lock_scopes COMMAND lambo_frame_pump_tests)

endif()

# ultramodern + librecomp, which cascades N64Recomp / LiveRecomp / miniz.
# The runtime root CMake (lib/N64ModernRuntime/CMakeLists.txt) deliberately
# omits RT64 â€” it is pulled in only by a game's own CMake.
add_subdirectory(${N64MR})

if(BUILD_TESTING)
    add_executable(lambo_mod_runtime_refresh_tests tests/test_mod_runtime_refresh.cpp)
    target_include_directories(lambo_mod_runtime_refresh_tests PRIVATE ${N64MR}/N64Recomp/include)
    target_link_libraries(lambo_mod_runtime_refresh_tests PRIVATE librecomp Threads::Threads)
    add_test(NAME lambo_mod_runtime_refresh
        COMMAND ${LAMBO_PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tests/run_mod_runtime_refresh.py
            $<TARGET_FILE:lambo_mod_runtime_refresh_tests>)
endif()

# --- RecompiledFuncs: the whole-ROM recompiled image as a static library -----
# The generated funcs #include "recomp.h" (N64Recomp/include), "funcs.h"
# (resolved relative to each TU in RecompiledFuncs/), and lookup.cpp is picked
# up by the *.cpp glob. recomp_overlays.inl is an include (NOT a TU) and is
# intentionally excluded by the *.c/*.cpp globs.
#
# Skipped when empty so the first configure (which builds the recompiler
# tools) succeeds before N64Recomp populates this directory.
file(GLOB FUNC_C_SOURCES   CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/RecompiledFuncs/*.c)
file(GLOB FUNC_CXX_SOURCES CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/RecompiledFuncs/*.cpp)
if(FUNC_C_SOURCES OR FUNC_CXX_SOURCES)
    include(cmake/GuestPatches.cmake)
    add_library(RecompiledFuncs STATIC)
    target_sources(RecompiledFuncs PRIVATE ${FUNC_C_SOURCES} ${FUNC_CXX_SOURCES})

    target_compile_options(RecompiledFuncs PRIVATE
        -fno-strict-aliasing
        # Runtime mod replacement writes a 12-byte x64 / 16-byte ARM64 jump.
        # Reserve space even for tiny stubs and preserve separate entrypoints.
        -fpatchable-function-entry=16
        -falign-functions=16
        $<$<C_COMPILER_ID:GNU>:-fno-ipa-icf>
        -ggdb
        -Wno-unused-variable
        # implicit-function-declaration is a C-only diagnostic; lookup.cpp is C++.
        $<$<COMPILE_LANGUAGE:C>:-Wno-implicit-function-declaration>
    )

    target_include_directories(RecompiledFuncs PRIVATE
        ${N64MR}/ultramodern/include
        ${N64MR}/librecomp/include
        ${N64MR}/N64Recomp/include
    )
endif()

# --- Headless harness: used by scripted scenarios and source-only diagnostics ---
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp)
    # src/aspMain.cpp is RSPRecomp output (see BUILDING.md step 3); appended
    # only when present so the first configure (which builds the recompilers)
    # can succeed before RSPRecomp runs.
    set(LAMBO_SOURCES
        src/main.cpp
        src/lambo_vi.cpp
        src/register_overlays.cpp
        src/stub_renderer.cpp
        src/lambo_audio.cpp    # SDL2 push-audio sink for the AI buffer
        src/lambo_audio_override.cpp # audio status getter override
        src/lambo_config.cpp   # persistent graphics.json -> GraphicsConfig
        src/lambo_player_name.cpp # remember player one's confirmed name for later name-entry screens
        src/lambo_startup.cpp  # runtime-ready -> Play startup state machine
        src/lambo_mods.cpp
        src/lambo_mod_api.cpp
        src/lambo_mod_game.cpp
        src/lambo_mod_storage.cpp
        src/lambo_mod_gameplay.cpp
        src/lambo_rain.cpp
        src/lambo_rain_runtime.cpp
        src/lambo_input_gate.cpp # controller capture/neutral-release barrier
        src/lambo_window_resize.cpp # live window-size applies from the settings menu
        src/lambo_replay.cpp
        src/lambo_replay_runtime.cpp
        src/lambo_driving_assists_runtime.cpp
        src/lambo_harness_report.cpp
        src/lambo_file.cpp
        src/lambo_race_field.cpp
        src/lambo_automatic_pit_stops.cpp
        src/lambo_cheats.cpp
        src/lambo_cheats_runtime.cpp
        src/lambo_analog_throttle.cpp # host-to-guest throttle bridge + race hook
        src/lambo_analog_brake.cpp    # host-to-guest brake bridge + race hook
        src/lambo_steering.cpp        # opt-in steering deadzone and direct response
        src/controls/lambo_controls.cpp
        src/ui/lambo_frontend.cpp
        src/lambo_reset.c
        src/ui/lambo_launcher_menu.cpp
        src/ui/lambo_frontend_settings.cpp
        src/ui/lambo_frontend_input.cpp
        src/lambo_driving_assists.cpp
        src/lambo_main_loop_idle.cpp
        src/lambo_stall_report.cpp  # Android present-stall thread report; see docs/ANDROID.md
        src/lambo_crash.cpp    # native crash backtrace: Win32 EXCEPTION_POINTERS +
                               # POSIX sigaction handler printing KSEG0/RDRAM offset + a 32-entry
                               # function-lookup trace ring. No deps beyond libc + DbgHelp (Win) /
                               # libc backtrace(3) (POSIX).
        src/libultra_stubs.c   # no-op symbols for ignored libultra CP0 helpers (e.g. __osSetSR)
        src/lambo_pak_io.c
        src/lambo_pak_storage.cpp
        src/lambo_hud_widescreen.c  # extended-GBI alignment around race HUD elements
        src/lambo_hud.cpp          # optional removal of the decorative blue strip
        src/lambo_car_card.cpp     # optional car-select info card
        src/lambo_flare_widescreen.c  # extended-GBI aspect policy for lens flares
        src/lambo_fog_widescreen.cpp  # wider fog policy for three/four-player views
        src/lambo_graphics_task.cpp
        src/lambo_hud_texture_bounds.cpp
        src/lambo_sky_widescreen.cpp  # sky panorama policy for three/four-player views
        src/lambo_rt_shadows.cpp  # task-owned sunlight provenance diagnostics
        src/lambo_interpolation.cpp
        src/lambo_no_lod.cpp   # per-segment scenery policy; see docs/no_lod_audit.md
        src/lambo_no_lod_policy.cpp # measured exceptions for synthesized PVS extras
        src/lambo_track_patch.cpp # Track Lab: guarded sparse PVS corrections applied after the stock track loader
        src/lambo_camera.cpp   # sense of speed: chase-camera distance/height + FOV delta float-bit shims for the hooks
        src/lambo_gpu_advisory.cpp  # outdated-Intel-driver detection and user advisory
        src/lambo_warp.c       # developer warp menu (Ctrl+Shift+1-6 / LAMBO_WARP)
        src/lambo_savestate.c  # developer RDRAM snapshot; see docs/debugging.md
        src/lambo_savestate_io.cpp  # off-thread atomic publish for save-states
        src/lambo_log.cpp      # file-first levelled logging + --console/--verbose CLI policy
        src/lambo_car_trace.c  # car-differences campaign: LAMBO_CAR_TRACE per-frame vehicle-record trace
    )
    if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src/aspMain.cpp)
        list(APPEND LAMBO_SOURCES src/aspMain.cpp)
    endif()

    # The shipped Windows application is a GUI-subsystem executable.  Its
    # WinMain wrapper still accepts normal command-line arguments; lambo_log
    # allocates a console only when --console is requested.
    if(ANDROID)
        add_library(lamborghini_modern SHARED ${LAMBO_SOURCES})
        set_target_properties(lamborghini_modern PROPERTIES OUTPUT_NAME main)
        target_link_libraries(lamborghini_modern PRIVATE SDL2::SDL2 SDL2main android log)
        add_dependencies(lamborghini_modern lambo_vulkan)
    elseif(WIN32)
        add_executable(lamborghini_modern WIN32 ${LAMBO_SOURCES})
    else()
        add_executable(lamborghini_modern ${LAMBO_SOURCES})
    endif()
    set(LAMBO_MOD_GUARDS ${CMAKE_CURRENT_BINARY_DIR}/generated/lambo_mod_patch_guards.inc)
    add_custom_command(OUTPUT ${LAMBO_MOD_GUARDS}
        COMMAND ${LAMBO_PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/scripts/gen_mod_patch_guards.py
            ${CMAKE_CURRENT_SOURCE_DIR}/lamborghini.us.toml
            ${CMAKE_CURRENT_SOURCE_DIR}/lamborghini.syms.toml ${LAMBO_MOD_GUARDS}
        DEPENDS scripts/gen_mod_patch_guards.py lamborghini.us.toml lamborghini.syms.toml
        VERBATIM)
    target_sources(lamborghini_modern PRIVATE ${LAMBO_MOD_GUARDS})
    target_include_directories(lamborghini_modern PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/generated)

    target_compile_definitions(lamborghini_modern PRIVATE
        HLSL_CPU
        LAMBO_VERSION="${PROJECT_VERSION}"
        LAMBO_VERSION_MAJOR=${PROJECT_VERSION_MAJOR}
        LAMBO_VERSION_MINOR=${PROJECT_VERSION_MINOR}
        LAMBO_VERSION_PATCH=${PROJECT_VERSION_PATCH}
    )
    if(WIN32)
        target_compile_definitions(lamborghini_modern PRIVATE SDL_MAIN_HANDLED)
    endif()
    if(NOT WIN32 AND NOT APPLE)
        target_compile_definitions(lamborghini_modern PRIVATE
            PLUME_SDL_VULKAN_ENABLED
            RT64_SDL_WINDOW_VULKAN
        )
    endif()
    target_compile_options(lamborghini_modern PRIVATE
        -fno-strict-aliasing
        -fms-extensions
        -ggdb
        # GCC 16+ stopped pulling <cstdint> into <limits>/<algorithm>/<cstdlib>
        # transitively; RmlUi's vendored robin_hood.h relies on that and fails
        # with "Unsupported bitness" at the SIZE_MAX check. RmlUi_Platform_SDL.cpp
        # (compiled directly into lamborghini_modern, C++) pulls RmlUi headers.
        # The flag is scoped to CXX via two-argument generator expressions
        # because `-include` is a single compiler flag followed by a header
        # name, not a `-flag,value` shorthand â€” passing both as bare strings
        # inside $<COMPILE_LANGUAGE:CXX>:...> makes CMake emit them as two
        # separate tokens for C++ TUs and empty strings for C TUs.
        "$<$<COMPILE_LANGUAGE:CXX>:-include>" "$<$<COMPILE_LANGUAGE:CXX>:cstdint>"
    )
    if(CMAKE_SIZEOF_VOID_P EQUAL 8 AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64")
        target_compile_options(lamborghini_modern PRIVATE -march=nehalem)
    endif()
    target_include_directories(lamborghini_modern PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
        ${N64MR}/ultramodern/include
        ${N64MR}/librecomp/include
        ${N64MR}/N64Recomp/include
        ${CMAKE_CURRENT_SOURCE_DIR}/RecompiledFuncs
        ${N64MR}/thirdparty/concurrentqueue
    )
    target_link_libraries(lamborghini_modern PRIVATE
        librecomp
        ultramodern
        Threads::Threads
    )
    if(TARGET RecompiledFuncs)
        target_link_libraries(lamborghini_modern PRIVATE RecompiledFuncs GuestPatches)
        target_sources(lamborghini_modern PRIVATE src/lambo_guest_patches.cpp src/lambo_guest_settings.cpp
            src/lambo_vehicle_input.cpp)
        # The registration TU must include guest metadata, not the base table.
        set_source_files_properties(src/lambo_guest_patches.cpp PROPERTIES
            INCLUDE_DIRECTORIES "${LAMBO_GUEST_DIR}")
    endif()

    # RT64 renderer: default presenter; see the RT64 block above.
    target_sources(lamborghini_modern PRIVATE src/rt64_renderer.cpp src/lambo_rt_evidence.cpp
    src/lambo_rt_presented.cpp src/lambo_rt_admission.cpp src/lambo_rt_production.cpp)
    # rt64's build_pixel_shader/build_vertex_shader read ${DXC} and the DXC_*_OPTS
    # variables from the CALLER's scope (CMake evaluates unreferenced variables at call
    # time). Those variables are set inside rt64/CMakeLists.txt's own project() scope, so
    # invoking it from THIS file finds them unset and the generated build command is
    # missing the dxc.exe path AND the compiler args (-T ps_6_3, -spirv, ...). Pin the
    # full set of variables here so the shader build commands resolve end-to-end.
    set(LAMBO_DXC_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/lib/rt64/src/contrib/dxc")
    if(ANDROID)
        set(DXC ${LAMBO_HOST_DXC})
    elseif(WIN32)
        set(DXC "${LAMBO_DXC_ROOT}/bin/x64/dxc.exe")
    elseif(APPLE)
        find_library(LAMBO_ZLIB_LIBRARY NAMES z)
        get_filename_component(LAMBO_ZLIB_PATH ${LAMBO_ZLIB_LIBRARY} DIRECTORY)
        if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
            set(DXC "DYLD_LIBRARY_PATH=${LAMBO_DXC_ROOT}/lib/x64:${LAMBO_ZLIB_PATH}"
                "${LAMBO_DXC_ROOT}/bin/x64/dxc-macos")
        else()
            set(DXC "DYLD_LIBRARY_PATH=${LAMBO_DXC_ROOT}/lib/arm64:${LAMBO_ZLIB_PATH}"
                "${LAMBO_DXC_ROOT}/bin/arm64/dxc-macos")
        endif()
    elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
        set(DXC "LD_LIBRARY_PATH=${LAMBO_DXC_ROOT}/lib/x64"
            "${LAMBO_DXC_ROOT}/bin/x64/dxc-linux")
    else()
        set(DXC "LD_LIBRARY_PATH=${LAMBO_DXC_ROOT}/lib/arm64"
            "${LAMBO_DXC_ROOT}/bin/arm64/dxc-linux")
    endif()
    set(DXC_COMMON_OPTS "-I${CMAKE_CURRENT_SOURCE_DIR}/lib/rt64/src")
    set(DXC_DXIL_OPTS "-Wno-ignored-attributes")
    set(DXC_SPV_OPTS "-spirv" "-fspv-target-env=vulkan1.0" "-fvk-use-dx-layout")
    set(DXC_PS_OPTS "${DXC_COMMON_OPTS}" "-E" "PSMain" "-T ps_6_3")
    set(DXC_VS_OPTS "${DXC_COMMON_OPTS}" "-E" "VSMain" "-T vs_6_3" "-fvk-invert-y")
    set(RECOMP_FRONTEND_N64MODERNRUNTIME_PATH "${N64MR}" CACHE PATH "" FORCE)
    set(RECOMP_FRONTEND_RT64_PATH "${CMAKE_CURRENT_SOURCE_DIR}/lib/rt64" CACHE PATH "" FORCE)
    set(sdl2_SOURCE_DIR "${SDL2_WIN32_DEPS}")
    add_subdirectory(lib/RecompFrontend)
    foreach(frontend_target recompui recompinput rmlui_core rmlui_debugger)
        target_compile_options(${frontend_target} PRIVATE "$<$<COMPILE_LANGUAGE:CXX>:-include>" "$<$<COMPILE_LANGUAGE:CXX>:cstdint>")
        target_include_directories(${frontend_target} PRIVATE ${SDL2_INCLUDE_DIRS})
    endforeach()
    if(ANDROID)
        # recompui includes SDL through the installed <SDL2/...> prefix, which the
        # shared SDL2_INCLUDE_DIRS above (SDL's flat source include/) cannot satisfy.
        # Linking the target supplies SDL's generated header tree and orders this
        # compile after sdl_headers_copy has produced it. See docs/ANDROID.md; scoped
        # to recompui because it is the only target here whose sources include SDL
        # with the SDL2/ prefix.
        target_link_libraries(recompui PRIVATE SDL2::SDL2)
    endif()
    # recompui/src/renderer/rt64_render_context.cpp assigns ultramodern's
    # WindowHandle to RT64's Core::window -- a plume::RenderWindow. plume only
    # typedefs RenderWindow as SDL_Window* when PLUME_SDL_VULKAN_ENABLED is set;
    # otherwise Linux gets the X11 {Display*, Window} struct and Android gets
    # ANativeWindow*, and the assignment stops compiling. rt64's own
    # add_compile_definitions is directory-scoped to rt64 and never reaches
    # recompui, so the definition has to be repeated for the target that includes
    # the header. Scope it to recompui: it is the only frontend target whose
    # sources include RT64 or plume headers.
    if(NOT WIN32 AND NOT APPLE)
        target_compile_definitions(recompui PRIVATE
            PLUME_SDL_VULKAN_ENABLED
            RT64_SDL_WINDOW_VULKAN
        )
    endif()
    target_link_libraries(lamborghini_modern PRIVATE recompui recompinput)
    if(BUILD_TESTING)
        add_executable(lambo_frontend_debugger_tests tests/test_frontend_debugger.cpp)
        target_include_directories(lambo_frontend_debugger_tests PRIVATE
            lib/RecompFrontend/recompui/src)
        target_link_libraries(lambo_frontend_debugger_tests PRIVATE RmlUi::Core RmlUi::Debugger)
        add_test(NAME lambo_frontend_debugger_default COMMAND lambo_frontend_debugger_tests)
        add_test(NAME lambo_frontend_debugger_enabled COMMAND lambo_frontend_debugger_tests enabled)

        add_executable(lambo_frontend_asset_url_tests tests/test_frontend_asset_url.cpp)
        target_include_directories(lambo_frontend_asset_url_tests PRIVATE
            lib/RecompFrontend/recompui/src)
        target_link_libraries(lambo_frontend_asset_url_tests PRIVATE RmlUi::Core)
        add_test(NAME lambo_frontend_asset_url COMMAND lambo_frontend_asset_url_tests)

        add_executable(lambo_frontend_settings_tests
            tests/test_frontend_settings.cpp src/ui/lambo_frontend_settings.cpp
            src/lambo_cheats.cpp
            src/ui/lambo_frontend_input.cpp src/controls/lambo_controls.cpp src/lambo_driving_assists.cpp src/lambo_steering.cpp
            src/lambo_input_gate.cpp
            src/lambo_config.cpp src/lambo_player_name.cpp src/lambo_log.cpp src/lambo_file.cpp)
        target_include_directories(lambo_frontend_settings_tests PRIVATE src ${SDL2_INCLUDE_DIRS})
        target_link_libraries(lambo_frontend_settings_tests PRIVATE
            recompui recompinput librecomp ultramodern rt64 Threads::Threads)
        if(WIN32)
            target_compile_definitions(lambo_frontend_settings_tests PRIVATE SDL_MAIN_HANDLED NOMINMAX)
            target_link_libraries(lambo_frontend_settings_tests PRIVATE SDL2 shell32)
        else()
            target_link_libraries(lambo_frontend_settings_tests PRIVATE ${SDL2_LIBRARIES})
        endif()
        add_test(NAME lambo_frontend_settings COMMAND lambo_frontend_settings_tests
            ${CMAKE_BINARY_DIR}/frontend-settings-test-data)
    endif()
    # rt64's include_directories() are directory-scoped and do not propagate;
    # mirror Zelda64Recomp's include list for the game target.
    set(RT64_DIR ${CMAKE_CURRENT_SOURCE_DIR}/lib/rt64)
    target_include_directories(lamborghini_modern PRIVATE
        ${RT64_DIR}/include
        ${RT64_DIR}/src
        ${RT64_DIR}/src/rhi
        ${RT64_DIR}/src/render
        ${RT64_DIR}/src/contrib
        ${RT64_DIR}/src/contrib/plume
        ${RT64_DIR}/src/contrib/imgui
        ${RT64_DIR}/src/contrib/hlslpp/include
        ${RT64_DIR}/src/contrib/nativefiledialog-extended/src/include
        ${SDL2_INCLUDE_DIRS}
        ${CMAKE_BINARY_DIR}/shaders
    )
    target_link_libraries(lamborghini_modern PRIVATE
        rt64
        RmlUi::Core
        RmlUi::Debugger
    )
    if(WIN32)
        # We own WinMain for the GUI-subsystem executable; SDL2main supplies
        # its own entrypoint and would conflict with it.
        target_link_libraries(lamborghini_modern PRIVATE SDL2)
    else()
        target_link_libraries(lamborghini_modern PRIVATE ${SDL2_LIBRARIES})
    endif()

    # Release and source-build output needs the frontend assets and RmlUi fonts
    # beside the executable. Desktop builds also stage the window icon here.
    set(LAMBO_RUNTIME_ASSETS
        ${CMAKE_CURRENT_SOURCE_DIR}/lib/RecompFrontend/recompui/lib/RmlUi/Samples/assets/LatoLatin-Regular.ttf
        ${CMAKE_CURRENT_SOURCE_DIR}/lib/RecompFrontend/recompui/lib/RmlUi/Samples/assets/LatoLatin-Bold.ttf)
    if(NOT ANDROID)
        list(APPEND LAMBO_RUNTIME_ASSETS
            ${CMAKE_CURRENT_SOURCE_DIR}/assets/lambo-icon.bmp
            ${CMAKE_CURRENT_SOURCE_DIR}/assets/lambo-icon.png)
    endif()
    add_custom_command(TARGET lamborghini_modern POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_directory
            ${CMAKE_CURRENT_SOURCE_DIR}/assets/frontend
            $<TARGET_FILE_DIR:lamborghini_modern>/assets
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
            ${LAMBO_RUNTIME_ASSETS}
            $<TARGET_FILE_DIR:lamborghini_modern>/assets
    )

    if(WIN32)
        # Per-Monitor V2 DPI awareness: embed src/app.manifest so the
        # process gets true physical pixel dimensions at >100% display scaling --
        # without it DWM bitmap-stretches the window by the scale factor and a
        # 1600x900 window overflows 1080p screens at 175% scaling. MinGW ld has no
        # /MANIFEST switch, so compile the resource script with windres and
        # link the manifest and application icon.
        find_program(LAMBO_WINDRES_EXECUTABLE NAMES windres REQUIRED)
        set(LAMBO_WINDOWS_RESOURCES_OBJ ${CMAKE_CURRENT_BINARY_DIR}/lambo_resources.rc.o)
        add_custom_command(OUTPUT ${LAMBO_WINDOWS_RESOURCES_OBJ}
            COMMAND ${LAMBO_WINDRES_EXECUTABLE}
                -I ${CMAKE_CURRENT_SOURCE_DIR}/src
                -I ${CMAKE_CURRENT_SOURCE_DIR}/assets
                -O coff -o ${LAMBO_WINDOWS_RESOURCES_OBJ}
                ${CMAKE_CURRENT_SOURCE_DIR}/src/lambo_manifest.rc
            DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/lambo_manifest.rc
                    ${CMAKE_CURRENT_SOURCE_DIR}/src/app.manifest
                    ${CMAKE_CURRENT_SOURCE_DIR}/assets/lambo-icon.ico
            COMMENT "Embedding Windows manifest and application icon")
        target_sources(lamborghini_modern PRIVATE ${LAMBO_WINDOWS_RESOURCES_OBJ})
        # Native crash backtrace: CaptureStackBackTrace lives in
        # dbghelp.dll. MinGW64 ships the import lib (libdbghelp.a) so an explicit
        # target_link_libraries entry is enough; we don't ship the DLL â€” the
        # system one is fine.
        target_link_libraries(lamborghini_modern PRIVATE dbghelp shell32)
        # Self-contained exe dir: RT64 dlopen()s dxcompiler/dxil at runtime and SDL2 is
        # a dynamic dep; MinGW's own runtime is linked statically so the exe runs
        # outside an MSYS/MinGW shell.
        target_link_options(lamborghini_modern PRIVATE -static-libgcc -static-libstdc++
            -Wl,-Bstatic,--whole-archive -lwinpthread -Wl,--no-whole-archive,-Bdynamic)
        set(RT64_DXC_BIN ${CMAKE_CURRENT_SOURCE_DIR}/lib/rt64/src/contrib/dxc/bin/x64)
        add_custom_command(TARGET lamborghini_modern POST_BUILD
            COMMAND ${CMAKE_COMMAND} -E copy_if_different
                ${SDL2_WIN32_DEPS}/lib/x64/SDL2.dll
                "${CMAKE_CURRENT_SOURCE_DIR}/lib/RecompFrontend/recompui/lib/freetype-windows-binaries/release dll/win64/freetype.dll"
                ${RT64_DXC_BIN}/dxcompiler.dll
                ${RT64_DXC_BIN}/dxil.dll
                $<TARGET_FILE_DIR:lamborghini_modern>)
    endif()
endif()

# Build every registered host fixture without relying on the game target's
# dependencies. The ROM-backed fixtures join this target after generation.
if(BUILD_TESTING)
    add_custom_target(lambo_host_tests)
    get_property(lambo_directory_targets DIRECTORY PROPERTY BUILDSYSTEM_TARGETS)
    foreach(lambo_target IN LISTS lambo_directory_targets)
        if(lambo_target MATCHES "_tests$")
            add_dependencies(lambo_host_tests ${lambo_target})
        endif()
    endforeach()
endif()
