# rexcore - Core utilities library
# Foundation types, data structures, and threading primitives

add_library(rexcore OBJECT
    arena.cpp
    bit_map.cpp
    bit_stream.cpp
    byte_stream.cpp
    clock.cpp
    cvar.cpp
    exception_handler.cpp
    filesystem.cpp
    filesystem_wildcard.cpp
    hash.cpp
    logging.cpp
    memory.cpp
    mutex.cpp
    ring_buffer.cpp
    string_buffer.cpp
    threading.cpp
    timer_queue.cpp
    utf8.cpp
    vec128.cpp
)
add_library(rex::core ALIAS rexcore)

if(APPLE)
    # Apple's libc++ still gates std::jthread/std::stop_token behind the
    # experimental-library feature flag. Only timer_queue.cpp uses them, and
    # neither type crosses a header boundary.
    set_source_files_properties(timer_queue.cpp PROPERTIES
        COMPILE_OPTIONS "-fexperimental-library")
endif()

# Platform-specific sources
if(WIN32)
    target_sources(rexcore PRIVATE
        atomic_win.cpp
        clock_win.cpp
        dbg_win.cpp
        dynlib_win.cpp
        exception_handler_win.cpp
        filesystem_win.cpp
        fiber_win32.cpp
        mapped_memory_win.cpp
        math_msvc.cpp
        memory_win.cpp
        platform/console_win.cpp
        platform/env_win.cpp
        seh_win.cpp
        socket_win.cpp
        system_win.cpp
        threading_win.cpp
    )
    target_compile_definitions(rexcore PUBLIC NOMINMAX WIN32_LEAN_AND_MEAN)
elseif(REXGLUE_PLATFORM_PS4)
    # PS4 (ps4-kit: clang 21, OpenOrbis libc, x86-64 Jaguar). ps4.cmake sets CMAKE_SYSTEM_NAME
    # Generic, so like the Switch it needs a branch of its own. The POSIX layer builds on the
    # OpenOrbis libc; what the PS4 kernel does differently is in the *_ps4.cpp files.
    target_sources(rexcore PRIVATE
        atomic_posix.cpp
        clock_posix.cpp
        dbg_posix.cpp
        filesystem_posix.cpp
        mapped_memory_posix.cpp
        math_gcc.cpp
        platform/console_posix.cpp
        platform/env_posix.cpp
        socket_posix.cpp
        system_posix.cpp
        threading_posix.cpp
        dynlib_ps4.cpp                # no dlopen for homebrew: everything is in the eboot
        exception_handler_ps4.cpp     # FreeBSD signal context, 16 KiB sibling faults
        fiber_ps4.cpp                 # x86-64 System V context switch (no makecontext)
        guest_memory_ps4.cpp          # window, direct memory aliases, real permissions
        memory_ps4.cpp                # rex::memory API on top of it
        seh_ps4.cpp                   # SEH scopes: faults are fatal (no throw from signals)
    )
elseif(UNIX)
    # Linux and macOS/Darwin share the POSIX sources; Darwin-specific behavior
    # is selected inside them with #if defined(__APPLE__).
    target_sources(rexcore PRIVATE
        atomic_posix.cpp
        clock_posix.cpp
        dbg_posix.cpp
        dynlib_posix.cpp
        exception_handler_posix.cpp
        filesystem_posix.cpp
        fiber_posix.cpp
        mapped_memory_posix.cpp
        math_gcc.cpp
        memory_posix.cpp
        platform/console_posix.cpp
        platform/env_posix.cpp
        seh_posix.cpp
        socket_posix.cpp
        system_posix.cpp
        threading_posix.cpp
    )
elseif(REXGLUE_PLATFORM_SWITCH)
    # Horizon/libnx/devkitA64. CMAKE_SYSTEM_NAME is Generic, so neither WIN32 nor
    # UNIX is set; most of the POSIX layer builds on newlib and the gaps go into
    # the *_switch.cpp files.
    target_sources(rexcore PRIVATE
        atomic_posix.cpp clock_posix.cpp dbg_posix.cpp
        filesystem_posix.cpp math_gcc.cpp
        platform/console_posix.cpp platform/env_posix.cpp
        socket_posix.cpp system_posix.cpp threading_posix.cpp
        threading_switch.cpp dynlib_switch.cpp exception_handler_switch.cpp
        fiber_switch.cpp guest_memory_switch.cpp mapped_memory_switch.cpp
        memory_switch.cpp seh_switch.cpp switch_libc_supplement.c
    )
endif()

# Xenos data-format layer (stateless; headers under include/rex/graphics/).
# The GPU emulation consuming it lives in the rexgpu-xenos plugin.
target_sources(rexcore PRIVATE
    ${PROJECT_SOURCE_DIR}/src/graphics/xenos.cpp
    ${PROJECT_SOURCE_DIR}/src/graphics/pipeline/texture/info.cpp
    ${PROJECT_SOURCE_DIR}/src/graphics/pipeline/texture/info_formats.cpp
    ${PROJECT_SOURCE_DIR}/src/graphics/pipeline/texture/extent.cpp
    ${PROJECT_SOURCE_DIR}/src/graphics/pipeline/texture/util.cpp
    ${PROJECT_SOURCE_DIR}/src/graphics/pipeline/texture/conversion.cpp
)

target_include_directories(rexcore PUBLIC
    $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
    $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include>
    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)

target_include_directories(rexcore PRIVATE
    ${PROJECT_SOURCE_DIR}
    ${PROJECT_SOURCE_DIR}/thirdparty/cli11/include
)

if(APPLE)
    target_link_libraries(rexcore PRIVATE pthread)
elseif(UNIX)
    target_link_libraries(rexcore PRIVATE pthread rt dl)
endif()

target_link_libraries(rexcore
    PUBLIC
        fmt::fmt
        simde
        tomlplusplus
        spdlog::spdlog
    PRIVATE
        disruptorplus
        utf8cpp
        xxHash::xxhash
)

if(REXGLUE_USE_D3D12)
    target_compile_definitions(rexcore PUBLIC REX_HAS_D3D12=1)
endif()
if(REXGLUE_USE_VULKAN)
    target_compile_definitions(rexcore PUBLIC REX_HAS_VULKAN=1)
endif()

if(REXGLUE_ENABLE_TRACY)
    target_link_libraries(rexcore PUBLIC
        $<$<NOT:$<CONFIG:Release>>:$<TARGET_NAME:TracyClient>>)
    target_compile_definitions(rexcore PUBLIC
        $<$<NOT:$<CONFIG:Release>>:REXGLUE_ENABLE_PROFILING>)
endif()

if(REXGLUE_ENABLE_PERF_COUNTERS)
    target_sources(rexcore PRIVATE perf/counter.cpp)
    target_compile_definitions(rexcore PUBLIC
        $<$<NOT:$<CONFIG:Release>>:REXGLUE_ENABLE_PERF_COUNTERS>)
endif()
