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