Commit ccdbe2905 for llama.cpp

commit ccdbe290533f68154ede46e0618622eebcb6c070
Author: Georgi Gerganov <ggerganov@gmail.com>
Date:   Mon Oct 12 13:32:56 2026 +0300

    tests : link each test against only the libraries it uses (#30299)

    Give llama_build() and llama_build_and_test() a LINK keyword (default:
    llama-common) so call sites can declare what a test actually needs:

    - ggml-only tests now link just ggml: test-opt, test-metal-graph-optimize,
      test-backend-ops, test-tiled-mulmat, test-barrier, test-quantize-fns,
      test-quantize-perf, test-rope, test-col2im-1d, test-gguf, test-alloc
    - llama-only tests drop llama-common: test-unicode, test-sampling,
      test-grammar-parser, test-llama-grammar, test-batch-alloc,
      test-gbnf-validator, test-quant-type-selection
    - both mtmd tests link mtmd only, dropping the LLAMA_TEST_NAME /
      target_link_libraries workarounds

    Both helpers now set cxx_std_17 explicitly, since the tests no longer
    inherit it from llama-common's PUBLIC interface.

    tests/testing.h no longer includes common.h; the only symbol it used from
    there (string_join) is inlined.

    Assisted-by: pi:llama.cpp/Qwen3.8-Flash-Next

diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index a732b6d65..daccea063 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -1,7 +1,18 @@
 llama_add_compile_flags()

+# Optional args:
+# - LINK: libraries to link against (defaults to llama-common, which also brings llama)
 function(llama_build source)
-    set(TEST_SOURCES ${source} ${ARGN})
+    set(options)
+    set(oneValueArgs)
+    set(multiValueArgs LINK)
+    cmake_parse_arguments(LLAMA_BUILD "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+    set(TEST_SOURCES ${source} ${LLAMA_BUILD_UNPARSED_ARGUMENTS})
+
+    if (NOT LLAMA_BUILD_LINK)
+        set(LLAMA_BUILD_LINK llama-common)
+    endif()

     if (DEFINED LLAMA_TEST_NAME)
         set(TEST_TARGET ${LLAMA_TEST_NAME})
@@ -10,7 +21,8 @@ function(llama_build source)
     endif()

     add_executable(${TEST_TARGET} ${TEST_SOURCES})
-    target_link_libraries(${TEST_TARGET} PRIVATE llama llama-common) # TODO: [TAG_TESTS_LLAMA_LINK]
+    target_compile_features(${TEST_TARGET} PRIVATE cxx_std_17)
+    target_link_libraries(${TEST_TARGET} PRIVATE ${LLAMA_BUILD_LINK})
     if (LLAMA_TESTS_INSTALL)
         install(TARGETS ${TEST_TARGET} RUNTIME)
     endif()
@@ -80,15 +92,20 @@ endfunction()
 # - LABEL: label for the test (defaults to main)
 # - ARGS: arguments to pass to the test executable
 # - WORKING_DIRECTORY
+# - LINK: libraries to link against (defaults to llama-common, which also brings llama)
 function(llama_build_and_test source)
     include(CMakeParseArguments)
     set(options)
     set(oneValueArgs NAME LABEL WORKING_DIRECTORY)
-    set(multiValueArgs ARGS)
+    set(multiValueArgs ARGS LINK)
     cmake_parse_arguments(LLAMA_TEST "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

     set(TEST_SOURCES ${source} ${LLAMA_TEST_UNPARSED_ARGUMENTS})

+    if (NOT LLAMA_TEST_LINK)
+        set(LLAMA_TEST_LINK llama-common)
+    endif()
+
     if (NOT DEFINED LLAMA_TEST_LABEL)
         set(LLAMA_TEST_LABEL "main")
     endif()
@@ -102,10 +119,11 @@ function(llama_build_and_test source)
     endif()

     add_executable(${TEST_TARGET} ${TEST_SOURCES})
+    target_compile_features(${TEST_TARGET} PRIVATE cxx_std_17)
     if (LLAMA_TESTS_INSTALL)
         install(TARGETS ${TEST_TARGET} RUNTIME)
     endif()
-    target_link_libraries(${TEST_TARGET} PRIVATE llama-common)
+    target_link_libraries(${TEST_TARGET} PRIVATE ${LLAMA_TEST_LINK})

     add_test(
         NAME ${TEST_TARGET}
@@ -153,13 +171,13 @@ llama_build(test-save-load-state.cpp)

 if (NOT WIN32 OR NOT BUILD_SHARED_LIBS)
     # these tests are disabled on Windows because they use internal functions not exported with LLAMA_API (when building with shared libraries)
-    llama_build_and_test(test-unicode.cpp)
-    llama_build_and_test(test-sampling.cpp)
+    llama_build_and_test(test-unicode.cpp LINK llama)
+    llama_build_and_test(test-sampling.cpp LINK llama)
     llama_build_and_test(test-reasoning-budget.cpp)
-    llama_build_and_test(test-grammar-parser.cpp)
+    llama_build_and_test(test-grammar-parser.cpp LINK llama)
     llama_build_and_test(test-grammar-integration.cpp)
-    llama_build_and_test(test-llama-grammar.cpp)
-    llama_build_and_test(test-batch-alloc.cpp)
+    llama_build_and_test(test-llama-grammar.cpp LINK llama)
+    llama_build_and_test(test-batch-alloc.cpp LINK llama)
     llama_build_and_test(test-chat.cpp WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
     target_include_directories(test-chat PRIVATE ${PROJECT_SOURCE_DIR}/tools/server)
     target_link_libraries(test-chat PRIVATE server-context)
@@ -172,7 +190,7 @@ if (NOT WIN32 OR NOT BUILD_SHARED_LIBS)
         llama_build(test-quantize-stats.cpp)
     endif()

-    llama_build(test-gbnf-validator.cpp)
+    llama_build(test-gbnf-validator.cpp LINK llama)

     # build test-tokenizer-1-bpe target once and add many tests
     llama_build(test-tokenizer-1-bpe.cpp)
@@ -280,19 +298,17 @@ target_link_libraries(test-model-resolution PRIVATE cpp-httplib)

 if (NOT LLAMA_SANITIZE_ADDRESS AND NOT GGML_SCHED_NO_REALLOC)
   # TODO: repair known memory leaks
-  llama_build_and_test(test-opt.cpp)
+  llama_build_and_test(test-opt.cpp LINK ggml)
 endif()
 if (GGML_METAL AND NOT GGML_BACKEND_DL)
     # calls the Metal backend's graph optimizer and fusion table directly
-    llama_build_and_test(test-metal-graph-optimize.cpp)
+    llama_build_and_test(test-metal-graph-optimize.cpp LINK ggml ggml-metal)
     target_include_directories(test-metal-graph-optimize PRIVATE ${PROJECT_SOURCE_DIR}/ggml/src ${PROJECT_SOURCE_DIR}/ggml/src/ggml-metal)
-    target_link_libraries(test-metal-graph-optimize PRIVATE ggml-metal)
 endif()

-# TODO: make this test (and others) not link `libllama` as it is not needed [TAG_TESTS_LLAMA_LINK]
-llama_build(test-backend-ops.cpp)
+llama_build(test-backend-ops.cpp LINK ggml)

-llama_build_and_test(test-tiled-mulmat.cpp)
+llama_build_and_test(test-tiled-mulmat.cpp LINK ggml)
 llama_build_and_test(test-model-load-cancel.cpp LABEL "model")
 llama_build_and_test(test-autorelease.cpp       LABEL "model")
 llama_build_and_test(test-backend-sampler.cpp   LABEL "model")
@@ -309,21 +325,17 @@ endif()

 if (NOT GGML_BACKEND_DL AND GGML_CPU)
     # these tests use the backends directly and cannot be built with dynamic loading
-    llama_build_and_test(test-barrier.cpp)
-    llama_build_and_test(test-quantize-fns.cpp)
-    llama_build_and_test(test-quantize-perf.cpp)
-    llama_build_and_test(test-rope.cpp)
-    llama_build_and_test(test-col2im-1d.cpp)
+    llama_build_and_test(test-barrier.cpp LINK ggml)
+    llama_build_and_test(test-quantize-fns.cpp LINK ggml)
+    llama_build_and_test(test-quantize-perf.cpp LINK ggml)
+    llama_build_and_test(test-rope.cpp LINK ggml)
+    llama_build_and_test(test-col2im-1d.cpp LINK ggml)
 endif()

 # libmtmd
-set(LLAMA_TEST_NAME test-mtmd-c-api)
-llama_build_and_test(test-mtmd-c-api.c)
-target_link_libraries(${LLAMA_TEST_NAME} PRIVATE mtmd)
-unset(LLAMA_TEST_NAME)
+llama_build_and_test(test-mtmd-c-api.c LINK mtmd)

-llama_build_and_test(test-mtmd-impl.cpp)
-target_link_libraries(test-mtmd-impl PRIVATE mtmd)
+llama_build_and_test(test-mtmd-impl.cpp LINK mtmd)

 # GGUF model data fetcher library for tests that need real model metadata
 # Only compile when cpp-httplib has SSL support (CPPHTTPLIB_OPENSSL_SUPPORT)
@@ -339,7 +351,7 @@ if (TARGET cpp-httplib)
         llama_test(test-gguf-model-data LABEL "model")

         # test-quant-type-selection requires gguf-model-data for remote model metadata
-        llama_build_and_test(test-quant-type-selection.cpp LABEL "model")
+        llama_build_and_test(test-quant-type-selection.cpp LABEL "model" LINK llama)
         target_link_libraries(test-quant-type-selection PRIVATE gguf-model-data)
         target_compile_definitions(test-quant-type-selection PRIVATE
             SNAPSHOT_DIR="${CMAKE_CURRENT_SOURCE_DIR}/snapshots")
@@ -353,10 +365,10 @@ target_link_libraries(${TEST_TARGET} PRIVATE llama)

 if (NOT LLAMA_USE_SYSTEM_GGML)
     # Needs non-public ggml-impl.h
-    llama_build_and_test(test-gguf.cpp)
+    llama_build_and_test(test-gguf.cpp LINK ggml)

     # Needs non-public ggml{,-backend}-impl.h
-    llama_build_and_test(test-alloc.cpp)
+    llama_build_and_test(test-alloc.cpp LINK ggml)
 endif()

 llama_build(test-export-graph-ops.cpp)
diff --git a/tests/testing.h b/tests/testing.h
index 891d78530..6e2de6e08 100644
--- a/tests/testing.h
+++ b/tests/testing.h
@@ -1,7 +1,5 @@
 #pragma once

-#include "common.h"
-
 #include <chrono>
 #include <exception>
 #include <iostream>
@@ -39,7 +37,14 @@ struct testing {
     }

     std::string full_name() const {
-        return string_join(stack, ".");
+        std::string name;
+        for (std::size_t i = 0; i < stack.size(); ++i) {
+            if (i != 0) {
+                name += ".";
+            }
+            name += stack[i];
+        }
+        return name;
     }

     void log(const std::string & msg) {