cmake_minimum_required(VERSION 3.10)

project(yps-quickjs LANGUAGES C)

# 设置 C 标准
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS ON)

# 库版本号
set(YPQJS_VERSION_MAJOR 0)
set(YPQJS_VERSION_MINOR 1)
set(YPQJS_VERSION_PATCH 0)

# 构建类型默认为 Release
if(NOT CMAKE_BUILD_TYPE)
    message(STATUS "No build type selected, default to Release")
    set(CMAKE_BUILD_TYPE "Release")
endif()

message(STATUS "Building yps-quickjs in ${CMAKE_BUILD_TYPE} mode")
message(STATUS "Building with ${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION} on ${CMAKE_SYSTEM_NAME}")

# 包含编译器检查模块
include(CheckCCompilerFlag)
include(GNUInstallDirs)

# 平台检测
if(MINGW OR CMAKE_C_COMPILER MATCHES "mingw")
    set(MINGW TRUE)
else()
    set(MINGW FALSE)
endif()

# 添加编译器标志的宏
macro(xcheck_add_c_compiler_flag FLAG)
    string(REPLACE "-" "" FLAG_NO_HYPHEN ${FLAG})
    check_c_compiler_flag(${FLAG} COMPILER_SUPPORTS_${FLAG_NO_HYPHEN})
    if(COMPILER_SUPPORTS_${FLAG_NO_HYPHEN})
        add_compile_options(${FLAG})
    endif()
endmacro()

# 通用编译器警告标志
xcheck_add_c_compiler_flag(-Wall)
if(NOT MSVC AND NOT IOS)
    xcheck_add_c_compiler_flag(-Werror)
    xcheck_add_c_compiler_flag(-Wextra)
endif()
xcheck_add_c_compiler_flag(-Wformat=2)
xcheck_add_c_compiler_flag(-Wno-implicit-fallthrough)
xcheck_add_c_compiler_flag(-Wno-sign-compare)
xcheck_add_c_compiler_flag(-Wno-missing-field-initializers)
xcheck_add_c_compiler_flag(-Wno-unused-parameter)
xcheck_add_c_compiler_flag(-Wno-unused-but-set-variable)
xcheck_add_c_compiler_flag(-Wno-unused-result)
xcheck_add_c_compiler_flag(-Wno-stringop-truncation)
xcheck_add_c_compiler_flag(-Wno-array-bounds)
xcheck_add_c_compiler_flag(-funsigned-char)

# MSVC 特定标志
if(MSVC)
    xcheck_add_c_compiler_flag(-Wno-unsafe-buffer-usage)
    xcheck_add_c_compiler_flag(-Wno-sign-conversion)
    xcheck_add_c_compiler_flag(-Wno-nonportable-system-include-path)
    xcheck_add_c_compiler_flag(-Wno-implicit-int-conversion)
    xcheck_add_c_compiler_flag(-Wno-shorten-64-to-32)
    xcheck_add_c_compiler_flag(-Wno-reserved-macro-identifier)
    xcheck_add_c_compiler_flag(-Wno-reserved-identifier)
    xcheck_add_c_compiler_flag(-Wdeprecated-declarations)
    xcheck_add_c_compiler_flag(/experimental:c11atomics)
    xcheck_add_c_compiler_flag(/wd4018)
    xcheck_add_c_compiler_flag(/wd4061)
    xcheck_add_c_compiler_flag(/wd4100)
    xcheck_add_c_compiler_flag(/wd4200)
    xcheck_add_c_compiler_flag(/wd4242)
    xcheck_add_c_compiler_flag(/wd4244)
    xcheck_add_c_compiler_flag(/wd4245)
    xcheck_add_c_compiler_flag(/wd4267)
    xcheck_add_c_compiler_flag(/wd4388)
    xcheck_add_c_compiler_flag(/wd4389)
    xcheck_add_c_compiler_flag(/wd4456)
    xcheck_add_c_compiler_flag(/wd4457)
    xcheck_add_c_compiler_flag(/wd4710)
    xcheck_add_c_compiler_flag(/wd4711)
    xcheck_add_c_compiler_flag(/wd4820)
    xcheck_add_c_compiler_flag(/wd4996)
    xcheck_add_c_compiler_flag(/wd5045)
endif()

# Windows 特定配置
if(WIN32)
    # 设置 8MB 默认栈大小（Windows 默认为 1MB，会导致栈溢出）
    if(MSVC)
        set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:8388608")
    else()
        set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--stack,8388608")
    endif()
endif()

# macOS 和 GCC 11+ 特定配置
if(APPLE AND CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 11)
    xcheck_add_c_compiler_flag(-Wno-maybe-uninitialized)
endif()

# Debug 模式特定标志
if(CMAKE_BUILD_TYPE MATCHES "Debug")
    xcheck_add_c_compiler_flag(/Od)
    xcheck_add_c_compiler_flag(-O0)
    xcheck_add_c_compiler_flag(-ggdb)
    xcheck_add_c_compiler_flag(-fno-omit-frame-pointer)
endif()

# 构建选项
option(YPQJS_BUILD_SHARED_LIBS "Build shared library instead of static" OFF)
option(YPQJS_ENABLE_LIBC "Build libc extension as part of the library" ON)

message(STATUS "  YPQJS_BUILD_SHARED_LIBS: ${YPQJS_BUILD_SHARED_LIBS}")
message(STATUS "  YPQJS_ENABLE_LIBC: ${YPQJS_ENABLE_LIBC}")

# QuickJS 核心源文件
set(ypqjs_core_sources
    cutils.c
    dtoa.c
    libregexp.c
    libunicode.c
    quickjs.c
)

# 添加 libc 扩展（如果启用）
if(YPQJS_ENABLE_LIBC)
    list(APPEND ypqjs_core_sources quickjs-libc.c)
endif()

# 编译定义
list(APPEND ypqjs_defines _GNU_SOURCE)

if(WIN32)
    list(APPEND ypqjs_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0601)
endif()

# 链接库
list(APPEND ypqjs_libs ${CMAKE_DL_LIBS})

# 查找线程库
find_package(Threads)
if(NOT CMAKE_SYSTEM_NAME STREQUAL "WASI")
    list(APPEND ypqjs_libs ${CMAKE_THREAD_LIBS_INIT})
endif()

# 查找数学库
find_library(M_LIBRARIES m)
if(M_LIBRARIES OR CMAKE_C_COMPILER_ID STREQUAL "TinyCC")
    list(APPEND ypqjs_libs m)
endif()

# 创建 yps-quickjs 库
if(YPQJS_BUILD_SHARED_LIBS)
    add_library(ypqjs SHARED ${ypqjs_core_sources})
    message(STATUS "Building shared library: ypqjs")
else()
    add_library(ypqjs STATIC ${ypqjs_core_sources})
    message(STATUS "Building static library: ypqjs")
endif()

# 设置库属性
target_compile_definitions(ypqjs PRIVATE ${ypqjs_defines})
target_include_directories(ypqjs PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
target_link_libraries(ypqjs PUBLIC ${ypqjs_libs})

# 设置库版本
set_target_properties(ypqjs PROPERTIES
    VERSION ${YPQJS_VERSION_MAJOR}.${YPQJS_VERSION_MINOR}.${YPQJS_VERSION_PATCH}
    SOVERSION ${YPQJS_VERSION_MAJOR}
    OUTPUT_NAME "ypqjs"
)

# 安装配置
install(FILES quickjs.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
if(YPQJS_ENABLE_LIBC)
    install(FILES quickjs-libc.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
endif()
install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR})

install(TARGETS ypqjs EXPORT ypqjsConfig
        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})

install(EXPORT ypqjsConfig DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/yps-quickjs)

# 导出 CMake 配置供其他项目使用
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
    "${CMAKE_CURRENT_BINARY_DIR}/yps-quickjs-config-version.cmake"
    VERSION ${YPQJS_VERSION_MAJOR}.${YPQJS_VERSION_MINOR}.${YPQJS_VERSION_PATCH}
    COMPATIBILITY SameMajorVersion
)

configure_package_config_file(
    "${CMAKE_CURRENT_SOURCE_DIR}/yps-quickjs-config.cmake.in"
    "${CMAKE_CURRENT_BINARY_DIR}/yps-quickjs-config.cmake"
    INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/yps-quickjs
)

install(
    FILES
        "${CMAKE_CURRENT_BINARY_DIR}/yps-quickjs-config.cmake"
        "${CMAKE_CURRENT_BINARY_DIR}/yps-quickjs-config-version.cmake"
    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/yps-quickjs
)