#
# 86Box    A hypervisor and IBM PC system emulator that specializes in
#          running old operating systems and software designed for IBM
#          PC systems and compatibles from 1981 through fairly recent
#          system designs based on the PCI bus.
#
#          This file is part of the 86Box distribution.
#
#          CMake build script.
#
# Authors: David Hrdlička, <hrdlickadavid@outlook.com>
#
#          Copyright 2020-2021 David Hrdlička.
#          Copyright 2021-2025 Jasmine Iwanek.
#

cmake_minimum_required(VERSION 3.16)

cmake_policy(SET CMP0091 NEW)
cmake_policy(SET CMP0079 NEW)

if(HAIKU)
    set(OPENAL ON)
endif()

if(NOT DEFINED QT OR QT)
    list(APPEND VCPKG_MANIFEST_FEATURES "qt-ui")
endif()

if(NOT DEFINED OPENAL OR OPENAL)
    list(APPEND VCPKG_MANIFEST_FEATURES "openal")
endif()

if(MUNT_EXTERNAL)
    list(APPEND VCPKG_MANIFEST_FEATURES "munt")
endif()

project(86Box
    VERSION 5.4
    DESCRIPTION "Emulator of x86-based systems"
    HOMEPAGE_URL "https://86box.net"
    LANGUAGES C CXX)

include(CPack)
include(CMakeDependentOption)

# Basic build options
if(VCPKG_TOOLCHAIN)
    # For vcpkg builds we have to respect the linking method used by the
    # specified triplet.
    set(NO_STATIC_OPTION ON)
    if(VCPKG_TARGET_TRIPLET MATCHES "-static$")
        # `-static` triplet, use static linking
        set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
        set(STATIC_BUILD ON)
    elseif(VCPKG_TARGET_TRIPLET MATCHES "-static-md$")
        # `-static-md` triplet, use static linking with dynamic CRT
        set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
        set(STATIC_BUILD ON)
    elseif()
        # Regular triplet, use dynamic linking
        set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
        set(STATIC_BUILD OFF)
    endif()

    # `vcpkg.json` defaults to Qt6
    set(USE_QT6 ON)
endif()

if(WIN32)
    # Prefer static builds on Windows
    set(PREFER_STATIC ON)

    # Default value for the `WIN32` target property, which specifies whether
    # to build the application for the Windows GUI or console subsystem
    option(CMAKE_WIN32_EXECUTABLE "Build a Windows GUI executable" ON)
else()
    # Prefer dynamic builds everywhere else
    set(PREFER_STATIC OFF)
endif()

if(APPLE)
    option(CMAKE_MACOSX_BUNDLE "Build a macOS bundle (.app)" ON)
endif()

if(NOT NO_STATIC_OPTION)
    if(PREFER_STATIC)
        option(STATIC_BUILD "Static build" ON)
    else()
        option(STATIC_BUILD "Static build" OFF)
    endif()
endif()

# Detect the target architecture by trying to compile `src/arch_detect.c`
try_compile(RESULT_VAR ${CMAKE_BINARY_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/src/arch_detect.c" OUTPUT_VARIABLE ARCH)
string(REGEX MATCH "ARCH ([a-zA-Z0-9_]+)" ARCH "${ARCH}")
string(REPLACE "ARCH " "" ARCH "${ARCH}")
if (NOT ARCH)
    set(ARCH unknown)
endif()

add_compile_definitions(CMAKE)
add_compile_definitions("$<$<CONFIG:Debug>:DEBUG>")

if(WIN32)
    # Disables *_s function warnings
    add_compile_definitions(_CRT_SECURE_NO_WARNINGS)

    # Disables POSIX name warnings
    add_compile_definitions(_CRT_NONSTDC_NO_WARNINGS)

    # Disables WinSock deprecation warnings
    add_compile_definitions(_WINSOCK_DEPRECATED_NO_WARNINGS)
endif()

if(NOT (WIN32 OR APPLE OR CMAKE_SYSTEM_NAME STREQUAL "Linux"))
    set(DISCORD OFF)
endif()

set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)

# Optional features
#
#      Option       Description                                                  Def.
#      ------       -----------                                                  ----
option(RELEASE      "Release build"                                              OFF)
option(DYNAREC      "Dynamic recompiler"                                         ON)
option(OPENAL       "OpenAL"                                                     ON)
option(RTMIDI       "RtMidi"                                                     ON)
option(FLUIDSYNTH   "FluidSynth"                                                 ON)
option(MUNT         "MUNT"                                                       ON)
option(VNC          "VNC renderer"                                               OFF)
option(MINITRACE    "Enable Chrome tracing using the modified minitrace library" OFF)
option(GDBSTUB      "Enable GDB stub server for debugging"                       OFF)
option(DEV_BRANCH   "Development branch"                                         OFF)
option(DISCORD      "Discord Rich Presence support"                              ON)
option(DEBUGREGS486 "Enable debug register opeartion on 486+ CPUs"               OFF)
option(LIBASAN      "Enable compilation with the addresss sanitizer"             OFF)

if((ARCH STREQUAL "arm64"))
    set(NEW_DYNAREC ON)
else()
    option(NEW_DYNAREC "Use the PCem v15 (\"new\") dynamic recompiler" OFF)
endif()

if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
    option(AUDIO4 "Use audio(4) as sound backend" ON)
else()
    set(AUDIO4 OFF)
endif()

if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
    option(SNDIO "Use sndio as sound backend" ON)
else()
    set(SNDIO OFF)
endif()

if(WIN32)
    set(QT ON)
    option(CPPTHREADS "C++11 threads" OFF)
else()
    option(QT "Qt GUI" ON)
    option(CPPTHREADS "C++11 threads" ON)
endif()

if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
    SET(CMAKE_EXE_LINKER_FLAGS "-Wl,-z,wxneeded")
endif()

# Development branch features
#
#                      Option         Description                                Def.  Condition     Otherwise
#                      ------         -----------                                ----  ------------  ---------
cmake_dependent_option(AMD_K5         "AMD K5"                                   ON    "DEV_BRANCH"  OFF)
cmake_dependent_option(CDROM_MITSUMI  "Mitsumi CDROM"                            ON    "DEV_BRANCH"  OFF)
cmake_dependent_option(G100           "Matrox Productiva G100"                   ON    "DEV_BRANCH"  OFF)
cmake_dependent_option(ISAMEM_RAMPAGE "AST Rampage"                              ON    "DEV_BRANCH"  OFF)
cmake_dependent_option(ISAMEM_IAB     "Intel Above Board"                        ON    "DEV_BRANCH"  OFF)
cmake_dependent_option(ISAMEM_BRAT    "BocaRAM/AT"                               ON    "DEV_BRANCH"  OFF)
cmake_dependent_option(OPL4ML         "OPL4-ML daughterboard"                    ON    "DEV_BRANCH"  OFF)
cmake_dependent_option(PCL            "Generic PCL5e Printer"                    ON    "DEV_BRANCH"  OFF)
cmake_dependent_option(SIO_DETECT     "Super I/O Detection Helper"               ON    "DEV_BRANCH"  OFF)
cmake_dependent_option(WACOM          "Wacom Input Devices"                      ON    "DEV_BRANCH"  OFF)
cmake_dependent_option(XL24           "ATI VGA Wonder XL24 (ATI-28800-6)"        ON    "DEV_BRANCH"  OFF)
cmake_dependent_option(VFIO           "Virtual Function I/O"                     ON    "DEV_BRANCH"  OFF)
cmake_dependent_option(SOFTMODEM      "AC'97 Softmodem"                          ON    "DEV_BRANCH"  OFF)

# Ditto but for Qt
if(QT)
    option(USE_QT6 "Use Qt6 instead of Qt5" OFF)
    if(APPLE)
        option(MOLTENVK "Use MoltenVK libraries for Vulkan support on macOS. Requires a Vulkan-enabled QT." OFF)
    endif()
endif()

# Determine the build type
set(RELEASE_BUILD   OFF)
set(BETA_BUILD      OFF)
set(ALPHA_BUILD     OFF)

string(TOLOWER "${BUILD_TYPE}" BUILD_TYPE_LOWER)
if(BUILD_TYPE_LOWER STREQUAL "release")
    # Release build
    set(RELEASE_BUILD ON)
    add_compile_definitions(RELEASE_BUILD)
elseif(BUILD_TYPE_LOWER STREQUAL "beta")
    # Beta build
    set(BETA_BUILD ON)
    add_compile_definitions(BETA_BUILD)
elseif(BUILD_TYPE_LOWER STREQUAL "alpha")
    # Alpha build
    set(ALPHA_BUILD ON)
    add_compile_definitions(ALPHA_BUILD)
endif()

# Versioning variables
if(NOT CMAKE_PROJECT_VERSION_PATCH)
    set(CMAKE_PROJECT_VERSION_PATCH 0)
endif()
if(NOT EMU_BUILD_NUM)
    set(EMU_BUILD_NUM 0)
endif()
if(NOT EMU_COPYRIGHT_YEAR)
    set(EMU_COPYRIGHT_YEAR 2026)
endif()

# Libasan
if(LIBASAN)
    add_compile_options(-fsanitize=address)
    add_link_options(-fsanitize=address)
endif()

set(CMAKE_TOP_LEVEL_PROCESSED TRUE)

add_subdirectory(src)
