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