Files
searchi/tools/embeddinggemma2/build_runtime.py
T

133 lines
7.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Build a pinned isolated native worker; development VM builds use --backend cpu."""
import argparse
import hashlib
import json
import os
import re
from pathlib import Path
import shutil
import subprocess
import sys
ROOT = Path(__file__).resolve().parents[2]
TAG = "b11461"
COMMIT = "4d756bc72bf00a4aacf410ae15a2d315f3db400d"
WINDOWS_CRT_FILES = (
"concrt140.dll", "msvcp140.dll", "msvcp140_1.dll", "msvcp140_2.dll",
"msvcp140_atomic_wait.dll", "msvcp140_codecvt_ids.dll", "vccorlib140.dll",
"vcruntime140.dll", "vcruntime140_1.dll", "vcruntime140_threads.dll",
)
def bundle_windows_crt(build):
"""Copy unchanged release CRT from the selected Visual Studio installation."""
cache = (build / "CMakeCache.txt").read_text(encoding="utf-8")
match = re.search(r"^CMAKE_GENERATOR_INSTANCE:[^=]+=([^\r\n]+)$", cache, re.MULTILINE)
if not match:
raise RuntimeError("Selected Visual Studio installation is missing from CMake cache")
installation = Path(match.group(1))
auxiliary = installation / "VC/Auxiliary/Build"
version = (auxiliary / "Microsoft.VCRedistVersion.default.txt").read_text().strip()
tools_version = (auxiliary / "Microsoft.VCToolsVersion.default.txt").read_text().strip()
if not re.fullmatch(r"\d+\.\d+\.\d+", version) or version.split(".")[:2] != tools_version.split(".")[:2]:
raise RuntimeError("Visual Studio CRT redistributable does not match selected build tools")
cmake_version = [re.search(rf"^CMAKE_CACHE_{part}_VERSION:[^=]+=(\d+)$", cache, re.MULTILINE)
for part in ("MAJOR", "MINOR", "PATCH")]
if all(cmake_version):
compiler_info = build / "CMakeFiles" / ".".join(match.group(1) for match in cmake_version) / "CMakeCXXCompiler.cmake"
if compiler_info.is_file():
compiler = compiler_info.read_text(encoding="utf-8")
actual = re.search(r'set\(CMAKE_CXX_COMPILER_VERSION "(\d+)\.(\d+)\.[^"]+"\)', compiler)
if not actual or (int(actual.group(1)), int(actual.group(2))) != (19, int(version.split(".")[1])):
raise RuntimeError("Visual Studio CRT redistributable does not match actual selected compiler")
source = installation / "VC/Redist/MSVC" / version / "x64/Microsoft.VC143.CRT"
files = [source / name for name in WINDOWS_CRT_FILES]
if any(not path.is_file() or path.is_symlink() for path in files):
raise RuntimeError("Required release Visual Studio CRT redistributable is missing")
destination = build / "Release"
for path in files:
shutil.copy2(path, destination / path.name)
(destination / "MSVC-REDISTRIBUTION.txt").write_text(
"Microsoft Visual C++ release runtime — copyright Microsoft Corporation.\n"
f"Unmodified x64 redistributable files from Visual Studio VC/Redist/MSVC/{version}/x64/Microsoft.VC143.CRT.\n"
"These proprietary files are distributed under Microsoft's applicable Visual Studio license terms, not searchi's license.\n"
"Terms: https://visualstudio.microsoft.com/license-terms/vs2022-ga-diagnosticbuildtools/\n"
"Redistributable list: https://learn.microsoft.com/en-us/visualstudio/releases/2022/redistribution\n"
"Deployment guidance: https://learn.microsoft.com/en-us/cpp/windows/redistributing-visual-cpp-files\n",
encoding="utf-8")
def run(arguments, cwd=None):
subprocess.run([str(value) for value in arguments], cwd=cwd, check=True)
def main():
parser = argparse.ArgumentParser(description="Build Searchi's pinned Google embedding worker")
parser.add_argument("--backend", choices=["cpu", "auto", "metal", "vulkan", "cuda"], default="auto")
parser.add_argument("--jobs", type=int, default=2)
args = parser.parse_args()
if not 1 <= args.jobs <= 16:
parser.error("jobs must be 1–16")
vulkan_loader = None
if os.name == "nt" and args.backend in {"auto", "vulkan"}:
from provision_vulkan import provision
sdk, vulkan_loader = provision()
os.environ["VULKAN_SDK"] = str(sdk)
source = ROOT / ".searchi/references/llama.cpp"
build = ROOT / ".searchi/runtime" / args.backend
if not source.exists():
source.parent.mkdir(parents=True, exist_ok=True)
run(["git", "clone", "--depth", "1", "--branch", TAG,
"https://github.com/ggml-org/llama.cpp.git", source])
actual = subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=source, text=True).strip()
if actual != COMMIT:
raise RuntimeError("Runtime reference checkout differs from pinned commit; refusing to reset it")
patch = Path(__file__).with_name("no-logits.patch")
check = subprocess.run(["git", "apply", "--check", str(patch)], cwd=source, capture_output=True)
if check.returncode == 0:
run(["git", "apply", patch], cwd=source)
else:
reverse = subprocess.run(["git", "apply", "--reverse", "--check", str(patch)], cwd=source, capture_output=True)
if reverse.returncode:
raise RuntimeError("Runtime memory patch cannot be applied or verified")
if os.name == "nt" and args.backend != "cpu":
for patch_name in ["cpu-dispatch.patch", "cpu-only-loader.patch"]:
dispatch_patch = Path(__file__).with_name(patch_name)
check = subprocess.run(["git", "apply", "--check", str(dispatch_patch)], cwd=source, capture_output=True)
if check.returncode == 0:
run(["git", "apply", dispatch_patch], cwd=source)
elif subprocess.run(["git", "apply", "--reverse", "--check", str(dispatch_patch)], cwd=source, capture_output=True).returncode:
raise RuntimeError(f"Runtime patch cannot be applied or verified: {patch_name}")
cmake_exe = shutil.which("cmake")
if not cmake_exe:
try:
import cmake
cmake_exe = str(Path(cmake.CMAKE_BIN_DIR) / ("cmake.exe" if os.name == "nt" else "cmake"))
except ImportError as error:
raise RuntimeError("Install CMake first (python -m pip install cmake)") from error
worker_source = ROOT / "crates/searchi-semantic/native"
run([cmake_exe, "-S", worker_source, "-B", build,
"-DCMAKE_BUILD_TYPE=Release", f"-DLLAMA_CPP_DIR={source}",
f"-DSEARCHI_ACCELERATION={args.backend}"])
run([cmake_exe, "--build", build, "--config", "Release", "--parallel", args.jobs])
if vulkan_loader:
for name in ["vulkan-1.dll", "VULKAN-LICENSE.txt"]:
shutil.copy2(vulkan_loader / name, build / "Release" / name)
if os.name == "nt" and args.backend != "cpu":
directory = build / "Release"
bundle_windows_crt(build)
def checksum(path):
with path.open("rb") as stream:
return hashlib.file_digest(stream, "sha256").hexdigest()
inventory = {"worker_sha256": checksum(directory / "searchi-gemma-worker.exe"),
"libraries": [{"path": path.name, "bytes": path.stat().st_size, "sha256": checksum(path)}
for path in sorted(directory.glob("*.dll"))]}
temporary = directory / "runtime-libraries.json.partial"
temporary.write_text(json.dumps(inventory, indent=2), encoding="utf-8")
os.replace(temporary, directory / "runtime-libraries.json")
print(f"Runtime build complete: {build}")
if __name__ == "__main__":
main()