2 # General callPackage-supplied arguments
4 autoAddCudaCompatRunpath,
9 markForCudatoolkitRootHook,
12 # Builder-specific arguments
13 # Short package name (e.g., "cuda_cccl")
16 # Common name (e.g., "cutensor" or "cudnn") -- used in the URL.
17 # Also known as the Redistributable Name.
18 # redistName : String,
20 # If libPath is non-null, it must be a subdirectory of `lib`.
21 # The contents of `libPath` will be moved to the root of `lib`.
23 # See ./modules/generic/manifests/redistrib/release.nix
25 # See ./modules/generic/manifests/feature/release.nix
27 cudaMajorMinorVersion,
41 inherit (stdenv) hostPlatform;
43 # Get the redist architectures for which package provides distributables.
44 # These are used by meta.platforms.
45 supportedRedistArchs = builtins.attrNames featureRelease;
46 # redistArch :: String
47 # The redistArch is the name of the architecture for which the redistributable is built.
48 # It is `"unsupported"` if the redistributable is not supported on the target platform.
49 redistArch = flags.getRedistArch hostPlatform.system;
51 sourceMatchesHost = flags.getNixSystem redistArch == hostPlatform.system;
53 backendStdenv.mkDerivation (finalAttrs: {
54 # NOTE: Even though there's no actual buildPhase going on here, the derivations of the
55 # redistributables are sensitive to the compiler flags provided to stdenv. The patchelf package
56 # is sensitive to the compiler flags provided to stdenv, and we depend on it. As such, we are
57 # also sensitive to the compiler flags provided to stdenv.
59 inherit (redistribRelease) version;
61 # Don't force serialization to string for structured attributes, like outputToPatterns
62 # and brokenConditions.
63 # Avoids "set cannot be coerced to string" errors.
64 __structuredAttrs = true;
66 # Keep better track of dependencies.
69 # NOTE: Outputs are evaluated jointly with meta, so in the case that this is an unsupported platform,
70 # we still need to provide a list of outputs.
73 # Checks whether the redistributable provides an output.
80 ] false featureRelease;
81 # Order is important here so we use a list.
91 # Filter out outputs that don't exist in the redistributable.
92 # NOTE: In the case the redistributable isn't supported on the target platform,
93 # we will have `outputs = [ "out" ] ++ possibleOutputs`. This is of note because platforms which
94 # aren't supported would otherwise have evaluation errors when trying to access outputs other than `out`.
95 # The alternative would be to have `outputs = [ "out" ]` when`redistArch = "unsupported"`, but that would
96 # require adding guards throughout the entirety of the CUDA package set to ensure `cudaSupport` is true --
97 # recall that OfBorg will evaluate packages marked as broken and that `cudaPackages` will be evaluated with
98 # `cudaSupport = false`!
100 if redistArch == "unsupported" then possibleOutputs else builtins.filter hasOutput possibleOutputs;
101 # The out output is special -- it's the default output and we always include it.
102 outputs = [ "out" ] ++ additionalOutputs;
106 # Traversed in the order of the outputs speficied in outputs;
107 # entries are skipped if they don't exist in outputs.
119 static = [ "**/*.a" ];
120 sample = [ "samples" ];
121 python = [ "**/*.whl" ];
124 # Useful for introspecting why something went wrong. Maps descriptions of why the derivation would be marked as
125 # broken on have badPlatforms include the current platform.
127 # brokenConditions :: AttrSet Bool
128 # Sets `meta.broken = true` if any of the conditions are true.
129 # Example: Broken on a specific version of CUDA or when a dependency has a specific version.
131 # Unclear how this is handled by Nix internals.
132 "Duplicate entries in outputs" = finalAttrs.outputs != lists.unique finalAttrs.outputs;
133 # Typically this results in the static output being empty, as all libraries are moved
134 # back to the lib output.
135 "lib output follows static output" =
137 libIndex = lists.findFirstIndex (x: x == "lib") null finalAttrs.outputs;
138 staticIndex = lists.findFirstIndex (x: x == "static") null finalAttrs.outputs;
140 libIndex != null && staticIndex != null && libIndex > staticIndex;
143 # badPlatformsConditions :: AttrSet Bool
144 # Sets `meta.badPlatforms = meta.platforms` if any of the conditions are true.
145 # Example: Broken on a specific architecture when some condition is met (like targeting Jetson).
146 badPlatformsConditions = {
147 "No source" = !sourceMatchesHost;
150 # src :: Optional Derivation
151 # If redistArch doesn't exist in redistribRelease, return null.
152 src = trivial.mapNullable (
153 { relative_path, sha256, ... }:
155 url = "https://developer.download.nvidia.com/compute/${redistName}/redist/${relative_path}";
158 ) (redistribRelease.${redistArch} or null);
161 # Pkg-config's setup hook expects configuration files in $out/share/pkgconfig
163 for path in pkg-config pkgconfig; do
164 [[ -d "$path" ]] || continue
165 mkdir -p share/pkgconfig
166 mv "$path"/* share/pkgconfig/
170 # Rewrite FHS paths with store paths
171 # NOTE: output* fall back to out if the corresponding output isn't defined.
173 for pc in share/pkgconfig/*.pc; do
175 -e "s|^cudaroot\s*=.*\$|cudaroot=''${!outputDev}|" \
176 -e "s|^libdir\s*=.*/lib\$|libdir=''${!outputLib}/lib|" \
177 -e "s|^includedir\s*=.*/include\$|includedir=''${!outputDev}/include|" \
181 # Generate unversioned names.
182 # E.g. cuda-11.8.pc -> cuda.pc
184 for pc in share/pkgconfig/*-"$majorMinorVersion.pc"; do
185 ln -s "$(basename "$pc")" "''${pc%-$majorMinorVersion.pc}".pc
189 env.majorMinorVersion = cudaMajorMinorVersion;
191 # We do need some other phases, like configurePhase, so the multiple-output setup hook works.
197 # This hook will make sure libcuda can be found
198 # in typically /lib/opengl-driver by adding that
199 # directory to the rpath of all ELF binaries.
200 # Check e.g. with `patchelf --print-rpath path/to/my/binary
202 markForCudatoolkitRootHook
204 # autoAddCudaCompatRunpath depends on cuda_compat and would cause
205 # infinite recursion if applied to `cuda_compat` itself (beside the fact
206 # that it doesn't make sense in the first place)
207 ++ lib.optionals (pname != "cuda_compat" && flags.isJetsonBuild) [
208 # autoAddCudaCompatRunpath must appear AFTER autoAddDriverRunpath.
209 # See its documentation in ./setup-hooks/extension.nix.
210 autoAddCudaCompatRunpath
214 # autoPatchelfHook will search for a libstdc++ and we're giving it
215 # one that is compatible with the rest of nixpkgs, even when
216 # nvcc forces us to use an older gcc
217 # NB: We don't actually know if this is the right thing to do
218 (lib.getLib stdenv.cc.cc)
221 # Picked up by autoPatchelf
222 # Needed e.g. for libnvrtc to locate (dlopen) libnvrtc-builtins
223 appendRunpaths = [ "$ORIGIN" ];
225 # NOTE: We don't need to check for dev or doc, because those outputs are handled by
226 # the multiple-outputs setup hook.
227 # NOTE: moveToOutput operates on all outputs:
228 # https://github.com/NixOS/nixpkgs/blob/2920b6fc16a9ed5d51429e94238b28306ceda79e/pkgs/build-support/setup-hooks/multiple-outputs.sh#L105-L107
231 mkMoveToOutputCommand =
234 template = pattern: ''moveToOutput "${pattern}" "${"$" + output}"'';
235 patterns = finalAttrs.outputToPatterns.${output} or [ ];
237 strings.concatMapStringsSep "\n" template patterns;
243 # Handle the existence of libPath, which requires us to re-arrange the lib directory
244 + strings.optionalString (libPath != null) ''
245 full_lib_path="lib/${libPath}"
246 if [[ ! -d "$full_lib_path" ]]; then
247 echo "${finalAttrs.pname}: '$full_lib_path' does not exist, only found:" >&2
248 find lib/ -mindepth 1 -maxdepth 1 >&2
249 echo "This release might not support your CUDA version" >&2
252 echo "Making libPath '$full_lib_path' the root of lib" >&2
253 mv "$full_lib_path" lib_new
257 # Create the primary output, out, and move the other outputs into it.
262 # Move the outputs into their respective outputs.
263 + strings.concatMapStringsSep "\n" mkMoveToOutputCommand (builtins.tail finalAttrs.outputs)
264 # Add a newline to the end of the installPhase, so that the post-install hook doesn't
265 # get concatenated with the last moveToOutput command.
272 doInstallCheck = true;
273 allowFHSReferences = true; # TODO: Default to `false`
274 postInstallCheck = ''
275 echo "Executing postInstallCheck"
277 if [[ -z "''${allowFHSReferences-}" ]]; then
278 mapfile -t outputPaths < <(for o in $(getAllOutputNames); do echo "''${!o}"; done)
279 if grep --max-count=5 --recursive --exclude=LICENSE /usr/ "''${outputPaths[@]}"; then
280 echo "Detected references to /usr" >&2
286 # libcuda needs to be resolved during runtime
287 autoPatchelfIgnoreMissingDeps = [
292 # _multioutPropagateDev() currently expects a space-separated string rather than an array
294 export propagatedBuildOutputs="''${propagatedBuildOutputs[@]}"
297 # Propagate all outputs, including `static`
298 propagatedBuildOutputs = builtins.filter (x: x != "dev") finalAttrs.outputs;
300 # Kept in case overrides assume postPhases have already been defined
301 postPhases = [ "postPatchelf" ];
306 # Make the CUDA-patched stdenv available
307 passthru.stdenv = backendStdenv;
310 description = "${redistribRelease.name}. By downloading and using the packages you accept the terms and conditions of the ${finalAttrs.meta.license.shortName}";
311 sourceProvenance = [ sourceTypes.binaryNativeCode ];
312 broken = lists.any trivial.id (attrsets.attrValues finalAttrs.brokenConditions);
313 platforms = trivial.pipe supportedRedistArchs [
314 # Map each redist arch to the equivalent nix system or null if there is no equivalent.
315 (builtins.map flags.getNixSystem)
316 # Filter out unsupported systems
317 (builtins.filter (nixSystem: !(strings.hasPrefix "unsupported-" nixSystem)))
321 isBadPlatform = lists.any trivial.id (attrsets.attrValues finalAttrs.badPlatformsConditions);
323 lists.optionals isBadPlatform finalAttrs.meta.platforms;
324 license = licenses.unfree;
325 maintainers = teams.cuda.members;