Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
1# Notes:
2#
3# Silvan (Tweag) covered some things on recursive attribute sets in the Nix Hour:
4# https://www.youtube.com/watch?v=BgnUFtd1Ivs
5#
6# I (@connorbaker) highly recommend watching it.
7#
8# Most helpful comment regarding recursive attribute sets:
9#
10# https://github.com/NixOS/nixpkgs/pull/256324#issuecomment-1749935979
11#
12# To summarize:
13#
14# - `prev` should only be used to access attributes which are going to be overridden.
15# - `final` should only be used to access `callPackage` to build new packages.
16# - Attribute names are evaluated eagerly ("NAMESET STRICTNESS").
17# - Extensions must not depend on `final` when computing names and count of new attributes.
18#
19# Silvan's recommendation then is to explicitly use `callPackage` to provide everything our
20# extensions need to compute the attribute names, without relying on `final`.
21#
22# I've (@connorbaker) attempted to do that, though I'm unsure of how this will interact with overrides.
23{
24 config,
25 _cuda,
26 cudaMajorMinorVersion,
27 lib,
28 pkgs,
29 stdenv,
30 runCommand,
31}:
32let
33 inherit (lib)
34 attrsets
35 customisation
36 fixedPoints
37 lists
38 strings
39 versions
40 ;
41
42 cudaLib = _cuda.lib;
43
44 # Since Jetson capabilities are never built by default, we can check if any of them were requested
45 # through final.config.cudaCapabilities and use that to determine if we should change some manifest versions.
46 # Copied from backendStdenv.
47 jetsonCudaCapabilities = lib.filter (
48 cudaCapability: _cuda.db.cudaCapabilityToInfo.${cudaCapability}.isJetson
49 ) _cuda.db.allSortedCudaCapabilities;
50 hasJetsonCudaCapability =
51 lib.intersectLists jetsonCudaCapabilities (config.cudaCapabilities or [ ]) != [ ];
52 redistSystem = _cuda.lib.getRedistSystem hasJetsonCudaCapability stdenv.hostPlatform.system;
53
54 # We must use an instance of Nixpkgs where the CUDA package set we're building is the default; if we do not, members
55 # of the versioned, non-default package sets may rely on (transitively) members of the default, unversioned CUDA
56 # package set.
57 # See `Using cudaPackages.pkgs` in doc/languages-frameworks/cuda.section.md for more information.
58 pkgs' =
59 let
60 cudaPackagesUnversionedName = "cudaPackages";
61 cudaPackagesMajorVersionName = cudaLib.mkVersionedName cudaPackagesUnversionedName (
62 versions.major cudaMajorMinorVersion
63 );
64 cudaPackagesMajorMinorVersionName = cudaLib.mkVersionedName cudaPackagesUnversionedName cudaMajorMinorVersion;
65 in
66 # If the CUDA version of pkgs matches our CUDA version, we are constructing the default package set and can use
67 # pkgs without modification.
68 if pkgs.cudaPackages.cudaMajorMinorVersion == cudaMajorMinorVersion then
69 pkgs
70 else
71 pkgs.extend (
72 final: _: {
73 recurseForDerivations = false;
74 # The CUDA package set will be available as cudaPackages_x_y, so we need only update the aliases for the
75 # minor-versioned and unversioned package sets.
76 # cudaPackages_x = cudaPackages_x_y
77 ${cudaPackagesMajorVersionName} = final.${cudaPackagesMajorMinorVersionName};
78 # cudaPackages = cudaPackages_x
79 ${cudaPackagesUnversionedName} = final.${cudaPackagesMajorVersionName};
80 }
81 );
82
83 passthruFunction = final: {
84 # NOTE:
85 # It is important that _cuda is not part of the package set fixed-point. As described by
86 # @SomeoneSerge:
87 # > The layering should be: configuration -> (identifies/is part of) cudaPackages -> (is built using) cudaLib.
88 # > No arrows should point in the reverse directions.
89 # That is to say that cudaLib should only know about package sets and configurations, because it implements
90 # functionality for interpreting configurations, resolving them against data, and constructing package sets.
91 # This decision is driven both by a separation of concerns and by "NAMESET STRICTNESS" (see above).
92 # Also see the comment in `pkgs/top-level/all-packages.nix` about the `_cuda` attribute.
93
94 inherit cudaMajorMinorVersion;
95
96 pkgs = pkgs';
97
98 cudaNamePrefix = "cuda${cudaMajorMinorVersion}";
99
100 cudaMajorVersion = versions.major cudaMajorMinorVersion;
101 cudaOlder = strings.versionOlder cudaMajorMinorVersion;
102 cudaAtLeast = strings.versionAtLeast cudaMajorMinorVersion;
103
104 flags =
105 cudaLib.formatCapabilities {
106 inherit (final.backendStdenv) cudaCapabilities cudaForwardCompat;
107 inherit (_cuda.db) cudaCapabilityToInfo;
108 }
109 # TODO(@connorbaker): Enable the corresponding warnings in `../development/cuda-modules/aliases.nix` after some
110 # time to allow users to migrate to cudaLib and backendStdenv.
111 // {
112 inherit (cudaLib) dropDots;
113 cudaComputeCapabilityToName =
114 cudaCapability: _cuda.db.cudaCapabilityToInfo.${cudaCapability}.archName;
115 dropDot = cudaLib.dropDots;
116 isJetsonBuild = final.backendStdenv.hasJetsonCudaCapability;
117 };
118
119 # Loose packages
120 # Barring packages which share a home (e.g., cudatoolkit and cudatoolkit-legacy-runfile), new packages
121 # should be added to ../development/cuda-modules/packages in "by-name" style, where they will be automatically
122 # discovered and added to the package set.
123
124 # TODO: Move to aliases.nix once all Nixpkgs has migrated to the splayed CUDA packages
125 cudatoolkit = final.callPackage ../development/cuda-modules/cudatoolkit/redist-wrapper.nix { };
126 cudatoolkit-legacy-runfile = final.callPackage ../development/cuda-modules/cudatoolkit { };
127
128 tests =
129 let
130 bools = [
131 true
132 false
133 ];
134 configs = {
135 openCVFirst = bools;
136 useOpenCVDefaultCuda = bools;
137 useTorchDefaultCuda = bools;
138 };
139 builder =
140 {
141 openCVFirst,
142 useOpenCVDefaultCuda,
143 useTorchDefaultCuda,
144 }@config:
145 {
146 name = strings.concatStringsSep "-" (
147 [
148 "test"
149 (if openCVFirst then "opencv" else "torch")
150 ]
151 ++ lists.optionals (if openCVFirst then useOpenCVDefaultCuda else useTorchDefaultCuda) [
152 "with-default-cuda"
153 ]
154 ++ [
155 "then"
156 (if openCVFirst then "torch" else "opencv")
157 ]
158 ++ lists.optionals (if openCVFirst then useTorchDefaultCuda else useOpenCVDefaultCuda) [
159 "with-default-cuda"
160 ]
161 );
162 value = final.callPackage ../development/cuda-modules/tests/opencv-and-torch config;
163 };
164 in
165 attrsets.listToAttrs (attrsets.mapCartesianProduct builder configs)
166 // {
167 flags = final.callPackage ../development/cuda-modules/tests/flags.nix { };
168 };
169 };
170
171 composedExtension = fixedPoints.composeManyExtensions (
172 [
173 (
174 final: _:
175 {
176 # Prevent missing attribute errors
177 # NOTE(@connorbaker): CUDA 12.3 does not have a cuda_compat package; indeed, none of the release supports
178 # Jetson devices. To avoid errors in the case that cuda_compat is not defined, we have a dummy package which
179 # is always defined, but does nothing, will not build successfully, and has no platforms.
180 cuda_compat = runCommand "cuda_compat" { meta.platforms = [ ]; } "false";
181 }
182 // lib.packagesFromDirectoryRecursive {
183 inherit (final) callPackage;
184 directory = ../development/cuda-modules/packages;
185 }
186 )
187 (import ../development/cuda-modules/cuda/extension.nix { inherit cudaMajorMinorVersion lib; })
188 (import ../development/cuda-modules/generic-builders/multiplex.nix {
189 inherit
190 cudaLib
191 cudaMajorMinorVersion
192 lib
193 redistSystem
194 stdenv
195 ;
196 pname = "cudnn";
197 redistName = "cudnn";
198 releasesModule = ../development/cuda-modules/cudnn/releases.nix;
199 shimsFn = ../development/cuda-modules/cudnn/shims.nix;
200 })
201 (import ../development/cuda-modules/cutensor/extension.nix {
202 inherit
203 cudaLib
204 cudaMajorMinorVersion
205 lib
206 redistSystem
207 ;
208 })
209 (import ../development/cuda-modules/cusparselt/extension.nix {
210 inherit
211 cudaLib
212 lib
213 redistSystem
214 ;
215 })
216 (import ../development/cuda-modules/generic-builders/multiplex.nix {
217 inherit
218 cudaLib
219 cudaMajorMinorVersion
220 lib
221 redistSystem
222 stdenv
223 ;
224 pname = "tensorrt";
225 redistName = "tensorrt";
226 releasesModule = ../development/cuda-modules/tensorrt/releases.nix;
227 shimsFn = ../development/cuda-modules/tensorrt/shims.nix;
228 })
229 (import ../development/cuda-modules/cuda-samples/extension.nix {
230 inherit cudaMajorMinorVersion lib stdenv;
231 })
232 (import ../development/cuda-modules/cuda-library-samples/extension.nix { inherit lib stdenv; })
233 ]
234 ++ lib.optionals config.allowAliases [
235 (import ../development/cuda-modules/aliases.nix { inherit lib; })
236 ]
237 ++ _cuda.extensions
238 );
239
240 cudaPackages = customisation.makeScope pkgs'.newScope (
241 fixedPoints.extends composedExtension passthruFunction
242 );
243in
244# We want to warn users about the upcoming deprecation of old CUDA
245# versions, without breaking Nixpkgs CI with evaluation warnings. This
246# gross hack ensures that the warning only triggers if aliases are
247# enabled, which is true by default, but not for ofborg.
248lib.warnIf (cudaPackages.cudaOlder "12.0" && config.allowAliases)
249 "CUDA versions older than 12.0 will be removed in Nixpkgs 25.05; see the 24.11 release notes for more information"
250 cudaPackages