Skip to content

Commit cd2a0ff

Browse files
committed
unix: install pip and setuptools from wheels
This commit refactors the install of pip and setuptools. Previously, we installed both of these by invoking `setup.py` from the host Python. This worked, but it was somewhat old school. And in the case of cross-compiling, it installed the packages to the host Python, not the target Python. After this commit, we download wheels for both pip and setuptools and the install invokes the host Python but runs the pip wheel to invoke pip to install the packages. This is conceptually similar to how the `ensurepip` module works. The end result is that pip is used to install itself and setuptools into the appropriate output directory. This works with both native and cross builds. Aside from minor changes to the directory layout, the end result is the same as far as I can tell. But since cross-compiles now install pip and setuptools correctly, this fixes #84. Because pip now bootstraps self and this doesn't work on musl builds without a patch, we had to move the patching of pip to before it is invoked. We moved the patching of setuptools as well, because it is related. Windows builds were updated to use the wheel based pip and setuptools. However, we don't support cross-compiling on Windows yet, so we continue to use the built python.exe to install these wheels.
1 parent 6e553e8 commit cd2a0ff

File tree

5 files changed

+110
-74
lines changed

5 files changed

+110
-74
lines changed

cpython-unix/build-cpython.sh

Lines changed: 81 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,74 @@ export LLVM_PROFDATA=${TOOLS_PATH}/${TOOLCHAIN}/bin/llvm-profdata
2020
find ${TOOLS_PATH}/deps -name '*.so*' -exec rm {} \;
2121

2222
tar -xf Python-${PYTHON_VERSION}.tar.xz
23-
tar -xf setuptools-${SETUPTOOLS_VERSION}.tar.gz
24-
tar -xf pip-${PIP_VERSION}.tar.gz
23+
24+
PIP_WHEEL="${ROOT}/pip-${PIP_VERSION}-py3-none-any.whl"
25+
SETUPTOOLS_WHEEL="${ROOT}/setuptools-${SETUPTOOLS_VERSION}-py3-none-any.whl"
26+
27+
chmod 644 "${PIP_WHEEL}"
28+
chmod 644 "${SETUPTOOLS_WHEEL}"
29+
30+
# pip and setuptools don't properly handle the case where the current executable
31+
# isn't dynamic. This is tracked by https://github.com/pypa/pip/issues/6543.
32+
# We need to patch both.
33+
#
34+
# Ideally we'd do this later in the build. However, since we use the pip
35+
# wheel to bootstrap itself, we need to patch the wheel before it is used.
36+
#
37+
# Wheels are zip files. So we simply unzip, patch, and rezip.
38+
mkdir pip-tmp
39+
pushd pip-tmp
40+
unzip "${PIP_WHEEL}"
41+
42+
patch -p1 <<EOF
43+
diff --git a/pip/_internal/utils/glibc.py b/pip/_internal/utils/glibc.py
44+
index 819979d80..4ae91e364 100644
45+
--- a/pip/_internal/utils/glibc.py
46+
+++ b/pip/_internal/utils/glibc.py
47+
@@ -47,7 +47,10 @@ def glibc_version_string_ctypes():
48+
# manpage says, "If filename is NULL, then the returned handle is for the
49+
# main program". This way we can let the linker do the work to figure out
50+
# which libc our process is actually using.
51+
- process_namespace = ctypes.CDLL(None)
52+
+ try:
53+
+ process_namespace = ctypes.CDLL(None)
54+
+ except OSError:
55+
+ return None
56+
try:
57+
gnu_get_libc_version = process_namespace.gnu_get_libc_version
58+
except AttributeError:
59+
EOF
60+
61+
zip -r "${PIP_WHEEL}" *
62+
popd
63+
rm -rf pip-tmp
64+
65+
mkdir setuptools-tmp
66+
pushd setuptools-tmp
67+
unzip "${SETUPTOOLS_WHEEL}"
68+
69+
patch -p1 <<EOF
70+
diff --git a/setuptools/_vendor/packaging/tags.py b/setuptools/_vendor/packaging/tags.py
71+
index 9064910b..c541e648 100644
72+
--- a/setuptools/_vendor/packaging/tags.py
73+
+++ b/setuptools/_vendor/packaging/tags.py
74+
@@ -475,7 +475,10 @@ def _glibc_version_string_ctypes():
75+
# which libc our process is actually using.
76+
#
77+
# Note: typeshed is wrong here so we are ignoring this line.
78+
- process_namespace = ctypes.CDLL(None) # type: ignore
79+
+ try:
80+
+ process_namespace = ctypes.CDLL(None) # type: ignore
81+
+ except OSError:
82+
+ return None
83+
try:
84+
gnu_get_libc_version = process_namespace.gnu_get_libc_version
85+
except AttributeError:
86+
EOF
87+
88+
zip -r "${SETUPTOOLS_WHEEL}" *
89+
popd
90+
rm -rf setuptools-tmp
2591

2692
# If we are cross-compiling, we need to build a host Python to use during
2793
# the build.
@@ -50,7 +116,9 @@ if [ "${BUILD_TRIPLE}" != "${TARGET_TRIPLE}" ]; then
50116
;;
51117
esac
52118

53-
CC="${HOST_CC}" CFLAGS="${EXTRA_HOST_CFLAGS}" CPPFLAGS="${EXTRA_HOST_CFLAGS}" LDFLAGS="${EXTRA_HOST_LDFLAGS}" ./configure --prefix "${TOOLS_PATH}/pyhost"
119+
CC="${HOST_CC}" CFLAGS="${EXTRA_HOST_CFLAGS}" CPPFLAGS="${EXTRA_HOST_CFLAGS}" LDFLAGS="${EXTRA_HOST_LDFLAGS}" ./configure \
120+
--prefix "${TOOLS_PATH}/pyhost" \
121+
--without-ensurepip
54122

55123
make -j "${NUM_CPUS}" install
56124

@@ -770,63 +838,17 @@ if [ "${PYBUILD_SHARED}" = "1" ]; then
770838
fi
771839
fi
772840

773-
# Install pip so we can patch it to work with non-dynamic executables
774-
# and work around https://github.com/pypa/pip/issues/6543. But pip's bundled
775-
# setuptools has the same bug! So we need to install a patched version.
776-
pushd ${ROOT}/setuptools-${SETUPTOOLS_VERSION}
777-
patch -p1 <<EOF
778-
diff --git a/setuptools/_vendor/packaging/tags.py b/setuptools/_vendor/packaging/tags.py
779-
index 9064910b..c541e648 100644
780-
--- a/setuptools/_vendor/packaging/tags.py
781-
+++ b/setuptools/_vendor/packaging/tags.py
782-
@@ -475,7 +475,10 @@ def _glibc_version_string_ctypes():
783-
# which libc our process is actually using.
784-
#
785-
# Note: typeshed is wrong here so we are ignoring this line.
786-
- process_namespace = ctypes.CDLL(None) # type: ignore
787-
+ try:
788-
+ process_namespace = ctypes.CDLL(None) # type: ignore
789-
+ except OSError:
790-
+ return None
791-
try:
792-
gnu_get_libc_version = process_namespace.gnu_get_libc_version
793-
except AttributeError:
794-
EOF
795-
796-
${BUILD_PYTHON} setup.py install
797-
popd
798-
799-
pushd ${ROOT}/pip-${PIP_VERSION}
800-
801-
# pip 21 shipped DOS line endings. https://github.com/pypa/pip/issues/9638.
802-
# Let's fix that.
803-
if [ "${PYBUILD_PLATFORM}" = "macos" ]; then
804-
find . -name '*.py' -exec perl -i -pe 's/\r\n$/\n/g' {} \;
805-
else
806-
find . -name '*.py' -exec sed -i 's/\r$//g' {} \;
807-
fi
808-
809-
patch -p1 <<EOF
810-
diff --git a/src/pip/_internal/utils/glibc.py b/src/pip/_internal/utils/glibc.py
811-
index 819979d80..4ae91e364 100644
812-
--- a/src/pip/_internal/utils/glibc.py
813-
+++ b/src/pip/_internal/utils/glibc.py
814-
@@ -47,7 +47,10 @@ def glibc_version_string_ctypes():
815-
# manpage says, "If filename is NULL, then the returned handle is for the
816-
# main program". This way we can let the linker do the work to figure out
817-
# which libc our process is actually using.
818-
- process_namespace = ctypes.CDLL(None)
819-
+ try:
820-
+ process_namespace = ctypes.CDLL(None)
821-
+ except OSError:
822-
+ return None
823-
try:
824-
gnu_get_libc_version = process_namespace.gnu_get_libc_version
825-
except AttributeError:
826-
EOF
841+
# Install setuptools and pip as they are common tools that should be in any
842+
# Python distribution.
843+
#
844+
# We disabled ensurepip because we insist on providing our own pip and don't
845+
# want the final product to possibly be contaminated by another version.
846+
#
847+
# It is possible for the Python interpreter to run wheels directly. So we
848+
# simply use our pip to install self. Kinda crazy, but it works!
827849

828-
${BUILD_PYTHON} setup.py install
829-
popd
850+
${BUILD_PYTHON} "${PIP_WHEEL}/pip" install --prefix="${ROOT}/out/python/install" --no-cache-dir --no-index "${PIP_WHEEL}"
851+
${BUILD_PYTHON} "${PIP_WHEEL}/pip" install --prefix="${ROOT}/out/python/install" --no-cache-dir --no-index "${SETUPTOOLS_WHEEL}"
830852

831853
# Emit metadata to be used in PYTHON.json.
832854
cat > ${ROOT}/generate_metadata.py << EOF

cpython-unix/build.Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ RUN apt-get install \
2323
tar \
2424
xz-utils \
2525
unzip \
26+
zip \
2627
zlib1g-dev

cpython-unix/build.cross.Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ RUN apt-get install \
4343
tar \
4444
xz-utils \
4545
unzip \
46+
zip \
4647
zlib1g-dev
4748

4849
# Cross-building.

cpython-windows/build.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1909,8 +1909,8 @@ def build_cpython(
19091909

19101910
python_version = entry["version"]
19111911

1912-
setuptools_archive = download_entry("setuptools", BUILD)
1913-
pip_archive = download_entry("pip", BUILD)
1912+
setuptools_wheel = download_entry("setuptools", BUILD)
1913+
pip_wheel = download_entry("pip", BUILD)
19141914

19151915
if arch == "amd64":
19161916
build_platform = "x64"
@@ -1930,8 +1930,6 @@ def build_cpython(
19301930
python_archive,
19311931
bzip2_archive,
19321932
openssl_archive,
1933-
pip_archive,
1934-
setuptools_archive,
19351933
sqlite_archive,
19361934
tk_bin_archive,
19371935
xz_archive,
@@ -2113,16 +2111,30 @@ def build_cpython(
21132111
args, pcbuild_path, os.environ,
21142112
)
21152113

2116-
# Install setuptools and pip.
2114+
# Install pip and setuptools.
21172115
exec_and_log(
2118-
[str(install_dir / "python.exe"), "setup.py", "install"],
2119-
str(td / ("setuptools-%s" % DOWNLOADS["setuptools"]["version"])),
2116+
[
2117+
str(install_dir / "python.exe"),
2118+
str(pip_wheel / "pip"),
2119+
"install",
2120+
"--no-cache-dir",
2121+
"--no-index",
2122+
str(pip_wheel),
2123+
],
2124+
td,
21202125
os.environ,
21212126
)
21222127

21232128
exec_and_log(
2124-
[str(install_dir / "python.exe"), "setup.py", "install"],
2125-
str(td / ("pip-%s" % DOWNLOADS["pip"]["version"])),
2129+
[
2130+
str(install_dir / "python.exe"),
2131+
str(pip_wheel / "pip"),
2132+
"install",
2133+
"--no-cache-dir",
2134+
"--no-index",
2135+
str(setuptools_wheel),
2136+
],
2137+
td,
21262138
os.environ,
21272139
)
21282140

pythonbuild/downloads.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -286,9 +286,9 @@
286286
"version": "0.12",
287287
},
288288
"pip": {
289-
"url": "https://files.pythonhosted.org/packages/52/e1/06c018197d8151383f66ebf6979d951995cf495629fc54149491f5d157d0/pip-21.2.4.tar.gz",
290-
"size": 1564487,
291-
"sha256": "0eb8a1516c3d138ae8689c0c1a60fde7143310832f9dc77e11d8a4bc62de193b",
289+
"url": "https://files.pythonhosted.org/packages/ca/31/b88ef447d595963c01060998cb329251648acf4a067721b0452c45527eb8/pip-21.2.4-py3-none-any.whl",
290+
"size": 1555100,
291+
"sha256": "fa9ebb85d3fd607617c0c44aca302b1b45d87f9c2a1649b46c26167ca4296323",
292292
"version": "21.2.4",
293293
},
294294
"readline": {
@@ -301,9 +301,9 @@
301301
"license_file": "LICENSE.readline.txt",
302302
},
303303
"setuptools": {
304-
"url": "https://files.pythonhosted.org/packages/db/e2/c0ced9ccffb61432305665c22842ea120c0f649eec47ecf2a45c596707c4/setuptools-57.4.0.tar.gz",
305-
"size": 2141309,
306-
"sha256": "6bac238ffdf24e8806c61440e755192470352850f3419a52f26ffe0a1a64f465",
304+
"url": "https://files.pythonhosted.org/packages/bd/25/5bdf7f1adeebd4e3fa76b2e2f045ae53ee208e40a4231ad0f0c3007e4353/setuptools-57.4.0-py3-none-any.whl",
305+
"size": 819017,
306+
"sha256": "a49230977aa6cfb9d933614d2f7b79036e9945c4cdd7583163f4e920b83418d6",
307307
"version": "57.4.0",
308308
},
309309
"sqlite": {

0 commit comments

Comments
 (0)