# Copyright 2026 Cavanşir Qurbanzadə. SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.26)
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/release/release.json" release_json)
string(JSON release_version GET "${release_json}" version)
project(YLSpec VERSION ${release_version} LANGUAGES C)
include(GNUInstallDirs)
include(CTest)
option(YLSPEC_BUILD_PYTHON "Build the CPython extension" OFF)
option(YLSPEC_BUILD_CLI "Build the inspection CLI" ON)
option(YLSPEC_SANITIZE "Enable address and undefined behavior sanitizers" OFF)
option(YLSPEC_FUZZ "Build the libFuzzer target (Clang only)" OFF)
option(YLSPEC_BUILD_NODE "Build the stable Node-API addon" OFF)
option(YLSPEC_BUILD_JNI "Build the Java and Android JNI bridge" OFF)
option(YLSPEC_BUILD_WASM "Build the browser WebAssembly module" OFF)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
if(YLSPEC_SANITIZE AND NOT MSVC)
  add_compile_options(-fsanitize=address,undefined -fno-omit-frame-pointer)
  add_link_options(-fsanitize=address,undefined)
endif()
add_library(ylspec src/ylspec.c vendor/tomlc17/tomlc17.c)
add_library(YLSpec::ylspec ALIAS ylspec)
set_target_properties(ylspec PROPERTIES POSITION_INDEPENDENT_CODE ON C_VISIBILITY_PRESET hidden VERSION ${PROJECT_VERSION} SOVERSION 0)
target_compile_definitions(ylspec PRIVATE YLSPEC_BUILD YLSPEC_VERSION="${PROJECT_VERSION}")
if(BUILD_SHARED_LIBS)
  target_compile_definitions(ylspec PUBLIC YLSPEC_SHARED)
endif()
target_include_directories(ylspec PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> PRIVATE vendor/tomlc17)
if(NOT MSVC)
  target_link_libraries(ylspec PRIVATE m)
  set_source_files_properties(src/ylspec.c PROPERTIES COMPILE_OPTIONS "-Wall;-Wextra;-Wpedantic;-Wno-misleading-indentation")
endif()
if(YLSPEC_BUILD_NODE OR YLSPEC_BUILD_JNI OR YLSPEC_BUILD_WASM)
  add_library(ylspec_bridge STATIC bindings/common/bridge.c)
  set_target_properties(ylspec_bridge PROPERTIES POSITION_INDEPENDENT_CODE ON)
  target_include_directories(ylspec_bridge PUBLIC bindings/common)
  target_link_libraries(ylspec_bridge PUBLIC YLSpec::ylspec)
endif()
if(YLSPEC_BUILD_NODE)
  if(NOT EXISTS "${NODE_INCLUDE_DIR}/node_api.h")
    message(FATAL_ERROR "Set NODE_INCLUDE_DIR to the Node headers directory")
  endif()
  add_library(ylspec_node MODULE bindings/node/addon.c)
  target_include_directories(ylspec_node PRIVATE "${NODE_INCLUDE_DIR}")
  target_compile_definitions(ylspec_node PRIVATE NAPI_VERSION=8)
  target_link_libraries(ylspec_node PRIVATE ylspec_bridge)
  if(WIN32)
    target_link_libraries(ylspec_node PRIVATE "${NODE_LIBRARY}")
  elseif(APPLE)
    target_link_options(ylspec_node PRIVATE -undefined dynamic_lookup)
  endif()
  set_target_properties(ylspec_node PROPERTIES PREFIX "" SUFFIX ".node")
endif()
if(YLSPEC_BUILD_JNI)
  if(NOT ANDROID)
    find_package(JNI REQUIRED)
  endif()
  add_library(ylspec_jni SHARED bindings/jni/jni.c)
  target_include_directories(ylspec_jni PRIVATE ${JNI_INCLUDE_DIRS})
  target_link_libraries(ylspec_jni PRIVATE ylspec_bridge)
endif()
if(YLSPEC_BUILD_WASM)
  if(NOT EMSCRIPTEN)
    message(FATAL_ERROR "Use the Emscripten CMake toolchain for WebAssembly")
  endif()
  add_executable(ylspec_web bindings/wasm/web.c)
  target_link_libraries(ylspec_web PRIVATE ylspec_bridge)
  set_target_properties(ylspec_web PROPERTIES OUTPUT_NAME core SUFFIX ".mjs")
  target_link_options(ylspec_web PRIVATE --no-entry -sMODULARIZE=1 -sEXPORT_ES6=1 -sENVIRONMENT=web,worker,node -sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=268435456 -sSTACK_SIZE=2097152 -sABORTING_MALLOC=0 "-sEXPORTED_RUNTIME_METHODS=['HEAPU8']" "-sEXPORTED_FUNCTIONS=['_malloc','_free','_yl_web_process','_yl_web_data','_yl_web_size','_yl_web_message','_yl_web_offset','_yl_web_line','_yl_web_column']")
endif()
if(YLSPEC_BUILD_CLI)
  add_executable(ylspec_cli src/cli.c)
  set_target_properties(ylspec_cli PROPERTIES OUTPUT_NAME ylspec)
  target_link_libraries(ylspec_cli PRIVATE YLSpec::ylspec)
  install(TARGETS ylspec_cli RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT native)
endif()
if(YLSPEC_BUILD_PYTHON)
  find_package(Python 3.11 REQUIRED COMPONENTS Interpreter Development.SABIModule)
  Python_add_library(_native MODULE USE_SABI 3.11 WITH_SOABI python/ylspec/_native.c)
  target_link_libraries(_native PRIVATE YLSpec::ylspec)
  install(TARGETS _native LIBRARY DESTINATION ylspec COMPONENT python RUNTIME DESTINATION ylspec COMPONENT python)
endif()
if(BUILD_TESTING)
  add_executable(ylspec_toml_decoder vendor/tomlc17/conformance.c)
  if(NOT MSVC)
    target_link_libraries(ylspec_toml_decoder PRIVATE m)
  endif()
  add_executable(ylspec_tests tests/test_core.c)
  target_link_libraries(ylspec_tests PRIVATE YLSpec::ylspec)
  add_test(NAME core COMMAND ylspec_tests)
  add_executable(ylspec_c_example examples/basic.c)
  target_link_libraries(ylspec_c_example PRIVATE YLSpec::ylspec)
  add_test(NAME c_example COMMAND ylspec_c_example)
  if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/build/docs/readme.c")
    add_executable(ylspec_readme_example build/docs/readme.c)
    target_link_libraries(ylspec_readme_example PRIVATE YLSpec::ylspec)
    add_test(NAME readme_c_example COMMAND ylspec_readme_example)
  endif()
endif()
if(YLSPEC_FUZZ)
  add_executable(ylspec_fuzz tests/fuzz.c src/ylspec.c bindings/common/bridge.c vendor/tomlc17/tomlc17.c)
  target_include_directories(ylspec_fuzz PRIVATE include vendor/tomlc17 bindings/common)
  target_compile_options(ylspec_fuzz PRIVATE -fsanitize=fuzzer,address,undefined -fno-omit-frame-pointer)
  target_link_options(ylspec_fuzz PRIVATE -fsanitize=fuzzer,address,undefined)
endif()
install(TARGETS ylspec EXPORT YLSpecTargets ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT native)
install(FILES include/ylspec.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT native)
install(EXPORT YLSpecTargets NAMESPACE YLSpec:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/YLSpec COMPONENT native)
include(CMakePackageConfigHelpers)
configure_package_config_file(cmake/YLSpecConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/YLSpecConfig.cmake INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/YLSpec)
write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/YLSpecConfigVersion.cmake VERSION ${PROJECT_VERSION} COMPATIBILITY SameMinorVersion)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/YLSpecConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/YLSpecConfigVersion.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/YLSpec COMPONENT native)
install(FILES LICENSE NOTICE THIRD_PARTY_NOTICES.md DESTINATION ${CMAKE_INSTALL_DATADIR}/ylspec COMPONENT native)
install(FILES vendor/tomlc17/LICENSE DESTINATION ${CMAKE_INSTALL_DATADIR}/ylspec/third_party/tomlc17 COMPONENT native)
