1{ 2 lib, 3 stdenv, 4 fetchurl, 5 fetchpatch, 6 fetchgit, 7 8 # build dependencies 9 autoconf-archive, 10 autoreconfHook, 11 nukeReferences, 12 pkg-config, 13 python-setup-hook, 14 15 # runtime dependencies 16 bzip2, 17 expat, 18 libffi, 19 libuuid, 20 libxcrypt, 21 mpdecimal, 22 ncurses, 23 openssl, 24 sqlite, 25 xz, 26 zlib, 27 28 # platform-specific dependencies 29 bashNonInteractive, 30 windows, 31 32 # optional dependencies 33 bluezSupport ? false, 34 bluez, 35 mimetypesSupport ? true, 36 mailcap, 37 tzdata, 38 withGdbm ? !stdenv.hostPlatform.isWindows, 39 gdbm, 40 withReadline ? !stdenv.hostPlatform.isWindows, 41 readline, 42 x11Support ? false, 43 tcl, 44 tk, 45 tclPackages, 46 libX11, 47 xorgproto, 48 49 # splicing/cross 50 pythonAttr ? "python${sourceVersion.major}${sourceVersion.minor}", 51 self, 52 pkgsBuildBuild, 53 pkgsBuildHost, 54 pkgsBuildTarget, 55 pkgsHostHost, 56 pkgsTargetTarget, 57 __splices ? { }, 58 59 # build customization 60 sourceVersion, 61 hash, 62 passthruFun, 63 stripConfig ? false, 64 stripIdlelib ? false, 65 stripTests ? false, 66 stripTkinter ? false, 67 rebuildBytecode ? true, 68 stripBytecode ? true, 69 includeSiteCustomize ? true, 70 static ? stdenv.hostPlatform.isStatic, 71 enableFramework ? false, 72 noldconfigPatch ? ./. + "/${sourceVersion.major}.${sourceVersion.minor}/no-ldconfig.patch", 73 enableGIL ? true, 74 75 # pgo (not reproducible) + -fno-semantic-interposition 76 # https://docs.python.org/3/using/configure.html#cmdoption-enable-optimizations 77 enableOptimizations ? false, 78 79 # improves performance, but remains reproducible 80 enableNoSemanticInterposition ? true, 81 82 # enabling LTO on 32bit arch causes downstream packages to fail when linking 83 enableLTO ? 84 stdenv.hostPlatform.isDarwin || (stdenv.hostPlatform.is64bit && stdenv.hostPlatform.isLinux), 85 86 # enable asserts to ensure the build remains reproducible 87 reproducibleBuild ? false, 88 89 # for the Python package set 90 packageOverrides ? (self: super: { }), 91 92 # tests 93 testers, 94 95}@inputs: 96 97# Note: this package is used for bootstrapping fetchurl, and thus 98# cannot use fetchpatch! All mutable patches (generated by GitHub or 99# cgit) that are needed here should be included directly in Nixpkgs as 100# files. 101 102assert x11Support -> tcl != null && tk != null && xorgproto != null && libX11 != null; 103 104assert bluezSupport -> bluez != null; 105 106assert lib.assertMsg ( 107 enableFramework -> stdenv.hostPlatform.isDarwin 108) "Framework builds are only supported on Darwin."; 109 110assert lib.assertMsg ( 111 reproducibleBuild -> stripBytecode 112) "Deterministic builds require stripping bytecode."; 113 114assert lib.assertMsg ( 115 reproducibleBuild -> (!enableOptimizations) 116) "Deterministic builds are not achieved when optimizations are enabled."; 117 118assert lib.assertMsg ( 119 reproducibleBuild -> (!rebuildBytecode) 120) "Deterministic builds are not achieved when (default unoptimized) bytecode is created."; 121 122let 123 inherit (lib) 124 concatMapStringsSep 125 concatStringsSep 126 enableFeature 127 getDev 128 getLib 129 optionals 130 optionalString 131 replaceStrings 132 versionOlder 133 ; 134 135 # mixes libc and libxcrypt headers and libs and causes segfaults on importing crypt 136 libxcrypt = if stdenv.hostPlatform.isFreeBSD then null else inputs.libxcrypt; 137 138 buildPackages = pkgsBuildHost; 139 inherit (passthru) pythonOnBuildForHost; 140 141 tzdataSupport = tzdata != null && passthru.pythonAtLeast "3.9"; 142 143 passthru = 144 let 145 # When we override the interpreter we also need to override the spliced versions of the interpreter 146 # bluez is excluded manually to break an infinite recursion. 147 inputs' = lib.filterAttrs (n: v: n != "bluez" && n != "passthruFun" && !lib.isDerivation v) inputs; 148 # Memoization of the splices to avoid re-evaluating this function for all combinations of splices e.g. 149 # python3.pythonOnBuildForHost.pythonOnBuildForTarget == python3.pythonOnBuildForTarget by consuming 150 # __splices as an arg and using the cache if populated. 151 splices = { 152 pythonOnBuildForBuild = override pkgsBuildBuild.${pythonAttr}; 153 pythonOnBuildForHost = override pkgsBuildHost.${pythonAttr}; 154 pythonOnBuildForTarget = override pkgsBuildTarget.${pythonAttr}; 155 pythonOnHostForHost = override pkgsHostHost.${pythonAttr}; 156 pythonOnTargetForTarget = lib.optionalAttrs (lib.hasAttr pythonAttr pkgsTargetTarget) ( 157 override pkgsTargetTarget.${pythonAttr} 158 ); 159 } // __splices; 160 override = 161 attr: 162 let 163 python = attr.override ( 164 inputs' 165 // { 166 self = python; 167 __splices = splices; 168 } 169 ); 170 in 171 python; 172 in 173 passthruFun rec { 174 inherit self sourceVersion packageOverrides; 175 implementation = "cpython"; 176 libPrefix = "python${pythonVersion}${lib.optionalString (!enableGIL) "t"}"; 177 executable = libPrefix; 178 pythonVersion = with sourceVersion; "${major}.${minor}"; 179 sitePackages = "lib/${libPrefix}/site-packages"; 180 inherit hasDistutilsCxxPatch pythonAttr; 181 inherit (splices) 182 pythonOnBuildForBuild 183 pythonOnBuildForHost 184 pythonOnBuildForTarget 185 pythonOnHostForHost 186 pythonOnTargetForTarget 187 ; 188 }; 189 190 version = with sourceVersion; "${major}.${minor}.${patch}${suffix}"; 191 192 nativeBuildInputs = 193 [ 194 nukeReferences 195 ] 196 ++ optionals (!stdenv.hostPlatform.isDarwin) [ 197 autoconf-archive # needed for AX_CHECK_COMPILE_FLAG 198 autoreconfHook 199 pkg-config 200 ] 201 ++ optionals (stdenv.hostPlatform != stdenv.buildPlatform) [ 202 buildPackages.stdenv.cc 203 pythonOnBuildForHost 204 ] 205 ++ 206 optionals 207 ( 208 stdenv.cc.isClang 209 && (!stdenv.hostPlatform.useAndroidPrebuilt or false) 210 && (enableLTO || enableOptimizations) 211 ) 212 [ 213 stdenv.cc.cc.libllvm.out 214 ]; 215 216 buildInputs = lib.filter (p: p != null) ( 217 [ 218 bzip2 219 expat 220 libffi 221 libuuid 222 libxcrypt 223 mpdecimal 224 ncurses 225 openssl 226 sqlite 227 xz 228 zlib 229 ] 230 ++ optionals bluezSupport [ 231 bluez 232 ] 233 ++ optionals stdenv.hostPlatform.isMinGW [ 234 windows.dlfcn 235 windows.mingw_w64_pthreads 236 ] 237 ++ optionals tzdataSupport [ 238 tzdata 239 ] 240 ++ optionals withGdbm [ 241 gdbm 242 ] 243 ++ optionals withReadline [ 244 readline 245 ] 246 ++ optionals x11Support [ 247 libX11 248 tcl 249 tk 250 xorgproto 251 ] 252 ); 253 254 hasDistutilsCxxPatch = !(stdenv.cc.isGNU or false); 255 256 pythonOnBuildForHostInterpreter = 257 if stdenv.hostPlatform == stdenv.buildPlatform then 258 "$out/bin/python" 259 else 260 pythonOnBuildForHost.interpreter; 261 262 src = fetchurl { 263 url = 264 with sourceVersion; 265 "https://www.python.org/ftp/python/${major}.${minor}.${patch}/Python-${version}.tar.xz"; 266 inherit hash; 267 }; 268 269 # win32 is added by Fedora’s patch 270 machdep = if stdenv.hostPlatform.isWindows then "win32" else stdenv.hostPlatform.parsed.kernel.name; 271 272 # https://github.com/python/cpython/blob/e488e300f5c01289c10906c2e53a8e43d6de32d8/configure.ac#L428 273 # The configure script uses "arm" as the CPU name for all 32-bit ARM 274 # variants when cross-compiling, but native builds include the version 275 # suffix, so we do the same. 276 pythonHostPlatform = 277 let 278 cpu = 279 { 280 # According to PEP600, Python's name for the Power PC 281 # architecture is "ppc", not "powerpc". Without the Rosetta 282 # Stone below, the PEP600 requirement that "${ARCH} matches 283 # the return value from distutils.util.get_platform()" fails. 284 # https://peps.python.org/pep-0600/ 285 powerpc = "ppc"; 286 powerpcle = "ppcle"; 287 powerpc64 = "ppc64"; 288 powerpc64le = "ppc64le"; 289 } 290 .${stdenv.hostPlatform.parsed.cpu.name} or stdenv.hostPlatform.parsed.cpu.name; 291 in 292 "${machdep}-${cpu}"; 293 294 execSuffix = stdenv.hostPlatform.extensions.executable; 295in 296with passthru; 297stdenv.mkDerivation (finalAttrs: { 298 pname = "python3"; 299 inherit src version; 300 301 inherit nativeBuildInputs; 302 buildInputs = 303 lib.optionals (!stdenv.hostPlatform.isWindows) [ 304 bashNonInteractive # only required for patchShebangs 305 ] 306 ++ buildInputs; 307 308 prePatch = optionalString stdenv.hostPlatform.isDarwin '' 309 substituteInPlace configure --replace-fail '`/usr/bin/arch`' '"i386"' 310 ''; 311 312 patches = 313 [ 314 # Disable the use of ldconfig in ctypes.util.find_library (since 315 # ldconfig doesn't work on NixOS), and don't use 316 # ctypes.util.find_library during the loading of the uuid module 317 # (since it will do a futile invocation of gcc (!) to find 318 # libuuid, slowing down program startup a lot). 319 noldconfigPatch 320 ] 321 ++ optionals (stdenv.hostPlatform != stdenv.buildPlatform && stdenv.hostPlatform.isFreeBSD) [ 322 # Cross compilation only supports a limited number of "known good" 323 # configurations. If you're reading this and it's been a long time 324 # since this diff, consider submitting this patch upstream! 325 ./freebsd-cross.patch 326 ] 327 ++ optionals (pythonOlder "3.13") [ 328 # Make sure that the virtualenv activation scripts are 329 # owner-writable, so venvs can be recreated without permission 330 # errors. 331 ./virtualenv-permissions.patch 332 ] 333 ++ optionals (pythonAtLeast "3.13") [ 334 ./3.13/virtualenv-permissions.patch 335 ] 336 ++ optionals mimetypesSupport [ 337 # Make the mimetypes module refer to the right file 338 ./mimetypes.patch 339 ] 340 ++ optionals (pythonAtLeast "3.9" && pythonOlder "3.11" && stdenv.hostPlatform.isDarwin) [ 341 # Stop checking for TCL/TK in global macOS locations 342 ./3.9/darwin-tcl-tk.patch 343 ] 344 ++ optionals (hasDistutilsCxxPatch && pythonOlder "3.12") [ 345 # Fix for http://bugs.python.org/issue1222585 346 # Upstream distutils is calling C compiler to compile C++ code, which 347 # only works for GCC and Apple Clang. This makes distutils to call C++ 348 # compiler when needed. 349 ( 350 if pythonAtLeast "3.7" && pythonOlder "3.11" then 351 ./3.7/python-3.x-distutils-C++.patch 352 else if pythonAtLeast "3.11" then 353 ./3.11/python-3.x-distutils-C++.patch 354 else 355 fetchpatch { 356 url = "https://bugs.python.org/file48016/python-3.x-distutils-C++.patch"; 357 sha256 = "1h18lnpx539h5lfxyk379dxwr8m2raigcjixkf133l4xy3f4bzi2"; 358 } 359 ) 360 ] 361 ++ optionals (pythonAtLeast "3.7" && pythonOlder "3.12") [ 362 # LDSHARED now uses $CC instead of gcc. Fixes cross-compilation of extension modules. 363 ./3.8/0001-On-all-posix-systems-not-just-Darwin-set-LDSHARED-if.patch 364 # Use sysconfigdata to find headers. Fixes cross-compilation of extension modules. 365 ./3.7/fix-finding-headers-when-cross-compiling.patch 366 ] 367 ++ optionals (pythonOlder "3.12") [ 368 # https://github.com/python/cpython/issues/90656 369 ./loongarch-support.patch 370 # fix failing tests with openssl >= 3.4 371 # https://github.com/python/cpython/pull/127361 372 ] 373 ++ optionals (pythonAtLeast "3.11" && pythonOlder "3.13") [ 374 # backport fix for https://github.com/python/cpython/issues/95855 375 ./platform-triplet-detection.patch 376 ] 377 ++ optionals (stdenv.hostPlatform.isMinGW) ( 378 let 379 # https://src.fedoraproject.org/rpms/mingw-python3 380 mingw-patch = fetchgit { 381 name = "mingw-python-patches"; 382 url = "https://src.fedoraproject.org/rpms/mingw-python3.git"; 383 rev = "3edecdbfb4bbf1276d09cd5e80e9fb3dd88c9511"; # for python 3.11.9 at the time of writing. 384 hash = "sha256-kpXoIHlz53+0FAm/fK99ZBdNUg0u13erOr1XP2FSkQY="; 385 }; 386 in 387 (builtins.map (f: "${mingw-patch}/${f}") [ 388 # The other patches in that repo are already applied to 3.11.10 389 "mingw-python3_distutils.patch" 390 "mingw-python3_frozenmain.patch" 391 "mingw-python3_make-sysconfigdata.py-relocatable.patch" 392 "mingw-python3_mods-failed.patch" 393 "mingw-python3_module-select.patch" 394 "mingw-python3_module-socket.patch" 395 "mingw-python3_modules.patch" 396 "mingw-python3_platform-mingw.patch" 397 "mingw-python3_posix-layout.patch" 398 "mingw-python3_pthread_threadid.patch" 399 "mingw-python3_pythonw.patch" 400 "mingw-python3_setenv.patch" 401 "mingw-python3_win-modules.patch" 402 ]) 403 ); 404 405 postPatch = 406 optionalString (!stdenv.hostPlatform.isWindows) '' 407 substituteInPlace Lib/subprocess.py \ 408 --replace-fail "'/bin/sh'" "'${bashNonInteractive}/bin/sh'" 409 '' 410 + optionalString mimetypesSupport '' 411 substituteInPlace Lib/mimetypes.py \ 412 --replace-fail "@mime-types@" "${mailcap}" 413 '' 414 + optionalString (pythonOlder "3.13" && x11Support && ((tclPackages.tix or null) != null)) '' 415 substituteInPlace "Lib/tkinter/tix.py" --replace-fail \ 416 "os.environ.get('TIX_LIBRARY')" \ 417 "os.environ.get('TIX_LIBRARY') or '${tclPackages.tix}/lib'" 418 ''; 419 420 env = { 421 CPPFLAGS = concatStringsSep " " (map (p: "-I${getDev p}/include") buildInputs); 422 LDFLAGS = concatStringsSep " " (map (p: "-L${getLib p}/lib") buildInputs); 423 LIBS = "${optionalString (!stdenv.hostPlatform.isDarwin) "-lcrypt"}"; 424 NIX_LDFLAGS = lib.optionalString (stdenv.cc.isGNU && !stdenv.hostPlatform.isStatic) ( 425 { 426 "glibc" = "-lgcc_s"; 427 "musl" = "-lgcc_eh"; 428 } 429 ."${stdenv.hostPlatform.libc}" or "" 430 ); 431 # Determinism: We fix the hashes of str, bytes and datetime objects. 432 PYTHONHASHSEED = 0; 433 }; 434 435 # https://docs.python.org/3/using/configure.html 436 configureFlags = 437 [ 438 "--without-ensurepip" 439 "--with-system-expat" 440 "--with-system-libmpdec" 441 ] 442 ++ optionals (openssl != null) [ 443 "--with-openssl=${openssl.dev}" 444 ] 445 ++ optionals tzdataSupport [ 446 "--with-tzpath=${tzdata}/share/zoneinfo" 447 ] 448 ++ optionals (execSuffix != "") [ 449 "--with-suffix=${execSuffix}" 450 ] 451 ++ optionals enableLTO [ 452 "--with-lto" 453 ] 454 ++ optionals (!static && !enableFramework) [ 455 "--enable-shared" 456 ] 457 ++ optionals enableFramework [ 458 "--enable-framework=${placeholder "out"}/Library/Frameworks" 459 ] 460 ++ optionals (pythonAtLeast "3.13") [ 461 (enableFeature enableGIL "gil") 462 ] 463 ++ optionals enableOptimizations [ 464 "--enable-optimizations" 465 ] 466 ++ optionals (sqlite != null) [ 467 "--enable-loadable-sqlite-extensions" 468 ] 469 ++ optionals (libxcrypt != null) [ 470 "CFLAGS=-I${libxcrypt}/include" 471 "LIBS=-L${libxcrypt}/lib" 472 ] 473 ++ optionals (stdenv.hostPlatform != stdenv.buildPlatform) [ 474 "ac_cv_buggy_getaddrinfo=no" 475 # Assume little-endian IEEE 754 floating point when cross compiling 476 "ac_cv_little_endian_double=yes" 477 "ac_cv_big_endian_double=no" 478 "ac_cv_mixed_endian_double=no" 479 "ac_cv_x87_double_rounding=yes" 480 "ac_cv_tanh_preserves_zero_sign=yes" 481 # Generally assume that things are present and work 482 "ac_cv_posix_semaphores_enabled=yes" 483 "ac_cv_broken_sem_getvalue=no" 484 "ac_cv_wchar_t_signed=yes" 485 "ac_cv_rshift_extends_sign=yes" 486 "ac_cv_broken_nice=no" 487 "ac_cv_broken_poll=no" 488 "ac_cv_working_tzset=yes" 489 "ac_cv_have_long_long_format=yes" 490 "ac_cv_have_size_t_format=yes" 491 "ac_cv_computed_gotos=yes" 492 # Both fail when building for windows, normally configure checks this by itself but on other platforms this is set to yes always. 493 "ac_cv_file__dev_ptmx=${if stdenv.hostPlatform.isWindows then "no" else "yes"}" 494 "ac_cv_file__dev_ptc=${if stdenv.hostPlatform.isWindows then "no" else "yes"}" 495 ] 496 ++ optionals (stdenv.hostPlatform != stdenv.buildPlatform && pythonAtLeast "3.11") [ 497 "--with-build-python=${pythonOnBuildForHostInterpreter}" 498 ] 499 ++ optionals stdenv.hostPlatform.isLinux [ 500 # Never even try to use lchmod on linux, 501 # don't rely on detecting glibc-isms. 502 "ac_cv_func_lchmod=no" 503 ] 504 ++ optionals static [ 505 "LDFLAGS=-static" 506 "MODULE_BUILDTYPE=static" 507 ] 508 ++ optionals (stdenv.hostPlatform.isStatic && stdenv.hostPlatform.isMusl) [ 509 # dlopen is a no-op in static musl builds, and since we build everything without -fPIC it's better not to pretend. 510 "ac_cv_func_dlopen=no" 511 ]; 512 513 preConfigure = 514 '' 515 # Attempt to purify some of the host info collection 516 sed -E -i -e 's/uname -r/echo/g' -e 's/uname -n/echo nixpkgs/g' config.guess 517 sed -E -i -e 's/uname -r/echo/g' -e 's/uname -n/echo nixpkgs/g' configure 518 '' 519 + optionalString (pythonOlder "3.12") '' 520 # Improve purity 521 for path in /usr /sw /opt /pkg; do 522 substituteInPlace ./setup.py --replace-warn $path /no-such-path 523 done 524 '' 525 + optionalString (stdenv.hostPlatform.isDarwin && pythonOlder "3.12") '' 526 # Fix _ctypes module compilation 527 export NIX_CFLAGS_COMPILE+=" -DUSING_APPLE_OS_LIBFFI=1" 528 '' 529 + optionalString stdenv.hostPlatform.isDarwin '' 530 # Override the auto-detection in setup.py, which assumes a universal build 531 export PYTHON_DECIMAL_WITH_MACHINE=${if stdenv.hostPlatform.isAarch64 then "uint128" else "x64"} 532 # Ensure that modern platform features are enabled on Darwin in spite of having no version suffix. 533 sed -E -i -e 's|Darwin/\[12\]\[0-9\]\.\*|Darwin/*|' configure 534 '' 535 + optionalString (pythonAtLeast "3.11") '' 536 # Also override the auto-detection in `configure`. 537 substituteInPlace configure \ 538 --replace-fail 'libmpdec_machine=universal' 'libmpdec_machine=${ 539 if stdenv.hostPlatform.isAarch64 then "uint128" else "x64" 540 }' 541 '' 542 + optionalString (stdenv.hostPlatform.isDarwin && x11Support && pythonAtLeast "3.11") '' 543 export TCLTK_LIBS="-L${tcl}/lib -L${tk}/lib -l${tcl.libPrefix} -l${tk.libPrefix}" 544 export TCLTK_CFLAGS="-I${tcl}/include -I${tk}/include" 545 '' 546 + optionalString stdenv.hostPlatform.isWindows '' 547 export NIX_CFLAGS_COMPILE+=" -Wno-error=incompatible-pointer-types" 548 '' 549 + optionalString stdenv.hostPlatform.isMusl '' 550 export NIX_CFLAGS_COMPILE+=" -DTHREAD_STACK_SIZE=0x100000" 551 '' 552 + 553 554 # enableNoSemanticInterposition essentially sets that CFLAG -fno-semantic-interposition 555 # which changes how symbols are looked up. This essentially means we can't override 556 # libpython symbols via LD_PRELOAD anymore. This is common enough as every build 557 # that uses --enable-optimizations has the same "issue". 558 # 559 # The Fedora wiki has a good article about their journey towards enabling this flag: 560 # https://fedoraproject.org/wiki/Changes/PythonNoSemanticInterpositionSpeedup 561 optionalString enableNoSemanticInterposition '' 562 export CFLAGS_NODIST="-fno-semantic-interposition" 563 ''; 564 565 setupHook = python-setup-hook sitePackages; 566 567 postInstall = 568 let 569 # References *not* to nuke from (sys)config files 570 keep-references = concatMapStringsSep " " (val: "-e ${val}") ( 571 [ 572 (placeholder "out") 573 ] 574 ++ lib.optional (libxcrypt != null) libxcrypt 575 ++ lib.optional tzdataSupport tzdata 576 ); 577 in 578 lib.optionalString enableFramework '' 579 for dir in include lib share; do 580 ln -s $out/Library/Frameworks/Python.framework/Versions/Current/$dir $out/$dir 581 done 582 '' 583 + '' 584 # needed for some packages, especially packages that backport functionality 585 # to 2.x from 3.x 586 for item in $out/lib/${libPrefix}/test/*; do 587 if [[ "$item" != */test_support.py* 588 && "$item" != */test/support 589 && "$item" != */test/libregrtest 590 && "$item" != */test/regrtest.py* ]]; then 591 rm -rf "$item" 592 else 593 echo $item 594 fi 595 done 596 touch $out/lib/${libPrefix}/test/__init__.py 597 598 # Determinism: Windows installers were not deterministic. 599 # We're also not interested in building Windows installers. 600 find "$out" -name 'wininst*.exe' | xargs -r rm -f 601 602 # Use Python3 as default python 603 ln -s "$out/bin/idle3" "$out/bin/idle" 604 ln -s "$out/bin/pydoc3" "$out/bin/pydoc" 605 ln -s "$out/bin/python3${execSuffix}" "$out/bin/python${execSuffix}" 606 ln -s "$out/bin/python3-config" "$out/bin/python-config" 607 ln -s "$out/lib/pkgconfig/python3.pc" "$out/lib/pkgconfig/python.pc" 608 ln -sL "$out/share/man/man1/python3.1.gz" "$out/share/man/man1/python.1.gz" 609 610 # Get rid of retained dependencies on -dev packages, and remove 611 # some $TMPDIR references to improve binary reproducibility. 612 # Note that the .pyc file of _sysconfigdata.py should be regenerated! 613 for i in $out/lib/${libPrefix}/_sysconfigdata*.py $out/lib/${libPrefix}/config-${sourceVersion.major}${sourceVersion.minor}*/Makefile; do 614 sed -i $i -e "s|$TMPDIR|/no-such-path|g" 615 done 616 617 # Further get rid of references. https://github.com/NixOS/nixpkgs/issues/51668 618 find $out/lib/python*/config-* -type f -print -exec nuke-refs ${keep-references} '{}' + 619 find $out/lib -name '_sysconfigdata*.py*' -print -exec nuke-refs ${keep-references} '{}' + 620 621 # Make the sysconfigdata module accessible on PYTHONPATH 622 # This allows build Python to import host Python's sysconfigdata 623 mkdir -p "$out/${sitePackages}" 624 ln -s "$out/lib/${libPrefix}/"_sysconfigdata*.py "$out/${sitePackages}/" 625 '' 626 + optionalString (pythonAtLeast "3.14") '' 627 # Get rid of retained dependencies on -dev packages, and remove from _sysconfig_vars*.json introduced with Python3.14 628 for i in $out/lib/${libPrefix}/_sysconfig_vars*.json; do 629 sed -i $i -e "s|$TMPDIR|/no-such-path|g" 630 done 631 find $out/lib -name '_sysconfig_vars*.json*' -print -exec nuke-refs ${keep-references} '{}' + 632 ln -s "$out/lib/${libPrefix}/"_sysconfig_vars*.json "$out/${sitePackages}/" 633 '' 634 + optionalString stripConfig '' 635 rm -R $out/bin/python*-config $out/lib/python*/config-* 636 '' 637 + optionalString stripIdlelib '' 638 # Strip IDLE (and turtledemo, which uses it) 639 rm -R $out/bin/idle* $out/lib/python*/{idlelib,turtledemo} 640 '' 641 + optionalString stripTkinter '' 642 rm -R $out/lib/python*/tkinter 643 '' 644 + optionalString stripTests '' 645 # Strip tests 646 rm -R $out/lib/python*/test $out/lib/python*/**/test{,s} 647 '' 648 + optionalString includeSiteCustomize '' 649 # Include a sitecustomize.py file 650 cp ${../sitecustomize.py} $out/${sitePackages}/sitecustomize.py 651 '' 652 + optionalString stripBytecode '' 653 # Determinism: deterministic bytecode 654 # First we delete all old bytecode. 655 find $out -type d -name __pycache__ -print0 | xargs -0 -I {} rm -rf "{}" 656 '' 657 + optionalString rebuildBytecode '' 658 # Python 3.7 implements PEP 552, introducing support for deterministic bytecode. 659 # compileall uses the therein introduced checked-hash method by default when 660 # `SOURCE_DATE_EPOCH` is set. 661 # We exclude lib2to3 because that's Python 2 code which fails 662 # We build 3 levels of optimized bytecode. Note the default level, without optimizations, 663 # is not reproducible yet. https://bugs.python.org/issue29708 664 # Not creating bytecode will result in a large performance loss however, so we do build it. 665 find $out -name "*.py" | ${pythonOnBuildForHostInterpreter} -m compileall -q -f -x "lib2to3" -i - 666 find $out -name "*.py" | ${pythonOnBuildForHostInterpreter} -O -m compileall -q -f -x "lib2to3" -i - 667 find $out -name "*.py" | ${pythonOnBuildForHostInterpreter} -OO -m compileall -q -f -x "lib2to3" -i - 668 '' 669 + '' 670 # *strip* shebang from libpython gdb script - it should be dual-syntax and 671 # interpretable by whatever python the gdb in question is using, which may 672 # not even match the major version of this python. doing this after the 673 # bytecode compilations for the same reason - we don't want bytecode generated. 674 mkdir -p $out/share/gdb 675 sed '/^#!/d' Tools/gdb/libpython.py > $out/share/gdb/libpython.py 676 677 # Disable system-wide pip installation. See https://peps.python.org/pep-0668/. 678 cat <<'EXTERNALLY_MANAGED' > $out/lib/${libPrefix}/EXTERNALLY-MANAGED 679 [externally-managed] 680 Error=This command has been disabled as it tries to modify the immutable 681 `/nix/store` filesystem. 682 683 To use Python with Nix and nixpkgs, have a look at the online documentation: 684 <https://nixos.org/manual/nixpkgs/stable/#python>. 685 EXTERNALLY_MANAGED 686 '' 687 + optionalString stdenv.hostPlatform.isWindows '' 688 # Shebang files that link against the build python. Shebang dont work on windows 689 rm $out/bin/2to3* 690 rm $out/bin/idle* 691 rm $out/bin/pydoc* 692 693 echo linking DLLs for pythons compiled librairies 694 linkDLLsInfolder $out/lib/python*/lib-dynload/ 695 ''; 696 697 preFixup = lib.optionalString (stdenv.hostPlatform != stdenv.buildPlatform) '' 698 # Ensure patch-shebangs uses shebangs of host interpreter. 699 export PATH=${lib.makeBinPath [ "$out" ]}:$PATH 700 ''; 701 702 # Add CPython specific setup-hook that configures distutils.sysconfig to 703 # always load sysconfigdata from host Python. 704 postFixup = lib.optionalString (!stdenv.hostPlatform.isDarwin) '' 705 # https://github.com/python/cpython/blob/e488e300f5c01289c10906c2e53a8e43d6de32d8/configure.ac#L78 706 sysconfigdataName="$(make --eval $'print-sysconfigdata-name: 707 \t@echo _sysconfigdata_$(ABIFLAGS)_$(MACHDEP)_$(MULTIARCH) ' print-sysconfigdata-name)" 708 709 # The CPython interpreter contains a _sysconfigdata_<platform specific suffix> 710 # module that is imported by the sysconfig and distutils.sysconfig modules. 711 # The sysconfigdata module is generated at build time and contains settings 712 # required for building Python extension modules, such as include paths and 713 # other compiler flags. By default, the sysconfigdata module is loaded from 714 # the currently running interpreter (ie. the build platform interpreter), but 715 # when cross-compiling we want to load it from the host platform interpreter. 716 # This can be done using the _PYTHON_SYSCONFIGDATA_NAME environment variable. 717 # The _PYTHON_HOST_PLATFORM variable also needs to be set to get the correct 718 # platform suffix on extension modules. The correct values for these variables 719 # are not documented, and must be derived from the configure script (see links 720 # below). 721 cat <<EOF >> "$out/nix-support/setup-hook" 722 sysconfigdataHook() { 723 if [ "\$1" = '$out' ]; then 724 export _PYTHON_HOST_PLATFORM='${pythonHostPlatform}' 725 export _PYTHON_SYSCONFIGDATA_NAME='$sysconfigdataName' 726 fi 727 } 728 729 addEnvHooks "\$hostOffset" sysconfigdataHook 730 EOF 731 ''; 732 733 # Enforce that we don't have references to the OpenSSL -dev package, which we 734 # explicitly specify in our configure flags above. 735 disallowedReferences = 736 lib.optionals (openssl != null && !static && !enableFramework) [ 737 openssl.dev 738 ] 739 ++ lib.optionals (stdenv.hostPlatform != stdenv.buildPlatform) [ 740 # Ensure we don't have references to build-time packages. 741 # These typically end up in shebangs. 742 pythonOnBuildForHost 743 buildPackages.bashNonInteractive 744 ]; 745 746 separateDebugInfo = true; 747 748 passthru = passthru // { 749 doc = stdenv.mkDerivation { 750 inherit src; 751 name = "python${pythonVersion}-${version}-doc"; 752 753 postPatch = lib.optionalString (pythonAtLeast "3.9" && pythonOlder "3.11") '' 754 substituteInPlace Doc/tools/extensions/pyspecific.py \ 755 --replace-fail "from sphinx.util import status_iterator" "from sphinx.util.display import status_iterator" 756 ''; 757 758 dontConfigure = true; 759 760 dontBuild = true; 761 762 sphinxRoot = "Doc"; 763 764 postInstallSphinx = '' 765 mv $out/share/doc/* $out/share/doc/python${pythonVersion}-${version} 766 ''; 767 768 nativeBuildInputs = with pkgsBuildBuild.python3.pkgs; [ 769 sphinxHook 770 python-docs-theme 771 ]; 772 }; 773 774 tests = passthru.tests // { 775 pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage; 776 }; 777 }; 778 779 enableParallelBuilding = true; 780 781 meta = with lib; { 782 homepage = "https://www.python.org"; 783 changelog = 784 let 785 majorMinor = versions.majorMinor version; 786 dashedVersion = replaceStrings [ "." "a" "b" ] [ "-" "-alpha-" "-beta-" ] version; 787 in 788 if sourceVersion.suffix == "" then 789 "https://docs.python.org/release/${version}/whatsnew/changelog.html" 790 else 791 "https://docs.python.org/${majorMinor}/whatsnew/changelog.html#python-${dashedVersion}"; 792 description = "High-level dynamically-typed programming language"; 793 longDescription = '' 794 Python is a remarkably powerful dynamic programming language that 795 is used in a wide variety of application domains. Some of its key 796 distinguishing features include: clear, readable syntax; strong 797 introspection capabilities; intuitive object orientation; natural 798 expression of procedural code; full modularity, supporting 799 hierarchical packages; exception-based error handling; and very 800 high level dynamic data types. 801 ''; 802 license = licenses.psfl; 803 pkgConfigModules = [ "python3" ]; 804 platforms = platforms.linux ++ platforms.darwin ++ platforms.windows ++ platforms.freebsd; 805 mainProgram = executable; 806 teams = [ lib.teams.python ]; 807 # static build on x86_64-darwin/aarch64-darwin breaks with: 808 # configure: error: C compiler cannot create executables 809 810 # mingw patches only apply to Python 3.11 currently 811 broken = 812 (lib.versions.minor version != "11" && stdenv.hostPlatform.isWindows) 813 || (stdenv.hostPlatform.isStatic && stdenv.hostPlatform.isDarwin); 814 }; 815})