cmake_minimum_required(VERSION 3.14...3.28) # for add_link_options and implicit target directories.
project("gguf-cpp" C CXX)

#
# gguf.cpp: the unified engine — LLM server + diffusion + quantizer, all
# compiled from one tree against one shared copy of the ggml kernels.
#
#   kernels/     ggml compute kernels (CPU + optional GPU backends), shared
#   src/         the GGUF model runtime (libllama)
#   common/      argument parsing, chat templates, sampling, logging
#   mtmd/        multimodal (vision/audio) projector support
#   app/         the gguf-server HTTP server
#   ui/          embedded web UI assets (optional, empty by default)
#   diffusion/   the diffusion runtime + `diffusion` CLI (links shared ggml)
#   quantizer/   the standalone quantizer shared library (shares ggml-quants)
#   thirdparty/  cpp-httplib, nlohmann/json, stb, miniaudio, subprocess.h
#
# There is no vendored llama.cpp checkout and no external ggml: everything is
# compiled from the sources in this directory, in a single build.
#

set(CMAKE_WARN_UNUSED_CLI YES)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

if (NOT XCODE AND NOT MSVC AND NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
    set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()

message("CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

set(CMAKE_C_STANDARD          11)
set(CMAKE_C_STANDARD_REQUIRED true)
set(CMAKE_CXX_STANDARD        17)
set(CMAKE_CXX_STANDARD_REQUIRED true)

if (MINGW OR EMSCRIPTEN)
    set(BUILD_SHARED_LIBS_DEFAULT OFF)
else()
    set(BUILD_SHARED_LIBS_DEFAULT ON)
endif()

option(BUILD_SHARED_LIBS "build shared libraries" ${BUILD_SHARED_LIBS_DEFAULT})

if (WIN32)
    add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
endif()

if (MSVC)
    add_compile_options("$<$<COMPILE_LANGUAGE:C>:/utf-8>")
    add_compile_options("$<$<COMPILE_LANGUAGE:CXX>:/utf-8>")
    add_compile_options("$<$<COMPILE_LANGUAGE:C>:/bigobj>")
    add_compile_options("$<$<COMPILE_LANGUAGE:CXX>:/bigobj>")
    list(APPEND CMAKE_VS_GLOBALS UseMultiToolTask=true)
    list(APPEND CMAKE_VS_GLOBALS EnforceProcessCountAcrossBuilds=true)
endif()

#
# Options
#

# backends - these simply forward to the matching ggml option
option(GGUF_SERVER_CUDA     "gguf-server: CUDA backend"                     OFF)
option(GGUF_SERVER_HIP      "gguf-server: ROCm/HIP backend"                 OFF)
option(GGUF_SERVER_METAL    "gguf-server: Metal backend"                    ${APPLE})
option(GGUF_SERVER_VULKAN   "gguf-server: Vulkan backend"                   OFF)
option(GGUF_SERVER_BLAS     "gguf-server: BLAS backend"                     OFF)

# features
option(GGUF_SERVER_OPENSSL  "gguf-server: use OpenSSL for HTTPS model downloads"    ON)
option(GGUF_SERVER_INSTALL  "gguf-server: install the binary on `cmake --install`"  ON)

# subprocess spawning powers `--models` router mode; not available everywhere
if (CMAKE_SYSTEM_NAME STREQUAL "iOS" OR CMAKE_SYSTEM_NAME STREQUAL "Android" OR ANDROID
        OR CMAKE_SYSTEM_NAME STREQUAL "Emscripten" OR EMSCRIPTEN)
    set(GGUF_SERVER_SUBPROCESS_DEFAULT OFF)
else()
    set(GGUF_SERVER_SUBPROCESS_DEFAULT ON)
endif()
option(GGUF_SERVER_SUBPROCESS "gguf-server: support router mode (spawns child servers)" ${GGUF_SERVER_SUBPROCESS_DEFAULT})

# diagnostics
option(GGUF_SERVER_ALL_WARNINGS      "gguf-server: enable all compiler warnings" ON)
option(GGUF_SERVER_FATAL_WARNINGS    "gguf-server: enable -Werror flag"          OFF)
option(GGUF_SERVER_SANITIZE_THREAD    "gguf-server: enable thread sanitizer"     OFF)
option(GGUF_SERVER_SANITIZE_ADDRESS   "gguf-server: enable address sanitizer"    OFF)
option(GGUF_SERVER_SANITIZE_UNDEFINED "gguf-server: enable undefined sanitizer"  OFF)

# the vendored sources still use the LLAMA_* names internally
set(LLAMA_ALL_WARNINGS       ${GGUF_SERVER_ALL_WARNINGS})
set(LLAMA_FATAL_WARNINGS     ${GGUF_SERVER_FATAL_WARNINGS})
set(LLAMA_SANITIZE_THREAD    ${GGUF_SERVER_SANITIZE_THREAD})
set(LLAMA_SANITIZE_ADDRESS   ${GGUF_SERVER_SANITIZE_ADDRESS})
set(LLAMA_SANITIZE_UNDEFINED ${GGUF_SERVER_SANITIZE_UNDEFINED})
set(LLAMA_SUBPROCESS         ${GGUF_SERVER_SUBPROCESS})
set(LLAMA_OPENSSL            ${GGUF_SERVER_OPENSSL})

if (GGUF_SERVER_CUDA)
    message(STATUS "gguf-server: CUDA backend enabled")
    set(GGML_CUDA ON)
endif()
if (GGUF_SERVER_HIP)
    message(STATUS "gguf-server: HIP backend enabled")
    set(GGML_HIP ON)
    # ggml-hip's device-stub objects must be position-independent, or the
    # default-PIE executable link fails on distros that default to PIE
    set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
if (GGUF_SERVER_METAL)
    message(STATUS "gguf-server: Metal backend enabled")
    set(GGML_METAL ON)
endif()
if (GGUF_SERVER_VULKAN)
    message(STATUS "gguf-server: Vulkan backend enabled")
    set(GGML_VULKAN ON)
endif()
if (GGUF_SERVER_BLAS)
    message(STATUS "gguf-server: BLAS backend enabled")
    set(GGML_BLAS ON)
endif()

#
# Version / build info
#

include(build-info)
include(common)

if (NOT DEFINED LLAMA_BUILD_NUMBER)
    set(LLAMA_BUILD_NUMBER ${BUILD_NUMBER})
endif()
if (NOT DEFINED LLAMA_BUILD_COMMIT)
    set(LLAMA_BUILD_COMMIT ${BUILD_COMMIT})
endif()
set(LLAMA_INSTALL_VERSION 0.0.${LLAMA_BUILD_NUMBER})

#
# ggml options that the runtime relies on
#

set(GGML_ALL_WARNINGS   ${LLAMA_ALL_WARNINGS})
set(GGML_FATAL_WARNINGS ${LLAMA_FATAL_WARNINGS})

if (NOT DEFINED GGML_LLAMAFILE)
    set(GGML_LLAMAFILE_DEFAULT ON)
endif()
if (NOT DEFINED GGML_CUDA_GRAPHS)
    set(GGML_CUDA_GRAPHS_DEFAULT ON)
endif()

set(GGML_BUILD_NUMBER ${LLAMA_BUILD_NUMBER})
set(GGML_BUILD_COMMIT ${LLAMA_BUILD_COMMIT})

#
# Build
#

# Diffusion models carry tensor names longer than ggml's default 64-byte
# cap. GGML_MAX_NAME sizes a field inside struct ggml_tensor, so it must be
# identical for every consumer of the shared kernels — set it globally
# before anything compiles.
add_compile_definitions(GGML_MAX_NAME=128)

add_subdirectory(kernels)            # ggml (shared by everything below)
add_subdirectory(src)                # llama
add_subdirectory(thirdparty/cpp-httplib)
add_subdirectory(common)             # llama-common
add_subdirectory(mtmd)               # multimodal
add_subdirectory(ui)                 # embedded web UI assets
add_subdirectory(app)                # the gguf-server binary
add_subdirectory(diffusion)          # diffusion runtime + CLI
add_subdirectory(quantizer)          # quantizer shared library
