# SPDX-License-Identifier: GPL-2.0-or-later
# SPDX-FileCopyrightText: Copyright (C) 2026 Max A. Vilkki a.k.a. codise
#
# flipSID: a small, fast, cross-platform C64 SID player. See docs/DESIGN.md §2.2.
#
# Target-based throughout: no global compile flags or include_directories(). Third-party
# code builds from the pinned clones under lib/ (lib/fetch_externals.sh) through the
# wrappers in lib/cmake/<lib>/, and is exposed as ext::<lib> targets.

# 3.25 for add_subdirectory(SYSTEM), which keeps SDL's headers out of our warnings. The
# ...3.31 upper bound opts into newer policies where available, e.g. CMP0156, so a library
# reached through two targets isn't passed to the linker twice (Apple's ld warns).
cmake_minimum_required(VERSION 3.25...3.31)

# The compiler probe in project() reads this, so it has to be set first.
if(CMAKE_HOST_APPLE)
    set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0" CACHE STRING "Minimum macOS version")
    # CMake 4 no longer passes -isysroot by default, and without one Apple clang adds
    # -I/usr/local/include, which is searched before our -isystem dirs: Homebrew's SDL3
    # headers then shadow the pinned clone's. An explicit SDK stops that injection.
    set(CMAKE_OSX_SYSROOT "macosx" CACHE STRING "macOS SDK to build against")
endif()

# MSVC: the C and C++ runtime linked into the executable (/MT), for every target including
# SDL. With CMake's default /MD, flipsid.exe would need VCRUNTIME140(_1).dll and
# MSVCP140.dll, which a clean Windows 10 only has after the VC++ Redistributable is
# installed. Set before project() so that everything created after it follows (CMP0091).
if(NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY)
    set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif()
# Release builds are compiled with debug info too (/Zi here, -g below), which the shipped
# binary leaves out and the release package keeps beside itself (flipsid_configure_app,
# DESIGN §2.2): a tester's crash report can then be read against the very build.
if(NOT DEFINED CMAKE_MSVC_DEBUG_INFORMATION_FORMAT)
    set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<$<CONFIG:Debug,RelWithDebInfo,Release>:ProgramDatabase>")
endif()

project(flipsid
    VERSION 0.3.0
    DESCRIPTION "C64 SID player"
    HOMEPAGE_URL "https://gitlab.com/dahliazone/c64/flipsid"
    LANGUAGES C CXX
)
if(NOT MSVC)
    string(APPEND CMAKE_C_FLAGS_RELEASE " -g")
    string(APPEND CMAKE_CXX_FLAGS_RELEASE " -g")
endif()

option(FLIPSID_BUILD_TESTS "Build the unit tests" ${PROJECT_IS_TOP_LEVEL})
option(FLIPSID_WARNINGS_AS_ERRORS "Treat warnings in flipSID's own code as errors" OFF)
option(FLIPSID_ALLOW_UNPINNED_EXTERNALS
    "Only warn when a lib/ clone isn't at its pin in lib/fetch_externals.sh" OFF)

# Without a preset or -DCMAKE_BUILD_TYPE, a single-config build would get no optimisation
# at all, which is too slow for the emulation.
get_property(flipsidMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(NOT flipsidMultiConfig AND NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
    message(STATUS "flipSID: no build type given, using Release")
endif()

list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
include(flipsid_compiler_check)
include(flipsid_externals)
include(flipsid_options)
include(flipsid_warnings)
include(flipsid_version)

set(FLIPSID_LIB_DIR "${PROJECT_SOURCE_DIR}/lib")

set(flipsidExternals
    SDL3/CMakeLists.txt
    ocornut-imgui/imgui.cpp
    implot/implot.cpp
    miniaudio/miniaudio.c
    yyjson/src/yyjson.c
    libebur128/ebur128/ebur128.c
    libresidfp/configure.ac
    libsidplayfp/configure.ac
    resid/siddefs.h.in
    residfp-2011/builders/residfp-builder/residfp/siddefs-fp.h.in
    libusb/libusb/core.c
)
if(FLIPSID_BUILD_TESTS)
    list(APPEND flipsidExternals
        doctest/doctest/doctest.h
        trompeloeil/include/trompeloeil.hpp
    )
endif()
flipsid_require_externals(${flipsidExternals})

# Third-party libraries (ext::* targets)
add_subdirectory(lib/cmake/SDL3)
add_subdirectory(lib/cmake/imgui)
add_subdirectory(lib/cmake/implot)
add_subdirectory(lib/cmake/miniaudio)
add_subdirectory(lib/cmake/yyjson)
add_subdirectory(lib/cmake/libebur128)
# libresidfp first: the libsidplayfp wrapper links ext::residfp and checks it exists.
add_subdirectory(lib/cmake/libresidfp)
add_subdirectory(lib/cmake/libsidplayfp)
add_subdirectory(lib/cmake/resid)
add_subdirectory(lib/cmake/residfp-2011)
add_subdirectory(lib/cmake/libusb)
add_subdirectory(lib/cmake/xz)
add_subdirectory(lib/cmake/libarchive)
if(FLIPSID_BUILD_TESTS)
    add_subdirectory(lib/cmake/doctest)
    add_subdirectory(lib/cmake/trompeloeil)
endif()

# flipSID
add_subdirectory(src)
add_subdirectory(apps/flipsid)
# Developer tools that don't need the test libraries.
add_subdirectory(tools/flipsid_render)

if(FLIPSID_BUILD_TESTS)
    enable_testing()
    add_subdirectory(tests)
    add_subdirectory(tools/audio_probe)
    add_subdirectory(tools/player_probe)
    add_subdirectory(tools/hardsid_probe)
    add_subdirectory(tools/hardsid_play)
    add_subdirectory(tools/sid_record)
endif()
