otadump: init at 0.1.2 (#329129)
[NixPkgs.git] / pkgs / development / cuda-modules / generic-builders / manifest.nix
blob26f4f1b972aed9da1120f19335cad87ba6de3b12
2   # General callPackage-supplied arguments
3   autoAddDriverRunpath,
4   autoAddCudaCompatRunpath,
5   autoPatchelfHook,
6   backendStdenv,
7   fetchurl,
8   lib,
9   markForCudatoolkitRootHook,
10   flags,
11   stdenv,
12   # Builder-specific arguments
13   # Short package name (e.g., "cuda_cccl")
14   # pname : String
15   pname,
16   # Common name (e.g., "cutensor" or "cudnn") -- used in the URL.
17   # Also known as the Redistributable Name.
18   # redistName : String,
19   redistName,
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`.
22   libPath ? null,
23   # See ./modules/generic/manifests/redistrib/release.nix
24   redistribRelease,
25   # See ./modules/generic/manifests/feature/release.nix
26   featureRelease,
27   cudaMajorMinorVersion,
29 let
30   inherit (lib)
31     attrsets
32     lists
33     meta
34     strings
35     trivial
36     licenses
37     teams
38     sourceTypes
39     ;
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.
58   inherit pname;
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.
67   strictDeps = true;
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.
71   outputs =
72     let
73       # Checks whether the redistributable provides an output.
74       hasOutput =
75         output:
76         attrsets.attrByPath [
77           redistArch
78           "outputs"
79           output
80         ] false featureRelease;
81       # Order is important here so we use a list.
82       possibleOutputs = [
83         "bin"
84         "lib"
85         "static"
86         "dev"
87         "doc"
88         "sample"
89         "python"
90       ];
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`!
99       additionalOutputs =
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;
103     in
104     outputs;
106   # Traversed in the order of the outputs speficied in outputs;
107   # entries are skipped if they don't exist in outputs.
108   outputToPatterns = {
109     bin = [ "bin" ];
110     dev = [
111       "share/pkgconfig"
112       "**/*.pc"
113       "**/*.cmake"
114     ];
115     lib = [
116       "lib"
117       "lib64"
118     ];
119     static = [ "**/*.a" ];
120     sample = [ "samples" ];
121     python = [ "**/*.whl" ];
122   };
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.
130   brokenConditions = {
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" =
136       let
137         libIndex = lists.findFirstIndex (x: x == "lib") null finalAttrs.outputs;
138         staticIndex = lists.findFirstIndex (x: x == "static") null finalAttrs.outputs;
139       in
140       libIndex != null && staticIndex != null && libIndex > staticIndex;
141   };
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;
148   };
150   # src :: Optional Derivation
151   # If redistArch doesn't exist in redistribRelease, return null.
152   src = trivial.mapNullable (
153     { relative_path, sha256, ... }:
154     fetchurl {
155       url = "https://developer.download.nvidia.com/compute/${redistName}/redist/${relative_path}";
156       inherit sha256;
157     }
158   ) (redistribRelease.${redistArch} or null);
160   postPatch =
161     # Pkg-config's setup hook expects configuration files in $out/share/pkgconfig
162     ''
163       for path in pkg-config pkgconfig; do
164         [[ -d "$path" ]] || continue
165         mkdir -p share/pkgconfig
166         mv "$path"/* share/pkgconfig/
167         rmdir "$path"
168       done
169     ''
170     # Rewrite FHS paths with store paths
171     # NOTE: output* fall back to out if the corresponding output isn't defined.
172     + ''
173       for pc in share/pkgconfig/*.pc; do
174         sed -i \
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|" \
178           "$pc"
179       done
180     ''
181     # Generate unversioned names.
182     # E.g. cuda-11.8.pc -> cuda.pc
183     + ''
184       for pc in share/pkgconfig/*-"$majorMinorVersion.pc"; do
185         ln -s "$(basename "$pc")" "''${pc%-$majorMinorVersion.pc}".pc
186       done
187     '';
189   env.majorMinorVersion = cudaMajorMinorVersion;
191   # We do need some other phases, like configurePhase, so the multiple-output setup hook works.
192   dontBuild = true;
194   nativeBuildInputs =
195     [
196       autoPatchelfHook
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
201       autoAddDriverRunpath
202       markForCudatoolkitRootHook
203     ]
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
211     ];
213   buildInputs = [
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)
219   ];
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
229   installPhase =
230     let
231       mkMoveToOutputCommand =
232         output:
233         let
234           template = pattern: ''moveToOutput "${pattern}" "${"$" + output}"'';
235           patterns = finalAttrs.outputToPatterns.${output} or [ ];
236         in
237         strings.concatMapStringsSep "\n" template patterns;
238     in
239     # Pre-install hook
240     ''
241       runHook preInstall
242     ''
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
250         exit 1
251       fi
252       echo "Making libPath '$full_lib_path' the root of lib" >&2
253       mv "$full_lib_path" lib_new
254       rm -r lib
255       mv lib_new lib
256     ''
257     # Create the primary output, out, and move the other outputs into it.
258     + ''
259       mkdir -p "$out"
260       mv * "$out"
261     ''
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.
266     + "\n"
267     # Post-install hook
268     + ''
269       runHook postInstall
270     '';
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
281         exit 1
282       fi
283     fi
284   '';
286   # libcuda needs to be resolved during runtime
287   autoPatchelfIgnoreMissingDeps = [
288     "libcuda.so"
289     "libcuda.so.*"
290   ];
292   # _multioutPropagateDev() currently expects a space-separated string rather than an array
293   preFixup = ''
294     export propagatedBuildOutputs="''${propagatedBuildOutputs[@]}"
295   '';
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" ];
302   postPatchelf = ''
303     true
304   '';
306   # Make the CUDA-patched stdenv available
307   passthru.stdenv = backendStdenv;
309   meta = {
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)))
318     ];
319     badPlatforms =
320       let
321         isBadPlatform = lists.any trivial.id (attrsets.attrValues finalAttrs.badPlatformsConditions);
322       in
323       lists.optionals isBadPlatform finalAttrs.meta.platforms;
324     license = licenses.unfree;
325     maintainers = teams.cuda.members;
326   };