# Copyright 2026 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 EAPI=8 ROCM_VERSION="6.3" PYTHON_COMPAT=( python3_{12..14} ) inherit python-single-r1 rocm toolchain-funcs wrapper DESCRIPTION="All-in-one local AI server (LLM, image, speech, TTS) on ggml/llama.cpp" HOMEPAGE="https://github.com/LostRuins/koboldcpp" SRC_URI="https://github.com/LostRuins/${PN}/archive/refs/tags/v${PV}.tar.gz -> ${P}.gh.tar.gz" S="${WORKDIR}/${PN}-${PV}" # koboldcpp + KoboldAI Lite UI are AGPL-3.0; the vendored ggml/llama.cpp/ # stable-diffusion.cpp/TTS.cpp code is MIT per # MIT_LICENSE_GGML_SDCPP_LLAMACPP_ONLY.md. LICENSE="AGPL-3+ MIT" SLOT="0" KEYWORDS="~amd64" # Vulkan on by default (upstream's supported GPU path for AMD+NVIDIA). # ROCm ships as upstream target koboldcpp_hipblas, untested on the # maintainer's hardware. No CUDA: nothing to build-test it with. IUSE="+vulkan rocm" # LLAMA_NOAVX1/LLAMA_NOAVX2 pick one of the Makefile's three x86 flag tiers # (lines 172-191 of the 1.122.1 Makefile): # unset -mavx2 -mavx -mfma -mf16c -msse3 -mssse3 # LLAMA_NOAVX2=1 -mavx -msse3 -mssse3 # LLAMA_NOAVX1=1 -msse3 -mssse3 # f16c/fma3 exist only inside the AVX2 tier, hence the REQUIRED_USE coupling. IUSE+=" cpu_flags_x86_avx cpu_flags_x86_avx2 cpu_flags_x86_f16c cpu_flags_x86_fma3" REQUIRED_USE=" ${PYTHON_REQUIRED_USE} rocm? ( ${ROCM_REQUIRED_USE} ) cpu_flags_x86_avx2? ( cpu_flags_x86_avx cpu_flags_x86_f16c cpu_flags_x86_fma3 ) " # No third-party Python deps: koboldcpp.py and kcpp_agent.py import stdlib # only (checked 2026-10-13). requirements.txt mentions jinja2, but that is # for the model-conversion scripts under conversion/ and gguf-py/, which are # not installed here. RDEPEND=" ${PYTHON_DEPS} rocm? ( >=dev-util/hip-${ROCM_VERSION} >=sci-libs/hipBLAS-${ROCM_VERSION} ) vulkan? ( media-libs/vulkan-loader ) " DEPEND=" ${RDEPEND} vulkan? ( dev-util/vulkan-headers ) " BDEPEND=" ${PYTHON_DEPS} vulkan? ( media-libs/shaderc ) " # Prebuilt binaries shipped in the tarball (Windows EXEs/DLLs, a stray # x86-64 ELF, bundled glslc). All seven confirmed present in v1.122.1. # Die if any is missing: with a Manifest-pinned distfile that can only mean # this list was never re-checked for the version being built. KCPP_BLOBS=( aria2c-win.exe cudart64_110.dll cudart64_12.dll glslc-linux glslc.exe simplecpuinfo simplecpuinfo.exe ) pkg_setup() { python-single-r1_pkg_setup } src_prepare() { default # Release flags hardcode -s (Makefile lines 62-63); drop it so Portage # keeps control of stripping. -DNDEBUG stays. grep -q -- '-DNDEBUG -s' Makefile || die "strip-deferral anchor '-DNDEBUG -s' is gone from Makefile" sed -i -e 's/-DNDEBUG -s/-DNDEBUG/g' Makefile || die # Removing the bundled glslc binaries forces the system shaderc one. # The Makefile tests LLAMA_USE_BUNDLED_GLSLC with [ -n ] (lines # 831/875) and defaults it to 1 (line 101), so src_compile overrides it # with an EMPTY value -- 0 would truthy-match the test. local blob for blob in "${KCPP_BLOBS[@]}"; do [[ -f ${blob} ]] || die "expected prebuilt blob ${blob} not found; re-audit the tarball" done rm -f "${KCPP_BLOBS[@]}" || die } src_compile() { tc-export CC CXX # LLAMA_PORTABLE=1 suppresses the Makefile's -march=native (x86, # lines 187-190) and -mcpu=native (aarch64, line 371) additions so the # result is not tuned to the build host. # # Upstream overwrites CFLAGS/CXXFLAGS/LDFLAGS outright (its include # paths live in those variables), so user *FLAGS cannot be passed # through make; ISA choice happens via cpu_flags_x86_* below. local makeargs=( LLAMA_PORTABLE=1 LLAMA_USE_BUNDLED_GLSLC= ) if use amd64; then if use cpu_flags_x86_avx2; then : # top tier, nothing to set elif use cpu_flags_x86_avx; then makeargs+=( LLAMA_NOAVX2=1 ) else makeargs+=( LLAMA_NOAVX1=1 ) fi fi local targets=( koboldcpp_default ) if use vulkan; then targets+=( koboldcpp_vulkan ) makeargs+=( LLAMA_VULKAN=1 ) fi emake "${makeargs[@]}" "${targets[@]}" if use rocm; then # Built in a second emake call so it reuses the objects from the # first run, matching upstream's default target structure. # # The Makefile locates its HIP toolchain via $(wildcard /opt/rocm) # and appends $(shell amdgpu-arch) (the build host's GPU) to # GPU_TARGETS; point all three at the Gentoo hip installation and # the AMDGPU_TARGETS USE_EXPAND instead. rocm_add_sandbox emake "${makeargs[@]}" \ LLAMA_HIPBLAS=1 \ ROCM_PATH="$(hipconfig -R)" \ HCC="$(hipconfig -l)/clang" \ HCXX="$(hipconfig -l)/clang++" \ GPU_TARGETS="${AMDGPU_TARGETS}" \ koboldcpp_hipblas fi } src_install() { local dest="/usr/share/${PN}" insinto "${dest}" # kcpp_agent.py has to sit next to koboldcpp.py: the launcher builds # the path /kcpp_agent.py and does a plain "import # kcpp_agent" for --agent (lines 11713/11723). doins koboldcpp.py kcpp_agent.py # Backend libraries are discovered relative to the launcher's own path. doins koboldcpp_*.so # Web UI, API docs, SD/TTS assets, chat-format adapters. doins -r embd_res kcpp_adapters python_fix_shebang "${ED}${dest}"/{koboldcpp,kcpp_agent}.py make_wrapper "${PN}" "${EPYTHON} ${EPREFIX}${dest}/koboldcpp.py" dodoc README.md } pkg_postinst() { elog "koboldcpp installed to ${EROOT}/usr/share/${PN}; run it with:" elog " koboldcpp --model /path/to/model.gguf" elog if use vulkan; then elog "Vulkan (the official AMD/NVIDIA GPU path) is available; add" elog " --usevulkan" elog "to offload to the GPU." fi if use rocm; then elog "ROCm/hipBLAS is available; add" elog " --usecublas" elog "to offload to an AMD GPU (koboldcpp reuses the cuBLAS flag" elog "for the hipBLAS backend)." elog elog "Note: USE=rocm is wired but was not build-verified by the" elog "maintainer; please report the result of your build." fi elog "Models are NOT bundled; download a .gguf yourself." }