diff --git a/pkgs/development/cuda-modules/aliases.nix b/pkgs/development/cuda-modules/aliases.nix index 36dd07d773bd9..bb260b798b69d 100644 --- a/pkgs/development/cuda-modules/aliases.nix +++ b/pkgs/development/cuda-modules/aliases.nix @@ -6,7 +6,6 @@ let final.lib.warn "cudaPackages.${oldName} is deprecated, use ${newName} instead" newPkg; in { - # Deprecated: an alias kept for compatibility. Consider removing after 24.05 autoFixElfFiles = mkRenamed "autoFixElfFiles" "pkgs.autoFixElfFiles" final.pkgs.autoFixElfFiles; # Added 2024-03-30 autoAddDriverRunpath = @@ -15,4 +14,8 @@ in autoAddOpenGLRunpathHook = mkRenamed "autoAddOpenGLRunpathHook" "pkgs.autoAddDriverRunpath" final.pkgs.autoAddDriverRunpath; # Added 2024-03-30 + markForCudatoolkitRootHook = + mkRenamed "markForCudatoolkitRootHook" "cudaPackages.markForCudatoolkitRoot" + final.markForCudatoolkitRoot; # Added 2024-04-19 + setupCudaHook = mkRenamed "setupCudaHook" "cudaPackages.setupCuda" final.setupCuda; # Added 2024-04-19 } diff --git a/pkgs/development/cuda-modules/cuda/overrides.nix b/pkgs/development/cuda-modules/cuda/overrides.nix index 5d23d8f7f2a1a..7be87ba808e34 100644 --- a/pkgs/development/cuda-modules/cuda/overrides.nix +++ b/pkgs/development/cuda-modules/cuda/overrides.nix @@ -170,7 +170,7 @@ filterAndCreateOverrides { backendStdenv, cuda_cudart, lib, - setupCudaHook, + setupCuda, }: prevAttrs: { # Patch the nvcc.profile. @@ -214,7 +214,7 @@ filterAndCreateOverrides { # `propagatedNativeBuildInputs`, it stops being propagated to downstream packages during their build because # setup hooks in `propagatedNativeBuildInputs` are not designed to affect the runtime or build environment of # dependencies; they are only meant to affect the build environment of the package that directly includes them. - propagatedBuildInputs = (prevAttrs.propagatedBuildInputs or [ ]) ++ [ setupCudaHook ]; + propagatedBuildInputs = (prevAttrs.propagatedBuildInputs or [ ]) ++ [ setupCuda ]; postInstall = (prevAttrs.postInstall or "") diff --git a/pkgs/development/cuda-modules/cudatoolkit/default.nix b/pkgs/development/cuda-modules/cudatoolkit/default.nix index e5606f9395129..a9689d347cd29 100644 --- a/pkgs/development/cuda-modules/cudatoolkit/default.nix +++ b/pkgs/development/cuda-modules/cudatoolkit/default.nix @@ -20,7 +20,7 @@ libkrb5, krb5, makeWrapper, - markForCudatoolkitRootHook, + markForCudatoolkitRoot, ncurses5, numactl, nss, @@ -28,7 +28,7 @@ perl, python3, # FIXME: CUDAToolkit 10 may still need python27 pulseaudio, - setupCudaHook, + setupCuda, stdenv, backendStdenv, # E.g. gcc11Stdenv, set in extension.nix unixODBC, @@ -77,11 +77,11 @@ backendStdenv.mkDerivation rec { addOpenGLRunpath autoPatchelfHook autoAddDriverRunpath - markForCudatoolkitRootHook + markForCudatoolkitRoot ] ++ lib.optionals (lib.versionOlder version "11") [ libsForQt5.wrapQtAppsHook ] ++ lib.optionals (lib.versionAtLeast version "11.8") [ qt6Packages.wrapQtAppsHook ]; - propagatedBuildInputs = [ setupCudaHook ]; + propagatedBuildInputs = [ setupCuda ]; buildInputs = lib.optionals (lib.versionOlder version "11") [ libsForQt5.qt5.qtwebengine diff --git a/pkgs/development/cuda-modules/generic-builders/manifest.nix b/pkgs/development/cuda-modules/generic-builders/manifest.nix index 006abb456cdc5..0af4be9c7adb9 100644 --- a/pkgs/development/cuda-modules/generic-builders/manifest.nix +++ b/pkgs/development/cuda-modules/generic-builders/manifest.nix @@ -7,7 +7,7 @@ fetchurl, lib, lndir, - markForCudatoolkitRootHook, + markForCudatoolkitRoot, flags, stdenv, # Builder-specific arguments @@ -200,7 +200,7 @@ backendStdenv.mkDerivation (finalAttrs: { # directory to the rpath of all ELF binaries. # Check e.g. with `patchelf --print-rpath path/to/my/binary autoAddDriverRunpath - markForCudatoolkitRootHook + markForCudatoolkitRoot ] # autoAddCudaCompatRunpath depends on cuda_compat and would cause # infinite recursion if applied to `cuda_compat` itself (beside the fact diff --git a/pkgs/development/cuda-modules/saxpy/default.nix b/pkgs/development/cuda-modules/saxpy/default.nix index a36cec3e692b3..6c682722d05c8 100644 --- a/pkgs/development/cuda-modules/saxpy/default.nix +++ b/pkgs/development/cuda-modules/saxpy/default.nix @@ -15,7 +15,6 @@ let cudatoolkit flags libcublas - setupCudaHook ; inherit (lib) getDev getLib getOutput; in diff --git a/pkgs/development/cuda-modules/setup-hooks/auto-add-cuda-compat-runpath.sh b/pkgs/development/cuda-modules/setup-hooks/auto-add-cuda-compat-runpath/auto-add-cuda-compat-runpath.sh similarity index 100% rename from pkgs/development/cuda-modules/setup-hooks/auto-add-cuda-compat-runpath.sh rename to pkgs/development/cuda-modules/setup-hooks/auto-add-cuda-compat-runpath/auto-add-cuda-compat-runpath.sh diff --git a/pkgs/development/cuda-modules/setup-hooks/auto-add-cuda-compat-runpath/default.nix b/pkgs/development/cuda-modules/setup-hooks/auto-add-cuda-compat-runpath/default.nix new file mode 100644 index 0000000000000..d25fc5da53c5f --- /dev/null +++ b/pkgs/development/cuda-modules/setup-hooks/auto-add-cuda-compat-runpath/default.nix @@ -0,0 +1,22 @@ +# autoAddCudaCompatRunpath hook must be added AFTER `setupCuda`. Both +# hooks prepend a path with `libcuda.so` to the `DT_RUNPATH` section of +# patched elf files, but `cuda_compat` path must take precedence (otherwise, +# it doesn't have any effect) and thus appear first. Meaning this hook must be +# executed last. +{ + autoFixElfFiles, + cuda_compat ? null, + flags, + lib, + makeSetupHook, +}: +makeSetupHook { + name = "auto-add-cuda-compat-runpath-hook"; + propagatedBuildInputs = [ autoFixElfFiles ]; + substitutions.libcudaPath = lib.optionalString flags.isJetsonBuild "${cuda_compat}/compat"; + meta = { + broken = !flags.isJetsonBuild; + badPlatforms = lib.optionals (cuda_compat == null) lib.platforms.all; + platforms = cuda_compat.meta.platforms or [ ]; + }; +} ./auto-add-cuda-compat-runpath.sh diff --git a/pkgs/development/cuda-modules/setup-hooks/extension.nix b/pkgs/development/cuda-modules/setup-hooks/extension.nix index 327f335f1890f..a3e8ae02ce8eb 100644 --- a/pkgs/development/cuda-modules/setup-hooks/extension.nix +++ b/pkgs/development/cuda-modules/setup-hooks/extension.nix @@ -1,55 +1,5 @@ final: _: { - # Internal hook, used by cudatoolkit and cuda redist packages - # to accommodate automatic CUDAToolkit_ROOT construction - markForCudatoolkitRootHook = final.callPackage ( - { makeSetupHook }: - makeSetupHook { name = "mark-for-cudatoolkit-root-hook"; } ./mark-for-cudatoolkit-root-hook.sh - ) { }; - - # Currently propagated by cuda_nvcc or cudatoolkit, rather than used directly - setupCudaHook = ( - final.callPackage ( - { makeSetupHook, backendStdenv }: - makeSetupHook { - name = "setup-cuda-hook"; - - substitutions.setupCudaHook = placeholder "out"; - - # Point NVCC at a compatible compiler - substitutions.ccRoot = "${backendStdenv.cc}"; - - # Required in addition to ccRoot as otherwise bin/gcc is looked up - # when building CMakeCUDACompilerId.cu - substitutions.ccFullPath = "${backendStdenv.cc}/bin/${backendStdenv.cc.targetPrefix}c++"; - } ./setup-cuda-hook.sh - ) { } - ); - - # autoAddCudaCompatRunpath hook must be added AFTER `setupCudaHook`. Both - # hooks prepend a path with `libcuda.so` to the `DT_RUNPATH` section of - # patched elf files, but `cuda_compat` path must take precedence (otherwise, - # it doesn't have any effect) and thus appear first. Meaning this hook must be - # executed last. - autoAddCudaCompatRunpath = final.callPackage ( - { - makeSetupHook, - autoFixElfFiles, - cuda_compat ? null, - }: - makeSetupHook { - name = "auto-add-cuda-compat-runpath-hook"; - propagatedBuildInputs = [ autoFixElfFiles ]; - - substitutions = { - # Hotfix Ofborg evaluation - libcudaPath = if final.flags.isJetsonBuild then "${cuda_compat}/compat" else null; - }; - - meta.broken = !final.flags.isJetsonBuild; - - # Pre-cuda_compat CUDA release: - meta.badPlatforms = final.lib.optionals (cuda_compat == null) final.lib.platforms.all; - meta.platforms = cuda_compat.meta.platforms or [ ]; - } ./auto-add-cuda-compat-runpath.sh - ) { }; + autoAddCudaCompatRunpath = final.callPackage ./auto-add-cuda-compat-runpath { }; + markForCudatoolkitRoot = final.callPackage ./mark-for-cudatoolkit-root { }; + setupCuda = final.callPackage ./setup-cuda { }; } diff --git a/pkgs/development/cuda-modules/setup-hooks/mark-for-cudatoolkit-root-hook.sh b/pkgs/development/cuda-modules/setup-hooks/mark-for-cudatoolkit-root-hook.sh deleted file mode 100644 index 0abd651005c66..0000000000000 --- a/pkgs/development/cuda-modules/setup-hooks/mark-for-cudatoolkit-root-hook.sh +++ /dev/null @@ -1,25 +0,0 @@ -# shellcheck shell=bash - -(( ${hostOffset:?} == -1 && ${targetOffset:?} == 0)) || return 0 - -echo "Sourcing mark-for-cudatoolkit-root-hook" >&2 - -markForCUDAToolkit_ROOT() { - mkdir -p "${prefix:?}/nix-support" - local markerPath="$prefix/nix-support/include-in-cudatoolkit-root" - - # Return early if the file already exists. - [[ -f "$markerPath" ]] && return 0 - - # Always create the file, even if it's empty, since setup-cuda-hook relies on its existence. - # However, only populate it if strictDeps is not set. - touch "$markerPath" - - # Return early if strictDeps is set. - [[ -n "${strictDeps-}" ]] && return 0 - - # Populate the file with the package name and output. - echo "${pname:?}-${output:?}" > "$markerPath" -} - -fixupOutputHooks+=(markForCUDAToolkit_ROOT) diff --git a/pkgs/development/cuda-modules/setup-hooks/mark-for-cudatoolkit-root/default.nix b/pkgs/development/cuda-modules/setup-hooks/mark-for-cudatoolkit-root/default.nix new file mode 100644 index 0000000000000..6ca396c013009 --- /dev/null +++ b/pkgs/development/cuda-modules/setup-hooks/mark-for-cudatoolkit-root/default.nix @@ -0,0 +1,7 @@ +# Internal hook, used by cudatoolkit and cuda redist packages +# to accommodate automatic CUDAToolkit_ROOT construction +{ makeSetupHook }: +makeSetupHook { + name = "mark-for-cudatoolkit-root"; + substitutions.logFromSetupHook = ../utilities/log-from-setup-hook.sh; +} ./mark-for-cudatoolkit-root.sh diff --git a/pkgs/development/cuda-modules/setup-hooks/mark-for-cudatoolkit-root/mark-for-cudatoolkit-root.sh b/pkgs/development/cuda-modules/setup-hooks/mark-for-cudatoolkit-root/mark-for-cudatoolkit-root.sh new file mode 100644 index 0000000000000..a08c8be823001 --- /dev/null +++ b/pkgs/development/cuda-modules/setup-hooks/mark-for-cudatoolkit-root/mark-for-cudatoolkit-root.sh @@ -0,0 +1,64 @@ +# shellcheck shell=bash + +# shellcheck disable=SC1091 +source "@logFromSetupHook@" + +# Guard helper function +# Returns 0 (success) if the hook should be run, 1 (failure) otherwise. +# This allows us to use short-circuit evaluation to avoid running the hook when it shouldn't be. +markForCUDAToolkit_ROOTGuard() { + log() { + logFromSetupHook \ + "${1:?}" \ + "mark-for-cudatoolkit-root" \ + "markForCUDAToolkit_ROOTGuard" \ + "${2:?}" + } + local guard="Skipping" + local reason="" + + # This hook is meant only to add a stub file to the nix-support directory of the package including it in its + # nativeBuildInputs, so that the setup hook propagated by cuda_nvcc, setup-cuda, can detect it and add the + # package to the CUDA toolkit root. Therefore, since it only modifies the package being built and will not be + # propagated, it should only ever be included in nativeBuildInputs. + if (( ${hostOffset:?} == -1 && ${targetOffset:?} == 0)); then + guard="Sourcing" + reason="because the hook is in nativeBuildInputs relative to the package being built" + fi + + log "INFO" "$guard $reason" + + # Recall that test commands return 0 for success and 1 for failure. + [[ "$guard" == Sourcing ]] + return $? +} + +# Guard against calling the hook at the wrong time. +markForCUDAToolkit_ROOTGuard || return 0 + +markForCUDAToolkit_ROOT() { + log() { + logFromSetupHook \ + "${1:?}" \ + "mark-for-cudatoolkit-root" \ + "markForCUDAToolkit_ROOT" \ + "${2:?}" + } + log "INFO" "Running on ${prefix:?}" + + local markerPath="$prefix/nix-support/include-in-cudatoolkit-root" + mkdir -p "$(dirname "$markerPath")" + if [[ -f "$markerPath" ]]; then + log "DEBUG" "$markerPath exists, skipping" + return 0 + fi + + # Always create the file, even if it's empty, since setup-cuda relies on its existence. + # However, only populate it if strictDeps is not set. + touch "$markerPath" + if [[ -z "${strictDeps-}" ]]; then + log "DEBUG" "Populating $markerPath" + echo "${pname:?}-${output:?}" > "$markerPath" + fi +} +fixupOutputHooks+=(markForCUDAToolkit_ROOT) diff --git a/pkgs/development/cuda-modules/setup-hooks/setup-cuda-hook.sh b/pkgs/development/cuda-modules/setup-hooks/setup-cuda-hook.sh deleted file mode 100644 index 6e57c7b1072e1..0000000000000 --- a/pkgs/development/cuda-modules/setup-hooks/setup-cuda-hook.sh +++ /dev/null @@ -1,122 +0,0 @@ -# shellcheck shell=bash - -# Only run the hook from nativeBuildInputs -(( "$hostOffset" == -1 && "$targetOffset" == 0)) || return 0 - -guard=Sourcing -reason= - -[[ -n ${cudaSetupHookOnce-} ]] && guard=Skipping && reason=" because the hook has been propagated more than once" - -if (( "${NIX_DEBUG:-0}" >= 1 )) ; then - echo "$guard hostOffset=$hostOffset targetOffset=$targetOffset setup-cuda-hook$reason" >&2 -else - echo "$guard setup-cuda-hook$reason" >&2 -fi - -[[ "$guard" = Sourcing ]] || return 0 - -declare -g cudaSetupHookOnce=1 -declare -Ag cudaHostPathsSeen=() -declare -Ag cudaOutputToPath=() - -extendcudaHostPathsSeen() { - (( "${NIX_DEBUG:-0}" >= 1 )) && echo "extendcudaHostPathsSeen $1" >&2 - - local markerPath="$1/nix-support/include-in-cudatoolkit-root" - [[ ! -f "${markerPath}" ]] && return 0 - [[ -v cudaHostPathsSeen[$1] ]] && return 0 - - cudaHostPathsSeen["$1"]=1 - - # E.g. cuda_cudart-lib - local cudaOutputName - # Fail gracefully if the file is empty. - # One reason the file may be empty: the package was built with strictDeps set, but the current build does not have - # strictDeps set. - read -r cudaOutputName < "$markerPath" || return 0 - - [[ -z "$cudaOutputName" ]] && return 0 - - local oldPath="${cudaOutputToPath[$cudaOutputName]-}" - [[ -n "$oldPath" ]] && echo "extendcudaHostPathsSeen: warning: overwriting $cudaOutputName from $oldPath to $1" >&2 - cudaOutputToPath["$cudaOutputName"]="$1" -} -addEnvHooks "$targetOffset" extendcudaHostPathsSeen - -setupCUDAToolkit_ROOT() { - (( "${NIX_DEBUG:-0}" >= 1 )) && echo "setupCUDAToolkit_ROOT: cudaHostPathsSeen=${!cudaHostPathsSeen[*]}" >&2 - - for path in "${!cudaHostPathsSeen[@]}" ; do - addToSearchPathWithCustomDelimiter ";" CUDAToolkit_ROOT "$path" - if [[ -d "$path/include" ]] ; then - addToSearchPathWithCustomDelimiter ";" CUDAToolkit_INCLUDE_DIR "$path/include" - fi - done - - export cmakeFlags+=" -DCUDAToolkit_INCLUDE_DIR=$CUDAToolkit_INCLUDE_DIR -DCUDAToolkit_ROOT=$CUDAToolkit_ROOT" -} -preConfigureHooks+=(setupCUDAToolkit_ROOT) - -setupCUDAToolkitCompilers() { - echo Executing setupCUDAToolkitCompilers >&2 - - if [[ -n "${dontSetupCUDAToolkitCompilers-}" ]] ; then - return 0 - fi - - # Point NVCC at a compatible compiler - - # For CMake-based projects: - # https://cmake.org/cmake/help/latest/module/FindCUDA.html#input-variables - # https://cmake.org/cmake/help/latest/envvar/CUDAHOSTCXX.html - # https://cmake.org/cmake/help/latest/variable/CMAKE_CUDA_HOST_COMPILER.html - - export cmakeFlags+=" -DCUDA_HOST_COMPILER=@ccFullPath@" - export cmakeFlags+=" -DCMAKE_CUDA_HOST_COMPILER=@ccFullPath@" - - # For non-CMake projects: - # We prepend --compiler-bindir to nvcc flags. - # Downstream packages can override these, because NVCC - # uses the last --compiler-bindir it gets on the command line. - # FIXME: this results in "incompatible redefinition" warnings. - # https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html#compiler-bindir-directory-ccbin - if [ -z "${CUDAHOSTCXX-}" ]; then - export CUDAHOSTCXX="@ccFullPath@"; - fi - - export NVCC_PREPEND_FLAGS+=" --compiler-bindir=@ccRoot@/bin" - - # NOTE: We set -Xfatbin=-compress-all, which reduces the size of the compiled - # binaries. If binaries grow over 2GB, they will fail to link. This is a problem for us, as - # the default set of CUDA capabilities we build can regularly cause this to occur (for - # example, with Magma). - # - # @SomeoneSerge: original comment was made by @ConnorBaker in .../cudatoolkit/common.nix - if [[ -z "${dontCompressFatbin-}" ]]; then - export NVCC_PREPEND_FLAGS+=" -Xfatbin=-compress-all" - fi -} -preConfigureHooks+=(setupCUDAToolkitCompilers) - -propagateCudaLibraries() { - (( "${NIX_DEBUG:-0}" >= 1 )) && echo "propagateCudaLibraries: cudaPropagateToOutput=$cudaPropagateToOutput cudaHostPathsSeen=${!cudaHostPathsSeen[*]}" >&2 - - [[ -z "${cudaPropagateToOutput-}" ]] && return 0 - - mkdir -p "${!cudaPropagateToOutput}/nix-support" - # One'd expect this should be propagated-bulid-build-deps, but that doesn't seem to work - echo "@setupCudaHook@" >> "${!cudaPropagateToOutput}/nix-support/propagated-native-build-inputs" - - local propagatedBuildInputs=( "${!cudaHostPathsSeen[@]}" ) - for output in $(getAllOutputNames) ; do - if [[ ! "$output" = "$cudaPropagateToOutput" ]] ; then - propagatedBuildInputs+=( "${!output}" ) - fi - break - done - - # One'd expect this should be propagated-host-host-deps, but that doesn't seem to work - printWords "${propagatedBuildInputs[@]}" >> "${!cudaPropagateToOutput}/nix-support/propagated-build-inputs" -} -postFixupHooks+=(propagateCudaLibraries) diff --git a/pkgs/development/cuda-modules/setup-hooks/setup-cuda/default.nix b/pkgs/development/cuda-modules/setup-hooks/setup-cuda/default.nix new file mode 100644 index 0000000000000..259595ca80fda --- /dev/null +++ b/pkgs/development/cuda-modules/setup-hooks/setup-cuda/default.nix @@ -0,0 +1,17 @@ +# Currently propagated by cuda_nvcc or cudatoolkit, rather than used directly +{ backendStdenv, makeSetupHook }: +let + inherit (backendStdenv) cc; +in +makeSetupHook { + name = "setup-cuda"; + substitutions = { + # Required in addition to ccRoot as otherwise bin/gcc is looked up + # when building CMakeCUDACompilerId.cu + ccFullPath = "${cc}/bin/${cc.targetPrefix}c++"; + # Point NVCC at a compatible compiler + ccRoot = "${cc}"; + logFromSetupHook = ../utilities/log-from-setup-hook.sh; + setupCuda = placeholder "out"; + }; +} ./setup-cuda.sh diff --git a/pkgs/development/cuda-modules/setup-hooks/setup-cuda/setup-cuda.sh b/pkgs/development/cuda-modules/setup-hooks/setup-cuda/setup-cuda.sh new file mode 100644 index 0000000000000..0bfa7791e6b55 --- /dev/null +++ b/pkgs/development/cuda-modules/setup-hooks/setup-cuda/setup-cuda.sh @@ -0,0 +1,192 @@ +# shellcheck shell=bash + +# shellcheck disable=SC1091 +source "@logFromSetupHook@" + +# Guard helper function +# Returns 0 (success) if the hook should be run, 1 (failure) otherwise. +# This allows us to use short-circuit evaluation to avoid running the hook when it shouldn't be. +setupCudaGuard() { + log() { + logFromSetupHook \ + "${1:?}" \ + "setup-cuda" \ + "setupCudaGuard" \ + "${2:?}" + } + local guard="Skipping" + local reason="" + + if (( ${hostOffset:?} == -1 && ${targetOffset:?} == 0)); then + guard="Sourcing" + reason="because the hook is in nativeBuildInputs relative to the package being built" + elif [[ -n "${cudaSetupOnce-}" ]]; then + guard=Skipping + reason="because the hook has been propagated more than once" + fi + + log "INFO" "$guard $reason" + + # Recall that test commands return 0 for success and 1 for failure. + [[ "$guard" == Sourcing ]] + return $? +} + +# Guard against calling the hook at the wrong time. +setupCudaGuard || return 0 + +# NOTE: While it would appear that we are in the global scope, we are not! As such, we must declare these variables as +# global to ensure they are accessible in the global scope. +declare -g cudaSetupOnce=1 +declare -gA cudaHostPathsSeen=() +declare -gA cudaOutputToPath=() + +extendcudaHostPathsSeen() { + log() { + logFromSetupHook \ + "${1:?}" \ + "setup-cuda" \ + "extendcudaHostPathsSeen" \ + "${2:?}" + } + local markerPath="${1:?}/nix-support/include-in-cudatoolkit-root" + + log "DEBUG" "checking for existence of $markerPath" + + if [[ ! -f "$markerPath" ]]; then + log "DEBUG" "skipping since $markerPath does not exist" + return 0 + fi + + if [[ -v cudaHostPathsSeen["$1"] ]]; then + log "DEBUG" "skipping since $1 has already been seen" + return 0 + fi + + cudaHostPathsSeen["$1"]=1 + log "DEBUG" "added $1 to cudaHostPathsSeen" + + # Only attempt to read the file referenced by markerPath if strictDeps is not set; otherwise it is blank and we + # don't need to read it. + [[ -n "${strictDeps-}" ]] && return 0 + + # E.g. cuda_cudart-lib + local cudaOutputName + # Fail gracefully if the file is empty. + # One reason the file may be empty: the package was built with strictDeps set, but the current build does not have + # strictDeps set. + read -r cudaOutputName < "$markerPath" || return 0 + + [[ -z "$cudaOutputName" ]] && return 0 + + local oldPath="${cudaOutputToPath[$cudaOutputName]-}" + if [[ -n "$oldPath" ]]; then + log "WARNING" "overwriting $cudaOutputName from $oldPath to $1" + fi + cudaOutputToPath["$cudaOutputName"]="$1" +} +addEnvHooks "$targetOffset" extendcudaHostPathsSeen + +setupCUDAToolkit_ROOT() { + log() { + logFromSetupHook \ + "${1:?}" \ + "setup-cuda" \ + "setupCUDAToolkit_ROOT" \ + "${2:?}" + } + log "DEBUG" "cudaHostPathsSeen is ${!cudaHostPathsSeen[*]}" + + for path in "${!cudaHostPathsSeen[@]}"; do + addToSearchPathWithCustomDelimiter ";" CUDAToolkit_ROOT "$path" + [[ -d "$path/include" ]] && addToSearchPathWithCustomDelimiter ";" CUDAToolkit_INCLUDE_DIR "$path/include" + done + + # NOTE: Due to the way CMake flags are structured within Nixpkgs, there is a distinction between flags set by + # cmakeFlags, and those set by cmakeFlagsArray (the former is a string, the latter is an array). + # The setup hook in Nixpkgs, as of this comment, interpolates the cmakeFlags string before expanding the array. + # Since we want these flags to have the lowest priority (and thus, be overridden), we must set them with + # cmakeFlags so all user flags will override them. + export cmakeFlags+=" -DCUDAToolkit_INCLUDE_DIR=\"${CUDAToolkit_INCLUDE_DIR:-}\"" + export cmakeFlags+=" -DCUDAToolkit_ROOT=\"${CUDAToolkit_ROOT:-}\"" +} +preConfigureHooks+=(setupCUDAToolkit_ROOT) + +setupCUDAToolkitCompilers() { + log() { + logFromSetupHook \ + "${1:?}" \ + "setup-cuda" \ + "setupCUDAToolkitCompilers" \ + "${2:?}" + } + + if [[ -n "${dontSetupCUDAToolkitCompilers-}" ]]; then + log "INFO" "skipping setup of CUDA toolkit compilers as requested" + return 0 + else + log "INFO" "setting up CUDA toolkit compilers" + fi + + # Point NVCC at a compatible compiler + + # For CMake-based projects: + # https://cmake.org/cmake/help/latest/module/FindCUDA.html#input-variables + # https://cmake.org/cmake/help/latest/envvar/CUDAHOSTCXX.html + # https://cmake.org/cmake/help/latest/variable/CMAKE_CUDA_HOST_COMPILER.html + + # NOTE: See note in setupCUDAToolkit_ROOT about why we use cmakeFlags over cmakeFlagsArray. + export cmakeFlags+=" -DCUDA_HOST_COMPILER=\"@ccFullPath@\"" + export cmakeFlags+=" -DCMAKE_CUDA_HOST_COMPILER=\"@ccFullPath@\"" + + # For non-CMake projects: + # We prepend --compiler-bindir to nvcc flags. + # Downstream packages can override these, because NVCC + # uses the last --compiler-bindir it gets on the command line. + # FIXME: this results in "incompatible redefinition" warnings. + # https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html#compiler-bindir-directory-ccbin + [[ -z "${CUDAHOSTCXX-}" ]] && export CUDAHOSTCXX="@ccFullPath@" + + export NVCC_PREPEND_FLAGS+=" --compiler-bindir=\"@ccRoot@/bin\"" + + # NOTE: We set -Xfatbin=-compress-all, which reduces the size of the compiled + # binaries. If binaries grow over 2GB, they will fail to link. This is a problem for us, as + # the default set of CUDA capabilities we build can regularly cause this to occur (for + # example, with Magma). + # + # @SomeoneSerge: original comment was made by @ConnorBaker in .../cudatoolkit/common.nix + [[ -z "${dontCompressFatbin-}" ]] && export NVCC_PREPEND_FLAGS+=" -Xfatbin=-compress-all" +} +preConfigureHooks+=(setupCUDAToolkitCompilers) + +propagateCudaLibraries() { + log() { + logFromSetupHook \ + "${1:?}" \ + "setup-cuda" \ + "propagateCudaLibraries" \ + "${2:?}" + } + + if [[ -n "${cudaPropagateToOutput-}" ]]; then + log "INFO" "propagating CUDA libraries to $cudaPropagateToOutput" + else + log "DEBUG" "skipping propagation of CUDA libraries since cudaPropagateToOutput is not set" + return 0 + fi + + log "DEBUG" "cudaHostPathsSeen is ${!cudaHostPathsSeen[*]}" + + mkdir -p "${!cudaPropagateToOutput}/nix-support" + # One'd expect this should be propagated-bulid-build-deps, but that doesn't seem to work + echo "@setupCuda@" >> "${!cudaPropagateToOutput}/nix-support/propagated-native-build-inputs" + + local propagatedBuildInputs=( "${!cudaHostPathsSeen[@]}" ) + for output in $(getAllOutputNames); do + [[ "$output" != "$cudaPropagateToOutput" ]] && propagatedBuildInputs+=( "${!output}" ) && break + done + + # One'd expect this should be propagated-host-host-deps, but that doesn't seem to work + printWords "${propagatedBuildInputs[@]}" >> "${!cudaPropagateToOutput}/nix-support/propagated-build-inputs" +} +postFixupHooks+=(propagateCudaLibraries) diff --git a/pkgs/development/cuda-modules/setup-hooks/utilities/log-from-setup-hook.sh b/pkgs/development/cuda-modules/setup-hooks/utilities/log-from-setup-hook.sh new file mode 100644 index 0000000000000..20366fcf7db7b --- /dev/null +++ b/pkgs/development/cuda-modules/setup-hooks/utilities/log-from-setup-hook.sh @@ -0,0 +1,83 @@ +# shellcheck shell=bash + +echo "Sourcing log-from-setup-hook" + +logFromSetupHookUsage() { + echo "Usage: " + echo " logLevel: ERROR, WARNING, INFO, or DEBUG" + echo " scriptName: The name of the enclosing script" + echo " fnName: The name of the function being called" + echo " message: The message to log" +} + +# Utility function to log messages with default values for the host and target offsets. +# Expects arguments: +# 1. The level of the message (must be one of ERROR, WARNING, INFO, or DEBUG). DEBUG is only shown if NIX_DEBUG is +# greater than or equal to 1. +# 2. The name of the enclosing script. +# 3. The name of the function being called. +# 4. The message to log. +logFromSetupHook() { + if (( $# != 4 )); then + echo "logFromSetupHook: Expected 4 arguments, got $#" + logFromSetupHookUsage + exit 1 + fi + + # Check that the log level is non-empty and valid. + if [[ -z "${1-}" ]]; then + echo "logFromSetupHook: Log level is empty" + logFromSetupHookUsage + exit 1 + elif [[ ! "${1-}" =~ ^(ERROR|WARNING|INFO|DEBUG)$ ]]; then + echo "logFromSetupHook: Invalid log level: $1" + logFromSetupHookUsage + exit 1 + fi + local logLevel="${1:?}" + + # Check that the script name is non-empty. + if [[ -z "${2-}" ]]; then + echo "logFromSetupHook: Script name is empty" + logFromSetupHookUsage + exit 1 + fi + local scriptName="${2:?}" + + # Check that the function name is non-empty and valid. + if [[ -z "${3-}" ]]; then + echo "logFromSetupHook: Function name is empty" + logFromSetupHookUsage + exit 1 + fi + local fnName="${3:?}" + + # Check that the message is non-empty. + if [[ -z "${4-}" ]]; then + echo "logFromSetupHook: Message is empty" + logFromSetupHookUsage + exit 1 + fi + local message="${4:?}" + + # Early return if NIX_DEBUG is not set and the log level is DEBUG. + (( ${NIX_DEBUG:-0} == 0 )) && [[ "$logLevel" == DEBUG ]] && return 0 + + # Color handling + local -A logLevelColorMapping=( + [ERROR]=31 # Red + [WARNING]=33 # Yellow + [INFO]=0 # Default + [DEBUG]=32 # Green + ) + local -i logColor="${logLevelColorMapping[$logLevel]:?}" + local startColor="\e[${logColor}m" + local endColor="\e[0m" + + printf \ + "${startColor}[%b][%b][%b]: %b${endColor}\n" \ + "$scriptName" \ + "$fnName" \ + "$logLevel" \ + "$message" >&2 +} diff --git a/pkgs/development/libraries/nvidia-optical-flow-sdk/default.nix b/pkgs/development/libraries/nvidia-optical-flow-sdk/default.nix index 813821bfb71c2..68a8a3d21f03d 100644 --- a/pkgs/development/libraries/nvidia-optical-flow-sdk/default.nix +++ b/pkgs/development/libraries/nvidia-optical-flow-sdk/default.nix @@ -18,11 +18,11 @@ stdenv.mkDerivation { cp -R * $out/include ''; - # Makes setupCudaHook propagate nvidia-optical-flow-sdk together with cuda + # Makes setupCuda propagate nvidia-optical-flow-sdk together with cuda # packages. Currently used by opencv4.cxxdev, hopefully can be removed in the # future nativeBuildInputs = [ - cudaPackages.markForCudatoolkitRootHook + cudaPackages.markForCudatoolkitRoot ]; meta = with lib; {