Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
at gcc-offload 454 lines 14 kB view raw
1# Generic builder. 2 3{ 4 lib, 5 config, 6 python, 7 wrapPython, 8 unzip, 9 ensureNewerSourcesForZipFilesHook, 10 # Whether the derivation provides a Python module or not. 11 toPythonModule, 12 namePrefix, 13 update-python-libraries, 14 setuptools, 15 pypaBuildHook, 16 pypaInstallHook, 17 pythonCatchConflictsHook, 18 pythonImportsCheckHook, 19 pythonNamespacesHook, 20 pythonOutputDistHook, 21 pythonRelaxDepsHook, 22 pythonRemoveBinBytecodeHook, 23 pythonRemoveTestsDirHook, 24 pythonRuntimeDepsCheckHook, 25 setuptoolsBuildHook, 26 wheelUnpackHook, 27 eggUnpackHook, 28 eggBuildHook, 29 eggInstallHook, 30}: 31 32let 33 inherit (builtins) unsafeGetAttrPos; 34 inherit (lib) 35 elem 36 optionalString 37 max 38 stringLength 39 fixedWidthString 40 getName 41 optional 42 optionals 43 optionalAttrs 44 hasSuffix 45 escapeShellArgs 46 extendDerivation 47 head 48 splitString 49 isBool 50 ; 51 52 leftPadName = 53 name: against: 54 let 55 len = max (stringLength name) (stringLength against); 56 in 57 fixedWidthString len " " name; 58 59 isPythonModule = 60 drv: 61 # all pythonModules have the pythonModule attribute 62 (drv ? "pythonModule") 63 # Some pythonModules are turned in to a pythonApplication by setting the field to false 64 && (!isBool drv.pythonModule); 65 66 isMismatchedPython = drv: drv.pythonModule != python; 67 68 withDistOutput' = lib.flip elem [ 69 "pyproject" 70 "setuptools" 71 "wheel" 72 ]; 73 74 isBootstrapInstallPackage' = lib.flip elem [ 75 "flit-core" 76 "installer" 77 ]; 78 79 isBootstrapPackage' = lib.flip elem ( 80 [ 81 "build" 82 "packaging" 83 "pyproject-hooks" 84 "wheel" 85 ] 86 ++ optionals (python.pythonOlder "3.11") [ 87 "tomli" 88 ] 89 ); 90 91 isSetuptoolsDependency' = lib.flip elem [ 92 "setuptools" 93 "wheel" 94 ]; 95 96 cleanAttrs = lib.flip removeAttrs [ 97 "disabled" 98 "checkPhase" 99 "checkInputs" 100 "nativeCheckInputs" 101 "doCheck" 102 "doInstallCheck" 103 "dontWrapPythonPrograms" 104 "catchConflicts" 105 "pyproject" 106 "format" 107 "disabledTestPaths" 108 "disabledTests" 109 "pytestFlagsArray" 110 "unittestFlagsArray" 111 "outputs" 112 "stdenv" 113 "dependencies" 114 "optional-dependencies" 115 "build-system" 116 ]; 117 118in 119 120{ 121 name ? "${attrs.pname}-${attrs.version}", 122 123 # Build-time dependencies for the package 124 nativeBuildInputs ? [ ], 125 126 # Run-time dependencies for the package 127 buildInputs ? [ ], 128 129 # Dependencies needed for running the checkPhase. 130 # These are added to buildInputs when doCheck = true. 131 checkInputs ? [ ], 132 nativeCheckInputs ? [ ], 133 134 # propagate build dependencies so in case we have A -> B -> C, 135 # C can import package A propagated by B 136 propagatedBuildInputs ? [ ], 137 138 # Python module dependencies. 139 # These are named after PEP-621. 140 dependencies ? [ ], 141 optional-dependencies ? { }, 142 143 # Python PEP-517 build systems. 144 build-system ? [ ], 145 146 # DEPRECATED: use propagatedBuildInputs 147 pythonPath ? [ ], 148 149 # Enabled to detect some (native)BuildInputs mistakes 150 strictDeps ? true, 151 152 outputs ? [ "out" ], 153 154 # used to disable derivation, useful for specific python versions 155 disabled ? false, 156 157 # Raise an error if two packages are installed with the same name 158 # TODO: For cross we probably need a different PYTHONPATH, or not 159 # add the runtime deps until after buildPhase. 160 catchConflicts ? (python.stdenv.hostPlatform == python.stdenv.buildPlatform), 161 162 # Additional arguments to pass to the makeWrapper function, which wraps 163 # generated binaries. 164 makeWrapperArgs ? [ ], 165 166 # Skip wrapping of python programs altogether 167 dontWrapPythonPrograms ? false, 168 169 # Don't use Pip to install a wheel 170 # Note this is actually a variable for the pipInstallPhase in pip's setupHook. 171 # It's included here to prevent an infinite recursion. 172 dontUsePipInstall ? false, 173 174 # Skip setting the PYTHONNOUSERSITE environment variable in wrapped programs 175 permitUserSite ? false, 176 177 # Remove bytecode from bin folder. 178 # When a Python script has the extension `.py`, bytecode is generated 179 # Typically, executables in bin have no extension, so no bytecode is generated. 180 # However, some packages do provide executables with extensions, and thus bytecode is generated. 181 removeBinBytecode ? true, 182 183 # pyproject = true <-> format = "pyproject" 184 # pyproject = false <-> format = "other" 185 # https://github.com/NixOS/nixpkgs/issues/253154 186 pyproject ? null, 187 188 # Several package formats are supported. 189 # "setuptools" : Install a common setuptools/distutils based package. This builds a wheel. 190 # "wheel" : Install from a pre-compiled wheel. 191 # "pyproject": Install a package using a ``pyproject.toml`` file (PEP517). This builds a wheel. 192 # "egg": Install a package from an egg. 193 # "other" : Provide your own buildPhase and installPhase. 194 format ? null, 195 196 meta ? { }, 197 198 doCheck ? true, 199 200 disabledTestPaths ? [ ], 201 202 # Allow passing in a custom stdenv to buildPython* 203 stdenv ? python.stdenv, 204 205 ... 206}@attrs: 207 208assert (pyproject != null) -> (format == null); 209 210let 211 format' = 212 if pyproject != null then 213 if pyproject then "pyproject" else "other" 214 else if format != null then 215 format 216 else 217 "setuptools"; 218 219 withDistOutput = withDistOutput' format'; 220 221 validatePythonMatches = 222 let 223 throwMismatch = 224 attrName: drv: 225 let 226 myName = "'${namePrefix}${name}'"; 227 theirName = "'${drv.name}'"; 228 optionalLocation = 229 let 230 pos = unsafeGetAttrPos (if attrs ? "pname" then "pname" else "name") attrs; 231 in 232 optionalString (pos != null) " at ${pos.file}:${toString pos.line}:${toString pos.column}"; 233 in 234 throw '' 235 Python version mismatch in ${myName}: 236 237 The Python derivation ${myName} depends on a Python derivation 238 named ${theirName}, but the two derivations use different versions 239 of Python: 240 241 ${leftPadName myName theirName} uses ${python} 242 ${leftPadName theirName myName} uses ${toString drv.pythonModule} 243 244 Possible solutions: 245 246 * If ${theirName} is a Python library, change the reference to ${theirName} 247 in the ${attrName} of ${myName} to use a ${theirName} built from the same 248 version of Python 249 250 * If ${theirName} is used as a tool during the build, move the reference to 251 ${theirName} in ${myName} from ${attrName} to nativeBuildInputs 252 253 * If ${theirName} provides executables that are called at run time, pass its 254 bin path to makeWrapperArgs: 255 256 makeWrapperArgs = [ "--prefix PATH : ''${lib.makeBinPath [ ${getName drv} ] }" ]; 257 258 ${optionalLocation} 259 ''; 260 261 checkDrv = 262 attrName: drv: 263 if (isPythonModule drv) && (isMismatchedPython drv) then throwMismatch attrName drv else drv; 264 265 in 266 attrName: inputs: map (checkDrv attrName) inputs; 267 268 isBootstrapInstallPackage = isBootstrapInstallPackage' (attrs.pname or null); 269 270 isBootstrapPackage = isBootstrapInstallPackage || isBootstrapPackage' (attrs.pname or null); 271 272 isSetuptoolsDependency = isSetuptoolsDependency' (attrs.pname or null); 273 274 # Keep extra attributes from `attrs`, e.g., `patchPhase', etc. 275 self = toPythonModule ( 276 stdenv.mkDerivation ( 277 (cleanAttrs attrs) 278 // { 279 280 name = namePrefix + name; 281 282 nativeBuildInputs = 283 [ 284 python 285 wrapPython 286 ensureNewerSourcesForZipFilesHook # move to wheel installer (pip) or builder (setuptools, flit, ...)? 287 pythonRemoveTestsDirHook 288 ] 289 ++ optionals (catchConflicts && !isBootstrapPackage && !isSetuptoolsDependency) [ 290 # 291 # 1. When building a package that is also part of the bootstrap chain, we 292 # must ignore conflicts after installation, because there will be one with 293 # the package in the bootstrap. 294 # 295 # 2. When a package is a dependency of setuptools, we must ignore conflicts 296 # because the hook that checks for conflicts uses setuptools. 297 # 298 pythonCatchConflictsHook 299 ] 300 ++ optionals (attrs ? pythonRelaxDeps || attrs ? pythonRemoveDeps) [ 301 pythonRelaxDepsHook 302 ] 303 ++ optionals removeBinBytecode [ 304 pythonRemoveBinBytecodeHook 305 ] 306 ++ optionals (hasSuffix "zip" (attrs.src.name or "")) [ 307 unzip 308 ] 309 ++ optionals (format' == "setuptools") [ 310 setuptoolsBuildHook 311 ] 312 ++ optionals (format' == "pyproject") [ 313 ( 314 if isBootstrapPackage then 315 pypaBuildHook.override { 316 inherit (python.pythonOnBuildForHost.pkgs.bootstrap) build; 317 wheel = null; 318 } 319 else 320 pypaBuildHook 321 ) 322 ( 323 if isBootstrapPackage then 324 pythonRuntimeDepsCheckHook.override { 325 inherit (python.pythonOnBuildForHost.pkgs.bootstrap) packaging; 326 } 327 else 328 pythonRuntimeDepsCheckHook 329 ) 330 ] 331 ++ optionals (format' == "wheel") [ 332 wheelUnpackHook 333 ] 334 ++ optionals (format' == "egg") [ 335 eggUnpackHook 336 eggBuildHook 337 eggInstallHook 338 ] 339 ++ optionals (format' != "other") [ 340 ( 341 if isBootstrapInstallPackage then 342 pypaInstallHook.override { 343 inherit (python.pythonOnBuildForHost.pkgs.bootstrap) installer; 344 } 345 else 346 pypaInstallHook 347 ) 348 ] 349 ++ optionals (stdenv.buildPlatform == stdenv.hostPlatform) [ 350 # This is a test, however, it should be ran independent of the checkPhase and checkInputs 351 pythonImportsCheckHook 352 ] 353 ++ optionals (python.pythonAtLeast "3.3") [ 354 # Optionally enforce PEP420 for python3 355 pythonNamespacesHook 356 ] 357 ++ optionals withDistOutput [ 358 pythonOutputDistHook 359 ] 360 ++ nativeBuildInputs 361 ++ build-system; 362 363 buildInputs = validatePythonMatches "buildInputs" (buildInputs ++ pythonPath); 364 365 propagatedBuildInputs = validatePythonMatches "propagatedBuildInputs" ( 366 propagatedBuildInputs 367 ++ dependencies 368 ++ [ 369 # we propagate python even for packages transformed with 'toPythonApplication' 370 # this pollutes the PATH but avoids rebuilds 371 # see https://github.com/NixOS/nixpkgs/issues/170887 for more context 372 python 373 ] 374 ); 375 376 inherit strictDeps; 377 378 LANG = "${if python.stdenv.hostPlatform.isDarwin then "en_US" else "C"}.UTF-8"; 379 380 # Python packages don't have a checkPhase, only an installCheckPhase 381 doCheck = false; 382 doInstallCheck = attrs.doCheck or true; 383 nativeInstallCheckInputs = nativeCheckInputs; 384 installCheckInputs = checkInputs; 385 386 postFixup = 387 optionalString (!dontWrapPythonPrograms) '' 388 wrapPythonPrograms 389 '' 390 + attrs.postFixup or ""; 391 392 # Python packages built through cross-compilation are always for the host platform. 393 disallowedReferences = optionals (python.stdenv.hostPlatform != python.stdenv.buildPlatform) [ 394 python.pythonOnBuildForHost 395 ]; 396 397 outputs = outputs ++ optional withDistOutput "dist"; 398 399 passthru = 400 attrs.passthru or { } 401 // { 402 updateScript = 403 let 404 filename = head (splitString ":" self.meta.position); 405 in 406 attrs.passthru.updateScript or [ 407 update-python-libraries 408 filename 409 ]; 410 } 411 // optionalAttrs (dependencies != [ ]) { 412 inherit dependencies; 413 } 414 // optionalAttrs (optional-dependencies != { }) { 415 inherit optional-dependencies; 416 } 417 // optionalAttrs (build-system != [ ]) { 418 inherit build-system; 419 }; 420 421 meta = { 422 # default to python's platforms 423 platforms = python.meta.platforms; 424 isBuildPythonPackage = python.meta.platforms; 425 } // meta; 426 } 427 // optionalAttrs (attrs ? checkPhase) { 428 # If given use the specified checkPhase, otherwise use the setup hook. 429 # Longer-term we should get rid of `checkPhase` and use `installCheckPhase`. 430 installCheckPhase = attrs.checkPhase; 431 } 432 // optionalAttrs (attrs.doCheck or true) ( 433 optionalAttrs (disabledTestPaths != [ ]) { 434 disabledTestPaths = escapeShellArgs disabledTestPaths; 435 } 436 // optionalAttrs (attrs ? disabledTests) { 437 # `escapeShellArgs` should be used as well as `disabledTestPaths`, 438 # but some packages rely on existing raw strings. 439 disabledTests = attrs.disabledTests; 440 } 441 // optionalAttrs (attrs ? pytestFlagsArray) { 442 pytestFlagsArray = attrs.pytestFlagsArray; 443 } 444 // optionalAttrs (attrs ? unittestFlagsArray) { 445 unittestFlagsArray = attrs.unittestFlagsArray; 446 } 447 ) 448 ) 449 ); 450 451in 452extendDerivation ( 453 disabled -> throw "${name} not supported for interpreter ${python.executable}" 454) { } self