Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 56 additions & 15 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ endif()

set(CMAKE_CXX_STANDARD 26)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# The public binary drop (docs/releases.md): prebuilt proprietary parts for a source build outside
# the org. Sets ONEBIT_BINARY_DROP_* and verifies the drop; a no-op when ONEBIT_BINARY_DROP is unset.
include(cmake/binary_drop.cmake)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

Expand Down Expand Up @@ -178,7 +182,10 @@ if(ONEBIT_GPU_PRIVATE AND NOT ONEBIT_HRX)
endif()
if(ONEBIT_HRX)
include(cmake/hrx.cmake)
add_dependencies(onebit llama_hrx)
# A drop build has no llama_hrx target: the prebuilt server and its libraries come from the drop.
if(TARGET llama_hrx)
add_dependencies(onebit llama_hrx)
endif()
target_compile_definitions(onebit PRIVATE ONEBIT_HRX_SERVER="${ONEBIT_HRX_SERVER}" ONEBIT_HRX_LIBHSA="${ONEBIT_HRX_LIBHSA}"
ONEBIT_HRX_ALLOW_NO_SVM=${ONEBIT_HRX_ALLOW_NO_SVM})
if(ONEBIT_SERVE_TEST_GGUF)
Expand Down Expand Up @@ -420,15 +427,21 @@ add_test(NAME npu_private_route COMMAND npu_private_route_test)
endif() # ONEBIT_NPU_HOST

# The lane itself: needs the NPU runtime and an XDNA NPU to run.
option(ONEBIT_NPU "Build the NPU lane (needs the private NPU runtime: ONEBIT_NPU_RT_DIR)" OFF)
option(ONEBIT_NPU "Build the NPU lane (needs the private NPU runtime: ONEBIT_NPU_RT_LIB or ONEBIT_NPU_RT_DIR)" OFF)
# The NPU code compiles against one runtime (npu/rt.h, docs/npu.md "The NPU runtime"): our own, an
# XRT-compatible runtime that is not part of this repository. ONEBIT_NPU_RT_DIR holds its npu_rt.h
# and npu_rt.cpp, built here into the static library onebit_npu_rt and linked into 1bit. AMD's XRT
# is not supported: the engine links no XRT library. The release build takes the runtime from the
# pinned private checkout in config/npu-runtime.config (scripts/fetch-private.sh).
# XRT-compatible runtime that is not part of this repository, behind our public header
# npu/npu_rt_api.h. It comes one of two ways, exactly one of which must be set:
# ONEBIT_NPU_RT_LIB a prebuilt static library (libnpu_rt_api.a) that implements npu_rt_api.h;
# no runtime source or private header is needed.
# ONEBIT_NPU_RT_DIR the runtime's private sources (npu_rt.h, npu_rt.cpp, npu_rt_api.cpp), built
# here into the static library onebit_npu_rt. npu_rt.h stays on that library's
# own include path only; the engine's sources see npu_rt_api.h.
# AMD's XRT is not supported: the engine links no XRT library. The release build takes the runtime
# from the pinned private checkout in config/npu-runtime.config (scripts/fetch-private.sh).
set(ONEBIT_NPU_RUNTIME "own" CACHE STRING "NPU runtime: own (the only value)")
set_property(CACHE ONEBIT_NPU_RUNTIME PROPERTY STRINGS own)
set(ONEBIT_NPU_RT_DIR "" CACHE PATH "Directory with the NPU runtime's npu_rt.h and npu_rt.cpp (private)")
set(ONEBIT_NPU_RT_DIR "" CACHE PATH "Directory with the NPU runtime's private sources: npu_rt.h, npu_rt.cpp, npu_rt_api.cpp")
set(ONEBIT_NPU_RT_LIB "" CACHE FILEPATH "Prebuilt NPU runtime static library implementing npu/npu_rt_api.h (libnpu_rt_api.a)")
if(NOT ONEBIT_NPU_RUNTIME STREQUAL "own")
message(FATAL_ERROR "ONEBIT_NPU_RUNTIME must be own, not '${ONEBIT_NPU_RUNTIME}': the engine builds "
"no XRT NPU lane (docs/npu.md, \"The NPU runtime\")")
Expand All @@ -443,16 +456,44 @@ if(ONEBIT_NPU_HOST AND NOT WIN32)
set_tests_properties(npu_runtime_option PROPERTIES TIMEOUT 300)
endif()
if(ONEBIT_NPU)
if(NOT EXISTS "${ONEBIT_NPU_RT_DIR}/npu_rt.h" OR NOT EXISTS "${ONEBIT_NPU_RT_DIR}/npu_rt.cpp")
message(FATAL_ERROR "ONEBIT_NPU needs the NPU runtime: ONEBIT_NPU_RT_DIR must hold npu_rt.h and "
"npu_rt.cpp (ONEBIT_NPU_RT_DIR='${ONEBIT_NPU_RT_DIR}'). The runtime is private; "
"without it, build with ONEBIT_NPU=OFF (docs/npu.md, \"The NPU runtime\")")
# The public binary drop carries the runtime already compiled (libnpu_rt_api.a behind
# npu/npu_rt_api.h), for a source build that has no private runtime sources
# (docs/releases.md, "The public binary drop").
if(NOT ONEBIT_NPU_RT_LIB AND NOT ONEBIT_NPU_RT_DIR AND ONEBIT_BINARY_DROP_NPU_LIB)
set(ONEBIT_NPU_RT_LIB "${ONEBIT_BINARY_DROP_NPU_LIB}")
message(STATUS "ONEBIT_NPU: runtime from the binary drop: ${ONEBIT_NPU_RT_LIB}")
endif()
if(ONEBIT_NPU_RT_LIB AND ONEBIT_NPU_RT_DIR)
message(FATAL_ERROR "ONEBIT_NPU takes one NPU runtime: set ONEBIT_NPU_RT_LIB or ONEBIT_NPU_RT_DIR, "
"not both (docs/npu.md, \"The NPU runtime\")")
endif()
add_library(onebit_npu_rt STATIC ${ONEBIT_NPU_RT_DIR}/npu_rt.cpp)
target_include_directories(onebit_npu_rt SYSTEM PUBLIC ${ONEBIT_NPU_RT_DIR})
target_compile_definitions(onebit_npu_rt PUBLIC ONEBIT_NPU_RUNTIME_OWN)
find_package(Threads REQUIRED)
target_link_libraries(onebit_npu_rt PUBLIC Threads::Threads)
if(ONEBIT_NPU_RT_LIB)
if(NOT EXISTS "${ONEBIT_NPU_RT_LIB}" OR IS_DIRECTORY "${ONEBIT_NPU_RT_LIB}")
message(FATAL_ERROR "ONEBIT_NPU_RT_LIB='${ONEBIT_NPU_RT_LIB}' is not a library file "
"(docs/npu.md, \"The NPU runtime\")")
endif()
add_library(onebit_npu_rt_prebuilt STATIC IMPORTED)
set_target_properties(onebit_npu_rt_prebuilt PROPERTIES IMPORTED_LOCATION "${ONEBIT_NPU_RT_LIB}")
add_library(onebit_npu_rt INTERFACE)
target_link_libraries(onebit_npu_rt INTERFACE onebit_npu_rt_prebuilt Threads::Threads)
target_include_directories(onebit_npu_rt INTERFACE ${CMAKE_SOURCE_DIR}/npu)
target_compile_definitions(onebit_npu_rt INTERFACE ONEBIT_NPU_RUNTIME_OWN)
else()
if(NOT EXISTS "${ONEBIT_NPU_RT_DIR}/npu_rt.h" OR NOT EXISTS "${ONEBIT_NPU_RT_DIR}/npu_rt.cpp"
OR NOT EXISTS "${ONEBIT_NPU_RT_DIR}/npu_rt_api.cpp")
message(FATAL_ERROR "ONEBIT_NPU needs the NPU runtime: ONEBIT_NPU_RT_LIB must name its prebuilt "
"library, or ONEBIT_NPU_RT_DIR must hold npu_rt.h, npu_rt.cpp and npu_rt_api.cpp "
"(ONEBIT_NPU_RT_DIR='${ONEBIT_NPU_RT_DIR}'). The runtime is private; "
"without it, build with ONEBIT_NPU=OFF (docs/npu.md, \"The NPU runtime\")")
endif()
add_library(onebit_npu_rt STATIC ${ONEBIT_NPU_RT_DIR}/npu_rt.cpp ${ONEBIT_NPU_RT_DIR}/npu_rt_api.cpp)
# npu_rt.h: this library's own include path only (PRIVATE), never the engine's.
target_include_directories(onebit_npu_rt SYSTEM PRIVATE ${ONEBIT_NPU_RT_DIR})
target_include_directories(onebit_npu_rt PUBLIC ${CMAKE_SOURCE_DIR}/npu)
target_compile_definitions(onebit_npu_rt PUBLIC ONEBIT_NPU_RUNTIME_OWN)
target_link_libraries(onebit_npu_rt PUBLIC Threads::Threads)
endif()
add_library(onebit_npu_lane STATIC npu/lane.cpp npu/generate.cpp)
target_link_libraries(onebit_npu_lane PUBLIC onebit_npu onebit_npu_rt)
target_sources(onebit PRIVATE app/unified.cpp)
Expand Down
175 changes: 175 additions & 0 deletions cmake/binary_drop.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
# Copyright 2026 bong-water-water-bong
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# The public binary drop (docs/releases.md, "The public binary drop").
#
# A source build outside the org has no private HIP kernels and no private NPU runtime source, so it
# cannot compile those parts itself. The drop carries them already compiled, for one exact engine
# pin, under the 1bit Binary License. ONEBIT_BINARY_DROP names it: a directory (unpacked, or the
# tarball's own directory) or the tarball's URL.
#
# Everything is verified before use and a mismatch is fatal:
# URL the sha256 pinned in config/binary-drop.config for this engine commit (or
# -DONEBIT_BINARY_DROP_SHA256 when the pin file has no line yet) is the expected hash of
# the download; file(DOWNLOAD) refuses a body that does not match.
# path the drop's MANIFEST lists a sha256 per file and the engine commit it was built from;
# a file that does not match, or a drop built from another commit, stops the configure.
#
# On success this sets, for the two consumers:
# ONEBIT_BINARY_DROP_DIR the unpacked drop root
# ONEBIT_BINARY_DROP_HRX_BIN <root>/hrx/llama/bin (cmake/hrx.cmake)
# ONEBIT_BINARY_DROP_NPU_LIB <root>/npu/libnpu_rt_api.a (the NPU block in CMakeLists.txt)
# ONEBIT_BINARY_DROP_NPU_INCLUDE <root>/npu/include
# and leaves them unset otherwise, so a build without a drop behaves exactly as before.

set(ONEBIT_BINARY_DROP "" CACHE STRING
"Path or URL of the public binary drop to link instead of compiling the private parts (docs/releases.md)")
set(ONEBIT_BINARY_DROP_SHA256 "" CACHE STRING
"sha256 of the drop tarball, for a URL whose engine pin has no line in config/binary-drop.config")
mark_as_advanced(ONEBIT_BINARY_DROP_SHA256)

set(ONEBIT_BINARY_DROP_DIR "")
set(ONEBIT_BINARY_DROP_HRX_BIN "")
set(ONEBIT_BINARY_DROP_NPU_LIB "")
set(ONEBIT_BINARY_DROP_NPU_INCLUDE "")

if(NOT ONEBIT_BINARY_DROP)
return()
endif()

# The engine commit this build is from: the drop is built for exactly one.
set(_drop_engine_sha "")
if(EXISTS "${CMAKE_SOURCE_DIR}/.git")
find_package(Git QUIET)
if(Git_FOUND)
execute_process(COMMAND "${GIT_EXECUTABLE}" -C "${CMAKE_SOURCE_DIR}" rev-parse HEAD
OUTPUT_VARIABLE _drop_engine_sha OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET)
endif()
endif()

# config/binary-drop.config: the url pattern and one sha256 per published engine commit.
set(_drop_url_pattern "")
set(_drop_pinned_sha "")
if(EXISTS "${CMAKE_SOURCE_DIR}/config/binary-drop.config")
file(STRINGS "${CMAKE_SOURCE_DIR}/config/binary-drop.config" _drop_cfg)
foreach(_line IN LISTS _drop_cfg)
if(_line MATCHES "^url_pattern=(.+)$")
set(_drop_url_pattern "${CMAKE_MATCH_1}")
elseif(_line MATCHES "^drop=([0-9a-f]+)[ \t]+([^ \t]+)[ \t]+([0-9a-f]+)[ \t]*$")
string(LENGTH "${CMAKE_MATCH_1}" _n_sha)
string(LENGTH "${CMAKE_MATCH_3}" _n_sum)
if(_n_sha EQUAL 40 AND _n_sum EQUAL 64 AND _drop_engine_sha STREQUAL CMAKE_MATCH_1)
set(_drop_pinned_sha "${CMAKE_MATCH_3}")
set(_drop_pinned_version "${CMAKE_MATCH_2}")
endif()
endif()
endforeach()
endif()

set(_drop_verify_manifest FALSE)
if(IS_DIRECTORY "${ONEBIT_BINARY_DROP}")
set(ONEBIT_BINARY_DROP_DIR "${ONEBIT_BINARY_DROP}")
set(_drop_verify_manifest TRUE)
elseif(ONEBIT_BINARY_DROP MATCHES "^[a-zA-Z][a-zA-Z0-9+.-]*://")
# A URL: download it, with the pinned sha256 as the expected hash.
if(NOT _drop_pinned_sha)
if(ONEBIT_BINARY_DROP_SHA256)
set(_drop_pinned_sha "${ONEBIT_BINARY_DROP_SHA256}")
message(STATUS "ONEBIT_BINARY_DROP: pin file has no line for this engine commit; using ONEBIT_BINARY_DROP_SHA256")
else()
message(FATAL_ERROR
"ONEBIT_BINARY_DROP is a URL but config/binary-drop.config pins no drop for engine commit "
"'${_drop_engine_sha}'. Add its line (drop=<sha> <version> <sha256>), or pass "
"-DONEBIT_BINARY_DROP_SHA256=<sha256> (docs/releases.md, \"The public binary drop\").")
endif()
endif()
set(_drop_dir "${CMAKE_BINARY_DIR}/_binary_drop")
set(_drop_tgz "${_drop_dir}/binary-drop.tar.zst")
file(MAKE_DIRECTORY "${_drop_dir}")
message(STATUS "ONEBIT_BINARY_DROP: downloading ${ONEBIT_BINARY_DROP}")
file(DOWNLOAD "${ONEBIT_BINARY_DROP}" "${_drop_tgz}"
EXPECTED_HASH SHA256=${_drop_pinned_sha}
TLS_VERIFY ON STATUS _drop_dl_status)
list(GET _drop_dl_status 0 _drop_dl_code)
if(NOT _drop_dl_code EQUAL 0)
list(GET _drop_dl_status 1 _drop_dl_msg)
message(FATAL_ERROR "ONEBIT_BINARY_DROP: download failed (${_drop_dl_msg}); the pinned sha256 "
"was ${_drop_pinned_sha}. Refusing to build against an unverified drop.")
endif()
file(MAKE_DIRECTORY "${_drop_dir}/root")
execute_process(COMMAND "${CMAKE_COMMAND}" -E tar xf "${_drop_tgz}"
WORKING_DIRECTORY "${_drop_dir}/root"
RESULT_VARIABLE _drop_untar)
if(NOT _drop_untar EQUAL 0)
message(FATAL_ERROR "ONEBIT_BINARY_DROP: cannot unpack ${_drop_tgz}")
endif()
file(GLOB _drop_roots "${_drop_dir}/root/binary-drop-*")
list(LENGTH _drop_roots _drop_n)
if(NOT _drop_n EQUAL 1)
message(FATAL_ERROR "ONEBIT_BINARY_DROP: the tarball does not hold one binary-drop-* directory")
endif()
list(GET _drop_roots 0 ONEBIT_BINARY_DROP_DIR)
set(_drop_verify_manifest TRUE)
else()
message(FATAL_ERROR "ONEBIT_BINARY_DROP='${ONEBIT_BINARY_DROP}' is neither a directory nor a URL")
endif()

# Verify: the MANIFEST lists a sha256 per file and the engine commit it was built from.
if(_drop_verify_manifest)
if(NOT EXISTS "${ONEBIT_BINARY_DROP_DIR}/MANIFEST")
message(FATAL_ERROR "ONEBIT_BINARY_DROP: ${ONEBIT_BINARY_DROP_DIR} has no MANIFEST; not a binary drop")
endif()
file(STRINGS "${ONEBIT_BINARY_DROP_DIR}/MANIFEST" _drop_lines)
set(_drop_manifest_sha "")
set(_drop_checked 0)
foreach(_line IN LISTS _drop_lines)
if(_line MATCHES "^engine_sha=([0-9a-f]+)$")
string(LENGTH "${CMAKE_MATCH_1}" _n_sha)
if(_n_sha EQUAL 40)
set(_drop_manifest_sha "${CMAKE_MATCH_1}")
endif()
elseif(_line MATCHES "^([0-9a-f]+) +([0-9]+) +(.+)$")
string(LENGTH "${CMAKE_MATCH_1}" _n_sum)
if(NOT _n_sum EQUAL 64)
message(FATAL_ERROR "ONEBIT_BINARY_DROP: MANIFEST line does not start with a sha256: ${_line}")
endif()
set(_drop_hash "${CMAKE_MATCH_1}")
set(_drop_file "${CMAKE_MATCH_3}")
file(SHA256 "${ONEBIT_BINARY_DROP_DIR}/${_drop_file}" _drop_actual)
if(NOT _drop_actual STREQUAL _drop_hash)
message(FATAL_ERROR "ONEBIT_BINARY_DROP: ${_drop_file} does not match its MANIFEST sha256 "
"(expected ${_drop_hash}, got ${_drop_actual}). Refusing to link it.")
endif()
math(EXPR _drop_checked "${_drop_checked} + 1")
endif()
endforeach()
if(_drop_checked EQUAL 0)
message(FATAL_ERROR "ONEBIT_BINARY_DROP: the MANIFEST lists no files")
endif()
if(_drop_engine_sha AND _drop_manifest_sha AND NOT _drop_manifest_sha STREQUAL _drop_engine_sha)
message(FATAL_ERROR "ONEBIT_BINARY_DROP: ${ONEBIT_BINARY_DROP_DIR} was built for engine commit "
"${_drop_manifest_sha}, but this checkout is ${_drop_engine_sha}. The drop is per "
"engine pin; build the matching one (docs/releases.md).")
endif()
message(STATUS "ONEBIT_BINARY_DROP: ${ONEBIT_BINARY_DROP_DIR}: ${_drop_checked} files verified against MANIFEST")
endif()

if(EXISTS "${ONEBIT_BINARY_DROP_DIR}/hrx/llama/bin/llama-server")
set(ONEBIT_BINARY_DROP_HRX_BIN "${ONEBIT_BINARY_DROP_DIR}/hrx/llama/bin")
endif()
if(EXISTS "${ONEBIT_BINARY_DROP_DIR}/npu/libnpu_rt_api.a")
set(ONEBIT_BINARY_DROP_NPU_LIB "${ONEBIT_BINARY_DROP_DIR}/npu/libnpu_rt_api.a")
set(ONEBIT_BINARY_DROP_NPU_INCLUDE "${ONEBIT_BINARY_DROP_DIR}/npu/include")
endif()
35 changes: 35 additions & 0 deletions cmake/hrx.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,41 @@ include(ExternalProject)

set(ONEBIT_HRX_TOOLCHAIN "/opt/rocm-therock" CACHE PATH "ROCm/TheRock root: its amdclang builds llama.cpp and HRX")

# A source build outside the org has no private HIP kernels to compile, so it links the prebuilt
# HRX tree from the public binary drop instead (docs/releases.md, "The public binary drop"): the
# pinned llama-server and its libraries, libggml-hrx.so with those kernels compiled in. Nothing is
# built here in that case, so neither TheRock nor the llama.cpp/hrx-system submodules are needed;
# HRX still dlopens TheRock's HSA runtime on the machine that runs it.
if(ONEBIT_BINARY_DROP_HRX_BIN AND EXISTS "${ONEBIT_BINARY_DROP_HRX_BIN}/llama-server")
if(ONEBIT_GPU_PRIVATE)
message(FATAL_ERROR "ONEBIT_HRX: set either ONEBIT_GPU_PRIVATE (compile the private kernels here) "
"or ONEBIT_BINARY_DROP (use them prebuilt), not both (docs/releases.md)")
endif()
if(NOT ONEBIT_HRX_LIBHSA)
file(GLOB_RECURSE _drop_libhsa "${ONEBIT_HRX_TOOLCHAIN}/*/libhsa-runtime64.so.1")
set(_drop_libhsa_first "")
if(_drop_libhsa)
list(SORT _drop_libhsa)
list(GET _drop_libhsa 0 _drop_libhsa_first)
endif()
if(_drop_libhsa_first)
set(ONEBIT_HRX_LIBHSA "${_drop_libhsa_first}" CACHE FILEPATH
"TheRock HSA runtime HRX loads (IREE_HAL_AMDGPU_LIBHSA_PATH)" FORCE)
else()
set(ONEBIT_HRX_LIBHSA "" CACHE FILEPATH
"TheRock HSA runtime HRX loads (IREE_HAL_AMDGPU_LIBHSA_PATH)" FORCE)
message(STATUS "ONEBIT_HRX: no libhsa-runtime64.so.1 under ${ONEBIT_HRX_TOOLCHAIN}; the build "
"proceeds, but HRX needs TheRock's on the machine that runs it (pass "
"-DONEBIT_HRX_LIBHSA=<path> to bake it in)")
endif()
endif()
set(ONEBIT_HRX_SERVER "${ONEBIT_BINARY_DROP_HRX_BIN}/llama-server" CACHE FILEPATH
"HRX llama-server 1bit runs" FORCE)
set(ONEBIT_HRX_ALLOW_NO_SVM 1)
message(STATUS "ONEBIT_HRX: prebuilt from the binary drop: ${ONEBIT_HRX_SERVER} (HSA runtime: ${ONEBIT_HRX_LIBHSA})")
return()
endif()

foreach(_sub hrx-system llama.cpp)
if(NOT EXISTS "${CMAKE_SOURCE_DIR}/third_party/${_sub}/CMakeLists.txt")
message(FATAL_ERROR "ONEBIT_HRX needs third_party/${_sub}: git submodule update --init third_party/${_sub}")
Expand Down
Loading
Loading