{ lib, stdenv, fetchFromGitHub, cmake, ninja, git, pkg-config, python3, python3Packages, # Boost (filesystem + program_options required by XRT) boost, # OpenCL (headers + ICD loader — XRT uses FindOpenCL) opencl-headers, ocl-icd, # Core system libraries curl, openssl, elfutils, # libelf + libdw libdrm, libuuid, ncurses, libyaml, zlib, # protobuf for XRT's RPC/metadata serialisation protobuf, # provides both the library and the protoc binary # rapidjson (header-only, but XRT finds it via cmake) rapidjson, # systemd for libudev (device enumeration) systemd, # patchelf for post-install fixup patchelf, autoPatchelfHook, # writeTextFile to create the systemtap SDT stub header runCommandLocal, }: # AMD XRT + XDNA Shim — built together from amd/xdna-driver. # # This package produces: # $out/lib/libxrt_coreutil.so — XRT core utility library # $out/lib/libxrt_core.so — XRT platform-independent core # $out/lib/xrt/module/ # libxrt_driver_xdna.so — XDNA NPU shim plugin # $out/include/xrt/ — Public C++ headers # $out/include/experimental/ # $out/bin/xrt-smi — System management tool # # Build strategy # ============== # amd/xdna-driver is the canonical build system for the XDNA stack. # It brings in Xilinx/XRT as a submodule and builds it with XRT_NPU=1, # excluding PCIe/Alveo/edge components. Then it builds the XDNA shim # (src/shim/) which links against libxrt_core + libxrt_coreutil. # # XRT itself has several required submodules that must be injected: # src/runtime_src/core/common/aiebu — AIE binary utilities (NPU required) # src/runtime_src/xdp — XRT Data Platform (profiling) # src/runtime_src/core/common/elf — ELFIO header library # src/runtime_src/core/common/gsl — Microsoft GSL headers # src/runtime_src/aie-rt — AIE runtime # aiebu itself has sub-submodules (aie-rt, ELFIO, cxxopts). # # We build with -DSKIP_KMOD=1 so the kernel module (amdxdna.ko) is # NOT compiled here — it ships in-tree since Linux 6.14. # # To update # ========= # 1. Pin xdnaRev to the desired amd/xdna-driver commit. # 2. Update xdnaHash: nix-prefetch-git --url .../xdna-driver --rev # 3. Confirm the xrt submodule ref: # curl -s "https://api.github.com/repos/amd/xdna-driver/contents/xrt?ref=" \ # | python3 -c "import sys,json; print(json.load(sys.stdin)['sha'])" # 4. For each changed submodule, update the corresponding fetchFromGitHub below # and re-run nix-prefetch-git to get the new hash. let # amd/xdna-driver — driver + shim build system xdnaRev = "66fd7aef0fe53b1b712141047326ea767488e2e9"; # Xilinx/XRT submodule commit pinned by the xdnaRev above xrtRev = "481583db9a26cb506a37cab7f1881ae7c7de2f32"; # XRT version strings — must match what settings.cmake sets for xrtRev xrtVersionMajor = "2"; xrtVersionMinor = "23"; xrtVersionPatch = "0"; xrtVersion = "${xrtVersionMajor}.${xrtVersionMinor}.${xrtVersionPatch}"; # ── SystemTap SDT stub ──────────────────────────────────────────────────── # XRT unconditionally includes for DTrace/SystemTap tracing # probes. Nixpkgs does not package systemtap-sdt-dev as a standalone # header package. We provide a minimal stub that satisfies the include # without pulling in any runtime tracing infrastructure. systemtap-sdt-stub = runCommandLocal "systemtap-sdt-stub" { } '' mkdir -p "$out/include/sys" cat > "$out/include/sys/sdt.h" << 'EOF' /* Minimal SystemTap SDT stub for building XRT on NixOS. * All probe macros expand to nothing — tracing is disabled at compile time. */ #pragma once #ifndef _SYS_SDT_H #define _SYS_SDT_H #define STAP_PROBEV(provider, name, ...) do {} while (0) #define DTRACE_PROBE(provider, name) do {} while (0) #define DTRACE_PROBE1(provider, name, a1) do {} while (0) #define DTRACE_PROBE2(p, n, a1, a2) do {} while (0) #define DTRACE_PROBE3(p, n, a1, a2, a3) do {} while (0) #define DTRACE_PROBE4(p, n, a1, a2, a3, a4) do {} while (0) #define DTRACE_PROBE5(p, n, a1, a2, a3, a4, a5) do {} while (0) #endif /* _SYS_SDT_H */ EOF ''; # ── XRT source ──────────────────────────────────────────────────────────── xrt-src = fetchFromGitHub { owner = "Xilinx"; repo = "XRT"; rev = xrtRev; hash = "sha256-WLZDjuuEGd3i77zXpAJkfQy/AszdSQ9pagy64yGX58Q="; fetchSubmodules = false; # We inject all submodules manually below }; # ── XRT submodules (fetched individually, injected in preConfigure) ─────── # AIE binary utilities — required for NPU support xrt-aiebu = fetchFromGitHub { owner = "Xilinx"; repo = "aiebu"; rev = "fb62863a0f3d8eaf79b88231603f9d464d0afc24"; hash = "sha256-iKnT/U2T1Q9WGMpTLtJGZZg2OLalhXaHOo9ZdEGznoM="; fetchSubmodules = false; # aiebu sub-submodules injected separately }; # XRT Data Platform (performance profiling infrastructure) xrt-xdp = fetchFromGitHub { owner = "Xilinx"; repo = "XDP"; rev = "a868510682074c5a52ca100bb33dbf2e39ea9e9b"; hash = "sha256-DTIPK+/ShX7xZerMBMU5rxIXjwVx2yViGwNa9qhN5TM="; }; # ELFIO — C++ ELF reader/writer (used by XRT core) xrt-elfio = fetchFromGitHub { owner = "serge1"; repo = "ELFIO"; rev = "f849001fc229c2598f8557e0df22866af194ef98"; hash = "sha256-/H+ajhOx6q4cHatJUMhJP2DPrWNtm+qlfNfDXbBjOEw="; }; # Microsoft GSL — Guidelines Support Library headers xrt-gsl = fetchFromGitHub { owner = "microsoft"; repo = "GSL"; rev = "a3534567187d2edc428efd3f13466ff75fe5805c"; hash = "sha256-cXDFqt2KgMFGfdh6NGE+JmP4R0Wm9LNHM0eIblYe6zU="; }; # AIE runtime — pinned by XRT directly xrt-aie-rt = fetchFromGitHub { owner = "Xilinx"; repo = "aie-rt"; rev = "a8b0667133ea2851ce27793a1796c5968226d9af"; hash = "sha256-VZxFpc60O5LXuVJ5AajDUtGrfXU+NIlyY+M87EHkIac="; }; # ── aiebu sub-submodules ────────────────────────────────────────────────── # AIE runtime version pinned by aiebu (may differ from xrt-aie-rt above) aiebu-aie-rt = fetchFromGitHub { owner = "Xilinx"; repo = "aie-rt"; rev = "8849e208bdcc533b20a0ed3f95c1ce961dee9c3a"; hash = "sha256-CiczNOcjsRd+163gRqGpjNW9ap/6ntHNV8ImkLssWts="; }; # ELFIO version pinned by aiebu aiebu-elfio = fetchFromGitHub { owner = "serge1"; repo = "ELFIO"; rev = "182248f364e6375eaad30cefdd6b67660abaa3b3"; hash = "sha256-wg4Sed3xKJIkc0F3qOQzLdo0rL/so1fpa6nS9rpzB/Q="; }; # cxxopts — command-line option parser used by aiebu tools aiebu-cxxopts = fetchFromGitHub { owner = "jarro2783"; repo = "cxxopts"; rev = "10a7a647791fa3a24ec4f572f2573a6e0aaa881b"; hash = "sha256-QrqNe2XICY+Ej0A01XIoigIpv/YOh07cV/PGeYyIgMA="; }; in stdenv.mkDerivation rec { pname = "xrt"; version = xrtVersion; src = fetchFromGitHub { owner = "amd"; repo = "xdna-driver"; rev = xdnaRev; hash = "sha256-oOp1MiscLez6yxT59Aw/ZeO9JXuB8pz1fm6b64IgM3E="; fetchSubmodules = false; # We inject xrt manually below }; nativeBuildInputs = [ cmake ninja git pkg-config python3 python3Packages.pybind11 autoPatchelfHook patchelf protobuf # provides protoc binary ]; buildInputs = [ boost opencl-headers ocl-icd curl openssl elfutils libdrm libuuid ncurses libyaml zlib protobuf rapidjson systemd # libudev systemtap-sdt-stub # sys/sdt.h — stub header for XRT tracing probes ]; preConfigure = '' # ── 1. Inject the XRT submodule ──────────────────────────────────────── cp -r --no-preserve=mode,ownership "${xrt-src}/." xrt/ # Make xrt/ look like a git repo so find_package(Git) and any git # invocations inside the build don't escape the sandbox. git init xrt git -C xrt config user.email "nix@build" git -C xrt config user.name "Nix Build" git -C xrt add -A git -C xrt commit -m "xrt source" --allow-empty # ── 2. Inject XRT's required submodules ──────────────────────────────── # These are all needed for the NPU (XRT_NPU=1) build path. cp -r --no-preserve=mode,ownership "${xrt-aiebu}/." \ xrt/src/runtime_src/core/common/aiebu/ cp -r --no-preserve=mode,ownership "${xrt-xdp}/." \ xrt/src/runtime_src/xdp/ cp -r --no-preserve=mode,ownership "${xrt-elfio}/." \ xrt/src/runtime_src/core/common/elf/ cp -r --no-preserve=mode,ownership "${xrt-gsl}/." \ xrt/src/runtime_src/core/common/gsl/ cp -r --no-preserve=mode,ownership "${xrt-aie-rt}/." \ xrt/src/runtime_src/aie-rt/ # ── 3. Inject aiebu's own sub-submodules ─────────────────────────────── cp -r --no-preserve=mode,ownership "${aiebu-aie-rt}/." \ xrt/src/runtime_src/core/common/aiebu/lib/aie-rt/ cp -r --no-preserve=mode,ownership "${aiebu-elfio}/." \ xrt/src/runtime_src/core/common/aiebu/src/cpp/ELFIO/ cp -r --no-preserve=mode,ownership "${aiebu-cxxopts}/." \ xrt/src/runtime_src/core/common/aiebu/src/cpp/cxxopts/ # ── 4. Patch hardcoded /bins path ────────────────────────────────────── # CMakeLists.txt line 30 uses plain set(XDNA_BIN_DIR /bins) which shadows # any -D cache variable we pass. Rewrite it to use CMAKE_INSTALL_PREFIX # so the secondary "quick testing" install lands inside $out. substituteInPlace CMakeLists.txt \ --replace-fail \ 'set(XDNA_BIN_DIR /bins)' \ 'set(XDNA_BIN_DIR ''${CMAKE_INSTALL_PREFIX})' # ── 5. Patch pkg.cmake to handle NixOS ───────────────────────────────── # pkg.cmake reads /etc/os-release at configure-time and issues a # FATAL_ERROR for unrecognised distros (which includes NixOS). # CPack is never invoked in a Nix build — only cmake --install runs. python3 << 'PYEOF' import re, pathlib p = pathlib.Path('CMake/pkg.cmake') txt = p.read_text() txt = re.sub( r'else\(\)\s*message\(FATAL_ERROR.*?endif\(\)', 'else()\n' ' message(STATUS "Unrecognised distro, falling back to DEB CPack generator (NixOS build).")\n' ' set(CPACK_GENERATOR "DEB")\n' ' set(CPACK_DEB_COMPONENT_INSTALL ON)\n' ' set(CPACK_DEBIAN_PACKAGE_DEPENDS "")\n' 'endif()', txt, flags=re.DOTALL ) p.write_text(txt) print('CMake/pkg.cmake patched') PYEOF ''; cmakeFlags = [ "-DCMAKE_BUILD_TYPE=Release" "-DCMAKE_INSTALL_PREFIX=${placeholder "out"}" "-DCMAKE_INSTALL_LIBDIR=lib" "-DSKIP_KMOD=1" "-DBUILD_VXDNA=OFF" "-DXRT_UPSTREAM_DEBIAN=1" "-DXRT_VERSION_MAJOR=${xrtVersionMajor}" "-DXRT_VERSION_MINOR=${xrtVersionMinor}" "-DXRT_VERSION_PATCH=${xrtVersionPatch}" "-DXRT_BUILD_NUMBER=${xrtVersionPatch}" "-DXRT_ENABLE_WERROR=OFF" "-DOpenCL_INCLUDE_DIR=${opencl-headers}/include" "-DOpenCL_LIBRARY=${ocl-icd}/lib/libOpenCL.so" ]; installPhase = '' runHook preInstall # Install the xdna shim + XRT libs (the normal install target). cmake --install . --prefix "$out" # XRT is built EXCLUDE_FROM_ALL so its header install rules are not in # the default install. The component-based install (--component xrt_base_dev) # embeds the absolute build-dir path in the destination and produces the # wrong layout (headers go to $out/nix/store/$out/include/ instead of # $out/include/). # # Instead, copy the headers directly from the XRT source tree — the public # API surface is fully captured in src/runtime_src/core/include/. mkdir -p "$out/include" cp -r --no-preserve=mode,ownership \ xrt/src/runtime_src/core/include/. \ "$out/include/" # Also install the generated version headers from the build directory. if [ -d "xrt/src/gen" ]; then cp -r --no-preserve=mode,ownership xrt/src/gen/. "$out/include/" fi runHook postInstall ''; postFixup = '' rpath="${lib.makeLibraryPath buildInputs}:$out/lib" for so in "$out/lib/xrt/module"/*.so; do [ -f "$so" ] && patchelf --set-rpath "$rpath" "$so" 2>/dev/null || true done for so in "$out/lib"/*.so "$out/lib"/*.so.*; do [ -f "$so" ] && patchelf --set-rpath "$rpath" "$so" 2>/dev/null || true done for bin in "$out/bin"/*; do [ -f "$bin" ] && patchelf --set-rpath "$rpath" "$bin" 2>/dev/null || true done rm -f "$out"/setup.sh "$out"/setup.csh 2>/dev/null || true ''; meta = with lib; { description = "AMD XRT runtime and XDNA NPU shim for Ryzen AI NPUs"; longDescription = '' AMD XRT (Xilinx Runtime) is the userspace runtime for AMD XDNA 2 NPU devices (Ryzen AI — Strix Point, Strix Halo, Kraken Point, Gorgon Point). This package builds the XRT base libraries (libxrt_coreutil, libxrt_core) together with the XDNA shim plugin (libxrt_driver_xdna) from the amd/xdna-driver repository. The kernel driver (amdxdna.ko) ships in-tree since Linux 6.14 and is available for older kernels via a DKMS package. NPU firmware is provided by the linux-firmware package (version >= 20260221 required). Usage: xrt-smi validate — validate the NPU setup end-to-end xrt-smi examine — query the NPU device ''; homepage = "https://github.com/amd/xdna-driver"; license = licenses.asl20; platforms = [ "x86_64-linux" ]; maintainers = [ ]; }; }