Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
1{ 2 # General callPackage-supplied arguments 3 autoAddDriverRunpath, 4 autoAddCudaCompatRunpath, 5 autoPatchelfHook, 6 backendStdenv, 7 callPackage, 8 _cuda, 9 fetchurl, 10 lib, 11 markForCudatoolkitRootHook, 12 flags, 13 stdenv, 14 # Builder-specific arguments 15 # Short package name (e.g., "cuda_cccl") 16 # pname : String 17 pname, 18 # Common name (e.g., "cutensor" or "cudnn") -- used in the URL. 19 # Also known as the Redistributable Name. 20 # redistName : String, 21 redistName, 22 # If libPath is non-null, it must be a subdirectory of `lib`. 23 # The contents of `libPath` will be moved to the root of `lib`. 24 libPath ? null, 25 # See ./modules/generic/manifests/redistrib/release.nix 26 redistribRelease, 27 # See ./modules/generic/manifests/feature/release.nix 28 featureRelease, 29 cudaMajorMinorVersion, 30}: 31let 32 inherit (lib) 33 attrsets 34 lists 35 strings 36 trivial 37 licenses 38 teams 39 sourceTypes 40 ; 41 42 inherit (stdenv) hostPlatform; 43 44 # Last step before returning control to `callPackage` (adds the `.override` method) 45 # we'll apply (`overrideAttrs`) necessary package-specific "fixup" functions. 46 # Order is significant. 47 maybeFixup = _cuda.fixups.${pname} or null; 48 fixup = if maybeFixup != null then callPackage maybeFixup { } else { }; 49 50 # Get the redist systems for which package provides distributables. 51 # These are used by meta.platforms. 52 supportedRedistSystems = builtins.attrNames featureRelease; 53 # redistSystem :: String 54 # The redistSystem is the name of the system for which the redistributable is built. 55 # It is `"unsupported"` if the redistributable is not supported on the target system. 56 redistSystem = _cuda.lib.getRedistSystem backendStdenv.hasJetsonCudaCapability hostPlatform.system; 57 58 sourceMatchesHost = lib.elem hostPlatform.system (_cuda.lib.getNixSystems redistSystem); 59in 60(backendStdenv.mkDerivation (finalAttrs: { 61 # NOTE: Even though there's no actual buildPhase going on here, the derivations of the 62 # redistributables are sensitive to the compiler flags provided to stdenv. The patchelf package 63 # is sensitive to the compiler flags provided to stdenv, and we depend on it. As such, we are 64 # also sensitive to the compiler flags provided to stdenv. 65 inherit pname; 66 inherit (redistribRelease) version; 67 68 # Don't force serialization to string for structured attributes, like outputToPatterns 69 # and brokenConditions. 70 # Avoids "set cannot be coerced to string" errors. 71 __structuredAttrs = true; 72 73 # Keep better track of dependencies. 74 strictDeps = true; 75 76 # NOTE: Outputs are evaluated jointly with meta, so in the case that this is an unsupported platform, 77 # we still need to provide a list of outputs. 78 outputs = 79 let 80 # Checks whether the redistributable provides an output. 81 hasOutput = 82 output: 83 attrsets.attrByPath [ 84 redistSystem 85 "outputs" 86 output 87 ] false featureRelease; 88 # Order is important here so we use a list. 89 possibleOutputs = [ 90 "bin" 91 "lib" 92 "static" 93 "dev" 94 "doc" 95 "sample" 96 "python" 97 ]; 98 # Filter out outputs that don't exist in the redistributable. 99 # NOTE: In the case the redistributable isn't supported on the target platform, 100 # we will have `outputs = [ "out" ] ++ possibleOutputs`. This is of note because platforms which 101 # aren't supported would otherwise have evaluation errors when trying to access outputs other than `out`. 102 # The alternative would be to have `outputs = [ "out" ]` when`redistSystem = "unsupported"`, but that would 103 # require adding guards throughout the entirety of the CUDA package set to ensure `cudaSupport` is true -- 104 # recall that OfBorg will evaluate packages marked as broken and that `cudaPackages` will be evaluated with 105 # `cudaSupport = false`! 106 additionalOutputs = 107 if redistSystem == "unsupported" then 108 possibleOutputs 109 else 110 builtins.filter hasOutput possibleOutputs; 111 # The out output is special -- it's the default output and we always include it. 112 outputs = [ "out" ] ++ additionalOutputs; 113 in 114 outputs; 115 116 # Traversed in the order of the outputs specified in outputs; 117 # entries are skipped if they don't exist in outputs. 118 outputToPatterns = { 119 bin = [ "bin" ]; 120 dev = [ 121 "share/pkgconfig" 122 "**/*.pc" 123 "**/*.cmake" 124 ]; 125 lib = [ 126 "lib" 127 "lib64" 128 ]; 129 static = [ "**/*.a" ]; 130 sample = [ "samples" ]; 131 python = [ "**/*.whl" ]; 132 }; 133 134 # Useful for introspecting why something went wrong. Maps descriptions of why the derivation would be marked as 135 # broken on have badPlatforms include the current platform. 136 137 # brokenConditions :: AttrSet Bool 138 # Sets `meta.broken = true` if any of the conditions are true. 139 # Example: Broken on a specific version of CUDA or when a dependency has a specific version. 140 brokenConditions = { 141 # Unclear how this is handled by Nix internals. 142 "Duplicate entries in outputs" = finalAttrs.outputs != lists.unique finalAttrs.outputs; 143 # Typically this results in the static output being empty, as all libraries are moved 144 # back to the lib output. 145 "lib output follows static output" = 146 let 147 libIndex = lists.findFirstIndex (x: x == "lib") null finalAttrs.outputs; 148 staticIndex = lists.findFirstIndex (x: x == "static") null finalAttrs.outputs; 149 in 150 libIndex != null && staticIndex != null && libIndex > staticIndex; 151 }; 152 153 # badPlatformsConditions :: AttrSet Bool 154 # Sets `meta.badPlatforms = meta.platforms` if any of the conditions are true. 155 # Example: Broken on a specific architecture when some condition is met (like targeting Jetson). 156 badPlatformsConditions = { 157 "No source" = !sourceMatchesHost; 158 }; 159 160 # src :: Optional Derivation 161 # If redistSystem doesn't exist in redistribRelease, return null. 162 src = trivial.mapNullable ( 163 { relative_path, sha256, ... }: 164 fetchurl { 165 url = "https://developer.download.nvidia.com/compute/${redistName}/redist/${relative_path}"; 166 inherit sha256; 167 } 168 ) (redistribRelease.${redistSystem} or null); 169 170 postPatch = 171 # Pkg-config's setup hook expects configuration files in $out/share/pkgconfig 172 '' 173 for path in pkg-config pkgconfig; do 174 [[ -d "$path" ]] || continue 175 mkdir -p share/pkgconfig 176 mv "$path"/* share/pkgconfig/ 177 rmdir "$path" 178 done 179 '' 180 # Rewrite FHS paths with store paths 181 # NOTE: output* fall back to out if the corresponding output isn't defined. 182 + '' 183 for pc in share/pkgconfig/*.pc; do 184 sed -i \ 185 -e "s|^cudaroot\s*=.*\$|cudaroot=''${!outputDev}|" \ 186 -e "s|^libdir\s*=.*/lib\$|libdir=''${!outputLib}/lib|" \ 187 -e "s|^includedir\s*=.*/include\$|includedir=''${!outputDev}/include|" \ 188 "$pc" 189 done 190 '' 191 # Generate unversioned names. 192 # E.g. cuda-11.8.pc -> cuda.pc 193 + '' 194 for pc in share/pkgconfig/*-"$majorMinorVersion.pc"; do 195 ln -s "$(basename "$pc")" "''${pc%-$majorMinorVersion.pc}".pc 196 done 197 ''; 198 199 env.majorMinorVersion = cudaMajorMinorVersion; 200 201 # We do need some other phases, like configurePhase, so the multiple-output setup hook works. 202 dontBuild = true; 203 204 nativeBuildInputs = [ 205 autoPatchelfHook 206 # This hook will make sure libcuda can be found 207 # in typically /lib/opengl-driver by adding that 208 # directory to the rpath of all ELF binaries. 209 # Check e.g. with `patchelf --print-rpath path/to/my/binary 210 autoAddDriverRunpath 211 markForCudatoolkitRootHook 212 ] 213 # autoAddCudaCompatRunpath depends on cuda_compat and would cause 214 # infinite recursion if applied to `cuda_compat` itself (beside the fact 215 # that it doesn't make sense in the first place) 216 ++ lib.optionals (pname != "cuda_compat" && flags.isJetsonBuild) [ 217 # autoAddCudaCompatRunpath must appear AFTER autoAddDriverRunpath. 218 # See its documentation in ./setup-hooks/extension.nix. 219 autoAddCudaCompatRunpath 220 ]; 221 222 buildInputs = [ 223 # autoPatchelfHook will search for a libstdc++ and we're giving it 224 # one that is compatible with the rest of nixpkgs, even when 225 # nvcc forces us to use an older gcc 226 # NB: We don't actually know if this is the right thing to do 227 (lib.getLib stdenv.cc.cc) 228 ]; 229 230 # Picked up by autoPatchelf 231 # Needed e.g. for libnvrtc to locate (dlopen) libnvrtc-builtins 232 appendRunpaths = [ "$ORIGIN" ]; 233 234 # NOTE: We don't need to check for dev or doc, because those outputs are handled by 235 # the multiple-outputs setup hook. 236 # NOTE: moveToOutput operates on all outputs: 237 # https://github.com/NixOS/nixpkgs/blob/2920b6fc16a9ed5d51429e94238b28306ceda79e/pkgs/build-support/setup-hooks/multiple-outputs.sh#L105-L107 238 installPhase = 239 let 240 mkMoveToOutputCommand = 241 output: 242 let 243 template = pattern: ''moveToOutput "${pattern}" "${"$" + output}"''; 244 patterns = finalAttrs.outputToPatterns.${output} or [ ]; 245 in 246 strings.concatMapStringsSep "\n" template patterns; 247 in 248 # Pre-install hook 249 '' 250 runHook preInstall 251 '' 252 # Handle the existence of libPath, which requires us to re-arrange the lib directory 253 + strings.optionalString (libPath != null) '' 254 full_lib_path="lib/${libPath}" 255 if [[ ! -d "$full_lib_path" ]]; then 256 echo "${finalAttrs.pname}: '$full_lib_path' does not exist, only found:" >&2 257 find lib/ -mindepth 1 -maxdepth 1 >&2 258 echo "This release might not support your CUDA version" >&2 259 exit 1 260 fi 261 echo "Making libPath '$full_lib_path' the root of lib" >&2 262 mv "$full_lib_path" lib_new 263 rm -r lib 264 mv lib_new lib 265 '' 266 # Create the primary output, out, and move the other outputs into it. 267 + '' 268 mkdir -p "$out" 269 mv * "$out" 270 '' 271 # Move the outputs into their respective outputs. 272 + strings.concatMapStringsSep "\n" mkMoveToOutputCommand (builtins.tail finalAttrs.outputs) 273 # Add a newline to the end of the installPhase, so that the post-install hook doesn't 274 # get concatenated with the last moveToOutput command. 275 + "\n" 276 # Post-install hook 277 + '' 278 runHook postInstall 279 ''; 280 281 doInstallCheck = true; 282 allowFHSReferences = true; # TODO: Default to `false` 283 postInstallCheck = '' 284 echo "Executing postInstallCheck" 285 286 if [[ -z "''${allowFHSReferences-}" ]]; then 287 mapfile -t outputPaths < <(for o in $(getAllOutputNames); do echo "''${!o}"; done) 288 if grep --max-count=5 --recursive --exclude=LICENSE /usr/ "''${outputPaths[@]}"; then 289 echo "Detected references to /usr" >&2 290 exit 1 291 fi 292 fi 293 ''; 294 295 # libcuda needs to be resolved during runtime 296 autoPatchelfIgnoreMissingDeps = [ 297 "libcuda.so" 298 "libcuda.so.*" 299 ]; 300 301 # _multioutPropagateDev() currently expects a space-separated string rather than an array 302 preFixup = '' 303 export propagatedBuildOutputs="''${propagatedBuildOutputs[@]}" 304 ''; 305 306 # Propagate all outputs, including `static` 307 propagatedBuildOutputs = builtins.filter (x: x != "dev") finalAttrs.outputs; 308 309 # Kept in case overrides assume postPhases have already been defined 310 postPhases = [ "postPatchelf" ]; 311 postPatchelf = '' 312 true 313 ''; 314 315 passthru = { 316 # Provide access to the release information for fixup functions. 317 inherit redistribRelease featureRelease; 318 # Make the CUDA-patched stdenv available 319 stdenv = backendStdenv; 320 }; 321 322 meta = { 323 description = "${redistribRelease.name}. By downloading and using the packages you accept the terms and conditions of the ${finalAttrs.meta.license.shortName}"; 324 sourceProvenance = [ sourceTypes.binaryNativeCode ]; 325 broken = lists.any trivial.id (attrsets.attrValues finalAttrs.brokenConditions); 326 platforms = trivial.pipe supportedRedistSystems [ 327 # Map each redist system to the equivalent nix systems. 328 (lib.concatMap _cuda.lib.getNixSystems) 329 # Take all the unique values. 330 lib.unique 331 # Sort the list. 332 lib.naturalSort 333 ]; 334 badPlatforms = 335 let 336 isBadPlatform = lists.any trivial.id (attrsets.attrValues finalAttrs.badPlatformsConditions); 337 in 338 lists.optionals isBadPlatform finalAttrs.meta.platforms; 339 license = 340 if redistName == "cuda" then 341 # Add the package-specific license. 342 let 343 licensePath = 344 if redistribRelease.license_path != null then 345 redistribRelease.license_path 346 else 347 "${pname}/LICENSE.txt"; 348 url = "https://developer.download.nvidia.com/compute/cuda/redist/${licensePath}"; 349 in 350 lib.licenses.nvidiaCudaRedist // { inherit url; } 351 else 352 licenses.unfree; 353 teams = [ teams.cuda ]; 354 }; 355})).overrideAttrs 356 fixup