From 4ff2a7ef29b42e8f3934cd4a51be3b33f8ba2ed4 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sat, 24 Oct 2026 05:58:40 +0900 Subject: [PATCH 01/13] feat: ship an executable llama.cpp CPU project template --- .../2026-10-24-project-template-checkpoint.md | 11 ++++ .github/workflows/ci.yml | 9 ++- .gitignore | 7 +- .xlings.json | 1 + README.md | 30 +++++++-- generated/ggml-cpu_cpp.cpp | 1 + generated/ggml_build_info.h | 3 + generated/ggml_cpp.cpp | 1 + generated/ggml_metal_device_m.m | 1 + mcpp.toml | 4 +- templates/cpu/mcpp.toml.in | 7 ++ templates/cpu/src/main.cpp.in | 36 ++++++++++ templates/cpu/template.toml | 4 ++ tools/generate_build_files.py | 26 ++++++++ tools/test_template.py | 66 +++++++++++++++++++ 15 files changed, 197 insertions(+), 10 deletions(-) create mode 100644 .agents/docs/2026-10-24-project-template-checkpoint.md create mode 100644 .xlings.json create mode 100644 generated/ggml-cpu_cpp.cpp create mode 100644 generated/ggml_build_info.h create mode 100644 generated/ggml_cpp.cpp create mode 100644 generated/ggml_metal_device_m.m create mode 100644 templates/cpu/mcpp.toml.in create mode 100644 templates/cpu/src/main.cpp.in create mode 100644 templates/cpu/template.toml create mode 100644 tools/generate_build_files.py create mode 100644 tools/test_template.py diff --git a/.agents/docs/2026-10-24-project-template-checkpoint.md b/.agents/docs/2026-10-24-project-template-checkpoint.md new file mode 100644 index 0000000..2ea4a2f --- /dev/null +++ b/.agents/docs/2026-10-24-project-template-checkpoint.md @@ -0,0 +1,11 @@ +# Runnable project template checkpoint + +The existing ggml-org.llamacpp identity is retained. Package b10069.3 follows the existing upstream b10069 plus one packaging revision; no existing release or index hash is rewritten. + +The default cpu template uses the fully qualified self.name and self.version dependency. It initializes the actual CPU backend with no model download. With a local GGUF path it loads the model, creates a context, decodes and samples. Resource cleanup is explicit and scoped. + +The template test uses the actual mcpp package renderer and verifies the emitted dependency before substituting the staged candidate source. It then compiles and runs the generated program. Both the no-argument flow and a pinned 19 MB GGUF inference flow passed locally on LLVM 23.1.3 (sampled token 471). + +A fresh path consumer revealed missing generated build inputs that earlier install-time materialization had hidden. The four stable generated inputs are now checked in verbatim from generated_files, with tools/generate_build_files.py --check guarding drift. Feature-specific Metal/Vulkan generation still uses the build output. Current libc++ also exposed missing standard includes in upstream source; two scoped wrapper compile-flag rules provide cstdlib/cerrno without patching upstream. + +mcpp is pinned to 2026.10.21.1. The root package built under LLVM 23.1.3 and all 116 existing unit/repository/build-helper checks passed with LLAMACPP_REQUIRE_BUILD_HELPER=1. Native CPU CI now additionally executes the real template with the existing checksummed model. No merge or release is performed by this checkpoint. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ec83093..e6b290f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ permissions: contents: read env: - MCPP_VERSION: "2026.9.6.3" + MCPP_VERSION: "2026.10.21.1" MCPP_RELEASE_BASE: https://github.com/mcpp-community/mcpp/releases/download jobs: @@ -45,12 +45,15 @@ jobs: - name: Cold CPU package build run: | rm -rf target + python3 tools/generate_build_files.py --check mcpp --version | grep -F "${MCPP_VERSION}" mcpp build --strict --no-cache - name: Unit and repository checks env: LLAMACPP_REQUIRE_BUILD_HELPER: "1" run: python3 -m unittest discover -s tests/unit -p 'test_*.py' -v + - name: Actual default project template + run: python3 tools/test_template.py --toolchain llvm@23.1.3 - name: Verify vendored upstream and generated API env: GITHUB_TOKEN: ${{ github.token }} @@ -146,6 +149,10 @@ jobs: throw "CPU pass marker missing" } + - name: Actual template GGUF decode + shell: bash + run: python3 tools/test_template.py --run-arg "$RUNNER_TEMP/stories15M.gguf" + linux-arm64: runs-on: ubuntu-24.04-arm steps: diff --git a/.gitignore b/.gitignore index 5aec130..7b4546b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,11 @@ .mcpp/ +.xlings/ target/ -generated/ +generated/* +!generated/ggml_cpp.cpp +!generated/ggml-cpu_cpp.cpp +!generated/ggml_metal_device_m.m +!generated/ggml_build_info.h compile_commands.json __pycache__/ *.pyc diff --git a/.xlings.json b/.xlings.json new file mode 100644 index 0000000..8475678 --- /dev/null +++ b/.xlings.json @@ -0,0 +1 @@ +{"workspace":{"xim:mcpp":"2026.10.21.1"}} diff --git a/README.md b/README.md index a3fb04d..ae18723 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ import llamacpp; ``` The package version IS llama.cpp's build number, plus this packaging's own -revision of it: `b10069.2`. CPU is the default backend; Metal is an additive +revision of it: `b10069.3`. CPU is the default backend; Metal is an additive feature for macOS ARM64 and Vulkan an additive feature for Linux. Consumers pin exactly -- `b10069` is not semver, so no range expresses "b10069 or later" -- which means a consumer wanting a feature names the revision that has it. @@ -16,31 +16,31 @@ which means a consumer wanting a feature names the revision that has it. ## Add The Package -After `b10069.2` is published in mcpp-index: +After `b10069.3` is published in mcpp-index: ```bash -mcpp add ggml-org:llamacpp@b10069.2 +mcpp add ggml-org:llamacpp@b10069.3 ``` The equivalent manifest entry is: ```toml [dependencies.ggml-org] -llamacpp = "b10069.2" +llamacpp = "b10069.3" ``` For Metal on macOS ARM64: ```toml [dependencies.ggml-org] -llamacpp = { version = "b10069.2", features = ["backend-metal"] } +llamacpp = { version = "b10069.3", features = ["backend-metal"] } ``` For Vulkan on Linux: ```toml [dependencies.ggml-org] -llamacpp = { version = "b10069.2", features = ["backend-vulkan"] } +llamacpp = { version = "b10069.3", features = ["backend-vulkan"] } ``` That line is the whole diff. The shader compiler, the Khronos loader, the @@ -217,7 +217,7 @@ before the tokens are compared. ## Supported Boundary -`b10069.2` includes: +`b10069.3` includes: - the public llama.cpp C API exposed through `import llamacpp;`; - the CPU backend on Linux x86_64, Linux ARM64, Windows x86_64, and macOS ARM64; @@ -235,3 +235,19 @@ calls them may receive the deprecation warnings defined by upstream. See [the update policy](docs/upstream-update-policy.md) for versioning and checkpoint selection, and [the b10069 validation record](docs/validation/b10069.md) for exact evidence and remaining release gates. + +## Quickstart project template + +The b10069.3 package adds a runnable default template. After that version is indexed: + +```sh +mcpp new my-llama --template ggml-org.llamacpp@b10069.3 +cd my-llama +mcpp run +``` + +The default run initializes the CPU backend and prints its capabilities without +downloading a model. `mcpp run -- /path/to/model.gguf` loads that local model, +decodes a small batch and samples a token. This smoke example is a starting +point; the existing chat-cpu example demonstrates prompt tokenization and chat. +`python3 tools/test_template.py` exercises the real renderer and generated project. diff --git a/generated/ggml-cpu_cpp.cpp b/generated/ggml-cpu_cpp.cpp new file mode 100644 index 0000000..bf147c1 --- /dev/null +++ b/generated/ggml-cpu_cpp.cpp @@ -0,0 +1 @@ +#include "ggml-cpu.cpp" diff --git a/generated/ggml_build_info.h b/generated/ggml_build_info.h new file mode 100644 index 0000000..6513d5f --- /dev/null +++ b/generated/ggml_build_info.h @@ -0,0 +1,3 @@ +#pragma once +#define GGML_VERSION "b10069" +#define GGML_COMMIT "178a6c44937154dc4c4eff0d166f4a044c4fceba" diff --git a/generated/ggml_cpp.cpp b/generated/ggml_cpp.cpp new file mode 100644 index 0000000..4f5c280 --- /dev/null +++ b/generated/ggml_cpp.cpp @@ -0,0 +1 @@ +#include "ggml.cpp" diff --git a/generated/ggml_metal_device_m.m b/generated/ggml_metal_device_m.m new file mode 100644 index 0000000..359fbf2 --- /dev/null +++ b/generated/ggml_metal_device_m.m @@ -0,0 +1 @@ +#include "ggml-metal-device.m" diff --git a/mcpp.toml b/mcpp.toml index d1c737e..c919757 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -21,7 +21,7 @@ [package] namespace = "ggml-org" name = "llamacpp" -version = "b10069.2" +version = "b10069.3" description = "C++23 module package for llama.cpp b10069" license = "MIT" standard = "c++23" @@ -233,6 +233,8 @@ sources = [ cflags = ["-w", "-include", "ggml_build_info.h", "-DGGML_USE_CPU_REPACK"] cxxflags = ["-w", "-include", "ggml_build_info.h", "-DGGML_USE_CPU_REPACK"] flags = [ + { glob = "third_party/llama.cpp/src/**", cxxflags = ["-include", "cstdlib"] }, + { glob = "third_party/llama.cpp/ggml/src/gguf.cpp", cxxflags = ["-include", "cerrno"] }, { glob = "third_party/llama.cpp/ggml/src/ggml-backend-reg.cpp", defines = ["GGML_USE_CPU"] }, { glob = "third_party/llama.cpp/ggml/src/ggml-cpu/**", defines = ["GGML_USE_LLAMAFILE"] }, { glob = "generated/ggml-cpu_cpp.cpp", defines = ["GGML_USE_LLAMAFILE"] }, diff --git a/templates/cpu/mcpp.toml.in b/templates/cpu/mcpp.toml.in new file mode 100644 index 0000000..9077430 --- /dev/null +++ b/templates/cpu/mcpp.toml.in @@ -0,0 +1,7 @@ +[package] +name = "{{project.name}}" +version = "0.1.0" +description = "llama.cpp CPU quickstart" + +[dependencies] +"{{self.name}}" = "{{self.version}}" diff --git a/templates/cpu/src/main.cpp.in b/templates/cpu/src/main.cpp.in new file mode 100644 index 0000000..7a815e9 --- /dev/null +++ b/templates/cpu/src/main.cpp.in @@ -0,0 +1,36 @@ +import std; +import llamacpp; + +struct Backend { + Backend() { llama_backend_init(); } + ~Backend() { llama_backend_free(); } +}; + +int main(int argc, char** argv) { + // Destroy every model/context before releasing the backend. + const Backend backend; + std::println("llama.cpp CPU ready: {}", llama_print_system_info()); + if (argc < 2) { + std::println("Pass a local GGUF path to decode and sample: mcpp run -- model.gguf"); + return 0; + } + auto params = llama_model_default_params(); + params.n_gpu_layers = 0; + const auto model = std::unique_ptr( + llama_model_load_from_file(argv[1], params), llama_model_free); + if (!model) return 1; + auto context_params = llama_context_default_params(); + context_params.n_ctx = 64; + context_params.n_threads = 2; + const auto context = std::unique_ptr( + llama_init_from_model(model.get(), context_params), llama_free); + if (!context) return 2; + if (llama_vocab_n_tokens(llama_model_get_vocab(model.get())) < 4) return 3; + llama_token tokens[]{1, 2, 3}; + if (llama_decode(context.get(), llama_batch_get_one(tokens, 3))) return 4; + const auto sampler = std::unique_ptr( + llama_sampler_init_greedy(), llama_sampler_free); + const auto sampled = llama_sampler_sample(sampler.get(), context.get(), -1); + if (sampled < 0 || sampled >= llama_vocab_n_tokens(llama_model_get_vocab(model.get()))) return 5; + std::println("CPU decode passed; sampled token {}", sampled); +} diff --git a/templates/cpu/template.toml b/templates/cpu/template.toml new file mode 100644 index 0000000..3336299 --- /dev/null +++ b/templates/cpu/template.toml @@ -0,0 +1,4 @@ +[template] +description = "Initialize llama.cpp on the CPU and optionally decode a local GGUF model" +default = true +post_message = "Run `mcpp run` for CPU initialization, or `mcpp run -- /path/to/model.gguf` for a decode and sample." diff --git a/tools/generate_build_files.py b/tools/generate_build_files.py new file mode 100644 index 0000000..28677cb --- /dev/null +++ b/tools/generate_build_files.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +"""Materialize stable manifest-generated build inputs for path consumers too.""" +import argparse +from pathlib import Path +import tomllib + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--check", action="store_true") + args = parser.parse_args() + root = Path(__file__).resolve().parents[1] + manifest = tomllib.loads((root / "mcpp.toml").read_text()) + for relative, content in manifest["generated_files"].items(): + path = root / relative + if args.check: + if not path.is_file() or path.read_text() != content: + raise SystemExit(f"Stale or absent build input: {relative}") + else: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(content) + print("Stable generated inputs match the manifest") + + +if __name__ == "__main__": + main() diff --git a/tools/test_template.py b/tools/test_template.py new file mode 100644 index 0000000..cb4712d --- /dev/null +++ b/tools/test_template.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +"""Render an installed candidate's default mcpp template, then build and run it.""" +import argparse +import json +import os +from pathlib import Path +import shutil +import subprocess +import tempfile +import tomllib + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--mcpp", default="mcpp") + parser.add_argument("--toolchain", default="llvm@23.1.3") + parser.add_argument("--run-arg", action="append", default=[], help="argument passed to the generated application") + args = parser.parse_args() + root = Path(__file__).resolve().parents[1] + metadata = tomllib.loads((root / "mcpp.toml").read_text())["package"] + namespace, name, version = (metadata[key] for key in ("namespace", "name", "version")) + identity = namespace + "." + name + with tempfile.TemporaryDirectory(prefix=name + "-template-") as directory: + temporary = Path(directory) + home = temporary / "home" + package = home / "registry/data/xpkgs" / (namespace + "-x-" + name) / version / (name + "-" + version) + shutil.copytree(root, package, ignore=shutil.ignore_patterns( + ".git", "target", ".mcpp", ".xlings", "__pycache__", "mcpp.lock", "compile_commands.json", "mcpp-2026.*")) + index = home / "indices/mcpplibs/pkgs/mwrap" + index.mkdir(parents=True) + entry = '{url="https://example.invalid/candidate.tar.gz",sha256="fixture"}' + descriptor = ('package={spec="1",namespace=' + json.dumps(namespace) + ',name=' + json.dumps(name) + + ',description="Installed template fixture",type="package",mcpp="mcpp.toml",xpm={') + descriptor += ",".join(platform + "={[" + json.dumps(version) + "]=" + entry + "}" + for platform in ("linux", "macosx", "windows")) + "}}\n" + (index / (identity + ".lua")).write_text(descriptor) + env = dict(os.environ, MCPP_HOME=str(home)) + selector = identity + "@" + version + for command in ([args.mcpp, "new", "--list-templates", selector], + [args.mcpp, "new", "quickstart", "--template", selector]): + print("+", " ".join(command), flush=True) + subprocess.run(command, cwd=temporary, env=env, check=True) + project = temporary / "quickstart" + manifest = project / "mcpp.toml" + text = manifest.read_text() + dependency = tomllib.loads(text)["dependencies"][identity] + options = {"version": dependency} if isinstance(dependency, str) else dependency + assert options["version"] == version, options + replacement = '{ path = ' + json.dumps(package.as_posix()) + if options.get("features"): + replacement += ', features = ' + json.dumps(options["features"]) + replacement += ' }' + lines = text.splitlines() + matches = [i for i, line in enumerate(lines) if line.startswith(json.dumps(identity) + " =")] + assert len(matches) == 1, "Expected exactly one qualified dependency from self.name" + lines[matches[0]] = json.dumps(identity) + " = " + replacement + manifest.write_text("\n".join(lines) + "\n") + command = [args.mcpp, "run", "--toolchain", args.toolchain] + if args.run_arg: + command += ["--", *args.run_arg] + print("+", " ".join(command), flush=True) + subprocess.run(command, cwd=project, check=True) + + +if __name__ == "__main__": + main() From 63f7596f9ec69fc264c72ce4a740d7d1a368b56e Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sat, 24 Oct 2026 06:05:05 +0900 Subject: [PATCH 02/13] fix: align the Vulkan runtime pin with the SDK dependency --- .agents/docs/2026-10-24-project-template-checkpoint.md | 2 ++ mcpp.toml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.agents/docs/2026-10-24-project-template-checkpoint.md b/.agents/docs/2026-10-24-project-template-checkpoint.md index 2ea4a2f..f2c37ea 100644 --- a/.agents/docs/2026-10-24-project-template-checkpoint.md +++ b/.agents/docs/2026-10-24-project-template-checkpoint.md @@ -9,3 +9,5 @@ The template test uses the actual mcpp package renderer and verifies the emitted A fresh path consumer revealed missing generated build inputs that earlier install-time materialization had hidden. The four stable generated inputs are now checked in verbatim from generated_files, with tools/generate_build_files.py --check guarding drift. Feature-specific Metal/Vulkan generation still uses the build output. Current libc++ also exposed missing standard includes in upstream source; two scoped wrapper compile-flag rules provide cstdlib/cerrno without patching upstream. mcpp is pinned to 2026.10.21.1. The root package built under LLVM 23.1.3 and all 116 existing unit/repository/build-helper checks passed with LLAMACPP_REQUIRE_BUILD_HELPER=1. Native CPU CI now additionally executes the real template with the existing checksummed model. No merge or release is performed by this checkpoint. + +Native CI exposed an existing exact-version conflict: compat.vulkan@1.4.357.0 requires compat.vulkan-runtime@2026.09.11 while this wrapper directly requested 2026.09.07. The direct pin is aligned to 2026.09.11 rather than linking or mangling two copies of a runtime with no module. Evidence: job 120654792434. diff --git a/mcpp.toml b/mcpp.toml index c919757..5747b17 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -338,7 +338,7 @@ flags = [ [feature-deps.backend-vulkan] compat.vulkan = "1.4.357.0" compat.spirv-headers = "1.4.357.0" -compat.vulkan-runtime = "2026.09.07" +compat.vulkan-runtime = "2026.09.11" # shaderc carries glslc, which upstream's generator drives by name and whose # flags are not glslang's. mesa-lavapipe is a Vulkan device that needs no GPU; From 663c86c759d68c4df9f92053956afb5fb1285448 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sat, 24 Oct 2026 06:10:06 +0900 Subject: [PATCH 03/13] test: verify the ARM runtime closure against the current managed SDK --- .../2026-10-24-project-template-checkpoint.md | 2 + .github/workflows/ci.yml | 15 +++---- tools/check_native_runtime.py | 45 +++++++++++++++++++ 3 files changed, 52 insertions(+), 10 deletions(-) create mode 100644 tools/check_native_runtime.py diff --git a/.agents/docs/2026-10-24-project-template-checkpoint.md b/.agents/docs/2026-10-24-project-template-checkpoint.md index f2c37ea..232614b 100644 --- a/.agents/docs/2026-10-24-project-template-checkpoint.md +++ b/.agents/docs/2026-10-24-project-template-checkpoint.md @@ -11,3 +11,5 @@ A fresh path consumer revealed missing generated build inputs that earlier insta mcpp is pinned to 2026.10.21.1. The root package built under LLVM 23.1.3 and all 116 existing unit/repository/build-helper checks passed with LLAMACPP_REQUIRE_BUILD_HELPER=1. Native CPU CI now additionally executes the real template with the existing checksummed model. No merge or release is performed by this checkpoint. Native CI exposed an existing exact-version conflict: compat.vulkan@1.4.357.0 requires compat.vulkan-runtime@2026.09.11 while this wrapper directly requested 2026.09.07. The direct pin is aligned to 2026.09.11 rather than linking or mangling two copies of a runtime with no module. Evidence: job 120654792434. + +The native ARM64 job decoded correctly, but its old static-file-label check rejected the current engine-managed glibc loader. The check now inspects actual PT_INTERP and the loader-reported complete dependency closure: static remains accepted, dynamic is accepted only when loader and every resolved library belong to the declared isolated registry. Any system-library escape fails. This retains the no-host-runtime invariant and architecture check without changing the engine or skipping inference. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e6b290f..863c33d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -198,16 +198,11 @@ jobs: test_bin=$(find target -type f -path "*/bin/cpu_decode" -print -quit) test -x "${helper}" test -n "${test_bin}" - for binary in "${helper}" "${test_bin}"; do - file "${binary}" | tee /tmp/file.log - grep -F "ARM aarch64" /tmp/file.log - grep -F "statically linked" /tmp/file.log - if readelf -l "${binary}" | grep -q INTERP; then - echo "PT_INTERP present in ${binary}" - exit 1 - fi - echo "PT_INTERP absent in ${binary}" - done + # Current mcpp may bind a dynamic managed glibc runtime. + # Validate PT_INTERP and every loaded path, rather than assuming + # the host helper and target must both have a static file label. + python3 tools/check_native_runtime.py --home "${MCPP_HOME}" \ + --arch "ARM aarch64" "${helper}" "${test_bin}" test -f compile_commands.json grep -F "/arch/arm/quants.c" compile_commands.json diff --git a/tools/check_native_runtime.py b/tools/check_native_runtime.py new file mode 100644 index 0000000..c648ab7 --- /dev/null +++ b/tools/check_native_runtime.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +"""Verify native ELF artifacts use static or explicitly managed runtimes.""" +import argparse +from pathlib import Path +import re +import subprocess + + +def output(command): + return subprocess.check_output(command, text=True, stderr=subprocess.STDOUT) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--home", required=True, type=Path) + parser.add_argument("--arch", required=True) + parser.add_argument("binaries", nargs="+", type=Path) + args = parser.parse_args() + registry = (args.home / "registry").resolve() + for binary in args.binaries: + binary = binary.resolve() + description = output(["file", str(binary)]) + print(description, end="") + if args.arch not in description: + raise SystemExit(f"Wrong artifact architecture: {binary}") + headers = output(["readelf", "-l", str(binary)]) + interpreter = re.search(r"Requesting program interpreter: ([^\]]+)", headers) + if not interpreter: + if "statically linked" not in description: + raise SystemExit(f"Artifact has neither a managed PT_INTERP nor static linkage: {binary}") + print(f"PT_INTERP absent: {binary}") + continue + loader = Path(interpreter[1]).resolve() + if not loader.is_relative_to(registry) or "xim-x-glibc" not in loader.parts: + raise SystemExit(f"Unmanaged ELF interpreter: {loader}") + dependencies = output([str(loader), "--list", str(binary)]) + print(dependencies, end="") + for path in re.findall(r"(/[^\s()]+)", dependencies): + if not Path(path).resolve().is_relative_to(registry): + raise SystemExit(f"Host library escaped the managed runtime: {path}") + print(f"PT_INTERP and dependency closure are managed: {binary}") + + +if __name__ == "__main__": + main() From 2de7714a531b12af65c8989f64fd6c5a61361d43 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sat, 24 Oct 2026 06:24:04 +0900 Subject: [PATCH 04/13] test: validate Vulkan against the pinned runtime adapter corrections --- .../2026-10-24-project-template-checkpoint.md | 2 ++ .github/workflows/ci.yml | 15 +++++++++++++++ .gitignore | 1 + tools/test_template.py | 2 +- 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/.agents/docs/2026-10-24-project-template-checkpoint.md b/.agents/docs/2026-10-24-project-template-checkpoint.md index 232614b..88c7717 100644 --- a/.agents/docs/2026-10-24-project-template-checkpoint.md +++ b/.agents/docs/2026-10-24-project-template-checkpoint.md @@ -13,3 +13,5 @@ mcpp is pinned to 2026.10.21.1. The root package built under LLVM 23.1.3 and all Native CI exposed an existing exact-version conflict: compat.vulkan@1.4.357.0 requires compat.vulkan-runtime@2026.09.11 while this wrapper directly requested 2026.09.07. The direct pin is aligned to 2026.09.11 rather than linking or mangling two copies of a runtime with no module. Evidence: job 120654792434. The native ARM64 job decoded correctly, but its old static-file-label check rejected the current engine-managed glibc loader. The check now inspects actual PT_INTERP and the loader-reported complete dependency closure: static remains accepted, dynamic is accepted only when loader and every resolved library belong to the declared isolated registry. Any system-library escape fails. This retains the no-host-runtime invariant and architecture check without changing the engine or skipping inference. + +The next Vulkan CI passed compilation but strict mode exposed static adapter/header anchors shared between program and multiple DSOs. The actual provider defaults are fixed in index commit a4130c75a49c6e9df03690743467696ef81d3a19, and only the Vulkan CI job checks out that exact candidate index and routes compat through it. This tests the paired change without merging the index or weakening --strict. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 863c33d..973ef3b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,7 @@ permissions: env: MCPP_VERSION: "2026.10.21.1" MCPP_RELEASE_BASE: https://github.com/mcpp-community/mcpp/releases/download + VULKAN_INDEX_COMMIT: "a4130c75a49c6e9df03690743467696ef81d3a19" jobs: unit-and-import: @@ -275,6 +276,20 @@ jobs: MCPP_HOME: /tmp/llamacpp-vulkan-mcpp-home steps: - uses: actions/checkout@v4 + - name: Checkout the candidate runtime adapter metadata + uses: actions/checkout@v4 + with: + repository: mcpplibs/mcpp-index + ref: ${{ env.VULKAN_INDEX_COMMIT }} + path: .candidate-index + - name: Route Vulkan dependencies through the candidate index + run: | + python3 - <<'PY' + from pathlib import Path + import json + with Path("mcpp.toml").open("a", encoding="utf-8") as manifest: + manifest.write('\n[indices]\ncompat = { path = ' + json.dumps(Path(".candidate-index").resolve().as_posix()) + ' }\n') + PY - uses: actions/setup-python@v5 with: python-version: "3.12" diff --git a/.gitignore b/.gitignore index 7b4546b..dfa5df0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .mcpp/ .xlings/ +.candidate-index/ target/ generated/* !generated/ggml_cpp.cpp diff --git a/tools/test_template.py b/tools/test_template.py index cb4712d..0a9955c 100644 --- a/tools/test_template.py +++ b/tools/test_template.py @@ -25,7 +25,7 @@ def main(): home = temporary / "home" package = home / "registry/data/xpkgs" / (namespace + "-x-" + name) / version / (name + "-" + version) shutil.copytree(root, package, ignore=shutil.ignore_patterns( - ".git", "target", ".mcpp", ".xlings", "__pycache__", "mcpp.lock", "compile_commands.json", "mcpp-2026.*")) + ".git", "target", ".mcpp", ".xlings", ".candidate-index", "__pycache__", "mcpp.lock", "compile_commands.json", "mcpp-2026.*")) index = home / "indices/mcpplibs/pkgs/mwrap" index.mkdir(parents=True) entry = '{url="https://example.invalid/candidate.tar.gz",sha256="fixture"}' From f5a046c332a0929281692a102c5819bc2d40f172 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sat, 24 Oct 2026 07:31:06 +0900 Subject: [PATCH 05/13] build: validate runnable templates with mcpp 2026.10.24.1 --- .github/workflows/ci.yml | 2 +- .xlings.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 973ef3b..0aa1fe0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ permissions: contents: read env: - MCPP_VERSION: "2026.10.21.1" + MCPP_VERSION: "2026.10.24.1" MCPP_RELEASE_BASE: https://github.com/mcpp-community/mcpp/releases/download VULKAN_INDEX_COMMIT: "a4130c75a49c6e9df03690743467696ef81d3a19" diff --git a/.xlings.json b/.xlings.json index 8475678..b914806 100644 --- a/.xlings.json +++ b/.xlings.json @@ -1 +1 @@ -{"workspace":{"xim:mcpp":"2026.10.21.1"}} +{"workspace":{"xim:mcpp":"2026.10.24.1"}} From 5028a1aa4f741db4dbd86d6ebd1928ef21027147 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sat, 24 Oct 2026 10:09:05 +0900 Subject: [PATCH 06/13] docs: unify the concise package README and move details into docs --- README.md | 249 +++++------------------------------------------- docs/usage.md | 255 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 277 insertions(+), 227 deletions(-) create mode 100644 docs/usage.md diff --git a/README.md b/README.md index ae18723..7271520 100644 --- a/README.md +++ b/README.md @@ -1,253 +1,48 @@ # llama.cpp-m -`llama.cpp-m` packages a pinned, audited llama.cpp checkpoint as a C++23 -module for mcpp. The public module is: +llama.cpp **b10069** as a C++23 module, preserving the upstream C API through `import llamacpp;`. -```cpp -import llamacpp; -``` - -The package version IS llama.cpp's build number, plus this packaging's own -revision of it: `b10069.3`. CPU is the default backend; Metal is an additive -feature for macOS ARM64 and Vulkan an additive feature for Linux. Consumers pin -exactly -- `b10069` is not semver, so no range expresses "b10069 or later" -- -which means a consumer wanting a feature names the revision that has it. -`backend-vulkan` arrived in `b10069.1`. - -## Add The Package +## Quick start -After `b10069.3` is published in mcpp-index: +Use mcpp **2026.10.24.1**. The candidate revision below requires index publication. -```bash -mcpp add ggml-org:llamacpp@b10069.3 -``` - -The equivalent manifest entry is: - -```toml -[dependencies.ggml-org] -llamacpp = "b10069.3" +```sh +mcpp new inference --template ggml-org.llamacpp@b10069.3 +cd inference +mcpp run ``` -For Metal on macOS ARM64: - -```toml -[dependencies.ggml-org] -llamacpp = { version = "b10069.3", features = ["backend-metal"] } -``` +The default run initializes the CPU backend without downloading a model. +Use `mcpp run -- /path/to/model.gguf` to decode a small batch and sample a token. -For Vulkan on Linux: +## Existing projects ```toml -[dependencies.ggml-org] -llamacpp = { version = "b10069.3", features = ["backend-vulkan"] } +[dependencies] +"ggml-org.llamacpp" = "b10069.3" ``` -That line is the whole diff. The shader compiler, the Khronos loader, the -SPIR-V headers and the adapter that lets a built binary reach the machine's own -driver are declared by this package under the feature, so a consumer names none -of them -- and a consumer that does not name the feature acquires none of them -either. - -## Minimal CPU Program - ```cpp import std; import llamacpp; - int main() { llama_backend_init(); - - auto params = llama_model_default_params(); - params.n_gpu_layers = 0; - llama_model * model = llama_model_load_from_file("model.gguf", params); - if (!model) { - llama_backend_free(); - return 1; - } - - llama_model_free(model); + std::println("{}", llama_print_system_info()); llama_backend_free(); } ``` -Build and run it with the normal mcpp commands: - -```bash -mcpp build -mcpp run -``` - -Model loading alone does not perform inference. See `tests/cpu_decode.cpp` for -a compact load/decode/sample path and `examples/chat-cpu` for token generation. - -## CPU Chat Example - -The checked-in example uses a path dependency on this repository: - -```bash -cd examples/chat-cpu -mcpp run -- /path/to/model.gguf \ - 'User: Introduce yourself in one sentence.\nAssistant:' -``` - -It sets `n_gpu_layers = 0`, imports `llamacpp`, and performs real -tokenization, decode, and sampling. - -## Metal Chat Example - -Metal requires macOS ARM64 and the `backend-metal` feature: - -```bash -cd examples/chat-metal -mcpp run -- /path/to/model.gguf metal \ - 'User: Introduce yourself in one sentence.\nAssistant:' -``` - -The example requests GPU offload and exits nonzero if Metal cannot be used. A -valid run should report all of the following: - -```text -using embedded metal library -GPU name: MTL0 (...) -offloaded N/M layers to GPU -MTL0_Mapped model buffer size = ... MiB -MTL0 compute buffer size = ... MiB -backend=metal ... generated_tokens=32 -``` - -The package test is stricter than successful compilation: it checks Metal -registration, graph execution, positive layer offload, positive Metal-owned -model and compute buffers, decode, and sampling. The Metal example exits -nonzero before reporting success if either Metal buffer is absent. - -## Vulkan Chat Example - -Vulkan requires Linux and the `backend-vulkan` feature: - -```bash -cd examples/chat-vulkan -mcpp run -- /path/to/model.gguf vulkan \ - 'User: Introduce yourself in one sentence.\nAssistant:' -``` - -The example refuses to report a device run that did not happen: it exits -nonzero when Vulkan is requested and no layer was offloaded, because a build -that quietly fell back to the CPU produces output indistinguishable from -success. - -### How the shaders are built - -The backend needs 134 shader sets, and upstream generates them with a tool it -keeps in its own tree. `build.mcpp` does not run that tool 134 times; it -DECLARES 136 build-graph edges -- one per shader, one to compile the generator -from the vendored source, one for the header they share. Each shader is then -incremental, parallel, and attributable to the edge that failed rather than to -`build.mcpp exited 1`. - -The build program does exactly one thing itself: it asks `glslc` which -extensions it accepts. That answer has two readers -- the generator, which -decides which variants to emit, and `ggml-vulkan.cpp`, which decides which to -look for -- and asking twice would make one truth into two. - -### A libstdc++ toolchain, on this checkpoint - -`backend-vulkan` builds with a libstdc++ toolchain. Under libc++ the compile of -upstream's `ggml-vulkan.cpp` stops at - -``` -error: invalid application of 'sizeof' to an incomplete type 'vk_memory_logger' - in instantiation of member function 'std::unique_ptr::~unique_ptr' -``` - -`vk_device_struct` holds a `std::unique_ptr` and its -destructor is instantiated at line 1015, while the class is defined at line -1920. Destroying a `unique_ptr` to an incomplete type is undefined behaviour; -libc++ has a static assertion for it and libstdc++ does not. It is upstream's -source rather than this packaging, and nothing in a build program can repair -it without patching the vendored tree, which this repository does not do. - -`build.mcpp` therefore refuses the combination and says so, instead of letting -the compiler produce a page of template diagnostics about a header the reader -did not write. The refusal became possible with mcpp 2026.9.6.3, which added -`mcpp::cxx_stdlib()`; the only signal available before that was the compiler's -NAME, and refusing on it would also have refused clang configured against -libstdc++, which builds this backend correctly. +Pin the exact build key; `b10069.3` is an upstream build identifier with a wrapper revision. -Everything else is unaffected: the CPU backend builds under both standard -libraries, measured. +## Scope -### Running without a GPU +CPU: Linux x86_64/arm64, Windows x86_64 and macOS arm64. +`backend-metal` adds Metal on macOS arm64; `backend-vulkan` adds Vulkan on Linux with libstdc++. +Vulkan with libc++ is refused for the documented upstream incomplete-type issue. -ggml keeps only Vulkan devices whose type is not `eCpu`, so a software -implementation is excluded for its type alone. Measured: Mesa's lavapipe -advertises `storageBuffer16BitAccess` and every feature the backend requires, -and is still dropped. Upstream ships the selector for this case, and a machine -with no GPU needs both halves of it: - -```bash -VK_DRIVER_FILES=/share/vulkan/icd.d/lvp_icd.x86_64.json \ -GGML_VK_VISIBLE_DEVICES=0 \ - mcpp test vulkan_decode --features backend-vulkan -``` +CUDA, mtmd, RPC and other backends are outside this checkpoint. Model coverage is documented separately. -### What the artifact depends on - -Measured on the built test binary, everything outside the mcpp registry: - -``` -$ ldd target/*/*/bin/vulkan_decode | grep -v mcpp/registry - linux-vdso.so.1 - libvulkan.so.1 => .../bin/libvulkan.so.1 -``` - -The Khronos loader is built from source by `compat:vulkan` and travels beside -the binary; the kernel's vDSO is the only thing left. The shader generator is -statically linked for the same reason -- it runs from inside the build, and a -build tool that needs the host's libstdc++ is a host dependency this ecosystem -does not accept. - -The package test is stricter than a token in range: it decodes the same prompt -twice from one model, once with every layer on the host and once with every -layer offloaded, and requires greedy sampling to produce the SAME token. A -token inside the vocabulary is produced by a backend that computed nonsense -just as readily as by one that worked. The equality is only evidence about the -device if the device ran, so the offload is asserted from llama.cpp's own log -before the tokens are compared. - -## Supported Boundary - -`b10069.3` includes: - -- the public llama.cpp C API exposed through `import llamacpp;`; -- the CPU backend on Linux x86_64, Linux ARM64, Windows x86_64, and macOS ARM64; -- the Metal backend on macOS ARM64; -- the Vulkan backend on Linux, under `backend-vulkan`, with a libstdc++ - toolchain (a libc++ one is refused by name, for the upstream reason recorded - above); -- architecture-specific x86_64 and ARM64 CPU source selection. - -It does not include `mtmd`, CUDA, RPC, or other upstream backends. It also does -not claim that every upstream model architecture has been tested. -Deprecated upstream C APIs remain exported for API completeness; code that -calls them may receive the deprecation warnings defined by upstream. - -See [the update policy](docs/upstream-update-policy.md) for versioning and -checkpoint selection, and [the b10069 validation record](docs/validation/b10069.md) -for exact evidence and remaining release gates. - -## Quickstart project template - -The b10069.3 package adds a runnable default template. After that version is indexed: - -```sh -mcpp new my-llama --template ggml-org.llamacpp@b10069.3 -cd my-llama -mcpp run -``` +## Documentation -The default run initializes the CPU backend and prints its capabilities without -downloading a model. `mcpp run -- /path/to/model.gguf` loads that local model, -decodes a small batch and samples a token. This smoke example is a starting -point; the existing chat-cpu example demonstrates prompt tokenization and chat. -`python3 tools/test_template.py` exercises the real renderer and generated project. +[Usage and backends](docs/usage.md) · [CPU chat](examples/chat-cpu) · +[Update policy](docs/upstream-update-policy.md) · [Validation](docs/validation/b10069.md) · [MIT](LICENSE) diff --git a/docs/usage.md b/docs/usage.md new file mode 100644 index 0000000..80febac --- /dev/null +++ b/docs/usage.md @@ -0,0 +1,255 @@ +Detailed usage and background. See the [README](../README.md) for the current candidate quickstart and support boundary. + +# llama.cpp-m + +`llama.cpp-m` packages a pinned, audited llama.cpp checkpoint as a C++23 +module for mcpp. The public module is: + +```cpp +import llamacpp; +``` + +The package version IS llama.cpp's build number, plus this packaging's own +revision of it: `b10069.3`. CPU is the default backend; Metal is an additive +feature for macOS ARM64 and Vulkan an additive feature for Linux. Consumers pin +exactly -- `b10069` is not semver, so no range expresses "b10069 or later" -- +which means a consumer wanting a feature names the revision that has it. +`backend-vulkan` arrived in `b10069.1`. + +## Add The Package + +After `b10069.3` is published in mcpp-index: + +```bash +mcpp add ggml-org:llamacpp@b10069.3 +``` + +The equivalent manifest entry is: + +```toml +[dependencies.ggml-org] +llamacpp = "b10069.3" +``` + +For Metal on macOS ARM64: + +```toml +[dependencies.ggml-org] +llamacpp = { version = "b10069.3", features = ["backend-metal"] } +``` + +For Vulkan on Linux: + +```toml +[dependencies.ggml-org] +llamacpp = { version = "b10069.3", features = ["backend-vulkan"] } +``` + +That line is the whole diff. The shader compiler, the Khronos loader, the +SPIR-V headers and the adapter that lets a built binary reach the machine's own +driver are declared by this package under the feature, so a consumer names none +of them -- and a consumer that does not name the feature acquires none of them +either. + +## Minimal CPU Program + +```cpp +import std; +import llamacpp; + +int main() { + llama_backend_init(); + + auto params = llama_model_default_params(); + params.n_gpu_layers = 0; + llama_model * model = llama_model_load_from_file("model.gguf", params); + if (!model) { + llama_backend_free(); + return 1; + } + + llama_model_free(model); + llama_backend_free(); +} +``` + +Build and run it with the normal mcpp commands: + +```bash +mcpp build +mcpp run +``` + +Model loading alone does not perform inference. See `tests/cpu_decode.cpp` for +a compact load/decode/sample path and `examples/chat-cpu` for token generation. + +## CPU Chat Example + +The checked-in example uses a path dependency on this repository: + +```bash +cd examples/chat-cpu +mcpp run -- /path/to/model.gguf \ + 'User: Introduce yourself in one sentence.\nAssistant:' +``` + +It sets `n_gpu_layers = 0`, imports `llamacpp`, and performs real +tokenization, decode, and sampling. + +## Metal Chat Example + +Metal requires macOS ARM64 and the `backend-metal` feature: + +```bash +cd examples/chat-metal +mcpp run -- /path/to/model.gguf metal \ + 'User: Introduce yourself in one sentence.\nAssistant:' +``` + +The example requests GPU offload and exits nonzero if Metal cannot be used. A +valid run should report all of the following: + +```text +using embedded metal library +GPU name: MTL0 (...) +offloaded N/M layers to GPU +MTL0_Mapped model buffer size = ... MiB +MTL0 compute buffer size = ... MiB +backend=metal ... generated_tokens=32 +``` + +The package test is stricter than successful compilation: it checks Metal +registration, graph execution, positive layer offload, positive Metal-owned +model and compute buffers, decode, and sampling. The Metal example exits +nonzero before reporting success if either Metal buffer is absent. + +## Vulkan Chat Example + +Vulkan requires Linux and the `backend-vulkan` feature: + +```bash +cd examples/chat-vulkan +mcpp run -- /path/to/model.gguf vulkan \ + 'User: Introduce yourself in one sentence.\nAssistant:' +``` + +The example refuses to report a device run that did not happen: it exits +nonzero when Vulkan is requested and no layer was offloaded, because a build +that quietly fell back to the CPU produces output indistinguishable from +success. + +### How the shaders are built + +The backend needs 134 shader sets, and upstream generates them with a tool it +keeps in its own tree. `build.mcpp` does not run that tool 134 times; it +DECLARES 136 build-graph edges -- one per shader, one to compile the generator +from the vendored source, one for the header they share. Each shader is then +incremental, parallel, and attributable to the edge that failed rather than to +`build.mcpp exited 1`. + +The build program does exactly one thing itself: it asks `glslc` which +extensions it accepts. That answer has two readers -- the generator, which +decides which variants to emit, and `ggml-vulkan.cpp`, which decides which to +look for -- and asking twice would make one truth into two. + +### A libstdc++ toolchain, on this checkpoint + +`backend-vulkan` builds with a libstdc++ toolchain. Under libc++ the compile of +upstream's `ggml-vulkan.cpp` stops at + +``` +error: invalid application of 'sizeof' to an incomplete type 'vk_memory_logger' + in instantiation of member function 'std::unique_ptr::~unique_ptr' +``` + +`vk_device_struct` holds a `std::unique_ptr` and its +destructor is instantiated at line 1015, while the class is defined at line +1920. Destroying a `unique_ptr` to an incomplete type is undefined behaviour; +libc++ has a static assertion for it and libstdc++ does not. It is upstream's +source rather than this packaging, and nothing in a build program can repair +it without patching the vendored tree, which this repository does not do. + +`build.mcpp` therefore refuses the combination and says so, instead of letting +the compiler produce a page of template diagnostics about a header the reader +did not write. The refusal became possible with mcpp 2026.9.6.3, which added +`mcpp::cxx_stdlib()`; the only signal available before that was the compiler's +NAME, and refusing on it would also have refused clang configured against +libstdc++, which builds this backend correctly. + +Everything else is unaffected: the CPU backend builds under both standard +libraries, measured. + +### Running without a GPU + +ggml keeps only Vulkan devices whose type is not `eCpu`, so a software +implementation is excluded for its type alone. Measured: Mesa's lavapipe +advertises `storageBuffer16BitAccess` and every feature the backend requires, +and is still dropped. Upstream ships the selector for this case, and a machine +with no GPU needs both halves of it: + +```bash +VK_DRIVER_FILES=/share/vulkan/icd.d/lvp_icd.x86_64.json \ +GGML_VK_VISIBLE_DEVICES=0 \ + mcpp test vulkan_decode --features backend-vulkan +``` + +### What the artifact depends on + +Measured on the built test binary, everything outside the mcpp registry: + +``` +$ ldd target/*/*/bin/vulkan_decode | grep -v mcpp/registry + linux-vdso.so.1 + libvulkan.so.1 => .../bin/libvulkan.so.1 +``` + +The Khronos loader is built from source by `compat:vulkan` and travels beside +the binary; the kernel's vDSO is the only thing left. The shader generator is +statically linked for the same reason -- it runs from inside the build, and a +build tool that needs the host's libstdc++ is a host dependency this ecosystem +does not accept. + +The package test is stricter than a token in range: it decodes the same prompt +twice from one model, once with every layer on the host and once with every +layer offloaded, and requires greedy sampling to produce the SAME token. A +token inside the vocabulary is produced by a backend that computed nonsense +just as readily as by one that worked. The equality is only evidence about the +device if the device ran, so the offload is asserted from llama.cpp's own log +before the tokens are compared. + +## Supported Boundary + +`b10069.3` includes: + +- the public llama.cpp C API exposed through `import llamacpp;`; +- the CPU backend on Linux x86_64, Linux ARM64, Windows x86_64, and macOS ARM64; +- the Metal backend on macOS ARM64; +- the Vulkan backend on Linux, under `backend-vulkan`, with a libstdc++ + toolchain (a libc++ one is refused by name, for the upstream reason recorded + above); +- architecture-specific x86_64 and ARM64 CPU source selection. + +It does not include `mtmd`, CUDA, RPC, or other upstream backends. It also does +not claim that every upstream model architecture has been tested. +Deprecated upstream C APIs remain exported for API completeness; code that +calls them may receive the deprecation warnings defined by upstream. + +See [the update policy](../docs/upstream-update-policy.md) for versioning and +checkpoint selection, and [the b10069 validation record](../docs/validation/b10069.md) +for exact evidence and remaining release gates. + +## Quickstart project template + +The b10069.3 package adds a runnable default template. After that version is indexed: + +```sh +mcpp new my-llama --template ggml-org.llamacpp@b10069.3 +cd my-llama +mcpp run +``` + +The default run initializes the CPU backend and prints its capabilities without +downloading a model. `mcpp run -- /path/to/model.gguf` loads that local model, +decodes a small batch and samples a token. This smoke example is a starting +point; the existing chat-cpu example demonstrates prompt tokenization and chat. +`python3 tools/test_template.py` exercises the real renderer and generated project. From aadf2e85a2767799a368cbb56c0492c861674aca Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 25 Oct 2026 07:09:46 +0900 Subject: [PATCH 07/13] feat: unify mwrap identity and upstream-aligned first release --- .../2026-10-25-unified-mwrap-checkpoint.md | 8 ++ .github/workflows/ci.yml | 5 +- .github/workflows/release.yml | 86 ++++++------------- README.md | 59 +++++++------ README.zh.md | 53 ++++++++++++ docs/upstream-update-policy.md | 2 +- docs/usage.md | 30 +++---- docs/validation/b10069.md | 2 +- examples/chat-cpu/mcpp.toml | 2 +- examples/chat-cpu/src/main.cpp | 4 +- examples/chat-metal/mcpp.toml | 2 +- examples/chat-metal/src/main.cpp | 4 +- examples/chat-vulkan/mcpp.toml | 2 +- examples/chat-vulkan/src/main.cpp | 4 +- mcpp.toml | 29 ++----- src/llamacpp.cppm | 4 +- src/macros.cppm | 25 ++++++ templates/cpu/src/main.cpp.in | 2 +- tests/cpu_decode.cpp | 6 +- tests/macros.cpp | 3 + tests/metal_decode.cpp | 2 +- tests/unit/test_build_contract.py | 2 +- tests/unit/test_check_release.py | 8 ++ tests/unit/test_repository_contract.py | 8 +- tests/vulkan_decode.cpp | 2 +- tools/check_mwrap_release.py | 33 +++++++ tools/check_release.py | 8 +- 27 files changed, 243 insertions(+), 152 deletions(-) create mode 100644 .agents/docs/2026-10-25-unified-mwrap-checkpoint.md create mode 100644 README.zh.md create mode 100644 src/macros.cppm create mode 100644 tests/macros.cpp create mode 100644 tools/check_mwrap_release.py diff --git a/.agents/docs/2026-10-25-unified-mwrap-checkpoint.md b/.agents/docs/2026-10-25-unified-mwrap-checkpoint.md new file mode 100644 index 0000000..e913b76 --- /dev/null +++ b/.agents/docs/2026-10-25-unified-mwrap-checkpoint.md @@ -0,0 +1,8 @@ +# Unified mwrap first release + +Package/module: `mcpplibs.mwrap.llamacpp`; upstream version: `b10069`. + +This checkpoint migrates wrapper identity while retaining upstream API names and SDK sources. +Default README is English with a mandatory Chinese counterpart; original section order is preserved. +Validation and release evidence are recorded in the PR and the index ecosystem ledger. +No old release tag or source resource is rewritten. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0aa1fe0..b98441e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,6 +19,9 @@ jobs: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 + - name: Mwrap identity and bilingual README contract + run: python3 tools/check_mwrap_release.py + - uses: actions/setup-python@v5 with: python-version: "3.12" @@ -440,4 +443,4 @@ jobs: # moved to upstream's checkpoint (mcpp-index#163). tag=$(sed -n 's/^version *= *"\(.*\)"/\1/p' mcpp.toml | head -1) echo "release contract for tag: $tag" - python3 tools/check_release.py --tag "$tag" + python3 tools/check_release.py --tag "mwrap-$tag" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 457e93b..237dac0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,24 +1,16 @@ -name: release - +name: Release on: push: - # The tag IS the package version, which is upstream's build number - # (`b10069`), optionally with a wrapper revision (`b10069.1`) — see - # docs/upstream-update-policy.md. `v*` was the third place the old - # semantic-version scheme was written down, and it silently did not fire. - tags: ["b[0-9]*"] - + tags: ["mwrap-*"] permissions: contents: read - jobs: - verify: - runs-on: ubuntu-24.04 + publish: + runs-on: ubuntu-latest + timeout-minutes: 30 permissions: + contents: write actions: read - contents: read - outputs: - mapping: ${{ steps.contract.outputs.mapping }} steps: - uses: actions/checkout@v4 with: @@ -26,62 +18,36 @@ jobs: - uses: actions/setup-python@v5 with: python-version: "3.12" + - name: Check tag, upstream version and bilingual entry pages + run: python3 tools/check_mwrap_release.py --tag "$GITHUB_REF_NAME" - name: Run complete unit suite run: python3 -m unittest discover -s tests/unit -p 'test_*.py' -v - - name: Verify immutable release contract - id: contract - env: - GITHUB_TOKEN: ${{ github.token }} - shell: bash - run: | - set -euo pipefail - mapping=$(python3 tools/check_release.py --tag "${GITHUB_REF_NAME}" | tail -n 1) - echo "${mapping}" - echo "mapping=${mapping}" >> "${GITHUB_OUTPUT}" - - name: Require latest successful CI run for the tag commit + - name: Verify immutable upstream release mapping + run: python3 tools/check_release.py --tag "$GITHUB_REF_NAME" + - name: Require latest successful source CI env: GH_TOKEN: ${{ github.token }} shell: bash run: | set -euo pipefail - output="${RUNNER_TEMP}/ci-runs.json" - downloaded=0 - for attempt in 1 2 3 4 5; do - if gh api \ - "repos/${GITHUB_REPOSITORY}/actions/workflows/ci.yml/runs?head_sha=${GITHUB_SHA}&per_page=100" \ - > "${output}"; then - downloaded=1 - break - fi - if [[ "${attempt}" -lt 5 ]]; then sleep $((attempt * 2)); fi - done - if [[ "${downloaded}" -ne 1 ]]; then - echo "failed to query CI workflow runs after 5 attempts" - exit 1 - fi - python3 tools/check_ci_run.py --runs "${output}" --sha "${GITHUB_SHA}" - - publish: - needs: verify - runs-on: ubuntu-24.04 - permissions: - contents: write - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Create release notes for the immutable tag archive + gh api "repos/${GITHUB_REPOSITORY}/actions/workflows/ci.yml/runs?head_sha=${GITHUB_SHA}&per_page=100" > "$RUNNER_TEMP/ci-runs.json" + python3 tools/check_ci_run.py --runs "$RUNNER_TEMP/ci-runs.json" --sha "$GITHUB_SHA" + - name: Build immutable source asset and publish env: GH_TOKEN: ${{ github.token }} - RELEASE_MAPPING: ${{ needs.verify.outputs.mapping }} shell: bash run: | set -euo pipefail - if gh release view "${GITHUB_REF_NAME}" >/dev/null 2>&1; then - echo "release ${GITHUB_REF_NAME} already exists; refusing to mutate it" - exit 1 + version="${GITHUB_REF_NAME#mwrap-}" + repo="${GITHUB_REPOSITORY#*/}" + asset="${repo}-${version}.tar.gz" + git archive --format=tar.gz --prefix="${repo}-${version}/" "$GITHUB_SHA" > "$RUNNER_TEMP/$asset" + (cd "$RUNNER_TEMP" && sha256sum "$asset" > "$asset.sha256") + if gh release view "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then + echo 'Release already exists; refusing to change immutable assets'; exit 1 fi - gh release create "${GITHUB_REF_NAME}" \ - --verify-tag \ - --title "llama.cpp-m ${GITHUB_REF_NAME#v}" \ - --notes "${RELEASE_MAPPING}" + extra=() + if [[ "$version" == *-rc* ]]; then extra+=(--prerelease); fi + gh release create "$GITHUB_REF_NAME" "$RUNNER_TEMP/$asset" "$RUNNER_TEMP/$asset.sha256" \ + --repo "$GITHUB_REPOSITORY" --verify-tag --title "$repo $version" \ + --notes "Module wrapper for upstream $version. New mwrap package identities become installable after mcpp-index publication; see the bilingual README for the tested support scope." "${extra[@]}" diff --git a/README.md b/README.md index 7271520..c738e1f 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,53 @@ # llama.cpp-m -llama.cpp **b10069** as a C++23 module, preserving the upstream C API through `import llamacpp;`. +> Pinned llama.cpp b10069 through C++23 modules; upstream API names are preserved. -## Quick start +**English** · [简体中文](README.zh.md) -Use mcpp **2026.10.24.1**. The candidate revision below requires index publication. +Use mcpp **2026.10.24.1**. The new mwrap identity becomes installable after index publication. + +## Add The Package ```sh -mcpp new inference --template ggml-org.llamacpp@b10069.3 -cd inference +mcpp new llama_app --template mcpplibs.mwrap.llamacpp@b10069 +cd llama_app mcpp run ``` -The default run initializes the CPU backend without downloading a model. -Use `mcpp run -- /path/to/model.gguf` to decode a small batch and sample a token. - -## Existing projects - ```toml [dependencies] -"ggml-org.llamacpp" = "b10069.3" +mcpplibs.mwrap.llamacpp = "b10069" ``` +## Minimal CPU Program + ```cpp -import std; -import llamacpp; -int main() { - llama_backend_init(); - std::println("{}", llama_print_system_info()); - llama_backend_free(); -} +import mcpplibs.mwrap.llamacpp; +int main() { llama_backend_init(); llama_backend_free(); } +``` + +The default template checks CPU initialization without downloading a model. + +## CPU Chat Example + +```sh +cd examples/chat-cpu +mcpp run -- /path/to/model.gguf "Hello" ``` -Pin the exact build key; `b10069.3` is an upstream build identifier with a wrapper revision. +A compatible local GGUF model is required for tokenization, decode and sampling. + +## Metal Chat Example -## Scope +Use `backend-metal` on macOS ARM64; [the example](examples/chat-metal) requires actual offload and Metal buffers. -CPU: Linux x86_64/arm64, Windows x86_64 and macOS arm64. -`backend-metal` adds Metal on macOS arm64; `backend-vulkan` adds Vulkan on Linux with libstdc++. -Vulkan with libc++ is refused for the documented upstream incomplete-type issue. +## Vulkan Chat Example -CUDA, mtmd, RPC and other backends are outside this checkpoint. Model coverage is documented separately. +Use `backend-vulkan` on Linux. [The example](examples/chat-vulkan) rejects silent CPU fallback. +Shader generation, libstdc++ constraints and driver boundaries are in [usage](docs/usage.md). -## Documentation +## Supported Boundary -[Usage and backends](docs/usage.md) · [CPU chat](examples/chat-cpu) · -[Update policy](docs/upstream-update-policy.md) · [Validation](docs/validation/b10069.md) · [MIT](LICENSE) +Pin `b10069` exactly; it is not a semver range. `.macros` exposes mapped constants. +Model quality and unsupported GPU configurations are not implied by the CPU template. +[Upstream policy](docs/upstream-update-policy.md) · [Validation](docs/validation/b10069.md) · [MIT](LICENSE) diff --git a/README.zh.md b/README.zh.md new file mode 100644 index 0000000..2384e7c --- /dev/null +++ b/README.zh.md @@ -0,0 +1,53 @@ +# llama.cpp-m + +> 通过 C++23 模块使用固定的 llama.cpp b10069,保留上游 API 名称。 + +[English](README.md) · **简体中文** + +使用 mcpp **2026.10.24.1**。新 mwrap 身份在索引发布后可直接安装。 + +## 添加依赖 + +```sh +mcpp new llama_app --template mcpplibs.mwrap.llamacpp@b10069 +cd llama_app +mcpp run +``` + +```toml +[dependencies] +mcpplibs.mwrap.llamacpp = "b10069" +``` + +## 最小 CPU 程序 + +```cpp +import mcpplibs.mwrap.llamacpp; +int main() { llama_backend_init(); llama_backend_free(); } +``` + +默认模板验证 CPU 初始化,无需下载模型。 + +## CPU 对话示例 + +```sh +cd examples/chat-cpu +mcpp run -- /path/to/model.gguf "Hello" +``` + +实际分词、解码与采样需要兼容的本地 GGUF 模型。 + +## Metal 对话示例 + +macOS ARM64 使用 `backend-metal`;[示例](examples/chat-metal) 要求真实 offload 和 Metal buffer。 + +## Vulkan 对话示例 + +Linux 使用 `backend-vulkan`;[示例](examples/chat-vulkan) 拒绝静默 CPU 回退。 +shader 生成、libstdc++ 限制及驱动边界见[使用说明](docs/usage.md)。 + +## 支持边界 + +精确固定 `b10069`,不使用 semver 范围;`.macros` 导出映射常量。 +CPU 模板通过不代表模型质量或未支持 GPU 配置通过。 +[上游策略](docs/upstream-update-policy.md) · [验证](docs/validation/b10069.md) · [MIT](LICENSE) diff --git a/docs/upstream-update-policy.md b/docs/upstream-update-policy.md index 8b526fa..5a612f6 100644 --- a/docs/upstream-update-policy.md +++ b/docs/upstream-update-policy.md @@ -13,7 +13,7 @@ The wrapper and upstream project have separate identities: version. - Every wrapper release maps to exactly one upstream tag and commit. - The package coordinate is `ggml-org:llamacpp`; consumers use - `import llamacpp;`. The namespace names whose library this is — llama.cpp is + `import mcpplibs.mwrap.llamacpp;`. The namespace names whose library this is — llama.cpp is ggml-org's — rather than who packaged it (see mcpp-index#163). - mcpp-index points only to immutable `llama.cpp-m` releases, never a moving upstream branch. diff --git a/docs/usage.md b/docs/usage.md index 80febac..83494d0 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -6,11 +6,11 @@ Detailed usage and background. See the [README](../README.md) for the current ca module for mcpp. The public module is: ```cpp -import llamacpp; +import mcpplibs.mwrap.llamacpp; ``` The package version IS llama.cpp's build number, plus this packaging's own -revision of it: `b10069.3`. CPU is the default backend; Metal is an additive +revision of it: `b10069`. CPU is the default backend; Metal is an additive feature for macOS ARM64 and Vulkan an additive feature for Linux. Consumers pin exactly -- `b10069` is not semver, so no range expresses "b10069 or later" -- which means a consumer wanting a feature names the revision that has it. @@ -18,31 +18,31 @@ which means a consumer wanting a feature names the revision that has it. ## Add The Package -After `b10069.3` is published in mcpp-index: +After `b10069` is published in mcpp-index: ```bash -mcpp add ggml-org:llamacpp@b10069.3 +mcpp add ggml-org:llamacpp@b10069 ``` The equivalent manifest entry is: ```toml -[dependencies.ggml-org] -llamacpp = "b10069.3" +[dependencies.mcpplibs.mwrap] +llamacpp = "b10069" ``` For Metal on macOS ARM64: ```toml -[dependencies.ggml-org] -llamacpp = { version = "b10069.3", features = ["backend-metal"] } +[dependencies.mcpplibs.mwrap] +llamacpp = { version = "b10069", features = ["backend-metal"] } ``` For Vulkan on Linux: ```toml -[dependencies.ggml-org] -llamacpp = { version = "b10069.3", features = ["backend-vulkan"] } +[dependencies.mcpplibs.mwrap] +llamacpp = { version = "b10069", features = ["backend-vulkan"] } ``` That line is the whole diff. The shader compiler, the Khronos loader, the @@ -55,7 +55,7 @@ either. ```cpp import std; -import llamacpp; +import mcpplibs.mwrap.llamacpp; int main() { llama_backend_init(); @@ -219,9 +219,9 @@ before the tokens are compared. ## Supported Boundary -`b10069.3` includes: +`b10069` includes: -- the public llama.cpp C API exposed through `import llamacpp;`; +- the public llama.cpp C API exposed through `import mcpplibs.mwrap.llamacpp;`; - the CPU backend on Linux x86_64, Linux ARM64, Windows x86_64, and macOS ARM64; - the Metal backend on macOS ARM64; - the Vulkan backend on Linux, under `backend-vulkan`, with a libstdc++ @@ -240,10 +240,10 @@ for exact evidence and remaining release gates. ## Quickstart project template -The b10069.3 package adds a runnable default template. After that version is indexed: +The b10069 package adds a runnable default template. After that version is indexed: ```sh -mcpp new my-llama --template ggml-org.llamacpp@b10069.3 +mcpp new my-llama --template mcpplibs.mwrap.llamacpp@b10069 cd my-llama mcpp run ``` diff --git a/docs/validation/b10069.md b/docs/validation/b10069.md index 8a25845..d5fa31e 100644 --- a/docs/validation/b10069.md +++ b/docs/validation/b10069.md @@ -10,7 +10,7 @@ branch. |---|---| | Wrapper | `llama.cpp-m b10069` | | Package | `ggml-org:llamacpp@b10069` | -| Module | `import llamacpp;` | +| Module | `import mcpplibs.mwrap.llamacpp;` | | Upstream tag | `b10069` | | Upstream commit | `178a6c44937154dc4c4eff0d166f4a044c4fceba` | | Official archive SHA-256 | `293a7c65a11e2203c5468a06d0d0e8d21dfff16ad08712b16c61efbe0d93e097` | diff --git a/examples/chat-cpu/mcpp.toml b/examples/chat-cpu/mcpp.toml index ec9f875..935f32f 100644 --- a/examples/chat-cpu/mcpp.toml +++ b/examples/chat-cpu/mcpp.toml @@ -8,4 +8,4 @@ kind = "bin" main = "src/main.cpp" [dependencies] -llamacpp = { path = "../.." } +"mcpplibs.mwrap.llamacpp" = { path = "../.." } diff --git a/examples/chat-cpu/src/main.cpp b/examples/chat-cpu/src/main.cpp index 73a278c..c724161 100644 --- a/examples/chat-cpu/src/main.cpp +++ b/examples/chat-cpu/src/main.cpp @@ -1,5 +1,5 @@ import std; -import llamacpp; +import mcpplibs.mwrap.llamacpp; namespace { @@ -88,7 +88,7 @@ int main(int argc, char ** argv) { int generated = 0; int exit_code = 0; - llama_token sampled = LLAMA_TOKEN_NULL; + llama_token sampled = mcpplibs::mwrap::llamacpp::macros::LLAMA_TOKEN_NULL; for (; generated < max_generated_tokens; ++generated) { const int decode_result = llama_decode(context, batch); if (decode_result != 0) { diff --git a/examples/chat-metal/mcpp.toml b/examples/chat-metal/mcpp.toml index 7cc7ed2..2e34391 100644 --- a/examples/chat-metal/mcpp.toml +++ b/examples/chat-metal/mcpp.toml @@ -8,4 +8,4 @@ kind = "bin" main = "src/main.cpp" [dependencies] -llamacpp = { path = "../..", features = ["backend-metal"] } +"mcpplibs.mwrap.llamacpp" = { path = "../..", features = ["backend-metal"] } diff --git a/examples/chat-metal/src/main.cpp b/examples/chat-metal/src/main.cpp index 75c73a0..10824dc 100644 --- a/examples/chat-metal/src/main.cpp +++ b/examples/chat-metal/src/main.cpp @@ -1,5 +1,5 @@ import std; -import llamacpp; +import mcpplibs.mwrap.llamacpp; namespace { @@ -146,7 +146,7 @@ int main(int argc, char ** argv) { int generated = 0; int exit_code = 0; - llama_token sampled = LLAMA_TOKEN_NULL; + llama_token sampled = mcpplibs::mwrap::llamacpp::macros::LLAMA_TOKEN_NULL; for (; generated < max_generated_tokens; ++generated) { const int decode_result = llama_decode(context, batch); if (decode_result != 0) { diff --git a/examples/chat-vulkan/mcpp.toml b/examples/chat-vulkan/mcpp.toml index 8ec2ef0..7241853 100644 --- a/examples/chat-vulkan/mcpp.toml +++ b/examples/chat-vulkan/mcpp.toml @@ -13,4 +13,4 @@ kind = "bin" main = "src/main.cpp" [dependencies] -llamacpp = { path = "../..", features = ["backend-vulkan"] } +"mcpplibs.mwrap.llamacpp" = { path = "../..", features = ["backend-vulkan"] } diff --git a/examples/chat-vulkan/src/main.cpp b/examples/chat-vulkan/src/main.cpp index 7d2a594..1e890c9 100644 --- a/examples/chat-vulkan/src/main.cpp +++ b/examples/chat-vulkan/src/main.cpp @@ -5,7 +5,7 @@ // reports which backend ran and how many layers were offloaded, and refuses to // claim the device when it did not get one. import std; -import llamacpp; +import mcpplibs.mwrap.llamacpp; namespace { @@ -146,7 +146,7 @@ int main(int argc, char ** argv) { int generated = 0; int exit_code = 0; - llama_token sampled = LLAMA_TOKEN_NULL; + llama_token sampled = mcpplibs::mwrap::llamacpp::macros::LLAMA_TOKEN_NULL; for (; generated < max_generated_tokens; ++generated) { const int decode_result = llama_decode(context, batch); if (decode_result != 0) { diff --git a/mcpp.toml b/mcpp.toml index 5747b17..8e88d53 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -1,27 +1,8 @@ -# The namespace names whose library this is, not who packaged it; the version -# says which upstream you are getting. `mcpplibs` is mcpp's DEFAULT namespace -# (kDefaultNamespace), not an answer to "whose library" — llama.cpp is -# ggml-org's, and this repository only adds the C++23 module layer. -# -# The version is upstream's build number VERBATIM. `0.1.0` needed a lookup -# table to read, and the README carried it: "Version 0.1.0 maps to llama.cpp -# b10069". A version that needs a decoder ring is not a version. -# -# `b10069` is not semver, and mcpp handles it — verified: resolution, version-key -# matching and wire addressing all work on a literal non-semver key. What it -# cannot do is RANGES over it (`^b10069` is not expressible), so consumers pin -# exactly. See mcpp#363; rule and migration table in mcpp-index#163. -# -# The fourth segment is this PACKAGING's revision of that checkpoint, and it -# moves when the packaging changes without the upstream tree changing: -# `b10069.1` added `backend-vulkan`, `b10069.2` refuses a libc++ toolchain for -# it by name. Consumers pin exactly, so a consumer wanting a feature must name -# the revision that has it -- which is why every version in the README moves -# with this line rather than staying at the bare checkpoint. +# Module wrapper; upstream API preserved. Policy: mcpp-index/docs/mwrap.md. [package] -namespace = "ggml-org" +namespace = "mcpplibs.mwrap" name = "llamacpp" -version = "b10069.3" +version = "b10069" description = "C++23 module package for llama.cpp b10069" license = "MIT" standard = "c++23" @@ -63,6 +44,7 @@ sources = [ "third_party/llama.cpp/ggml/src/ggml-cpu/amx/mmq.cpp", "third_party/llama.cpp/ggml/src/ggml-cpu/llamafile/sgemm.cpp", "src/llamacpp.cppm", + "src/macros.cppm", "third_party/llama.cpp/src/llama.cpp", "third_party/llama.cpp/src/llama-adapter.cpp", "third_party/llama.cpp/src/llama-arch.cpp", @@ -364,3 +346,6 @@ flags = [ { glob = "third_party/llama.cpp/ggml/src/ggml-metal/ggml-metal.cpp", cxxflags = ["-include", "memory"] }, { glob = "third_party/llama.cpp/ggml/src/ggml-backend-reg.cpp", defines = ["GGML_USE_METAL"] }, ] + +[package.metadata.mwrap] +upstream-version = "b10069" diff --git a/src/llamacpp.cppm b/src/llamacpp.cppm index 09aca34..547b830 100644 --- a/src/llamacpp.cppm +++ b/src/llamacpp.cppm @@ -18,8 +18,8 @@ module; #undef LLAMA_STATE_SEQ_FLAGS_PARTIAL_ONLY #undef LLAMA_STATE_SEQ_FLAGS_ON_DEVICE -export module llamacpp; +export module mcpplibs.mwrap.llamacpp; #include "gen_exports/required_ggml.inc" #include "gen_exports/llama.inc" -#include "gen_exports/typed_constants.inc" +export import mcpplibs.mwrap.llamacpp.macros; diff --git a/src/macros.cppm b/src/macros.cppm new file mode 100644 index 0000000..67406ac --- /dev/null +++ b/src/macros.cppm @@ -0,0 +1,25 @@ +module; + +#include +#include +#include + +#undef LLAMA_DEFAULT_SEED +#undef LLAMA_TOKEN_NULL +#undef LLAMA_FILE_MAGIC_GGLA +#undef LLAMA_FILE_MAGIC_GGSN +#undef LLAMA_FILE_MAGIC_GGSQ +#undef LLAMA_SESSION_MAGIC +#undef LLAMA_SESSION_VERSION +#undef LLAMA_STATE_SEQ_MAGIC +#undef LLAMA_STATE_SEQ_VERSION +#undef LLAMA_STATE_SEQ_FLAGS_NONE +#undef LLAMA_STATE_SEQ_FLAGS_SWA_ONLY +#undef LLAMA_STATE_SEQ_FLAGS_PARTIAL_ONLY +#undef LLAMA_STATE_SEQ_FLAGS_ON_DEVICE + +export module mcpplibs.mwrap.llamacpp.macros; + +namespace mcpplibs::mwrap::llamacpp::macros { +#include "gen_exports/typed_constants.inc" +} diff --git a/templates/cpu/src/main.cpp.in b/templates/cpu/src/main.cpp.in index 7a815e9..5ee848c 100644 --- a/templates/cpu/src/main.cpp.in +++ b/templates/cpu/src/main.cpp.in @@ -1,5 +1,5 @@ import std; -import llamacpp; +import mcpplibs.mwrap.llamacpp; struct Backend { Backend() { llama_backend_init(); } diff --git a/tests/cpu_decode.cpp b/tests/cpu_decode.cpp index 08fbe44..cbef08a 100644 --- a/tests/cpu_decode.cpp +++ b/tests/cpu_decode.cpp @@ -1,7 +1,7 @@ /// Portable CPU smoke: load a pinned GGUF, decode one batch, and sample. import std; -import llamacpp; +import mcpplibs.mwrap.llamacpp; #ifdef LLAMA_H #error "import llamacpp leaked LLAMA_H" @@ -13,8 +13,8 @@ import llamacpp; int main() { - static_assert(LLAMA_DEFAULT_SEED == 0xFFFFFFFFu); - static_assert(LLAMA_TOKEN_NULL == llama_token{-1}); + static_assert(mcpplibs::mwrap::llamacpp::macros::LLAMA_DEFAULT_SEED == 0xFFFFFFFFu); + static_assert(mcpplibs::mwrap::llamacpp::macros::LLAMA_TOKEN_NULL == llama_token{-1}); const char * model_path = std::getenv("LLAMACPP_TEST_MODEL"); if (!model_path || !*model_path) { diff --git a/tests/macros.cpp b/tests/macros.cpp new file mode 100644 index 0000000..1ed3439 --- /dev/null +++ b/tests/macros.cpp @@ -0,0 +1,3 @@ +import mcpplibs.mwrap.llamacpp; +namespace macros = mcpplibs::mwrap::llamacpp::macros; +int main() { static_assert(macros::LLAMA_DEFAULT_SEED == 0xFFFFFFFFu); static_assert(macros::LLAMA_TOKEN_NULL == -1); return 0; } diff --git a/tests/metal_decode.cpp b/tests/metal_decode.cpp index d41c25c..325db35 100644 --- a/tests/metal_decode.cpp +++ b/tests/metal_decode.cpp @@ -8,7 +8,7 @@ import std; -import llamacpp; +import mcpplibs.mwrap.llamacpp; #ifdef LLAMA_H #error "import llamacpp leaked LLAMA_H" diff --git a/tests/unit/test_build_contract.py b/tests/unit/test_build_contract.py index 3fe20a4..38cb6fb 100644 --- a/tests/unit/test_build_contract.py +++ b/tests/unit/test_build_contract.py @@ -78,7 +78,7 @@ def test_identity_and_public_module_are_cxx23(self): # The namespace names whose library this is (mcpp-index#163); the version # IS the upstream checkpoint, so it must agree with the build info the # manifest generates for ggml. - self.assertEqual(package["namespace"], "ggml-org") + self.assertEqual(package["namespace"], "mcpplibs.mwrap") # THE VERSION AND GGML_VERSION ARE TWO FACTS, AND A WRAPPER REVISION # SEPARATES THEM. The package version may carry a dotted revision for a diff --git a/tests/unit/test_check_release.py b/tests/unit/test_check_release.py index 66e6d27..8fac1cc 100644 --- a/tests/unit/test_check_release.py +++ b/tests/unit/test_check_release.py @@ -48,6 +48,14 @@ def test_tag_matches_package_version_and_lock_mapping(self): "178a6c44937154dc4c4eff0d166f4a044c4fceba", ) + def test_mwrap_first_release_has_independent_tag_namespace(self): + manifest = self.root / "mcpp.toml" + manifest.write_text(manifest.read_text().replace('[package]', '[package]\nnamespace = "mcpplibs.mwrap"')) + identity = check_release.load_identity(self.root, "mwrap-b10069") + self.assertEqual(str(identity.version), "b10069") + with self.assertRaisesRegex(ValueError, "tag.*version"): + check_release.load_identity(self.root, "b10069") + def test_rejects_tag_version_mismatch(self): with self.assertRaisesRegex(ValueError, "tag.*version"): check_release.load_identity(self.root, "b10069.1") diff --git a/tests/unit/test_repository_contract.py b/tests/unit/test_repository_contract.py index b9665fa..1f0efee 100644 --- a/tests/unit/test_repository_contract.py +++ b/tests/unit/test_repository_contract.py @@ -33,7 +33,7 @@ def test_no_submodule_or_consumer_time_upstream_fetch(self): def test_package_and_module_identity(self): manifest = (ROOT / "mcpp.toml").read_text(encoding="utf-8") module = (ROOT / "src/llamacpp.cppm").read_text(encoding="utf-8") - self.assertRegex(manifest, r'(?m)^namespace\s*=\s*"ggml-org"$') + self.assertRegex(manifest, r'(?m)^namespace\s*=\s*"mcpplibs.mwrap"$') self.assertRegex(manifest, r'(?m)^name\s*=\s*"llamacpp"$') # The wrapper revision on an unchanged upstream checkpoint. The # checkpoint the version NAMES is asserted separately below, so a @@ -41,7 +41,7 @@ def test_package_and_module_identity(self): self.assertRegex(manifest, r'(?m)^version\s*=\s*"b10069(\.[1-9]\d*)?"$') lock = (ROOT / "upstream.lock").read_text(encoding="utf-8") self.assertIn('"b10069"', lock) - self.assertIn("export module llamacpp;", module) + self.assertIn("export module mcpplibs.mwrap.llamacpp;", module) def test_vendored_tree_is_not_locally_patched(self): patches = ROOT / "patches" @@ -117,7 +117,7 @@ def test_chat_examples_keep_next_token_alive_and_report_runtime_errors(self): ).read_text(encoding="utf-8") self.assertRegex( source, - r"llama_token\s+sampled\s*=\s*LLAMA_TOKEN_NULL;" + r"llama_token\s+sampled\s*=\s*mcpplibs::mwrap::llamacpp::macros::LLAMA_TOKEN_NULL;" r"[\s\S]*for\s*\([^)]*\)\s*\{" r"[\s\S]*sampled\s*=\s*llama_sampler_sample", ) @@ -184,7 +184,7 @@ def test_policy_workflows_are_report_only_and_tag_gated(self): # why the scheme change did not ship a release workflow that never # fires: it was the FOURTH place `v*` was written down, and the only # one that would have failed loudly on its own. - 'tags: ["b[0-9]*"]', + 'tags: ["mwrap-*"]', "fetch-depth: 0", "python3 -m unittest discover", "tools/check_release.py", diff --git a/tests/vulkan_decode.cpp b/tests/vulkan_decode.cpp index 3edce87..84032d0 100644 --- a/tests/vulkan_decode.cpp +++ b/tests/vulkan_decode.cpp @@ -19,7 +19,7 @@ import std; -import llamacpp; +import mcpplibs.mwrap.llamacpp; #ifdef LLAMA_H #error "import llamacpp leaked LLAMA_H" diff --git a/tools/check_mwrap_release.py b/tools/check_mwrap_release.py new file mode 100644 index 0000000..4dde1a9 --- /dev/null +++ b/tools/check_mwrap_release.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +"""Check the immutable mwrap release coordinate and bilingual entry pages.""" +import argparse +from pathlib import Path +import re +import tomllib + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--tag', help='release tag; omitted during PR checks') + args = parser.parse_args() + root = Path(__file__).resolve().parents[1] + package = tomllib.loads((root / 'mcpp.toml').read_text())['package'] + assert package['namespace'] == 'mcpplibs.mwrap', package + assert re.fullmatch(r'[A-Za-z_][A-Za-z_0-9]*', package['name']), package['name'] + upstream = package['metadata']['mwrap']['upstream-version'] + version = package['version'] + assert version == upstream or re.fullmatch(re.escape(upstream) + r'\.[1-9][0-9]*', version), (version, upstream) + if args.tag: + assert args.tag == 'mwrap-' + version, (args.tag, version) + identity = package['namespace'] + '.' + package['name'] + for name, other in [('README.md', 'README.zh.md'), ('README.zh.md', 'README.md')]: + text = (root / name).read_text() + assert len(text.splitlines()) <= 100, name + assert '](' + other + ')' in '\n'.join(text.splitlines()[:12]), name + assert identity in text and version in text, name + assert text.count('```') % 2 == 0, name + print(identity + '@' + version) + + +if __name__ == '__main__': + main() diff --git a/tools/check_release.py b/tools/check_release.py index 83dd99c..f6a7b56 100644 --- a/tools/check_release.py +++ b/tools/check_release.py @@ -92,7 +92,8 @@ def _identity_from_text(manifest_text: str, lock_text: str, tag: str) -> Release # The tag is the version verbatim, which is also upstream's own tag form # (ggml-org/llama.cpp tags releases `b10069`, not `vb10069`). - if tag != str(identity.version): + prefix = "mwrap-" if manifest["package"].get("namespace") == "mcpplibs.mwrap" else "" + if tag != prefix + str(identity.version): raise ValueError( f"release tag {tag} does not match package version {identity.version}" ) @@ -247,14 +248,15 @@ def _tag_identity(root: Path, tag: str) -> ReleaseIdentity | None: def _previous_identity( root: Path, current: ReleaseIdentity, current_tag: str ) -> ReleaseIdentity | None: - tags = _git(root, "tag", "--list", "v[0-9]*", "--sort=-version:refname") + pattern = "mwrap-b[0-9]*" if current_tag.startswith("mwrap-") else "b[0-9]*" + tags = _git(root, "tag", "--list", pattern, "--sort=-version:refname") if tags.returncode != 0: raise ValueError(f"cannot list release tags: {tags.stderr.strip()}") for tag in tags.stdout.splitlines(): if tag == current_tag: continue try: - version = Version.parse(tag) + version = Version.parse(tag.removeprefix("mwrap-")) except ValueError: continue if version > current.version: From 46969b29e5e84ddc9704533baec8db7a7ec08200 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 25 Oct 2026 07:11:11 +0900 Subject: [PATCH 08/13] fix: place macro module imports before exported declarations --- src/llamacpp.cppm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llamacpp.cppm b/src/llamacpp.cppm index 547b830..49a3d82 100644 --- a/src/llamacpp.cppm +++ b/src/llamacpp.cppm @@ -19,7 +19,7 @@ module; #undef LLAMA_STATE_SEQ_FLAGS_ON_DEVICE export module mcpplibs.mwrap.llamacpp; +export import mcpplibs.mwrap.llamacpp.macros; #include "gen_exports/required_ggml.inc" #include "gen_exports/llama.inc" -export import mcpplibs.mwrap.llamacpp.macros; From 40815555a0189959802069529d9994317555c765 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 25 Oct 2026 07:13:21 +0900 Subject: [PATCH 09/13] fix(ci): read bilingual metadata explicitly as UTF-8 --- tools/check_mwrap_release.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/check_mwrap_release.py b/tools/check_mwrap_release.py index 4dde1a9..9222469 100644 --- a/tools/check_mwrap_release.py +++ b/tools/check_mwrap_release.py @@ -11,7 +11,7 @@ def main(): parser.add_argument('--tag', help='release tag; omitted during PR checks') args = parser.parse_args() root = Path(__file__).resolve().parents[1] - package = tomllib.loads((root / 'mcpp.toml').read_text())['package'] + package = tomllib.loads((root / 'mcpp.toml').read_text(encoding="utf-8"))['package'] assert package['namespace'] == 'mcpplibs.mwrap', package assert re.fullmatch(r'[A-Za-z_][A-Za-z_0-9]*', package['name']), package['name'] upstream = package['metadata']['mwrap']['upstream-version'] @@ -21,7 +21,7 @@ def main(): assert args.tag == 'mwrap-' + version, (args.tag, version) identity = package['namespace'] + '.' + package['name'] for name, other in [('README.md', 'README.zh.md'), ('README.zh.md', 'README.md')]: - text = (root / name).read_text() + text = (root / name).read_text(encoding="utf-8") assert len(text.splitlines()) <= 100, name assert '](' + other + ')' in '\n'.join(text.splitlines()[:12]), name assert identity in text and version in text, name From 5a050faef4252e02f2e424b908816fbd1fc66013 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 25 Oct 2026 07:23:10 +0900 Subject: [PATCH 10/13] docs: align llama commands and diagnostics with mwrap identity --- build.mcpp | 22 +++++++++++----------- docs/upstream-update-policy.md | 7 +++---- docs/usage.md | 2 +- docs/validation/b10069.md | 5 +++++ examples/chat-vulkan/mcpp.toml | 2 +- tools/audit_snapshot.py | 2 +- tools/gen_exports.py | 2 +- 7 files changed, 23 insertions(+), 19 deletions(-) diff --git a/build.mcpp b/build.mcpp index 449e897..3f0a39d 100644 --- a/build.mcpp +++ b/build.mcpp @@ -93,7 +93,7 @@ int validate_features() { if (!supported.empty()) supported += ", "; supported += name; } - std::cerr << "ggml-org:llamacpp: unsupported feature '" << feature + std::cerr << "mcpplibs.mwrap.llamacpp: unsupported feature '" << feature << "' (supported features: " << supported << ")\n"; return 2; } @@ -108,15 +108,15 @@ int emit_metal() { const std::string manifest = mcpp::manifest_dir(); const std::string out_env = mcpp::out_dir(); if (std::string(os) != "macos") { - std::cerr << "ggml-org:llamacpp backend-metal requires target_os=macos\n"; + std::cerr << "mcpplibs.mwrap.llamacpp backend-metal requires target_os=macos\n"; return 2; } if (std::string(arch) != "aarch64") { - std::cerr << "ggml-org:llamacpp backend-metal requires target_arch=aarch64\n"; + std::cerr << "mcpplibs.mwrap.llamacpp backend-metal requires target_arch=aarch64\n"; return 2; } if (manifest.empty() || out_env.empty()) { - std::cerr << "ggml-org:llamacpp requires MCPP_MANIFEST_DIR and MCPP_OUT_DIR\n"; + std::cerr << "mcpplibs.mwrap.llamacpp requires MCPP_MANIFEST_DIR and MCPP_OUT_DIR\n"; return 2; } @@ -269,7 +269,7 @@ int emit_vulkan() { // that tried anyway would fail somewhere further in, with a message about // whatever broke first rather than about the platform. if (std::string(mcpp::target_os()) != "linux") { - std::cerr << "ggml-org:llamacpp backend-vulkan is Linux only; this " + std::cerr << "mcpplibs.mwrap.llamacpp backend-vulkan is Linux only; this " "build targets " << mcpp::target_os() << ". On macOS use backend-metal.\n"; return 2; @@ -291,7 +291,7 @@ int emit_vulkan() { // libstdc++, which builds this backend correctly. `mcpp::cxx_stdlib()` // answers the question that is actually being asked. if (std::string(mcpp::cxx_stdlib()) == "libc++") { - std::cerr << "ggml-org:llamacpp backend-vulkan needs a libstdc++ " + std::cerr << "mcpplibs.mwrap.llamacpp backend-vulkan needs a libstdc++ " "toolchain; this build resolved libc++.\n" " Upstream's ggml-vulkan.cpp destroys a std::unique_ptr to " "an incomplete type, which libc++ rejects by static " @@ -308,7 +308,7 @@ int emit_vulkan() { // failure worth naming here rather than a confusing "Exec format error" // from the middle of the graph. if (std::string(mcpp::host()) != std::string(mcpp::target())) { - std::cerr << "ggml-org:llamacpp backend-vulkan does not cross-compile: " + std::cerr << "mcpplibs.mwrap.llamacpp backend-vulkan does not cross-compile: " << "the shader generator is built from the vendored source and " << "run during the build, and this build targets " << mcpp::target() << " from " << mcpp::host() << "\n"; @@ -317,21 +317,21 @@ int emit_vulkan() { const std::string shaderc = mcpp::xpkg_dir("xim", "shaderc"); if (shaderc.empty()) { - std::cerr << "ggml-org:llamacpp backend-vulkan needs glslc. Declare it:\n" + std::cerr << "mcpplibs.mwrap.llamacpp backend-vulkan needs glslc. Declare it:\n" << " [feature-xlings.backend-vulkan]\n" << " \"xim:shaderc\" = \"2026.3\"\n"; return 2; } const fs::path glslc = fs::path(shaderc) / "bin/glslc"; if (!fs::exists(glslc)) { - std::cerr << "ggml-org:llamacpp backend-vulkan: xim:shaderc is installed at " + std::cerr << "mcpplibs.mwrap.llamacpp backend-vulkan: xim:shaderc is installed at " << shaderc << " but carries no bin/glslc\n"; return 2; } const host_compiler compiler = find_host_compiler(); if (!compiler) { - std::cerr << "ggml-org:llamacpp backend-vulkan: no C++ compiler found under " + std::cerr << "mcpplibs.mwrap.llamacpp backend-vulkan: no C++ compiler found under " << mcpp::toolchain_dir() << "/bin (looked for g++, clang++, c++)\n"; return 2; } @@ -534,6 +534,6 @@ int main() try { } return 0; } catch (const std::exception & error) { - std::cerr << "ggml-org:llamacpp build.mcpp: " << error.what() << "\n"; + std::cerr << "mcpplibs.mwrap.llamacpp build.mcpp: " << error.what() << "\n"; return 1; } diff --git a/docs/upstream-update-policy.md b/docs/upstream-update-policy.md index 5a612f6..b7b6c4f 100644 --- a/docs/upstream-update-policy.md +++ b/docs/upstream-update-policy.md @@ -12,9 +12,8 @@ The wrapper and upstream project have separate identities: own. See "Version Model" below for why that replaced a separate semantic version. - Every wrapper release maps to exactly one upstream tag and commit. -- The package coordinate is `ggml-org:llamacpp`; consumers use - `import mcpplibs.mwrap.llamacpp;`. The namespace names whose library this is — llama.cpp is - ggml-org's — rather than who packaged it (see mcpp-index#163). +- The package coordinate is `mcpplibs.mwrap.llamacpp`; consumers use + `import mcpplibs.mwrap.llamacpp;`. The wrapper belongs to the mwrap category; the vendored upstream remains ggml-org/llama.cpp. - mcpp-index points only to immutable `llama.cpp-m` releases, never a moving upstream branch. @@ -190,7 +189,7 @@ No release claims all upstream models merely because the API compiled. 5. Verify the tag, version, lock, vendored source, exports, and snapshot: ```bash - python3 tools/check_release.py --tag v + python3 tools/check_release.py --tag mwrap- ``` 6. Create an immutable wrapper tag and release only after all gates pass. diff --git a/docs/usage.md b/docs/usage.md index 83494d0..60d64fb 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -21,7 +21,7 @@ which means a consumer wanting a feature names the revision that has it. After `b10069` is published in mcpp-index: ```bash -mcpp add ggml-org:llamacpp@b10069 +mcpp add mcpplibs.mwrap.llamacpp@b10069 ``` The equivalent manifest entry is: diff --git a/docs/validation/b10069.md b/docs/validation/b10069.md index d5fa31e..bb18168 100644 --- a/docs/validation/b10069.md +++ b/docs/validation/b10069.md @@ -1,5 +1,10 @@ # llama.cpp-m b10069 Validation +This is historical validation of the legacy package identity. New releases use +`mcpplibs.mwrap.llamacpp`; current exact-head CI and installed-consumer results +are tracked in the PR and the mcpp-index execution ledger. + + This record separates completed local evidence from GitHub Actions evidence that requires an authorized push. Version `b10069` is not published by this branch. diff --git a/examples/chat-vulkan/mcpp.toml b/examples/chat-vulkan/mcpp.toml index 7241853..3b84b19 100644 --- a/examples/chat-vulkan/mcpp.toml +++ b/examples/chat-vulkan/mcpp.toml @@ -1,7 +1,7 @@ # The consumer's whole diff for a Vulkan build is the feature name below. # Every payload the backend needs -- glslc for the shaders, the Khronos loader, # the SPIR-V headers, the adapter that lets a built artifact reach the machine's -# own driver -- is declared by `ggml-org:llamacpp` under that feature, and a +# own driver -- is declared by `mcpplibs.mwrap.llamacpp` under that feature, and a # consumer that does not name it acquires none of them. [package] name = "chat-vulkan" diff --git a/tools/audit_snapshot.py b/tools/audit_snapshot.py index da47e58..266c60f 100644 --- a/tools/audit_snapshot.py +++ b/tools/audit_snapshot.py @@ -542,7 +542,7 @@ def main() -> int: root = args.source.resolve() if not (root / 'include/llama.h').is_file(): - ap.error(f'ggml-org:llamacpp source tree not found: {root}') + ap.error(f'mcpplibs.mwrap.llamacpp source tree not found: {root}') expected = None if args.check: diff --git a/tools/gen_exports.py b/tools/gen_exports.py index 42b6f47..0276c2b 100644 --- a/tools/gen_exports.py +++ b/tools/gen_exports.py @@ -565,7 +565,7 @@ def main(argv=None): upstream = Path(args.upstream) if args.upstream else DEFAULT_UPSTREAM_DIR if not args.upstream and not (upstream / "include/llama.h").is_file(): print( - f"ggml-org:llamacpp upstream tree not found: {upstream}", + f"mcpplibs.mwrap.llamacpp upstream tree not found: {upstream}", file=sys.stderr, ) return 1 From e0c7051794fb08d98b10b1297041f8525c8dfaf8 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 25 Oct 2026 07:31:39 +0900 Subject: [PATCH 11/13] docs: apply concise bilingual mwrap README layout --- README.md | 2 +- README.zh.md | 2 +- tools/check_mwrap_release.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c738e1f..242f95d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ **English** · [简体中文](README.zh.md) -Use mcpp **2026.10.24.1**. The new mwrap identity becomes installable after index publication. +Upstream: [ggml-org/llama.cpp](https://github.com/ggml-org/llama.cpp) ## Add The Package diff --git a/README.zh.md b/README.zh.md index 2384e7c..745d2e1 100644 --- a/README.zh.md +++ b/README.zh.md @@ -4,7 +4,7 @@ [English](README.md) · **简体中文** -使用 mcpp **2026.10.24.1**。新 mwrap 身份在索引发布后可直接安装。 +上游仓库:[ggml-org/llama.cpp](https://github.com/ggml-org/llama.cpp) ## 添加依赖 diff --git a/tools/check_mwrap_release.py b/tools/check_mwrap_release.py index 9222469..227fd8d 100644 --- a/tools/check_mwrap_release.py +++ b/tools/check_mwrap_release.py @@ -22,7 +22,7 @@ def main(): identity = package['namespace'] + '.' + package['name'] for name, other in [('README.md', 'README.zh.md'), ('README.zh.md', 'README.md')]: text = (root / name).read_text(encoding="utf-8") - assert len(text.splitlines()) <= 100, name + assert len(text.splitlines()) <= 150, name assert '](' + other + ')' in '\n'.join(text.splitlines()[:12]), name assert identity in text and version in text, name assert text.count('```') % 2 == 0, name From c31f2beed8edc492e90a49da89cc9359ac28f186 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 25 Oct 2026 07:36:19 +0900 Subject: [PATCH 12/13] docs: standardize navigation and introductory layout --- README.md | 6 ++++-- README.zh.md | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 242f95d..52d69d1 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,11 @@ > Pinned llama.cpp b10069 through C++23 modules; upstream API names are preserved. -**English** · [简体中文](README.zh.md) +**English** · [简体中文](README.zh.md) · Upstream: [ggml-org/llama.cpp](https://github.com/ggml-org/llama.cpp) · [Releases](https://github.com/mcpplibs/llama.cpp-m/releases) · [mcpp](https://github.com/mcpp-community/mcpp) · [Index](https://github.com/mcpplibs/mcpp-index) -Upstream: [ggml-org/llama.cpp](https://github.com/ggml-org/llama.cpp) +[![C++23](https://img.shields.io/badge/C%2B%2B-23-blue.svg)](https://en.cppreference.com/w/cpp/23) +[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) +[![CI](https://github.com/mcpplibs/llama.cpp-m/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mcpplibs/llama.cpp-m/actions/workflows/ci.yml) ## Add The Package diff --git a/README.zh.md b/README.zh.md index 745d2e1..40ffc3c 100644 --- a/README.zh.md +++ b/README.zh.md @@ -2,9 +2,11 @@ > 通过 C++23 模块使用固定的 llama.cpp b10069,保留上游 API 名称。 -[English](README.md) · **简体中文** +[English](README.md) · **简体中文** · 上游:[ggml-org/llama.cpp](https://github.com/ggml-org/llama.cpp) · [Releases](https://github.com/mcpplibs/llama.cpp-m/releases) · [mcpp](https://github.com/mcpp-community/mcpp) · [Index](https://github.com/mcpplibs/mcpp-index) -上游仓库:[ggml-org/llama.cpp](https://github.com/ggml-org/llama.cpp) +[![C++23](https://img.shields.io/badge/C%2B%2B-23-blue.svg)](https://en.cppreference.com/w/cpp/23) +[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) +[![CI](https://github.com/mcpplibs/llama.cpp-m/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mcpplibs/llama.cpp-m/actions/workflows/ci.yml) ## 添加依赖 From 0d55de134c5c16bc31b5fb1e91c5946236b8b829 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 25 Oct 2026 07:42:57 +0900 Subject: [PATCH 13/13] docs: lead quickstarts with core module imports and uniform upstream links --- README.md | 9 ++++++++- README.zh.md | 9 ++++++++- docs/usage.md | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 52d69d1..8c3fbec 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,19 @@ > Pinned llama.cpp b10069 through C++23 modules; upstream API names are preserved. -**English** · [简体中文](README.zh.md) · Upstream: [ggml-org/llama.cpp](https://github.com/ggml-org/llama.cpp) · [Releases](https://github.com/mcpplibs/llama.cpp-m/releases) · [mcpp](https://github.com/mcpp-community/mcpp) · [Index](https://github.com/mcpplibs/mcpp-index) +**English** · [简体中文](README.zh.md) · [Upstream](https://github.com/ggml-org/llama.cpp) · [Releases](https://github.com/mcpplibs/llama.cpp-m/releases) · [mcpp](https://github.com/mcpp-community/mcpp) · [Index](https://github.com/mcpplibs/mcpp-index) [![C++23](https://img.shields.io/badge/C%2B%2B-23-blue.svg)](https://en.cppreference.com/w/cpp/23) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![CI](https://github.com/mcpplibs/llama.cpp-m/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mcpplibs/llama.cpp-m/actions/workflows/ci.yml) +## Modules + +- `import mcpplibs.mwrap.llamacpp;`: llama.cpp model, context and inference APIs +- `import mcpplibs.mwrap.llamacpp.macros;`: Typed macro constants + +> More Modules API -> [Usage and API](docs/usage.md) + ## Add The Package ```sh diff --git a/README.zh.md b/README.zh.md index 40ffc3c..4a30c81 100644 --- a/README.zh.md +++ b/README.zh.md @@ -2,12 +2,19 @@ > 通过 C++23 模块使用固定的 llama.cpp b10069,保留上游 API 名称。 -[English](README.md) · **简体中文** · 上游:[ggml-org/llama.cpp](https://github.com/ggml-org/llama.cpp) · [Releases](https://github.com/mcpplibs/llama.cpp-m/releases) · [mcpp](https://github.com/mcpp-community/mcpp) · [Index](https://github.com/mcpplibs/mcpp-index) +[English](README.md) · **简体中文** · [Upstream](https://github.com/ggml-org/llama.cpp) · [Releases](https://github.com/mcpplibs/llama.cpp-m/releases) · [mcpp](https://github.com/mcpp-community/mcpp) · [Index](https://github.com/mcpplibs/mcpp-index) [![C++23](https://img.shields.io/badge/C%2B%2B-23-blue.svg)](https://en.cppreference.com/w/cpp/23) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![CI](https://github.com/mcpplibs/llama.cpp-m/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mcpplibs/llama.cpp-m/actions/workflows/ci.yml) +## 模块 + +- `import mcpplibs.mwrap.llamacpp;`: llama.cpp 模型、上下文与推理 API +- `import mcpplibs.mwrap.llamacpp.macros;`: 类型化宏常量 + +> More Modules API -> [模块与 API](docs/usage.md) + ## 添加依赖 ```sh diff --git a/docs/usage.md b/docs/usage.md index 60d64fb..3d541bf 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -93,7 +93,7 @@ mcpp run -- /path/to/model.gguf \ 'User: Introduce yourself in one sentence.\nAssistant:' ``` -It sets `n_gpu_layers = 0`, imports `llamacpp`, and performs real +It sets `n_gpu_layers = 0`, imports `mcpplibs.mwrap.llamacpp`, and performs real tokenization, decode, and sampling. ## Metal Chat Example