cmake_minimum_required(VERSION 3.14) project(ggufviewer LANGUAGES C CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # version.h: embed git commit hash into all binaries. # runs on every build, only rewrites if the hash changed. set(VERSION_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/version.h") add_custom_target(version ALL COMMAND "${CMAKE_COMMAND}" "-DSRC_DIR=${CMAKE_CURRENT_SOURCE_DIR}" "-DOUTPUT=${VERSION_OUTPUT}" -P "${CMAKE_CURRENT_SOURCE_DIR}/tools/version.cmake" BYPRODUCTS "${VERSION_OUTPUT}" COMMENT "Checking git version" ) # pthread: required explicitly on older glibc (< 2.34) where libpthread # is not merged into libc. Modern distros link it implicitly but aarch64 # and older x86_64 toolchains need the explicit dependency. find_package(Threads REQUIRED) # Suppress MSVC fopen/sprintf deprecation warnings if(MSVC) add_compile_definitions(_CRT_SECURE_NO_WARNINGS) endif() # Put executables and backend .so in the same directory (build root). # Without this, ggml defaults to bin/ for .so but executables stay in root, # and ggml_backend_load_all() can't find the backends at runtime. set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) # GGUF tensor names can exceed default GGML_MAX_NAME of 64 add_compile_definitions(GGML_MAX_NAME=128) # Harden: mark fread/fwrite/etc with warn_unused_result on all platforms if(NOT MSVC) add_compile_definitions(_FORTIFY_SOURCE=2) endif() # CUDA architectures: cover Turing to Blackwell for distributed binaries. # Users can override with -DCMAKE_CUDA_ARCHITECTURES=native for local builds. if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES) find_package(CUDAToolkit QUIET) if(CUDAToolkit_FOUND AND CUDAToolkit_VERSION VERSION_GREATER_EQUAL "12.8") set(CMAKE_CUDA_ARCHITECTURES "75-virtual;80-virtual;86-real;89-real;120a-real;121a-real") else() set(CMAKE_CUDA_ARCHITECTURES "75-virtual;80-virtual;86-real;89-real") endif() endif() # ggml as subdirectory, inherits GGML_CUDA, GGML_METAL, etc. from cmake flags add_subdirectory(ggml) # cpp-httplib (HTTP server library, used by gguf-viewer) add_subdirectory(vendor/cpp-httplib) # Shared compile options and ggml linkage macro(link_ggml_backends target) target_include_directories(${target} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) target_include_directories(${target} SYSTEM PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/ggml/include ) if(MSVC) target_compile_options(${target} PRIVATE /W4 /wd4100 /wd4505) else() target_compile_options(${target} PRIVATE -Wall -Wextra -Wshadow -Wconversion -Wno-unused-parameter -Wno-unused-function -Wno-sign-conversion) endif() target_link_libraries(${target} PRIVATE ggml Threads::Threads) if(TARGET ggml-base) target_link_libraries(${target} PRIVATE ggml-base) endif() foreach(backend cpu blas cuda metal vulkan) if(TARGET ggml-${backend}) get_target_property(CURRENT_BACKEND_TYPE ggml-${backend} TYPE) if (CURRENT_BACKEND_TYPE STREQUAL "MODULE_LIBRARY") # DL mode: backend is loaded at runtime via dlopen, # skip all link-time deps. continue() endif() target_link_libraries(${target} PRIVATE ggml-${backend}) endif() endforeach() add_dependencies(${target} version) endmacro() # webui: convert tools/public/index.html.gz to a C header for embedding. # the .gz is committed to git so the C++ build works without npm. # to update: cd tools/webui && npm install && npm run build, then rebuild. set(WEBUI_INPUT "${CMAKE_CURRENT_SOURCE_DIR}/tools/public/index.html.gz") set(WEBUI_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/index.html.gz.hpp") if(EXISTS "${WEBUI_INPUT}") add_custom_command( OUTPUT "${WEBUI_OUTPUT}" COMMAND "${CMAKE_COMMAND}" "-DINPUT=${WEBUI_INPUT}" "-DOUTPUT=${WEBUI_OUTPUT}" -P "${CMAKE_CURRENT_SOURCE_DIR}/tools/xxd.cmake" DEPENDS "${WEBUI_INPUT}" COMMENT "Embedding webui into index.html.gz.hpp" ) set_source_files_properties(${WEBUI_OUTPUT} PROPERTIES GENERATED TRUE) set(WEBUI_SOURCES ${WEBUI_OUTPUT}) set(WEBUI_DEFINE "VIEWER_HAS_WEBUI") else() set(WEBUI_SOURCES "") set(WEBUI_DEFINE "") message(STATUS "No webui found at ${WEBUI_INPUT}, building without embedded UI") endif() # gguf-viewer: HTTP server with embedded webui add_executable(gguf-viewer tools/gguf-viewer.cpp src/viewer-io.cpp src/viewer-tensor.cpp src/viewer-routes.cpp ${WEBUI_SOURCES} ) link_ggml_backends(gguf-viewer) target_include_directories(gguf-viewer SYSTEM PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/vendor ) target_link_libraries(gguf-viewer PRIVATE httplib) if(WEBUI_DEFINE) target_compile_definitions(gguf-viewer PRIVATE ${WEBUI_DEFINE}) endif()