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