# gguf.cpp / quantizer — the GGUF quantizer library.
#
# Standalone, this component was deliberately ggml-free: it carried a verbatim
# copy of ggml-quants.c plus a shim (qz-traits.c / qz-init.cpp) re-implementing
# the type-trait table and ggml_quantize_chunk(). In the unified engine those
# kernels are already here — the same ones the LLM server and the diffusion
# runtime run on — so the copy is gone and this links ggml-base instead. Only
# src/kernels/qz-compat.c remains, for the two helpers ggml does not have.
#
# The standalone tree's `quantizer` CLI is not built: the editor panel drives
# the library through ctypes, so src/main.cpp is not vendored either.
#
# The GPU quantization paths (device_gpu.cu, device_metal.mm) are the
# quantizer's own kernels and stay independent of the ggml backends.

set(QUANTIZER_SOURCES
    src/quantize.cpp
    src/quantize.h
    src/gguf_io.cpp
    src/gguf_io.h
    src/safetensors_io.cpp
    src/safetensors_io.h
    src/device.cpp
    src/device.h
    src/kernels/qz-compat.c
    src/kernels/qz-ggml.h
)

if(QUANTIZER_CUDA)
    enable_language(CUDA)
    if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES)
        set(CMAKE_CUDA_ARCHITECTURES "75;80;86;87;89;90;100;120")
    endif()
    list(APPEND QUANTIZER_SOURCES src/device_gpu.cu src/device_gpu.h)
endif()

if(QUANTIZER_HIP)
    enable_language(HIP)
    list(APPEND QUANTIZER_SOURCES src/device_gpu.cu src/device_gpu.h)
    set_source_files_properties(src/device_gpu.cu PROPERTIES LANGUAGE HIP)
endif()

if(QUANTIZER_METAL)
    if(NOT APPLE)
        message(FATAL_ERROR "gguf.cpp: QUANTIZER_METAL requires macOS")
    endif()
    enable_language(OBJCXX)
    list(APPEND QUANTIZER_SOURCES src/device_metal.mm src/device_metal.h)
    set_source_files_properties(src/device_metal.mm PROPERTIES COMPILE_OPTIONS "-fobjc-arc")
endif()

# Shared library, and only that: the editor panel loads it through ctypes, so
# the standalone tree's `quantizer` CLI is not built here.
add_library(gguf_quantizer SHARED ${QUANTIZER_SOURCES})
target_include_directories(gguf_quantizer PUBLIC src)
target_compile_definitions(gguf_quantizer PRIVATE GGUF_QUANTIZER_BUILD PUBLIC GGUF_QUANTIZER_SHARED)

# ggml-base carries the quantization kernels, the type traits and gguf.cpp's
# GGUF reader; the compute backends are not needed here.
target_link_libraries(gguf_quantizer PRIVATE ggml-base)

if(QUANTIZER_CUDA)
    find_package(CUDAToolkit REQUIRED)
    target_compile_definitions(gguf_quantizer PRIVATE QZ_USE_CUDA)
    target_link_libraries(gguf_quantizer PRIVATE CUDA::cudart)
endif()

if(QUANTIZER_HIP)
    find_package(hip REQUIRED)
    target_compile_definitions(gguf_quantizer PRIVATE QZ_USE_HIP)
    target_link_libraries(gguf_quantizer PRIVATE hip::host)
endif()

if(QUANTIZER_METAL)
    target_compile_definitions(gguf_quantizer PRIVATE QZ_USE_METAL)
    find_library(FOUNDATION_FRAMEWORK Foundation REQUIRED)
    find_library(METAL_FRAMEWORK Metal REQUIRED)
    target_link_libraries(gguf_quantizer PRIVATE ${FOUNDATION_FRAMEWORK} ${METAL_FRAMEWORK})
endif()

find_package(Threads REQUIRED)
target_link_libraries(gguf_quantizer PRIVATE Threads::Threads)

set_target_properties(gguf_quantizer PROPERTIES
    CXX_VISIBILITY_PRESET hidden
    C_VISIBILITY_PRESET hidden
    VISIBILITY_INLINES_HIDDEN ON
)
if(WIN32)
    set_target_properties(gguf_quantizer PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
endif()

# portable optimization baseline for the scalar kernels; the hot loops
# vectorize well under -O3 without requiring -march=native
if(NOT MSVC)
    target_compile_options(gguf_quantizer PRIVATE
        $<$<COMPILE_LANGUAGE:C>:-O3>
        $<$<COMPILE_LANGUAGE:CXX>:-O3>
    )
endif()

# Keep the shipped runtime deps resolvable next to the library.
if(APPLE)
    set_target_properties(gguf_quantizer PROPERTIES
        INSTALL_RPATH "@loader_path" BUILD_WITH_INSTALL_RPATH TRUE)
elseif(UNIX)
    set_target_properties(gguf_quantizer PROPERTIES
        INSTALL_RPATH "$ORIGIN" BUILD_WITH_INSTALL_RPATH TRUE)
endif()

if(MINGW)
    # -static-libgcc/-static-libstdc++ alone still leave a dynamic dependency on
    # libwinpthread-1.dll, which is not shipped in the wheel; -static folds it
    # (and any other MinGW runtime) into the DLL.
    target_link_options(gguf_quantizer PRIVATE -static -static-libgcc -static-libstdc++)
elseif(UNIX AND NOT APPLE)
    # Apple Clang uses the system libc++/compiler runtime and rejects these.
    target_link_options(gguf_quantizer PRIVATE -static-libgcc -static-libstdc++)
endif()

if(GGUF_CPP_INSTALL)
    install(TARGETS gguf_quantizer
        RUNTIME DESTINATION bin
        LIBRARY DESTINATION bin
    )
endif()
