LLAMA_LOG_TIMESTAMPS: 1
jobs:
+ determine-tag:
+ name: Determine tag name
+ runs-on: ubuntu-slim
+ outputs:
+ tag_name: ${{ steps.tag.outputs.name }}
+ steps:
+ - name: Clone
+ uses: actions/checkout@v6
+ with:
+ fetch-depth: 0
+ - name: Determine tag name
+ id: tag
+ uses: ./.github/actions/get-tag-name
+
ggml-ci-nvidia-cuda:
+ needs: determine-tag
runs-on: [self-hosted, Linux, NVIDIA]
steps:
- name: Test
id: ggml-ci
+ env:
+ HF_WEBUI_VERSION: ${{ needs.determine-tag.outputs.tag_name }}
run: |
nvidia-smi
GG_BUILD_CUDA=1 bash ./ci/run.sh ~/results/llama.cpp /mnt/llama.cpp
ggml-ci-nvidia-vulkan-cm:
+ needs: determine-tag
runs-on: [self-hosted, Linux, NVIDIA]
steps:
- name: Test
id: ggml-ci
+ env:
+ HF_WEBUI_VERSION: ${{ needs.determine-tag.outputs.tag_name }}
run: |
vulkaninfo --summary
GG_BUILD_VULKAN=1 GGML_VK_DISABLE_COOPMAT2=1 bash ./ci/run.sh ~/results/llama.cpp /mnt/llama.cpp
ggml-ci-nvidia-vulkan-cm2:
+ needs: determine-tag
runs-on: [self-hosted, Linux, NVIDIA, COOPMAT2]
steps:
- name: Test
id: ggml-ci
+ env:
+ HF_WEBUI_VERSION: ${{ needs.determine-tag.outputs.tag_name }}
run: |
vulkaninfo --summary
GG_BUILD_VULKAN=1 bash ./ci/run.sh ~/results/llama.cpp /mnt/llama.cpp
# GG_BUILD_ROCM=1 GG_BUILD_AMDGPU_TARGETS="gfx1101" bash ./ci/run.sh ~/results/llama.cpp /mnt/llama.cpp
ggml-ci-mac-metal:
+ needs: determine-tag
runs-on: [self-hosted, macOS, ARM64]
steps:
- name: Test
id: ggml-ci
+ env:
+ HF_WEBUI_VERSION: ${{ needs.determine-tag.outputs.tag_name }}
run: |
GG_BUILD_METAL=1 bash ./ci/run.sh ~/results/llama.cpp ~/mnt/llama.cpp
ggml-ci-mac-webgpu:
+ needs: determine-tag
runs-on: [self-hosted, macOS, ARM64]
steps:
- name: Test
id: ggml-ci
+ env:
+ HF_WEBUI_VERSION: ${{ needs.determine-tag.outputs.tag_name }}
run: |
GG_BUILD_WEBGPU=1 GG_BUILD_WEBGPU_DAWN_PREFIX="$GITHUB_WORKSPACE/dawn" \
bash ./ci/run.sh ~/results/llama.cpp ~/mnt/llama.cpp
ggml-ci-mac-vulkan:
+ needs: determine-tag
runs-on: [self-hosted, macOS, ARM64]
steps:
- name: Test
id: ggml-ci
+ env:
+ HF_WEBUI_VERSION: ${{ needs.determine-tag.outputs.tag_name }}
run: |
vulkaninfo --summary
GG_BUILD_VULKAN=1 bash ./ci/run.sh ~/results/llama.cpp ~/mnt/llama.cpp
ggml-ci-linux-intel-vulkan:
+ needs: determine-tag
runs-on: [self-hosted, Linux, Intel]
steps:
- name: Test
id: ggml-ci
+ env:
+ HF_WEBUI_VERSION: ${{ needs.determine-tag.outputs.tag_name }}
run: |
vulkaninfo --summary
GG_BUILD_VULKAN=1 bash ./ci/run.sh ~/results/llama.cpp ~/mnt/llama.cpp
ggml-ci-win-intel-vulkan:
+ needs: determine-tag
runs-on: [self-hosted, Windows, X64, Intel]
steps:
MSYSTEM: UCRT64
CHERE_INVOKING: 1
PATH: C:\msys64\ucrt64\bin;C:\msys64\usr\bin;C:\Windows\System32;${{ env.PATH }}
+ HF_WEBUI_VERSION: ${{ needs.determine-tag.outputs.tag_name }}
run: |
vulkaninfo --summary
# Skip python related tests with GG_BUILD_LOW_PERF=1 since Windows MSYS2 UCRT64 currently fails to create
LLAMA_FATAL_WARNINGS=OFF GG_BUILD_NINJA=1 GG_BUILD_VULKAN=1 GG_BUILD_LOW_PERF=1 ./ci/run.sh ./results/llama.cpp ./mnt/llama.cpp
ggml-ci-intel-openvino-gpu-low-perf:
+ needs: determine-tag
runs-on: [self-hosted, Linux, Intel, OpenVINO]
concurrency:
- name: Test
id: ggml-ci
+ env:
+ HF_WEBUI_VERSION: ${{ needs.determine-tag.outputs.tag_name }}
run: |
source ./openvino_toolkit/setupvars.sh
GG_BUILD_OPENVINO=1 GGML_OPENVINO_DEVICE=GPU GG_BUILD_LOW_PERF=1 bash ./ci/run.sh ./tmp/results ./tmp/mnt
set(PUBLIC_DIR "" CACHE STRING "Directory to store/download assets")
set(HF_BUCKET "" CACHE STRING "Hugging Face bucket name")
set(HF_VERSION "" CACHE STRING "Version to download (empty = resolve from git)")
-set(ASSETS "" CACHE STRING "Semicolon-separated list of asset filenames")
+set(ASSETS "" CACHE STRING "Plus-separated list of asset filenames (+)")
set(STAMP_FILE "" CACHE STRING "Stamp file to create on success (optional)")
set(SOURCE_DIR "" CACHE STRING "Project source root (to resolve version from git)")
set(NPM_DIR "" CACHE STRING "WebUI source directory (to run npm build)")
endif()
endif()
+# Convert + back to CMake list (+ is used as separator instead of ; to
+# avoid platform-specific escaping issues when passing via -D arguments)
+string(REGEX REPLACE "\\+" ";" ASSETS "${ASSETS}")
+
# ---------------------------------------------------------------------------
# 2. Check stamp freshness — re-download if resolved version changed
# ---------------------------------------------------------------------------
if(NOT PROVISION_SUCCESS AND NOT "${NPM_DIR}" STREQUAL "")
if(EXISTS "${NPM_DIR}/package.json")
- message(STATUS "WebUI: building from source in ${NPM_DIR}")
+ # Check if npm is available before attempting npm build
+ find_program(NPM_EXECUTABLE npm)
+ if(NPM_EXECUTABLE)
+ message(STATUS "WebUI: building from source in ${NPM_DIR}")
+
+ # Run npm install if node_modules is missing
+ if(NOT EXISTS "${NPM_DIR}/node_modules")
+ message(STATUS "WebUI: running npm install (first time)")
+ execute_process(
+ COMMAND npm install
+ WORKING_DIRECTORY "${NPM_DIR}"
+ RESULT_VARIABLE NPM_INSTALL_RESULT
+ OUTPUT_VARIABLE NPM_OUT
+ ERROR_VARIABLE NPM_ERR
+ )
+ if(NOT NPM_INSTALL_RESULT EQUAL 0)
+ message(STATUS "WebUI: npm install failed (${NPM_INSTALL_RESULT}), falling back to download")
+ message(STATUS " stderr: ${NPM_ERR}")
+ endif()
+ endif()
- # Run npm install if node_modules is missing
- if(NOT EXISTS "${NPM_DIR}/node_modules")
- message(STATUS "WebUI: running npm install (first time)")
+ # Run the build
execute_process(
- COMMAND npm install
+ COMMAND npm run build
WORKING_DIRECTORY "${NPM_DIR}"
- RESULT_VARIABLE NPM_INSTALL_RESULT
+ RESULT_VARIABLE NPM_BUILD_RESULT
OUTPUT_VARIABLE NPM_OUT
ERROR_VARIABLE NPM_ERR
)
- if(NOT NPM_INSTALL_RESULT EQUAL 0)
- message(STATUS "WebUI: npm install failed (${NPM_INSTALL_RESULT}), falling back to download")
- message(STATUS " stderr: ${NPM_ERR}")
- endif()
- endif()
- # Run the build
- execute_process(
- COMMAND npm run build
- WORKING_DIRECTORY "${NPM_DIR}"
- RESULT_VARIABLE NPM_BUILD_RESULT
- OUTPUT_VARIABLE NPM_OUT
- ERROR_VARIABLE NPM_ERR
- )
-
- if(NPM_BUILD_RESULT EQUAL 0)
- # Verify that the expected assets were produced
- set(ALL_BUILT TRUE)
- foreach(asset ${ASSETS})
- if(NOT EXISTS "${PUBLIC_DIR}/${asset}")
- set(ALL_BUILT FALSE)
- break()
+ if(NPM_BUILD_RESULT EQUAL 0)
+ # Verify that the expected assets were produced
+ set(ALL_BUILT TRUE)
+ foreach(asset ${ASSETS})
+ if(NOT EXISTS "${PUBLIC_DIR}/${asset}")
+ set(ALL_BUILT FALSE)
+ break()
+ endif()
+ endforeach()
+
+ if(ALL_BUILT)
+ message(STATUS "WebUI: local npm build succeeded")
+ set(PROVISION_SUCCESS TRUE)
+ else()
+ message(STATUS "WebUI: npm build completed but assets missing from ${PUBLIC_DIR}, falling back to download")
endif()
- endforeach()
-
- if(ALL_BUILT)
- message(STATUS "WebUI: local npm build succeeded")
- set(PROVISION_SUCCESS TRUE)
else()
- message(STATUS "WebUI: npm build completed but assets missing from ${PUBLIC_DIR}, falling back to download")
+ message(STATUS "WebUI: npm build failed (${NPM_BUILD_RESULT}), falling back to download")
+ message(STATUS " stderr: ${NPM_ERR}")
endif()
else()
- message(STATUS "WebUI: npm build failed (${NPM_BUILD_RESULT}), falling back to download")
- message(STATUS " stderr: ${NPM_ERR}")
+ message(STATUS "WebUI: npm not found, skipping npm build and trying HF Bucket download")
endif()
else()
message(STATUS "WebUI: NPM_DIR (${NPM_DIR}) has no package.json, skipping npm build")
string(REGEX MATCH "${EXPECTED_HASH_UPPER}[ \\t]+${asset}" CHECKSUM_LINE "${CHECKSUMS_CONTENT}")
if(NOT CHECKSUM_LINE)
message(WARNING "WebUI: checksum verification failed for ${asset}")
- set(ALL_OK FALSE)
- break()
+ message(WARNING " downloaded file may not match expected checksum, but will be used")
endif()
endforeach()
if(ALL_OK)
# Priority 2: Build-time asset provisioning (npm build → HF Bucket fallback)
if(NOT WEBUI_SOURCE_DIR)
- if(DEFINED LLAMA_BUILD_NUMBER)
- set(HF_WEBUI_VERSION "${LLAMA_BUILD_NUMBER}")
+ # Environment variable takes precedence (e.g., from CI workflows)
+ if(DEFINED ENV{HF_WEBUI_VERSION})
+ set(HF_WEBUI_VERSION "$ENV{HF_WEBUI_VERSION}")
+ # Validate against allowed characters to prevent CMake list separator
+ # or path-traversal issues in stamp filenames and download URLs
+ if(NOT HF_WEBUI_VERSION MATCHES "^[A-Za-z0-9._-]+$")
+ message(FATAL_ERROR "WebUI: invalid HF_WEBUI_VERSION='${HF_WEBUI_VERSION}' - must match ^[A-Za-z0-9._-]+$")
+ endif()
+ message(STATUS "WebUI: using HF_WEBUI_VERSION from environment=${HF_WEBUI_VERSION}")
+ elseif(DEFINED LLAMA_BUILD_NUMBER)
+ set(HF_WEBUI_VERSION "b${LLAMA_BUILD_NUMBER}")
message(STATUS "WebUI: using LLAMA_BUILD_NUMBER=${HF_WEBUI_VERSION}")
else()
set(HF_WEBUI_VERSION "")
- message(STATUS "WebUI: LLAMA_BUILD_NUMBER not defined")
+ message(STATUS "WebUI: version not specified (will use HF 'latest')")
endif()
# Stamp file embeds the version tag so a changed build number triggers
endif()
set(WEBUI_STAMP "${CMAKE_CURRENT_BINARY_DIR}/.webui-${WEBUI_VERSION_TAG}.stamp")
- # Escape semicolons so the CMake list is passed as a single -D argument
- string(REPLACE ";" "\\;" PUBLIC_ASSETS_ESC "${PUBLIC_ASSETS}")
+ # Join assets with + separator (safe across all platforms, unlike ; and |)
+ string(REPLACE ";" "+" PUBLIC_ASSETS_JOINED "${PUBLIC_ASSETS}")
add_custom_command(
OUTPUT ${WEBUI_STAMP}
"-DHF_BUCKET=${LLAMA_WEBUI_HF_BUCKET}"
"-DHF_VERSION=${HF_WEBUI_VERSION}"
"-DHF_ENABLED=${LLAMA_USE_PREBUILT_WEBUI}"
- "-DASSETS=${PUBLIC_ASSETS_ESC}"
+ "-DASSETS=${PUBLIC_ASSETS_JOINED}"
"-DSTAMP_FILE=${WEBUI_STAMP}"
"-DNPM_DIR=${CMAKE_CURRENT_SOURCE_DIR}/webui"
-P ${PROJECT_SOURCE_DIR}/scripts/webui-download.cmake