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