Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
5cb3edd
Ship natives as one jar per backend, declared once in natives.csv
claude Sep 30, 2026
551f527
Build checks as a tested library; shared files, release gate, leaner …
claude Sep 30, 2026
03f9fb6
Smoke fat jars as one matrix, macOS/Windows Java tests as a reusable …
claude Sep 30, 2026
818bef5
Split CLAUDE.md: agent and app guidance next to their code, dropped p…
claude Oct 1, 2026
efc67da
Restore six line continuations lost in the workflow cleanup
claude Oct 1, 2026
1de7e25
CI: shared-files checks the workflow jobs kept identical across the r…
claude Oct 1, 2026
d40c7e9
CI: warn where a Maven dependency or plugin differs from a sibling re…
claude Oct 1, 2026
f6f5c75
CI: bash -n over every bash run script of the workflows and actions
claude Oct 1, 2026
f198ad7
License the CI files MIT OR Apache-2.0 and share the small workflows
claude Oct 1, 2026
3be6fd7
Remove the outdated dockcross/update.sh
claude Oct 1, 2026
a08edd5
License the remaining CI files MIT OR Apache-2.0 and share the small …
claude Oct 1, 2026
c8bfb91
Remove the unused dockcross wrappers linux-arm64-lts and android-arm
claude Oct 1, 2026
8ccf888
Drop the stdc++fs link for GCC < 9
claude Oct 1, 2026
177805c
CI: the JDK is .java-version in every workflow; codeql.yml shared
claude Oct 1, 2026
f19005f
REUSE: attribute the dockcross wrappers to the dockcross project
claude Oct 1, 2026
63a63bd
CI: share more files, incl. ones identical up to the repository name
claude Oct 1, 2026
9bc2572
Drop the upstream copyright line where no upstream code is left
claude Oct 1, 2026
5254b14
Rewrite the four examples for the current API and run them in CI
claude Oct 1, 2026
9c517ca
Own .clang-format, llama.cpp's current .clang-tidy
claude Oct 1, 2026
0f39a9a
LICENSE: name the current copyright holder first
claude Oct 1, 2026
cf4da0d
Rewrite what LlamaModel, CliParameters and ModelFlag kept from upstream
claude Oct 1, 2026
d36d537
Rewrite ProcessRunner on ProcessBuilder; describe the current test-mo…
claude Oct 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
# SPDX-FileCopyrightText: 2023-2025 Konstantin Herud
#
# SPDX-License-Identifier: MIT
# SPDX-License-Identifier: MIT OR Apache-2.0

# https://editorconfig.org
root = true
Expand Down
4 changes: 2 additions & 2 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
# SPDX-FileCopyrightText: 2023-2025 Konstantin Herud
#
# SPDX-License-Identifier: MIT
# SPDX-License-Identifier: MIT OR Apache-2.0

* text=auto eol=lf
*.gguf binary
4 changes: 4 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
#
# SPDX-License-Identifier: MIT OR Apache-2.0

# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
# Default reviewer for all paths.
* @bernardladenthin
3 changes: 1 addition & 2 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
# SPDX-FileCopyrightText: 2023-2025 Konstantin Herud
#
# SPDX-License-Identifier: MIT
# SPDX-License-Identifier: MIT OR Apache-2.0

# Sponsorship configuration for github.com/bernardladenthin.
# Uncomment any line below to advertise a funding channel on the repository.
Expand Down
3 changes: 1 addition & 2 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
# SPDX-FileCopyrightText: 2023-2025 Konstantin Herud
#
# SPDX-License-Identifier: MIT
# SPDX-License-Identifier: MIT OR Apache-2.0

blank_issues_enabled: false
contact_links:
Expand Down
32 changes: 32 additions & 0 deletions .github/actions/build-core/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
#
# SPDX-License-Identifier: MIT OR Apache-2.0

# Builds the parent POM and net.ladenthin:llama -- plus further reactor modules when asked -- as plain
# Java: no tests, no checks, no javadoc or sources jar, no signing. With `install` they land in the
# local Maven repository for a job that builds a module or an artifact on top of them; with `package`
# only in target/. The one place for that skip-flag list, which nine jobs used to repeat.
# Needs the repository checked out and a JDK set up.
name: Build the core classes
description: Build parent + net.ladenthin:llama (and more reactor modules) without tests, checks, javadoc or signing.
inputs:
modules:
description: The reactor modules to build (-pl); their reactor dependencies are built too (-am).
required: false
default: llama
goal:
description: install (into the local Maven repository) or package (target/ only).
required: false
default: install
runs:
using: composite
steps:
- name: mvn -pl ${{ inputs.modules }} -am ${{ inputs.goal }} (no tests, checks or signing)
shell: bash
env:
MODULES: ${{ inputs.modules }}
GOAL: ${{ inputs.goal }}
run: >
mvn -B --no-transfer-progress -pl "$MODULES" -am -DskipTests -Denforcer.skip=true
-Dspotless.check.skip=true -Dspotbugs.skip=true
-Dmaven.javadoc.skip=true -Dmaven.source.skip=true -Dgpg.skip=true "$GOAL"
32 changes: 32 additions & 0 deletions .github/actions/install-sccache-windows/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
#
# SPDX-License-Identifier: MIT OR Apache-2.0

# Puts sccache on PATH on a Windows runner, from the release zip (x86_64, or the native
# aarch64-pc-windows-msvc build on windows-11-arm, where it wraps clang-cl). The caller keeps the
# `if:` (USE_CACHE and a Depot token present) and `continue-on-error: true`: a failed install is
# only a slower build, because build.bat probes sccache before trusting it and retries a build that
# fails with it as the launcher once uncached (CLAUDE.md, "sccache on every Windows Ninja job").
# Keep `version` equal to SCCACHE_DL_VERSION in .github/build.sh (the Linux fetch).
name: Install sccache (Windows)
description: Download the sccache release zip matching the runner's architecture and add it to PATH.
inputs:
version:
description: sccache release to install.
required: false
default: '0.18.0'
runs:
using: composite
steps:
- name: Install sccache ${{ inputs.version }}
shell: pwsh
env:
SCCACHE_VERSION: ${{ inputs.version }}
run: |
$arch = if ($env:RUNNER_ARCH -eq 'ARM64') { 'aarch64' } else { 'x86_64' }
$rel = "sccache-v$env:SCCACHE_VERSION-$arch-pc-windows-msvc"
$url = "https://github.com/mozilla/sccache/releases/download/v$env:SCCACHE_VERSION/$rel.zip"
Write-Host "Downloading $url"
Invoke-WebRequest -Uri $url -OutFile "$env:RUNNER_TEMP\sccache.zip"
Expand-Archive -Path "$env:RUNNER_TEMP\sccache.zip" -DestinationPath "$env:RUNNER_TEMP\sccache" -Force
Add-Content -Path $env:GITHUB_PATH -Value "$env:RUNNER_TEMP\sccache\$rel"
31 changes: 31 additions & 0 deletions .github/actions/publish-cpu-aar-local/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
#
# SPDX-License-Identifier: MIT OR Apache-2.0

# Downloads the Android CPU natives (arm64-v8a for devices, x86_64 for the emulator), stages them where
# llama-android's Gradle build expects them and publishes the CPU AAR to mavenLocal -- what the
# emulator test and the two llmservice jobs consume. Needs the repository checked out, the core jar
# built (build-core, `package`) and Gradle on PATH; the calling job must `need` both Android CPU
# build jobs.
name: Publish the CPU AAR to mavenLocal
description: Download + stage the Android CPU natives (arm64-v8a, x86_64) and publish the llama-android AAR to mavenLocal.
runs:
using: composite
steps:
- name: Download Android CPU natives (arm64)
uses: actions/download-artifact@v8
with:
name: natives-cpu-android-aarch64
path: stage/cpu/
- name: Download Android CPU natives (x86_64)
uses: actions/download-artifact@v8
with:
name: natives-cpu-android-x86-64
path: stage/cpu-x86_64/
- name: Stage natives + publish the CPU AAR to mavenLocal
shell: bash
run: |
mkdir -p llama-android/natives/cpu/arm64-v8a llama-android/natives/cpu/x86_64
cp stage/cpu/Linux-Android/aarch64/cpu/libjllama.so llama-android/natives/cpu/arm64-v8a/
cp stage/cpu-x86_64/Linux-Android/x86_64/cpu/libjllama.so llama-android/natives/cpu/x86_64/
gradle -p llama-android publishLlamaAndroidPublicationToMavenLocal
33 changes: 33 additions & 0 deletions .github/actions/restore-models/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
#
# SPDX-License-Identifier: MIT OR Apache-2.0

# Restores the shared GGUF model cache and validates it -- the one place a job gets its models.
# The download-models job is the cache's ONLY writer (actions/cache, same key); every consumer
# uses this restore-only action, so a job running on a cache miss can never re-save an empty or
# partial entry under the immutable key. enableCrossOsArchive matches the writer's entry version,
# so macOS and Windows restore the same ubuntu-built entry (without it the entries are per OS, and
# the unreachable Windows-side one was once found re-saved EMPTY after an eviction). The key is
# the hash of .github/models.csv, so editing the manifest creates a fresh complete entry.
# validate-models.sh then fails a partial or absent restore loudly instead of letting the
# model-backed tests self-skip. Needs the repository checked out.
name: Restore GGUF models
description: Restore the shared GGUF model cache (written by download-models) and validate every model of .github/models.csv.
inputs:
fail-on-cache-miss:
description: Fail at the restore already when the cache entry is missing ('true' in verify-model-cache).
required: false
default: 'false'
runs:
using: composite
steps:
- name: Restore shared GGUF model cache (populated by download-models; no re-download)
uses: actions/cache/restore@v6
with:
path: models/
key: gguf-models-${{ hashFiles('.github/models.csv') }}
enableCrossOsArchive: true
fail-on-cache-miss: ${{ inputs.fail-on-cache-miss }}
- name: Validate model files
shell: bash
run: bash .github/validate-models.sh
2 changes: 1 addition & 1 deletion .github/android-consumer-test/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!--
SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>

SPDX-License-Identifier: MIT
SPDX-License-Identifier: MIT OR Apache-2.0
-->
# llama-android consumer-test fixture (CI only)

Expand Down
2 changes: 1 addition & 1 deletion .github/android-consumer-test/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
//
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT OR Apache-2.0

plugins {
id("com.android.application")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
//
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT OR Apache-2.0

package net.ladenthin.llama.consumertest;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<!--
SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>

SPDX-License-Identifier: MIT
SPDX-License-Identifier: MIT OR Apache-2.0
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:label="jllama consumer test" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
//
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT OR Apache-2.0

package net.ladenthin.llama.consumertest;

Expand Down
2 changes: 1 addition & 1 deletion .github/android-consumer-test/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
#
# SPDX-License-Identifier: MIT
# SPDX-License-Identifier: MIT OR Apache-2.0
org.gradle.jvmargs=-Xmx2g
android.useAndroidX=true
2 changes: 1 addition & 1 deletion .github/android-consumer-test/settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
//
// SPDX-License-Identifier: MIT
// SPDX-License-Identifier: MIT OR Apache-2.0

// CI fixture (NOT a shipped project): a minimal AGP app that consumes the
// net.ladenthin:llama-android AAR from mavenLocal and runs a full R8 release
Expand Down
3 changes: 1 addition & 2 deletions .github/build.bat
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
REM SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
REM SPDX-FileCopyrightText: 2023-2025 Konstantin Herud
REM
REM SPDX-License-Identifier: MIT
REM SPDX-License-Identifier: MIT OR Apache-2.0

@echo off
setlocal enabledelayedexpansion
Expand Down
3 changes: 1 addition & 2 deletions .github/build.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
#!/bin/bash

# SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
# SPDX-FileCopyrightText: 2023-2025 Konstantin Herud
#
# SPDX-License-Identifier: MIT
# SPDX-License-Identifier: MIT OR Apache-2.0

# The core project (CMakeLists.txt + src/) lives in the `llama/` module of the Maven
# reactor. Re-root here once — every native build delegates to this script (incl. the
Expand Down
3 changes: 1 addition & 2 deletions .github/build_cuda_linux.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
#!/bin/sh

# SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
# SPDX-FileCopyrightText: 2023-2025 Konstantin Herud
#
# SPDX-License-Identifier: MIT
# SPDX-License-Identifier: MIT OR Apache-2.0

# A Cuda 13.4 install script for RHEL8/Rocky8/Manylinux_2.28
# Available versions can be found at:
Expand Down
2 changes: 1 addition & 1 deletion .github/build_opencl_android.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
#
# SPDX-License-Identifier: MIT
# SPDX-License-Identifier: MIT OR Apache-2.0
#
# Android arm64 build with the OpenCL backend enabled and Adreno-tuned
# kernels embedded. Runs inside the dockcross/android-arm64 container.
Expand Down
2 changes: 1 addition & 1 deletion .github/build_opencl_windows.bat
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
REM SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
REM
REM SPDX-License-Identifier: MIT
REM SPDX-License-Identifier: MIT OR Apache-2.0
REM
REM Windows x86_64 build with the OpenCL backend enabled, shipped as the
REM `opencl-windows-x86-64` classifier. The windows-2025 runner image ships
Expand Down
14 changes: 14 additions & 0 deletions .github/buildcheck/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
#
# SPDX-License-Identifier: MIT OR Apache-2.0
"""Build checks as a library, so buildcheck/tests can test them. Standard library only.

Two kinds of module live here. workflow.py, releasegate.py, sharedfiles.py, versions.py and
runscripts.py (with their tests and the check-*.py entry points next to this package) are kept
BYTE-IDENTICAL in java-llama.cpp, BitcoinAddressFinder, srcmorph and streambuffer: each repository
lists them in .github/shared-files.sha256, which its `shared-files` job checks (see sharedfiles.py).
Every other module is the repository's own.

Run the tests from the repository root:
python3 -m unittest discover -s .github/buildcheck/tests -t .github
"""
82 changes: 82 additions & 0 deletions .github/buildcheck/hipoffload.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# SPDX-FileCopyrightText: 2026 Bernard Ladenthin <bernard.ladenthin@gmail.com>
#
# SPDX-License-Identifier: MIT OR Apache-2.0

"""Fail when a ROCm/HIP build ships its GPU code uncompressed.

llama/CMakeLists.txt compiles ggml-hip with clang's --offload-compress, so every embedded
device-code bundle is a compressed "CCOB" bundle. An uncompressed bundle starts with the magic
"__CLANG_OFFLOAD_BUNDLE__"; one of those in the shipped library means the flag was lost and the
library is back to carrying every GPU target's code uncompressed (~1 GB on Windows).

Usage (the CLI is .github/verify-hip-offload-compressed.py): verify-hip-offload-compressed.py <dir-or-file>...

Scans every jllama.dll / libjllama.so found, prints its size and the bundle counts, and exits
non-zero if a library has an uncompressed bundle, has no compressed bundle at all, or if no
library was found. Only the standard library, so it runs on any runner.
"""

import os
import sys

UNCOMPRESSED = b"__CLANG_OFFLOAD_BUNDLE__"
COMPRESSED = b"CCOB"
NAMES = ("jllama.dll", "libjllama.so")
CHUNK = 64 * 1024 * 1024


def count(path, chunk=CHUNK):
"""Counts both magics in one streaming pass (the file can be ~1 GB)."""
overlap = len(UNCOMPRESSED) - 1
uncompressed = compressed = 0
tail = b""
with open(path, "rb") as f:
while True:
block = f.read(chunk)
if not block:
break
data = tail + block
# a match lying entirely inside `tail` was counted in the previous round
uncompressed += data.count(UNCOMPRESSED) - tail.count(UNCOMPRESSED)
compressed += data.count(COMPRESSED) - tail.count(COMPRESSED)
tail = data[-overlap:]
return uncompressed, compressed


def libraries(paths):
for p in paths:
if os.path.isfile(p):
yield p
for root, _, files in os.walk(p):
for name in files:
if name in NAMES:
yield os.path.join(root, name)


def main(argv):
if len(argv) < 2:
print("usage: verify-hip-offload-compressed.py <dir-or-file>...", file=sys.stderr)
return 2
found = failed = 0
summary = []
for lib in libraries(argv[1:]):
found += 1
size = os.path.getsize(lib)
uncompressed, compressed = count(lib)
line = f"{lib}: {size / 1024 / 1024:.0f} MiB, {compressed} compressed / {uncompressed} uncompressed offload bundle(s)"
print(line)
summary.append(line)
if uncompressed:
print(f"::error::{lib} embeds {uncompressed} uncompressed GPU code bundle(s); is --offload-compress still set on ggml-hip?")
failed += 1
elif not compressed:
print(f"::error::{lib} embeds no compressed GPU code bundle; was it built with GGML_HIP=ON?")
failed += 1
if not found:
print(f"::error::no {' / '.join(NAMES)} found under {argv[1:]}")
return 2
step_summary = os.environ.get("GITHUB_STEP_SUMMARY")
if step_summary:
with open(step_summary, "a", encoding="utf-8") as f:
f.write("### ROCm/HIP device code\n\n" + "\n".join(f"- `{s}`" for s in summary) + "\n")
return 1 if failed else 0
Loading
Loading