cmake_minimum_required(VERSION 3.15)
project(c4e2e_crypto VERSION 2.5.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# ── OpenSSL (3.0+ recommended; 1.1.1 supported via compile-time guard) ──────
# macOS wheel builds only: link OpenSSL statically so the wheel is
# self-contained and delocate-wheel can complete the repair step without
# needing to bundle external dylib files.
#
# Linux wheel builds use dynamic linking — auditwheel repair bundles
# libssl.so / libcrypto.so into the wheel automatically (the same approach
# used by the cryptography package). openssl-static is not reliably
# available in the manylinux container's default repositories.
#
# Windows always links dynamically; delvewheel handles DLL bundling.
if(DEFINED SKBUILD_PLATLIB_DIR AND APPLE)
    set(OPENSSL_USE_STATIC_LIBS ON)
endif()

find_package(OpenSSL 1.1.1 REQUIRED)
message(STATUS "OpenSSL version: ${OPENSSL_VERSION}")
message(STATUS "OpenSSL include: ${OPENSSL_INCLUDE_DIR}")

# ── Shared library target ─────────────────────────────────────────────────────
add_library(c4e2e_crypto SHARED
    src/c4e2e_crypto.cpp
)

target_include_directories(c4e2e_crypto
    PUBLIC  include/
    PRIVATE src/
)

target_link_libraries(c4e2e_crypto
    PRIVATE OpenSSL::SSL OpenSSL::Crypto
)

# Only symbols explicitly marked C4E2E_EXPORT are visible. All C++ internals
# (KeyRegistry, PlaintextRegistry, SecureBuf, helpers) are hidden at link time.
set_target_properties(c4e2e_crypto PROPERTIES
    CXX_VISIBILITY_PRESET    hidden
    VISIBILITY_INLINES_HIDDEN ON
    POSITION_INDEPENDENT_CODE ON
)

# ── Hardened compiler flags ───────────────────────────────────────────────────
if(MSVC)
    target_compile_options(c4e2e_crypto PRIVATE
        /W4           # High warning level
        /WX           # Warnings as errors
        /GS           # Stack buffer security check (canaries)
        /guard:cf     # Control Flow Guard
        /sdl          # Additional Security Development Lifecycle checks
    )
    target_link_options(c4e2e_crypto PRIVATE
        /DYNAMICBASE  # ASLR — randomise load address
        /NXCOMPAT     # DEP / NX — mark stack and heap non-executable
    )
else()
    target_compile_options(c4e2e_crypto PRIVATE
        -Wall
        -Wextra
        -Werror
        -Wformat=2
        -Wformat-security
        -fstack-protector-strong
        -fPIC
        -fvisibility=hidden
        $<$<NOT:$<CONFIG:Debug>>:-D_FORTIFY_SOURCE=2>
    )
    # Full RELRO + NX stack on Linux ELF targets
    if(NOT APPLE)
        target_link_options(c4e2e_crypto PRIVATE
            -Wl,-z,relro
            -Wl,-z,now
            -Wl,-z,noexecstack
        )
    endif()
endif()

# ── Release build: strip internal symbols ─────────────────────────────────────
if(NOT MSVC)
    target_link_options(c4e2e_crypto PRIVATE
        $<$<CONFIG:Release>:-Wl,-s>
    )
endif()

# ── Output name / install ─────────────────────────────────────────────────────
# The shared library is named c4e2e_crypto (.dll / .so / .dylib).
# When installed into a scikit-build-core wheel the install prefix is the
# Python package directory; the ctypes loader in _native/ finds it there.
set_target_properties(c4e2e_crypto PROPERTIES OUTPUT_NAME "c4e2e_crypto")

install(TARGETS c4e2e_crypto
    RUNTIME DESTINATION "${SKBUILD_PLATLIB_DIR}/c4e2e/_native"   # .dll (Windows)
    LIBRARY DESTINATION "${SKBUILD_PLATLIB_DIR}/c4e2e/_native"   # .so / .dylib
)
install(FILES include/c4e2e_crypto.h
    DESTINATION "${SKBUILD_PLATLIB_DIR}/c4e2e/_native/include"
)

# ── Standalone build (outside scikit-build-core) ──────────────────────────────
# When built with: cmake -B build native && cmake --build build
# the output lands in build/Release/ (MSVC) or build/ (GCC/Clang).
if(NOT DEFINED SKBUILD_PLATLIB_DIR)
    # Override install prefix to a local build/ subdirectory for dev builds.
    install(TARGETS c4e2e_crypto
        RUNTIME DESTINATION "${CMAKE_BINARY_DIR}/dist"
        LIBRARY DESTINATION "${CMAKE_BINARY_DIR}/dist"
    )
endif()
