2023-11-07 15:35:11 +01:00
{
# General callPackage-supplied arguments
autoAddOpenGLRunpathHook ,
2023-11-17 16:51:48 +01:00
autoAddCudaCompatRunpathHook ,
2023-11-07 15:35:11 +01:00
autoPatchelfHook ,
backendStdenv ,
fetchurl ,
lib ,
lndir ,
markForCudatoolkitRootHook ,
flags ,
stdenv ,
hostPlatform ,
# Builder-specific arguments
# Short package name (e.g., "cuda_cccl")
# pname : String
pname ,
# Common name (e.g., "cutensor" or "cudnn") -- used in the URL.
# Also known as the Redistributable Name.
# redistName : String,
redistName ,
# If libPath is non-null, it must be a subdirectory of `lib`.
# The contents of `libPath` will be moved to the root of `lib`.
libPath ? null ,
# See ./modules/generic/manifests/redistrib/release.nix
redistribRelease ,
# See ./modules/generic/manifests/feature/release.nix
featureRelease ,
} :
let
inherit ( lib )
attrsets
lists
meta
strings
trivial
licenses
teams
sourceTypes
;
# Get the redist architectures for which package provides distributables.
# These are used by meta.platforms.
supportedRedistArchs = builtins . attrNames featureRelease ;
redistArch = flags . getRedistArch hostPlatform . system ;
in
backendStdenv . mkDerivation (
finalAttrs : {
# NOTE: Even though there's no actual buildPhase going on here, the derivations of the
# redistributables are sensitive to the compiler flags provided to stdenv. The patchelf package
# is sensitive to the compiler flags provided to stdenv, and we depend on it. As such, we are
# also sensitive to the compiler flags provided to stdenv.
inherit pname ;
inherit ( redistribRelease ) version ;
# Don't force serialization to string for structured attributes, like outputToPatterns
# and brokenConditions.
# Avoids "set cannot be coerced to string" errors.
__structuredAttrs = true ;
# Keep better track of dependencies.
strictDeps = true ;
# NOTE: Outputs are evaluated jointly with meta, so in the case that this is an unsupported platform,
# we still need to provide a list of outputs.
outputs =
let
# Checks whether the redistributable provides an output.
hasOutput =
output :
attrsets . attrByPath
[
redistArch
" o u t p u t s "
output
]
false
featureRelease ;
# Order is important here so we use a list.
additionalOutputs = builtins . filter hasOutput [
" b i n "
" l i b "
" s t a t i c "
" d e v "
" d o c "
" s a m p l e "
" p y t h o n "
] ;
# The out output is special -- it's the default output and we always include it.
outputs = [ " o u t " ] ++ additionalOutputs ;
in
outputs ;
# Traversed in the order of the outputs speficied in outputs;
# entries are skipped if they don't exist in outputs.
outputToPatterns = {
bin = [ " b i n " ] ;
lib = [
" l i b "
" l i b 6 4 "
] ;
static = [ " * * / * . a " ] ;
sample = [ " s a m p l e s " ] ;
python = [ " * * / * . w h l " ] ;
} ;
# Useful for introspecting why something went wrong.
# Maps descriptions of why the derivation would be marked broken to
# booleans indicating whether that description is true.
brokenConditions = { } ;
src = fetchurl {
url = " h t t p s : / / d e v e l o p e r . d o w n l o a d . n v i d i a . c o m / c o m p u t e / ${ redistName } / r e d i s t / ${
redistribRelease . ${ redistArch } . relative_path
} " ;
inherit ( redistribRelease . ${ redistArch } ) sha256 ;
} ;
# We do need some other phases, like configurePhase, so the multiple-output setup hook works.
dontBuild = true ;
nativeBuildInputs = [
autoPatchelfHook
# This hook will make sure libcuda can be found
# in typically /lib/opengl-driver by adding that
# directory to the rpath of all ELF binaries.
# Check e.g. with `patchelf --print-rpath path/to/my/binary
autoAddOpenGLRunpathHook
markForCudatoolkitRootHook
2023-11-17 16:51:48 +01:00
]
# autoAddCudaCompatRunpathHook depends on cuda_compat and would cause
# infinite recursion if applied to `cuda_compat` itself (beside the fact
# that it doesn't make sense in the first place)
++ lib . optionals ( pname != " c u d a _ c o m p a t " && flags . isJetsonBuild ) [
# autoAddCudaCompatRunpathHook must appear AFTER autoAddOpenGLRunpathHook.
# See its documentation in ./setup-hooks/extension.nix.
autoAddCudaCompatRunpathHook
2023-11-07 15:35:11 +01:00
] ;
buildInputs =
[
# autoPatchelfHook will search for a libstdc++ and we're giving it
# one that is compatible with the rest of nixpkgs, even when
# nvcc forces us to use an older gcc
# NB: We don't actually know if this is the right thing to do
stdenv . cc . cc . lib
] ;
# Picked up by autoPatchelf
# Needed e.g. for libnvrtc to locate (dlopen) libnvrtc-builtins
appendRunpaths = [ " $ O R I G I N " ] ;
# NOTE: We don't need to check for dev or doc, because those outputs are handled by
# the multiple-outputs setup hook.
# NOTE: moveToOutput operates on all outputs:
# https://github.com/NixOS/nixpkgs/blob/2920b6fc16a9ed5d51429e94238b28306ceda79e/pkgs/build-support/setup-hooks/multiple-outputs.sh#L105-L107
installPhase =
let
mkMoveToOutputCommand =
output :
let
template = pattern : '' m o v e T o O u t p u t " ${ pattern } " " ${ " $ " + output } " '' ;
patterns = finalAttrs . outputToPatterns . ${ output } or [ ] ;
in
strings . concatMapStringsSep " \n " template patterns ;
in
# Pre-install hook
''
runHook preInstall
''
# Handle the existence of libPath, which requires us to re-arrange the lib directory
+ strings . optionalString ( libPath != null ) ''
2023-12-12 16:55:17 +01:00
full_lib_path = " l i b / ${ libPath } "
if [ [ ! - d " $ f u l l _ l i b _ p a t h " ] ] ; then
echo " ${ finalAttrs . pname } : ' $ f u l l _ l i b _ p a t h ' d o e s n o t e x i s t , o n l y f o u n d : " > & 2
find lib / - mindepth 1 - maxdepth 1 > & 2
2023-11-07 15:35:11 +01:00
echo " T h i s r e l e a s e m i g h t n o t s u p p o r t y o u r C U D A v e r s i o n " > & 2
exit 1
fi
2023-12-12 16:55:17 +01:00
echo " M a k i n g l i b P a t h ' $ f u l l _ l i b _ p a t h ' t h e r o o t o f l i b " > & 2
mv " $ f u l l _ l i b _ p a t h " lib_new
2023-11-07 15:35:11 +01:00
rm - r lib
mv lib_new lib
''
2023-12-07 19:37:23 +01:00
# Create the primary output, out, and move the other outputs into it.
2023-11-07 15:35:11 +01:00
+ ''
mkdir - p " $ o u t "
mv * " $ o u t "
2023-12-07 19:37:23 +01:00
''
# Move the outputs into their respective outputs.
+ strings . concatMapStringsSep " \n " mkMoveToOutputCommand ( builtins . tail finalAttrs . outputs )
2023-12-13 03:32:57 +01:00
# Add a newline to the end of the installPhase, so that the post-install hook doesn't
# get concatenated with the last moveToOutput command.
+ " \n "
2023-12-07 19:37:23 +01:00
# Post-install hook
+ ''
2023-11-07 15:35:11 +01:00
runHook postInstall
'' ;
# libcuda needs to be resolved during runtime
# NOTE: Due to the use of __structuredAttrs, we can't use a list for autoPatchelfIgnoreMissingDeps, since it
# will take only the first value. Instead, we produce a string with the values separated by spaces.
# Using the `env` attribute ensures that the value is representable as one of the primitives allowed by
# bash's environment variables.
env . autoPatchelfIgnoreMissingDeps = " l i b c u d a . s o l i b c u d a . s o . * " ;
# The out output leverages the same functionality which backs the `symlinkJoin` function in
# Nixpkgs:
# https://github.com/NixOS/nixpkgs/blob/d8b2a92df48f9b08d68b0132ce7adfbdbc1fbfac/pkgs/build-support/trivial-builders/default.nix#L510
#
# That should allow us to emulate "fat" default outputs without having to actually create them.
#
# It is important that this run after the autoPatchelfHook, otherwise the symlinks in out will reference libraries in lib, creating a circular dependency.
postPhases = [ " p o s t P a t c h e l f " ] ;
# For each output, create a symlink to it in the out output.
2023-12-07 19:37:23 +01:00
# NOTE: We must recreate the out output here, because the setup hook will have deleted it if it was empty.
postPatchelf = ''
mkdir - p " $ o u t "
for output in $ ( getAllOutputNames ) ; do
if [ [ " $ o u t p u t " != " o u t " ] ] ; then
$ { meta . getExe lndir } " ' ' ${ ! output } " " $ o u t "
fi
done
'' ;
2023-11-07 15:35:11 +01:00
# Make the CUDA-patched stdenv available
passthru . stdenv = backendStdenv ;
# Setting propagatedBuildInputs to false will prevent outputs known to the multiple-outputs
# from depending on `out` by default.
# https://github.com/NixOS/nixpkgs/blob/2920b6fc16a9ed5d51429e94238b28306ceda79e/pkgs/build-support/setup-hooks/multiple-outputs.sh#L196
# Indeed, we want to do the opposite -- fat "out" outputs that contain all the other outputs.
propagatedBuildOutputs = false ;
# By default, if the dev output exists it just uses that.
# However, because we disabled propagatedBuildOutputs, dev doesn't contain libraries or
# anything of the sort. To remedy this, we set outputSpecified to true, and use
# outputsToInstall, which tells Nix which outputs to use when the package name is used
# unqualified (that is, without an explicit output).
outputSpecified = true ;
meta = {
description = " ${ redistribRelease . name } . B y d o w n l o a d i n g a n d u s i n g t h e p a c k a g e s y o u a c c e p t t h e t e r m s a n d c o n d i t i o n s o f t h e ${ finalAttrs . meta . license . shortName } " ;
sourceProvenance = [ sourceTypes . binaryNativeCode ] ;
platforms =
lists . concatMap
(
redistArch :
let
nixSystem = builtins . tryEval ( flags . getNixSystem redistArch ) ;
in
if nixSystem . success then [ nixSystem . value ] else [ ]
)
supportedRedistArchs ;
broken = lists . any trivial . id ( attrsets . attrValues finalAttrs . brokenConditions ) ;
license = licenses . unfree ;
maintainers = teams . cuda . members ;
# Force the use of the default, fat output by default (even though `dev` exists, which
# causes Nix to prefer that output over the others if outputSpecified isn't set).
outputsToInstall = [ " o u t " ] ;
} ;
}
)