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