Files
nixpkgs/pkgs/development/cuda-modules/packages/gdrcopy.nix
Connor Baker d7b4eb14e9 cudaPackages: stop leaking build-time paths into runtime closures
Build systems bake absolute paths into installed artifacts: nvcc
records its own location in the linker command lines it embeds, and
CMake freezes whatever it resolved at configure time into exported
targets. Nix counts any store hash as a reference, so a compiler that
is only ever a nativeBuildInput ends up a runtime dependency.

- gdrcopy: gdrcopy_pplat is the only test built with relocatable
  device code, and nvlink embeds its command line, naming both
  cuda_nvcc and the cudart that supplied cudadevrt. Neither is needed
  at runtime: no binary here has libcudart in DT_NEEDED, and
  libcuda.so.1 comes from the driver. CUDA 13 only; on 13.3 the
  closure drops from 688,439,736 to 61,081,560 bytes, and all seven
  releases now have identical reference sets.

- cudnn-frontend: upstream passes CUDAToolkit_INCLUDE_DIRS to
  target_include_directories as a bare absolute path and never
  forwards the dependency, so consumers inherit a build-machine path
  instead of resolving the toolkit themselves. Confine the path to the
  build and export the dependency, so find_package(CUDAToolkit) runs
  in the consumer's environment. Closure drops from 1,360,621,552 to
  171,758,136 bytes. This is load-bearing rather than cosmetic: on
  CUDA 12 crt/ ships in cuda_nvcc and cuda_runtime_api.h includes it,
  so a consumer using only find_package(cudnn_frontend) previously
  relied on that exported path to compile at all.

- libnvshmem: NVSHMEMEnv.cmake bakes every -D*_HOME into
  NVSHMEM_BUILD_VARS, a diagnostic banner that nvshmem-info and
  init.cu only ever print, and substitutes it into an installed header
  so consumers inherit it too. Strip the dev outputs and nvcc; gdrcopy
  and mpi appear in the same string but are genuine runtime
  dependencies. References drop from 16 to 12.

gdrcopy also gains a disallowedRequisites guard so the leak cannot
return unnoticed. libnvshmem deliberately does not: ucx and openmpi
pull nvcc into its closure independently of the banner, so the guard
would fail for reasons unrelated to this change.

Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 14:55:40 -07:00

133 lines
3.4 KiB
Nix

{
_cuda,
backendStdenv,
cuda_cudart,
cuda_nvcc,
cudaMajorMinorVersion,
cudaNamePrefix,
fetchFromGitHub,
flags,
lib,
removeReferencesTo,
# passthru.updateScript
gitUpdater,
}:
let
inherit (_cuda.lib) _mkMetaBadPlatforms;
inherit (lib) licenses maintainers teams;
in
backendStdenv.mkDerivation (finalAttrs: {
__structuredAttrs = true;
strictDeps = true;
# NOTE: Depends on the CUDA package set, so use cudaNamePrefix.
name = "${cudaNamePrefix}-${finalAttrs.pname}-${finalAttrs.version}";
pname = "gdrcopy";
version = "2.6";
src = fetchFromGitHub {
owner = "NVIDIA";
repo = "gdrcopy";
tag = "v${finalAttrs.version}";
hash = "sha256-Waq/Of0LcLDqyaWaU47lorJcG30CijcdTsvf9nMqgrg=";
};
outputs = [ "out" ];
nativeBuildInputs = [
cuda_nvcc
removeReferencesTo
];
postPatch = ''
nixLog "patching shebang in $PWD/config_arch"
patchShebangs "$PWD/config_arch"
nixLog "patching awk expression in $PWD/Makefile"
substituteInPlace "$PWD/Makefile" \
--replace-fail \
"/\#" \
"/#" \
--replace-fail \
'lib64' \
'lib'
nixLog "patching $PWD/src/Makefile"
substituteInPlace "$PWD/src/Makefile" \
--replace-fail \
"/\#" \
"/#"
nixLog "patching $PWD/tests/Makefile"
substituteInPlace "$PWD/tests/Makefile" \
--replace-fail \
'CUDA_VERSION := $(shell $(GET_CUDA_VERSION) $(NVCC))' \
'CUDA_VERSION := ${cudaMajorMinorVersion}' \
--replace-fail \
'NVCCFLAGS ?= $(shell $(GET_CUDA_GENCODE) $(NVCC)) $(NVCC_STD)' \
'NVCCFLAGS ?= ${flags.gencodeString} $(NVCC_STD)' \
--replace-fail \
'lib64' \
'lib'
'';
enableParallelBuilding = true;
buildInputs = [
cuda_cudart
];
buildFlags = [
# Makefile variables which must be set explicitly
"CUDA=${lib.getLib cuda_cudart}"
"NVCC=${lib.getExe cuda_nvcc}" # TODO: shoud be using cuda_nvcc from pkgsBuildHost
# Make targets
# NOTE: We cannot use `all` because it includes the driver, which needs the driver source code.
"lib"
"exes"
];
# Since CUDA 13, gdrcopy_pplat -- the only test built with relocatable device code -- embeds the
# nvlink command line, naming the store paths of both nvcc and the cudart supplying cudadevrt.
# Neither is needed at runtime: no binary here has libcudart in DT_NEEDED, and libcuda.so.1 comes
# from the driver. Same leak as nccl's; see https://github.com/NixOS/nixpkgs/pull/457803
postFixup = ''
remove-references-to \
-t "${lib.getBin cuda_nvcc}" \
-t "${lib.getLib cuda_cudart}" \
"$out"/bin/*
'';
# C.f. remove-references-to above. Ensure *all* such references are removed.
disallowedRequisites = [
(lib.getBin cuda_nvcc)
(lib.getLib cuda_cudart)
];
# Tests require gdrdrv be installed (don't know how to communicate dependency on the driver).
doCheck = false;
installFlags = [
"DESTDIR=${placeholder "out"}"
"prefix=/"
];
passthru.updateScript = gitUpdater {
inherit (finalAttrs) pname version;
rev-prefix = "v";
};
meta = {
description = "Fast GPU memory copy library based on NVIDIA GPUDirect RDMA technology";
homepage = "https://github.com/NVIDIA/gdrcopy";
license = licenses.mit;
platforms = [
"aarch64-linux"
"x86_64-linux"
];
maintainers = [ maintainers.connorbaker ];
teams = [ teams.cuda ];
};
})