push sheeet
Some checks failed
Periodic Merges (6h) / master → staging-nixos (push) Failing after 12m50s
Periodic Merges (6h) / master → staging-next (push) Failing after 12m54s
Periodic Merges (24h) / merge-base(master,staging) → haskell-updates (push) Failing after 11m54s
Periodic Merges (6h) / staging-next → staging (push) Failing after 12m13s
Periodic Merges (24h) / staging-next-25.05 → staging-25.05 (push) Failing after 13m24s
Periodic Merges (24h) / release-25.05 → staging-next-25.05 (push) Failing after 14m28s

This commit is contained in:
Dark Steveneq
2025-10-09 14:15:47 +02:00
commit 646b892680
49168 changed files with 5897842 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
catch_conflicts.py
==================
The file catch_conflicts.py is in a subdirectory because, if it isn't, the
/nix/store/ directory is added to sys.path causing a delay when building.
Pointers:
- https://docs.python.org/3/library/sys.html#sys.path
- https://github.com/NixOS/nixpkgs/pull/23600

View File

@@ -0,0 +1,85 @@
from importlib.metadata import PathDistribution
from pathlib import Path
import collections
import sys
import os
from typing import Dict, List, Set, Tuple
do_abort: bool = False
packages: Dict[str, Dict[str, Dict[str, List[str]]]] = collections.defaultdict(dict)
found_paths: Set[Path] = set()
out_path: Path = Path(os.getenv("out"))
version: Tuple[int, int] = sys.version_info
site_packages_path: str = f'lib/python{version[0]}.{version[1]}/site-packages'
def get_name(dist: PathDistribution) -> str:
return dist.metadata['name'].lower().replace('-', '_')
# pretty print a package
def describe_package(dist: PathDistribution) -> str:
return f"{get_name(dist)} {dist.version} ({dist._path})"
# pretty print a list of parents (dependency chain)
def describe_parents(parents: List[str]) -> str:
if not parents:
return ""
return \
f" dependency chain:\n " \
+ str(f"\n ...depending on: ".join(parents))
# inserts an entry into 'packages'
def add_entry(name: str, version: str, store_path: str, parents: List[str]) -> None:
packages[name][store_path] = dict(
version=version,
parents=parents,
)
# transitively discover python dependencies and store them in 'packages'
def find_packages(store_path: Path, site_packages_path: str, parents: List[str]) -> None:
site_packages: Path = (store_path / site_packages_path)
propagated_build_inputs: Path = (store_path / "nix-support/propagated-build-inputs")
# only visit each path once, to avoid exponential complexity with highly
# connected dependency graphs
if store_path in found_paths:
return
found_paths.add(store_path)
# add the current package to the list
if site_packages.exists():
for dist_info in site_packages.glob("*.dist-info"):
dist: PathDistribution = PathDistribution(dist_info)
add_entry(get_name(dist), dist.version, store_path, parents)
# recursively add dependencies
if propagated_build_inputs.exists():
with open(propagated_build_inputs, "r") as f:
build_inputs: List[str] = f.read().split()
for build_input in build_inputs:
find_packages(Path(build_input), site_packages_path, parents + [build_input])
find_packages(out_path, site_packages_path, [f"this derivation: {out_path}"])
# print all duplicates
for name, store_paths in packages.items():
if len(store_paths) > 1:
do_abort = True
print("Found duplicated packages in closure for dependency '{}': ".format(name))
for store_path, candidate in store_paths.items():
print(f" {name} {candidate['version']} ({store_path})")
print(describe_parents(candidate['parents']))
# fail if duplicates were found
if do_abort:
print("")
print(
"Package duplicates found in closure, see above. Usually this "
"happens if two packages depend on different version "
"of the same dependency."
)
sys.exit(1)

View File

@@ -0,0 +1,30 @@
import pkg_resources
import collections
import sys
do_abort = False
packages = collections.defaultdict(list)
for f in sys.path:
for req in pkg_resources.find_distributions(f):
if req not in packages[req.project_name]:
# some exceptions inside buildPythonPackage
if req.project_name in ['setuptools', 'pip', 'wheel']:
continue
packages[req.project_name].append(req)
for name, duplicates in packages.items():
if len(duplicates) > 1:
do_abort = True
print("Found duplicated packages in closure for dependency '{}': ".format(name))
for dup in duplicates:
print(" " + repr(dup))
if do_abort:
print("")
print(
'Package duplicates found in closure, see above. Usually this '
'happens if two packages depend on different version '
'of the same dependency.')
sys.exit(1)

View File

@@ -0,0 +1,29 @@
{ pkgs }:
{
# List of libraries that are needed for conda binary packages.
# When installing a conda binary package, just extend
# the `buildInputs` with `condaAutopatchLibs`.
condaPatchelfLibs = map (p: p.lib or p) (
[
pkgs.alsa-lib
pkgs.cups
pkgs.gcc-unwrapped
pkgs.libGL
]
++ (with pkgs.xorg; [
libSM
libICE
libX11
libXau
libXdamage
libXi
libXrender
libXrandr
libXcomposite
libXcursor
libXtst
libXScrnSaver
])
);
}

View File

@@ -0,0 +1,34 @@
--- origsrc/Lib/ctypes/util.py 2007-09-14 15:05:26.000000000 -0500
+++ src/Lib/ctypes/util.py 2008-11-25 17:54:47.319296200 -0600
@@ -41,6 +41,20 @@
continue
return None
+elif sys.platform == "cygwin":
+ def find_library(name):
+ for libdir in ['/usr/lib', '/usr/local/lib']:
+ for libext in ['lib%s.dll.a' % name, 'lib%s.a' % name]:
+ implib = os.path.join(libdir, libext)
+ if not os.path.exists(implib):
+ continue
+ cmd = "dlltool -I " + implib + " 2>/dev/null"
+ res = os.popen(cmd).read().replace("\n","")
+ if not res:
+ continue
+ return res
+ return None
+
elif os.name == "posix":
# Andreas Degert's find functions, using gcc, /sbin/ldconfig, objdump
import re, tempfile, errno
@@ -157,6 +173,10 @@
print cdll.LoadLibrary("libcrypto.dylib")
print cdll.LoadLibrary("libSystem.dylib")
print cdll.LoadLibrary("System.framework/System")
+ elif sys.platform == "cygwin":
+ print cdll.LoadLibrary("cygbz2-1.dll")
+ print find_library("crypt")
+ print cdll.LoadLibrary("cygcrypt-0.dll")
else:
print cdll.LoadLibrary("libm.so")
print cdll.LoadLibrary("libcrypt.so")

View File

@@ -0,0 +1,27 @@
--- origsrc/setup.py 2008-02-04 17:41:02.000000000 -0600
+++ src/setup.py 2008-07-02 02:11:28.671875000 -0500
@@ -1277,12 +1279,6 @@
include_dirs.append('/usr/X11/include')
added_lib_dirs.append('/usr/X11/lib')
- # If Cygwin, then verify that X is installed before proceeding
- if host_platform == 'cygwin':
- x11_inc = find_file('X11/Xlib.h', [], include_dirs)
- if x11_inc is None:
- return
-
# Check for BLT extension
if self.compiler.find_library_file(lib_dirs + added_lib_dirs,
'BLT8.0'):
@@ -1300,9 +1296,8 @@
if host_platform in ['aix3', 'aix4']:
libs.append('ld')
- # Finally, link with the X11 libraries (not appropriate on cygwin)
- if host_platform != "cygwin":
- libs.append('X11')
+ # Finally, link with the X11 libraries
+ libs.append('X11')
ext = Extension('_tkinter', ['_tkinter.c', 'tkappinit.c'],
define_macros=[('WITH_APPINIT', 1)] + defs,

View File

@@ -0,0 +1,13 @@
--- origsrc/Modules/_ssl.c 2009-01-26 10:55:41.000000000 -0600
+++ src/Modules/_ssl.c 2009-08-20 00:04:59.346816700 -0500
@@ -15,6 +15,10 @@
#include "Python.h"
+#ifdef __CYGWIN__
+#undef WITH_THREAD
+#endif
+
#ifdef WITH_THREAD
#include "pythread.h"
#define PySSL_BEGIN_ALLOW_THREADS { \

View File

@@ -0,0 +1,41 @@
--- Python-2.6.5.orig/Modules/selectmodule.c 2012-02-02 22:35:21.835125000 -0500
+++ Python-2.6.5/Modules/selectmodule.c 2012-02-02 22:41:41.210125000 -0500
@@ -6,6 +6,21 @@
>= 0.
*/
+/* Windows #defines FD_SETSIZE to 64 if FD_SETSIZE isn't already defined.
+ 64 is too small (too many people have bumped into that limit).
+ Here we boost it.
+
+ Cygwin also defines FD_SETSIZE to 64, so also increase the limit on
+ Cygwin. We must do this before sys/types.h is included, which otherwise
+ sets FD_SETSIZE to the default.
+
+ Users who want even more than the boosted limit should #define
+ FD_SETSIZE higher before this; e.g., via compiler /D switch.
+*/
+#if (defined(MS_WINDOWS) || defined(__CYGWIN__)) && !defined(FD_SETSIZE)
+#define FD_SETSIZE 512
+#endif
+
#include "Python.h"
#include <structmember.h>
@@ -16,16 +31,6 @@
#undef HAVE_BROKEN_POLL
#endif
-/* Windows #defines FD_SETSIZE to 64 if FD_SETSIZE isn't already defined.
- 64 is too small (too many people have bumped into that limit).
- Here we boost it.
- Users who want even more than the boosted limit should #define
- FD_SETSIZE higher before this; e.g., via compiler /D switch.
-*/
-#if defined(MS_WINDOWS) && !defined(FD_SETSIZE)
-#define FD_SETSIZE 512
-#endif
-
#if defined(HAVE_POLL_H)
#include <poll.h>
#elif defined(HAVE_SYS_POLL_H)

View File

@@ -0,0 +1,11 @@
--- origsrc/Include/pyerrors.h 2008-06-08 23:58:54.000000000 -0500
+++ src/Include/pyerrors.h 2010-05-12 04:19:31.535297200 -0500
@@ -232,7 +232,7 @@ PyAPI_FUNC(int) PyErr_CheckSignals(void)
PyAPI_FUNC(void) PyErr_SetInterrupt(void);
/* In signalmodule.c */
-int PySignal_SetWakeupFd(int fd);
+PyAPI_FUNC(int) PySignal_SetWakeupFd(int fd);
/* Support for adding program text to SyntaxErrors */
PyAPI_FUNC(void) PyErr_SyntaxLocation(const char *, int);

View File

@@ -0,0 +1,16 @@
--- origsrc/Include/py_curses.h 2009-09-06 16:23:05.000000000 -0500
+++ src/Include/py_curses.h 2010-04-14 15:21:23.008971400 -0500
@@ -17,6 +17,13 @@
#define NCURSES_OPAQUE 0
#endif /* __APPLE__ */
+#ifdef __CYGWIN__
+/* the following define is necessary for Cygwin; without it, the
+ Cygwin-supplied ncurses.h sets NCURSES_OPAQUE to 1, and then Python
+ can't get at the WINDOW flags field. */
+#define NCURSES_INTERNALS
+#endif /* __CYGWIN__ */
+
#ifdef __FreeBSD__
/*
** On FreeBSD, [n]curses.h and stdlib.h/wchar.h use different guards

View File

@@ -0,0 +1,27 @@
--- origsrc/setup.py.orig 2012-11-27 10:20:47.442395900 -0500
+++ src/setup.py 2012-11-27 10:53:15.583020900 -0500
@@ -1141,7 +1141,7 @@
dbm_order = ['gdbm']
# The standard Unix dbm module:
- if host_platform not in ['cygwin']:
+ if host_platform not in ['win32']:
config_args = [arg.strip("'")
for arg in sysconfig.get_config_var("CONFIG_ARGS").split()]
dbm_args = [arg for arg in config_args
@@ -1192,6 +1192,15 @@
],
libraries = gdbm_libs)
break
+ if find_file("ndbm.h", inc_dirs, []) is not None:
+ print("building dbm using gdbm")
+ dbmext = Extension(
+ 'dbm', ['dbmmodule.c'],
+ define_macros=[
+ ('HAVE_NDBM_H', None),
+ ],
+ libraries = gdbm_libs)
+ break
elif cand == "bdb":
if db_incs is not None:
print "building dbm using bdb"

View File

@@ -0,0 +1,10 @@
--- origsrc/Lib/distutils/unixccompiler.py.orig 2012-11-27 07:44:15.409993500 -0500
+++ src/Lib/distutils/unixccompiler.py 2012-11-27 08:09:57.801770900 -0500
@@ -141,6 +141,7 @@
static_lib_format = shared_lib_format = dylib_lib_format = "lib%s%s"
if sys.platform == "cygwin":
exe_extension = ".exe"
+ dylib_lib_extension = ".dll.a"
def preprocess(self, source,
output_file=None, macros=None, include_dirs=None,

View File

@@ -0,0 +1,31 @@
--- origsrc/Modules/getpath.c.orig 2012-11-27 12:07:56.098645900 -0500
+++ src/Modules/getpath.c 2012-11-27 12:10:11.254895900 -0500
@@ -436,6 +436,28 @@
if (isxfile(progpath))
break;
+#ifdef __CYGWIN__
+ /*
+ * Cygwin automatically removes the ".exe" extension from argv[0]
+ * to make programs feel like they are in a more Unix-like
+ * environment. Unfortunately, this can make it problemmatic for
+ * Cygwin to distinguish between a directory and an executable with
+ * the same name excluding the ".exe" extension. For example, the
+ * Cygwin Python build directory has a "Python" directory and a
+ * "python.exe" executable. This causes isxfile() to erroneously
+ * return false. If isdir() returns true and there is enough space
+ * to append the ".exe" extension, then we try again with the
+ * extension appended.
+ */
+#define EXE ".exe"
+ if (isdir(progpath) && strlen(progpath) + strlen(EXE) <= MAXPATHLEN)
+ {
+ strcat(progpath, EXE);
+ if (isxfile(progpath))
+ break;
+ }
+#endif /* __CYGWIN__ */
+
if (!delim) {
progpath[0] = '\0';
break;

View File

@@ -0,0 +1,11 @@
--- origsrc/setup.py.orig 2012-11-27 09:28:34.051770900 -0500
+++ src/setup.py 2012-11-27 09:28:47.239270900 -0500
@@ -470,7 +470,7 @@
# Check for MacOS X, which doesn't need libm.a at all
math_libs = ['m']
- if host_platform in ['darwin', 'beos']:
+ if host_platform in ['darwin', 'beos', 'cygwin']:
math_libs = []
# XXX Omitted modules: gl, pure, dl, SGI-specific modules

View File

@@ -0,0 +1,116 @@
diff --git a/Lib/py_compile.py b/Lib/py_compile.py
index 978da73d74..3559eb95ca 100644
--- a/Lib/py_compile.py
+++ b/Lib/py_compile.py
@@ -120,16 +120,27 @@ def compile(file, cfile=None, dfile=None, doraise=False):
return
if cfile is None:
cfile = file + (__debug__ and 'c' or 'o')
- with open(cfile, 'wb') as fc:
- fc.write('\0\0\0\0')
- if "DETERMINISTIC_BUILD" in os.environ:
+ # Atomically write the pyc/pyo file. Issue #13146.
+ # id() is used to generate a pseudo-random filename.
+ path_tmp = '{}.{}'.format(cfile, id(cfile))
+ try:
+ with open(path_tmp, 'wb') as fc:
fc.write('\0\0\0\0')
- else:
- wr_long(fc, timestamp)
- marshal.dump(codeobject, fc)
- fc.flush()
- fc.seek(0, 0)
- fc.write(MAGIC)
+ if "DETERMINISTIC_BUILD" in os.environ:
+ fc.write('\0\0\0\0')
+ else:
+ wr_long(fc, timestamp)
+ marshal.dump(codeobject, fc)
+ fc.flush()
+ fc.seek(0, 0)
+ fc.write(MAGIC)
+ os.rename(path_tmp, cfile)
+ except OSError:
+ try:
+ os.unlink(path_tmp)
+ except OSError:
+ pass
+ raise
def main(args=None):
"""Compile several source files.
diff --git a/Python/import.c b/Python/import.c
index 1e31d79279..f78a1efcf0 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -951,6 +951,8 @@ static void
write_compiled_module(PyCodeObject *co, char *cpathname, struct stat *srcstat, time_t mtime)
{
FILE *fp;
+ size_t cpathname_len;
+ char *cpathname_tmp;
#ifdef MS_WINDOWS /* since Windows uses different permissions */
mode_t mode = srcstat->st_mode & ~S_IEXEC;
/* Issue #6074: We ensure user write access, so we can delete it later
@@ -963,11 +965,28 @@ write_compiled_module(PyCodeObject *co, char *cpathname, struct stat *srcstat, t
mode_t mode = srcstat->st_mode & ~S_IXUSR & ~S_IXGRP & ~S_IXOTH;
#endif
+#ifdef MS_WINDOWS
fp = open_exclusive(cpathname, mode);
+#else
+ /* Under POSIX, we first write to a tmp file and then take advantage
+ of atomic renaming. */
+ cpathname_len = strlen(cpathname);
+ cpathname_tmp = PyMem_MALLOC(cpathname_len + 5);
+ if (cpathname_tmp == NULL) {
+ PyErr_Clear();
+ return;
+ }
+ memcpy(cpathname_tmp, cpathname, cpathname_len);
+ memcpy(cpathname_tmp + cpathname_len, ".tmp", 5);
+ fp = open_exclusive(cpathname_tmp, mode);
+#endif
if (fp == NULL) {
if (Py_VerboseFlag)
PySys_WriteStderr(
"# can't create %s\n", cpathname);
+#ifndef MS_WINDOWS
+ PyMem_FREE(cpathname_tmp);
+#endif
return;
}
PyMarshal_WriteLongToFile(pyc_magic, fp, Py_MARSHAL_VERSION);
@@ -979,7 +998,12 @@ write_compiled_module(PyCodeObject *co, char *cpathname, struct stat *srcstat, t
PySys_WriteStderr("# can't write %s\n", cpathname);
/* Don't keep partial file */
fclose(fp);
+#ifdef MS_WINDOWS
(void) unlink(cpathname);
+#else
+ (void) unlink(cpathname_tmp);
+ PyMem_FREE(cpathname_tmp);
+#endif
return;
}
/* Now write the true mtime (as a 32-bit field) */
@@ -989,6 +1013,19 @@ write_compiled_module(PyCodeObject *co, char *cpathname, struct stat *srcstat, t
PyMarshal_WriteLongToFile((long)mtime, fp, Py_MARSHAL_VERSION);
fflush(fp);
}
+ /* Under POSIX, do an atomic rename */
+#ifndef MS_WINDOWS
+ if (rename(cpathname_tmp, cpathname)) {
+ if (Py_VerboseFlag)
+ PySys_WriteStderr("# can't write %s\n", cpathname);
+ /* Don't keep tmp file */
+ fclose(fp);
+ (void) unlink(cpathname_tmp);
+ PyMem_FREE(cpathname_tmp);
+ return;
+ }
+ PyMem_FREE(cpathname_tmp);
+#endif
fclose(fp);
if (Py_VerboseFlag)
PySys_WriteStderr("# wrote %s\n", cpathname);

View File

@@ -0,0 +1,32 @@
--- ./setup.py.orig 2018-04-29 15:47:33.000000000 -0700
+++ ./setup.py 2018-11-11 09:41:58.097682221 -0800
@@ -458,8 +458,6 @@
if not cross_compiling:
add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib')
add_dir_to_list(self.compiler.include_dirs, '/usr/local/include')
- if cross_compiling:
- self.add_gcc_paths()
self.add_multiarch_paths()
# Add paths specified in the environment variables LDFLAGS and
@@ -517,7 +515,10 @@
# be assumed that no additional -I,-L directives are needed.
inc_dirs = self.compiler.include_dirs[:]
lib_dirs = self.compiler.library_dirs[:]
- if not cross_compiling:
+ if cross_compiling:
+ inc_dirs = []
+ lib_dirs = []
+ else:
for d in (
'/usr/include',
):
@@ -582,6 +584,8 @@ class PyBuildExt(build_ext):
# Some modules that are normally always on:
#exts.append( Extension('_weakref', ['_weakref.c']) )
+ self.compiler.library_dirs = lib_dirs + [ '.' ]
+
# array objects
exts.append( Extension('array', ['arraymodule.c']) )

View File

@@ -0,0 +1,426 @@
{
lib,
stdenv,
fetchFromGitHub,
fetchpatch,
bzip2,
expat,
libffi,
gdbm,
db,
ncurses,
openssl,
readline,
sqlite,
tcl ? null,
tk ? null,
tclPackages,
libX11 ? null,
x11Support ? false,
zlib,
self,
coreutils,
autoreconfHook,
python-setup-hook,
# Some proprietary libs assume UCS2 unicode, especially on darwin :(
ucsEncoding ? 4,
# For the Python package set
packageOverrides ? (self: super: { }),
pkgsBuildBuild,
pkgsBuildHost,
pkgsBuildTarget,
pkgsHostHost,
pkgsTargetTarget,
sourceVersion,
hash,
passthruFun,
static ? stdenv.hostPlatform.isStatic,
stripBytecode ? reproducibleBuild,
rebuildBytecode ? true,
reproducibleBuild ? false,
enableOptimizations ? false,
strip2to3 ? false,
stripConfig ? false,
stripIdlelib ? false,
stripTests ? false,
pythonAttr ? "python${sourceVersion.major}${sourceVersion.minor}",
}:
assert x11Support -> tcl != null && tk != null && libX11 != null;
assert lib.assertMsg (enableOptimizations -> (!stdenv.cc.isClang))
"Optimizations with clang are not supported. configure: error: llvm-profdata is required for a --enable-optimizations build but could not be found.";
assert lib.assertMsg (
reproducibleBuild -> stripBytecode
) "Deterministic builds require stripping bytecode.";
assert lib.assertMsg (
reproducibleBuild -> (!enableOptimizations)
) "Deterministic builds are not achieved when optimizations are enabled.";
assert lib.assertMsg (
reproducibleBuild -> (!rebuildBytecode)
) "Deterministic builds are not achieved when (default unoptimized) bytecode is created.";
let
buildPackages = pkgsBuildHost;
inherit (passthru) pythonOnBuildForHost;
pythonOnBuildForHostInterpreter =
if stdenv.hostPlatform == stdenv.buildPlatform then
"$out/bin/python"
else
pythonOnBuildForHost.interpreter;
passthru =
passthruFun rec {
inherit self sourceVersion packageOverrides;
implementation = "cpython";
libPrefix = "python${pythonVersion}";
executable = libPrefix;
pythonVersion = with sourceVersion; "${major}.${minor}";
sitePackages = "lib/${libPrefix}/site-packages";
inherit hasDistutilsCxxPatch pythonAttr;
pythonOnBuildForBuild = pkgsBuildBuild.${pythonAttr};
pythonOnBuildForHost = pkgsBuildHost.${pythonAttr};
pythonOnBuildForTarget = pkgsBuildTarget.${pythonAttr};
pythonOnHostForHost = pkgsHostHost.${pythonAttr};
pythonOnTargetForTarget = pkgsTargetTarget.${pythonAttr} or { };
pythonABITags = [
"none"
"cp${sourceVersion.major}${sourceVersion.minor}"
];
}
// {
inherit ucsEncoding;
};
version = with sourceVersion; "${major}.${minor}.${patch}${suffix}";
# ActiveState is a fork of cpython that includes fixes for security
# issues after its EOL
src = fetchFromGitHub {
owner = "ActiveState";
repo = "cpython";
rev = "v${version}";
inherit hash;
};
hasDistutilsCxxPatch = !(stdenv.cc.isGNU or false);
patches = [
# Look in C_INCLUDE_PATH and LIBRARY_PATH for stuff.
./search-path.patch
# Python recompiles a Python if the mtime stored *in* the
# pyc/pyo file differs from the mtime of the source file. This
# doesn't work in Nix because Nix changes the mtime of files in
# the Nix store to 1. So treat that as a special case.
./nix-store-mtime.patch
# patch python to put zero timestamp into pyc
# if DETERMINISTIC_BUILD env var is set
./deterministic-build.patch
# Fix python bug #27177 (https://bugs.python.org/issue27177)
# The issue is that `match.group` only recognizes python integers
# instead of everything that has `__index__`.
# This bug was fixed upstream, but not backported to 2.7
(fetchpatch {
name = "re_match_index.patch";
url = "https://bugs.python.org/file43084/re_match_index.patch";
sha256 = "0l9rw6r5r90iybdkp3hhl2pf0h0s1izc68h5d3ywrm92pq32wz57";
})
# Fix race-condition during pyc creation. Has a slight backwards
# incompatible effect: pyc symlinks will now be overridden
# (https://bugs.python.org/issue17222). Included in python >= 3.4,
# backported in debian since 2013.
# https://bugs.python.org/issue13146
./atomic_pyc.patch
# Backport from CPython 3.8 of a good list of tests to run for PGO.
./profile-task.patch
# The workaround is for unittests on Win64, which we don't support.
# It does break aarch64-darwin, which we do support. See:
# * https://bugs.python.org/issue35523
# * https://github.com/python/cpython/commit/e6b247c8e524
../3.7/no-win64-workaround.patch
# fix openssl detection by reverting irrelevant change for us, to enable hashlib which is required by pip
(fetchpatch {
url = "https://github.com/ActiveState/cpython/pull/35/commits/20ea5b46aaf1e7bdf9d6905ba8bece2cc73b05b0.patch";
revert = true;
hash = "sha256-Lp5fGlcfJJ6p6vKmcLckJiAA2AZz4prjFE0aMEJxotw=";
})
]
++ lib.optionals (x11Support && stdenv.hostPlatform.isDarwin) [
./use-correct-tcl-tk-on-darwin.patch
]
++ lib.optionals stdenv.hostPlatform.isLinux [
# Disable the use of ldconfig in ctypes.util.find_library (since
# ldconfig doesn't work on NixOS), and don't use
# ctypes.util.find_library during the loading of the uuid module
# (since it will do a futile invocation of gcc (!) to find
# libuuid, slowing down program startup a lot).
./no-ldconfig.patch
# Fix ctypes.util.find_library with gcc10.
./find_library-gcc10.patch
]
++ lib.optionals stdenv.hostPlatform.isCygwin [
./2.5.2-ctypes-util-find_library.patch
./2.5.2-tkinter-x11.patch
./2.6.2-ssl-threads.patch
./2.6.5-export-PySignal_SetWakeupFd.patch
./2.6.5-FD_SETSIZE.patch
./2.6.5-ncurses-abi6.patch
./2.7.3-dbm.patch
./2.7.3-dylib.patch
./2.7.3-getpath-exe-extension.patch
./2.7.3-no-libm.patch
]
++ lib.optionals hasDistutilsCxxPatch [
# Patch from http://bugs.python.org/issue1222585 adapted to work with
# `patch -p1' and with a last hunk removed
# Upstream distutils is calling C compiler to compile C++ code, which
# only works for GCC and Apple Clang. This makes distutils to call C++
# compiler when needed.
./python-2.7-distutils-C++.patch
]
++ lib.optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
./cross-compile.patch
];
preConfigure = ''
# Purity.
for i in /usr /sw /opt /pkg; do
substituteInPlace ./setup.py --replace $i /no-such-path
done
''
+ lib.optionalString (stdenv ? cc && stdenv.cc.libc != null) ''
for i in Lib/plat-*/regen; do
substituteInPlace $i --replace /usr/include/ ${stdenv.cc.libc}/include/
done
''
+ lib.optionalString stdenv.hostPlatform.isDarwin ''
substituteInPlace configure --replace '`/usr/bin/arch`' '"i386"'
substituteInPlace Lib/multiprocessing/__init__.py \
--replace 'os.popen(comm)' 'os.popen("${coreutils}/bin/nproc")'
'';
configureFlags =
lib.optionals enableOptimizations [
"--enable-optimizations"
]
++ lib.optionals (!static) [
"--enable-shared"
]
++ [
"--with-threads"
"--with-system-ffi"
"--with-system-expat"
"--enable-unicode=ucs${toString ucsEncoding}"
]
++ lib.optionals stdenv.hostPlatform.isCygwin [
"ac_cv_func_bind_textdomain_codeset=yes"
]
++ lib.optionals stdenv.hostPlatform.isDarwin [
"--disable-toolbox-glue"
]
++ lib.optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
"PYTHON_FOR_BUILD=${lib.getBin buildPackages.python27}/bin/python"
"ac_cv_buggy_getaddrinfo=no"
# Assume little-endian IEEE 754 floating point when cross compiling
"ac_cv_little_endian_double=yes"
"ac_cv_big_endian_double=no"
"ac_cv_mixed_endian_double=no"
"ac_cv_x87_double_rounding=yes"
"ac_cv_tanh_preserves_zero_sign=yes"
# Generally assume that things are present and work
"ac_cv_posix_semaphores_enabled=yes"
"ac_cv_broken_sem_getvalue=no"
"ac_cv_wchar_t_signed=yes"
"ac_cv_rshift_extends_sign=yes"
"ac_cv_broken_nice=no"
"ac_cv_broken_poll=no"
"ac_cv_working_tzset=yes"
"ac_cv_have_long_long_format=yes"
"ac_cv_have_size_t_format=yes"
"ac_cv_computed_gotos=yes"
"ac_cv_file__dev_ptmx=yes"
"ac_cv_file__dev_ptc=yes"
]
# Never even try to use lchmod on linux,
# don't rely on detecting glibc-isms.
++ lib.optional stdenv.hostPlatform.isLinux "ac_cv_func_lchmod=no"
++ lib.optional static "LDFLAGS=-static";
strictDeps = true;
buildInputs =
lib.optional (stdenv ? cc && stdenv.cc.libc != null) stdenv.cc.libc
++ [
bzip2
openssl
zlib
libffi
expat
db
gdbm
ncurses
sqlite
readline
]
++ lib.optionals x11Support [
tcl
tk
libX11
];
nativeBuildInputs = [
autoreconfHook
]
++ lib.optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
buildPackages.stdenv.cc
buildPackages.python27
];
mkPaths = paths: {
C_INCLUDE_PATH = lib.makeSearchPathOutput "dev" "include" paths;
LIBRARY_PATH = lib.makeLibraryPath paths;
};
# Python 2.7 needs this
crossCompileEnv = lib.optionalAttrs (stdenv.hostPlatform != stdenv.buildPlatform) {
_PYTHON_HOST_PLATFORM = stdenv.hostPlatform.config;
};
# Build the basic Python interpreter without modules that have
# external dependencies.
in
with passthru;
stdenv.mkDerivation (
{
pname = "python";
inherit version;
inherit
src
patches
buildInputs
nativeBuildInputs
preConfigure
configureFlags
;
LDFLAGS = lib.optionalString (!stdenv.hostPlatform.isDarwin) "-lgcc_s";
inherit (mkPaths buildInputs) C_INCLUDE_PATH LIBRARY_PATH;
env.NIX_CFLAGS_COMPILE =
lib.optionalString (stdenv.targetPlatform.system == "x86_64-darwin") "-msse2"
+ lib.optionalString stdenv.hostPlatform.isMusl " -DTHREAD_STACK_SIZE=0x100000";
DETERMINISTIC_BUILD = 1;
setupHook = python-setup-hook sitePackages;
postPatch = lib.optionalString (x11Support && ((tclPackages.tix or null) != null)) ''
substituteInPlace "Lib/lib-tk/Tix.py" --replace "os.environ.get('TIX_LIBRARY')" "os.environ.get('TIX_LIBRARY') or '${tclPackages.tix}/lib'"
'';
postInstall = ''
# needed for some packages, especially packages that backport
# functionality to 2.x from 3.x
for item in $out/lib/${libPrefix}/test/*; do
if [[ "$item" != */test_support.py*
&& "$item" != */test/support
&& "$item" != */test/regrtest.py* ]]; then
rm -rf "$item"
else
echo $item
fi
done
touch $out/lib/${libPrefix}/test/__init__.py
ln -s $out/lib/${libPrefix}/pdb.py $out/bin/pdb
ln -s $out/lib/${libPrefix}/pdb.py $out/bin/pdb${sourceVersion.major}.${sourceVersion.minor}
ln -s $out/share/man/man1/{python2.7.1.gz,python.1.gz}
rm "$out"/lib/python*/plat-*/regen # refers to glibc.dev
# Determinism: Windows installers were not deterministic.
# We're also not interested in building Windows installers.
find "$out" -name 'wininst*.exe' | xargs -r rm -f
''
+ lib.optionalString stripBytecode ''
# Determinism: deterministic bytecode
# First we delete all old bytecode.
find $out -name "*.pyc" -delete
''
+ lib.optionalString rebuildBytecode ''
# We build 3 levels of optimized bytecode. Note the default level, without optimizations,
# is not reproducible yet. https://bugs.python.org/issue29708
# Not creating bytecode will result in a large performance loss however, so we do build it.
find $out -name "*.py" | ${pythonOnBuildForHostInterpreter} -m compileall -q -f -x "lib2to3" -i -
find $out -name "*.py" | ${pythonOnBuildForHostInterpreter} -O -m compileall -q -f -x "lib2to3" -i -
find $out -name "*.py" | ${pythonOnBuildForHostInterpreter} -OO -m compileall -q -f -x "lib2to3" -i -
''
+ lib.optionalString stdenv.hostPlatform.isCygwin ''
cp libpython2.7.dll.a $out/lib
'';
inherit passthru;
postFixup = ''
# Include a sitecustomize.py file. Note it causes an error when it's in postInstall with 2.7.
cp ${../../sitecustomize.py} $out/${sitePackages}/sitecustomize.py
''
+ lib.optionalString strip2to3 ''
rm -R $out/bin/2to3 $out/lib/python*/lib2to3
''
+ lib.optionalString stripConfig ''
rm -R $out/bin/python*-config $out/lib/python*/config*
''
+ lib.optionalString stripIdlelib ''
# Strip IDLE
rm -R $out/bin/idle* $out/lib/python*/idlelib
''
+ lib.optionalString stripTests ''
# Strip tests
rm -R $out/lib/python*/test $out/lib/python*/**/test{,s}
'';
enableParallelBuilding = true;
doCheck = false; # expensive, and fails
meta = {
homepage = "http://python.org";
description = "High-level dynamically-typed programming language";
longDescription = ''
Python is a remarkably powerful dynamic programming language that
is used in a wide variety of application domains. Some of its key
distinguishing features include: clear, readable syntax; strong
introspection capabilities; intuitive object orientation; natural
expression of procedural code; full modularity, supporting
hierarchical packages; exception-based error handling; and very
high level dynamic data types.
'';
license = lib.licenses.psfl;
platforms = lib.platforms.all;
knownVulnerabilities = [
"Python 2.7 has reached its end of life after 2020-01-01. See https://www.python.org/doc/sunset-python-2/."
# Quote: That means that we will not improve it anymore after that day,
# even if someone finds a security problem in it. You should upgrade to
# Python 3 as soon as you can. [..] So, in 2008, we announced that we
# would sunset Python 2 in 2015, and asked people to upgrade before
# then. Some did, but many did not. So, in 2014, we extended that
# sunset till 2020.
];
};
}
// crossCompileEnv
)

View File

@@ -0,0 +1,36 @@
diff -ur orig/Lib/py_compile.py new/Lib/py_compile.py
--- orig/Lib/py_compile.py
+++ new/Lib/py_compile.py
@@ -122,7 +122,10 @@
cfile = file + (__debug__ and 'c' or 'o')
with open(cfile, 'wb') as fc:
fc.write('\0\0\0\0')
- wr_long(fc, timestamp)
+ if "DETERMINISTIC_BUILD" in os.environ:
+ fc.write('\0\0\0\0')
+ else:
+ wr_long(fc, timestamp)
marshal.dump(codeobject, fc)
fc.flush()
fc.seek(0, 0)
diff -ur orig/Python/import.c new/Python/import.c
--- orig/Python/import.c
+++ new/Python/import.c
@@ -939,10 +939,12 @@
return;
}
/* Now write the true mtime (as a 32-bit field) */
- fseek(fp, 4L, 0);
- assert(mtime <= 0xFFFFFFFF);
- PyMarshal_WriteLongToFile((long)mtime, fp, Py_MARSHAL_VERSION);
- fflush(fp);
+ if (Py_GETENV("DETERMINISTIC_BUILD") == NULL) {
+ fseek(fp, 4L, 0);
+ assert(mtime <= 0xFFFFFFFF);
+ PyMarshal_WriteLongToFile((long)mtime, fp, Py_MARSHAL_VERSION);
+ fflush(fp);
+ }
fclose(fp);
if (Py_VerboseFlag)
PySys_WriteStderr("# wrote %s\n", cpathname);

View File

@@ -0,0 +1,79 @@
Backport https://github.com/python/cpython/commit/82df3b3071bb003247c33eac4670775e9883c994
and https://github.com/python/cpython/commit/27ac19cca2c639caaf6fedf3632fe6beb265f24f
Fixes the check phase of python2Packages.cffi.
--- a/Lib/ctypes/util.py
+++ b/Lib/ctypes/util.py
@@ -87,6 +87,12 @@ elif os.name == "posix":
# Andreas Degert's find functions, using gcc, /sbin/ldconfig, objdump
import re, tempfile, errno
+ def _is_elf(filename):
+ "Return True if the given file is an ELF file"
+ elf_header = b'\x7fELF'
+ with open(filename, 'rb') as thefile:
+ return thefile.read(4) == elf_header
+
def _findLib_gcc(name):
# Run GCC's linker with the -t (aka --trace) option and examine the
# library name it prints out. The GCC command will fail because we
@@ -110,10 +116,17 @@ elif os.name == "posix":
# the normal behaviour of GCC if linking fails
if e.errno != errno.ENOENT:
raise
- res = re.search(expr, trace)
+ res = re.findall(expr, trace)
if not res:
return None
- return res.group(0)
+
+ for file in res:
+ # Check if the given file is an elf file: gcc can report
+ # some files that are linker scripts and not actual
+ # shared objects. See bpo-41976 for more details
+ if not _is_elf(file):
+ continue
+ return file
if sys.platform == "sunos5":
@@ -237,8 +250,37 @@ elif os.name == "posix":
def _findSoname_ldconfig(name):
return None
+ def _findLib_ld(name):
+ # See issue #9998 for why this is needed
+ expr = r'[^\(\)\s]*lib%s\.[^\(\)\s]*' % re.escape(name)
+ cmd = ['ld', '-t']
+ libpath = os.environ.get('LD_LIBRARY_PATH')
+ if libpath:
+ for d in libpath.split(':'):
+ cmd.extend(['-L', d])
+ cmd.extend(['-o', os.devnull, '-l%s' % name])
+ result = None
+ try:
+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ universal_newlines=True)
+ out, _ = p.communicate()
+ res = re.findall(expr, out)
+ for file in res:
+ # Check if the given file is an elf file: gcc can report
+ # some files that are linker scripts and not actual
+ # shared objects. See bpo-41976 for more details
+ if not _is_elf(file):
+ continue
+ return file
+ except Exception:
+ pass # result will be None
+ return result
+
def find_library(name):
- return _findSoname_ldconfig(name) or _get_soname(_findLib_gcc(name))
+ # See issue #9998
+ return _findSoname_ldconfig(name) or \
+ _get_soname(_findLib_gcc(name)) or _get_soname(_findLib_ld(name))
################################################################
# test code

View File

@@ -0,0 +1,12 @@
diff -ru -x '*~' Python-2.7.1-orig/Python/import.c Python-2.7.1/Python/import.c
--- Python-2.7.1-orig/Python/import.c 2010-05-20 20:37:55.000000000 +0200
+++ Python-2.7.1/Python/import.c 2011-01-04 15:55:11.000000000 +0100
@@ -751,7 +751,7 @@
return NULL;
}
pyc_mtime = PyMarshal_ReadLongFromFile(fp);
- if (pyc_mtime != mtime) {
+ if (pyc_mtime != mtime && mtime != 1) {
if (Py_VerboseFlag)
PySys_WriteStderr("# %s has bad mtime\n", cpathname);
fclose(fp);

View File

@@ -0,0 +1,117 @@
From 6b0f329a9f37110020ca02b35c8125391ef282b7 Mon Sep 17 00:00:00 2001
From: Frederik Rietdijk <fridh@fridh.nl>
Date: Sat, 24 Dec 2016 15:56:10 +0100
Subject: [PATCH] no ldconfig
---
Lib/ctypes/util.py | 35 +----------------------------------
Lib/uuid.py | 47 -----------------------------------------------
2 files changed, 1 insertion(+), 81 deletions(-)
diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py
index ab10ec5..f253e34 100644
--- a/Lib/ctypes/util.py
+++ b/Lib/ctypes/util.py
@@ -235,40 +235,7 @@ elif os.name == "posix":
else:
def _findSoname_ldconfig(name):
- import struct
- if struct.calcsize('l') == 4:
- machine = os.uname()[4] + '-32'
- else:
- machine = os.uname()[4] + '-64'
- mach_map = {
- 'x86_64-64': 'libc6,x86-64',
- 'ppc64-64': 'libc6,64bit',
- 'sparc64-64': 'libc6,64bit',
- 's390x-64': 'libc6,64bit',
- 'ia64-64': 'libc6,IA-64',
- }
- abi_type = mach_map.get(machine, 'libc6')
-
- # XXX assuming GLIBC's ldconfig (with option -p)
- expr = r'\s+(lib%s\.[^\s]+)\s+\(%s' % (re.escape(name), abi_type)
-
- env = dict(os.environ)
- env['LC_ALL'] = 'C'
- env['LANG'] = 'C'
- null = open(os.devnull, 'wb')
- try:
- with null:
- p = subprocess.Popen(['/sbin/ldconfig', '-p'],
- stderr=null,
- stdout=subprocess.PIPE,
- env=env)
- except OSError: # E.g. command not found
- return None
- [data, _] = p.communicate()
- res = re.search(expr, data)
- if not res:
- return None
- return res.group(1)
+ return None
def find_library(name):
return _findSoname_ldconfig(name) or _get_soname(_findLib_gcc(name))
diff --git a/Lib/uuid.py b/Lib/uuid.py
index 7432032..05eeee5 100644
--- a/Lib/uuid.py
+++ b/Lib/uuid.py
@@ -441,53 +441,6 @@ def _netbios_getnode():
# If ctypes is available, use it to find system routines for UUID generation.
_uuid_generate_time = _UuidCreate = None
-try:
- import ctypes, ctypes.util
- import sys
-
- # The uuid_generate_* routines are provided by libuuid on at least
- # Linux and FreeBSD, and provided by libc on Mac OS X.
- _libnames = ['uuid']
- if not sys.platform.startswith('win'):
- _libnames.append('c')
- for libname in _libnames:
- try:
- lib = ctypes.CDLL(ctypes.util.find_library(libname))
- except:
- continue
- if hasattr(lib, 'uuid_generate_time'):
- _uuid_generate_time = lib.uuid_generate_time
- break
- del _libnames
-
- # The uuid_generate_* functions are broken on MacOS X 10.5, as noted
- # in issue #8621 the function generates the same sequence of values
- # in the parent process and all children created using fork (unless
- # those children use exec as well).
- #
- # Assume that the uuid_generate functions are broken from 10.5 onward,
- # the test can be adjusted when a later version is fixed.
- if sys.platform == 'darwin':
- import os
- if int(os.uname()[2].split('.')[0]) >= 9:
- _uuid_generate_time = None
-
- # On Windows prior to 2000, UuidCreate gives a UUID containing the
- # hardware address. On Windows 2000 and later, UuidCreate makes a
- # random UUID and UuidCreateSequential gives a UUID containing the
- # hardware address. These routines are provided by the RPC runtime.
- # NOTE: at least on Tim's WinXP Pro SP2 desktop box, while the last
- # 6 bytes returned by UuidCreateSequential are fixed, they don't appear
- # to bear any relationship to the MAC address of any network device
- # on the box.
- try:
- lib = ctypes.windll.rpcrt4
- except:
- lib = None
- _UuidCreate = getattr(lib, 'UuidCreateSequential',
- getattr(lib, 'UuidCreate', None))
-except:
- pass
def _unixdll_getnode():
"""Get the hardware address on Unix using ctypes."""
--
2.11.0

View File

@@ -0,0 +1,21 @@
Backport from CPython 3.8 of a good list of tests to run for PGO.
Upstream commit:
https://github.com/python/cpython/commit/4e16a4a31
Upstream discussion:
https://bugs.python.org/issue36044
diff --git a/Makefile.pre.in b/Makefile.pre.in
index 00fdd21ce..713dc1e53 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -259,7 +259,7 @@ TCLTK_LIBS=
# The task to run while instrumented when building the profile-opt target.
# We exclude unittests with -x that take a rediculious amount of time to
# run in the instrumented training build or do not provide much value.
-PROFILE_TASK=-m test.regrtest --pgo -x test_asyncore test_gdb test_multiprocessing test_subprocess
+PROFILE_TASK=-m test.regrtest --pgo test_array test_base64 test_binascii test_binop test_bisect test_bytes test_bz2 test_cmath test_codecs test_collections test_complex test_dataclasses test_datetime test_decimal test_difflib test_embed test_float test_fstring test_functools test_generators test_hashlib test_heapq test_int test_itertools test_json test_long test_lzma test_math test_memoryview test_operator test_ordered_dict test_pickle test_pprint test_re test_set test_sqlite test_statistics test_struct test_tabnanny test_time test_unicode test_xml_etree test_xml_etree_c
# report files for gcov / lcov coverage report
COVERAGE_INFO= $(abs_builddir)/coverage.info

View File

@@ -0,0 +1,259 @@
--- a/Lib/distutils/cygwinccompiler.py
+++ b/Lib/distutils/cygwinccompiler.py
@@ -117,8 +117,10 @@
# dllwrap 2.10.90 is buggy
if self.ld_version >= "2.10.90":
self.linker_dll = "gcc"
+ self.linker_dll_cxx = "g++"
else:
self.linker_dll = "dllwrap"
+ self.linker_dll_cxx = "dllwrap"
# ld_version >= "2.13" support -shared so use it instead of
# -mdll -static
@@ -132,9 +134,13 @@
self.set_executables(compiler='gcc -mcygwin -O -Wall',
compiler_so='gcc -mcygwin -mdll -O -Wall',
compiler_cxx='g++ -mcygwin -O -Wall',
+ compiler_so_cxx='g++ -mcygwin -mdll -O -Wall',
linker_exe='gcc -mcygwin',
linker_so=('%s -mcygwin %s' %
- (self.linker_dll, shared_option)))
+ (self.linker_dll, shared_option)),
+ linker_exe_cxx='g++ -mcygwin',
+ linker_so_cxx=('%s -mcygwin %s' %
+ (self.linker_dll_cxx, shared_option)))
# cygwin and mingw32 need different sets of libraries
if self.gcc_version == "2.91.57":
@@ -160,8 +166,12 @@
raise CompileError, msg
else: # for other files use the C-compiler
try:
- self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
- extra_postargs)
+ if self.detect_language(src) == 'c++':
+ self.spawn(self.compiler_so_cxx + cc_args + [src, '-o', obj] +
+ extra_postargs)
+ else:
+ self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
+ extra_postargs)
except DistutilsExecError, msg:
raise CompileError, msg
@@ -327,9 +337,14 @@
self.set_executables(compiler='gcc%s -O -Wall' % no_cygwin,
compiler_so='gcc%s -mdll -O -Wall' % no_cygwin,
compiler_cxx='g++%s -O -Wall' % no_cygwin,
+ compiler_so_cxx='g++%s -mdll -O -Wall' % no_cygwin,
linker_exe='gcc%s' % no_cygwin,
linker_so='%s%s %s %s'
% (self.linker_dll, no_cygwin,
+ shared_option, entry_point),
+ linker_exe_cxx='g++%s' % no_cygwin,
+ linker_so_cxx='%s%s %s %s'
+ % (self.linker_dll_cxx, no_cygwin,
shared_option, entry_point))
# Maybe we should also append -mthreads, but then the finished
# dlls need another dll (mingwm10.dll see Mingw32 docs)
--- a/Lib/distutils/emxccompiler.py
+++ b/Lib/distutils/emxccompiler.py
@@ -65,8 +65,12 @@
# XXX optimization, warnings etc. should be customizable.
self.set_executables(compiler='gcc -Zomf -Zmt -O3 -fomit-frame-pointer -mprobe -Wall',
compiler_so='gcc -Zomf -Zmt -O3 -fomit-frame-pointer -mprobe -Wall',
+ compiler_cxx='g++ -Zomf -Zmt -O3 -fomit-frame-pointer -mprobe -Wall',
+ compiler_so_cxx='g++ -Zomf -Zmt -O3 -fomit-frame-pointer -mprobe -Wall',
linker_exe='gcc -Zomf -Zmt -Zcrtdll',
- linker_so='gcc -Zomf -Zmt -Zcrtdll -Zdll')
+ linker_so='gcc -Zomf -Zmt -Zcrtdll -Zdll',
+ linker_exe_cxx='g++ -Zomf -Zmt -Zcrtdll',
+ linker_so_cxx='g++ -Zomf -Zmt -Zcrtdll -Zdll')
# want the gcc library statically linked (so that we don't have
# to distribute a version dependent on the compiler we have)
@@ -83,8 +87,12 @@
raise CompileError, msg
else: # for other files use the C-compiler
try:
- self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
- extra_postargs)
+ if self.detect_language(src) == 'c++':
+ self.spawn(self.compiler_so_cxx + cc_args + [src, '-o', obj] +
+ extra_postargs)
+ else:
+ self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
+ extra_postargs)
except DistutilsExecError, msg:
raise CompileError, msg
--- a/Lib/distutils/sysconfig.py
+++ b/Lib/distutils/sysconfig.py
@@ -170,10 +170,12 @@
_osx_support.customize_compiler(_config_vars)
_config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True'
- (cc, cxx, cflags, ccshared, ldshared, so_ext, ar, ar_flags) = \
- get_config_vars('CC', 'CXX', 'CFLAGS',
- 'CCSHARED', 'LDSHARED', 'SO', 'AR',
- 'ARFLAGS')
+ (cc, cxx, ccshared, ldshared, ldcxxshared, so_ext, ar, ar_flags) = \
+ get_config_vars('CC', 'CXX', 'CCSHARED', 'LDSHARED', 'LDCXXSHARED',
+ 'SO', 'AR', 'ARFLAGS')
+
+ cflags = ''
+ cxxflags = ''
if 'CC' in os.environ:
newcc = os.environ['CC']
@@ -188,19 +190,27 @@
cxx = os.environ['CXX']
if 'LDSHARED' in os.environ:
ldshared = os.environ['LDSHARED']
+ if 'LDCXXSHARED' in os.environ:
+ ldcxxshared = os.environ['LDCXXSHARED']
if 'CPP' in os.environ:
cpp = os.environ['CPP']
else:
cpp = cc + " -E" # not always
if 'LDFLAGS' in os.environ:
ldshared = ldshared + ' ' + os.environ['LDFLAGS']
+ ldcxxshared = ldcxxshared + ' ' + os.environ['LDFLAGS']
if 'CFLAGS' in os.environ:
cflags = cflags + ' ' + os.environ['CFLAGS']
ldshared = ldshared + ' ' + os.environ['CFLAGS']
+ if 'CXXFLAGS' in os.environ:
+ cxxflags = os.environ['CXXFLAGS']
+ ldcxxshared = ldcxxshared + ' ' + os.environ['CXXFLAGS']
if 'CPPFLAGS' in os.environ:
cpp = cpp + ' ' + os.environ['CPPFLAGS']
cflags = cflags + ' ' + os.environ['CPPFLAGS']
+ cxxflags = cxxflags + ' ' + os.environ['CPPFLAGS']
ldshared = ldshared + ' ' + os.environ['CPPFLAGS']
+ ldcxxshared = ldcxxshared + ' ' + os.environ['CPPFLAGS']
if 'AR' in os.environ:
ar = os.environ['AR']
if 'ARFLAGS' in os.environ:
@@ -209,13 +219,17 @@
archiver = ar + ' ' + ar_flags
cc_cmd = cc + ' ' + cflags
+ cxx_cmd = cxx + ' ' + cxxflags
compiler.set_executables(
preprocessor=cpp,
compiler=cc_cmd,
compiler_so=cc_cmd + ' ' + ccshared,
- compiler_cxx=cxx,
+ compiler_cxx=cxx_cmd,
+ compiler_so_cxx=cxx_cmd + ' ' + ccshared,
linker_so=ldshared,
linker_exe=cc,
+ linker_so_cxx=ldcxxshared,
+ linker_exe_cxx=cxx,
archiver=archiver)
compiler.shared_lib_extension = so_ext
--- a/Lib/distutils/unixccompiler.py
+++ b/Lib/distutils/unixccompiler.py
@@ -55,14 +55,17 @@
# are pretty generic; they will probably have to be set by an outsider
# (eg. using information discovered by the sysconfig about building
# Python extensions).
- executables = {'preprocessor' : None,
- 'compiler' : ["cc"],
- 'compiler_so' : ["cc"],
- 'compiler_cxx' : ["cc"],
- 'linker_so' : ["cc", "-shared"],
- 'linker_exe' : ["cc"],
- 'archiver' : ["ar", "-cr"],
- 'ranlib' : None,
+ executables = {'preprocessor' : None,
+ 'compiler' : ["cc"],
+ 'compiler_so' : ["cc"],
+ 'compiler_cxx' : ["c++"],
+ 'compiler_so_cxx' : ["c++"],
+ 'linker_so' : ["cc", "-shared"],
+ 'linker_exe' : ["cc"],
+ 'linker_so_cxx' : ["c++", "-shared"],
+ 'linker_exe_cxx' : ["c++"],
+ 'archiver' : ["ar", "-cr"],
+ 'ranlib' : None,
}
if sys.platform[:6] == "darwin":
@@ -112,12 +115,19 @@
def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
compiler_so = self.compiler_so
+ compiler_so_cxx = self.compiler_so_cxx
if sys.platform == 'darwin':
compiler_so = _osx_support.compiler_fixup(compiler_so,
cc_args + extra_postargs)
+ compiler_so_cxx = _osx_support.compiler_fixup(compiler_so_cxx,
+ cc_args + extra_postargs)
try:
- self.spawn(compiler_so + cc_args + [src, '-o', obj] +
- extra_postargs)
+ if self.detect_language(src) == 'c++':
+ self.spawn(compiler_so_cxx + cc_args + [src, '-o', obj] +
+ extra_postargs)
+ else:
+ self.spawn(compiler_so + cc_args + [src, '-o', obj] +
+ extra_postargs)
except DistutilsExecError, msg:
raise CompileError, msg
@@ -174,23 +184,16 @@
ld_args.extend(extra_postargs)
self.mkpath(os.path.dirname(output_filename))
try:
- if target_desc == CCompiler.EXECUTABLE:
- linker = self.linker_exe[:]
+ if target_lang == "c++":
+ if target_desc == CCompiler.EXECUTABLE:
+ linker = self.linker_exe_cxx[:]
+ else:
+ linker = self.linker_so_cxx[:]
else:
- linker = self.linker_so[:]
- if target_lang == "c++" and self.compiler_cxx:
- # skip over environment variable settings if /usr/bin/env
- # is used to set up the linker's environment.
- # This is needed on OSX. Note: this assumes that the
- # normal and C++ compiler have the same environment
- # settings.
- i = 0
- if os.path.basename(linker[0]) == "env":
- i = 1
- while '=' in linker[i]:
- i = i + 1
-
- linker[i] = self.compiler_cxx[i]
+ if target_desc == CCompiler.EXECUTABLE:
+ linker = self.linker_exe[:]
+ else:
+ linker = self.linker_so[:]
if sys.platform == 'darwin':
linker = _osx_support.compiler_fixup(linker, ld_args)
--- a/Lib/_osx_support.py
+++ b/Lib/_osx_support.py
@@ -14,13 +14,13 @@
# configuration variables that may contain universal build flags,
# like "-arch" or "-isdkroot", that may need customization for
# the user environment
-_UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS', 'BASECFLAGS',
- 'BLDSHARED', 'LDSHARED', 'CC', 'CXX',
- 'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS',
- 'PY_CORE_CFLAGS')
+_UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'CXXFLAGS', 'LDFLAGS', 'CPPFLAGS',
+ 'BASECFLAGS', 'BLDSHARED', 'LDSHARED', 'LDCXXSHARED',
+ 'CC', 'CXX', 'PY_CFLAGS', 'PY_LDFLAGS',
+ 'PY_CPPFLAGS', 'PY_CORE_CFLAGS')
# configuration variables that may contain compiler calls
-_COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'CC', 'CXX')
+_COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'LDCXXSHARED', 'CC', 'CXX')
# prefix added to original configuration variable names
_INITPRE = '_OSX_SUPPORT_INITIAL_'

View File

@@ -0,0 +1,27 @@
diff -rc Python-2.4.4-orig/setup.py Python-2.4.4/setup.py
*** Python-2.4.4-orig/setup.py 2006-10-08 19:41:25.000000000 +0200
--- Python-2.4.4/setup.py 2007-05-27 16:04:54.000000000 +0200
***************
*** 279,288 ****
# Check for AtheOS which has libraries in non-standard locations
if platform == 'atheos':
lib_dirs += ['/system/libs', '/atheos/autolnk/lib']
- lib_dirs += os.getenv('LIBRARY_PATH', '').split(os.pathsep)
inc_dirs += ['/system/include', '/atheos/autolnk/include']
- inc_dirs += os.getenv('C_INCLUDE_PATH', '').split(os.pathsep)
# OSF/1 and Unixware have some stuff in /usr/ccs/lib (like -ldb)
if platform in ['osf1', 'unixware7', 'openunix8']:
lib_dirs += ['/usr/ccs/lib']
--- 279,289 ----
# Check for AtheOS which has libraries in non-standard locations
if platform == 'atheos':
lib_dirs += ['/system/libs', '/atheos/autolnk/lib']
inc_dirs += ['/system/include', '/atheos/autolnk/include']
+ lib_dirs += os.getenv('LIBRARY_PATH', '').split(os.pathsep)
+ inc_dirs += os.getenv('C_INCLUDE_PATH', '').split(os.pathsep)
+
# OSF/1 and Unixware have some stuff in /usr/ccs/lib (like -ldb)
if platform in ['osf1', 'unixware7', 'openunix8']:
lib_dirs += ['/usr/ccs/lib']

View File

@@ -0,0 +1,48 @@
diff --git a/setup.py b/setup.py
index 2779658..902d0eb 100644
--- a/setup.py
+++ b/setup.py
@@ -1699,9 +1699,6 @@ class PyBuildExt(build_ext):
# Rather than complicate the code below, detecting and building
# AquaTk is a separate method. Only one Tkinter will be built on
# Darwin - either AquaTk, if it is found, or X11 based Tk.
- if (host_platform == 'darwin' and
- self.detect_tkinter_darwin(inc_dirs, lib_dirs)):
- return
# Assume we haven't found any of the libraries or include files
# The versions with dots are used on Unix, and the versions without
@@ -1747,22 +1744,6 @@ class PyBuildExt(build_ext):
if dir not in include_dirs:
include_dirs.append(dir)
- # Check for various platform-specific directories
- if host_platform == 'sunos5':
- include_dirs.append('/usr/openwin/include')
- added_lib_dirs.append('/usr/openwin/lib')
- elif os.path.exists('/usr/X11R6/include'):
- include_dirs.append('/usr/X11R6/include')
- added_lib_dirs.append('/usr/X11R6/lib64')
- added_lib_dirs.append('/usr/X11R6/lib')
- elif os.path.exists('/usr/X11R5/include'):
- include_dirs.append('/usr/X11R5/include')
- added_lib_dirs.append('/usr/X11R5/lib')
- else:
- # Assume default location for X11
- include_dirs.append('/usr/X11/include')
- added_lib_dirs.append('/usr/X11/lib')
-
# If Cygwin, then verify that X is installed before proceeding
if host_platform == 'cygwin':
x11_inc = find_file('X11/Xlib.h', [], include_dirs)
@@ -1786,10 +1767,6 @@ class PyBuildExt(build_ext):
if host_platform in ['aix3', 'aix4']:
libs.append('ld')
- # Finally, link with the X11 libraries (not appropriate on cygwin)
- if host_platform != "cygwin":
- libs.append('X11')
-
ext = Extension('_tkinter', ['_tkinter.c', 'tkappinit.c'],
define_macros=[('WITH_APPINIT', 1)] + defs,
include_dirs = include_dirs,

View File

@@ -0,0 +1,52 @@
From 084c6dd6352077e64f10cf7aa168f95d800f3819 Mon Sep 17 00:00:00 2001
From: Jonathan Ringer <jonringer117@gmail.com>
Date: Mon, 9 Nov 2020 10:24:35 -0800
Subject: [PATCH] CPython: Don't use ldconfig
---
Lib/ctypes/util.py | 77 ++--------------------------------------------
1 file changed, 2 insertions(+), 75 deletions(-)
diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py
index 0c2510e..7fb98af 100644
--- a/Lib/ctypes/util.py
+++ b/Lib/ctypes/util.py
@@ -268,34 +222,7 @@ elif os.name == "posix":
else:
def _findSoname_ldconfig(name):
- import struct
- if struct.calcsize('l') == 4:
- machine = os.uname().machine + '-32'
- else:
- machine = os.uname().machine + '-64'
- mach_map = {
- 'x86_64-64': 'libc6,x86-64',
- 'ppc64-64': 'libc6,64bit',
- 'sparc64-64': 'libc6,64bit',
- 's390x-64': 'libc6,64bit',
- 'ia64-64': 'libc6,IA-64',
- }
- abi_type = mach_map.get(machine, 'libc6')
-
- # XXX assuming GLIBC's ldconfig (with option -p)
- regex = r'\s+(lib%s\.[^\s]+)\s+\(%s'
- regex = os.fsencode(regex % (re.escape(name), abi_type))
- try:
- with subprocess.Popen(['/sbin/ldconfig', '-p'],
- stdin=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL,
- stdout=subprocess.PIPE,
- env={'LC_ALL': 'C', 'LANG': 'C'}) as p:
- res = re.search(regex, p.stdout.read())
- if res:
- return os.fsdecode(res.group(1))
- except OSError:
- pass
+ return None
def _findLib_ld(name):
# See issue #9998 for why this is needed
--
2.28.0

View File

@@ -0,0 +1,52 @@
From 5330b6af9f832af59aa5c61d9ef6971053a8e709 Mon Sep 17 00:00:00 2001
From: Jonathan Ringer <jonringer117@gmail.com>
Date: Mon, 9 Nov 2020 10:24:35 -0800
Subject: [PATCH] CPython: Don't use ldconfig
---
Lib/ctypes/util.py | 77 ++--------------------------------------------
1 file changed, 2 insertions(+), 75 deletions(-)
diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py
index 0c2510e161..7fb98af308 100644
--- a/Lib/ctypes/util.py
+++ b/Lib/ctypes/util.py
@@ -268,34 +222,7 @@ def find_library(name, is64 = False):
else:
def _findSoname_ldconfig(name):
- import struct
- if struct.calcsize('l') == 4:
- machine = os.uname().machine + '-32'
- else:
- machine = os.uname().machine + '-64'
- mach_map = {
- 'x86_64-64': 'libc6,x86-64',
- 'ppc64-64': 'libc6,64bit',
- 'sparc64-64': 'libc6,64bit',
- 's390x-64': 'libc6,64bit',
- 'ia64-64': 'libc6,IA-64',
- }
- abi_type = mach_map.get(machine, 'libc6')
-
- # XXX assuming GLIBC's ldconfig (with option -p)
- regex = r'\s+(lib%s\.[^\s]+)\s+\(%s'
- regex = os.fsencode(regex % (re.escape(name), abi_type))
- try:
- with subprocess.Popen(['/sbin/ldconfig', '-p'],
- stdin=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL,
- stdout=subprocess.PIPE,
- env={'LC_ALL': 'C', 'LANG': 'C'}) as p:
- res = re.search(regex, p.stdout.read())
- if res:
- return os.fsdecode(res.group(1))
- except OSError:
- pass
+ return None
def _findLib_ld(name):
# See issue #9998 for why this is needed
--
2.33.1

View File

@@ -0,0 +1,257 @@
diff --git a/Lib/_osx_support.py b/Lib/_osx_support.py
index aa66c8b9f4..71e6556bac 100644
--- a/Lib/_osx_support.py
+++ b/Lib/_osx_support.py
@@ -14,13 +14,13 @@
# configuration variables that may contain universal build flags,
# like "-arch" or "-isdkroot", that may need customization for
# the user environment
-_UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS', 'BASECFLAGS',
- 'BLDSHARED', 'LDSHARED', 'CC', 'CXX',
- 'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS',
- 'PY_CORE_CFLAGS', 'PY_CORE_LDFLAGS')
+_UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'CXXFLAGS', 'LDFLAGS', 'CPPFLAGS',
+ 'BASECFLAGS', 'BLDSHARED', 'LDSHARED', 'LDCXXSHARED',
+ 'CC', 'CXX', 'PY_CFLAGS', 'PY_LDFLAGS',
+ 'PY_CPPFLAGS', 'PY_CORE_LDFLAGS', 'PY_CORE_CFLAGS')
# configuration variables that may contain compiler calls
-_COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'CC', 'CXX')
+_COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'LDCXXSHARED', 'CC', 'CXX')
# prefix added to original configuration variable names
_INITPRE = '_OSX_SUPPORT_INITIAL_'
diff --git a/Lib/distutils/cygwinccompiler.py b/Lib/distutils/cygwinccompiler.py
index 66c12dd358..dddb9fd2d4 100644
--- a/Lib/distutils/cygwinccompiler.py
+++ b/Lib/distutils/cygwinccompiler.py
@@ -123,8 +123,10 @@ def __init__(self, verbose=0, dry_run=0, force=0):
# dllwrap 2.10.90 is buggy
if self.ld_version >= "2.10.90":
self.linker_dll = "gcc"
+ self.linker_dll_cxx = "g++"
else:
self.linker_dll = "dllwrap"
+ self.linker_dll_cxx = "dllwrap"
# ld_version >= "2.13" support -shared so use it instead of
# -mdll -static
@@ -138,9 +140,13 @@ def __init__(self, verbose=0, dry_run=0, force=0):
self.set_executables(compiler='gcc -mcygwin -O -Wall',
compiler_so='gcc -mcygwin -mdll -O -Wall',
compiler_cxx='g++ -mcygwin -O -Wall',
+ compiler_so_cxx='g++ -mcygwin -mdll -O -Wall',
linker_exe='gcc -mcygwin',
linker_so=('%s -mcygwin %s' %
- (self.linker_dll, shared_option)))
+ (self.linker_dll, shared_option)),
+ linker_exe_cxx='g++ -mcygwin',
+ linker_so_cxx=('%s -mcygwin %s' %
+ (self.linker_dll_cxx, shared_option)))
# cygwin and mingw32 need different sets of libraries
if self.gcc_version == "2.91.57":
@@ -164,8 +170,12 @@ def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
raise CompileError(msg)
else: # for other files use the C-compiler
try:
- self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
- extra_postargs)
+ if self.detect_language(src) == 'c++':
+ self.spawn(self.compiler_so_cxx + cc_args + [src, '-o', obj] +
+ extra_postargs)
+ else:
+ self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
+ extra_postargs)
except DistutilsExecError as msg:
raise CompileError(msg)
@@ -300,9 +310,14 @@ def __init__(self, verbose=0, dry_run=0, force=0):
self.set_executables(compiler='gcc -O -Wall',
compiler_so='gcc -mdll -O -Wall',
compiler_cxx='g++ -O -Wall',
+ compiler_so_cxx='g++ -mdll -O -Wall',
linker_exe='gcc',
linker_so='%s %s %s'
% (self.linker_dll, shared_option,
+ entry_point),
+ linker_exe_cxx='g++',
+ linker_so_cxx='%s %s %s'
+ % (self.linker_dll_cxx, shared_option,
entry_point))
# Maybe we should also append -mthreads, but then the finished
# dlls need another dll (mingwm10.dll see Mingw32 docs)
diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py
index 3414a761e7..f1af560cc1 100644
--- a/Lib/distutils/sysconfig.py
+++ b/Lib/distutils/sysconfig.py
@@ -216,9 +216,11 @@ def customize_compiler(compiler):
_osx_support.customize_compiler(_config_vars)
_config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True'
- (cc, cxx, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \
- get_config_vars('CC', 'CXX', 'CFLAGS',
- 'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS')
+ (cc, cxx, cflags, ccshared, ldshared, ldcxxshared, shlib_suffix, ar, ar_flags) = \
+ get_config_vars('CC', 'CXX', 'CFLAGS', 'CCSHARED', 'LDSHARED', 'LDCXXSHARED',
+ 'SHLIB_SUFFIX', 'AR', 'ARFLAGS')
+
+ cxxflags = cflags
if 'CC' in os.environ:
newcc = os.environ['CC']
@@ -233,19 +235,27 @@ def customize_compiler(compiler):
cxx = os.environ['CXX']
if 'LDSHARED' in os.environ:
ldshared = os.environ['LDSHARED']
+ if 'LDCXXSHARED' in os.environ:
+ ldcxxshared = os.environ['LDCXXSHARED']
if 'CPP' in os.environ:
cpp = os.environ['CPP']
else:
cpp = cc + " -E" # not always
if 'LDFLAGS' in os.environ:
ldshared = ldshared + ' ' + os.environ['LDFLAGS']
+ ldcxxshared = ldcxxshared + ' ' + os.environ['LDFLAGS']
if 'CFLAGS' in os.environ:
- cflags = cflags + ' ' + os.environ['CFLAGS']
+ cflags = os.environ['CFLAGS']
ldshared = ldshared + ' ' + os.environ['CFLAGS']
+ if 'CXXFLAGS' in os.environ:
+ cxxflags = os.environ['CXXFLAGS']
+ ldcxxshared = ldcxxshared + ' ' + os.environ['CXXFLAGS']
if 'CPPFLAGS' in os.environ:
cpp = cpp + ' ' + os.environ['CPPFLAGS']
cflags = cflags + ' ' + os.environ['CPPFLAGS']
+ cxxflags = cxxflags + ' ' + os.environ['CPPFLAGS']
ldshared = ldshared + ' ' + os.environ['CPPFLAGS']
+ ldcxxshared = ldcxxshared + ' ' + os.environ['CPPFLAGS']
if 'AR' in os.environ:
ar = os.environ['AR']
if 'ARFLAGS' in os.environ:
@@ -254,13 +264,17 @@ def customize_compiler(compiler):
archiver = ar + ' ' + ar_flags
cc_cmd = cc + ' ' + cflags
+ cxx_cmd = cxx + ' ' + cxxflags
compiler.set_executables(
preprocessor=cpp,
compiler=cc_cmd,
compiler_so=cc_cmd + ' ' + ccshared,
- compiler_cxx=cxx,
+ compiler_cxx=cxx_cmd,
+ compiler_so_cxx=cxx_cmd + ' ' + ccshared,
linker_so=ldshared,
linker_exe=cc,
+ linker_so_cxx=ldcxxshared,
+ linker_exe_cxx=cxx,
archiver=archiver)
compiler.shared_lib_extension = shlib_suffix
diff --git a/Lib/distutils/unixccompiler.py b/Lib/distutils/unixccompiler.py
index d00c48981e..4a3d271fee 100644
--- a/Lib/distutils/unixccompiler.py
+++ b/Lib/distutils/unixccompiler.py
@@ -52,14 +52,17 @@ class UnixCCompiler(CCompiler):
# are pretty generic; they will probably have to be set by an outsider
# (eg. using information discovered by the sysconfig about building
# Python extensions).
- executables = {'preprocessor' : None,
- 'compiler' : ["cc"],
- 'compiler_so' : ["cc"],
- 'compiler_cxx' : ["cc"],
- 'linker_so' : ["cc", "-shared"],
- 'linker_exe' : ["cc"],
- 'archiver' : ["ar", "-cr"],
- 'ranlib' : None,
+ executables = {'preprocessor' : None,
+ 'compiler' : ["cc"],
+ 'compiler_so' : ["cc"],
+ 'compiler_cxx' : ["c++"],
+ 'compiler_so_cxx' : ["c++"],
+ 'linker_so' : ["cc", "-shared"],
+ 'linker_exe' : ["cc"],
+ 'linker_so_cxx' : ["c++", "-shared"],
+ 'linker_exe_cxx' : ["c++"],
+ 'archiver' : ["ar", "-cr"],
+ 'ranlib' : None,
}
if sys.platform[:6] == "darwin":
@@ -110,12 +113,19 @@ def preprocess(self, source, output_file=None, macros=None,
def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
compiler_so = self.compiler_so
+ compiler_so_cxx = self.compiler_so_cxx
if sys.platform == 'darwin':
compiler_so = _osx_support.compiler_fixup(compiler_so,
cc_args + extra_postargs)
+ compiler_so_cxx = _osx_support.compiler_fixup(compiler_so_cxx,
+ cc_args + extra_postargs)
try:
- self.spawn(compiler_so + cc_args + [src, '-o', obj] +
- extra_postargs)
+ if self.detect_language(src) == 'c++':
+ self.spawn(compiler_so_cxx + cc_args + [src, '-o', obj] +
+ extra_postargs)
+ else:
+ self.spawn(compiler_so + cc_args + [src, '-o', obj] +
+ extra_postargs)
except DistutilsExecError as msg:
raise CompileError(msg)
@@ -173,30 +183,16 @@ def link(self, target_desc, objects,
ld_args.extend(extra_postargs)
self.mkpath(os.path.dirname(output_filename))
try:
- if target_desc == CCompiler.EXECUTABLE:
- linker = self.linker_exe[:]
+ if target_lang == "c++":
+ if target_desc == CCompiler.EXECUTABLE:
+ linker = self.linker_exe_cxx[:]
+ else:
+ linker = self.linker_so_cxx[:]
else:
- linker = self.linker_so[:]
- if target_lang == "c++" and self.compiler_cxx:
- # skip over environment variable settings if /usr/bin/env
- # is used to set up the linker's environment.
- # This is needed on OSX. Note: this assumes that the
- # normal and C++ compiler have the same environment
- # settings.
- i = 0
- if os.path.basename(linker[0]) == "env":
- i = 1
- while '=' in linker[i]:
- i += 1
-
- if os.path.basename(linker[i]) == 'ld_so_aix':
- # AIX platforms prefix the compiler with the ld_so_aix
- # script, so we need to adjust our linker index
- offset = 1
+ if target_desc == CCompiler.EXECUTABLE:
+ linker = self.linker_exe[:]
else:
- offset = 0
-
- linker[i+offset] = self.compiler_cxx[i]
+ linker = self.linker_so[:]
if sys.platform == 'darwin':
linker = _osx_support.compiler_fixup(linker, ld_args)
diff --git a/Makefile.pre.in b/Makefile.pre.in
index f803391346..090f14c46c 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -732,9 +732,9 @@ sharedmods: $(BUILDPYTHON) pybuilddir.txt @LIBMPDEC_INTERNAL@ @LIBEXPAT_INTERNAL
*\ -s*|s*) quiet="-q";; \
*) quiet="";; \
esac; \
- echo "$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' \
+ echo "$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' CFLAGS='$(PY_CFLAGS)' \
$(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build"; \
- $(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' \
+ $(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' CFLAGS='$(PY_CFLAGS)' \
$(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build

View File

@@ -0,0 +1,52 @@
From 5330b6af9f832af59aa5c61d9ef6971053a8e709 Mon Sep 17 00:00:00 2001
From: Jonathan Ringer <jonringer117@gmail.com>
Date: Mon, 9 Nov 2020 10:24:35 -0800
Subject: [PATCH] CPython: Don't use ldconfig
---
Lib/ctypes/util.py | 77 ++--------------------------------------------
1 file changed, 2 insertions(+), 75 deletions(-)
diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py
index 0c2510e161..7fb98af308 100644
--- a/Lib/ctypes/util.py
+++ b/Lib/ctypes/util.py
@@ -268,34 +222,7 @@ def find_library(name, is64 = False):
else:
def _findSoname_ldconfig(name):
- import struct
- if struct.calcsize('l') == 4:
- machine = os.uname().machine + '-32'
- else:
- machine = os.uname().machine + '-64'
- mach_map = {
- 'x86_64-64': 'libc6,x86-64',
- 'ppc64-64': 'libc6,64bit',
- 'sparc64-64': 'libc6,64bit',
- 's390x-64': 'libc6,64bit',
- 'ia64-64': 'libc6,IA-64',
- }
- abi_type = mach_map.get(machine, 'libc6')
-
- # XXX assuming GLIBC's ldconfig (with option -p)
- regex = r'\s+(lib%s\.[^\s]+)\s+\(%s'
- regex = os.fsencode(regex % (re.escape(name), abi_type))
- try:
- with subprocess.Popen(['/sbin/ldconfig', '-p'],
- stdin=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL,
- stdout=subprocess.PIPE,
- env={'LC_ALL': 'C', 'LANG': 'C'}) as p:
- res = re.search(regex, p.stdout.read())
- if res:
- return os.fsdecode(res.group(1))
- except OSError:
- pass
+ return None
def _findLib_ld(name):
# See issue #9998 for why this is needed
--
2.33.1

View File

@@ -0,0 +1,52 @@
From 5330b6af9f832af59aa5c61d9ef6971053a8e709 Mon Sep 17 00:00:00 2001
From: Jonathan Ringer <jonringer117@gmail.com>
Date: Mon, 9 Nov 2020 10:24:35 -0800
Subject: [PATCH] CPython: Don't use ldconfig
---
Lib/ctypes/util.py | 77 ++--------------------------------------------
1 file changed, 2 insertions(+), 75 deletions(-)
diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py
index 0c2510e161..7fb98af308 100644
--- a/Lib/ctypes/util.py
+++ b/Lib/ctypes/util.py
@@ -268,34 +222,7 @@ def find_library(name, is64 = False):
else:
def _findSoname_ldconfig(name):
- import struct
- if struct.calcsize('l') == 4:
- machine = os.uname().machine + '-32'
- else:
- machine = os.uname().machine + '-64'
- mach_map = {
- 'x86_64-64': 'libc6,x86-64',
- 'ppc64-64': 'libc6,64bit',
- 'sparc64-64': 'libc6,64bit',
- 's390x-64': 'libc6,64bit',
- 'ia64-64': 'libc6,IA-64',
- }
- abi_type = mach_map.get(machine, 'libc6')
-
- # XXX assuming GLIBC's ldconfig (with option -p)
- regex = r'\s+(lib%s\.[^\s]+)\s+\(%s'
- regex = os.fsencode(regex % (re.escape(name), abi_type))
- try:
- with subprocess.Popen(['/sbin/ldconfig', '-p'],
- stdin=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL,
- stdout=subprocess.PIPE,
- env={'LC_ALL': 'C', 'LANG': 'C'}) as p:
- res = re.search(regex, p.stdout.read())
- if res:
- return os.fsdecode(res.group(1))
- except OSError:
- pass
+ return None
def _findLib_ld(name):
# See issue #9998 for why this is needed
--
2.33.1

View File

@@ -0,0 +1,12 @@
diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py
index 4856594755..6769ab8026 100644
--- a/Lib/venv/__init__.py
+++ b/Lib/venv/__init__.py
@@ -522,6 +522,7 @@ def skip_file(f):
with open(dstfile, 'wb') as f:
f.write(new_data)
shutil.copymode(srcfile, dstfile)
+ os.chmod(dstfile, 0o644)
def upgrade_dependencies(self, context):
logger.debug(

View File

@@ -0,0 +1,483 @@
From 9f69a58623bd01349a18ba0c7a9cb1dad6a51e8e Mon Sep 17 00:00:00 2001
From: Serhiy Storchaka <storchaka@gmail.com>
Date: Mon, 12 May 2025 20:42:23 +0300
Subject: [PATCH] gh-133767: Fix use-after-free in the unicode-escape decoder
with an error handler (GH-129648)
If the error handler is used, a new bytes object is created to set as
the object attribute of UnicodeDecodeError, and that bytes object then
replaces the original data. A pointer to the decoded data will became invalid
after destroying that temporary bytes object. So we need other way to return
the first invalid escape from _PyUnicode_DecodeUnicodeEscapeInternal().
_PyBytes_DecodeEscape() does not have such issue, because it does not
use the error handlers registry, but it should be changed for compatibility
with _PyUnicode_DecodeUnicodeEscapeInternal().
---
Include/internal/pycore_bytesobject.h | 5 +-
Include/internal/pycore_unicodeobject.h | 12 +++--
Lib/test/test_codeccallbacks.py | 39 +++++++++++++-
Lib/test/test_codecs.py | 52 +++++++++++++++----
...-05-09-20-22-54.gh-issue-133767.kN2i3Q.rst | 2 +
Objects/bytesobject.c | 41 ++++++++-------
Objects/unicodeobject.c | 46 +++++++++-------
Parser/string_parser.c | 26 ++++++----
8 files changed, 160 insertions(+), 63 deletions(-)
create mode 100644 Misc/NEWS.d/next/Security/2025-05-09-20-22-54.gh-issue-133767.kN2i3Q.rst
diff --git a/Include/internal/pycore_bytesobject.h b/Include/internal/pycore_bytesobject.h
index 300e7f4896a39e..8ea9b3ebb88454 100644
--- a/Include/internal/pycore_bytesobject.h
+++ b/Include/internal/pycore_bytesobject.h
@@ -20,8 +20,9 @@ extern PyObject* _PyBytes_FromHex(
// Helper for PyBytes_DecodeEscape that detects invalid escape chars.
// Export for test_peg_generator.
-PyAPI_FUNC(PyObject*) _PyBytes_DecodeEscape(const char *, Py_ssize_t,
- const char *, const char **);
+PyAPI_FUNC(PyObject*) _PyBytes_DecodeEscape2(const char *, Py_ssize_t,
+ const char *,
+ int *, const char **);
// Substring Search.
diff --git a/Include/internal/pycore_unicodeobject.h b/Include/internal/pycore_unicodeobject.h
index c85d53b89accdb..3791b913c17546 100644
--- a/Include/internal/pycore_unicodeobject.h
+++ b/Include/internal/pycore_unicodeobject.h
@@ -139,14 +139,18 @@ extern PyObject* _PyUnicode_DecodeUnicodeEscapeStateful(
// Helper for PyUnicode_DecodeUnicodeEscape that detects invalid escape
// chars.
// Export for test_peg_generator.
-PyAPI_FUNC(PyObject*) _PyUnicode_DecodeUnicodeEscapeInternal(
+PyAPI_FUNC(PyObject*) _PyUnicode_DecodeUnicodeEscapeInternal2(
const char *string, /* Unicode-Escape encoded string */
Py_ssize_t length, /* size of string */
const char *errors, /* error handling */
Py_ssize_t *consumed, /* bytes consumed */
- const char **first_invalid_escape); /* on return, points to first
- invalid escaped char in
- string. */
+ int *first_invalid_escape_char, /* on return, if not -1, contain the first
+ invalid escaped char (<= 0xff) or invalid
+ octal escape (> 0xff) in string. */
+ const char **first_invalid_escape_ptr); /* on return, if not NULL, may
+ point to the first invalid escaped
+ char in string.
+ May be NULL if errors is not NULL. */
/* --- Raw-Unicode-Escape Codecs ---------------------------------------------- */
diff --git a/Lib/test/test_codeccallbacks.py b/Lib/test/test_codeccallbacks.py
index 86e5e5c1474674..a767f67a02cf56 100644
--- a/Lib/test/test_codeccallbacks.py
+++ b/Lib/test/test_codeccallbacks.py
@@ -2,6 +2,7 @@
import codecs
import html.entities
import itertools
+import re
import sys
import unicodedata
import unittest
@@ -1125,7 +1126,7 @@ def test_bug828737(self):
text = 'abc<def>ghi'*n
text.translate(charmap)
- def test_mutatingdecodehandler(self):
+ def test_mutating_decode_handler(self):
baddata = [
("ascii", b"\xff"),
("utf-7", b"++"),
@@ -1160,6 +1161,42 @@ def mutating(exc):
for (encoding, data) in baddata:
self.assertEqual(data.decode(encoding, "test.mutating"), "\u4242")
+ def test_mutating_decode_handler_unicode_escape(self):
+ decode = codecs.unicode_escape_decode
+ def mutating(exc):
+ if isinstance(exc, UnicodeDecodeError):
+ r = data.get(exc.object[:exc.end])
+ if r is not None:
+ exc.object = r[0] + exc.object[exc.end:]
+ return ('\u0404', r[1])
+ raise AssertionError("don't know how to handle %r" % exc)
+
+ codecs.register_error('test.mutating2', mutating)
+ data = {
+ br'\x0': (b'\\', 0),
+ br'\x3': (b'xxx\\', 3),
+ br'\x5': (b'x\\', 1),
+ }
+ def check(input, expected, msg):
+ with self.assertWarns(DeprecationWarning) as cm:
+ self.assertEqual(decode(input, 'test.mutating2'), (expected, len(input)))
+ self.assertIn(msg, str(cm.warning))
+
+ check(br'\x0n\z', '\u0404\n\\z', r'"\z" is an invalid escape sequence')
+ check(br'\x0n\501', '\u0404\n\u0141', r'"\501" is an invalid octal escape sequence')
+ check(br'\x0z', '\u0404\\z', r'"\z" is an invalid escape sequence')
+
+ check(br'\x3n\zr', '\u0404\n\\zr', r'"\z" is an invalid escape sequence')
+ check(br'\x3zr', '\u0404\\zr', r'"\z" is an invalid escape sequence')
+ check(br'\x3z5', '\u0404\\z5', r'"\z" is an invalid escape sequence')
+ check(memoryview(br'\x3z5x')[:-1], '\u0404\\z5', r'"\z" is an invalid escape sequence')
+ check(memoryview(br'\x3z5xy')[:-2], '\u0404\\z5', r'"\z" is an invalid escape sequence')
+
+ check(br'\x5n\z', '\u0404\n\\z', r'"\z" is an invalid escape sequence')
+ check(br'\x5n\501', '\u0404\n\u0141', r'"\501" is an invalid octal escape sequence')
+ check(br'\x5z', '\u0404\\z', r'"\z" is an invalid escape sequence')
+ check(memoryview(br'\x5zy')[:-1], '\u0404\\z', r'"\z" is an invalid escape sequence')
+
# issue32583
def test_crashing_decode_handler(self):
# better generating one more character to fill the extra space slot
diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py
index 94fcf98e75721f..d42270da15ee32 100644
--- a/Lib/test/test_codecs.py
+++ b/Lib/test/test_codecs.py
@@ -1196,23 +1196,39 @@ def test_escape(self):
check(br"[\1010]", b"[A0]")
check(br"[\x41]", b"[A]")
check(br"[\x410]", b"[A0]")
+
+ def test_warnings(self):
+ decode = codecs.escape_decode
+ check = coding_checker(self, decode)
for i in range(97, 123):
b = bytes([i])
if b not in b'abfnrtvx':
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\%c" is an invalid escape sequence' % i):
check(b"\\" + b, b"\\" + b)
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\%c" is an invalid escape sequence' % (i-32)):
check(b"\\" + b.upper(), b"\\" + b.upper())
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\8" is an invalid escape sequence'):
check(br"\8", b"\\8")
with self.assertWarns(DeprecationWarning):
check(br"\9", b"\\9")
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\\xfa" is an invalid escape sequence') as cm:
check(b"\\\xfa", b"\\\xfa")
for i in range(0o400, 0o1000):
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\%o" is an invalid octal escape sequence' % i):
check(rb'\%o' % i, bytes([i & 0o377]))
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\z" is an invalid escape sequence'):
+ self.assertEqual(decode(br'\x\z', 'ignore'), (b'\\z', 4))
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\501" is an invalid octal escape sequence'):
+ self.assertEqual(decode(br'\x\501', 'ignore'), (b'A', 6))
+
def test_errors(self):
decode = codecs.escape_decode
self.assertRaises(ValueError, decode, br"\x")
@@ -2661,24 +2677,40 @@ def test_escape_decode(self):
check(br"[\x410]", "[A0]")
check(br"\u20ac", "\u20ac")
check(br"\U0001d120", "\U0001d120")
+
+ def test_decode_warnings(self):
+ decode = codecs.unicode_escape_decode
+ check = coding_checker(self, decode)
for i in range(97, 123):
b = bytes([i])
if b not in b'abfnrtuvx':
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\%c" is an invalid escape sequence' % i):
check(b"\\" + b, "\\" + chr(i))
if b.upper() not in b'UN':
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\%c" is an invalid escape sequence' % (i-32)):
check(b"\\" + b.upper(), "\\" + chr(i-32))
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\8" is an invalid escape sequence'):
check(br"\8", "\\8")
with self.assertWarns(DeprecationWarning):
check(br"\9", "\\9")
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\\xfa" is an invalid escape sequence') as cm:
check(b"\\\xfa", "\\\xfa")
for i in range(0o400, 0o1000):
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\%o" is an invalid octal escape sequence' % i):
check(rb'\%o' % i, chr(i))
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\z" is an invalid escape sequence'):
+ self.assertEqual(decode(br'\x\z', 'ignore'), ('\\z', 4))
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\501" is an invalid octal escape sequence'):
+ self.assertEqual(decode(br'\x\501', 'ignore'), ('\u0141', 6))
+
def test_decode_errors(self):
decode = codecs.unicode_escape_decode
for c, d in (b'x', 2), (b'u', 4), (b'U', 4):
diff --git a/Misc/NEWS.d/next/Security/2025-05-09-20-22-54.gh-issue-133767.kN2i3Q.rst b/Misc/NEWS.d/next/Security/2025-05-09-20-22-54.gh-issue-133767.kN2i3Q.rst
new file mode 100644
index 00000000000000..39d2f1e1a892cf
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2025-05-09-20-22-54.gh-issue-133767.kN2i3Q.rst
@@ -0,0 +1,2 @@
+Fix use-after-free in the "unicode-escape" decoder with a non-"strict" error
+handler.
diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c
index fc407ec6bf99d6..87ea1162e03513 100644
--- a/Objects/bytesobject.c
+++ b/Objects/bytesobject.c
@@ -1075,10 +1075,11 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len,
}
/* Unescape a backslash-escaped string. */
-PyObject *_PyBytes_DecodeEscape(const char *s,
+PyObject *_PyBytes_DecodeEscape2(const char *s,
Py_ssize_t len,
const char *errors,
- const char **first_invalid_escape)
+ int *first_invalid_escape_char,
+ const char **first_invalid_escape_ptr)
{
int c;
char *p;
@@ -1092,7 +1093,8 @@ PyObject *_PyBytes_DecodeEscape(const char *s,
return NULL;
writer.overallocate = 1;
- *first_invalid_escape = NULL;
+ *first_invalid_escape_char = -1;
+ *first_invalid_escape_ptr = NULL;
end = s + len;
while (s < end) {
@@ -1130,9 +1132,10 @@ PyObject *_PyBytes_DecodeEscape(const char *s,
c = (c<<3) + *s++ - '0';
}
if (c > 0377) {
- if (*first_invalid_escape == NULL) {
- *first_invalid_escape = s-3; /* Back up 3 chars, since we've
- already incremented s. */
+ if (*first_invalid_escape_char == -1) {
+ *first_invalid_escape_char = c;
+ /* Back up 3 chars, since we've already incremented s. */
+ *first_invalid_escape_ptr = s - 3;
}
}
*p++ = c;
@@ -1173,9 +1176,10 @@ PyObject *_PyBytes_DecodeEscape(const char *s,
break;
default:
- if (*first_invalid_escape == NULL) {
- *first_invalid_escape = s-1; /* Back up one char, since we've
- already incremented s. */
+ if (*first_invalid_escape_char == -1) {
+ *first_invalid_escape_char = (unsigned char)s[-1];
+ /* Back up one char, since we've already incremented s. */
+ *first_invalid_escape_ptr = s - 1;
}
*p++ = '\\';
s--;
@@ -1195,18 +1199,19 @@ PyObject *PyBytes_DecodeEscape(const char *s,
Py_ssize_t Py_UNUSED(unicode),
const char *Py_UNUSED(recode_encoding))
{
- const char* first_invalid_escape;
- PyObject *result = _PyBytes_DecodeEscape(s, len, errors,
- &first_invalid_escape);
+ int first_invalid_escape_char;
+ const char *first_invalid_escape_ptr;
+ PyObject *result = _PyBytes_DecodeEscape2(s, len, errors,
+ &first_invalid_escape_char,
+ &first_invalid_escape_ptr);
if (result == NULL)
return NULL;
- if (first_invalid_escape != NULL) {
- unsigned char c = *first_invalid_escape;
- if ('4' <= c && c <= '7') {
+ if (first_invalid_escape_char != -1) {
+ if (first_invalid_escape_char > 0xff) {
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
- "b\"\\%.3s\" is an invalid octal escape sequence. "
+ "b\"\\%o\" is an invalid octal escape sequence. "
"Such sequences will not work in the future. ",
- first_invalid_escape) < 0)
+ first_invalid_escape_char) < 0)
{
Py_DECREF(result);
return NULL;
@@ -1216,7 +1221,7 @@ PyObject *PyBytes_DecodeEscape(const char *s,
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
"b\"\\%c\" is an invalid escape sequence. "
"Such sequences will not work in the future. ",
- c) < 0)
+ first_invalid_escape_char) < 0)
{
Py_DECREF(result);
return NULL;
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index f3f0c9646a652e..cd26494ad8f1d6 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -6596,13 +6596,15 @@ _PyUnicode_GetNameCAPI(void)
/* --- Unicode Escape Codec ----------------------------------------------- */
PyObject *
-_PyUnicode_DecodeUnicodeEscapeInternal(const char *s,
+_PyUnicode_DecodeUnicodeEscapeInternal2(const char *s,
Py_ssize_t size,
const char *errors,
Py_ssize_t *consumed,
- const char **first_invalid_escape)
+ int *first_invalid_escape_char,
+ const char **first_invalid_escape_ptr)
{
const char *starts = s;
+ const char *initial_starts = starts;
_PyUnicodeWriter writer;
const char *end;
PyObject *errorHandler = NULL;
@@ -6610,7 +6612,8 @@ _PyUnicode_DecodeUnicodeEscapeInternal(const char *s,
_PyUnicode_Name_CAPI *ucnhash_capi;
// so we can remember if we've seen an invalid escape char or not
- *first_invalid_escape = NULL;
+ *first_invalid_escape_char = -1;
+ *first_invalid_escape_ptr = NULL;
if (size == 0) {
if (consumed) {
@@ -6698,9 +6701,12 @@ _PyUnicode_DecodeUnicodeEscapeInternal(const char *s,
}
}
if (ch > 0377) {
- if (*first_invalid_escape == NULL) {
- *first_invalid_escape = s-3; /* Back up 3 chars, since we've
- already incremented s. */
+ if (*first_invalid_escape_char == -1) {
+ *first_invalid_escape_char = ch;
+ if (starts == initial_starts) {
+ /* Back up 3 chars, since we've already incremented s. */
+ *first_invalid_escape_ptr = s - 3;
+ }
}
}
WRITE_CHAR(ch);
@@ -6795,9 +6801,12 @@ _PyUnicode_DecodeUnicodeEscapeInternal(const char *s,
goto error;
default:
- if (*first_invalid_escape == NULL) {
- *first_invalid_escape = s-1; /* Back up one char, since we've
- already incremented s. */
+ if (*first_invalid_escape_char == -1) {
+ *first_invalid_escape_char = c;
+ if (starts == initial_starts) {
+ /* Back up one char, since we've already incremented s. */
+ *first_invalid_escape_ptr = s - 1;
+ }
}
WRITE_ASCII_CHAR('\\');
WRITE_CHAR(c);
@@ -6842,19 +6851,20 @@ _PyUnicode_DecodeUnicodeEscapeStateful(const char *s,
const char *errors,
Py_ssize_t *consumed)
{
- const char *first_invalid_escape;
- PyObject *result = _PyUnicode_DecodeUnicodeEscapeInternal(s, size, errors,
+ int first_invalid_escape_char;
+ const char *first_invalid_escape_ptr;
+ PyObject *result = _PyUnicode_DecodeUnicodeEscapeInternal2(s, size, errors,
consumed,
- &first_invalid_escape);
+ &first_invalid_escape_char,
+ &first_invalid_escape_ptr);
if (result == NULL)
return NULL;
- if (first_invalid_escape != NULL) {
- unsigned char c = *first_invalid_escape;
- if ('4' <= c && c <= '7') {
+ if (first_invalid_escape_char != -1) {
+ if (first_invalid_escape_char > 0xff) {
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
- "\"\\%.3s\" is an invalid octal escape sequence. "
+ "\"\\%o\" is an invalid octal escape sequence. "
"Such sequences will not work in the future. ",
- first_invalid_escape) < 0)
+ first_invalid_escape_char) < 0)
{
Py_DECREF(result);
return NULL;
@@ -6864,7 +6874,7 @@ _PyUnicode_DecodeUnicodeEscapeStateful(const char *s,
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
"\"\\%c\" is an invalid escape sequence. "
"Such sequences will not work in the future. ",
- c) < 0)
+ first_invalid_escape_char) < 0)
{
Py_DECREF(result);
return NULL;
diff --git a/Parser/string_parser.c b/Parser/string_parser.c
index d3631b114c5a3c..ebe68989d1af58 100644
--- a/Parser/string_parser.c
+++ b/Parser/string_parser.c
@@ -196,15 +196,18 @@ decode_unicode_with_escapes(Parser *parser, const char *s, size_t len, Token *t)
len = (size_t)(p - buf);
s = buf;
- const char *first_invalid_escape;
- v = _PyUnicode_DecodeUnicodeEscapeInternal(s, (Py_ssize_t)len, NULL, NULL, &first_invalid_escape);
+ int first_invalid_escape_char;
+ const char *first_invalid_escape_ptr;
+ v = _PyUnicode_DecodeUnicodeEscapeInternal2(s, (Py_ssize_t)len, NULL, NULL,
+ &first_invalid_escape_char,
+ &first_invalid_escape_ptr);
// HACK: later we can simply pass the line no, since we don't preserve the tokens
// when we are decoding the string but we preserve the line numbers.
- if (v != NULL && first_invalid_escape != NULL && t != NULL) {
- if (warn_invalid_escape_sequence(parser, s, first_invalid_escape, t) < 0) {
- /* We have not decref u before because first_invalid_escape points
- inside u. */
+ if (v != NULL && first_invalid_escape_ptr != NULL && t != NULL) {
+ if (warn_invalid_escape_sequence(parser, s, first_invalid_escape_ptr, t) < 0) {
+ /* We have not decref u before because first_invalid_escape_ptr
+ points inside u. */
Py_XDECREF(u);
Py_DECREF(v);
return NULL;
@@ -217,14 +220,17 @@ decode_unicode_with_escapes(Parser *parser, const char *s, size_t len, Token *t)
static PyObject *
decode_bytes_with_escapes(Parser *p, const char *s, Py_ssize_t len, Token *t)
{
- const char *first_invalid_escape;
- PyObject *result = _PyBytes_DecodeEscape(s, len, NULL, &first_invalid_escape);
+ int first_invalid_escape_char;
+ const char *first_invalid_escape_ptr;
+ PyObject *result = _PyBytes_DecodeEscape2(s, len, NULL,
+ &first_invalid_escape_char,
+ &first_invalid_escape_ptr);
if (result == NULL) {
return NULL;
}
- if (first_invalid_escape != NULL) {
- if (warn_invalid_escape_sequence(p, s, first_invalid_escape, t) < 0) {
+ if (first_invalid_escape_ptr != NULL) {
+ if (warn_invalid_escape_sequence(p, s, first_invalid_escape_ptr, t) < 0) {
Py_DECREF(result);
return NULL;
}

View File

@@ -0,0 +1,40 @@
diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py
index 117bf06cb01..ff50cb083bd 100644
--- a/Lib/ctypes/util.py
+++ b/Lib/ctypes/util.py
@@ -280,34 +280,7 @@ def find_library(name, is64 = False):
else:
def _findSoname_ldconfig(name):
- import struct
- if struct.calcsize('l') == 4:
- machine = os.uname().machine + '-32'
- else:
- machine = os.uname().machine + '-64'
- mach_map = {
- 'x86_64-64': 'libc6,x86-64',
- 'ppc64-64': 'libc6,64bit',
- 'sparc64-64': 'libc6,64bit',
- 's390x-64': 'libc6,64bit',
- 'ia64-64': 'libc6,IA-64',
- }
- abi_type = mach_map.get(machine, 'libc6')
-
- # XXX assuming GLIBC's ldconfig (with option -p)
- regex = r'\s+(lib%s\.[^\s]+)\s+\(%s'
- regex = os.fsencode(regex % (re.escape(name), abi_type))
- try:
- with subprocess.Popen(['/sbin/ldconfig', '-p'],
- stdin=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL,
- stdout=subprocess.PIPE,
- env={'LC_ALL': 'C', 'LANG': 'C'}) as p:
- res = re.search(regex, p.stdout.read())
- if res:
- return os.fsdecode(res.group(1))
- except OSError:
- pass
+ return None
def _findLib_ld(name):
# See issue #9998 for why this is needed

View File

@@ -0,0 +1,54 @@
From debccd4be0a8d619770f63622d9de1b451dd02ac Mon Sep 17 00:00:00 2001
From: Ben Wolsieffer <benwolsieffer@gmail.com>
Date: Fri, 25 Sep 2020 16:49:16 -0400
Subject: [PATCH] Fix finding headers when cross compiling
When cross-compiling third-party extensions, get_python_inc() may be called to
return the path to Python's headers. However, it uses the sys.prefix or
sys.exec_prefix of the build Python, which returns incorrect paths when
cross-compiling (paths pointing to build system headers).
To fix this, we use the INCLUDEPY and CONFINCLUDEPY conf variables, which can
be configured to point at host Python by setting _PYTHON_SYSCONFIGDATA_NAME.
The existing behavior is maintained on non-POSIX platforms or if a prefix is
manually specified.
---
Lib/distutils/sysconfig.py | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py
index 37feae5df7..6d4ad06696 100644
--- a/Lib/distutils/sysconfig.py
+++ b/Lib/distutils/sysconfig.py
@@ -95,8 +95,6 @@ def get_python_inc(plat_specific=0, prefix=None):
If 'prefix' is supplied, use it instead of sys.base_prefix or
sys.base_exec_prefix -- i.e., ignore 'plat_specific'.
"""
- if prefix is None:
- prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX
if os.name == "posix":
if python_build:
# Assume the executable is in the build directory. The
@@ -109,9 +107,17 @@ def get_python_inc(plat_specific=0, prefix=None):
else:
incdir = os.path.join(get_config_var('srcdir'), 'Include')
return os.path.normpath(incdir)
- python_dir = 'python' + get_python_version() + build_flags
- return os.path.join(prefix, "include", python_dir)
+ if prefix is None:
+ if plat_specific:
+ return get_config_var('CONFINCLUDEPY')
+ else:
+ return get_config_var('INCLUDEPY')
+ else:
+ python_dir = 'python' + get_python_version() + build_flags
+ return os.path.join(prefix, "include", python_dir)
elif os.name == "nt":
+ if prefix is None:
+ prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX
if python_build:
# Include both the include and PC dir to ensure we can find
# pyconfig.h
--
2.28.0

View File

@@ -0,0 +1,37 @@
From e6b247c8e524dbe5fc03b3492f628d0d5348bc49 Mon Sep 17 00:00:00 2001
From: Victor Stinner <vstinner@redhat.com>
Date: Tue, 18 Dec 2018 14:47:21 +0100
Subject: [PATCH] bpo-35523: Remove ctypes callback workaround (GH-11211)
Remove ctypes callback workaround: no longer create a callback at startup.
Avoid SELinux alert on "import ctypes" and "import uuid".
---
Lib/ctypes/__init__.py | 5 -----
.../next/Library/2018-12-18-13-52-13.bpo-35523.SkoMno.rst | 2 ++
2 files changed, 2 insertions(+), 5 deletions(-)
create mode 100644 Misc/NEWS.d/next/Library/2018-12-18-13-52-13.bpo-35523.SkoMno.rst
diff --git a/Lib/ctypes/__init__.py b/Lib/ctypes/__init__.py
index 6146773988648..5f78beda5866e 100644
--- a/Lib/ctypes/__init__.py
+++ b/Lib/ctypes/__init__.py
@@ -266,11 +266,6 @@ def _reset_cache():
# _SimpleCData.c_char_p_from_param
POINTER(c_char).from_param = c_char_p.from_param
_pointer_type_cache[None] = c_void_p
- # XXX for whatever reasons, creating the first instance of a callback
- # function is needed for the unittests on Win64 to succeed. This MAY
- # be a compiler bug, since the problem occurs only when _ctypes is
- # compiled with the MS SDK compiler. Or an uninitialized variable?
- CFUNCTYPE(c_int)(lambda: None)
def create_unicode_buffer(init, size=None):
"""create_unicode_buffer(aString) -> character array
diff --git a/Misc/NEWS.d/next/Library/2018-12-18-13-52-13.bpo-35523.SkoMno.rst b/Misc/NEWS.d/next/Library/2018-12-18-13-52-13.bpo-35523.SkoMno.rst
new file mode 100644
index 0000000000000..94a9fd257383e
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2018-12-18-13-52-13.bpo-35523.SkoMno.rst
@@ -0,0 +1,2 @@
+Remove :mod:`ctypes` callback workaround: no longer create a callback at
+startup. Avoid SELinux alert on ``import ctypes`` and ``import uuid``.

View File

@@ -0,0 +1,248 @@
--- a/Lib/_osx_support.py
+++ b/Lib/_osx_support.py
@@ -14,13 +14,13 @@ __all__ = [
# configuration variables that may contain universal build flags,
# like "-arch" or "-isdkroot", that may need customization for
# the user environment
-_UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS', 'BASECFLAGS',
- 'BLDSHARED', 'LDSHARED', 'CC', 'CXX',
- 'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS',
- 'PY_CORE_CFLAGS', 'PY_CORE_LDFLAGS')
+_UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'CXXFLAGS', 'LDFLAGS', 'CPPFLAGS',
+ 'BASECFLAGS', 'BLDSHARED', 'LDSHARED', 'LDCXXSHARED',
+ 'CC', 'CXX', 'PY_CFLAGS', 'PY_LDFLAGS',
+ 'PY_CPPFLAGS', 'PY_CORE_LDFLAGS', 'PY_CORE_CFLAGS')
# configuration variables that may contain compiler calls
-_COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'CC', 'CXX')
+_COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'LDCXXSHARED', 'CC', 'CXX')
# prefix added to original configuration variable names
_INITPRE = '_OSX_SUPPORT_INITIAL_'
--- a/Lib/distutils/cygwinccompiler.py
+++ b/Lib/distutils/cygwinccompiler.py
@@ -125,8 +125,10 @@ class CygwinCCompiler(UnixCCompiler):
# dllwrap 2.10.90 is buggy
if self.ld_version >= "2.10.90":
self.linker_dll = "gcc"
+ self.linker_dll_cxx = "g++"
else:
self.linker_dll = "dllwrap"
+ self.linker_dll_cxx = "dllwrap"
# ld_version >= "2.13" support -shared so use it instead of
# -mdll -static
@@ -140,9 +142,13 @@ class CygwinCCompiler(UnixCCompiler):
self.set_executables(compiler='gcc -mcygwin -O -Wall',
compiler_so='gcc -mcygwin -mdll -O -Wall',
compiler_cxx='g++ -mcygwin -O -Wall',
+ compiler_so_cxx='g++ -mcygwin -mdll -O -Wall',
linker_exe='gcc -mcygwin',
linker_so=('%s -mcygwin %s' %
- (self.linker_dll, shared_option)))
+ (self.linker_dll, shared_option)),
+ linker_exe_cxx='g++ -mcygwin',
+ linker_so_cxx=('%s -mcygwin %s' %
+ (self.linker_dll_cxx, shared_option)))
# cygwin and mingw32 need different sets of libraries
if self.gcc_version == "2.91.57":
@@ -166,8 +172,12 @@ class CygwinCCompiler(UnixCCompiler):
raise CompileError(msg)
else: # for other files use the C-compiler
try:
- self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
- extra_postargs)
+ if self.detect_language(src) == 'c++':
+ self.spawn(self.compiler_so_cxx + cc_args + [src, '-o', obj] +
+ extra_postargs)
+ else:
+ self.spawn(self.compiler_so + cc_args + [src, '-o', obj] +
+ extra_postargs)
except DistutilsExecError as msg:
raise CompileError(msg)
@@ -302,9 +312,14 @@ class Mingw32CCompiler(CygwinCCompiler):
self.set_executables(compiler='gcc -O -Wall',
compiler_so='gcc -mdll -O -Wall',
compiler_cxx='g++ -O -Wall',
+ compiler_so_cxx='g++ -mdll -O -Wall',
linker_exe='gcc',
linker_so='%s %s %s'
% (self.linker_dll, shared_option,
+ entry_point),
+ linker_exe_cxx='g++',
+ linker_so_cxx='%s %s %s'
+ % (self.linker_dll_cxx, shared_option,
entry_point))
# Maybe we should also append -mthreads, but then the finished
# dlls need another dll (mingwm10.dll see Mingw32 docs)
--- a/Lib/distutils/sysconfig.py
+++ b/Lib/distutils/sysconfig.py
@@ -170,9 +170,11 @@ def customize_compiler(compiler):
_osx_support.customize_compiler(_config_vars)
_config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True'
- (cc, cxx, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \
- get_config_vars('CC', 'CXX', 'CFLAGS',
- 'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS')
+ (cc, cxx, cflags, ccshared, ldshared, ldcxxshared, shlib_suffix, ar, ar_flags) = \
+ get_config_vars('CC', 'CXX', 'CFLAGS', 'CCSHARED', 'LDSHARED', 'LDCXXSHARED',
+ 'SHLIB_SUFFIX', 'AR', 'ARFLAGS')
+
+ cxxflags = cflags
if 'CC' in os.environ:
newcc = os.environ['CC']
@@ -187,19 +189,27 @@ def customize_compiler(compiler):
cxx = os.environ['CXX']
if 'LDSHARED' in os.environ:
ldshared = os.environ['LDSHARED']
+ if 'LDCXXSHARED' in os.environ:
+ ldcxxshared = os.environ['LDCXXSHARED']
if 'CPP' in os.environ:
cpp = os.environ['CPP']
else:
cpp = cc + " -E" # not always
if 'LDFLAGS' in os.environ:
ldshared = ldshared + ' ' + os.environ['LDFLAGS']
+ ldcxxshared = ldcxxshared + ' ' + os.environ['LDFLAGS']
if 'CFLAGS' in os.environ:
- cflags = cflags + ' ' + os.environ['CFLAGS']
+ cflags = os.environ['CFLAGS']
ldshared = ldshared + ' ' + os.environ['CFLAGS']
+ if 'CXXFLAGS' in os.environ:
+ cxxflags = os.environ['CXXFLAGS']
+ ldcxxshared = ldcxxshared + ' ' + os.environ['CXXFLAGS']
if 'CPPFLAGS' in os.environ:
cpp = cpp + ' ' + os.environ['CPPFLAGS']
cflags = cflags + ' ' + os.environ['CPPFLAGS']
+ cxxflags = cxxflags + ' ' + os.environ['CPPFLAGS']
ldshared = ldshared + ' ' + os.environ['CPPFLAGS']
+ ldcxxshared = ldcxxshared + ' ' + os.environ['CPPFLAGS']
if 'AR' in os.environ:
ar = os.environ['AR']
if 'ARFLAGS' in os.environ:
@@ -208,13 +218,17 @@ def customize_compiler(compiler):
archiver = ar + ' ' + ar_flags
cc_cmd = cc + ' ' + cflags
+ cxx_cmd = cxx + ' ' + cxxflags
compiler.set_executables(
preprocessor=cpp,
compiler=cc_cmd,
compiler_so=cc_cmd + ' ' + ccshared,
- compiler_cxx=cxx,
+ compiler_cxx=cxx_cmd,
+ compiler_so_cxx=cxx_cmd + ' ' + ccshared,
linker_so=ldshared,
linker_exe=cc,
+ linker_so_cxx=ldcxxshared,
+ linker_exe_cxx=cxx,
archiver=archiver)
compiler.shared_lib_extension = shlib_suffix
--- a/Lib/distutils/unixccompiler.py
+++ b/Lib/distutils/unixccompiler.py
@@ -52,14 +52,17 @@ class UnixCCompiler(CCompiler):
# are pretty generic; they will probably have to be set by an outsider
# (eg. using information discovered by the sysconfig about building
# Python extensions).
- executables = {'preprocessor' : None,
- 'compiler' : ["cc"],
- 'compiler_so' : ["cc"],
- 'compiler_cxx' : ["cc"],
- 'linker_so' : ["cc", "-shared"],
- 'linker_exe' : ["cc"],
- 'archiver' : ["ar", "-cr"],
- 'ranlib' : None,
+ executables = {'preprocessor' : None,
+ 'compiler' : ["cc"],
+ 'compiler_so' : ["cc"],
+ 'compiler_cxx' : ["c++"],
+ 'compiler_so_cxx' : ["c++"],
+ 'linker_so' : ["cc", "-shared"],
+ 'linker_exe' : ["cc"],
+ 'linker_so_cxx' : ["c++", "-shared"],
+ 'linker_exe_cxx' : ["c++"],
+ 'archiver' : ["ar", "-cr"],
+ 'ranlib' : None,
}
if sys.platform[:6] == "darwin":
@@ -110,12 +113,19 @@ class UnixCCompiler(CCompiler):
def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
compiler_so = self.compiler_so
+ compiler_so_cxx = self.compiler_so_cxx
if sys.platform == 'darwin':
compiler_so = _osx_support.compiler_fixup(compiler_so,
cc_args + extra_postargs)
+ compiler_so_cxx = _osx_support.compiler_fixup(compiler_so_cxx,
+ cc_args + extra_postargs)
try:
- self.spawn(compiler_so + cc_args + [src, '-o', obj] +
- extra_postargs)
+ if self.detect_language(src) == 'c++':
+ self.spawn(compiler_so_cxx + cc_args + [src, '-o', obj] +
+ extra_postargs)
+ else:
+ self.spawn(compiler_so + cc_args + [src, '-o', obj] +
+ extra_postargs)
except DistutilsExecError as msg:
raise CompileError(msg)
@@ -173,30 +183,16 @@ class UnixCCompiler(CCompiler):
ld_args.extend(extra_postargs)
self.mkpath(os.path.dirname(output_filename))
try:
- if target_desc == CCompiler.EXECUTABLE:
- linker = self.linker_exe[:]
+ if target_lang == "c++":
+ if target_desc == CCompiler.EXECUTABLE:
+ linker = self.linker_exe_cxx[:]
+ else:
+ linker = self.linker_so_cxx[:]
else:
- linker = self.linker_so[:]
- if target_lang == "c++" and self.compiler_cxx:
- # skip over environment variable settings if /usr/bin/env
- # is used to set up the linker's environment.
- # This is needed on OSX. Note: this assumes that the
- # normal and C++ compiler have the same environment
- # settings.
- i = 0
- if os.path.basename(linker[0]) == "env":
- i = 1
- while '=' in linker[i]:
- i += 1
-
- if os.path.basename(linker[i]) == 'ld_so_aix':
- # AIX platforms prefix the compiler with the ld_so_aix
- # script, so we need to adjust our linker index
- offset = 1
+ if target_desc == CCompiler.EXECUTABLE:
+ linker = self.linker_exe[:]
else:
- offset = 0
-
- linker[i+offset] = self.compiler_cxx[i]
+ linker = self.linker_so[:]
if sys.platform == 'darwin':
linker = _osx_support.compiler_fixup(linker, ld_args)
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -584,10 +584,10 @@ sharedmods: $(BUILDPYTHON) pybuilddir.txt Modules/_math.o
*\ -s*|s*) quiet="-q";; \
*) quiet="";; \
esac; \
- echo "$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' \
+ echo "$(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' CFLAGS='$(PY_CFLAGS)' \
_TCLTK_INCLUDES='$(TCLTK_INCLUDES)' _TCLTK_LIBS='$(TCLTK_LIBS)' \
$(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build"; \
- $(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' \
+ $(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' CFLAGS='$(PY_CFLAGS)' \
_TCLTK_INCLUDES='$(TCLTK_INCLUDES)' _TCLTK_LIBS='$(TCLTK_LIBS)' \
$(PYTHON_FOR_BUILD) $(srcdir)/setup.py $$quiet build

View File

@@ -0,0 +1,33 @@
From 1911995b1a1252d80bf2b9651840e185a1a6baf5 Mon Sep 17 00:00:00 2001
From: Hong Xu <hong@topbug.net>
Date: Thu, 25 Jul 2019 10:25:55 -0700
Subject: [PATCH] On all posix systems, not just Darwin, set LDSHARED (if not
set) according to CC
This patch is slightly different from https://bugs.python.org/issue24935
, except that we now handle LDSHARED according to CC on all posix
systems, not just Darwin or Linux.
---
Lib/distutils/sysconfig.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py
index 37feae5df7..9fdce6896d 100644
--- a/Lib/distutils/sysconfig.py
+++ b/Lib/distutils/sysconfig.py
@@ -199,10 +199,10 @@ def customize_compiler(compiler):
if 'CC' in os.environ:
newcc = os.environ['CC']
- if (sys.platform == 'darwin'
+ if (os.name == 'posix'
and 'LDSHARED' not in os.environ
and ldshared.startswith(cc)):
- # On OS X, if CC is overridden, use that as the default
+ # On POSIX systems, if CC is overridden, use that as the default
# command for LDSHARED as well
ldshared = newcc + ldshared[len(cc):]
cc = newcc
--
2.25.1

View File

@@ -0,0 +1,106 @@
From 66f492d2eda94bd64db833839a325caf6ba0fed5 Mon Sep 17 00:00:00 2001
From: Greg Roodt <greg@canva.com>
Date: Wed, 9 Dec 2020 17:59:24 +1100
Subject: [PATCH] Don't use ldconfig
---
Lib/ctypes/util.py | 77 ++--------------------------------------------
1 file changed, 2 insertions(+), 75 deletions(-)
diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py
index 0c2510e161..7fb98af308 100644
--- a/Lib/ctypes/util.py
+++ b/Lib/ctypes/util.py
@@ -100,53 +100,7 @@ elif os.name == "posix":
return thefile.read(4) == elf_header
def _findLib_gcc(name):
- # Run GCC's linker with the -t (aka --trace) option and examine the
- # library name it prints out. The GCC command will fail because we
- # haven't supplied a proper program with main(), but that does not
- # matter.
- expr = os.fsencode(r'[^\(\)\s]*lib%s\.[^\(\)\s]*' % re.escape(name))
-
- c_compiler = shutil.which('gcc')
- if not c_compiler:
- c_compiler = shutil.which('cc')
- if not c_compiler:
- # No C compiler available, give up
- return None
-
- temp = tempfile.NamedTemporaryFile()
- try:
- args = [c_compiler, '-Wl,-t', '-o', temp.name, '-l' + name]
-
- env = dict(os.environ)
- env['LC_ALL'] = 'C'
- env['LANG'] = 'C'
- try:
- proc = subprocess.Popen(args,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- env=env)
- except OSError: # E.g. bad executable
- return None
- with proc:
- trace = proc.stdout.read()
- finally:
- try:
- temp.close()
- except FileNotFoundError:
- # Raised if the file was already removed, which is the normal
- # behaviour of GCC if linking fails
- pass
- res = re.findall(expr, trace)
- if not res:
- return None
-
- for file in res:
- # Check if the given file is an elf file: gcc can report
- # some files that are linker scripts and not actual
- # shared objects. See bpo-41976 for more details
- if not _is_elf(file):
- continue
- return os.fsdecode(file)
+ return None
if sys.platform == "sunos5":
@@ -268,34 +222,7 @@ elif os.name == "posix":
else:
def _findSoname_ldconfig(name):
- import struct
- if struct.calcsize('l') == 4:
- machine = os.uname().machine + '-32'
- else:
- machine = os.uname().machine + '-64'
- mach_map = {
- 'x86_64-64': 'libc6,x86-64',
- 'ppc64-64': 'libc6,64bit',
- 'sparc64-64': 'libc6,64bit',
- 's390x-64': 'libc6,64bit',
- 'ia64-64': 'libc6,IA-64',
- }
- abi_type = mach_map.get(machine, 'libc6')
-
- # XXX assuming GLIBC's ldconfig (with option -p)
- regex = r'\s+(lib%s\.[^\s]+)\s+\(%s'
- regex = os.fsencode(regex % (re.escape(name), abi_type))
- try:
- with subprocess.Popen(['/sbin/ldconfig', '-p'],
- stdin=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL,
- stdout=subprocess.PIPE,
- env={'LC_ALL': 'C', 'LANG': 'C'}) as p:
- res = re.search(regex, p.stdout.read())
- if res:
- return os.fsdecode(res.group(1))
- except OSError:
- pass
+ return None
def _findLib_ld(name):
# See issue #9998 for why this is needed
--
2.24.3 (Apple Git-128)

View File

@@ -0,0 +1,15 @@
diff --git a/setup.py b/setup.py
index 04eb6b2..2e1160d 100644
--- a/setup.py
+++ b/setup.py
@@ -1981,8 +1981,8 @@ class PyBuildExt(build_ext):
# Rather than complicate the code below, detecting and building
# AquaTk is a separate method. Only one Tkinter will be built on
# Darwin - either AquaTk, if it is found, or X11 based Tk.
- if (MACOS and self.detect_tkinter_darwin()):
- return True
+ # if (MACOS and self.detect_tkinter_darwin()):
+ # return True
# Assume we haven't found any of the libraries or include files
# The versions with dots are used on Unix, and the versions without

View File

@@ -0,0 +1,51 @@
From 66f492d2eda94bd64db833839a325caf6ba0fed5 Mon Sep 17 00:00:00 2001
From: Greg Roodt <greg@canva.com>
Date: Wed, 9 Dec 2020 17:59:24 +1100
Subject: [PATCH] Don't use ldconfig
---
Lib/ctypes/util.py | 77 ++--------------------------------------------
1 file changed, 2 insertions(+), 75 deletions(-)
diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py
index 0c2510e161..7fb98af308 100644
--- a/Lib/ctypes/util.py
+++ b/Lib/ctypes/util.py
@@ -268,34 +222,7 @@ elif os.name == "posix":
else:
def _findSoname_ldconfig(name):
- import struct
- if struct.calcsize('l') == 4:
- machine = os.uname().machine + '-32'
- else:
- machine = os.uname().machine + '-64'
- mach_map = {
- 'x86_64-64': 'libc6,x86-64',
- 'ppc64-64': 'libc6,64bit',
- 'sparc64-64': 'libc6,64bit',
- 's390x-64': 'libc6,64bit',
- 'ia64-64': 'libc6,IA-64',
- }
- abi_type = mach_map.get(machine, 'libc6')
-
- # XXX assuming GLIBC's ldconfig (with option -p)
- regex = r'\s+(lib%s\.[^\s]+)\s+\(%s'
- regex = os.fsencode(regex % (re.escape(name), abi_type))
- try:
- with subprocess.Popen(['/sbin/ldconfig', '-p'],
- stdin=subprocess.DEVNULL,
- stderr=subprocess.DEVNULL,
- stdout=subprocess.PIPE,
- env={'LC_ALL': 'C', 'LANG': 'C'}) as p:
- res = re.search(regex, p.stdout.read())
- if res:
- return os.fsdecode(res.group(1))
- except OSError:
- pass
+ return None
def _findLib_ld(name):
# See issue #9998 for why this is needed
--
2.24.3 (Apple Git-128)

View File

@@ -0,0 +1,858 @@
{
lib,
stdenv,
fetchurl,
fetchpatch,
fetchgit,
# build dependencies
autoconf-archive,
autoreconfHook,
nukeReferences,
pkg-config,
python-setup-hook,
# high level switches
withMinimalDeps ? false,
# runtime dependencies
bzip2,
withExpat ? !withMinimalDeps,
expat,
libffi,
libuuid,
libxcrypt,
withMpdecimal ? !withMinimalDeps,
mpdecimal,
ncurses,
withOpenssl ? !withMinimalDeps,
openssl,
withSqlite ? !withMinimalDeps,
sqlite,
xz,
zlib,
zstd,
# platform-specific dependencies
bashNonInteractive,
windows,
# optional dependencies
bluezSupport ? !withMinimalDeps && stdenv.hostPlatform.isLinux,
bluez-headers,
mimetypesSupport ? !withMinimalDeps,
mailcap,
tzdata,
withGdbm ? !withMinimalDeps && !stdenv.hostPlatform.isWindows,
gdbm,
withReadline ? !withMinimalDeps && !stdenv.hostPlatform.isWindows,
readline,
# splicing/cross
pythonAttr ? "python${sourceVersion.major}${sourceVersion.minor}",
self,
pkgsBuildBuild,
pkgsBuildHost,
pkgsBuildTarget,
pkgsHostHost,
pkgsTargetTarget,
__splices ? { },
# build customization
sourceVersion,
hash,
passthruFun,
stripConfig ? withMinimalDeps,
stripIdlelib ? withMinimalDeps,
stripTests ? withMinimalDeps,
stripTkinter ? withMinimalDeps,
rebuildBytecode ? !withMinimalDeps,
stripBytecode ? true,
includeSiteCustomize ? !withMinimalDeps,
static ? stdenv.hostPlatform.isStatic,
enableFramework ? false,
noldconfigPatch ? ./. + "/${sourceVersion.major}.${sourceVersion.minor}/no-ldconfig.patch",
enableGIL ? true,
enableDebug ? false,
# pgo (not reproducible) + -fno-semantic-interposition
# https://docs.python.org/3/using/configure.html#cmdoption-enable-optimizations
enableOptimizations ? false,
# improves performance, but remains reproducible
enableNoSemanticInterposition ? true,
# enabling LTO on 32bit arch causes downstream packages to fail when linking
enableLTO ?
!withMinimalDeps
&& (stdenv.hostPlatform.isDarwin || (stdenv.hostPlatform.is64bit && stdenv.hostPlatform.isLinux)),
# enable asserts to ensure the build remains reproducible
reproducibleBuild ? false,
# for the Python package set
packageOverrides ? (self: super: { }),
# tests
testers,
# allow pythonMinimal to prevent accidental dependencies it doesn't want
# Having this as an option is useful to allow overriding, eg. adding things to
# python3Minimal
allowedReferenceNames ? if withMinimalDeps then [ "bashNonInteractive" ] else [ ],
}@inputs:
# Note: this package is used for bootstrapping fetchurl, and thus
# cannot use fetchpatch! All mutable patches (generated by GitHub or
# cgit) that are needed here should be included directly in Nixpkgs as
# files.
assert lib.assertMsg (
enableFramework -> stdenv.hostPlatform.isDarwin
) "Framework builds are only supported on Darwin.";
assert lib.assertMsg (
reproducibleBuild -> stripBytecode
) "Deterministic builds require stripping bytecode.";
assert lib.assertMsg (
reproducibleBuild -> (!enableOptimizations)
) "Deterministic builds are not achieved when optimizations are enabled.";
assert lib.assertMsg (
reproducibleBuild -> (!rebuildBytecode)
) "Deterministic builds are not achieved when (default unoptimized) bytecode is created.";
let
inherit (lib)
concatMapStringsSep
concatStringsSep
enableFeature
getDev
getLib
optionals
optionalString
replaceStrings
;
withLibxcrypt =
(!withMinimalDeps)
&&
# mixes libc and libxcrypt headers and libs and causes segfaults on importing crypt
(!stdenv.hostPlatform.isFreeBSD)
&&
# crypt module was removed in 3.13
passthru.pythonOlder "3.13";
buildPackages = pkgsBuildHost;
inherit (passthru) pythonOnBuildForHost;
tzdataSupport = !withMinimalDeps && tzdata != null && passthru.pythonAtLeast "3.9";
passthru =
let
# When we override the interpreter we also need to override the spliced versions of the interpreter
inputs' = lib.filterAttrs (n: v: n != "passthruFun" && !lib.isDerivation v) inputs;
# Memoization of the splices to avoid re-evaluating this function for all combinations of splices e.g.
# python3.pythonOnBuildForHost.pythonOnBuildForTarget == python3.pythonOnBuildForTarget by consuming
# __splices as an arg and using the cache if populated.
splices = {
pythonOnBuildForBuild = override pkgsBuildBuild.${pythonAttr};
pythonOnBuildForHost = override pkgsBuildHost.${pythonAttr};
pythonOnBuildForTarget = override pkgsBuildTarget.${pythonAttr};
pythonOnHostForHost = override pkgsHostHost.${pythonAttr};
pythonOnTargetForTarget = lib.optionalAttrs (lib.hasAttr pythonAttr pkgsTargetTarget) (
override pkgsTargetTarget.${pythonAttr}
);
}
// __splices;
override =
attr:
let
python = attr.override (
inputs'
// {
self = python;
__splices = splices;
}
);
in
python;
in
passthruFun rec {
inherit self sourceVersion packageOverrides;
implementation = "cpython";
libPrefix = "python${pythonVersion}${lib.optionalString (!enableGIL) "t"}";
executable = libPrefix;
pythonVersion = with sourceVersion; "${major}.${minor}";
sitePackages = "lib/${libPrefix}/site-packages";
inherit hasDistutilsCxxPatch pythonAttr;
inherit (splices)
pythonOnBuildForBuild
pythonOnBuildForHost
pythonOnBuildForTarget
pythonOnHostForHost
pythonOnTargetForTarget
;
pythonABITags = [
"abi3"
"none"
"cp${sourceVersion.major}${sourceVersion.minor}${lib.optionalString (!enableGIL) "t"}"
];
};
version = with sourceVersion; "${major}.${minor}.${patch}${suffix}";
nativeBuildInputs = [
nukeReferences
]
++ optionals (!stdenv.hostPlatform.isDarwin && !withMinimalDeps) [
autoconf-archive # needed for AX_CHECK_COMPILE_FLAG
autoreconfHook
]
++
optionals ((!stdenv.hostPlatform.isDarwin || passthru.pythonAtLeast "3.14") && !withMinimalDeps)
[
pkg-config
]
++ optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
buildPackages.stdenv.cc
pythonOnBuildForHost
]
++
optionals
(
stdenv.cc.isClang
&& (!stdenv.hostPlatform.useAndroidPrebuilt or false)
&& (enableLTO || enableOptimizations)
)
[
stdenv.cc.cc.libllvm.out
];
buildInputs = lib.filter (p: p != null) (
optionals (!withMinimalDeps) [
bzip2
libffi
libuuid
ncurses
xz
zlib
]
++ optionals withLibxcrypt [
libxcrypt
]
++ optionals withOpenssl [
openssl
]
++ optionals withSqlite [
sqlite
]
++ optionals withMpdecimal [
mpdecimal
]
++ optionals withExpat [
expat
]
++ optionals (passthru.pythonAtLeast "3.14") [
zstd
]
++ optionals bluezSupport [
bluez-headers
]
++ optionals stdenv.hostPlatform.isMinGW [
windows.dlfcn
windows.pthreads
]
++ optionals tzdataSupport [
tzdata
]
++ optionals withGdbm [
gdbm
]
++ optionals withReadline [
readline
]
);
hasDistutilsCxxPatch = !(stdenv.cc.isGNU or false);
pythonOnBuildForHostInterpreter =
if stdenv.hostPlatform == stdenv.buildPlatform then
"$out/bin/python"
else
pythonOnBuildForHost.interpreter;
src = fetchurl {
url =
with sourceVersion;
"https://www.python.org/ftp/python/${major}.${minor}.${patch}/Python-${version}.tar.xz";
inherit hash;
};
# win32 is added by Fedoras patch
machdep = if stdenv.hostPlatform.isWindows then "win32" else stdenv.hostPlatform.parsed.kernel.name;
# https://github.com/python/cpython/blob/e488e300f5c01289c10906c2e53a8e43d6de32d8/configure.ac#L428
# The configure script uses "arm" as the CPU name for all 32-bit ARM
# variants when cross-compiling, but native builds include the version
# suffix, so we do the same.
pythonHostPlatform =
let
cpu =
{
# According to PEP600, Python's name for the Power PC
# architecture is "ppc", not "powerpc". Without the Rosetta
# Stone below, the PEP600 requirement that "${ARCH} matches
# the return value from distutils.util.get_platform()" fails.
# https://peps.python.org/pep-0600/
powerpc = "ppc";
powerpcle = "ppcle";
powerpc64 = "ppc64";
powerpc64le = "ppc64le";
}
.${stdenv.hostPlatform.parsed.cpu.name} or stdenv.hostPlatform.parsed.cpu.name;
in
"${machdep}-${cpu}";
execSuffix = stdenv.hostPlatform.extensions.executable;
in
with passthru;
stdenv.mkDerivation (finalAttrs: {
pname = "python3";
inherit src version;
inherit nativeBuildInputs;
buildInputs =
lib.optionals (!stdenv.hostPlatform.isWindows) [
bashNonInteractive # only required for patchShebangs
]
++ buildInputs;
prePatch = optionalString stdenv.hostPlatform.isDarwin ''
substituteInPlace configure --replace-fail '`/usr/bin/arch`' '"i386"'
'';
patches = [
# Disable the use of ldconfig in ctypes.util.find_library (since
# ldconfig doesn't work on NixOS), and don't use
# ctypes.util.find_library during the loading of the uuid module
# (since it will do a futile invocation of gcc (!) to find
# libuuid, slowing down program startup a lot).
noldconfigPatch
]
++ optionals (stdenv.hostPlatform != stdenv.buildPlatform && stdenv.hostPlatform.isFreeBSD) [
# Cross compilation only supports a limited number of "known good"
# configurations. If you're reading this and it's been a long time
# since this diff, consider submitting this patch upstream!
./freebsd-cross.patch
]
++ optionals (pythonOlder "3.13") [
# Make sure that the virtualenv activation scripts are
# owner-writable, so venvs can be recreated without permission
# errors.
./virtualenv-permissions.patch
]
++ optionals (pythonAtLeast "3.13") [
./3.13/virtualenv-permissions.patch
]
++ optionals mimetypesSupport [
# Make the mimetypes module refer to the right file
./mimetypes.patch
]
++ optionals (pythonAtLeast "3.9" && pythonOlder "3.11" && stdenv.hostPlatform.isDarwin) [
# Stop checking for TCL/TK in global macOS locations
./3.9/darwin-tcl-tk.patch
]
++ optionals (hasDistutilsCxxPatch && pythonOlder "3.12") [
# Fix for http://bugs.python.org/issue1222585
# Upstream distutils is calling C compiler to compile C++ code, which
# only works for GCC and Apple Clang. This makes distutils to call C++
# compiler when needed.
(
if pythonAtLeast "3.7" && pythonOlder "3.11" then
./3.7/python-3.x-distutils-C++.patch
else if pythonAtLeast "3.11" then
./3.11/python-3.x-distutils-C++.patch
else
fetchpatch {
url = "https://bugs.python.org/file48016/python-3.x-distutils-C++.patch";
sha256 = "1h18lnpx539h5lfxyk379dxwr8m2raigcjixkf133l4xy3f4bzi2";
}
)
]
++ optionals (pythonAtLeast "3.7" && pythonOlder "3.12") [
# LDSHARED now uses $CC instead of gcc. Fixes cross-compilation of extension modules.
./3.8/0001-On-all-posix-systems-not-just-Darwin-set-LDSHARED-if.patch
# Use sysconfigdata to find headers. Fixes cross-compilation of extension modules.
./3.7/fix-finding-headers-when-cross-compiling.patch
]
++ optionals (pythonOlder "3.12") [
# https://github.com/python/cpython/issues/90656
./loongarch-support.patch
# fix failing tests with openssl >= 3.4
# https://github.com/python/cpython/pull/127361
]
++ optionals (pythonAtLeast "3.11" && pythonOlder "3.13") [
# backport fix for https://github.com/python/cpython/issues/95855
./platform-triplet-detection.patch
]
++ optionals (stdenv.hostPlatform.isMinGW) (
let
# https://src.fedoraproject.org/rpms/mingw-python3
mingw-patch = fetchgit {
name = "mingw-python-patches";
url = "https://src.fedoraproject.org/rpms/mingw-python3.git";
rev = "3edecdbfb4bbf1276d09cd5e80e9fb3dd88c9511"; # for python 3.11.9 at the time of writing.
hash = "sha256-kpXoIHlz53+0FAm/fK99ZBdNUg0u13erOr1XP2FSkQY=";
};
in
(map (f: "${mingw-patch}/${f}") [
# The other patches in that repo are already applied to 3.11.10
"mingw-python3_distutils.patch"
"mingw-python3_frozenmain.patch"
"mingw-python3_make-sysconfigdata.py-relocatable.patch"
"mingw-python3_mods-failed.patch"
"mingw-python3_module-select.patch"
"mingw-python3_module-socket.patch"
"mingw-python3_modules.patch"
"mingw-python3_platform-mingw.patch"
"mingw-python3_posix-layout.patch"
"mingw-python3_pthread_threadid.patch"
"mingw-python3_pythonw.patch"
"mingw-python3_setenv.patch"
"mingw-python3_win-modules.patch"
])
);
postPatch =
optionalString (!stdenv.hostPlatform.isWindows) ''
substituteInPlace Lib/subprocess.py \
--replace-fail "'/bin/sh'" "'${bashNonInteractive}/bin/sh'"
''
+ optionalString mimetypesSupport ''
substituteInPlace Lib/mimetypes.py \
--replace-fail "@mime-types@" "${mailcap}"
'';
env = {
CPPFLAGS = concatStringsSep " " (map (p: "-I${getDev p}/include") buildInputs);
LDFLAGS = concatStringsSep " " (map (p: "-L${getLib p}/lib") buildInputs);
LIBS = "${optionalString (!stdenv.hostPlatform.isDarwin && withLibxcrypt) "-lcrypt"}";
NIX_LDFLAGS = lib.optionalString (stdenv.cc.isGNU && !stdenv.hostPlatform.isStatic) (
{
"glibc" = "-lgcc_s";
"musl" = "-lgcc_eh";
}
."${stdenv.hostPlatform.libc}" or ""
);
# Determinism: We fix the hashes of str, bytes and datetime objects.
PYTHONHASHSEED = 0;
};
# https://docs.python.org/3/using/configure.html
configureFlags = [
"--without-ensurepip"
]
++ optionals withExpat [
"--with-system-expat"
]
++ optionals withMpdecimal [
"--with-system-libmpdec"
]
++ optionals withOpenssl [
"--with-openssl=${openssl.dev}"
]
++ optionals tzdataSupport [
"--with-tzpath=${tzdata}/share/zoneinfo"
]
++ optionals (execSuffix != "") [
"--with-suffix=${execSuffix}"
]
++ optionals enableLTO [
"--with-lto"
]
++ optionals (!static && !enableFramework) [
"--enable-shared"
]
++ optionals enableFramework [
"--enable-framework=${placeholder "out"}/Library/Frameworks"
]
++ optionals (pythonAtLeast "3.13") [
(enableFeature enableGIL "gil")
]
++ optionals enableOptimizations [
"--enable-optimizations"
]
++ optionals enableDebug [
"--with-pydebug"
]
++ optionals withSqlite [
"--enable-loadable-sqlite-extensions"
]
++ optionals withLibxcrypt [
"CFLAGS=-I${libxcrypt}/include"
"LIBS=-L${libxcrypt}/lib"
]
++ optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
"ac_cv_buggy_getaddrinfo=no"
# Assume little-endian IEEE 754 floating point when cross compiling
"ac_cv_little_endian_double=yes"
"ac_cv_big_endian_double=no"
"ac_cv_mixed_endian_double=no"
"ac_cv_x87_double_rounding=yes"
"ac_cv_tanh_preserves_zero_sign=yes"
# Generally assume that things are present and work
"ac_cv_posix_semaphores_enabled=yes"
"ac_cv_broken_sem_getvalue=no"
"ac_cv_wchar_t_signed=yes"
"ac_cv_rshift_extends_sign=yes"
"ac_cv_broken_nice=no"
"ac_cv_broken_poll=no"
"ac_cv_working_tzset=yes"
"ac_cv_have_long_long_format=yes"
"ac_cv_have_size_t_format=yes"
"ac_cv_computed_gotos=yes"
# Both fail when building for windows, normally configure checks this by itself but on other platforms this is set to yes always.
"ac_cv_file__dev_ptmx=${if stdenv.hostPlatform.isWindows then "no" else "yes"}"
"ac_cv_file__dev_ptc=${if stdenv.hostPlatform.isWindows then "no" else "yes"}"
]
++ optionals (stdenv.hostPlatform != stdenv.buildPlatform && pythonAtLeast "3.11") [
"--with-build-python=${pythonOnBuildForHostInterpreter}"
]
++ optionals stdenv.hostPlatform.isLinux [
# Never even try to use lchmod on linux,
# don't rely on detecting glibc-isms.
"ac_cv_func_lchmod=no"
]
++ optionals static [
"--disable-test-modules"
"LDFLAGS=-static"
"MODULE_BUILDTYPE=static"
]
++ optionals (stdenv.hostPlatform.isStatic && stdenv.hostPlatform.isMusl) [
# dlopen is a no-op in static musl builds, and since we build everything without -fPIC it's better not to pretend.
"ac_cv_func_dlopen=no"
];
preConfigure = ''
# Attempt to purify some of the host info collection
sed -E -i -e 's/uname -r/echo/g' -e 's/uname -n/echo nixpkgs/g' config.guess
sed -E -i -e 's/uname -r/echo/g' -e 's/uname -n/echo nixpkgs/g' configure
''
+ optionalString (pythonOlder "3.12") ''
# Improve purity
for path in /usr /sw /opt /pkg; do
substituteInPlace ./setup.py --replace-warn $path /no-such-path
done
''
+ optionalString (stdenv.hostPlatform.isDarwin && pythonOlder "3.12") ''
# Fix _ctypes module compilation
export NIX_CFLAGS_COMPILE+=" -DUSING_APPLE_OS_LIBFFI=1"
''
+ optionalString stdenv.hostPlatform.isDarwin ''
# Override the auto-detection in setup.py, which assumes a universal build
export PYTHON_DECIMAL_WITH_MACHINE=${if stdenv.hostPlatform.isAarch64 then "uint128" else "x64"}
# Ensure that modern platform features are enabled on Darwin in spite of having no version suffix.
sed -E -i -e 's|Darwin/\[12\]\[0-9\]\.\*|Darwin/*|' configure
''
+ optionalString (pythonAtLeast "3.11") ''
# Also override the auto-detection in `configure`.
substituteInPlace configure \
--replace-fail 'libmpdec_machine=universal' 'libmpdec_machine=${
if stdenv.hostPlatform.isAarch64 then "uint128" else "x64"
}'
''
+ optionalString stdenv.hostPlatform.isWindows ''
export NIX_CFLAGS_COMPILE+=" -Wno-error=incompatible-pointer-types"
''
+ optionalString stdenv.hostPlatform.isMusl ''
export NIX_CFLAGS_COMPILE+=" -DTHREAD_STACK_SIZE=0x100000"
''
+
# enableNoSemanticInterposition essentially sets that CFLAG -fno-semantic-interposition
# which changes how symbols are looked up. This essentially means we can't override
# libpython symbols via LD_PRELOAD anymore. This is common enough as every build
# that uses --enable-optimizations has the same "issue".
#
# The Fedora wiki has a good article about their journey towards enabling this flag:
# https://fedoraproject.org/wiki/Changes/PythonNoSemanticInterpositionSpeedup
optionalString enableNoSemanticInterposition ''
export CFLAGS_NODIST="-fno-semantic-interposition"
'';
# Our aarch64-linux bootstrap files lack Scrt1.o, which fails the config test
hardeningEnable = lib.optionals (!withMinimalDeps && !stdenv.hostPlatform.isAarch64) [ "pie" ];
setupHook = python-setup-hook sitePackages;
postInstall =
let
# References *not* to nuke from (sys)config files
keep-references = concatMapStringsSep " " (val: "-e ${val}") (
[
(placeholder "out")
]
++ lib.optional withLibxcrypt libxcrypt
++ lib.optional tzdataSupport tzdata
);
in
lib.optionalString enableFramework ''
for dir in include lib share; do
ln -s $out/Library/Frameworks/Python.framework/Versions/Current/$dir $out/$dir
done
''
+ ''
# needed for some packages, especially packages that backport functionality
# to 2.x from 3.x
for item in $out/lib/${libPrefix}/test/*; do
if [[ "$item" != */test_support.py*
&& "$item" != */test/support
&& "$item" != */test/libregrtest
&& "$item" != */test/regrtest.py* ]]; then
rm -rf "$item"
else
echo $item
fi
done
''
+ lib.optionalString (!static) ''
touch $out/lib/${libPrefix}/test/__init__.py
''
+ ''
# Determinism: Windows installers were not deterministic.
# We're also not interested in building Windows installers.
find "$out" -name 'wininst*.exe' | xargs -r rm -f
# Use Python3 as default python
ln -s "$out/bin/idle3" "$out/bin/idle"
ln -s "$out/bin/pydoc3" "$out/bin/pydoc"
ln -s "$out/bin/python3${execSuffix}" "$out/bin/python${execSuffix}"
ln -s "$out/bin/python3-config" "$out/bin/python-config"
ln -s "$out/lib/pkgconfig/python3.pc" "$out/lib/pkgconfig/python.pc"
ln -sL "$out/share/man/man1/python3.1.gz" "$out/share/man/man1/python.1.gz"
# Get rid of retained dependencies on -dev packages, and remove
# some $TMPDIR references to improve binary reproducibility.
# Note that the .pyc file of _sysconfigdata.py should be regenerated!
for i in $out/lib/${libPrefix}/_sysconfigdata*.py $out/lib/${libPrefix}/config-${sourceVersion.major}.${sourceVersion.minor}*/Makefile; do
sed -i $i -e "s|$TMPDIR|/no-such-path|g"
done
# Further get rid of references. https://github.com/NixOS/nixpkgs/issues/51668
find $out/lib/python*/config-* -type f -print -exec nuke-refs ${keep-references} '{}' +
find $out/lib -name '_sysconfigdata*.py*' -print -exec nuke-refs ${keep-references} '{}' +
# Make the sysconfigdata module accessible on PYTHONPATH
# This allows build Python to import host Python's sysconfigdata
mkdir -p "$out/${sitePackages}"
ln -s "$out/lib/${libPrefix}/"_sysconfigdata*.py "$out/${sitePackages}/"
''
+ optionalString (pythonAtLeast "3.14") ''
# Get rid of retained dependencies on -dev packages, and remove from _sysconfig_vars*.json introduced with Python3.14
for i in $out/lib/${libPrefix}/_sysconfig_vars*.json; do
sed -i $i -e "s|$TMPDIR|/no-such-path|g"
done
find $out/lib -name '_sysconfig_vars*.json*' -print -exec nuke-refs ${keep-references} '{}' +
ln -s "$out/lib/${libPrefix}/"_sysconfig_vars*.json "$out/${sitePackages}/"
''
+ optionalString stripConfig ''
rm -R $out/bin/python*-config $out/lib/python*/config-*
''
+ optionalString stripIdlelib ''
# Strip IDLE (and turtledemo, which uses it)
rm -R $out/bin/idle* $out/lib/python*/{idlelib,turtledemo}
''
+ optionalString stripTkinter ''
rm -R $out/lib/python*/tkinter
''
+ optionalString stripTests ''
# Strip tests
rm -R $out/lib/python*/test $out/lib/python*/**/test{,s}
''
+ optionalString includeSiteCustomize ''
# Include a sitecustomize.py file
cp ${../sitecustomize.py} $out/${sitePackages}/sitecustomize.py
''
+ optionalString stripBytecode ''
# Determinism: deterministic bytecode
# First we delete all old bytecode.
find $out -type d -name __pycache__ -print0 | xargs -0 -I {} rm -rf "{}"
''
+ optionalString rebuildBytecode ''
# Python 3.7 implements PEP 552, introducing support for deterministic bytecode.
# compileall uses the therein introduced checked-hash method by default when
# `SOURCE_DATE_EPOCH` is set.
# We exclude lib2to3 because that's Python 2 code which fails
# We build 3 levels of optimized bytecode. Note the default level, without optimizations,
# is not reproducible yet. https://bugs.python.org/issue29708
# Not creating bytecode will result in a large performance loss however, so we do build it.
find $out -name "*.py" | ${pythonOnBuildForHostInterpreter} -m compileall -q -f -x "lib2to3" -i -
find $out -name "*.py" | ${pythonOnBuildForHostInterpreter} -O -m compileall -q -f -x "lib2to3" -i -
find $out -name "*.py" | ${pythonOnBuildForHostInterpreter} -OO -m compileall -q -f -x "lib2to3" -i -
''
+ ''
# *strip* shebang from libpython gdb script - it should be dual-syntax and
# interpretable by whatever python the gdb in question is using, which may
# not even match the major version of this python. doing this after the
# bytecode compilations for the same reason - we don't want bytecode generated.
mkdir -p $out/share/gdb
sed '/^#!/d' Tools/gdb/libpython.py > $out/share/gdb/libpython.py
# Disable system-wide pip installation. See https://peps.python.org/pep-0668/.
cat <<'EXTERNALLY_MANAGED' > $out/lib/${libPrefix}/EXTERNALLY-MANAGED
[externally-managed]
Error=This command has been disabled as it tries to modify the immutable
`/nix/store` filesystem.
To use Python with Nix and nixpkgs, have a look at the online documentation:
<https://nixos.org/manual/nixpkgs/stable/#python>.
EXTERNALLY_MANAGED
''
+ optionalString stdenv.hostPlatform.isWindows ''
# Shebang files that link against the build python. Shebang dont work on windows
rm $out/bin/2to3*
rm $out/bin/idle*
rm $out/bin/pydoc*
echo linking DLLs for pythons compiled librairies
linkDLLsInfolder $out/lib/python*/lib-dynload/
'';
preFixup = lib.optionalString (stdenv.hostPlatform != stdenv.buildPlatform) ''
# Ensure patch-shebangs uses shebangs of host interpreter.
export PATH=${lib.makeBinPath [ "$out" ]}:$PATH
'';
# Add CPython specific setup-hook that configures distutils.sysconfig to
# always load sysconfigdata from host Python.
postFixup = lib.optionalString (!stdenv.hostPlatform.isDarwin) ''
# https://github.com/python/cpython/blob/e488e300f5c01289c10906c2e53a8e43d6de32d8/configure.ac#L78
sysconfigdataName="$(make --eval $'print-sysconfigdata-name:
\t@echo _sysconfigdata_$(ABIFLAGS)_$(MACHDEP)_$(MULTIARCH) ' print-sysconfigdata-name)"
# The CPython interpreter contains a _sysconfigdata_<platform specific suffix>
# module that is imported by the sysconfig and distutils.sysconfig modules.
# The sysconfigdata module is generated at build time and contains settings
# required for building Python extension modules, such as include paths and
# other compiler flags. By default, the sysconfigdata module is loaded from
# the currently running interpreter (ie. the build platform interpreter), but
# when cross-compiling we want to load it from the host platform interpreter.
# This can be done using the _PYTHON_SYSCONFIGDATA_NAME environment variable.
# The _PYTHON_HOST_PLATFORM variable also needs to be set to get the correct
# platform suffix on extension modules. The correct values for these variables
# are not documented, and must be derived from the configure script (see links
# below).
cat <<EOF >> "$out/nix-support/setup-hook"
sysconfigdataHook() {
if [ "\$1" = '$out' ]; then
export _PYTHON_HOST_PLATFORM='${pythonHostPlatform}'
export _PYTHON_SYSCONFIGDATA_NAME='$sysconfigdataName'
fi
}
addEnvHooks "\$hostOffset" sysconfigdataHook
EOF
'';
# Enforce that we don't have references to the OpenSSL -dev package, which we
# explicitly specify in our configure flags above.
disallowedReferences =
lib.optionals (withOpenssl && !static && !enableFramework) [
openssl.dev
]
++ lib.optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
# Ensure we don't have references to build-time packages.
# These typically end up in shebangs.
pythonOnBuildForHost
buildPackages.bashNonInteractive
];
# Optionally set allowedReferences to guarantee minimal dependencies
# Allows python3Minimal to stay minimal and not have deps added by accident
# Doesn't do anything if allowedReferenceNames is empty (was not set)
${if allowedReferenceNames != [ ] then "allowedReferences" else null} =
# map allowed names to their derivations
(map (name: inputs.${name}) allowedReferenceNames) ++ [
# any version of python depends on libc and libgcc
stdenv.cc.cc.lib
stdenv.cc.libc
# allows python referring to its own store path
"out"
];
separateDebugInfo = true;
__structuredAttrs = true;
passthru = passthru // {
doc = stdenv.mkDerivation {
inherit src;
name = "python${pythonVersion}-${version}-doc";
postPatch = lib.optionalString (pythonAtLeast "3.9" && pythonOlder "3.11") ''
substituteInPlace Doc/tools/extensions/pyspecific.py \
--replace-fail "from sphinx.util import status_iterator" "from sphinx.util.display import status_iterator"
'';
dontConfigure = true;
dontBuild = true;
sphinxRoot = "Doc";
postInstallSphinx = ''
mv $out/share/doc/* $out/share/doc/python${pythonVersion}-${version}
'';
nativeBuildInputs = with pkgsBuildBuild.python3.pkgs; [
sphinxHook
python-docs-theme
];
};
tests = passthru.tests // {
pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
};
};
enableParallelBuilding = true;
meta = with lib; {
homepage = "https://www.python.org";
changelog =
let
majorMinor = versions.majorMinor version;
dashedVersion = replaceStrings [ "." "a" "b" ] [ "-" "-alpha-" "-beta-" ] version;
in
if sourceVersion.suffix == "" then
"https://docs.python.org/release/${version}/whatsnew/changelog.html"
else
"https://docs.python.org/${majorMinor}/whatsnew/changelog.html#python-${dashedVersion}";
description = "High-level dynamically-typed programming language";
longDescription = ''
Python is a remarkably powerful dynamic programming language that
is used in a wide variety of application domains. Some of its key
distinguishing features include: clear, readable syntax; strong
introspection capabilities; intuitive object orientation; natural
expression of procedural code; full modularity, supporting
hierarchical packages; exception-based error handling; and very
high level dynamic data types.
'';
license = licenses.psfl;
pkgConfigModules = [ "python3" ];
platforms = platforms.linux ++ platforms.darwin ++ platforms.windows ++ platforms.freebsd;
mainProgram = executable;
teams = [ lib.teams.python ];
# static build on x86_64-darwin/aarch64-darwin breaks with:
# configure: error: C compiler cannot create executables
# mingw patches only apply to Python 3.11 currently
broken =
(lib.versions.minor version != "11" && stdenv.hostPlatform.isWindows)
|| (stdenv.hostPlatform.isStatic && stdenv.hostPlatform.isDarwin);
};
})

View File

@@ -0,0 +1,24 @@
# This file was generated and will be overwritten by ./generate.sh
{
stdenv,
lib,
fetchurl,
}:
stdenv.mkDerivation {
pname = "python27-docs-html";
version = "2.7.18";
src = fetchurl {
url = "http://www.python.org/ftp/python/doc/2.7.18/python-2.7.18-docs-html.tar.bz2";
sha256 = "03igxwpqc2lvzspnj78zz1prnmfwwj00jbvh1wsxvb0wayd5wi10";
};
installPhase = ''
mkdir -p $out/share/doc/python27
cp -R ./ $out/share/doc/python27/html
'';
meta = {
maintainers = [ ];
};
}

View File

@@ -0,0 +1,24 @@
# This file was generated and will be overwritten by ./generate.sh
{
stdenv,
lib,
fetchurl,
}:
stdenv.mkDerivation {
pname = "python27-docs-pdf-a4";
version = "2.7.18";
src = fetchurl {
url = "http://www.python.org/ftp/python/doc/2.7.18/python-2.7.18-docs-pdf-a4.tar.bz2";
sha256 = "0rxb2fpxwivjpk5wi2pl1fqibr4khf9s0yq6a49k9b4awi9nkb6v";
};
installPhase = ''
mkdir -p $out/share/doc/python27
cp -R ./ $out/share/doc/python27/pdf-a4
'';
meta = {
maintainers = [ ];
};
}

View File

@@ -0,0 +1,24 @@
# This file was generated and will be overwritten by ./generate.sh
{
stdenv,
lib,
fetchurl,
}:
stdenv.mkDerivation {
pname = "python27-docs-pdf-letter";
version = "2.7.18";
src = fetchurl {
url = "http://www.python.org/ftp/python/doc/2.7.18/python-2.7.18-docs-pdf-letter.tar.bz2";
sha256 = "07hbqvrdlq01cb95r1574bxqqhiqbkj4f92wzlq4d6dq1l272nan";
};
installPhase = ''
mkdir -p $out/share/doc/python27
cp -R ./ $out/share/doc/python27/pdf-letter
'';
meta = {
maintainers = [ ];
};
}

View File

@@ -0,0 +1,24 @@
# This file was generated and will be overwritten by ./generate.sh
{
stdenv,
lib,
fetchurl,
}:
stdenv.mkDerivation {
pname = "python27-docs-text";
version = "2.7.18";
src = fetchurl {
url = "http://www.python.org/ftp/python/doc/2.7.18/python-2.7.18-docs-text.tar.bz2";
sha256 = "1wj7mxs52kp5lmn5mvv574sygkfnk00kbz9ya9c03yfq5dd5nvy8";
};
installPhase = ''
mkdir -p $out/share/doc/python27
cp -R ./ $out/share/doc/python27/text
'';
meta = {
maintainers = [ ];
};
}

View File

@@ -0,0 +1,24 @@
# This file was generated and will be overwritten by ./generate.sh
{
stdenv,
lib,
fetchurl,
}:
stdenv.mkDerivation {
pname = "python310-docs-html";
version = "3.10.7";
src = fetchurl {
url = "http://www.python.org/ftp/python/doc/3.10.7/python-3.10.7-docs-html.tar.bz2";
sha256 = "0j86z1vmaghzj5i4frvzyfb9qwsmm09g4f4ssx5w27cm30b8k0v1";
};
installPhase = ''
mkdir -p $out/share/doc/python310
cp -R ./ $out/share/doc/python310/html
'';
meta = {
maintainers = [ ];
};
}

View File

@@ -0,0 +1,24 @@
# This file was generated and will be overwritten by ./generate.sh
{
stdenv,
lib,
fetchurl,
}:
stdenv.mkDerivation {
pname = "python310-docs-pdf-a4";
version = "3.10.7";
src = fetchurl {
url = "http://www.python.org/ftp/python/doc/3.10.7/python-3.10.7-docs-pdf-a4.tar.bz2";
sha256 = "1gvi457dsj3ywwvxysp7idkk9ndngnby1dnfh1q8f5gv3kg4093r";
};
installPhase = ''
mkdir -p $out/share/doc/python310
cp -R ./ $out/share/doc/python310/pdf-a4
'';
meta = {
maintainers = [ ];
};
}

View File

@@ -0,0 +1,24 @@
# This file was generated and will be overwritten by ./generate.sh
{
stdenv,
lib,
fetchurl,
}:
stdenv.mkDerivation {
pname = "python310-docs-pdf-letter";
version = "3.10.7";
src = fetchurl {
url = "http://www.python.org/ftp/python/doc/3.10.7/python-3.10.7-docs-pdf-letter.tar.bz2";
sha256 = "0hzq5n6absqsh21jp6j5iaim9a1wq69d8lc2assldzb2zg4i75hr";
};
installPhase = ''
mkdir -p $out/share/doc/python310
cp -R ./ $out/share/doc/python310/pdf-letter
'';
meta = {
maintainers = [ ];
};
}

View File

@@ -0,0 +1,24 @@
# This file was generated and will be overwritten by ./generate.sh
{
stdenv,
lib,
fetchurl,
}:
stdenv.mkDerivation {
pname = "python310-docs-texinfo";
version = "3.10.7";
src = fetchurl {
url = "http://www.python.org/ftp/python/doc/3.10.7/python-3.10.7-docs-texinfo.tar.bz2";
sha256 = "0p0fifi84ijz4ng6krw7c1x965jhgysprkijblmlnax7x9rmqrdf";
};
installPhase = ''
mkdir -p $out/share/info
cp ./python.info $out/share/info
'';
meta = {
maintainers = [ ];
};
}

View File

@@ -0,0 +1,24 @@
# This file was generated and will be overwritten by ./generate.sh
{
stdenv,
lib,
fetchurl,
}:
stdenv.mkDerivation {
pname = "python310-docs-text";
version = "3.10.7";
src = fetchurl {
url = "http://www.python.org/ftp/python/doc/3.10.7/python-3.10.7-docs-text.tar.bz2";
sha256 = "1zbmm2fvdjnl214y41yffyqw3ywfai5r5npc00n1wkfxsdp7gcc3";
};
installPhase = ''
mkdir -p $out/share/doc/python310
cp -R ./ $out/share/doc/python310/text
'';
meta = {
maintainers = [ ];
};
}

View File

@@ -0,0 +1,53 @@
{
stdenv,
fetchurl,
lib,
}:
let
pythonDocs = {
html = {
recurseForDerivations = true;
python27 = import ./2.7-html.nix {
inherit stdenv fetchurl lib;
};
python310 = import ./3.10-html.nix {
inherit stdenv fetchurl lib;
};
};
pdf_a4 = {
recurseForDerivations = true;
python27 = import ./2.7-pdf-a4.nix {
inherit stdenv fetchurl lib;
};
python310 = import ./3.10-pdf-a4.nix {
inherit stdenv fetchurl lib;
};
};
pdf_letter = {
recurseForDerivations = true;
python27 = import ./2.7-pdf-letter.nix {
inherit stdenv fetchurl lib;
};
python310 = import ./3.10-pdf-letter.nix {
inherit stdenv fetchurl lib;
};
};
text = {
recurseForDerivations = true;
python27 = import ./2.7-text.nix {
inherit stdenv fetchurl lib;
};
python310 = import ./3.10-text.nix {
inherit stdenv fetchurl lib;
};
};
texinfo = {
recurseForDerivations = true;
python310 = import ./3.10-texinfo.nix {
inherit stdenv fetchurl lib;
};
};
};
in
pythonDocs

View File

@@ -0,0 +1,71 @@
#!/usr/bin/env bash
cd -- "$(dirname -- "${BASH_SOURCE[0]}")"
TYPES="html pdf-a4 pdf-letter text texinfo"
URL=http://www.python.org/ftp/python/doc/VERSION/python-VERSION-docs-TYPE.tar.bz2
VERSIONS=$(for major in 2 3; do curl https://docs.python.org/$major/archives/ 2>/dev/null | perl -l -n -e'/<a href="python-([23].[0-9]+.[0-9]+)-docs-html.tar.bz2/ && print $1' | tail -n 1; done)
echo "Generating expressions for:
${VERSIONS}
"
cat >default.nix <<EOF
{ stdenv, fetchurl, lib }:
let
pythonDocs = {
EOF
for type in $TYPES; do
cat >>default.nix <<EOF
${type/-/_} = {
recurseForDerivations = true;
EOF
for version in $VERSIONS; do
major=$(echo -n ${version}| cut -d. -f1)
minor=$(echo -n ${version}| cut -d. -f2)
if [ "${type}" = "texinfo" ]; then
if [ "${major}" = "2" ]; then
# Python 2 doesn't have pregenerated texinfos available
continue
fi
template=template-info.nix
else
template=template.nix
fi
outfile=${major}.${minor}-${type}.nix
hash=
if [ -e ${outfile} ]; then
currentversion=$(grep "url =" ${outfile} |cut -d/ -f7)
if [ ${version} = ${currentversion} ]; then
hash=$(grep sha256 ${outfile} | cut -d'"' -f2)
fi
fi
echo "Generating ${outfile}"
url=$(echo -n $URL |sed -e "s,VERSION,${version},g" -e "s,TYPE,${type},")
sha=$(nix-prefetch-url ${url} ${hash})
sed -e "s,VERSION,${version}," \
-e "s,MAJOR,${major}," \
-e "s,MINOR,${minor}," \
-e "s,TYPE,${type}," \
-e "s,URL,${url}," \
-e "s,SHA,${sha}," < ${template} > ${outfile}
attrname=python${major}${minor}
cat >>default.nix <<EOF
${attrname} = import ./${major}.${minor}-${type}.nix {
inherit stdenv fetchurl lib;
};
EOF
echo "done."
echo
done
echo " };" >> default.nix
done
echo "}; in pythonDocs" >> default.nix

View File

@@ -0,0 +1,20 @@
# This file was generated and will be overwritten by ./generate.sh
{ stdenv, fetchurl }:
stdenv.mkDerivation {
pname = "pythonMAJORMINOR-docs-TYPE";
version = "VERSION";
src = fetchurl {
url = "URL";
sha256 = "SHA";
};
installPhase = ''
mkdir -p $out/share/info
cp ./python.info $out/share/info
'';
meta = {
maintainers = [ ];
};
}

View File

@@ -0,0 +1,20 @@
# This file was generated and will be overwritten by ./generate.sh
{ stdenv, fetchurl }:
stdenv.mkDerivation {
pname = "pythonMAJORMINOR-docs-TYPE";
version = "VERSION";
src = fetchurl {
url = "URL";
sha256 = "SHA";
};
installPhase = ''
mkdir -p $out/share/doc/pythonMAJORMINOR
cp -R ./ $out/share/doc/pythonMAJORMINOR/TYPE
'';
meta = {
maintainers = [ ];
};
}

View File

@@ -0,0 +1,22 @@
--- a/configure.ac 2024-06-07 09:17:50.608162031 -0700
+++ b/configure.ac 2024-06-07 09:45:59.844518241 -0700
@@ -554,6 +554,9 @@
*-*-wasi)
ac_sys_system=WASI
;;
+ *-*-freebsd)
+ ac_sys_system=FreeBSD
+ ;;
*)
# for now, limit cross builds to known configurations
MACHDEP="unknown"
@@ -614,6 +617,9 @@
wasm32-*-* | wasm64-*-*)
_host_cpu=$host_cpu
;;
+ x86_64-*-freebsd)
+ _host_cpu=x86_64
+ ;;
*)
# for now, limit cross builds to known configurations
MACHDEP="unknown"

View File

@@ -0,0 +1,50 @@
diff --git a/configure b/configure
index 8133d47f61..334c98e208 100755
--- a/configure
+++ b/configure
@@ -6215,6 +6215,20 @@ cat > conftest.c <<EOF
# else
# error unknown platform triplet
# endif
+# elif defined(__loongarch__)
+# if defined(__loongarch_lp64)
+# if defined(__loongarch_soft_float)
+ loongarch64-linux-gnusf
+# elif defined(__loongarch_single_float)
+ loongarch64-linux-gnuf32
+# elif defined(__loongarch_double_float)
+ loongarch64-linux-gnu
+# else
+# error unknown platform triplet
+# endif
+# else
+# error unknown platform triplet
+# endif
# else
# error unknown platform triplet
# endif
diff --git a/configure.ac b/configure.ac
index 3f20d8980d..acde94a181 100644
--- a/configure.ac
+++ b/configure.ac
@@ -959,6 +959,20 @@ cat > conftest.c <<EOF
hppa-linux-gnu
# elif defined(__ia64__)
ia64-linux-gnu
+# elif defined(__loongarch__)
+# if defined(__loongarch_lp64)
+# if defined(__loongarch_soft_float)
+ loongarch64-linux-gnusf
+# elif defined(__loongarch_single_float)
+ loongarch64-linux-gnuf32
+# elif defined(__loongarch_double_float)
+ loongarch64-linux-gnu
+# else
+# error unknown platform triplet
+# endif
+# else
+# error unknown platform triplet
+# endif
# elif defined(__m68k__) && !defined(__mcoldfire__)
m68k-linux-gnu
# elif defined(__mips_hard_float) && defined(__mips_isa_rev) && (__mips_isa_rev >=6) && defined(_MIPSEL)

View File

@@ -0,0 +1,23 @@
diff --git i/Lib/mimetypes.py w/Lib/mimetypes.py
index f3343c8..ab5b886 100644
--- i/Lib/mimetypes.py
+++ w/Lib/mimetypes.py
@@ -40,16 +40,8 @@
]
knownfiles = [
- "/etc/mime.types",
- "/etc/httpd/mime.types", # Mac OS X
- "/etc/httpd/conf/mime.types", # Apache
- "/etc/apache/mime.types", # Apache 1
- "/etc/apache2/mime.types", # Apache 2
- "/usr/local/etc/httpd/conf/mime.types",
- "/usr/local/lib/netscape/mime.types",
- "/usr/local/etc/httpd/conf/mime.types", # Apache 1.2
- "/usr/local/etc/mime.types", # Apache 1.3
- ]
+ "@mime-types@/etc/mime.types",
+]
inited = False
_db = None

View File

@@ -0,0 +1,295 @@
diff --git a/configure.ac b/configure.ac
index ba768aea93..621ac166bd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -936,125 +936,192 @@ cat > conftest.c <<EOF
#if defined(__ANDROID__)
# Android is not a multiarch system.
#elif defined(__linux__)
+# include <features.h>
+# if defined(__UCLIBC__)
+# error uclibc not supported
+# elif defined(__dietlibc__)
+# error dietlibc not supported
+# elif defined(__GLIBC__)
+# define LIBC gnu
+# define LIBC_X32 gnux32
+# if defined(__ARM_PCS_VFP)
+# define LIBC_ARM gnueabihf
+# else
+# define LIBC_ARM gnueabi
+# endif
+# if defined(__loongarch__)
+# if defined(__loongarch_soft_float)
+# define LIBC_LA gnusf
+# elif defined(__loongarch_single_float)
+# define LIBC_LA gnuf32
+# elif defined(__loongarch_double_float)
+# define LIBC_LA gnu
+# else
+# error unknown loongarch floating-point base abi
+# endif
+# endif
+# if defined(_MIPS_SIM)
+# if defined(__mips_hard_float)
+# if _MIPS_SIM == _ABIO32
+# define LIBC_MIPS gnu
+# elif _MIPS_SIM == _ABIN32
+# define LIBC_MIPS gnuabin32
+# elif _MIPS_SIM == _ABI64
+# define LIBC_MIPS gnuabi64
+# else
+# error unknown mips sim value
+# endif
+# else
+# if _MIPS_SIM == _ABIO32
+# define LIBC_MIPS gnusf
+# elif _MIPS_SIM == _ABIN32
+# define LIBC_MIPS gnuabin32sf
+# elif _MIPS_SIM == _ABI64
+# define LIBC_MIPS gnuabi64sf
+# else
+# error unknown mips sim value
+# endif
+# endif
+# endif
+# if defined(__SPE__)
+# define LIBC_PPC gnuspe
+# else
+# define LIBC_PPC gnu
+# endif
+# else
+# include <stdarg.h>
+# ifdef __DEFINED_va_list
+# define LIBC musl
+# define LIBC_X32 muslx32
+# if defined(__ARM_PCS_VFP)
+# define LIBC_ARM musleabihf
+# else
+# define LIBC_ARM musleabi
+# endif
+# if defined(__loongarch__)
+# if defined(__loongarch_soft_float)
+# define LIBC_LA muslsf
+# elif defined(__loongarch_single_float)
+# define LIBC_LA muslf32
+# elif defined(__loongarch_double_float)
+# define LIBC_LA musl
+# else
+# error unknown loongarch floating-point base abi
+# endif
+# endif
+# if defined(_MIPS_SIM)
+# if defined(__mips_hard_float)
+# if _MIPS_SIM == _ABIO32
+# define LIBC_MIPS musl
+# elif _MIPS_SIM == _ABIN32
+# define LIBC_MIPS musln32
+# elif _MIPS_SIM == _ABI64
+# define LIBC_MIPS musl
+# else
+# error unknown mips sim value
+# endif
+# else
+# if _MIPS_SIM == _ABIO32
+# define LIBC_MIPS muslsf
+# elif _MIPS_SIM == _ABIN32
+# define LIBC_MIPS musln32sf
+# elif _MIPS_SIM == _ABI64
+# define LIBC_MIPS muslsf
+# else
+# error unknown mips sim value
+# endif
+# endif
+# endif
+# if defined(_SOFT_FLOAT) || defined(__NO_FPRS__)
+# define LIBC_PPC muslsf
+# else
+# define LIBC_PPC musl
+# endif
+# else
+# error unknown libc
+# endif
+# endif
# if defined(__x86_64__) && defined(__LP64__)
- x86_64-linux-gnu
+ x86_64-linux-LIBC
# elif defined(__x86_64__) && defined(__ILP32__)
- x86_64-linux-gnux32
+ x86_64-linux-LIBC_X32
# elif defined(__i386__)
- i386-linux-gnu
+ i386-linux-LIBC
# elif defined(__aarch64__) && defined(__AARCH64EL__)
# if defined(__ILP32__)
- aarch64_ilp32-linux-gnu
+ aarch64_ilp32-linux-LIBC
# else
- aarch64-linux-gnu
+ aarch64-linux-LIBC
# endif
# elif defined(__aarch64__) && defined(__AARCH64EB__)
# if defined(__ILP32__)
- aarch64_be_ilp32-linux-gnu
+ aarch64_be_ilp32-linux-LIBC
# else
- aarch64_be-linux-gnu
+ aarch64_be-linux-LIBC
# endif
# elif defined(__alpha__)
- alpha-linux-gnu
-# elif defined(__ARM_EABI__) && defined(__ARM_PCS_VFP)
+ alpha-linux-LIBC
+# elif defined(__ARM_EABI__)
# if defined(__ARMEL__)
- arm-linux-gnueabihf
+ arm-linux-LIBC_ARM
# else
- armeb-linux-gnueabihf
-# endif
-# elif defined(__ARM_EABI__) && !defined(__ARM_PCS_VFP)
-# if defined(__ARMEL__)
- arm-linux-gnueabi
-# else
- armeb-linux-gnueabi
+ armeb-linux-LIBC_ARM
# endif
# elif defined(__hppa__)
- hppa-linux-gnu
+ hppa-linux-LIBC
# elif defined(__ia64__)
- ia64-linux-gnu
-# elif defined(__loongarch__)
-# if defined(__loongarch_lp64)
-# if defined(__loongarch_soft_float)
- loongarch64-linux-gnusf
-# elif defined(__loongarch_single_float)
- loongarch64-linux-gnuf32
-# elif defined(__loongarch_double_float)
- loongarch64-linux-gnu
+ ia64-linux-LIBC
+# elif defined(__loongarch__) && defined(__loongarch_lp64)
+ loongarch64-linux-LIBC_LA
+# elif defined(__m68k__) && !defined(__mcoldfire__)
+ m68k-linux-LIBC
+# elif defined(__mips__)
+# if defined(__mips_isa_rev) && (__mips_isa_rev >=6)
+# if defined(_MIPSEL) && defined(__mips64)
+ mipsisa64r6el-linux-LIBC_MIPS
+# elif defined(_MIPSEL)
+ mipsisa32r6el-linux-LIBC_MIPS
+# elif defined(__mips64)
+ mipsisa64r6-linux-LIBC_MIPS
# else
-# error unknown platform triplet
+ mipsisa32r6-linux-LIBC_MIPS
# endif
# else
-# error unknown platform triplet
-# endif
-# elif defined(__m68k__) && !defined(__mcoldfire__)
- m68k-linux-gnu
-# elif defined(__mips_hard_float) && defined(__mips_isa_rev) && (__mips_isa_rev >=6) && defined(_MIPSEL)
-# if _MIPS_SIM == _ABIO32
- mipsisa32r6el-linux-gnu
-# elif _MIPS_SIM == _ABIN32
- mipsisa64r6el-linux-gnuabin32
-# elif _MIPS_SIM == _ABI64
- mipsisa64r6el-linux-gnuabi64
-# else
-# error unknown platform triplet
-# endif
-# elif defined(__mips_hard_float) && defined(__mips_isa_rev) && (__mips_isa_rev >=6)
-# if _MIPS_SIM == _ABIO32
- mipsisa32r6-linux-gnu
-# elif _MIPS_SIM == _ABIN32
- mipsisa64r6-linux-gnuabin32
-# elif _MIPS_SIM == _ABI64
- mipsisa64r6-linux-gnuabi64
-# else
-# error unknown platform triplet
-# endif
-# elif defined(__mips_hard_float) && defined(_MIPSEL)
-# if _MIPS_SIM == _ABIO32
- mipsel-linux-gnu
-# elif _MIPS_SIM == _ABIN32
- mips64el-linux-gnuabin32
-# elif _MIPS_SIM == _ABI64
- mips64el-linux-gnuabi64
-# else
-# error unknown platform triplet
-# endif
-# elif defined(__mips_hard_float)
-# if _MIPS_SIM == _ABIO32
- mips-linux-gnu
-# elif _MIPS_SIM == _ABIN32
- mips64-linux-gnuabin32
-# elif _MIPS_SIM == _ABI64
- mips64-linux-gnuabi64
-# else
-# error unknown platform triplet
+# if defined(_MIPSEL) && defined(__mips64)
+ mips64el-linux-LIBC_MIPS
+# elif defined(_MIPSEL)
+ mipsel-linux-LIBC_MIPS
+# elif defined(__mips64)
+ mips64-linux-LIBC_MIPS
+# else
+ mips-linux-LIBC_MIPS
+# endif
# endif
# elif defined(__or1k__)
- or1k-linux-gnu
-# elif defined(__powerpc__) && defined(__SPE__)
- powerpc-linux-gnuspe
+ or1k-linux-LIBC
# elif defined(__powerpc64__)
# if defined(__LITTLE_ENDIAN__)
- powerpc64le-linux-gnu
+ powerpc64le-linux-LIBC
# else
- powerpc64-linux-gnu
+ powerpc64-linux-LIBC
# endif
# elif defined(__powerpc__)
- powerpc-linux-gnu
+ powerpc-linux-LIBC_PPC
# elif defined(__s390x__)
- s390x-linux-gnu
+ s390x-linux-LIBC
# elif defined(__s390__)
- s390-linux-gnu
+ s390-linux-LIBC
# elif defined(__sh__) && defined(__LITTLE_ENDIAN__)
- sh4-linux-gnu
+ sh4-linux-LIBC
# elif defined(__sparc__) && defined(__arch64__)
- sparc64-linux-gnu
+ sparc64-linux-LIBC
# elif defined(__sparc__)
- sparc-linux-gnu
+ sparc-linux-LIBC
# elif defined(__riscv)
# if __riscv_xlen == 32
- riscv32-linux-gnu
+ riscv32-linux-LIBC
# elif __riscv_xlen == 64
- riscv64-linux-gnu
+ riscv64-linux-LIBC
# else
# error unknown platform triplet
# endif
@@ -1102,12 +1169,7 @@ cat > conftest.c <<EOF
EOF
if $CPP $CPPFLAGS conftest.c >conftest.out 2>/dev/null; then
- PLATFORM_TRIPLET=`grep -v '^#' conftest.out | grep -v '^ *$' | tr -d ' '`
- case "$build_os" in
- linux-musl*)
- PLATFORM_TRIPLET=`echo "$PLATFORM_TRIPLET" | sed 's/linux-gnu/linux-musl/'`
- ;;
- esac
+ PLATFORM_TRIPLET=`grep -v '^#' conftest.out | grep -v '^ *$' | grep -v typedef | tr -d ' '`
AC_MSG_RESULT([$PLATFORM_TRIPLET])
else
AC_MSG_RESULT([none])

View File

@@ -0,0 +1,13 @@
diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py
index caa7285..ad666ac 100644
--- a/Lib/venv/__init__.py
+++ b/Lib/venv/__init__.py
@@ -379,7 +379,7 @@ class EnvBuilder:
if data is not None:
with open(dstfile, 'wb') as f:
f.write(data)
- shutil.copymode(srcfile, dstfile)
+ os.chmod(dstfile, 0o644)
def create(env_dir, system_site_packages=False, clear=False,

View File

@@ -0,0 +1,227 @@
{
__splicedPackages,
callPackage,
config,
db,
lib,
makeScopeWithSplicing',
pythonPackagesExtensions,
stdenv,
}@args:
(
let
# Common passthru for all Python interpreters.
passthruFun = import ./passthrufun.nix args;
sources = {
python313 = {
sourceVersion = {
major = "3";
minor = "13";
patch = "7";
suffix = "";
};
hash = "sha256-VGL5CZ39MOI43vg8cdkYl9jKpf9uvHpQ8U1IAs2qp5o=";
};
};
in
{
python27 = callPackage ./cpython/2.7 {
self = __splicedPackages.python27;
sourceVersion = {
major = "2";
minor = "7";
patch = "18";
suffix = ".8"; # ActiveState's Python 2 extended support
};
hash = "sha256-HUOzu3uJbtd+3GbmGD35KOk/CDlwL4S7hi9jJGRFiqI=";
inherit passthruFun;
};
python310 = callPackage ./cpython {
self = __splicedPackages.python310;
sourceVersion = {
major = "3";
minor = "10";
patch = "18";
suffix = "";
};
hash = "sha256-rmZbxnir2atqbhVz0kgWJaU3GbxRfppjTtK5/vrjgX8=";
inherit passthruFun;
};
python311 = callPackage ./cpython {
self = __splicedPackages.python311;
sourceVersion = {
major = "3";
minor = "11";
patch = "13";
suffix = "";
};
hash = "sha256-j7X5+8dgn6giyzFUmIRXXbf9llfL/7iVELXXl1ljqDo=";
inherit passthruFun;
};
python312 = callPackage ./cpython {
self = __splicedPackages.python312;
sourceVersion = {
major = "3";
minor = "12";
patch = "11";
suffix = "";
};
hash = "sha256-wwuyS38emhmxG1WlRkNPdOc5u0wnGj46gP9DgNSfets=";
inherit passthruFun;
};
python313 = callPackage ./cpython (
{
self = __splicedPackages.python313;
inherit passthruFun;
}
// sources.python313
);
python314 = callPackage ./cpython {
self = __splicedPackages.python314;
sourceVersion = {
major = "3";
minor = "14";
patch = "0";
suffix = "";
};
hash = "sha256-Ipna5ULTlc44g6ygDTyRAwfNaOCy9zNgmMjnt+7p8+k=";
inherit passthruFun;
};
# Minimal versions of Python (built without optional dependencies)
python3Minimal =
(callPackage ./cpython (
{
self = __splicedPackages.python3Minimal;
inherit passthruFun;
pythonAttr = "python3Minimal";
# strip down that python version as much as possible
withMinimalDeps = true;
}
// sources.python313
)).overrideAttrs
(old: {
# TODO(@Artturin): Add this to the main cpython expr
strictDeps = true;
pname = "python3-minimal";
});
pypy27 = callPackage ./pypy {
self = __splicedPackages.pypy27;
sourceVersion = {
major = "7";
minor = "3";
patch = "19";
};
hash = "sha256-hwPNywH5+Clm3UO2pgGPFAOZ21HrtDwSXB+aIV57sAM=";
pythonVersion = "2.7";
db = db.override { dbmSupport = !stdenv.hostPlatform.isDarwin; };
python = __splicedPackages.pythonInterpreters.pypy27_prebuilt;
inherit passthruFun;
};
pypy310 = callPackage ./pypy {
self = __splicedPackages.pypy310;
sourceVersion = {
major = "7";
minor = "3";
patch = "19";
};
hash = "sha256-p8IpMLkY9Ahwhl7Yp0FH9ENO+E09bKKzweupNV1JKcg=";
pythonVersion = "3.10";
db = db.override { dbmSupport = !stdenv.hostPlatform.isDarwin; };
python = __splicedPackages.pypy27;
inherit passthruFun;
};
pypy311 = callPackage ./pypy {
self = __splicedPackages.pypy311;
sourceVersion = {
major = "7";
minor = "3";
patch = "20";
};
hash = "sha256-d4bdp2AAPi6nQJwQN+UCAMV47EJ84CRaxM11hxCyBvs=";
pythonVersion = "3.11";
db = db.override { dbmSupport = !stdenv.hostPlatform.isDarwin; };
python = __splicedPackages.pypy27;
inherit passthruFun;
};
pypy27_prebuilt = callPackage ./pypy/prebuilt_2_7.nix {
# Not included at top-level
self = __splicedPackages.pythonInterpreters.pypy27_prebuilt;
sourceVersion = {
major = "7";
minor = "3";
patch = "19";
};
hash =
{
aarch64-linux = "sha256-/onU/UrxP3bf5zFZdQA1GM8XZSDjzOwVRKiNF09QkQ4=";
x86_64-linux = "sha256-04RFUIwurxTrs4DZwd7TIcXr6uMcfmaAAXPYPLjd9CM=";
aarch64-darwin = "sha256-KHgOC5CK1ttLTglvQjcSS+eezJcxlG2EDZyHSetnp1k=";
x86_64-darwin = "sha256-a+KNRI2OZP/8WG2bCuTQkGSoPMrrW4BgxlHFzZrgaHg=";
}
.${stdenv.system};
pythonVersion = "2.7";
inherit passthruFun;
};
pypy310_prebuilt = callPackage ./pypy/prebuilt.nix {
# Not included at top-level
self = __splicedPackages.pythonInterpreters.pypy310_prebuilt;
sourceVersion = {
major = "7";
minor = "3";
patch = "19";
};
hash =
{
aarch64-linux = "sha256-ryeliRePERmOIkSrZcpRBjC6l8Ex18zEAh61vFjef1c=";
x86_64-linux = "sha256-xzrCzCOArJIn/Sl0gr8qPheoBhi6Rtt1RNU1UVMh7B4=";
aarch64-darwin = "sha256-PbigP8SWFkgBZGhE1/OxK6oK2zrZoLfLEkUhvC4WijY=";
x86_64-darwin = "sha256-LF5cKjOsiCVR1/KLmNGdSGuJlapQgkpztO3Mau7DXGM=";
}
.${stdenv.system};
pythonVersion = "3.10";
inherit passthruFun;
};
pypy311_prebuilt = callPackage ./pypy/prebuilt.nix {
# Not included at top-level
self = __splicedPackages.pythonInterpreters.pypy311_prebuilt;
sourceVersion = {
major = "7";
minor = "3";
patch = "19";
};
hash =
{
aarch64-linux = "sha256-EyB9v4HOJOltp2CxuGNie3e7ILH7TJUZHgKgtyOD33Q=";
x86_64-linux = "sha256-kXfZ4LuRsF+SHGQssP9xoPNlO10ppC1A1qB4wVt1cg8=";
aarch64-darwin = "sha256-dwTg1TAuU5INMtz+mv7rEENtTJQjPogwz2A6qVWoYcE=";
x86_64-darwin = "sha256-okOfnTDf2ulqXpEBx9xUqKaLVsnXMU6jmbCiXT6H67I=";
}
.${stdenv.system};
pythonVersion = "3.11";
inherit passthruFun;
};
}
// lib.optionalAttrs config.allowAliases {
pypy39_prebuilt = throw "pypy 3.9 has been removed, use pypy 3.10 instead"; # Added 2025-01-03
}
)

View File

@@ -0,0 +1,99 @@
{
buildPythonPackage,
lib,
hatchling,
tomli-w,
}:
{
pname,
version,
# Editable root as string.
# Environment variables will be expanded at runtime using os.path.expandvars.
root,
# Arguments passed on verbatim to buildPythonPackage
derivationArgs ? { },
# Python dependencies
dependencies ? [ ],
optional-dependencies ? { },
# PEP-518 build-system https://peps.python.org/pep-518
build-system ? [ ],
# PEP-621 entry points https://peps.python.org/pep-0621/#entry-points
scripts ? { },
gui-scripts ? { },
entry-points ? { },
passthru ? { },
meta ? { },
}:
# Create a PEP-660 (https://peps.python.org/pep-0660/) editable package pointing to an impure location outside the Nix store.
# The primary use case of this function is to enable local development workflows where the local package is installed into a virtualenv-like environment using withPackages.
assert lib.isString root;
let
# In editable mode build-system's are considered to be runtime dependencies.
dependencies' = dependencies ++ build-system;
pyproject = {
# PEP-621 project table
project = {
name = pname;
inherit
version
scripts
gui-scripts
entry-points
;
dependencies = map lib.getName dependencies';
optional-dependencies = lib.mapAttrs (_: map lib.getName) optional-dependencies;
};
# Allow empty package
tool.hatch.build.targets.wheel.bypass-selection = true;
# Include our editable pointer file in build
tool.hatch.build.targets.wheel.force-include."_${pname}.pth" = "_${pname}.pth";
# Build editable package using hatchling
build-system = {
requires = [ "hatchling" ];
build-backend = "hatchling.build";
};
};
in
buildPythonPackage (
{
inherit
pname
version
optional-dependencies
passthru
meta
;
dependencies = dependencies';
pyproject = true;
unpackPhase = ''
python -c "import json, tomli_w; print(tomli_w.dumps(json.load(open('$pyprojectContentsPath'))))" > pyproject.toml
echo 'import os.path, sys; sys.path.insert(0, os.path.expandvars("${root}"))' > _${pname}.pth
'';
build-system = [ hatchling ];
}
// derivationArgs
// {
# Note: Using formats.toml generates another intermediary derivation that needs to be built.
# We inline the same functionality for better UX.
nativeBuildInputs = (derivationArgs.nativeBuildInputs or [ ]) ++ [ tomli-w ];
pyprojectContents = builtins.toJSON pyproject;
passAsFile = [ "pyprojectContents" ];
preferLocalBuild = true;
}
)

View File

@@ -0,0 +1,27 @@
# Setup hook to use in case a conda binary package is installed
echo "Sourcing conda install hook"
condaInstallPhase() {
echo "Executing condaInstallPhase"
runHook preInstall
# There are two different formats of conda packages.
# It either contains only a site-packages directory
# or multiple top level directories.
siteDir=@pythonSitePackages@
if [ -e ./site-packages ]; then
mkdir -p $out/$siteDir
cp -r ./site-packages/* $out/$siteDir
else
cp -r . $out
rm $out/env-vars
fi
runHook postInstall
echo "Finished executing condaInstallPhase"
}
if [ -z "${installPhase-}" ]; then
echo "Using condaInstallPhase"
installPhase=condaInstallPhase
fi

View File

@@ -0,0 +1,18 @@
# Setup hook to use in case a conda binary package is fetched
echo "Sourcing conda unpack hook"
condaUnpackPhase() {
echo "Executing condaUnpackPhase"
runHook preUnpack
# use lbzip2 for parallel decompression (bz2 is slow)
lbzip2 -dc -n $NIX_BUILD_CORES $src | tar --exclude='info' -x
# runHook postUnpack # Calls find...?
echo "Finished executing condaUnpackPhase"
}
if [ -z "${unpackPhase-}" ]; then
echo "Using condaUnpackPhase"
unpackPhase=condaUnpackPhase
fi

View File

@@ -0,0 +1,506 @@
self: dontUse:
with self;
let
inherit (python) pythonOnBuildForHost;
inherit (pkgs) runCommand;
pythonInterpreter = pythonOnBuildForHost.interpreter;
pythonSitePackages = python.sitePackages;
pythonCheckInterpreter = python.interpreter;
setuppy = ../run_setup.py;
in
{
makePythonHook =
let
defaultArgs = {
passthru.provides.setupHook = true;
};
in
args: pkgs.makeSetupHook (lib.recursiveUpdate defaultArgs args);
condaInstallHook = callPackage (
{
makePythonHook,
gnutar,
lbzip2,
}:
makePythonHook {
name = "conda-install-hook";
propagatedBuildInputs = [
gnutar
lbzip2
];
substitutions = {
inherit pythonSitePackages;
};
} ./conda-install-hook.sh
) { };
condaUnpackHook = callPackage (
{ makePythonHook }:
makePythonHook {
name = "conda-unpack-hook";
propagatedBuildInputs = [ ];
} ./conda-unpack-hook.sh
) { };
eggBuildHook = callPackage (
{ makePythonHook }:
makePythonHook {
name = "egg-build-hook.sh";
propagatedBuildInputs = [ ];
} ./egg-build-hook.sh
) { };
eggInstallHook = callPackage (
{ makePythonHook, setuptools }:
makePythonHook {
name = "egg-install-hook.sh";
propagatedBuildInputs = [ setuptools ];
substitutions = {
inherit pythonInterpreter pythonSitePackages;
};
} ./egg-install-hook.sh
) { };
eggUnpackHook = callPackage (
{ makePythonHook }:
makePythonHook {
name = "egg-unpack-hook.sh";
propagatedBuildInputs = [ ];
} ./egg-unpack-hook.sh
) { };
pipBuildHook = callPackage (
{
makePythonHook,
pip,
wheel,
}:
makePythonHook {
name = "pip-build-hook.sh";
propagatedBuildInputs = [
pip
wheel
];
substitutions = {
inherit pythonInterpreter pythonSitePackages;
};
} ./pip-build-hook.sh
) { };
pypaBuildHook =
callPackage
(
{
makePythonHook,
build,
wheel,
}:
makePythonHook {
name = "pypa-build-hook.sh";
propagatedBuildInputs = [ wheel ];
substitutions = {
inherit build;
};
# A test to ensure that this hook never propagates any of its dependencies
# into the build environment.
# This prevents false positive alerts raised by catchConflictsHook.
# Such conflicts don't happen within the standard nixpkgs python package
# set, but in downstream projects that build packages depending on other
# versions of this hook's dependencies.
passthru.tests = callPackage ./pypa-build-hook-test.nix {
inherit pythonOnBuildForHost;
};
} ./pypa-build-hook.sh
)
{
inherit (pythonOnBuildForHost.pkgs) build;
};
pipInstallHook = callPackage (
{ makePythonHook, pip }:
makePythonHook {
name = "pip-install-hook";
propagatedBuildInputs = [ pip ];
substitutions = {
inherit pythonInterpreter pythonSitePackages;
};
} ./pip-install-hook.sh
) { };
pypaInstallHook =
callPackage
(
{ makePythonHook, installer }:
makePythonHook {
name = "pypa-install-hook";
propagatedBuildInputs = [ installer ];
substitutions = {
inherit pythonInterpreter pythonSitePackages;
};
} ./pypa-install-hook.sh
)
{
inherit (pythonOnBuildForHost.pkgs) installer;
};
pytestCheckHook = callPackage (
{
makePythonHook,
pytest,
# For package tests
testers,
objprint,
}:
makePythonHook {
name = "pytest-check-hook";
propagatedBuildInputs = [ pytest ];
substitutions = {
inherit pythonCheckInterpreter;
};
passthru = {
tests = {
basic = objprint.overridePythonAttrs (previousPythonAttrs: {
pname = "test-pytestCheckHook-basic-${previousPythonAttrs.pname}";
});
disabledTests = objprint.overridePythonAttrs (previousPythonAttrs: {
pname = "test-pytestCheckHook-disabledTests-${previousPythonAttrs.pname}";
disabledTests = [
"test_print"
]
++ previousPythonAttrs.disabledTests or [ ];
});
disabledTests-expression = objprint.overridePythonAttrs (previousPythonAttrs: {
__structuredAttrs = true;
pname = "test-pytestCheckHook-disabledTests-expression-${previousPythonAttrs.pname}";
disabledTests = [
"TestBasic and test_print"
"test_str"
]
++ previousPythonAttrs.disabledTests or [ ];
});
disabledTestPaths = objprint.overridePythonAttrs (previousPythonAttrs: {
pname = "test-pytestCheckHook-disabledTestPaths-${previousPythonAttrs.pname}";
disabledTestPaths = [
"tests/test_basic.py"
]
++ previousPythonAttrs.disabledTestPaths or [ ];
});
disabledTestPaths-nonexistent = testers.testBuildFailure (
objprint.overridePythonAttrs (previousPythonAttrs: {
pname = "test-pytestCheckHook-disabledTestPaths-nonexistent-${previousPythonAttrs.pname}";
disabledTestPaths = [
"tests/test_foo.py"
]
++ previousPythonAttrs.disabledTestPaths or [ ];
})
);
disabledTestPaths-item = objprint.overridePythonAttrs (previousPythonAttrs: {
pname = "test-pytestCheckHook-disabledTestPaths-item-${previousPythonAttrs.pname}";
disabledTestPaths = [
"tests/test_basic.py::TestBasic"
]
++ previousPythonAttrs.disabledTestPaths or [ ];
});
disabledTestPaths-glob = objprint.overridePythonAttrs (previousPythonAttrs: {
pname = "test-pytestCheckHook-disabledTestPaths-glob-${previousPythonAttrs.pname}";
disabledTestPaths = [
"tests/test_obj*.py"
]
++ previousPythonAttrs.disabledTestPaths or [ ];
});
disabledTestPaths-glob-nonexistent = testers.testBuildFailure (
objprint.overridePythonAttrs (previousPythonAttrs: {
pname = "test-pytestCheckHook-disabledTestPaths-glob-nonexistent-${previousPythonAttrs.pname}";
disabledTestPaths = [
"tests/test_foo*.py"
]
++ previousPythonAttrs.disabledTestPaths or [ ];
})
);
enabledTests = objprint.overridePythonAttrs (previousPythonAttrs: {
pname = "test-pytestCheckHook-enabledTests-${previousPythonAttrs.pname}";
enabledTests = [
"TestBasic"
]
++ previousPythonAttrs.disabledTests or [ ];
});
enabledTests-expression = objprint.overridePythonAttrs (previousPythonAttrs: {
__structuredAttrs = true;
pname = "test-pytestCheckHook-enabledTests-expression-${previousPythonAttrs.pname}";
enabledTests = [
"TestBasic and test_print"
"test_str"
]
++ previousPythonAttrs.disabledTests or [ ];
});
enabledTests-disabledTests = objprint.overridePythonAttrs (previousPythonAttrs: {
pname = "test-pytestCheckHook-enabledTests-disabledTests-${previousPythonAttrs.pname}";
enabledTests = [
"TestBasic"
]
++ previousPythonAttrs.disabledTests or [ ];
disabledTests = [
"test_print"
]
++ previousPythonAttrs.disabledTests or [ ];
});
enabledTestPaths = objprint.overridePythonAttrs (previousPythonAttrs: {
pname = "test-pytestCheckHook-enabledTestPaths-${previousPythonAttrs.pname}";
enabledTestPaths = [
"tests/test_basic.py"
]
++ previousPythonAttrs.enabledTestPaths or [ ];
});
enabledTestPaths-nonexistent = testers.testBuildFailure (
objprint.overridePythonAttrs (previousPythonAttrs: {
pname = "test-pytestCheckHook-enabledTestPaths-nonexistent-${previousPythonAttrs.pname}";
enabledTestPaths = [
"tests/test_foo.py"
]
++ previousPythonAttrs.enabledTestPaths or [ ];
})
);
enabledTestPaths-dir = objprint.overridePythonAttrs (previousPythonAttrs: {
pname = "test-pytestCheckHook-enabledTestPaths-dir-${previousPythonAttrs.pname}";
enabledTestPaths = [
"tests"
]
++ previousPythonAttrs.enabledTestPaths or [ ];
});
enabledTestPaths-dir-disabledTestPaths = objprint.overridePythonAttrs (previousPythonAttrs: {
pname = "test-pytestCheckHook-enabledTestPaths-dir-disabledTestPaths-${previousPythonAttrs.pname}";
enabledTestPaths = [
"tests"
]
++ previousPythonAttrs.enabledTestPaths or [ ];
disabledTestPaths = [
"tests/test_basic.py"
]
++ previousPythonAttrs.disabledTestPaths or [ ];
});
enabledTestPaths-glob = objprint.overridePythonAttrs (previousPythonAttrs: {
pname = "test-pytestCheckHook-enabledTestPaths-glob-${previousPythonAttrs.pname}";
enabledTestPaths = [
"tests/test_obj*.py"
]
++ previousPythonAttrs.enabledTestPaths or [ ];
});
enabledTestPaths-glob-nonexistent = testers.testBuildFailure (
objprint.overridePythonAttrs (previousPythonAttrs: {
pname = "test-pytestCheckHook-enabledTestPaths-glob-nonexistent-${previousPythonAttrs.pname}";
enabledTestPaths = [
"tests/test_foo*.py"
]
++ previousPythonAttrs.enabledTestPaths or [ ];
})
);
enabledTestPaths-item = objprint.overridePythonAttrs (previousPythonAttrs: {
pname = "test-pytestCheckHook-enabledTestPaths-item-${previousPythonAttrs.pname}";
enabledTestPaths = [
"tests/test_basic.py::TestBasic"
]
++ previousPythonAttrs.enabledTestPaths or [ ];
});
};
};
} ./pytest-check-hook.sh
) { };
pythonCatchConflictsHook = callPackage (
{ makePythonHook, setuptools }:
makePythonHook {
name = "python-catch-conflicts-hook";
substitutions =
let
useLegacyHook = lib.versionOlder python.pythonVersion "3";
in
{
inherit pythonInterpreter pythonSitePackages;
catchConflicts =
if useLegacyHook then
../catch_conflicts/catch_conflicts_py2.py
else
../catch_conflicts/catch_conflicts.py;
}
// lib.optionalAttrs useLegacyHook {
inherit setuptools;
};
passthru.tests = import ./python-catch-conflicts-hook-tests.nix {
inherit pythonOnBuildForHost runCommand;
inherit lib;
inherit (pkgs) coreutils gnugrep writeShellScript;
};
} ./python-catch-conflicts-hook.sh
) { };
pythonImportsCheckHook = callPackage (
{ makePythonHook }:
makePythonHook {
name = "python-imports-check-hook.sh";
substitutions = {
inherit pythonCheckInterpreter pythonSitePackages;
};
} ./python-imports-check-hook.sh
) { };
pythonNamespacesHook = callPackage (
{ makePythonHook, buildPackages }:
makePythonHook {
name = "python-namespaces-hook.sh";
substitutions = {
inherit pythonSitePackages;
inherit (buildPackages) findutils;
};
} ./python-namespaces-hook.sh
) { };
pythonOutputDistHook = callPackage (
{ makePythonHook }:
makePythonHook {
name = "python-output-dist-hook";
} ./python-output-dist-hook.sh
) { };
pythonRecompileBytecodeHook = callPackage (
{ makePythonHook }:
makePythonHook {
name = "python-recompile-bytecode-hook";
substitutions = {
inherit pythonInterpreter pythonSitePackages;
compileArgs = lib.concatStringsSep " " (
[
"-q"
"-f"
"-i -"
]
++ lib.optionals isPy3k [ "-j $NIX_BUILD_CORES" ]
);
bytecodeName = if isPy3k then "__pycache__" else "*.pyc";
};
} ./python-recompile-bytecode-hook.sh
) { };
pythonRelaxDepsHook = callPackage (
{ makePythonHook, wheel }:
makePythonHook {
name = "python-relax-deps-hook";
substitutions = {
inherit pythonInterpreter pythonSitePackages wheel;
};
} ./python-relax-deps-hook.sh
) { };
pythonRemoveBinBytecodeHook = callPackage (
{ makePythonHook }:
makePythonHook {
name = "python-remove-bin-bytecode-hook";
} ./python-remove-bin-bytecode-hook.sh
) { };
pythonRemoveTestsDirHook = callPackage (
{ makePythonHook }:
makePythonHook {
name = "python-remove-tests-dir-hook";
substitutions = {
inherit pythonSitePackages;
};
} ./python-remove-tests-dir-hook.sh
) { };
pythonRuntimeDepsCheckHook = callPackage (
{ makePythonHook, packaging }:
makePythonHook {
name = "python-runtime-deps-check-hook.sh";
propagatedBuildInputs = [ packaging ];
substitutions = {
inherit pythonInterpreter pythonSitePackages;
hook = ./python-runtime-deps-check-hook.py;
};
} ./python-runtime-deps-check-hook.sh
) { };
setuptoolsBuildHook = callPackage (
{
makePythonHook,
setuptools,
wheel,
}:
makePythonHook {
name = "setuptools-build-hook";
propagatedBuildInputs = [
setuptools
wheel
];
substitutions = {
inherit pythonInterpreter setuppy;
# python2.pkgs.setuptools does not support parallelism
setuptools_has_parallel = setuptools != null && lib.versionAtLeast setuptools.version "69";
};
} ./setuptools-build-hook.sh
) { };
setuptoolsRustBuildHook = callPackage (
{ makePythonHook, setuptools-rust }:
makePythonHook {
name = "setuptools-rust-setup-hook";
propagatedBuildInputs = [ setuptools-rust ];
substitutions = {
pyLibDir = "${python}/lib/${python.libPrefix}";
cargoBuildTarget = stdenv.hostPlatform.rust.rustcTargetSpec;
cargoLinkerVar = stdenv.hostPlatform.rust.cargoEnvVarTarget;
targetLinker = "${stdenv.cc}/bin/${stdenv.cc.targetPrefix}cc";
};
} ./setuptools-rust-hook.sh
) { };
unittestCheckHook = callPackage (
{ makePythonHook }:
makePythonHook {
name = "unittest-check-hook";
substitutions = {
inherit pythonCheckInterpreter;
};
} ./unittest-check-hook.sh
) { };
venvShellHook = disabledIf (!isPy3k) (
callPackage (
{ makePythonHook, ensureNewerSourcesForZipFilesHook }:
makePythonHook {
name = "venv-shell-hook";
propagatedBuildInputs = [ ensureNewerSourcesForZipFilesHook ];
substitutions = {
inherit pythonInterpreter;
};
} ./venv-shell-hook.sh
) { }
);
wheelUnpackHook = callPackage (
{ makePythonHook, wheel }:
makePythonHook {
name = "wheel-unpack-hook.sh";
propagatedBuildInputs = [ wheel ];
} ./wheel-unpack-hook.sh
) { };
wrapPython = callPackage ../wrap-python.nix {
inherit (pkgs.buildPackages) makeWrapper;
};
sphinxHook = callPackage (
{ makePythonHook, installShellFiles }:
makePythonHook {
name = "python${python.pythonVersion}-sphinx-hook";
propagatedBuildInputs = [
pythonOnBuildForHost.pkgs.sphinx
installShellFiles
];
substitutions = {
sphinxBuild = "${pythonOnBuildForHost.pkgs.sphinx}/bin/sphinx-build";
};
} ./sphinx-hook.sh
) { };
}

View File

@@ -0,0 +1,15 @@
# Setup hook to use for eggs
echo "Sourcing egg-build-hook"
eggBuildPhase() {
echo "Executing eggBuildPhase"
runHook preBuild
runHook postBuild
echo "Finished executing eggBuildPhase"
}
if [ -z "${dontUseEggBuild-}" ] && [ -z "${buildPhase-}" ]; then
echo "Using eggBuildPhase"
buildPhase=eggBuildPhase
fi

View File

@@ -0,0 +1,21 @@
# Setup hook for eggs
echo "Sourcing egg-install-hook"
eggInstallPhase() {
echo "Executing eggInstallPhase"
runHook preInstall
mkdir -p "$out/@pythonSitePackages@"
export PYTHONPATH="$out/@pythonSitePackages@:$PYTHONPATH"
find
@pythonInterpreter@ -m easy_install --prefix="$out" *.egg
runHook postInstall
echo "Finished executing eggInstallPhase"
}
if [ -z "${dontUseEggInstall-}" ] && [ -z "${installPhase-}" ]; then
echo "Using eggInstallPhase"
installPhase=eggInstallPhase
fi

View File

@@ -0,0 +1,17 @@
# Setup hook to use in case an egg is fetched
echo "Sourcing egg setup hook"
eggUnpackPhase() {
echo "Executing eggUnpackPhase"
runHook preUnpack
cp "$src" "$(stripHash "$src")"
# runHook postUnpack # Calls find...?
echo "Finished executing eggUnpackPhase"
}
if [ -z "${dontUseEggUnpack-}" ] && [ -z "${unpackPhase-}" ]; then
echo "Using eggUnpackPhase"
unpackPhase=eggUnpackPhase
fi

View File

@@ -0,0 +1,57 @@
# Setup hook to use for pip projects
# shellcheck shell=bash
echo "Sourcing pip-build-hook"
pipBuildPhase() {
echo "Executing pipBuildPhase"
runHook preBuild
mkdir -p dist
local -a flagsArray=(
--verbose
--no-index
--no-deps
--no-clean
--no-build-isolation
--wheel-dir dist
)
concatTo flagsArray pipBuildFlags
echo "Creating a wheel..."
echoCmd 'pip build flags' "${flagsArray[@]}"
@pythonInterpreter@ -m pip wheel "${flagsArray[@]}" .
echo "Finished creating a wheel..."
runHook postBuild
echo "Finished executing pipBuildPhase"
}
pipShellHook() {
echo "Executing pipShellHook"
runHook preShellHook
# Long-term setup.py should be dropped.
if [ -e pyproject.toml ]; then
tmp_path=$(mktemp -d)
export PATH="$tmp_path/bin:$PATH"
export PYTHONPATH="$tmp_path/@pythonSitePackages@:$PYTHONPATH"
mkdir -p "$tmp_path/@pythonSitePackages@"
@pythonInterpreter@ -m pip install -e . --prefix "$tmp_path" \
--no-build-isolation >&2
fi
runHook postShellHook
echo "Finished executing pipShellHook"
}
if [ -z "${dontUsePipBuild-}" ] && [ -z "${buildPhase-}" ]; then
echo "Using pipBuildPhase"
buildPhase=pipBuildPhase
fi
if [ -z "${shellHook-}" ]; then
echo "Using pipShellHook"
shellHook=pipShellHook
fi

View File

@@ -0,0 +1,34 @@
# Setup hook for pip.
# shellcheck shell=bash
echo "Sourcing pip-install-hook"
pipInstallPhase() {
echo "Executing pipInstallPhase"
runHook preInstall
# shellcheck disable=SC2154
mkdir -p "$out/@pythonSitePackages@"
export PYTHONPATH="$out/@pythonSitePackages@:$PYTHONPATH"
local -a flagsArray=(
--no-index
--no-warn-script-location
--prefix="$out"
--no-cache
)
concatTo flagsArray pipInstallFlags
pushd dist || return 1
echoCmd 'pip install flags' "${flagsArray[@]}"
@pythonInterpreter@ -m pip install ./*.whl "${flagsArray[@]}"
popd || return 1
runHook postInstall
echo "Finished executing pipInstallPhase"
}
if [ -z "${dontUsePipInstall-}" ] && [ -z "${installPhase-}" ]; then
echo "Using pipInstallPhase"
installPhase=pipInstallPhase
fi

View File

@@ -0,0 +1,36 @@
{ pythonOnBuildForHost, runCommand }:
{
dont-propagate-conflicting-deps =
let
# customize a package so that its store paths differs
mkConflict = pkg: pkg.overrideAttrs { some_modification = true; };
# minimal pyproject.toml for the example project
pyprojectToml = builtins.toFile "pyproject.toml" ''
[project]
name = "my-project"
version = "1.0.0"
'';
# the source of the example project
projectSource = runCommand "my-project-source" { } ''
mkdir -p $out/src/my_project
cp ${pyprojectToml} $out/pyproject.toml
touch $out/src/my_project/__init__.py
'';
in
# this build must never triger conflicts
pythonOnBuildForHost.pkgs.buildPythonPackage {
pname = "dont-propagate-conflicting-deps";
version = "0.0.0";
src = projectSource;
pyproject = true;
dependencies = [
# At least one dependency of `build` should be included here to
# keep the test meaningful
(mkConflict pythonOnBuildForHost.pkgs.tomli)
];
build-system = [
# setuptools is also needed to build the example project
pythonOnBuildForHost.pkgs.setuptools
];
};
}

View File

@@ -0,0 +1,29 @@
# Setup hook to use for pypa/build projects
# shellcheck shell=bash
echo "Sourcing pypa-build-hook"
pypaBuildPhase() {
echo "Executing pypaBuildPhase"
runHook preBuild
local -a flagsArray=(
--no-isolation
--outdir dist/
--wheel
)
concatTo flagsArray pypaBuildFlags
echo "Creating a wheel..."
echoCmd 'pypa build flags' "${flagsArray[@]}"
@build@/bin/pyproject-build "${flagsArray[@]}"
echo "Finished creating a wheel..."
runHook postBuild
echo "Finished executing pypaBuildPhase"
}
if [ -z "${dontUsePypaBuild-}" ] && [ -z "${buildPhase-}" ]; then
echo "Using pypaBuildPhase"
buildPhase=pypaBuildPhase
fi

View File

@@ -0,0 +1,26 @@
# Setup hook for PyPA installer.
echo "Sourcing pypa-install-hook"
pypaInstallPhase() {
echo "Executing pypaInstallPhase"
runHook preInstall
pushd dist >/dev/null
for wheel in *.whl; do
@pythonInterpreter@ -m installer --prefix "$out" "$wheel"
echo "Successfully installed $wheel"
done
popd >/dev/null
export PYTHONPATH="$out/@pythonSitePackages@:$PYTHONPATH"
runHook postInstall
echo "Finished executing pypaInstallPhase"
}
if [ -z "${dontUsePypaInstall-}" ] && [ -z "${installPhase-}" ]; then
echo "Using pypaInstallPhase"
installPhase=pypaInstallPhase
fi

View File

@@ -0,0 +1,100 @@
# Setup hook for pytest
# shellcheck shell=bash
echo "Sourcing pytest-check-hook"
function _pytestIncludeExcludeExpr() {
local includeListName="$1"
local -n includeListRef="$includeListName"
local excludeListName="$2"
local -n excludeListRef="$excludeListName"
local includeString excludeString
if [[ -n "${includeListRef[*]-}" ]]; then
# ((element1) or (element2))
includeString="(($(concatStringsSep ") or (" "$includeListName")))"
fi
if [[ -n "${excludeListRef[*]-}" ]]; then
# and not (element1) and not (element2)
excludeString="${includeString:+ and }not ($(concatStringsSep ") and not (" "$excludeListName"))"
fi
echo "$includeString$excludeString"
}
function pytestCheckPhase() {
echo "Executing pytestCheckPhase"
runHook preCheck
# Compose arguments
local -a flagsArray=(-m pytest)
local -a _pathsArray
local path
_pathsArray=()
concatTo _pathsArray enabledTestPaths
for path in "${_pathsArray[@]}"; do
if [[ "$path" =~ "::" ]]; then
flagsArray+=("$path")
else
# The `|| kill "$$"` trick propagates the errors from the process substitutiton subshell,
# which is suggested by a StackOverflow answer: https://unix.stackexchange.com/a/217643
readarray -t -O"${#flagsArray[@]}" flagsArray < <(
@pythonCheckInterpreter@ - "$path" <<EOF || kill "$$"
import glob
import sys
path_glob=sys.argv[1]
if not len(path_glob):
sys.exit('Got an empty enabled tests path glob. Aborting')
path_expanded = glob.glob(path_glob)
if not len(path_expanded):
sys.exit('Enabled tests path glob "{}" does not match any paths. Aborting'.format(path_glob))
for path in path_expanded:
print(path)
EOF
)
fi
done
_pathsArray=()
concatTo _pathsArray disabledTestPaths
for path in "${_pathsArray[@]}"; do
if [[ "$path" =~ "::" ]]; then
flagsArray+=("--deselect=$path")
else
# Check if every path glob matches at least one path
@pythonCheckInterpreter@ - "$path" <<EOF
import glob
import sys
path_glob=sys.argv[1]
if not len(path_glob):
sys.exit('Got an empty disabled tests path glob. Aborting')
if next(glob.iglob(path_glob), None) is None:
sys.exit('Disabled tests path glob "{}" does not match any paths. Aborting'.format(path_glob))
EOF
flagsArray+=("--ignore-glob=$path")
fi
done
if [[ -n "${enabledTests[*]-}" ]] || [[ -n "${disabledTests[*]-}" ]]; then
flagsArray+=(-k "$(_pytestIncludeExcludeExpr enabledTests disabledTests)")
fi
if [[ -n "${enabledTestMarks[*]-}" ]] || [[ -n "${disabledTestMarks[*]-}" ]]; then
flagsArray+=(-m "$(_pytestIncludeExcludeExpr enabledTestMarks disabledTestMarks)")
fi
# Compatibility layer to the obsolete pytestFlagsArray
eval "flagsArray+=(${pytestFlagsArray[*]-})"
concatTo flagsArray pytestFlags
echoCmd 'pytest flags' "${flagsArray[@]}"
@pythonCheckInterpreter@ "${flagsArray[@]}"
runHook postCheck
echo "Finished executing pytestCheckPhase"
}
if [ -z "${dontUsePytestCheck-}" ] && [ -z "${installCheckPhase-}" ]; then
echo "Using pytestCheckPhase"
appendToVar preDistPhases pytestCheckPhase
fi

View File

@@ -0,0 +1,212 @@
{
lib,
pythonOnBuildForHost,
runCommand,
writeShellScript,
coreutils,
gnugrep,
}:
let
pythonPkgs = pythonOnBuildForHost.pkgs;
### UTILITIES
# customize a package so that its store paths differs
customize = pkg: pkg.overrideAttrs { some_modification = true; };
# generates minimal pyproject.toml
pyprojectToml =
pname:
builtins.toFile "pyproject.toml" ''
[project]
name = "${pname}"
version = "1.0.0"
'';
# generates source for a python project
projectSource =
pname:
runCommand "my-project-source" { } ''
mkdir -p $out/src
cp ${pyprojectToml pname} $out/pyproject.toml
touch $out/src/__init__.py
'';
# helper to reduce boilerplate
generatePythonPackage =
args:
pythonPkgs.buildPythonPackage (
{
version = "1.0.0";
src = runCommand "my-project-source" { } ''
mkdir -p $out/src
cp ${pyprojectToml args.pname} $out/pyproject.toml
touch $out/src/__init__.py
'';
pyproject = true;
catchConflicts = true;
buildInputs = [ pythonPkgs.setuptools ];
}
// args
);
# in order to test for a failing build, wrap it in a shell script
expectFailure =
build: errorMsg:
lib.overrideDerivation build (old: {
builder = writeShellScript "test-for-failure" ''
export PATH=${coreutils}/bin:${gnugrep}/bin:$PATH
${old.builder} "$@" > ./log 2>&1
status=$?
cat ./log
if [ $status -eq 0 ] || ! grep -q "${errorMsg}" ./log; then
echo "The build should have failed with '${errorMsg}', but it didn't"
exit 1
else
echo "The build failed as expected with: ${errorMsg}"
mkdir -p $out
fi
'';
});
in
{
### TEST CASES
# Test case which must not trigger any conflicts.
# This derivation has runtime dependencies on custom versions of multiple build tools.
# This scenario is relevant for lang2nix tools which do not override the nixpkgs fix-point.
# see https://github.com/NixOS/nixpkgs/issues/283695
ignores-build-time-deps = generatePythonPackage {
pname = "ignores-build-time-deps";
buildInputs = [
pythonPkgs.build
pythonPkgs.packaging
pythonPkgs.setuptools
pythonPkgs.wheel
];
propagatedBuildInputs = [
# Add customized versions of build tools as runtime deps
(customize pythonPkgs.packaging)
(customize pythonPkgs.setuptools)
(customize pythonPkgs.wheel)
];
};
# multi-output derivation with dependency on itself must not crash
cyclic-dependencies = generatePythonPackage {
pname = "cyclic-dependencies";
preFixup = ''
appendToVar propagatedBuildInputs "$out"
'';
};
# Simplest test case that should trigger a conflict
catches-simple-conflict =
let
# this build must fail due to conflicts
package = pythonPkgs.buildPythonPackage rec {
pname = "catches-simple-conflict";
version = "0.0.0";
src = projectSource pname;
pyproject = true;
catchConflicts = true;
buildInputs = [
pythonPkgs.setuptools
];
# depend on two different versions of packaging
# (an actual runtime dependency conflict)
propagatedBuildInputs = [
pythonPkgs.packaging
(customize pythonPkgs.packaging)
];
};
in
expectFailure package "Found duplicated packages in closure for dependency 'packaging'";
/*
More complex test case with a transitive conflict
Test sets up this dependency tree:
toplevel
dep1
leaf
dep2
leaf (customized version -> conflicting)
*/
catches-transitive-conflict =
let
# package depending on both dependency1 and dependency2
toplevel = generatePythonPackage {
pname = "catches-transitive-conflict";
propagatedBuildInputs = [
dep1
dep2
];
};
# dep1 package depending on leaf
dep1 = generatePythonPackage {
pname = "dependency1";
propagatedBuildInputs = [ leaf ];
};
# dep2 package depending on conflicting version of leaf
dep2 = generatePythonPackage {
pname = "dependency2";
propagatedBuildInputs = [ (customize leaf) ];
};
# some leaf package
leaf = generatePythonPackage {
pname = "leaf";
};
in
expectFailure toplevel "Found duplicated packages in closure for dependency 'leaf'";
/*
Transitive conflict with multiple dependency chains leading to the
conflicting package.
Test sets up this dependency tree:
toplevel
dep1
leaf
dep2
leaf
dep3
leaf (customized version -> conflicting)
*/
catches-conflict-multiple-chains =
let
# package depending on dependency1, dependency2 and dependency3
toplevel = generatePythonPackage {
pname = "catches-conflict-multiple-chains";
propagatedBuildInputs = [
dep1
dep2
dep3
];
};
# dep1 package depending on leaf
dep1 = generatePythonPackage {
pname = "dependency1";
propagatedBuildInputs = [ leaf ];
};
# dep2 package depending on leaf
dep2 = generatePythonPackage {
pname = "dependency2";
propagatedBuildInputs = [ leaf ];
};
# dep3 package depending on conflicting version of leaf
dep3 = generatePythonPackage {
pname = "dependency3";
propagatedBuildInputs = [ (customize leaf) ];
};
# some leaf package
leaf = generatePythonPackage {
pname = "leaf";
};
in
expectFailure toplevel "Found duplicated packages in closure for dependency 'leaf'";
}

View File

@@ -0,0 +1,10 @@
# Setup hook for detecting conflicts in Python packages
echo "Sourcing python-catch-conflicts-hook.sh"
pythonCatchConflictsPhase() {
PYTHONPATH="@setuptools@/@pythonSitePackages@:$PYTHONPATH" @pythonInterpreter@ @catchConflicts@
}
if [ -z "${dontUsePythonCatchConflicts-}" ]; then
appendToVar preDistPhases pythonCatchConflictsPhase
fi

View File

@@ -0,0 +1,28 @@
# shellcheck shell=bash
# Setup hook for checking whether Python imports succeed
echo "Sourcing python-imports-check-hook.sh"
pythonImportsCheckPhase() {
echo "Executing pythonImportsCheckPhase"
if [[ -n "${pythonImportsCheck[*]-}" ]]; then
echo "Check whether the following modules can be imported: ${pythonImportsCheck[*]}"
# shellcheck disable=SC2154
pythonImportsCheckOutput="$out"
if [[ -n "${python-}" ]]; then
echo "Using python specific output \$python for imports check"
pythonImportsCheckOutput=$python
fi
export PYTHONPATH="$pythonImportsCheckOutput/@pythonSitePackages@:$PYTHONPATH"
# Python modules and namespaces names are Python identifiers, which must not contain spaces.
# See https://docs.python.org/3/reference/lexical_analysis.html
# shellcheck disable=SC2048,SC2086
(cd "$pythonImportsCheckOutput" && @pythonCheckInterpreter@ -c 'import sys; import importlib; list(map(lambda mod: importlib.import_module(mod), sys.argv[1:]))' ${pythonImportsCheck[*]})
fi
}
if [[ -z "${dontUsePythonImportsCheck-}" ]]; then
echo "Using pythonImportsCheckPhase"
appendToVar preDistPhases pythonImportsCheckPhase
fi

View File

@@ -0,0 +1,57 @@
# Clean up __init__.py's found in namespace directories
# shellcheck shell=bash
echo "Sourcing python-namespaces-hook"
pythonNamespacesHook() {
echo "Executing pythonNamespacesHook"
# Python namespaces names are Python identifiers, which must not contain spaces.
# See https://docs.python.org/3/reference/lexical_analysis.html
# shellcheck disable=SC2048
for namespace in ${pythonNamespaces[*]-}; do
echo "Enforcing PEP420 namespace: ${namespace}"
# split namespace into segments. "azure.mgmt" -> "azure mgmt"
IFS='.' read -ra pathSegments <<<"$namespace"
# shellcheck disable=SC2154
constructedPath=$out/@pythonSitePackages@
# Need to remove the __init__.py at each namespace level
# E.g `azure/__init__.py` and `azure/mgmt/__init__.py`
# The __pycache__ entry also needs to be removed
for pathSegment in "${pathSegments[@]}"; do
constructedPath=${constructedPath}/${pathSegment}
pathToRemove=${constructedPath}/__init__.py
pycachePath=${constructedPath}/__pycache__/
# remove __init__.py
if [ -f "$pathToRemove" ]; then
rm -v "$pathToRemove"
fi
# remove ${pname}-${version}-${python-interpeter}-nspkg.pth
#
# Still need to check that parent directory exists in the
# event of a "meta-package" package, which will just install
# other packages, but not produce anything in site-packages
# besides meta information
if [[ -d "${constructedPath}/../" ]] && [[ -z "${dontRemovePth-}" ]]; then
# .pth files are located in the parent directory of a module
@findutils@/bin/find "${constructedPath}/../" -name '*-nspkg.pth' -exec rm -v "{}" +
fi
# remove __pycache__/ entry, can be interpreter specific. E.g. __init__.cpython-38.pyc
# use null characters to perserve potential whitespace in filepath
if [ -d "$pycachePath" ]; then
@findutils@/bin/find "$pycachePath" -name '__init__*' -exec rm -v "{}" +
fi
done
done
echo "Finished executing pythonNamespacesHook"
}
if [[ -z "${dontUsePythonNamespacesHook-}" ]] && [[ -n "${pythonNamespaces-}" ]]; then
postFixupHooks+=(pythonNamespacesHook)
fi

View File

@@ -0,0 +1,27 @@
# Setup hook for storing dist folder (wheels/sdists) in a separate output
# shellcheck shell=bash
echo "Sourcing python-catch-conflicts-hook.sh"
pythonOutputDistPhase() {
echo "Executing pythonOutputDistPhase"
if [[ -d dist ]]; then
# shellcheck disable=SC2154
mv "dist" "$dist"
else
cat >&2 <<EOF
The build contains no ./dist directory.
If this project is not setuptools-based, pass
format = "other";
to buildPythonApplication/buildPythonPackage or another appropriate value as described here:
https://nixos.org/manual/nixpkgs/stable/#buildpythonpackage-function
EOF
false
fi
echo "Finished executing pythonOutputDistPhase"
}
appendToVar preFixupPhases pythonOutputDistPhase

View File

@@ -0,0 +1,24 @@
# Setup hook for recompiling bytecode.
# https://github.com/NixOS/nixpkgs/issues/81441
echo "Sourcing python-recompile-bytecode-hook.sh"
# Remove all bytecode from the $out output. Then, recompile only site packages folder
# Note this effectively duplicates `python-remove-bin-bytecode`, but long-term
# this hook should be removed again.
pythonRecompileBytecodePhase() {
# TODO: consider other outputs than $out
items="$(find "$out" -name "@bytecodeName@")"
if [[ -n $items ]]; then
for pycache in $items; do
rm -rf "$pycache"
done
fi
find "$out"/@pythonSitePackages@ -name "*.py" -exec @pythonInterpreter@ -OO -m compileall @compileArgs@ {} +
}
if [ -z "${dontUsePythonRecompileBytecode-}" ]; then
appendToVar postPhases pythonRecompileBytecodePhase
fi

View File

@@ -0,0 +1,112 @@
# shellcheck shell=bash
# Setup hook that modifies Python dependencies versions.
#
# Example usage in a derivation:
#
# { …, python3Packages, … }:
#
# python3Packages.buildPythonPackage {
# …
# # This will relax the dependency restrictions
# # e.g.: abc>1,<=2 -> abc
# pythonRelaxDeps = [ "abc" ];
# # This will relax all dependencies restrictions instead
# # pythonRelaxDeps = true;
# # This will remove the dependency
# # e.g.: cde>1,<=2 -> <nothing>
# pythonRemoveDeps = [ "cde" ];
# # This will remove all dependencies from the project
# # pythonRemoveDeps = true;
# …
# }
#
# IMPLEMENTATION NOTES:
#
# The "Requires-Dist" dependency specification format is described in PEP 508.
# Examples that the regular expressions in this hook needs to support:
#
# Requires-Dist: foo
# -> foo
# Requires-Dist: foo[optional]
# -> foo[optional]
# Requires-Dist: foo[optional]~=1.2.3
# -> foo[optional]
# Requires-Dist: foo[optional, xyz] (~=1.2.3)
# -> foo[optional, xyz]
# Requires-Dist: foo[optional]~=1.2.3 ; os_name = "posix"
# -> foo[optional] ; os_name = "posix"
#
# Currently unsupported: URL specs (foo @ https://example.com/a.zip).
_pythonRelaxDeps() {
local -r metadata_file="$1"
if [[ -z "${pythonRelaxDeps[*]-}" ]] || [[ "$pythonRelaxDeps" == 0 ]]; then
return
elif [[ "$pythonRelaxDeps" == 1 ]]; then
sed -i "$metadata_file" -r \
-e 's/(Requires-Dist: [a-zA-Z0-9_.-]+\s*(\[[^]]+\])?)[^;]*(;.*)?/\1\3/'
else
# shellcheck disable=SC2048
for dep in ${pythonRelaxDeps[*]}; do
sed -i "$metadata_file" -r \
-e "s/(Requires-Dist: $dep\s*(\[[^]]+\])?)[^;]*(;.*)?/\1\3/i"
done
fi
}
_pythonRemoveDeps() {
local -r metadata_file="$1"
if [[ -z "${pythonRemoveDeps[*]-}" ]] || [[ "$pythonRemoveDeps" == 0 ]]; then
return
elif [[ "$pythonRemoveDeps" == 1 ]]; then
sed -i "$metadata_file" \
-e '/Requires-Dist:.*/d'
else
# shellcheck disable=SC2048
for dep in ${pythonRemoveDeps[*]-}; do
sed -i "$metadata_file" \
-e "/Requires-Dist: $dep/d"
done
fi
}
pythonRelaxDepsHook() {
pushd dist
local -r unpack_dir="unpacked"
local -r metadata_file="$unpack_dir/*/*.dist-info/METADATA"
# We generally shouldn't have multiple wheel files, but let's be safer here
for wheel in *".whl"; do
PYTHONPATH="@wheel@/@pythonSitePackages@:$PYTHONPATH" \
@pythonInterpreter@ -m wheel unpack --dest "$unpack_dir" "$wheel"
rm -rf "$wheel"
# Using no quotes on purpose since we need to expand the glob from `$metadata_file`
# shellcheck disable=SC2086
_pythonRelaxDeps $metadata_file
# shellcheck disable=SC2086
_pythonRemoveDeps $metadata_file
if (("${NIX_DEBUG:-0}" >= 1)); then
echo "pythonRelaxDepsHook: resulting METADATA for '$wheel':"
# shellcheck disable=SC2086
cat $metadata_file
fi
PYTHONPATH="@wheel@/@pythonSitePackages@:$PYTHONPATH" \
@pythonInterpreter@ -m wheel pack "$unpack_dir/"*
done
# Remove the folder since it will otherwise be in the dist output.
rm -rf "$unpack_dir"
popd
}
postBuild+=" pythonRelaxDepsHook"

View File

@@ -0,0 +1,17 @@
# Setup hook for removing bytecode from the bin folder
echo "Sourcing python-remove-bin-bytecode-hook.sh"
# The bin folder is added to $PATH and should only contain executables.
# It may happen there are executables with a .py extension for which
# bytecode is generated. This hook removes that bytecode.
pythonRemoveBinBytecodePhase() {
if [ -d "$out/bin" ]; then
rm -rf "$out/bin/__pycache__" # Python 3
find "$out/bin" -type f -name "*.pyc" -delete # Python 2
fi
}
if [ -z "${dontUsePythonRemoveBinBytecode-}" ]; then
appendToVar preDistPhases pythonRemoveBinBytecodePhase
fi

View File

@@ -0,0 +1,18 @@
# Clean up top-level tests directory in site-package installation.
# shellcheck shell=bash
echo "Sourcing python-remove-tests-dir-hook"
pythonRemoveTestsDir() {
echo "Executing pythonRemoveTestsDir"
# shellcheck disable=SC2154
rm -rf "$out/@pythonSitePackages@/tests"
rm -rf "$out/@pythonSitePackages@/test"
echo "Finished executing pythonRemoveTestsDir"
}
if [ -z "${dontUsePythonRemoveTestsDir-}" ]; then
postFixupHooks+=(pythonRemoveTestsDir)
fi

View File

@@ -0,0 +1,105 @@
#!/usr/bin/env python3
"""
The runtimeDependenciesHook validates, that all dependencies specified
in wheel metadata are available in the local environment.
In case that does not hold, it will print missing dependencies and
violated version constraints.
"""
import importlib.metadata
import re
import sys
import tempfile
from argparse import ArgumentParser
from zipfile import ZipFile
from packaging.metadata import Metadata, parse_email
from packaging.requirements import Requirement
argparser = ArgumentParser()
argparser.add_argument("wheel", help="Path to the .whl file to test")
def error(msg: str) -> None:
print(f" - {msg}", file=sys.stderr)
def normalize_name(name: str) -> str:
"""
Normalize package names according to PEP503
"""
return re.sub(r"[-_.]+", "-", name).lower()
def get_manifest_text_from_wheel(wheel: str) -> str:
"""
Given a path to a wheel, this function will try to extract the
METADATA file in the wheels .dist-info directory.
"""
with ZipFile(wheel) as zipfile:
for zipinfo in zipfile.infolist():
if zipinfo.filename.endswith(".dist-info/METADATA"):
with tempfile.TemporaryDirectory() as tmp:
path = zipfile.extract(zipinfo, path=tmp)
with open(path, encoding="utf-8") as fd:
return fd.read()
raise RuntimeError("No METADATA file found in wheel")
def get_metadata(wheel: str) -> Metadata:
"""
Given a path to a wheel, returns a parsed Metadata object.
"""
text = get_manifest_text_from_wheel(wheel)
raw, _ = parse_email(text)
metadata = Metadata.from_raw(raw, validate=False)
return metadata
def test_requirement(requirement: Requirement) -> bool:
"""
Given a requirement specification, tests whether the dependency can
be resolved in the local environment, and whether it satisfies the
specified version constraints.
"""
if requirement.marker and not requirement.marker.evaluate():
# ignore requirements with incompatible markers
return True
package_name = normalize_name(requirement.name)
try:
package = importlib.metadata.distribution(requirement.name)
except importlib.metadata.PackageNotFoundError:
error(f"{package_name} not installed")
return False
# Allow prereleases, to give to give us some wiggle-room
requirement.specifier.prereleases = True
if requirement.specifier and package.version not in requirement.specifier:
error(
f"{package_name}{requirement.specifier} not satisfied by version {package.version}"
)
return False
return True
if __name__ == "__main__":
args = argparser.parse_args()
metadata = get_metadata(args.wheel)
requirements = metadata.requires_dist
if not requirements:
sys.exit(0)
tests = [test_requirement(requirement) for requirement in requirements]
if not all(tests):
sys.exit(1)

View File

@@ -0,0 +1,20 @@
# Setup hook for PyPA installer.
echo "Sourcing python-runtime-deps-check-hook"
pythonRuntimeDepsCheckHook() {
echo "Executing pythonRuntimeDepsCheck"
export PYTHONPATH="$out/@pythonSitePackages@:$PYTHONPATH"
for wheel in dist/*.whl; do
echo "Checking runtime dependencies for $(basename $wheel)"
@pythonInterpreter@ @hook@ "$wheel"
done
echo "Finished executing pythonRuntimeDepsCheck"
}
if [ -z "${dontCheckRuntimeDeps-}" ]; then
echo "Using pythonRuntimeDepsCheckHook"
appendToVar preInstallPhases pythonRuntimeDepsCheckHook
fi

View File

@@ -0,0 +1,35 @@
# Setup hook for setuptools.
# shellcheck shell=bash
echo "Sourcing setuptools-build-hook"
setuptoolsBuildPhase() {
echo "Executing setuptoolsBuildPhase"
local setuptools_has_parallel=@setuptools_has_parallel@
runHook preBuild
cp -f @setuppy@ nix_run_setup
local -a flagsArray=()
if [ -n "${setupPyGlobalFlags[*]-}" ]; then
concatTo flagsArray setupPyGlobalFlags
fi
if [ -n "$enableParallelBuilding" ]; then
if [ -n "$setuptools_has_parallel" ]; then
appendToVar setupPyBuildFlags --parallel "$NIX_BUILD_CORES"
fi
fi
if [ -n "${setupPyBuildFlags[*]-}" ]; then
flagsArray+=(build_ext)
concatTo flagsArray setupPyBuildFlags
fi
echoCmd 'setup.py build flags' "${flagsArray[@]}"
@pythonInterpreter@ nix_run_setup "${flagsArray[@]}" bdist_wheel
runHook postBuild
echo "Finished executing setuptoolsBuildPhase"
}
if [ -z "${dontUseSetuptoolsBuild-}" ] && [ -z "${buildPhase-}" ]; then
echo "Using setuptoolsBuildPhase"
buildPhase=setuptoolsBuildPhase
fi

View File

@@ -0,0 +1,20 @@
# shellcheck shell=bash
echo "Sourcing setuptools-rust-hook"
setuptoolsRustSetup() {
# This can work only if rustPlatform.cargoSetupHook is also included
if ! command -v cargoSetupPostPatchHook >/dev/null; then
echo "ERROR: setuptools-rust has to be used alongside with rustPlatform.cargoSetupHook!"
exit 1
fi
export PYO3_CROSS_LIB_DIR="@pyLibDir@"
export CARGO_BUILD_TARGET=@cargoBuildTarget@
# TODO theoretically setting linker should not be required because it is
# already set in pkgs/build-support/rust/hooks/default.nix but build fails
# on missing linker without this.
export CARGO_TARGET_@cargoLinkerVar@_LINKER=@targetLinker@
}
preConfigureHooks+=(setuptoolsRustSetup)

View File

@@ -0,0 +1,72 @@
# shellcheck shell=bash
echo "Sourcing sphinx-hook"
declare -a __sphinxBuilders
buildSphinxPhase() {
echo "Executing buildSphinxPhase"
local __sphinxRoot=""
runHook preBuildSphinx
if [[ -n "${sphinxRoot:-}" ]]; then # explicit root
if ! [[ -f "${sphinxRoot}/conf.py" ]]; then
echo 2>&1 "$sphinxRoot/conf.py: no such file"
exit 1
fi
__sphinxRoot=$sphinxRoot
else
for candidate in doc docs doc/source docs/source; do
if [[ -f "$candidate/conf.py" ]]; then
echo "Sphinx documentation found in $candidate"
__sphinxRoot=$candidate
break
fi
done
fi
if [[ -z "${__sphinxRoot}" ]]; then
echo 2>&1 "Sphinx documentation not found, use 'sphinxRoot' variable"
exit 1
fi
if [ -n "${sphinxBuilders-}" ]; then
eval "__sphinxBuilders=($sphinxBuilders)"
else
__sphinxBuilders=(html)
fi
for __builder in "${__sphinxBuilders[@]}"; do
echo "Executing sphinx-build with ${__builder} builder"
@sphinxBuild@ -M "${__builder}" "${__sphinxRoot}" ".sphinx/${__builder}" -v
done
runHook postBuildSphinx
}
installSphinxPhase() {
echo "Executing installSphinxPhase"
local docdir=""
runHook preInstallSphinx
for __builder in "${__sphinxBuilders[@]}"; do
# divert output for man builder
if [ "$__builder" == "man" ]; then
installManPage .sphinx/man/man/*
else
# shellcheck disable=2154
docdir="${doc:-$out}/share/doc/${name}"
mkdir -p "$docdir"
cp -r ".sphinx/${__builder}/${__builder}" "$docdir/"
rm -fr "${docdir}/${__builder}/_sources" "${docdir}/${__builder}/.buildinfo"
fi
done
runHook postInstallSphinx
}
appendToVar preFixupPhases buildSphinxPhase installSphinxPhase

View File

@@ -0,0 +1,26 @@
# Setup hook for unittest.
# shellcheck shell=bash
echo "Sourcing unittest-check-hook"
unittestCheckPhase() {
echo "Executing unittestCheckPhase"
runHook preCheck
local -a flagsArray=()
# Compatibility layer to the obsolete unittestFlagsArray
eval "flagsArray+=(${unittestFlagsArray[*]-})"
concatTo flagsArray unittestFlags
echoCmd 'unittest flags' "${flagsArray[@]}"
@pythonCheckInterpreter@ -m unittest discover "${flagsArray[@]}"
runHook postCheck
echo "Finished executing unittestCheckPhase"
}
if [[ -z "${dontUseUnittestCheck-}" ]] && [[ -z "${installCheckPhase-}" ]]; then
echo "Using unittestCheckPhase"
appendToVar preDistPhases unittestCheckPhase
fi

View File

@@ -0,0 +1,28 @@
venvShellHook() {
echo "Executing venvHook"
runHook preShellHook
if [ -d "${venvDir}" ]; then
echo "Skipping venv creation, '${venvDir}' already exists"
source "${venvDir}/bin/activate"
else
echo "Creating new venv environment in path: '${venvDir}'"
@pythonInterpreter@ -m venv "${venvDir}"
source "${venvDir}/bin/activate"
runHook postVenvCreation
fi
runHook postShellHook
echo "Finished executing venvShellHook"
}
if [ -z "${dontUseVenvShellHook:-}" ] && [ -z "${shellHook-}" ]; then
echo "Using venvShellHook"
if [ -z "${venvDir-}" ]; then
echo "Error: \`venvDir\` should be set when using \`venvShellHook\`."
exit 1
else
shellHook=venvShellHook
fi
fi

View File

@@ -0,0 +1,18 @@
# Setup hook to use in case a wheel is fetched
echo "Sourcing wheel setup hook"
wheelUnpackPhase() {
echo "Executing wheelUnpackPhase"
runHook preUnpack
mkdir -p dist
cp "$src" "dist/$(stripHash "$src")"
# runHook postUnpack # Calls find...?
echo "Finished executing wheelUnpackPhase"
}
if [ -z "${dontUseWheelUnpack-}" ] && [ -z "${unpackPhase-}" ]; then
echo "Using wheelUnpackPhase"
unpackPhase=wheelUnpackPhase
fi

View File

@@ -0,0 +1,100 @@
{ lib, pkgs }:
let
# Create a derivation that links all desired manylinux libraries
createManyLinuxPackage =
name: libs:
let
drvs = lib.unique (lib.attrValues libs);
names = lib.attrNames libs;
in
pkgs.runCommand name
{
buildInputs = drvs;
}
''
mkdir -p $out/lib
num_found=0
IFS=:
export DESIRED_LIBRARIES=${lib.concatStringsSep ":" names}
export LIBRARY_PATH=${lib.makeLibraryPath drvs}
for desired in $DESIRED_LIBRARIES; do
for path in $LIBRARY_PATH; do
if [ -e $path/$desired ]; then
echo "FOUND $path/$desired"
ln -s $path/$desired $out/lib/$desired
num_found=$((num_found+1))
break
fi
done
done
num_desired=${toString (lib.length names)}
echo "Found $num_found of $num_desired libraries"
if [ "$num_found" -ne "$num_desired" ]; then
echo "Error: not all desired libraries were found"
exit 1
fi
'';
getLibOutputs = lib.mapAttrs (k: v: lib.getLib v);
# https://www.python.org/dev/peps/pep-0599/
manylinux2014Libs = getLibOutputs (
with pkgs;
{
"libgcc_s.so.1" = glibc;
"libstdc++.so.6" = stdenv.cc.cc;
"libm.so.6" = glibc;
"libdl.so.2" = glibc;
"librt.so.1" = glibc;
"libc.so.6" = glibc;
"libnsl.so.1" = glibc;
"libutil.so.1" = glibc;
"libpthread.so.0" = glibc;
"libresolv.so.2" = glibc;
"libX11.so.6" = xorg.libX11;
"libXext.so.6" = xorg.libXext;
"libXrender.so.1" = xorg.libXrender;
"libICE.so.6" = xorg.libICE;
"libSM.so.6" = xorg.libSM;
"libGL.so.1" = libGL;
"libgobject-2.0.so.0" = glib;
"libgthread-2.0.so.0" = glib;
"libglib-2.0.so.0" = glib;
"libz.so.1" = zlib;
"libexpat.so.1" = expat;
}
);
# https://www.python.org/dev/peps/pep-0571/
manylinux2010Libs = manylinux2014Libs;
# https://www.python.org/dev/peps/pep-0513/
manylinux1Libs = getLibOutputs (
manylinux2010Libs
// (with pkgs; {
"libpanelw.so.5" = ncurses5;
"libncursesw.so.5" = ncurses5;
"libcrypt.so.1" = libxcrypt;
})
);
in
{
# List of libraries that are needed for manylinux compatibility.
# When using a wheel that is manylinux1 compatible, just extend
# the `buildInputs` with one of these `manylinux` lists.
# Additionally, add `autoPatchelfHook` to `nativeBuildInputs`.
manylinux1 = lib.unique (lib.attrValues manylinux1Libs);
manylinux2010 = lib.unique (lib.attrValues manylinux2010Libs);
manylinux2014 = lib.unique (lib.attrValues manylinux2014Libs);
# These are symlink trees to the relevant libs and are typically not needed
# These exist so as to quickly test whether all required libraries are provided
# by the mapped packages.
manylinux1Package = createManyLinuxPackage "manylinux1" manylinux1Libs;
manylinux2010Package = createManyLinuxPackage "manylinux2010" manylinux2010Libs;
manylinux2014Package = createManyLinuxPackage "manylinux2014" manylinux2014Libs;
}

View File

@@ -0,0 +1,58 @@
{
buildPythonPackage,
lib,
hatchling,
}:
{
pname,
version,
dependencies ? [ ],
optional-dependencies ? { },
passthru ? { },
meta ? { },
}:
# Create a "fake" meta package to satisfy a dependency on a package, but don't actually build it.
# This is useful for packages that have a split binary/source dichotomy like psycopg2/psycopg2-binary,
# where we want to use the former, but some projects declare a dependency on the latter.
buildPythonPackage {
inherit
pname
version
dependencies
optional-dependencies
meta
passthru
;
pyproject = true;
# Make a minimal pyproject.toml that can be built
unpackPhase = ''
cat > pyproject.toml << EOF
[project]
name = "${pname}"
version = "${version}"
dependencies = ${builtins.toJSON (map lib.getName dependencies)}
[project.optional-dependencies]
${lib.optionalString (optional-dependencies != { }) (
lib.concatStringsSep "\n" (
lib.mapAttrsToList (
group: deps: group + " = " + builtins.toJSON (map lib.getName deps)
) optional-dependencies
)
)}
[tool.hatch.build.targets.wheel]
bypass-selection = true
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
EOF
'';
build-system = [ hatchling ];
}

View File

@@ -0,0 +1,476 @@
# Generic builder.
{
lib,
config,
python,
wrapPython,
unzip,
ensureNewerSourcesForZipFilesHook,
# Whether the derivation provides a Python module or not.
toPythonModule,
namePrefix,
nix-update-script,
setuptools,
pypaBuildHook,
pypaInstallHook,
pythonCatchConflictsHook,
pythonImportsCheckHook,
pythonNamespacesHook,
pythonOutputDistHook,
pythonRelaxDepsHook,
pythonRemoveBinBytecodeHook,
pythonRemoveTestsDirHook,
pythonRuntimeDepsCheckHook,
setuptoolsBuildHook,
wheelUnpackHook,
eggUnpackHook,
eggBuildHook,
eggInstallHook,
}:
let
inherit (builtins) unsafeGetAttrPos;
inherit (lib)
elem
extendDerivation
fixedWidthString
flip
getName
hasSuffix
head
isBool
max
optional
optionalAttrs
optionals
optionalString
removePrefix
splitString
stringLength
;
getOptionalAttrs =
names: attrs: lib.getAttrs (lib.intersectLists names (lib.attrNames attrs)) attrs;
leftPadName =
name: against:
let
len = max (stringLength name) (stringLength against);
in
fixedWidthString len " " name;
isPythonModule =
drv:
# all pythonModules have the pythonModule attribute
(drv ? "pythonModule")
# Some pythonModules are turned in to a pythonApplication by setting the field to false
&& (!isBool drv.pythonModule);
isMismatchedPython = drv: drv.pythonModule != python;
withDistOutput' = flip elem [
"pyproject"
"setuptools"
"wheel"
];
isBootstrapInstallPackage' = flip elem [
"flit-core"
"installer"
];
isBootstrapPackage' = flip elem (
[
"build"
"packaging"
"pyproject-hooks"
"wheel"
]
++ optionals (python.pythonOlder "3.11") [
"tomli"
]
);
isSetuptoolsDependency' = flip elem [
"setuptools"
"wheel"
];
cleanAttrs = flip removeAttrs [
"disabled"
"checkPhase"
"checkInputs"
"nativeCheckInputs"
"doCheck"
"doInstallCheck"
"pyproject"
"format"
"stdenv"
"dependencies"
"optional-dependencies"
"build-system"
];
in
{
# Build-time dependencies for the package
nativeBuildInputs ? [ ],
# Run-time dependencies for the package
buildInputs ? [ ],
# Dependencies needed for running the checkPhase.
# These are added to buildInputs when doCheck = true.
checkInputs ? [ ],
nativeCheckInputs ? [ ],
# propagate build dependencies so in case we have A -> B -> C,
# C can import package A propagated by B
propagatedBuildInputs ? [ ],
# Python module dependencies.
# These are named after PEP-621.
dependencies ? [ ],
optional-dependencies ? { },
# Python PEP-517 build systems.
build-system ? [ ],
# DEPRECATED: use propagatedBuildInputs
pythonPath ? [ ],
# Enabled to detect some (native)BuildInputs mistakes
strictDeps ? true,
outputs ? [ "out" ],
# used to disable derivation, useful for specific python versions
disabled ? false,
# Raise an error if two packages are installed with the same name
# TODO: For cross we probably need a different PYTHONPATH, or not
# add the runtime deps until after buildPhase.
catchConflicts ? (python.stdenv.hostPlatform == python.stdenv.buildPlatform),
# Additional arguments to pass to the makeWrapper function, which wraps
# generated binaries.
makeWrapperArgs ? [ ],
# Skip wrapping of python programs altogether
dontWrapPythonPrograms ? false,
# Don't use Pip to install a wheel
# Note this is actually a variable for the pipInstallPhase in pip's setupHook.
# It's included here to prevent an infinite recursion.
dontUsePipInstall ? false,
# Skip setting the PYTHONNOUSERSITE environment variable in wrapped programs
permitUserSite ? false,
# Remove bytecode from bin folder.
# When a Python script has the extension `.py`, bytecode is generated
# Typically, executables in bin have no extension, so no bytecode is generated.
# However, some packages do provide executables with extensions, and thus bytecode is generated.
removeBinBytecode ? true,
# pyproject = true <-> format = "pyproject"
# pyproject = false <-> format = "other"
# https://github.com/NixOS/nixpkgs/issues/253154
pyproject ? null,
# Several package formats are supported.
# "setuptools" : Install a common setuptools/distutils based package. This builds a wheel.
# "wheel" : Install from a pre-compiled wheel.
# "pyproject": Install a package using a ``pyproject.toml`` file (PEP517). This builds a wheel.
# "egg": Install a package from an egg.
# "other" : Provide your own buildPhase and installPhase.
format ? null,
meta ? { },
doCheck ? true,
# Allow passing in a custom stdenv to buildPython*
stdenv ? python.stdenv,
...
}@attrs:
let
# Keep extra attributes from `attrs`, e.g., `patchPhase', etc.
self = stdenv.mkDerivation (
finalAttrs:
let
getFinalPassthru =
let
pos = unsafeGetAttrPos "passthru" finalAttrs;
in
attrName:
finalAttrs.passthru.${attrName} or (throw (
''
${finalAttrs.name}: passthru.${attrName} missing after overrideAttrs overriding.
''
+ optionalString (pos != null) ''
Last overridden at ${pos.file}:${toString pos.line}
''
));
format' =
assert (getFinalPassthru "pyproject" != null) -> (format == null);
if getFinalPassthru "pyproject" != null then
if getFinalPassthru "pyproject" then "pyproject" else "other"
else if format != null then
format
else
throw "${name} does not configure a `format`. To build with setuptools as before, set `pyproject = true` and `build-system = [ setuptools ]`.`";
withDistOutput = withDistOutput' format';
validatePythonMatches =
let
throwMismatch =
attrName: drv:
let
myName = "'${finalAttrs.name}'";
theirName = "'${drv.name}'";
optionalLocation =
let
pos = unsafeGetAttrPos (if attrs ? "pname" then "pname" else "name") attrs;
in
optionalString (pos != null) " at ${pos.file}:${toString pos.line}:${toString pos.column}";
in
throw ''
Python version mismatch in ${myName}:
The Python derivation ${myName} depends on a Python derivation
named ${theirName}, but the two derivations use different versions
of Python:
${leftPadName myName theirName} uses ${python}
${leftPadName theirName myName} uses ${toString drv.pythonModule}
Possible solutions:
* If ${theirName} is a Python library, change the reference to ${theirName}
in the ${attrName} of ${myName} to use a ${theirName} built from the same
version of Python
* If ${theirName} is used as a tool during the build, move the reference to
${theirName} in ${myName} from ${attrName} to nativeBuildInputs
* If ${theirName} provides executables that are called at run time, pass its
bin path to makeWrapperArgs:
makeWrapperArgs = [ "--prefix PATH : ''${lib.makeBinPath [ ${getName drv} ] }" ];
${optionalLocation}
'';
checkDrv =
attrName: drv:
if (isPythonModule drv) && (isMismatchedPython drv) then throwMismatch attrName drv else drv;
in
attrName: inputs: map (checkDrv attrName) inputs;
isBootstrapInstallPackage = isBootstrapInstallPackage' (finalAttrs.pname or null);
isBootstrapPackage = isBootstrapInstallPackage || isBootstrapPackage' (finalAttrs.pname or null);
isSetuptoolsDependency = isSetuptoolsDependency' (finalAttrs.pname or null);
name = namePrefix + attrs.name or "${finalAttrs.pname}-${finalAttrs.version}";
in
(cleanAttrs attrs)
// {
inherit name;
inherit catchConflicts;
nativeBuildInputs = [
python
wrapPython
ensureNewerSourcesForZipFilesHook # move to wheel installer (pip) or builder (setuptools, flit, ...)?
pythonRemoveTestsDirHook
]
++ optionals (finalAttrs.catchConflicts && !isBootstrapPackage && !isSetuptoolsDependency) [
#
# 1. When building a package that is also part of the bootstrap chain, we
# must ignore conflicts after installation, because there will be one with
# the package in the bootstrap.
#
# 2. When a package is a dependency of setuptools, we must ignore conflicts
# because the hook that checks for conflicts uses setuptools.
#
pythonCatchConflictsHook
]
++
optionals (finalAttrs.pythonRelaxDeps or [ ] != [ ] || finalAttrs.pythonRemoveDeps or [ ] != [ ])
[
pythonRelaxDepsHook
]
++ optionals removeBinBytecode [
pythonRemoveBinBytecodeHook
]
++ optionals (hasSuffix "zip" (finalAttrs.src.name or "")) [
unzip
]
++ optionals (format' == "setuptools") [
setuptoolsBuildHook
]
++ optionals (format' == "pyproject") [
(
if isBootstrapPackage then
pypaBuildHook.override {
inherit (python.pythonOnBuildForHost.pkgs.bootstrap) build;
wheel = null;
}
else
pypaBuildHook
)
(
if isBootstrapPackage then
pythonRuntimeDepsCheckHook.override {
inherit (python.pythonOnBuildForHost.pkgs.bootstrap) packaging;
}
else
pythonRuntimeDepsCheckHook
)
]
++ optionals (format' == "wheel") [
wheelUnpackHook
]
++ optionals (format' == "egg") [
eggUnpackHook
eggBuildHook
eggInstallHook
]
++ optionals (format' != "other") [
(
if isBootstrapInstallPackage then
pypaInstallHook.override {
inherit (python.pythonOnBuildForHost.pkgs.bootstrap) installer;
}
else
pypaInstallHook
)
]
++ optionals (stdenv.buildPlatform == stdenv.hostPlatform) [
# This is a test, however, it should be ran independent of the checkPhase and checkInputs
pythonImportsCheckHook
]
++ optionals (python.pythonAtLeast "3.3") [
# Optionally enforce PEP420 for python3
pythonNamespacesHook
]
++ optionals withDistOutput [
pythonOutputDistHook
]
++ nativeBuildInputs
++ getFinalPassthru "build-system";
buildInputs = validatePythonMatches "buildInputs" (buildInputs ++ pythonPath);
propagatedBuildInputs = validatePythonMatches "propagatedBuildInputs" (
propagatedBuildInputs
++ getFinalPassthru "dependencies"
++ [
# we propagate python even for packages transformed with 'toPythonApplication'
# this pollutes the PATH but avoids rebuilds
# see https://github.com/NixOS/nixpkgs/issues/170887 for more context
python
]
);
inherit strictDeps;
LANG = "${if python.stdenv.hostPlatform.isDarwin then "en_US" else "C"}.UTF-8";
# Python packages don't have a checkPhase, only an installCheckPhase
doCheck = false;
doInstallCheck = attrs.doCheck or true;
nativeInstallCheckInputs = nativeCheckInputs ++ attrs.nativeInstallCheckInputs or [ ];
installCheckInputs = checkInputs ++ attrs.installCheckInputs or [ ];
inherit dontWrapPythonPrograms;
postFixup =
optionalString (!finalAttrs.dontWrapPythonPrograms) ''
wrapPythonPrograms
''
+ attrs.postFixup or "";
# Python packages built through cross-compilation are always for the host platform.
disallowedReferences = optionals (python.stdenv.hostPlatform != python.stdenv.buildPlatform) [
python.pythonOnBuildForHost
];
outputs = outputs ++ optional withDistOutput "dist";
passthru = {
inherit
disabled
pyproject
build-system
dependencies
optional-dependencies
;
}
// {
updateScript = nix-update-script { };
}
// attrs.passthru or { };
meta = {
# default to python's platforms
platforms = python.meta.platforms;
isBuildPythonPackage = python.meta.platforms;
}
// meta;
}
// optionalAttrs (attrs ? checkPhase) {
# If given use the specified checkPhase, otherwise use the setup hook.
# Longer-term we should get rid of `checkPhase` and use `installCheckPhase`.
installCheckPhase = attrs.checkPhase;
}
//
lib.mapAttrs
(
name: value:
lib.throwIf (
attrs.${name} == [ ]
) "${lib.getName finalAttrs}: ${name} must be unspecified, null or a non-empty list." attrs.${name}
)
(
getOptionalAttrs [
"enabledTestMarks"
"enabledTestPaths"
"enabledTests"
] attrs
)
);
# This derivation transformation function must be independent to `attrs`
# for fixed-point arguments support in the future.
transformDrv =
let
# Workaround to make the `lib.extendDerivation`-based disabled functionality
# respect `<pkg>.overrideAttrs`
# It doesn't cover `<pkg>.<output>.overrideAttrs`.
disablePythonPackage =
drv:
extendDerivation (
drv.disabled
-> throw "${removePrefix namePrefix drv.name} not supported for interpreter ${python.executable}"
) { } drv
// {
overrideAttrs = fdrv: disablePythonPackage (drv.overrideAttrs fdrv);
};
in
drv: disablePythonPackage (toPythonModule drv);
in
transformDrv self

View File

@@ -0,0 +1,152 @@
{
lib,
stdenv,
callPackage,
pythonPackagesExtensions,
config,
makeScopeWithSplicing',
...
}:
{
implementation,
libPrefix,
executable,
sourceVersion,
pythonVersion,
packageOverrides,
sitePackages,
hasDistutilsCxxPatch,
pythonOnBuildForBuild,
pythonOnBuildForHost,
pythonOnBuildForTarget,
pythonOnHostForHost,
pythonOnTargetForTarget,
pythonAttr ? null,
pythonABITags ? [ "none" ],
self, # is pythonOnHostForTarget
}:
let
pythonPackages =
let
ensurePythonModules =
items:
let
exceptions = [
stdenv
];
providesSetupHook = lib.attrByPath [ "provides" "setupHook" ] false;
valid =
value: pythonPackages.hasPythonModule value || providesSetupHook value || lib.elem value exceptions;
func =
name: value:
if lib.isDerivation value then
lib.extendDerivation (
valid value
|| throw "${name} should use `buildPythonPackage` or `toPythonModule` if it is to be part of the Python packages set."
) { } value
else
value;
in
lib.mapAttrs func items;
in
ensurePythonModules (
callPackage
# Function that when called
# - imports python-packages.nix
# - adds spliced package sets to the package set
# - applies overrides from `packageOverrides` and `pythonPackagesOverlays`.
(
{
pkgs,
stdenv,
python,
overrides,
}:
let
pythonPackagesFun = import ./python-packages-base.nix {
inherit stdenv pkgs lib;
python = self;
};
otherSplices = {
selfBuildBuild = pythonOnBuildForBuild.pkgs;
selfBuildHost = pythonOnBuildForHost.pkgs;
selfBuildTarget = pythonOnBuildForTarget.pkgs;
selfHostHost = pythonOnHostForHost.pkgs;
selfTargetTarget = pythonOnTargetForTarget.pkgs or { }; # There is no Python TargetTarget.
};
hooks = import ./hooks/default.nix;
keep = self: hooks self { };
optionalExtensions = cond: as: lib.optionals cond as;
pythonExtension = import ../../../top-level/python-packages.nix;
python2Extension = import ../../../top-level/python2-packages.nix;
extensions = lib.composeManyExtensions (
[
hooks
pythonExtension
]
++ (optionalExtensions (!self.isPy3k) [
python2Extension
])
++ pythonPackagesExtensions
++ [
overrides
]
);
aliases =
self: super:
lib.optionalAttrs config.allowAliases (import ../../../top-level/python-aliases.nix lib self super);
in
makeScopeWithSplicing' {
inherit otherSplices keep;
f = lib.extends (lib.composeExtensions aliases extensions) pythonPackagesFun;
}
)
{
overrides = packageOverrides;
python = self;
}
);
in
rec {
isPy27 = pythonVersion == "2.7";
isPy37 = pythonVersion == "3.7";
isPy38 = pythonVersion == "3.8";
isPy39 = pythonVersion == "3.9";
isPy310 = pythonVersion == "3.10";
isPy311 = pythonVersion == "3.11";
isPy312 = pythonVersion == "3.12";
isPy313 = pythonVersion == "3.13";
isPy314 = pythonVersion == "3.14";
isPy2 = lib.strings.substring 0 1 pythonVersion == "2";
isPy3 = lib.strings.substring 0 1 pythonVersion == "3";
isPy3k = isPy3;
isPyPy = lib.hasInfix "pypy" interpreter;
buildEnv = callPackage ./wrapper.nix {
python = self;
inherit (pythonPackages) requiredPythonModules;
};
withPackages = import ./with-packages.nix { inherit buildEnv pythonPackages; };
pkgs = pythonPackages;
interpreter = "${self}/bin/${executable}";
inherit
executable
implementation
libPrefix
pythonVersion
sitePackages
;
inherit sourceVersion;
pythonAtLeast = lib.versionAtLeast pythonVersion;
pythonOlder = lib.versionOlder pythonVersion;
inherit hasDistutilsCxxPatch;
inherit pythonOnBuildForHost;
inherit pythonABITags;
tests = callPackage ./tests.nix {
python = self;
};
inherit pythonAttr;
}

View File

@@ -0,0 +1,411 @@
{
lib,
stdenv,
replaceVars,
fetchurl,
autoconf,
zlibSupport ? true,
zlib,
bzip2,
pkg-config,
lndir,
libffi,
sqlite,
openssl,
ncurses,
python,
expat,
tcl,
tk,
tclPackages,
libX11,
gdbm,
db,
xz,
python-setup-hook,
optimizationLevel ? "jit",
boehmgc,
# For the Python package set
hash,
self,
packageOverrides ? (self: super: { }),
pkgsBuildBuild,
pkgsBuildHost,
pkgsBuildTarget,
pkgsHostHost,
pkgsTargetTarget,
sourceVersion,
pythonVersion,
passthruFun,
pythonAttr ? "pypy${lib.substring 0 1 pythonVersion}${lib.substring 2 3 pythonVersion}",
}:
assert zlibSupport -> zlib != null;
let
isPy3k = (lib.versions.major pythonVersion) == "3";
isPy38OrNewer = lib.versionAtLeast pythonVersion "3.8";
isPy39OrNewer = lib.versionAtLeast pythonVersion "3.9";
passthru = passthruFun rec {
inherit
self
sourceVersion
pythonVersion
packageOverrides
;
implementation = "pypy";
libPrefix = "pypy${pythonVersion}";
executable = "pypy${
if isPy39OrNewer then lib.versions.majorMinor pythonVersion else lib.optionalString isPy3k "3"
}";
sitePackages = "${lib.optionalString isPy38OrNewer "lib/${libPrefix}/"}site-packages";
hasDistutilsCxxPatch = false;
inherit pythonAttr;
pythonOnBuildForBuild = pkgsBuildBuild.${pythonAttr};
pythonOnBuildForHost = pkgsBuildHost.${pythonAttr};
pythonOnBuildForTarget = pkgsBuildTarget.${pythonAttr};
pythonOnHostForHost = pkgsHostHost.${pythonAttr};
pythonOnTargetForTarget = pkgsTargetTarget.${pythonAttr} or { };
pythonABITags = [
"none"
"pypy${lib.concatStrings (lib.take 2 (lib.splitString "." pythonVersion))}_pp${sourceVersion.major}${sourceVersion.minor}"
];
};
pname = passthru.executable;
version = with sourceVersion; "${major}.${minor}.${patch}";
pythonForPypy = python.withPackages (ppkgs: [ ]);
in
with passthru;
stdenv.mkDerivation rec {
inherit pname version;
src = fetchurl {
url = "https://downloads.python.org/pypy/pypy${pythonVersion}-v${version}-src.tar.bz2";
inherit hash;
};
nativeBuildInputs = [
pkg-config
lndir
];
buildInputs = [
bzip2
openssl
pythonForPypy
libffi
ncurses
expat
sqlite
tk
tcl
libX11
gdbm
db
]
++ lib.optionals isPy3k [
xz
]
++ lib.optionals (stdenv ? cc && stdenv.cc.libc != null) [
stdenv.cc.libc
]
++ lib.optionals zlibSupport [
zlib
]
++
lib.optionals
(lib.any (l: l == optimizationLevel) [
"0"
"1"
"2"
"3"
])
[
boehmgc
];
# Remove bootstrap python from closure
dontPatchShebangs = true;
disallowedReferences = [ python ];
env =
lib.optionalAttrs stdenv.cc.isClang {
# fix compiler error in curses cffi module, where char* != const char*
NIX_CFLAGS_COMPILE = "-Wno-error=incompatible-function-pointer-types";
}
// {
C_INCLUDE_PATH = lib.makeSearchPathOutput "dev" "include" buildInputs;
LIBRARY_PATH = lib.makeLibraryPath buildInputs;
LD_LIBRARY_PATH = lib.makeLibraryPath (
builtins.filter (x: x.outPath != stdenv.cc.libc.outPath or "") buildInputs
);
};
patches = [
./dont_fetch_vendored_deps.patch
(replaceVars ./tk_tcl_paths.patch {
inherit tk tcl;
tk_dev = tk.dev;
tcl_dev = tcl;
tk_libprefix = tk.libPrefix;
tcl_libprefix = tcl.libPrefix;
})
# Python ctypes.util uses three different strategies to find a library (on Linux):
# 1. /sbin/ldconfig
# 2. cc -Wl,-t -l"$libname"; objdump -p
# 3. ld -t (where it attaches the values in $LD_LIBRARY_PATH as -L arguments)
# The first is disabled in Nix (and wouldn't work in the build sandbox or on NixOS anyway), and
# the third was only introduced in Python 3.6 (see bugs.python.org/issue9998), so is not
# available when building PyPy (which is built using Python/PyPy 2.7).
# The second requires SONAME to be set for the dynamic library for the second part not to fail.
# As libsqlite3 stopped shipping with SONAME after the switch to autosetup (>= 3.50 in Nixpkgs;
# see https://www.sqlite.org/src/forumpost/5a3b44f510df8ded). This makes the Python CFFI module
# unable to find the SQLite library.
# To circumvent these issues, we hardcode the path during build.
# For more information, see https://github.com/NixOS/nixpkgs/issues/419942.
(replaceVars (if isPy3k then ./sqlite_paths.patch else ./sqlite_paths_2_7.patch) {
inherit (sqlite) out dev;
libsqlite = "${sqlite.out}/lib/libsqlite3${stdenv.hostPlatform.extensions.sharedLibrary}";
})
];
postPatch = ''
substituteInPlace lib_pypy/pypy_tools/build_cffi_imports.py \
--replace "multiprocessing.cpu_count()" "$NIX_BUILD_CORES"
substituteInPlace "lib-python/${if isPy3k then "3/tkinter/tix.py" else "2.7/lib-tk/Tix.py"}" \
--replace "os.environ.get('TIX_LIBRARY')" "os.environ.get('TIX_LIBRARY') or '${tclPackages.tix}/lib'"
'';
buildPhase = ''
runHook preBuild
${pythonForPypy.interpreter} rpython/bin/rpython \
--make-jobs="$NIX_BUILD_CORES" \
-O${optimizationLevel} \
--batch \
pypy/goal/targetpypystandalone.py \
${lib.optionalString ((toString optimizationLevel) == "1") "--withoutmod-cpyext"}
runHook postBuild
'';
installPhase = ''
runHook preInstall
mkdir -p $out/{bin,lib/${libPrefix}}
cp -R {include,lib_pypy,lib-python} $out
install -Dm755 lib${executable}-c${stdenv.hostPlatform.extensions.sharedLibrary} $out/lib/
install -Dm755 ${executable}-c $out/bin/${executable}
${lib.optionalString isPy39OrNewer "ln -s $out/bin/${executable} $out/bin/pypy3"}
# other packages expect to find stuff according to libPrefix
ln -s $out/include $out/include/${libPrefix}
lndir $out/lib-python/${if isPy3k then "3" else pythonVersion} $out/lib/${libPrefix}
lndir $out/lib_pypy $out/lib/${libPrefix}
# Include a sitecustomize.py file
cp ${../sitecustomize.py} $out/${
if isPy38OrNewer then sitePackages else "lib/${libPrefix}/${sitePackages}"
}/sitecustomize.py
runHook postInstall
'';
preFixup =
lib.optionalString (stdenv.hostPlatform.isDarwin) ''
install_name_tool -change @rpath/lib${executable}-c.dylib $out/lib/lib${executable}-c.dylib $out/bin/${executable}
''
# Create platform specific _sysconfigdata__*.py (eg: _sysconfigdata__linux_x86_64-linux-gnu.py)
# Can be tested by building: pypy3Packages.bcrypt
# Based on the upstream build code found here:
# https://github.com/pypy/pypy/blob/release-pypy3.11-v7.3.20/pypy/tool/release/package.py#L176-L189
# Upstream is not shipping config.guess, just take one from autoconf
+ lib.optionalString isPy3k ''
$out/bin/pypy3 -m sysconfig --generate-posix-vars HOST_GNU_TYPE "$(${autoconf}/share/autoconf/build-aux/config.guess)"
buildir="$(cat pybuilddir.txt)"
quadruplet=$(ls $buildir | sed -E 's/_sysconfigdata__(.*).py/\1/')
cp "$buildir/_sysconfigdata__$quadruplet.py" $out/lib_pypy/
ln -rs "$out/lib_pypy/_sysconfigdata__$quadruplet.py" $out/lib/pypy*/
''
# _testcapi is compiled dynamically, into the store.
# This would fail if we don't do it here.
+ lib.optionalString (stdenv.buildPlatform.canExecute stdenv.hostPlatform) ''
pushd /
$out/bin/${executable} -c "from test import support"
popd
'';
setupHook = python-setup-hook sitePackages;
# TODO: Investigate why so many tests are failing.
checkPhase =
let
disabledTests = [
# disable shutils because it assumes gid 0 exists
"test_shutil"
# disable socket because it has two actual network tests that fail
"test_socket"
]
++ lib.optionals (!isPy3k) [
# disable test_urllib2net, test_urllib2_localnet, and test_urllibnet because they require networking (example.com)
"test_urllib2net"
"test_urllibnet"
"test_urllib2_localnet"
# test_subclass fails with "internal error"
# test_load_default_certs_env fails for unknown reason
"test_ssl"
]
++ lib.optionals isPy3k [
# disable asyncio due to https://github.com/NixOS/nix/issues/1238
"test_asyncio"
# disable os due to https://github.com/NixOS/nixpkgs/issues/10496
"test_os"
# disable pathlib due to https://bitbucket.org/pypy/pypy/pull-requests/594
"test_pathlib"
# disable tarfile because it assumes gid 0 exists
"test_tarfile"
# disable __all__ because of spurious imp/importlib warning and
# warning-to-error test policy
"test___all__"
# fail for multiple reasons, TODO: investigate
"test__opcode"
"test_ast"
"test_audit"
"test_builtin"
"test_c_locale_coercion"
"test_call"
"test_class"
"test_cmd_line"
"test_cmd_line_script"
"test_code"
"test_code_module"
"test_codeop"
"test_compile"
"test_coroutines"
"test_cprofile"
"test_ctypes"
"test_embed"
"test_exceptions"
"test_extcall"
"test_frame"
"test_generators"
"test_grammar"
"test_idle"
"test_iter"
"test_itertools"
"test_list"
"test_marshal"
"test_memoryio"
"test_memoryview"
"test_metaclass"
"test_mmap"
"test_multibytecodec"
"test_opcache"
"test_pdb"
"test_peepholer"
"test_positional_only_arg"
"test_print"
"test_property"
"test_pyclbr"
"test_range"
"test_re"
"test_readline"
"test_regrtest"
"test_repl"
"test_rlcompleter"
"test_signal"
"test_sort"
"test_source_encoding"
"test_ssl"
"test_string_literals"
"test_structseq"
"test_subprocess"
"test_super"
"test_support"
"test_syntax"
"test_sys"
"test_sys_settrace"
"test_tcl"
"test_termios"
"test_threading"
"test_trace"
"test_tty"
"test_unpack_ex"
"test_utf8_mode"
"test_weakref"
"test_capi"
"test_concurrent_futures"
"test_dataclasses"
"test_doctest"
"test_future_stmt"
"test_importlib"
"test_inspect"
"test_pydoc"
"test_warnings"
]
++ lib.optionals isPy310 [
"test_contextlib_async"
"test_future"
"test_lzma"
"test_module"
"test_typing"
];
in
''
export TERMINFO="${ncurses.out}/share/terminfo/";
export TERM="xterm";
export HOME="$TMPDIR";
${pythonForPypy.interpreter} ./pypy/test_all.py --pypy=./${executable}-c -k 'not (${lib.concatStringsSep " or " disabledTests})' lib-python
'';
# verify cffi modules
doInstallCheck = true;
installCheckPhase =
let
modules = [
"curses"
"sqlite3"
]
++ lib.optionals (!isPy3k) [
"Tkinter"
]
++ lib.optionals isPy3k [
"tkinter"
"lzma"
];
imports = lib.concatMapStringsSep "; " (x: "import ${x}") modules;
in
''
echo "Testing whether we can import modules"
$out/bin/${executable} -c '${imports}'
'';
inherit passthru;
enableParallelBuilding = true; # almost no parallelization without STM
meta = with lib; {
homepage = "https://www.pypy.org/";
changelog = "https://doc.pypy.org/en/stable/release-v${version}.html";
description = "Fast, compliant alternative implementation of the Python language (${pythonVersion})";
mainProgram = "pypy";
license = licenses.mit;
platforms = [
"aarch64-linux"
"x86_64-linux"
"aarch64-darwin"
"x86_64-darwin"
];
broken = optimizationLevel == "0"; # generates invalid code
maintainers = with maintainers; [
andersk
fliegendewurst
];
};
}

View File

@@ -0,0 +1,12 @@
diff -ur a/lib_pypy/pypy_tools/build_cffi_imports.py b/lib_pypy/pypy_tools/build_cffi_imports.py
--- a/lib_pypy/pypy_tools/build_cffi_imports.py 2021-04-12 01:11:48.000000000 -0400
+++ b/lib_pypy/pypy_tools/build_cffi_imports.py 2021-07-16 06:37:03.000000000 -0400
@@ -225,6 +225,8 @@
print('*', ' '.join(args), file=sys.stderr)
if embed_dependencies and key in cffi_dependencies:
+ print("Nixpkgs: skipping fetching/building dependency", key)
+ elif False:
status, stdout, stderr = _build_dependency(key)
if status != 0:
failures.append((key, module))

View File

@@ -0,0 +1,187 @@
{
lib,
stdenv,
fetchurl,
autoPatchelfHook,
python-setup-hook,
self,
# Dependencies
bzip2,
expat,
gdbm,
ncurses6,
sqlite,
tcl-8_5,
tk-8_5,
tcl-8_6,
tk-8_6,
zlib,
# For the Python package set
packageOverrides ? (self: super: { }),
sourceVersion,
pythonVersion,
hash,
passthruFun,
}:
# This version of PyPy is primarily added to speed-up translation of
# our PyPy source build when developing that expression.
let
isPy3k = majorVersion == "3";
passthru = passthruFun rec {
inherit
self
sourceVersion
pythonVersion
packageOverrides
;
implementation = "pypy";
libPrefix = "pypy${pythonVersion}";
executable = "pypy${lib.optionalString isPy3k "3"}";
sitePackages = "lib/${libPrefix}/site-packages";
hasDistutilsCxxPatch = false;
# Not possible to cross-compile with.
pythonOnBuildForBuild = throw "${pname} does not support cross compilation";
pythonOnBuildForHost = self;
pythonOnBuildForTarget = throw "${pname} does not support cross compilation";
pythonOnHostForHost = throw "${pname} does not support cross compilation";
pythonOnTargetForTarget = throw "${pname} does not support cross compilation";
pythonABITags = [
"none"
"pypy${lib.concatStrings (lib.take 2 (lib.splitString "." pythonVersion))}_pp${sourceVersion.major}${sourceVersion.minor}"
];
};
pname = "${passthru.executable}_prebuilt";
version = with sourceVersion; "${major}.${minor}.${patch}";
majorVersion = lib.versions.major pythonVersion;
downloadUrls = {
aarch64-linux = "https://downloads.python.org/pypy/pypy${pythonVersion}-v${version}-aarch64.tar.bz2";
x86_64-linux = "https://downloads.python.org/pypy/pypy${pythonVersion}-v${version}-linux64.tar.bz2";
aarch64-darwin = "https://downloads.python.org/pypy/pypy${pythonVersion}-v${version}-macos_arm64.tar.bz2";
x86_64-darwin = "https://downloads.python.org/pypy/pypy${pythonVersion}-v${version}-macos_x86_64.tar.bz2";
};
in
with passthru;
stdenv.mkDerivation {
inherit pname version;
src = fetchurl {
url = downloadUrls.${stdenv.system} or (throw "Unsupported system: ${stdenv.system}");
inherit hash;
};
buildInputs = [
bzip2
expat
gdbm
ncurses6
sqlite
zlib
stdenv.cc.cc.libgcc or null
]
++ lib.optionals stdenv.hostPlatform.isLinux [
tcl-8_5
tk-8_5
]
++ lib.optionals stdenv.hostPlatform.isDarwin [
tcl-8_6
tk-8_6
];
nativeBuildInputs = lib.optionals stdenv.hostPlatform.isLinux [ autoPatchelfHook ];
installPhase = ''
runHook preInstall
mkdir -p $out
echo "Moving files to $out"
mv -t $out bin include lib
mv $out/bin/libpypy*-c${stdenv.hostPlatform.extensions.sharedLibrary} $out/lib/
${lib.optionalString stdenv.hostPlatform.isLinux ''
rm $out/bin/*.debug
''}
echo "Removing bytecode"
find . -name "__pycache__" -type d -depth -delete
# Include a sitecustomize.py file
cp ${../sitecustomize.py} $out/${sitePackages}/sitecustomize.py
runHook postInstall
'';
preFixup =
lib.optionalString stdenv.hostPlatform.isLinux ''
find $out/{lib,lib_pypy*} -name "*.so" \
-exec patchelf \
--replace-needed libtinfow.so.6 libncursesw.so.6 \
--replace-needed libgdbm.so.4 libgdbm_compat.so.4 {} \;
''
+ lib.optionalString stdenv.hostPlatform.isDarwin ''
install_name_tool \
-change \
@rpath/lib${libPrefix}-c.dylib \
$out/lib/lib${libPrefix}-c.dylib \
$out/bin/${executable}
install_name_tool \
-change \
@rpath/lib${libPrefix}-c.dylib \
$out/lib/lib${libPrefix}-c.dylib \
$out/bin/${libPrefix}
install_name_tool \
-change \
/opt/homebrew${lib.optionalString stdenv.hostPlatform.isx86_64 "_x86_64"}/opt/tcl-tk/lib/libtcl8.6.dylib \
${tcl-8_6}/lib/libtcl8.6.dylib \
$out/lib/${libPrefix}/_tkinter/*.so
install_name_tool \
-change \
/opt/homebrew${lib.optionalString stdenv.hostPlatform.isx86_64 "_x86_64"}/opt/tcl-tk/lib/libtk8.6.dylib \
${tk-8_6}/lib/libtk8.6.dylib \
$out/lib/${libPrefix}/_tkinter/*.so
'';
doInstallCheck = true;
# Check whether importing of (extension) modules functions
installCheckPhase =
let
modules = [
"ssl"
"sys"
"curses"
]
++ lib.optionals (!isPy3k) [
"Tkinter"
]
++ lib.optionals isPy3k [
"tkinter"
];
imports = lib.concatMapStringsSep "; " (x: "import ${x}") modules;
in
''
echo "Testing whether we can import modules"
$out/bin/${executable} -c '${imports}'
'';
setupHook = python-setup-hook sitePackages;
donPatchElf = true;
dontStrip = true;
inherit passthru;
meta = with lib; {
homepage = "http://pypy.org/";
description = "Fast, compliant alternative implementation of the Python language (${pythonVersion})";
mainProgram = "pypy";
license = licenses.mit;
platforms = lib.mapAttrsToList (arch: _: arch) downloadUrls;
};
}

View File

@@ -0,0 +1,181 @@
{
lib,
stdenv,
fetchurl,
autoPatchelfHook,
python-setup-hook,
self,
# Dependencies
bzip2,
expat,
gdbm,
ncurses6,
sqlite,
tcl-8_5,
tk-8_5,
tcl-8_6,
tk-8_6,
zlib,
# For the Python package set
packageOverrides ? (self: super: { }),
sourceVersion,
pythonVersion,
hash,
passthruFun,
}:
# This version of PyPy is primarily added to speed-up translation of
# our PyPy source build when developing that expression.
let
isPy3k = majorVersion == "3";
passthru = passthruFun {
inherit
self
sourceVersion
pythonVersion
packageOverrides
;
implementation = "pypy";
libPrefix = "pypy${pythonVersion}";
executable = "pypy${lib.optionalString isPy3k "3"}";
sitePackages = "site-packages";
hasDistutilsCxxPatch = false;
# Not possible to cross-compile with.
pythonOnBuildForBuild = throw "${pname} does not support cross compilation";
pythonOnBuildForHost = self;
pythonOnBuildForTarget = throw "${pname} does not support cross compilation";
pythonOnHostForHost = throw "${pname} does not support cross compilation";
pythonOnTargetForTarget = throw "${pname} does not support cross compilation";
pythonABITags = [
"none"
"pypy${lib.concatStrings (lib.take 2 (lib.splitString "." pythonVersion))}_pp${sourceVersion.major}${sourceVersion.minor}"
];
};
pname = "${passthru.executable}_prebuilt";
version = with sourceVersion; "${major}.${minor}.${patch}";
majorVersion = lib.versions.major pythonVersion;
downloadUrls = {
aarch64-linux = "https://downloads.python.org/pypy/pypy${pythonVersion}-v${version}-aarch64.tar.bz2";
x86_64-linux = "https://downloads.python.org/pypy/pypy${pythonVersion}-v${version}-linux64.tar.bz2";
aarch64-darwin = "https://downloads.python.org/pypy/pypy${pythonVersion}-v${version}-macos_arm64.tar.bz2";
x86_64-darwin = "https://downloads.python.org/pypy/pypy${pythonVersion}-v${version}-macos_x86_64.tar.bz2";
};
in
with passthru;
stdenv.mkDerivation {
inherit pname version;
src = fetchurl {
url = downloadUrls.${stdenv.system} or (throw "Unsupported system: ${stdenv.system}");
inherit hash;
};
buildInputs = [
bzip2
expat
gdbm
ncurses6
sqlite
zlib
stdenv.cc.cc.libgcc or null
]
++ lib.optionals stdenv.hostPlatform.isLinux [
tcl-8_5
tk-8_5
]
++ lib.optionals stdenv.hostPlatform.isDarwin [
tcl-8_6
tk-8_6
];
nativeBuildInputs = lib.optionals stdenv.hostPlatform.isLinux [ autoPatchelfHook ];
installPhase = ''
runHook preInstall
mkdir -p $out/lib
echo "Moving files to $out"
mv -t $out bin include lib-python lib_pypy site-packages
mv $out/bin/libpypy*-c${stdenv.hostPlatform.extensions.sharedLibrary} $out/lib/
${lib.optionalString stdenv.hostPlatform.isLinux ''
rm $out/bin/*.debug
''}
echo "Removing bytecode"
find . -name "__pycache__" -type d -depth -delete
# Include a sitecustomize.py file
cp ${../sitecustomize.py} $out/${sitePackages}/sitecustomize.py
runHook postInstall
'';
preFixup =
lib.optionalString (stdenv.hostPlatform.isLinux) ''
find $out/{lib,lib_pypy*} -name "*.so" \
-exec patchelf \
--replace-needed libtinfow.so.6 libncursesw.so.6 \
--replace-needed libgdbm.so.4 libgdbm_compat.so.4 {} \;
''
+ lib.optionalString (stdenv.hostPlatform.isDarwin) ''
install_name_tool \
-change \
@rpath/lib${executable}-c.dylib \
$out/lib/lib${executable}-c.dylib \
$out/bin/${executable}
install_name_tool \
-change \
/opt/homebrew${lib.optionalString stdenv.hostPlatform.isx86_64 "_x86_64"}/opt/tcl-tk/lib/libtcl8.6.dylib \
${tcl-8_6}/lib/libtcl8.6.dylib \
$out/lib_pypy/_tkinter/*.so
install_name_tool \
-change \
/opt/homebrew${lib.optionalString stdenv.hostPlatform.isx86_64 "_x86_64"}/opt/tcl-tk/lib/libtk8.6.dylib \
${tk-8_6}/lib/libtk8.6.dylib \
$out/lib_pypy/_tkinter/*.so
'';
doInstallCheck = true;
# Check whether importing of (extension) modules functions
installCheckPhase =
let
modules = [
"ssl"
"sys"
"curses"
]
++ lib.optionals (!isPy3k) [
"Tkinter"
]
++ lib.optionals isPy3k [
"tkinter"
];
imports = lib.concatMapStringsSep "; " (x: "import ${x}") modules;
in
''
echo "Testing whether we can import modules"
$out/bin/${executable} -c '${imports}'
'';
setupHook = python-setup-hook sitePackages;
donPatchElf = true;
dontStrip = true;
inherit passthru;
meta = with lib; {
homepage = "http://pypy.org/";
description = "Fast, compliant alternative implementation of the Python language (${pythonVersion})";
license = licenses.mit;
platforms = lib.mapAttrsToList (arch: _: arch) downloadUrls;
};
}

View File

@@ -0,0 +1,40 @@
diff --git a/lib_pypy/_sqlite3_build.py b/lib_pypy/_sqlite3_build.py
index 2a4e573..92ab786 100644
--- a/lib_pypy/_sqlite3_build.py
+++ b/lib_pypy/_sqlite3_build.py
@@ -352,7 +352,7 @@ def _has_load_extension():
typedef ... sqlite3;
int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
""")
- libname = 'sqlite3'
+ libname = '@libsqlite@'
if sys.platform == 'win32':
import os
_libname = os.path.join(os.path.dirname(sys.executable), libname)
@@ -369,7 +369,7 @@ def _has_backup():
typedef ... sqlite3_backup;
sqlite3_backup* sqlite3_backup_init(sqlite3 *, const char* , sqlite3 *, const char*);
""")
- libname = 'sqlite3'
+ libname = '@libsqlite@'
if sys.platform == 'win32':
import os
_libname = os.path.join(os.path.dirname(sys.executable), libname)
@@ -383,7 +383,7 @@ def _get_version():
unverified_ffi.cdef("""
int sqlite3_libversion_number(void);
""")
- libname = 'sqlite3'
+ libname = '@libsqlite@'
if sys.platform == 'win32':
import os
_libname = os.path.join(os.path.dirname(sys.executable), libname)
@@ -554,6 +554,8 @@ if sys.platform.startswith('freebsd'):
else:
extra_args = dict(
libraries=libraries,
+ include_dirs=['@dev@/include'],
+ library_dirs=['@out@/lib']
)
SOURCE = """

View File

@@ -0,0 +1,22 @@
diff --git a/lib_pypy/_sqlite3_build.py b/lib_pypy/_sqlite3_build.py
index fb03aee..b3b5f39 100644
--- a/lib_pypy/_sqlite3_build.py
+++ b/lib_pypy/_sqlite3_build.py
@@ -234,7 +234,7 @@ def _has_load_extension():
typedef ... sqlite3;
int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
""")
- libname = 'sqlite3'
+ libname = '@libsqlite@'
if sys.platform == 'win32':
import os
_libname = os.path.join(os.path.dirname(sys.executable), libname)
@@ -257,6 +257,8 @@ if sys.platform.startswith('freebsd'):
else:
extra_args = dict(
libraries=libraries,
+ include_dirs=['@dev@/include'],
+ library_dirs=['@out@/lib']
)
_ffi.set_source("_sqlite3_cffi", "#include <sqlite3.h>", **extra_args)

Some files were not shown because too many files have changed in this diff Show More