From ace5cb2487493270c68abcefa5459bb4cadcdc97 Mon Sep 17 00:00:00 2001 From: Ivan Zatevakhin Date: Sun, 16 Aug 2026 12:53:39 +0100 Subject: [PATCH] chore(release): prepare crates for publishing - complete crates.io and docs.rs metadata and packaged documentation - add manual release guidance and an exact local msrv policy - validate deterministic package inventories, licenses, and offline consumers - add sys-first publication dry-runs without uploading --- .cargo/config.toml | 2 + CHANGELOG.md | 24 ++ Justfile | 474 +++++++++++++++++++++++++++++----------- README.md | 25 +-- RELEASING.md | 59 +++++ flake.nix | 19 ++ vllm-cpp-sys/Cargo.toml | 9 +- vllm-cpp-sys/README.md | 8 +- vllm-cpp-sys/src/lib.rs | 35 ++- vllm-cpp/Cargo.toml | 10 +- vllm-cpp/README.md | 55 +++++ vllm-cpp/src/lib.rs | 44 +++- 12 files changed, 610 insertions(+), 154 deletions(-) create mode 100644 .cargo/config.toml create mode 100644 CHANGELOG.md create mode 100644 RELEASING.md create mode 100644 vllm-cpp/README.md diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..4a6a1ab --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[resolver] +incompatible-rust-versions = "fallback" diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..8ac77f2 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,24 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## Unreleased + +### Added + +- Checked-in raw Rust declarations for the 19-symbol stable vllm.cpp C API at ABI version 10, with header, symbol, layout, and runtime conformance checks. +- A safe API for model loading, blocking completion and streaming, raw-JSON and optional serde chat, structured output, owned sampling parameters, and concurrent request submission, cancellation, waiting, and diagnostics. +- RAII ownership for native engines, requests, completions, and strings, including callback panic containment and callback-thread-safe deferred request cleanup. +- Linux x86_64 CPU builds for bundled and system libraries with static or dynamic linking. +- Experimental bundled Linux x86_64/aarch64 build integration for CUDA, external CUTLASS, Triton AOT, and Vulkan. + +### Compatibility + +- The bundled native source is pinned to vllm.cpp commit `34aedfbe8ed9779697905541a62e2160ccfd9c05` and the Rust declarations require its C ABI version 10. +- The Rust crates are versioned together. `vllm-cpp` depends on exactly the matching `vllm-cpp-sys` version. + +### Known limitations + +- The supported runtime tier is native Linux x86_64 CPU. Accelerator features are experimental build/configuration surfaces, not runtime-support claims. +- Known native blockers include a CUDA teardown SIGSEGV after otherwise successful tests, a CUDA bf16 numerical tolerance failure, CUTLASS concurrent-output differences, and incomplete Vulkan runtime coverage. +- Dynamic builds require callers to deploy `libvllm.so` and its runtime dependencies through a loader-visible path. System static builds must also provide the matching private BLAKE3 archive. diff --git a/Justfile b/Justfile index 2c11ec6..de2666c 100644 --- a/Justfile +++ b/Justfile @@ -322,7 +322,22 @@ link-modes: echo 'all four Linux CPU link modes passed' -# Test the packaged sys crate and an offline downstream fixture. +# Check locked model-free targets on the exact Rust 1.85.0 toolchain. +msrv: + #!/usr/bin/env bash + set -euo pipefail + cd {{ quote(root) }} + rust_version=$(rustc --version | awk '{print $2}') + cargo_version=$(cargo --version | awk '{print $2}') + if [[ $rust_version != 1.85.0 || $cargo_version != 1.85.0 ]]; then + echo "msrv requires rustc and cargo 1.85.0; found rustc $rust_version and cargo $cargo_version" >&2 + exit 1 + fi + export CARGO_TARGET_DIR=${CARGO_TARGET_DIR:-{{ quote(root + "/target/msrv") }}} + env -u VLLM_CPP_TEST_MODEL \ + cargo check --locked --workspace --all-targets --features vllm-cpp/serde + +# Validate both crate archives, extracted builds, and downstream consumers. package-test: #!/usr/bin/env bash set -euo pipefail @@ -341,86 +356,65 @@ package-test: cargo fetch --locked fi export CARGO_NET_OFFLINE=true - version=$(cargo metadata --locked --offline --no-deps --format-version 1 \ - | jq -er '[.packages[] | select(.name == "vllm-cpp-sys") | .version] | if length == 1 then .[0] else error("expected exactly one vllm-cpp-sys package") end') - package_args=() - if [[ -n $(git status --porcelain=v1 --untracked-files=all -- vllm-cpp-sys) ]]; then - package_args+=(--allow-dirty) - fi - cargo package -p vllm-cpp-sys --locked --offline "${package_args[@]}" - package_file="$package_target/package/vllm-cpp-sys-$version.crate" temp=$(mktemp -d) trap 'rm -rf "$temp"' EXIT - tar -xzf "$package_file" -C "$temp" - package_root="$temp/vllm-cpp-sys-$version" - temp_target="$temp/target" - - package_size=$(stat -c '%s' "$package_file") - unpacked_size=$(du -sb "$package_root" | cut -f1) - entry_count=$(tar -tzf "$package_file" | wc -l) - max_compressed=$((6 * 1024 * 1024)) - max_unpacked=$((36 * 1024 * 1024)) - max_entries=1300 - ((package_size <= max_compressed)) || { - echo "package exceeds compressed budget: $package_size > $max_compressed" >&2 - exit 1 - } - ((unpacked_size <= max_unpacked)) || { - echo "package exceeds unpacked budget: $unpacked_size > $max_unpacked" >&2 - exit 1 - } - ((entry_count <= max_entries)) || { - echo "package exceeds entry budget: $entry_count > $max_entries" >&2 + metadata="$temp/workspace-metadata.json" + cargo metadata --locked --offline --no-deps --format-version 1 > "$metadata" + version=$(jq -er ' + [.packages[] | select(.name == "vllm-cpp-sys") | .version] + | if length == 1 then .[0] else error("expected exactly one vllm-cpp-sys package") end + ' "$metadata") + safe_version=$(jq -er ' + [.packages[] | select(.name == "vllm-cpp") | .version] + | if length == 1 then .[0] else error("expected exactly one vllm-cpp package") end + ' "$metadata") + [[ $safe_version == "$version" ]] || { + echo "crate versions differ: sys=$version safe=$safe_version" >&2 exit 1 } + jq -e --arg version "$version" ' + [.packages[] | select(.name == "vllm-cpp" or .name == "vllm-cpp-sys")] + | length == 2 + and all(.version == $version) + and all(.rust_version == "1.85") + and all(.license == "MIT OR Apache-2.0") + and all(.repository == "https://github.com/querymt/vllm-cpp-rs") + and all(.readme == "README.md") + and (map(select(.name == "vllm-cpp" and .documentation == "https://docs.rs/vllm-cpp")) | length == 1) + and (map(select(.name == "vllm-cpp-sys" and .documentation == "https://docs.rs/vllm-cpp-sys")) | length == 1) + and (map(select(.name == "vllm-cpp") | .dependencies[] | select(.name == "vllm-cpp-sys" and .req == ("=" + $version) and .uses_default_features == false)) | length == 1) + ' "$metadata" >/dev/null + + sys_list="$temp/vllm-cpp-sys.list" + safe_list="$temp/vllm-cpp.list" + cargo package -p vllm-cpp-sys --locked --offline --allow-dirty --list \ + | LC_ALL=C sort -u > "$sys_list" + cargo package -p vllm-cpp --locked --offline --allow-dirty --list \ + | LC_ALL=C sort -u > "$safe_list" + + cargo package -p vllm-cpp-sys --locked --offline --allow-dirty + cargo package --workspace --locked --offline --allow-dirty --no-verify + sys_package="$package_target/package/vllm-cpp-sys-$version.crate" + safe_package="$package_target/package/vllm-cpp-$safe_version.crate" + [[ -s $sys_package && -s $safe_package ]] + + tar -xzf "$sys_package" -C "$temp" + tar -xzf "$safe_package" -C "$temp" + sys_root="$temp/vllm-cpp-sys-$version" + safe_root="$temp/vllm-cpp-$safe_version" + temp_target="$temp/target" - required_members=( - Cargo.lock - Cargo.toml - LICENSE-APACHE - LICENSE-MIT - NOTICE - README.md - THIRD_PARTY.md - build.rs - licenses/FLASH-ATTENTION-BSD-3-CLAUSE.txt - licenses/FLASH-LINEAR-ATTENTION-MIT.txt - wrapper.h - src/bindings.rs - src/build_config.rs - src/build_support.rs - src/lib.rs - tests/build_config.rs - tests/build_support.rs - tests/layout.c - tests/layout.rs - tests/symbols.rs - vllm.cpp/CMakeLists.txt - vllm.cpp/LICENSE - vllm.cpp/NOTICE - vllm.cpp/include/vllm.h - vllm.cpp/src/capi/chat_prompt.cpp - vllm.cpp/src/capi/chat_prompt.h - vllm.cpp/src/capi/engine_handle.h - vllm.cpp/src/capi/vllm_c.cpp - vllm.cpp/src/vllm/version.cpp - vllm.cpp/src/vt/cuda/triton_aot_vendored/sm_121a/MANIFEST - vllm.cpp/scripts/triton-aot-compile.py - vllm.cpp/triton_kernels/chunk_delta_h.py - vllm.cpp/third_party/README.md - vllm.cpp/third_party/blake3/LICENSE_A2 - vllm.cpp/third_party/blake3/LICENSE_CC0 - vllm.cpp/third_party/minja/LICENSE - vllm.cpp/third_party/nlohmann/json.hpp - vllm.cpp/third_party/vulkan/vulkan_core.h - ) - for member in "${required_members[@]}"; do - [[ -s $package_root/$member ]] || { - echo "packaged crate is missing required member: $member" >&2 - exit 1 - } - done + archive_inventory() { + local archive=$1 + local prefix=$2 + tar -tzf "$archive" \ + | sed "s#^$prefix/##" \ + | grep -v '/$' \ + | LC_ALL=C sort + } + diff -u "$sys_list" <(archive_inventory "$sys_package" "vllm-cpp-sys-$version") + diff -u "$safe_list" <(archive_inventory "$safe_package" "vllm-cpp-$safe_version") native_inventory() { local base=$1 @@ -445,13 +439,106 @@ package-test: vllm.cpp/third_party/nlohmann vllm.cpp/third_party/vulkan ) + sys_expected="$temp/vllm-cpp-sys.expected" + { + printf '%s\n' \ + .cargo_vcs_info.json \ + Cargo.lock \ + Cargo.toml \ + Cargo.toml.orig \ + LICENSE-APACHE \ + LICENSE-MIT \ + NOTICE \ + README.md \ + THIRD_PARTY.md \ + build.rs \ + licenses/FLASH-ATTENTION-BSD-3-CLAUSE.txt \ + licenses/FLASH-LINEAR-ATTENTION-MIT.txt \ + src/bindings.rs \ + src/build_config.rs \ + src/build_support.rs \ + src/lib.rs \ + tests/build_config.rs \ + tests/build_support.rs \ + tests/layout.c \ + tests/layout.rs \ + tests/symbols.rs \ + wrapper.h + native_inventory "$repo_root/vllm-cpp-sys" "${native_members[@]}" + } | LC_ALL=C sort > "$sys_expected" + diff -u "$sys_expected" "$sys_list" diff -u \ <(native_inventory "$repo_root/vllm-cpp-sys" "${native_members[@]}") \ - <(native_inventory "$package_root" "${native_members[@]}") + <(native_inventory "$sys_root" "${native_members[@]}") diff -u \ <(printf '%s\n' CMakeLists.txt LICENSE NOTICE cmake include scripts src third_party triton_kernels | LC_ALL=C sort) \ - <(find "$package_root/vllm.cpp" -mindepth 1 -maxdepth 1 -printf '%f\n' | LC_ALL=C sort) - denied_members=( + <(find "$sys_root/vllm.cpp" -mindepth 1 -maxdepth 1 -printf '%f\n' | LC_ALL=C sort) + + safe_expected="$temp/vllm-cpp.expected" + printf '%s\n' \ + .cargo_vcs_info.json \ + Cargo.lock \ + Cargo.toml \ + Cargo.toml.orig \ + LICENSE-APACHE \ + LICENSE-MIT \ + README.md \ + examples/README.md \ + examples/chat.rs \ + examples/complete.rs \ + examples/concurrent.rs \ + examples/stream.rs \ + examples/structured.rs \ + src/callback.rs \ + src/engine.rs \ + src/error.rs \ + src/lib.rs \ + src/params.rs \ + src/request.rs \ + tests/qwen3.rs \ + tests/safe_api.rs \ + | LC_ALL=C sort > "$safe_expected" + diff -u "$safe_expected" "$safe_list" + + required_sys_members=( + README.md + THIRD_PARTY.md + licenses/FLASH-ATTENTION-BSD-3-CLAUSE.txt + licenses/FLASH-LINEAR-ATTENTION-MIT.txt + vllm.cpp/include/vllm.h + vllm.cpp/src/capi/chat_prompt.cpp + vllm.cpp/src/capi/chat_prompt.h + vllm.cpp/src/capi/engine_handle.h + vllm.cpp/src/capi/vllm_c.cpp + vllm.cpp/src/vllm/version.cpp + vllm.cpp/src/vt/cuda/cuda_matmul_fp8_cutlass.cu + vllm.cpp/src/vt/cuda/flash_attn/src/flash.h + vllm.cpp/src/vt/cuda/marlin/core/scalar_type.hpp + vllm.cpp/src/vt/cuda/triton_aot_vendored/sm_121a/MANIFEST + vllm.cpp/scripts/triton-aot-compile.py + vllm.cpp/triton_kernels/chunk_delta_h.py + vllm.cpp/src/vt/vulkan/vulkan_spirv.h + vllm.cpp/third_party/README.md + vllm.cpp/third_party/blake3/LICENSE_A2 + vllm.cpp/third_party/blake3/LICENSE_CC0 + vllm.cpp/third_party/minja/LICENSE + vllm.cpp/third_party/nlohmann/json.hpp + vllm.cpp/third_party/vulkan/vulkan_core.h + ) + for member in "${required_sys_members[@]}"; do + [[ -s $sys_root/$member ]] || { + echo "sys package is missing required member: $member" >&2 + exit 1 + } + done + while IFS= read -r member; do + [[ -s $safe_root/$member ]] || { + echo "safe package is missing required member: $member" >&2 + exit 1 + } + done < "$safe_expected" + + denied_sys_members=( Justfile layout.c vllm.cpp/.agents @@ -466,22 +553,123 @@ package-test: vllm.cpp/third_party/doctest vllm.cpp/third_party/httplib ) - for member in "${denied_members[@]}"; do - [[ ! -e $package_root/$member ]] || { - echo "denied upstream tree or record leaked into package: $member" >&2 + for member in "${denied_sys_members[@]}"; do + [[ ! -e $sys_root/$member ]] || { + echo "denied upstream tree or record leaked into sys package: $member" >&2 exit 1 } done + forbidden_pattern='(^|/)(target|stuff|\.git|\.github|__pycache__|\.cache|cache|fixtures?|downloads?|_deps|sdk)(/|$)|(^|/)(cutlass)(/|$)|(^|/)(model\.safetensors|tokenizer\.json|tokenizer_config\.json)$|\.(o|obj|a|so|dylib|dll|pyc|safetensors|gguf|pt|pth)$' + for listing in "$sys_list" "$safe_list"; do + if grep -Eiq "$forbidden_pattern" "$listing"; then + echo "forbidden package payload detected in $listing:" >&2 + grep -Ei "$forbidden_pattern" "$listing" >&2 + exit 1 + fi + done + + scan_authored_paths() { + local package_root=$1 + local files=() + if [[ -d $package_root/vllm.cpp ]]; then + mapfile -d '' files < <(find "$package_root" \ + -path "$package_root/vllm.cpp" -prune -o -type f -print0) + else + mapfile -d '' files < <(find "$package_root" -type f -print0) + fi + if ((${#files[@]})) && grep -IlF "$repo_root" "${files[@]}" >/dev/null; then + echo "local repository path leaked into $package_root" >&2 + grep -IlF "$repo_root" "${files[@]}" >&2 + exit 1 + fi + if grep -E '^(path|git)[[:space:]]*=' "$package_root/Cargo.toml.orig"; then + echo "local Cargo dependency source leaked into $package_root" >&2 + exit 1 + fi + } + scan_authored_paths "$sys_root" + scan_authored_paths "$safe_root" + + sys_license_actual="$temp/sys-licenses.actual" + find "$sys_root" -type f -printf '%P\n' \ + | grep -Ei '(^|/)(license[^/]*|copying[^/]*|notice[^/]*)$|^THIRD_PARTY\.md$|^licenses/' \ + | LC_ALL=C sort > "$sys_license_actual" + diff -u \ + <(printf '%s\n' \ + LICENSE-APACHE \ + LICENSE-MIT \ + NOTICE \ + THIRD_PARTY.md \ + licenses/FLASH-ATTENTION-BSD-3-CLAUSE.txt \ + licenses/FLASH-LINEAR-ATTENTION-MIT.txt \ + vllm.cpp/LICENSE \ + vllm.cpp/NOTICE \ + vllm.cpp/third_party/blake3/LICENSE_A2 \ + vllm.cpp/third_party/blake3/LICENSE_CC0 \ + vllm.cpp/third_party/minja/LICENSE | LC_ALL=C sort) \ + "$sys_license_actual" + diff -u \ + <(printf '%s\n' LICENSE-APACHE LICENSE-MIT | LC_ALL=C sort) \ + <(find "$safe_root" -type f -printf '%P\n' \ + | grep -Ei '(^|/)(license[^/]*|copying[^/]*|notice[^/]*)$' \ + | LC_ALL=C sort) + + check_package_links() { + local package_root=$1 + shift + local document document_dir link path + for document in "$@"; do + document_dir=$(dirname "$document") + while IFS= read -r link; do + case $link in + http://*|https://*|mailto:*|'#'*) continue ;; + esac + path=${link%%#*} + [[ -e $package_root/$document_dir/$path ]] || { + echo "broken packaged relative link in $document: $link" >&2 + exit 1 + } + done < <(grep -oE '\]\([^)]+\)' "$package_root/$document" \ + | sed -e 's/^](//' -e 's/)$//' || true) + done + } + check_package_links "$sys_root" README.md THIRD_PARTY.md + check_package_links "$safe_root" README.md examples/README.md + + sys_package_size=$(stat -c '%s' "$sys_package") + sys_unpacked_size=$(du -sb "$sys_root" | cut -f1) + sys_entry_count=$(wc -l < "$sys_list") + safe_package_size=$(stat -c '%s' "$safe_package") + safe_unpacked_size=$(du -sb "$safe_root" | cut -f1) + safe_entry_count=$(wc -l < "$safe_list") + ((sys_package_size <= 6 * 1024 * 1024)) + ((sys_unpacked_size <= 36 * 1024 * 1024)) + ((sys_entry_count <= 1300)) + ((safe_package_size <= 128 * 1024)) + ((safe_unpacked_size <= 256 * 1024)) + ((safe_entry_count <= 40)) + + jq -e --arg version "$version" ' + .packages | length == 1 + and .[0].name == "vllm-cpp-sys" + and .[0].version == $version + and .[0].readme == "README.md" + and .[0].documentation == "https://docs.rs/vllm-cpp-sys" + and .[0].license == "MIT OR Apache-2.0" + and .[0].rust_version == "1.85" + and .[0].features.default == ["bundled"] + ' <(cargo metadata --manifest-path "$sys_root/Cargo.toml" \ + --locked --offline --no-deps --format-version 1) >/dev/null ( - cd "$package_root" + cd "$sys_root" CARGO_NET_OFFLINE=true CARGO_TARGET_DIR="$temp_target" \ cargo test --locked --release --tests --offline ) - fixture="$temp/downstream" - mkdir -p "$fixture/src" - cat > "$fixture/Cargo.toml" < "$sys_consumer/Cargo.toml" < "$fixture/src/main.rs" <<'EOF' + cat > "$sys_consumer/src/main.rs" <<'EOF' use std::ffi::CStr; use vllm_cpp_sys as ffi; @@ -511,56 +699,96 @@ package-test: } EOF ( - cd "$fixture" + cd "$sys_consumer" CARGO_NET_OFFLINE=true cargo generate-lockfile --offline CARGO_NET_OFFLINE=true CARGO_TARGET_DIR="$temp_target" \ cargo run --locked --release --offline ) - safe_version=$(cargo metadata --locked --offline --no-deps --format-version 1 \ - | jq -er '[.packages[] | select(.name == "vllm-cpp") | .version] | if length == 1 then .[0] else error("expected exactly one vllm-cpp package") end') - safe_package_args=() - if [[ -n $(git status --porcelain=v1 --untracked-files=all -- vllm-cpp vllm-cpp-sys) ]]; then - safe_package_args+=(--allow-dirty) - fi - cargo package --workspace --locked --offline --no-verify "${safe_package_args[@]}" - safe_package_file="$package_target/package/vllm-cpp-$safe_version.crate" - tar -xzf "$safe_package_file" -C "$temp" - safe_root="$temp/vllm-cpp-$safe_version" - safe_manifest="$safe_root/Cargo.toml" - sed -i \ - "/\[dependencies.vllm-cpp-sys\]/a path = \"$package_root\"" \ - "$safe_manifest" + mkdir -p "$safe_root/.cargo" + cat > "$safe_root/.cargo/config.toml" </dev/null + + safe_consumer="$temp/safe-consumer" + mkdir -p "$safe_consumer/src" + cat > "$safe_consumer/Cargo.toml" < "$package_listing" - if grep -Eq '(^|/)(target|model\.safetensors)(/|$)' "$package_listing"; then - echo 'local build output or model fixture leaked into the safe crate package' >&2 - exit 1 - fi - if grep -RIlF "$repo_root" "$safe_root" --exclude=Cargo.toml >/dev/null; then - echo 'local repository path leaked into the safe crate package' >&2 - exit 1 - fi - [[ ! -e $safe_root/target ]] || { - echo 'local build output leaked into the safe crate package' >&2 - exit 1 - } - [[ ! -e $safe_root/model.safetensors ]] || { - echo 'model fixture leaked into the safe crate package' >&2 - exit 1 + [dependencies] + vllm-cpp = { path = "$safe_root", default-features = false, features = ["bundled", "serde"] } + + [patch.crates-io] + vllm-cpp-sys = { path = "$sys_root" } + EOF + cat > "$safe_consumer/src/main.rs" <<'EOF' + use vllm_cpp::{abi_version, expected_abi_version, Engine, Error, SamplingParams}; + + fn main() { + assert_eq!(expected_abi_version(), 10); + assert_eq!(abi_version(), 10); + let _params = SamplingParams::greedy().max_tokens(1); + assert!(matches!( + Engine::load("/nonexistent/vllm-cpp-rs-safe-package-smoke"), + Err(Error::ModelLoad { .. }) + )); } + EOF ( - cd "$safe_root" - env -u VLLM_CPP_TEST_MODEL \ - CARGO_NET_OFFLINE=true CARGO_TARGET_DIR="$temp_target" \ - cargo test --locked --release --offline --features bundled,serde + cd "$safe_consumer" + CARGO_NET_OFFLINE=true cargo generate-lockfile --offline + metadata=$(CARGO_NET_OFFLINE=true cargo metadata --locked --offline --format-version 1) + safe_manifest=$(realpath "$safe_root/Cargo.toml") + sys_manifest=$(realpath "$sys_root/Cargo.toml") + jq -e --arg safe "$safe_manifest" --arg sys "$sys_manifest" ' + any(.packages[]; .name == "vllm-cpp" and .manifest_path == $safe) + and any(.packages[]; .name == "vllm-cpp-sys" and .manifest_path == $sys) + ' <<<"$metadata" >/dev/null + CARGO_NET_OFFLINE=true CARGO_TARGET_DIR="$temp_target" \ + cargo run --locked --release --offline ) + printf 'sys package: %d entries, %d bytes unpacked, %d bytes compressed\n' \ + "$sys_entry_count" "$sys_unpacked_size" "$sys_package_size" + printf 'safe package: %d entries, %d bytes unpacked, %d bytes compressed\n' \ + "$safe_entry_count" "$safe_unpacked_size" "$safe_package_size" + +# Run sys-first crates.io publication checks without uploading. +publish-dry-run: + #!/usr/bin/env bash + set -euo pipefail + cd {{ quote(root) }} + export CARGO_TARGET_DIR=${CARGO_TARGET_DIR:-{{ quote(root + "/target/publish-dry-run") }}} + # package-test performs the full extracted/offline verification. Workspace + # dry-run preserves Cargo's sys-first order without requiring sys on crates.io. + cargo publish --workspace --locked --dry-run --allow-dirty --no-verify + # Download and verify the pinned Qwen3-0.6B model fixture. setup-test-model destination=env_var_or_default("VLLM_CPP_TEST_MODEL", env_var_or_default("XDG_CACHE_HOME", env_var("HOME") + "/.cache") + "/vllm-cpp-rs/Qwen3-0.6B-" + model_revision): #!/usr/bin/env bash diff --git a/README.md b/README.md index 396c024..747673e 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ This repository provides a Nix development shell with the pinned development too nix develop nix develop .#cuda nix develop .#vulkan +nix develop .#msrv ``` ## Checkout @@ -40,21 +41,7 @@ git submodule update --init --recursive ## Safe API -```rust -use vllm_cpp::{Engine, SamplingParams, StreamControl}; - -let engine = Engine::load("/models/Qwen3-0.6B")?; -let params = SamplingParams::greedy().max_tokens(16); -let completion = engine.complete("The capital of France is", ¶ms)?; -println!("{}", completion.text); - -let mut request = engine.submit("The capital of Germany is", ¶ms, |event| { - print!("{}", event.delta); - StreamControl::Continue -})?; -println!("{:?}", request.wait()?); -# Ok::<(), vllm_cpp::Error>(()) -``` +The packaged [`vllm-cpp` guide](vllm-cpp/README.md) covers model requirements, safe ownership, callbacks, concurrency, features, link modes, and deployment. The [`vllm-cpp-sys` guide](vllm-cpp-sys/README.md) documents the raw ABI and native build boundary. `EngineBuilder` owns model settings and converts them to temporary C strings only for the load call. `SamplingParams` owns stop strings and structured constraints. Completion and chat strings are copied into Rust values before the matching native free function runs. @@ -62,7 +49,7 @@ println!("{:?}", request.wait()?); All streaming callbacks receive copied UTF-8 deltas. Blocking callbacks may borrow stack data; their panics are caught before the C boundary and resumed only after the native call returns. Asynchronous callbacks must be `Send + 'static`, run on a native delivery thread, and report panic as `Error::CallbackPanicked` from `wait`. Waiting for or freeing a request from its own callback thread is prohibited by ABI v10: `wait` returns `Error::RequestCallbackThread`, while drop transfers cleanup to a prestarted reaper that owns the request, callback, and engine until native free/cancel/join completes. Chat methods accept raw OpenAI-compatible request JSON; enable `serde` for `serde_json::Value` request and response helpers. -See [the examples guide](vllm-cpp/examples/README.md) for ordinary Linux and optional Nix setup and commands for every example. +See [the examples guide](vllm-cpp/examples/README.md) for ordinary Linux and optional Nix setup and commands for every example. Release-facing changes are recorded in the [changelog](CHANGELOG.md), and maintainers use the manual [release process](RELEASING.md). ## Build and Test @@ -75,7 +62,7 @@ cargo test --locked -p vllm-cpp --release --features serde just ci ``` -Set `CMAKE_BUILD_PARALLEL_LEVEL` to control native parallelism. The default bundled build remains deterministic and CPU-only: native tests, examples, the HTTP server, CUDA, Metal, MLX, Vulkan, Triton, and CUTLASS fetching are disabled explicitly. +Set `CMAKE_BUILD_PARALLEL_LEVEL` to control native parallelism. The default bundled build remains deterministic and CPU-only: native tests, examples, the HTTP server, CUDA, Metal, MLX, Vulkan, Triton, and CUTLASS fetching are disabled explicitly. Use `nix develop .#msrv -c just msrv` for the exact local Rust 1.85.0 policy check; hosted exact-MSRV validation is deferred to a later CI slice. `build.rs` is consumer-only native build/link integration; it does not download dependencies or compile/execute the maintainer layout probe. Ordinary consumers do not need Just, bindgen, or libclang. Normal first-time Cargo dependency resolution may access crates.io; use Cargo's standard `--offline` mode after dependencies are cached. @@ -147,7 +134,9 @@ cargo package -p vllm-cpp --locked --list just package-test ``` -The package gate preserves the sys crate inventory, tests the extracted sys crate and downstream fixture offline, then points the extracted safe crate at the extracted sys crate and tests it offline with `bundled,serde`. It also rejects local paths, build output, and model files in the safe package. The sys package carries only native build inputs and required licenses/notices; upstream tests, large fixtures, media, benchmarks, and agent records are excluded. +The package gate validates deterministic inventories for both crates, package metadata, required source/docs/examples/tests/licenses/native inputs, forbidden payloads, and license provenance. It extracts and tests both crates offline, then runs independent sys and safe downstream consumers; the safe consumer resolves both extracted crates rather than this workspace. The sys package carries only native build inputs and required licenses/notices; upstream tests, large fixtures, media, benchmarks, fetched SDKs, external CUTLASS trees, and agent records are excluded. + +`just publish-dry-run` performs a sys-then-safe workspace packaging dry-run without uploading; it uses `--no-verify` to avoid the pre-publication registry cycle. As required by [RELEASING.md](RELEASING.md), after `vllm-cpp-sys` is available from crates.io, run the full `cargo publish -p vllm-cpp --locked --dry-run` verification before publishing the safe crate. ## Support diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 0000000..8ca3fcf --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,59 @@ +# Releasing + +Releases are prepared and published manually. The repository does not tag, publish, or create a GitHub release automatically. A successful local candidate or dry-run is not a release; crates.io publication is an irreversible registry action. + +## Prepare a candidate + +1. Start from the reviewed release commit and verify the branch, `HEAD`, and intended remote identity. +2. Require a clean worktree and index, including initialized submodules: + + ```console + test -z "$(git status --short --untracked-files=all)" + git diff --quiet + git diff --cached --quiet + git submodule status --recursive + test "$(git -C vllm-cpp-sys/vllm.cpp rev-parse HEAD)" = 34aedfbe8ed9779697905541a62e2160ccfd9c05 + test -z "$(git -C vllm-cpp-sys/vllm.cpp status --short --untracked-files=all)" + ``` + +3. Confirm the release version in the workspace manifest, both normalized package manifests, and `Cargo.lock`. Both crates must use the same version, and `vllm-cpp` must depend on exactly that `vllm-cpp-sys` version. +4. Confirm the native gitlink is `34aedfbe8ed9779697905541a62e2160ccfd9c05`, `VLLM_ABI_VERSION` is 10 in the pinned public C header and checked-in bindings, and generated bindings have no drift. +5. Move the relevant entries from `Unreleased` to a dated version section. Describe only validated support; preserve known backend/runtime blockers. +6. Audit dual-license metadata, crate license files, `NOTICE`, `THIRD_PARTY.md`, imported license texts, and the package inventory. Do not publish models, fixtures, build output, caches, SDKs, external CUTLASS trees, or repository-local paths. +7. Run the complete maintainer validation from the pinned development shell. At minimum run formatting, lint, model-free tests, docs, sys conformance, all CPU link modes, package extraction/downstream tests, and the exact MSRV gate. + +## Inspect and dry-run + +Build fresh archives; do not trust old files under `target/package`: + +```console +cargo package -p vllm-cpp-sys --locked --list +cargo package -p vllm-cpp --locked --list +just package-test +just publish-dry-run +``` + +Inspect both sorted inventories and extracted normalized `Cargo.toml` files. Confirm the packages contain their READMEs, dual licenses, notices and provenance where applicable, source, tests, examples, and every required native/backend input. Confirm extracted builds and independent downstream consumers pass offline and that the safe consumer resolves the extracted sys crate rather than the workspace. + +`just publish-dry-run` uses Cargo's workspace dry-run in sys-first order without uploading. The preceding package gate provides the full extracted/offline verification; the workspace command uses `--no-verify` to avoid a registry-resolution cycle before the exact sys version exists on crates.io. After sys is published, run `cargo publish -p vllm-cpp --locked --dry-run` and require its full verification to pass before the safe upload. + +## Publish + +Only an authorized maintainer should publish, from the exact reviewed commit with a clean worktree and index. Verify crates.io credentials and ownership, then publish one crate at a time: + +```console +cargo publish -p vllm-cpp-sys --locked +# Wait until crates.io serves the exact sys version. +cargo publish -p vllm-cpp --locked --dry-run +cargo publish -p vllm-cpp --locked +``` + +The sys crate must be accepted and available from crates.io before publishing the safe crate because the safe archive declares an exact registry dependency. After both uploads, verify the registry metadata, package contents, docs.rs results, and a clean downstream build. Create the Git tag and release notes only for the exact published commit and version. + +## Abort and recovery + +- Before an upload succeeds, abort on any mismatch, validation failure, unexpected file, dirty state, changed lockfile, changed native pin/ABI, or inaccurate release note. Fix the issue in a separately reviewed commit and restart the checklist. +- After crates.io accepts a version, that version cannot be replaced or deleted. Never rebuild a different archive under the same version. +- If the sys crate publishes but the safe crate fails, stop and diagnose. Retry the unchanged safe version only when the failure is transient and the exact reviewed archive remains valid; otherwise prepare a new coordinated version. +- Yank a published version only when leaving it selectable would harm users. Yanking prevents new resolution but does not erase the crate, undo existing lockfiles, or make the version reusable. Record the reason publicly and publish a corrected new version. +- Never use `cargo yank` as an ordinary abort mechanism, and never publish merely to test credentials or packaging. diff --git a/flake.nix b/flake.nix index f22ae48..5d2954f 100644 --- a/flake.nix +++ b/flake.nix @@ -22,6 +22,9 @@ }; rustToolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; + msrvToolchain = pkgs.rust-bin.stable."1.85.0".default.override { + extensions = ["clippy" "rustfmt"]; + }; in { devShells = { @@ -44,6 +47,22 @@ export PS1="(dev:vllm-cpp-rs) $PS1" ''; }; + + msrv = pkgs.mkShell { + packages = [ + msrvToolchain + pkgs.cmake + pkgs.just + pkgs.ninja + pkgs.pkg-config + pkgs.llvmPackages.clang + pkgs.llvmPackages.bintools + ]; + + shellHook = '' + export PS1="(msrv:vllm-cpp-rs) $PS1" + ''; + }; } // pkgs.lib.optionalAttrs (builtins.elem system [ diff --git a/vllm-cpp-sys/Cargo.toml b/vllm-cpp-sys/Cargo.toml index a657b19..f1bc77c 100644 --- a/vllm-cpp-sys/Cargo.toml +++ b/vllm-cpp-sys/Cargo.toml @@ -5,7 +5,11 @@ edition.workspace = true license.workspace = true repository.workspace = true rust-version.workspace = true -description = "Raw Rust bindings and a bundled build for vllm.cpp" +description = "Raw FFI bindings and native build integration for the stable vllm.cpp C API" +readme = "README.md" +documentation = "https://docs.rs/vllm-cpp-sys" +keywords = ["llm", "inference", "ffi", "bindings", "vllm"] +categories = ["external-ffi-bindings"] links = "vllm" build = "build.rs" include = [ @@ -45,5 +49,8 @@ cuda-cutlass = ["cuda"] triton-aot = ["cuda"] vulkan = [] +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + [build-dependencies] cmake = "0.1.58" diff --git a/vllm-cpp-sys/README.md b/vllm-cpp-sys/README.md index d8705ce..a6bfe57 100644 --- a/vllm-cpp-sys/README.md +++ b/vllm-cpp-sys/README.md @@ -1,8 +1,10 @@ # vllm-cpp-sys -Raw Rust bindings and native linking for [vllm.cpp](https://github.com/mudler/vllm.cpp). +Raw Rust bindings and native linking for the stable C API of [vllm.cpp](https://github.com/mudler/vllm.cpp). -This crate exposes generated unsafe functions that mirror the stable C API. Applications should use the application-facing `vllm-cpp` bindings when implemented. Ordinary consumers do not need Just, bindgen, or libclang. +This crate exposes checked-in generated unsafe declarations for the 19 exported C symbols in ABI version 10. Callers are responsible for pointer validity, lifetimes, callback threading, status/error handling, and matching every native allocation with its documented free function. Applications should prefer the current safe [`vllm-cpp`](https://docs.rs/vllm-cpp) crate unless they require direct ABI access. Ordinary consumers do not need Just, bindgen, or libclang. + +The package contains Rust declarations and conformance tests, native build/link integration, the pinned native source inputs required by the supported feature set, and their licenses/notices. It excludes upstream tests, fixtures, models, examples, benchmarks, agent records, fetched SDKs, external CUTLASS trees, and build output. See the repository [changelog](https://github.com/querymt/vllm-cpp-rs/blob/main/CHANGELOG.md) and [release process](https://github.com/querymt/vllm-cpp-rs/blob/main/RELEASING.md) for the coordinated crate boundary. ## Link Modes @@ -35,7 +37,7 @@ These features do not claim runtime support. Known native blockers remain: a CUD ## Generated Bindings -The bundled source is pinned to commit `34aedfbe8ed9779697905541a62e2160ccfd9c05` and exposes C ABI version 10. Bindings are generated with bindgen 0.72.1 from `wrapper.h`, which includes `vllm.cpp/include/vllm.h`, and committed to `src/bindings.rs`. Maintainers use Just 1.40 or newer from the repository root: +The bundled source is pinned to commit `34aedfbe8ed9779697905541a62e2160ccfd9c05` and exposes C ABI version 10. Bindings are generated with bindgen 0.72.1 from `wrapper.h`, which includes `vllm.cpp/include/vllm.h`, and committed to `src/bindings.rs`. The exported stable C boundary is narrower than the broader native C++ implementation; these declarations do not promise access to undocumented internals. Maintainers use Just 1.40 or newer from the repository root: ```console just bindings diff --git a/vllm-cpp-sys/src/lib.rs b/vllm-cpp-sys/src/lib.rs index 91db72e..34ad6f4 100644 --- a/vllm-cpp-sys/src/lib.rs +++ b/vllm-cpp-sys/src/lib.rs @@ -1,7 +1,36 @@ -//! Raw bindings to the stable vllm.cpp C API. +//! Raw FFI declarations for the stable vllm.cpp C API. //! -//! This crate exposes checked-in generated unsafe FFI declarations. Applications -//! should use the application-facing `vllm-cpp` bindings when implemented. +//! The checked-in bindings are generated from `vllm.cpp/include/vllm.h` and +//! expose that header's 19-symbol C boundary, versioned structs, constants, and +//! callback signatures. They target ABI version 10 from pinned vllm.cpp commit +//! `34aedfbe8ed9779697905541a62e2160ccfd9c05`. This exported ABI is narrower than +//! the broader native C++ implementation and does not expose undocumented +//! vllm.cpp internals. +//! +//! # Safety +//! +//! The declarations are intentionally raw. Callers must uphold every pointer, +//! lifetime, aliasing, thread, callback, and NUL-termination contract from the C +//! header. They must check returned status values, copy thread-local error text +//! before another API call on that thread, and release engines, requests, +//! completions, and allocated strings with their matching `vllm_*_free` +//! functions. In particular, ABI version 10 prohibits waiting for or freeing a +//! request from that request's callback thread. Prefer the safe `vllm-cpp` crate +//! unless direct ABI access is required. +//! +//! # Build and link modes +//! +//! The default `bundled` feature compiles and statically links the packaged +//! pinned source. `system` links a caller-provided compatible installation, and +//! `dynamic-link` selects `libvllm.so` in either source mode. Dynamic consumers +//! must deploy the shared library and dependencies through the platform loader. +//! CUDA, external CUTLASS, Triton AOT, and Vulkan features are experimental +//! bundled build configuration and require their documented native inputs. +//! +//! Native Linux x86_64 CPU is the supported runtime tier. Building the bundled +//! source requires CMake 3.24 or newer, a build tool, C11 and C++20 compilers, +//! and a linker/C++ standard library. Documentation builds skip native +//! compilation; that does not validate a runtime library or accelerator. #![allow(non_camel_case_types, non_upper_case_globals)] diff --git a/vllm-cpp/Cargo.toml b/vllm-cpp/Cargo.toml index 6d1571a..f4e3bf6 100644 --- a/vllm-cpp/Cargo.toml +++ b/vllm-cpp/Cargo.toml @@ -5,7 +5,11 @@ edition.workspace = true license.workspace = true repository.workspace = true rust-version.workspace = true -description = "Safe Rust bindings for vllm.cpp" +description = "Safe model inference, streaming, chat, and concurrent requests for vllm.cpp" +readme = "README.md" +documentation = "https://docs.rs/vllm-cpp" +keywords = ["llm", "inference", "ffi", "vllm", "machine-learning"] +categories = ["api-bindings", "science"] [features] default = ["bundled"] @@ -18,6 +22,10 @@ triton-aot = ["cuda", "vllm-cpp-sys/triton-aot"] vulkan = ["vllm-cpp-sys/vulkan"] serde = ["dep:serde_json"] +[package.metadata.docs.rs] +features = ["serde"] +targets = ["x86_64-unknown-linux-gnu"] + [dependencies] serde_json = { version = "1.0.149", optional = true } vllm-cpp-sys = { workspace = true, default-features = false } diff --git a/vllm-cpp/README.md b/vllm-cpp/README.md new file mode 100644 index 0000000..2c9d1a6 --- /dev/null +++ b/vllm-cpp/README.md @@ -0,0 +1,55 @@ +# vllm-cpp + +Safe Rust API for the stable [vllm.cpp](https://github.com/mudler/vllm.cpp) C boundary. The crate owns native resources, checks ABI compatibility before model loading, and provides blocking completion/streaming/chat plus concurrent requests. Use `vllm-cpp-sys` directly only when an application needs the unsafe raw ABI. + +## Quick use + +```rust +use vllm_cpp::{Engine, SamplingParams}; + +let engine = Engine::load("/models/Qwen3-0.6B")?; +let params = SamplingParams::greedy().max_tokens(32); +let completion = engine.complete("The capital of France is", ¶ms)?; +println!("{}", completion.text); +# Ok::<(), vllm_cpp::Error>(()) +``` + +The model argument is a directory understood by the pinned native engine, not a single weights file. The known-good test layout contains `model.safetensors`, `config.json`, `tokenizer.json`, and `tokenizer_config.json`; model-family compatibility remains a native vllm.cpp concern. See the packaged [examples guide](examples/README.md) for blocking completion, streaming, chat, structured output, and concurrent-request commands. + +## API and ownership + +- `EngineBuilder` configures and loads a model. `Engine` is `Clone + Send + Sync`; clones share one reference-counted native engine. +- `SamplingParams` owns stop strings and structured constraints. Completion, chat, error, and stream text is copied into Rust-owned values before native storage is released or reused. +- Blocking `complete`, `complete_stream`, `chat_json`, and `chat_stream_json` calls keep borrowed callbacks alive only for the call. Callback panics are caught before crossing C and resumed after the native call returns. +- `Engine::submit` returns a `Request` before generation finishes. A request retains its engine and callback until native free/join completes, is `Send`, and is deliberately not `Sync`. +- Asynchronous callbacks run on a native delivery thread and must be `Send + 'static`. `wait` reports callback panics as `Error::CallbackPanicked`; waiting or freeing from that same callback thread is prohibited by ABI v10, so callback-thread drop transfers cleanup to a prestarted reaper. +- Dropping a live request cancels and joins it. `cancel` is idempotent, `wait` reports the request outcome, and `native_error` copies the request-owned diagnostic after completion into an owned Rust `String`; the native storage remains valid until the request is dropped or freed. + +## Features and linking + +| Feature | Purpose | +|---|---| +| `bundled` (default) | Build and statically link the pinned CPU native source | +| `system` | Link a caller-provided installation; use with `--no-default-features` | +| `dynamic-link` | Link `libvllm` dynamically in bundled or system mode | +| `serde` | Add `serde_json::Value` chat helpers | +| `cuda` | Experimental bundled CUDA build configuration | +| `cuda-cutlass` | Experimental CUDA build with a caller-provided CUTLASS >=4.5.0 tree | +| `triton-aot` | Experimental CUDA build using checked-in Triton AOT artifacts | +| `vulkan` | Experimental bundled Vulkan build configuration | + +`bundled` and `system` conflict. CUDA and Vulkan conflict, and accelerator features are bundled-only but do not implicitly enable `bundled` for `--no-default-features` builds. The workspace [backend documentation](https://github.com/querymt/vllm-cpp-rs#experimental-backend-builds) records exact environment variables, supported build architectures, and current blockers. + +## ABI and deployment + +This crate is tied to the exact same `vllm-cpp-sys` crate version and the pinned vllm.cpp commit `34aedfbe8ed9779697905541a62e2160ccfd9c05`. Model loading requires exact C ABI version 10 before any versioned struct crosses FFI. A system library must implement the same ABI; the consumer build checks for its header, while maintainer conformance tests check layout and symbols. + +Static bundled builds include the native archive in the application link. Dynamic bundled or system builds do not deploy `libvllm.so`: install it and its backend/toolkit dependencies in a loader-visible location using `LD_LIBRARY_PATH`, rpath, or the system loader configuration. System mode uses `VLLM_CPP_ROOT`; `VLLM_CPP_LIB_DIR` can choose a nonstandard library directory. System static linking also requires the matching `libblake3_vendored.a` through `VLLM_CPP_BLAKE3_LIB_DIR` or the selected vllm library directory. + +## Support boundary + +The supported runtime tier is native Linux x86_64 CPU, covering bundled/system and static/dynamic link modes. Linux x86_64/aarch64 CUDA, external CUTLASS, Triton AOT, and Vulkan features are experimental build/configuration surfaces only. Known native blockers include CUDA teardown failure, CUDA bf16 numerical tolerance failure, CUTLASS concurrent-output differences, and incomplete Vulkan runtime coverage. Successful compilation is not a runtime-support claim. + +See the repository [changelog](https://github.com/querymt/vllm-cpp-rs/blob/main/CHANGELOG.md), [release process](https://github.com/querymt/vllm-cpp-rs/blob/main/RELEASING.md), and [root support details](https://github.com/querymt/vllm-cpp-rs#support) for the current release boundary. + +The crate is dual-licensed under MIT or Apache-2.0. diff --git a/vllm-cpp/src/lib.rs b/vllm-cpp/src/lib.rs index 1d21c30..8a98169 100644 --- a/vllm-cpp/src/lib.rs +++ b/vllm-cpp/src/lib.rs @@ -1,9 +1,43 @@ -//! Safe Rust bindings for the stable vllm.cpp C API. +//! Safe model inference API for the stable vllm.cpp C boundary. //! -//! [`Engine`] is a cloneable, shared owner of a complete native serving stack. -//! It provides blocking completion, streaming, and chat methods plus -//! [`Engine::submit`] for non-blocking requests. Each [`Request`] retains the -//! engine until native request free/join completes. +//! # Entry points +//! +//! Create an [`Engine`] with [`Engine::load`] or configure native model settings +//! through [`EngineBuilder`]. [`SamplingParams`] owns sampling, stop-string, and +//! [`StructuredOutput`] settings for completion calls. The engine provides +//! blocking completion, streaming, raw-JSON chat, and [`Engine::submit`] for a +//! concurrent [`Request`]. Enable `serde` for `serde_json::Value` chat helpers. +//! +//! # Ownership and callbacks +//! +//! [`Engine`] is a cloneable RAII owner; clones share one reference-counted +//! native engine. Rust copies completion, stream, chat, and error text before +//! native storage is freed or reused. Blocking callbacks may borrow caller data. +//! Their panics are caught before the C boundary and resumed after the native +//! call returns. +//! +//! A [`Request`] retains its engine and asynchronous callback until native +//! free/join completes. Requests are `Send` but intentionally not `Sync`, while +//! engines are `Send + Sync`. Asynchronous callbacks run on a native delivery +//! thread, must be `Send + 'static`, and surface panic through +//! [`Error::CallbackPanicked`]. ABI version 10 forbids waiting for or freeing a +//! request from its callback thread; callback-thread drop delegates ownership to +//! a cleanup reaper instead. +//! +//! # ABI, linking, and deployment +//! +//! Engine loading requires the linked native library's ABI to equal +//! [`expected_abi_version`] before versioned structs cross FFI. The default +//! `bundled` feature builds the pinned native source. `system` selects a +//! caller-provided installation, `dynamic-link` selects shared linking, and +//! `serde` adds typed JSON helpers. CUDA, CUTLASS, Triton AOT, and Vulkan features +//! are experimental bundled build configuration. +//! +//! Dynamic linking does not deploy `libvllm.so`; applications must make it and +//! its runtime dependencies visible through `LD_LIBRARY_PATH`, rpath, or system +//! loader configuration. The supported runtime tier is native Linux x86_64 CPU. +//! Accelerator features are build/configuration surfaces with known runtime +//! blockers, not complete accelerator runtime support. mod callback; mod engine;