Commit d63fbfe79 for llama.cpp

commit d63fbfe794b62990086043fa9e05fd6e8367b4d6
Author: Adrien Gallouët <angt@huggingface.co>
Date:   Fri Oct 30 10:56:53 2026 +0100

    cmake : embed an app manifest in all Windows exes (#31329)

    * cmake : embed an app manifest in all Windows exes

    Signed-off-by: Adrien Gallouët <angt@huggingface.co>

    * Remove LLAMA_WIN_APP_CMAKE

    Signed-off-by: Adrien Gallouët <angt@huggingface.co>

    ---------

    Signed-off-by: Adrien Gallouët <angt@huggingface.co>

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0cf2dc815..e37c8aa4c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -150,6 +150,7 @@ option(LLAMA_LLGUIDANCE "llama-common: include LLGuidance library for structured
 # Required for relocatable CMake package
 include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/build-info.cmake)
 include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/common.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/win-app.cmake)

 if (NOT DEFINED LLAMA_BUILD_NUMBER)
     set(LLAMA_BUILD_NUMBER        ${BUILD_NUMBER})
@@ -269,6 +270,8 @@ if (LLAMA_BUILD_MTMD AND NOT (LLAMA_BUILD_COMMON AND LLAMA_BUILD_TOOLS))
     add_subdirectory(tools/mtmd)
 endif()

+llama_apply_app_manifests()
+
 #
 # install
 #
diff --git a/cmake/win-app.cmake b/cmake/win-app.cmake
new file mode 100644
index 000000000..5456e48fd
--- /dev/null
+++ b/cmake/win-app.cmake
@@ -0,0 +1,66 @@
+set(LLAMA_WIN_APP_MANIFEST "${CMAKE_CURRENT_LIST_DIR}/../common/win-app.manifest")
+
+if(WIN32)
+    if(MSVC OR CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")
+        set(LLAMA_WIN_APP_MSVC_ABI TRUE)
+    else()
+        set(LLAMA_WIN_APP_MSVC_ABI FALSE)
+    endif()
+
+    if(NOT LLAMA_WIN_APP_MSVC_ABI)
+        if(CMAKE_VERSION VERSION_LESS 3.21)
+            message(FATAL_ERROR "CMake 3.21 or newer is required to build for Windows with the GNU ABI")
+        endif()
+        enable_language(RC)
+        set(LLAMA_WIN_APP_MANIFEST_RC "${CMAKE_CURRENT_BINARY_DIR}/win-app-manifest.rc")
+        configure_file("${CMAKE_CURRENT_LIST_DIR}/win-app.rc.in" "${LLAMA_WIN_APP_MANIFEST_RC}" @ONLY)
+        set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${LLAMA_WIN_APP_MANIFEST}")
+    endif()
+endif()
+
+function(llama_add_app_manifest target)
+    if(NOT WIN32)
+        return()
+    endif()
+    get_target_property(_aliased ${target} ALIASED_TARGET)
+    if(_aliased)
+        return()
+    endif()
+    get_target_property(_type ${target} TYPE)
+    if(NOT _type STREQUAL "EXECUTABLE")
+        return()
+    endif()
+    if(LLAMA_WIN_APP_MSVC_ABI)
+        target_sources(${target} PRIVATE "${LLAMA_WIN_APP_MANIFEST}")
+    else()
+        if(NOT TARGET llama-win-app-manifest-res)
+            add_library(llama-win-app-manifest-res OBJECT ${LLAMA_WIN_APP_MANIFEST_RC})
+            set_source_files_properties(${LLAMA_WIN_APP_MANIFEST_RC} PROPERTIES OBJECT_DEPENDS "${LLAMA_WIN_APP_MANIFEST}")
+        endif()
+        target_link_libraries(${target} PRIVATE "$<TARGET_OBJECTS:llama-win-app-manifest-res>")
+    endif()
+endfunction()
+
+function(llama_apply_app_manifests_dir dir)
+    get_property(_targets DIRECTORY "${dir}" PROPERTY BUILDSYSTEM_TARGETS)
+    foreach(_target IN LISTS _targets)
+        llama_add_app_manifest(${_target})
+    endforeach()
+    get_property(_subdirs DIRECTORY "${dir}" PROPERTY SUBDIRECTORIES)
+    foreach(_subdir IN LISTS _subdirs)
+        llama_apply_app_manifests_dir("${_subdir}")
+    endforeach()
+endfunction()
+
+function(llama_apply_app_manifests)
+    if(NOT WIN32)
+        return()
+    endif()
+    get_property(_subdirs DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" PROPERTY SUBDIRECTORIES)
+    foreach(_dir IN LISTS _subdirs)
+        get_filename_component(_name "${_dir}" NAME)
+        if(_name STREQUAL "app" OR _name STREQUAL "examples" OR _name STREQUAL "pocs" OR _name STREQUAL "tests" OR _name STREQUAL "tools")
+            llama_apply_app_manifests_dir("${_dir}")
+        endif()
+    endforeach()
+endfunction()
diff --git a/cmake/win-app.rc.in b/cmake/win-app.rc.in
new file mode 100644
index 000000000..38288a5f8
--- /dev/null
+++ b/cmake/win-app.rc.in
@@ -0,0 +1,3 @@
+// generated from cmake/win-app.rc.in - do not edit
+// RT_MANIFEST (24), ID 1: the application manifest shared by all llama.cpp executables
+1 24 "@LLAMA_WIN_APP_MANIFEST@"
diff --git a/common/win-app.manifest b/common/win-app.manifest
new file mode 100644
index 000000000..540f6ed81
--- /dev/null
+++ b/common/win-app.manifest
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+  <application xmlns="urn:schemas-microsoft-com:asm.v3">
+    <windowsSettings>
+      <activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
+      <longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
+    </windowsSettings>
+  </application>
+</assembly>
diff --git a/tools/server/server-tools.cpp b/tools/server/server-tools.cpp
index 12e9dbb8c..ad6dd1d78 100644
--- a/tools/server/server-tools.cpp
+++ b/tools/server/server-tools.cpp
@@ -39,9 +39,25 @@ namespace fs = std::filesystem;
 // internal helpers
 //

-// a child process writes in the OEM code page, so accented output would reach
-// the JSON layer as invalid bytes. run() spawns without a console, so the
-// console code page never applies
+#if defined(_WIN32)
+// code page of the system locale, read once at first use
+static UINT legacy_oem_code_page() {
+    static const UINT cp = [] {
+        DWORD value = 0;
+        const int ret = GetLocaleInfoEx(LOCALE_NAME_SYSTEM_DEFAULT, LOCALE_IDEFAULTCODEPAGE | LOCALE_RETURN_NUMBER,
+                                        reinterpret_cast<LPWSTR>(&value), sizeof(value) / sizeof(WCHAR));
+        if (ret > 0 && value && value != CP_OEMCP) {
+            return static_cast<UINT>(value);
+        }
+        return GetOEMCP();
+    }();
+    return cp;
+}
+#endif
+
+// a child process writes in the legacy console code page, so accented output would reach
+// the JSON layer as invalid bytes. run() spawns without a console, so the console
+// code page never applies
 static std::string console_output_to_utf8(const std::string & text) {
 #if defined(_WIN32)
     // a chunk can end mid sequence, so the incomplete tail is dropped first
@@ -50,7 +66,7 @@ static std::string console_output_to_utf8(const std::string & text) {
         return text;
     }

-    const UINT cp = GetOEMCP();
+    const UINT cp = legacy_oem_code_page();

     // fail rather than emit replacement characters when the code page is wrong
     const int wide_len = MultiByteToWideChar(cp, MB_ERR_INVALID_CHARS, text.data(), (int) text.size(), nullptr, 0);