Skip to content

Commit c38b3bc

Browse files
committed
[manylinux2014] Rework scripts to be more docker cache friendly
This won't change travis-ci build time (at least for now) but allows maintainers/contributors to benefit from docker caching for local developments (faster builds at the expense of higher disk usage) Round 1 Use docker multi-stage build to build the manylinux image in 3 steps: 1. runtime_base: this image has all the necessary bits that are common to the build_base image and the manylinux image. This includes system packages required for runtime, the gcc toolchain & some basic tools. 2. build_base: this image builds all the remaining tools required for the manylinux image. Any tool requiring specific system development package not required in the manylinux image shall be built from this image. For tools that used to be installed in /usr/local, they are staged in /manylinux-rootfs for an easy copy in the third stage. 3. manylinux: This image uses the runtime_base image as a base image. Tools built in the 2nd step are copied directly in the final filesystem. A finalization script is then run to install the remaining python tools/dependencies and run checks.
1 parent 91ce2b8 commit c38b3bc

File tree

7 files changed

+277
-209
lines changed

7 files changed

+277
-209
lines changed

docker/Dockerfile

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
ARG BASEIMAGE=amd64/centos:7
33
ARG POLICY=manylinux2014
44
ARG PLATFORM=x86_64
5-
ARG DEVTOOLSET_ROOTPATH=
6-
ARG LD_LIBRARY_PATH_ARG=
7-
ARG PREPEND_PATH=
5+
ARG DEVTOOLSET_ROOTPATH=/opt/rh/devtoolset-9/root
6+
ARG LD_LIBRARY_PATH_ARG=${DEVTOOLSET_ROOTPATH}/usr/lib64:${DEVTOOLSET_ROOTPATH}/usr/lib:${DEVTOOLSET_ROOTPATH}/usr/lib64/dyninst:${DEVTOOLSET_ROOTPATH}/usr/lib/dyninst:/usr/local/lib64:/usr/local/lib
7+
ARG PREPEND_PATH=${DEVTOOLSET_ROOTPATH}/usr/bin:
88

9-
FROM $BASEIMAGE
9+
FROM $BASEIMAGE AS runtime_base
1010
ARG POLICY
1111
ARG PLATFORM
1212
ARG DEVTOOLSET_ROOTPATH
@@ -22,14 +22,36 @@ ENV PATH=${PREPEND_PATH}${PATH}
2222
ENV PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
2323

2424
# setup entrypoint, this will wrap commands with `linux32` with i686 images
25-
COPY build_scripts/install-entrypoint.sh /build_scripts/install-entrypoint.sh
25+
COPY build_scripts/install-entrypoint.sh /build_scripts/
2626
RUN bash /build_scripts/install-entrypoint.sh && rm -rf build_scripts
2727
COPY manylinux-entrypoint /usr/local/bin/manylinux-entrypoint
2828
ENTRYPOINT ["manylinux-entrypoint"]
2929

30-
COPY build_scripts /build_scripts
30+
31+
COPY build_scripts/install-runtime-packages.sh /build_scripts/
32+
COPY build_scripts/build_utils.sh /build_scripts/
33+
COPY build_scripts/build_env_runtime.sh /build_scripts/
34+
RUN manylinux-entrypoint /build_scripts/install-runtime-packages.sh && rm -rf /build_scripts
35+
36+
FROM runtime_base AS build_base
37+
COPY build_scripts/*pubkey*.txt /build_scripts/
38+
COPY build_scripts/build_utils.sh /build_scripts/
39+
COPY build_scripts/build.sh /build_scripts/
40+
COPY build_scripts/build_env.sh /build_scripts/
3141
RUN manylinux-entrypoint bash build_scripts/build.sh && rm -rf build_scripts
3242

43+
FROM runtime_base
44+
COPY --from=build_base /manylinux-rootfs /
45+
COPY --from=build_base /opt/_internal /opt/_internal/
46+
COPY build_scripts/build_utils.sh /build_scripts/build_utils.sh
47+
COPY build_scripts/finalize.sh /build_scripts/finalize.sh
48+
COPY build_scripts/python-tag-abi-tag.py /build_scripts/python-tag-abi-tag.py
49+
COPY build_scripts/ssl-check.py /build_scripts/ssl-check.py
50+
COPY build_scripts/manylinux-check.py /build_scripts/manylinux-check.py
51+
COPY build_scripts/requirements.txt /build_scripts/requirements.txt
52+
COPY build_scripts/requirements-tools.txt /build_scripts/requirements-tools.txt
53+
RUN manylinux-entrypoint /build_scripts/finalize.sh && rm -rf /build_scripts
54+
3355
ENV SSL_CERT_FILE=/opt/_internal/certs.pem
3456

3557
CMD ["/bin/bash"]

docker/build_scripts/build.sh

Lines changed: 20 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -6,119 +6,40 @@ set -ex
66

77
# Set build environment variables
88
MY_DIR=$(dirname "${BASH_SOURCE[0]}")
9-
. $MY_DIR/build_env.sh
10-
11-
# Dependencies for compiling Python that we want to remove from
12-
# the final image after compiling Python
13-
PYTHON_COMPILE_DEPS="zlib-devel bzip2-devel expat-devel ncurses-devel readline-devel tk-devel gdbm-devel libdb-devel libpcap-devel xz-devel openssl-devel keyutils-libs-devel krb5-devel libcom_err-devel libidn-devel curl-devel perl-devel"
14-
15-
# Libraries that are allowed as part of the manylinux2014 profile
16-
# Extract from PEP: https://www.python.org/dev/peps/pep-0599/#the-manylinux2014-policy
17-
# On RPM-based systems, they are provided by these packages:
18-
# Package: Libraries
19-
# glib2: libglib-2.0.so.0, libgthread-2.0.so.0, libgobject-2.0.so.0
20-
# glibc: libresolv.so.2, libutil.so.1, libnsl.so.1, librt.so.1, libpthread.so.0, libdl.so.2, libm.so.6, libc.so.6
21-
# libICE: libICE.so.6
22-
# libX11: libX11.so.6
23-
# libXext: libXext.so.6
24-
# libXrender: libXrender.so.1
25-
# libgcc: libgcc_s.so.1
26-
# libstdc++: libstdc++.so.6
27-
# mesa: libGL.so.1
28-
#
29-
# PEP is missing the package for libSM.so.6 for RPM based system
30-
# Install development packages (except for libgcc which is provided by gcc install)
31-
MANYLINUX_DEPS="glibc-devel libstdc++-devel glib2-devel libX11-devel libXext-devel libXrender-devel mesa-libGL-devel libICE-devel libSM-devel"
32-
33-
CMAKE_DEPS="openssl-devel zlib-devel libcurl-devel"
9+
source $MY_DIR/build_env.sh
3410

3511
# Get build utilities
3612
source $MY_DIR/build_utils.sh
3713

38-
# See https://unix.stackexchange.com/questions/41784/can-yum-express-a-preference-for-x86-64-over-i386-packages
39-
echo "multilib_policy=best" >> /etc/yum.conf
40-
# Error out if requested packages do not exist
41-
echo "skip_missing_names_on_install=False" >> /etc/yum.conf
42-
# Make sure that locale will not be removed
43-
sed -i '/^override_install_langs=/d' /etc/yum.conf
44-
45-
# https://hub.docker.com/_/centos/
46-
# "Additionally, images with minor version tags that correspond to install
47-
# media are also offered. These images DO NOT recieve updates as they are
48-
# intended to match installation iso contents. If you choose to use these
49-
# images it is highly recommended that you include RUN yum -y update && yum
50-
# clean all in your Dockerfile, or otherwise address any potential security
51-
# concerns."
52-
# Decided not to clean at this point: https://github.com/pypa/manylinux/pull/129
53-
yum -y update
54-
yum -y install yum-utils curl
55-
yum-config-manager --enable extras
56-
57-
if ! which localedef &> /dev/null; then
58-
# somebody messed up glibc-common package to squeeze image size, reinstall the package
59-
yum -y reinstall glibc-common
60-
fi
61-
62-
# upgrading glibc-common can end with removal on en_US.UTF-8 locale
63-
localedef -i en_US -f UTF-8 en_US.UTF-8
64-
65-
TOOLCHAIN_DEPS="devtoolset-9-binutils devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-gcc-gfortran"
66-
if [ "${AUDITWHEEL_ARCH}" == "x86_64" ]; then
67-
# Software collection (for devtoolset-9)
68-
yum -y install centos-release-scl-rh
69-
# EPEL support (for yasm)
70-
yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
71-
YASM=yasm
72-
elif [ "${AUDITWHEEL_ARCH}" == "aarch64" ] || [ "${AUDITWHEEL_ARCH}" == "ppc64le" ] || [ "${AUDITWHEEL_ARCH}" == "s390x" ]; then
73-
# Software collection (for devtoolset-9)
74-
yum -y install centos-release-scl-rh
75-
elif [ "${AUDITWHEEL_ARCH}" == "i686" ]; then
76-
# No yasm on i686
77-
# Install mayeut/devtoolset-9 repo to get devtoolset-9
78-
curl -fsSLo /etc/yum.repos.d/mayeut-devtoolset-9.repo https://copr.fedorainfracloud.org/coprs/mayeut/devtoolset-9/repo/custom-1/mayeut-devtoolset-9-custom-1.repo
79-
fi
14+
# Dependencies for compiling Python that we want to remove from
15+
# the final image after compiling Python
16+
PYTHON_COMPILE_DEPS="zlib-devel bzip2-devel expat-devel ncurses-devel readline-devel tk-devel gdbm-devel libdb-devel libpcap-devel xz-devel openssl-devel keyutils-libs-devel krb5-devel libcom_err-devel libidn-devel curl-devel perl-devel libffi-devel kernel-devel"
17+
CMAKE_DEPS="openssl-devel zlib-devel libcurl-devel"
8018

8119
# Development tools and libraries
82-
yum -y install \
83-
autoconf \
84-
automake \
85-
bison \
86-
bzip2 \
87-
${TOOLCHAIN_DEPS} \
88-
diffutils \
89-
gettext \
90-
file \
91-
kernel-devel \
92-
libffi-devel \
93-
make \
94-
patch \
95-
unzip \
96-
which \
97-
${YASM} \
98-
${PYTHON_COMPILE_DEPS} \
99-
${CMAKE_DEPS}
20+
yum -y install ${PYTHON_COMPILE_DEPS} ${CMAKE_DEPS}
10021

10122
# Install git
10223
build_git $GIT_ROOT $GIT_HASH
103-
git version
104-
105-
# Install newest automake
106-
build_automake $AUTOMAKE_ROOT $AUTOMAKE_HASH
107-
automake --version
108-
109-
# Install newest libtool
110-
build_libtool $LIBTOOL_ROOT $LIBTOOL_HASH
111-
libtool --version
24+
/manylinux-rootfs/usr/local/bin/git version
11225

11326
# Install a more recent SQLite3
11427
curl -fsSLO $SQLITE_AUTOCONF_DOWNLOAD_URL/$SQLITE_AUTOCONF_ROOT.tar.gz
11528
check_sha256sum $SQLITE_AUTOCONF_ROOT.tar.gz $SQLITE_AUTOCONF_HASH
11629
tar xfz $SQLITE_AUTOCONF_ROOT.tar.gz
11730
cd $SQLITE_AUTOCONF_ROOT
118-
do_standard_install
31+
DESTDIR=/sqlite3 do_standard_install
11932
cd ..
12033
rm -rf $SQLITE_AUTOCONF_ROOT*
121-
rm /usr/local/lib/libsqlite3.a
34+
rm /sqlite3/usr/local/lib/libsqlite3.a
35+
# Install for build
36+
cp -rf /sqlite3/* /
37+
# Clean-up for runtime
38+
rm -rf /sqlite3/usr/local/bin /sqlite3/usr/local/include /sqlite3/usr/local/lib/pkg-config /sqlite3/usr/local/share
39+
# Install for runtime
40+
cp -rf /sqlite3/* /manylinux-rootfs/
41+
# clean-up
42+
rm -rf /sqlite3
12243

12344
# Install a recent version of cmake3
12445
curl -L -O $CMAKE_DOWNLOAD_URL/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}.tar.gz
@@ -127,101 +48,29 @@ tar -xzf cmake-${CMAKE_VERSION}.tar.gz
12748
cd cmake-${CMAKE_VERSION}
12849
./bootstrap --system-curl --parallel=$(nproc)
12950
make -j$(nproc)
130-
make install
51+
make install DESTDIR=/manylinux-rootfs
13152
cd ..
132-
rm -rf cmake-${CMAKE_VERSION}
133-
134-
# Install libcrypt.so.1 and libcrypt.so.2
135-
build_libxcrypt "$LIBXCRYPT_DOWNLOAD_URL" "$LIBXCRYPT_VERSION" "$LIBXCRYPT_HASH"
53+
rm -rf cmake-${CMAKE_VERSION}*
13654

13755
# Compile the latest Python releases.
13856
# (In order to have a proper SSL module, Python is compiled
13957
# against a recent openssl [see env vars above], which is linked
14058
# statically.
141-
mkdir -p /opt/python
14259
build_cpythons $CPYTHON_VERSIONS
14360

144-
# Create venv for auditwheel & certifi
145-
TOOLS_PATH=/opt/_internal/tools
146-
/opt/python/cp37-cp37m/bin/python -m venv $TOOLS_PATH
147-
source $TOOLS_PATH/bin/activate
148-
149-
# Install default packages
150-
pip install -U --require-hashes -r $MY_DIR/requirements.txt
151-
# Install certifi and auditwheel
152-
pip install -U --require-hashes -r $MY_DIR/requirements-tools.txt
153-
154-
# Make auditwheel available in PATH
155-
ln -s $TOOLS_PATH/bin/auditwheel /usr/local/bin/auditwheel
156-
157-
# Our openssl doesn't know how to find the system CA trust store
158-
# (https://github.com/pypa/manylinux/issues/53)
159-
# And it's not clear how up-to-date that is anyway
160-
# So let's just use the same one pip and everyone uses
161-
ln -s $(python -c 'import certifi; print(certifi.where())') /opt/_internal/certs.pem
162-
# If you modify this line you also have to modify the versions in the Dockerfiles:
163-
export SSL_CERT_FILE=/opt/_internal/certs.pem
164-
165-
# Deactivate the tools virtual environment
166-
deactivate
167-
168-
# Install patchelf (latest with unreleased bug fixes) and apply our patches
169-
build_patchelf $PATCHELF_VERSION $PATCHELF_HASH
170-
171-
# Clean up development headers and other unnecessary stuff for
172-
# final image
173-
yum -y erase \
174-
avahi \
175-
bitstream-vera-fonts \
176-
freetype \
177-
gettext \
178-
gtk2 \
179-
hicolor-icon-theme \
180-
libX11 \
181-
wireless-tools \
182-
${PYTHON_COMPILE_DEPS} > /dev/null 2>&1
183-
yum -y install ${MANYLINUX_DEPS}
184-
yum -y clean all > /dev/null 2>&1
185-
yum list installed
186-
18761
# we don't need libpython*.a, and they're many megabytes
18862
find /opt/_internal -name '*.a' -print0 | xargs -0 rm -f
18963

19064
# Strip what we can -- and ignore errors, because this just attempts to strip
19165
# *everything*, including non-ELF files:
19266
find /opt/_internal -type f -print0 \
19367
| xargs -0 -n1 strip --strip-unneeded 2>/dev/null || true
194-
find /usr/local -type f -print0 \
68+
find /manylinux-rootfs -type f -print0 \
19569
| xargs -0 -n1 strip --strip-unneeded 2>/dev/null || true
19670

197-
for PYTHON in /opt/python/*/bin/python; do
198-
# Smoke test to make sure that our Pythons work, and do indeed detect as
199-
# being manylinux compatible:
200-
$PYTHON $MY_DIR/manylinux-check.py
201-
# Make sure that SSL cert checking works
202-
$PYTHON $MY_DIR/ssl-check.py
203-
done
204-
20571
# We do not need the Python test suites, or indeed the precompiled .pyc and
20672
# .pyo files. Partially cribbed from:
20773
# https://github.com/docker-library/python/blob/master/3.4/slim/Dockerfile
20874
find /opt/_internal -depth \
20975
\( -type d -a -name test -o -name tests \) \
21076
-o \( -type f -a -name '*.pyc' -o -name '*.pyo' \) | xargs rm -rf
211-
212-
# Fix libc headers to remain compatible with C99 compilers.
213-
find /usr/include/ -type f -exec sed -i 's/\bextern _*inline_*\b/extern __inline __attribute__ ((__gnu_inline__))/g' {} +
214-
215-
if [ "${DEVTOOLSET_ROOTPATH:-}" != "" ]; then
216-
# remove useless things that have been installed by devtoolset
217-
rm -rf $DEVTOOLSET_ROOTPATH/usr/share/man
218-
find $DEVTOOLSET_ROOTPATH/usr/share/locale -mindepth 1 -maxdepth 1 -not \( -name 'en*' -or -name 'locale.alias' \) | xargs rm -rf
219-
fi
220-
rm -rf /usr/share/backgrounds
221-
# if we updated glibc, we need to strip locales again...
222-
localedef --list-archive | grep -v -i ^en_US.utf8 | xargs localedef --delete-from-archive
223-
mv -f /usr/lib/locale/locale-archive /usr/lib/locale/locale-archive.tmpl
224-
build-locale-archive
225-
find /usr/share/locale -mindepth 1 -maxdepth 1 -not \( -name 'en*' -or -name 'locale.alias' \) | xargs rm -rf
226-
find /usr/local/share/locale -mindepth 1 -maxdepth 1 -not \( -name 'en*' -or -name 'locale.alias' \) | xargs rm -rf
227-
rm -rf /usr/local/share/man

docker/build_scripts/build_env.sh

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,6 @@ PYTHON_DOWNLOAD_URL=https://www.python.org/ftp/python
44
# of the form <maj>.<min>.<rev> or <maj>.<min>.<rev>rc<n>
55
CPYTHON_VERSIONS="3.5.10 3.6.12 3.7.9 3.8.7 3.9.1"
66

7-
PATCHELF_VERSION=0.12
8-
PATCHELF_HASH=3dca33fb862213b3541350e1da262249959595903f559eae0fbc68966e9c3f56
9-
PATCHELF_DOWNLOAD_URL=https://github.com/NixOS/patchelf/archive
10-
11-
AUTOMAKE_ROOT=automake-1.16.2
12-
AUTOMAKE_HASH=b2f361094b410b4acbf4efba7337bdb786335ca09eb2518635a09fb7319ca5c1
13-
AUTOMAKE_DOWNLOAD_URL=http://ftp.gnu.org/gnu/automake
14-
15-
LIBTOOL_ROOT=libtool-2.4.6
16-
LIBTOOL_HASH=e3bd4d5d3d025a36c21dd6af7ea818a2afcd4dfc1ea5a17b39d7854bcd0c06e3
17-
LIBTOOL_DOWNLOAD_URL=http://ftp.gnu.org/gnu/libtool
18-
197
SQLITE_AUTOCONF_ROOT=sqlite-autoconf-3340000
208
SQLITE_AUTOCONF_HASH=bf6db7fae37d51754737747aaaf413b4d6b3b5fbacd52bdb2d0d6e5b2edd9aee
219
SQLITE_AUTOCONF_DOWNLOAD_URL=https://www.sqlite.org/2020
@@ -24,10 +12,6 @@ CMAKE_VERSION=3.18.3
2412
CMAKE_HASH=2c89f4e30af4914fd6fb5d00f863629812ada848eee4e2d29ec7e456d7fa32e5
2513
CMAKE_DOWNLOAD_URL=https://github.com/Kitware/CMake/releases/download
2614

27-
LIBXCRYPT_VERSION=4.4.17
28-
LIBXCRYPT_HASH=7665168d0409574a03f7b484682e68334764c29c21ca5df438955a381384ca07
29-
LIBXCRYPT_DOWNLOAD_URL=https://github.com/besser82/libxcrypt/archive
30-
3115
GIT_ROOT=git-2.30.0
3216
GIT_HASH=d24c4fa2a658318c2e66e25ab67cc30038a35696d2d39e6b12ceccf024de1e5e
3317
GIT_DOWNLOAD_URL=https://www.kernel.org/pub/software/scm/git
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# source me
2+
3+
PATCHELF_VERSION=0.12
4+
PATCHELF_HASH=3dca33fb862213b3541350e1da262249959595903f559eae0fbc68966e9c3f56
5+
PATCHELF_DOWNLOAD_URL=https://github.com/NixOS/patchelf/archive
6+
7+
AUTOMAKE_ROOT=automake-1.16.2
8+
AUTOMAKE_HASH=b2f361094b410b4acbf4efba7337bdb786335ca09eb2518635a09fb7319ca5c1
9+
AUTOMAKE_DOWNLOAD_URL=http://ftp.gnu.org/gnu/automake
10+
11+
LIBTOOL_ROOT=libtool-2.4.6
12+
LIBTOOL_HASH=e3bd4d5d3d025a36c21dd6af7ea818a2afcd4dfc1ea5a17b39d7854bcd0c06e3
13+
LIBTOOL_DOWNLOAD_URL=http://ftp.gnu.org/gnu/libtool
14+
15+
LIBXCRYPT_VERSION=4.4.17
16+
LIBXCRYPT_HASH=7665168d0409574a03f7b484682e68334764c29c21ca5df438955a381384ca07
17+
LIBXCRYPT_DOWNLOAD_URL=https://github.com/besser82/libxcrypt/archive

docker/build_scripts/build_utils.sh

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,25 +35,11 @@ function do_cpython_build {
3535
pushd Python-$py_ver
3636
local prefix="/opt/_internal/cpython-${py_ver}"
3737
mkdir -p ${prefix}/lib
38-
./configure --prefix=${prefix} --disable-shared > /dev/null
38+
./configure --prefix=${prefix} --disable-shared --with-ensurepip=no > /dev/null
3939
make -j$(nproc) > /dev/null
4040
make -j$(nproc) install > /dev/null
4141
popd
4242
rm -rf Python-$py_ver
43-
# Some python's install as bin/python3. Make them available as
44-
# bin/python.
45-
if [ -e ${prefix}/bin/python3 ] && [ ! -e ${prefix}/bin/python ]; then
46-
ln -s python3 ${prefix}/bin/python
47-
fi
48-
${prefix}/bin/python -m ensurepip
49-
if [ -e ${prefix}/bin/pip3 ] && [ ! -e ${prefix}/bin/pip ]; then
50-
ln -s pip3 ${prefix}/bin/pip
51-
fi
52-
# Since we fall back on a canned copy of pip, we might not have
53-
# the latest pip and friends. Upgrade them to make sure.
54-
${prefix}/bin/pip install -U --require-hashes -r ${MY_DIR}/requirements.txt
55-
local abi_tag=$(${prefix}/bin/python ${MY_DIR}/python-tag-abi-tag.py)
56-
ln -s ${prefix} /opt/python/${abi_tag}
5743
}
5844

5945

@@ -121,7 +107,7 @@ function build_git {
121107
fetch_source ${git_fname}.tar.gz ${GIT_DOWNLOAD_URL}
122108
check_sha256sum ${git_fname}.tar.gz ${git_sha256}
123109
tar -xzf ${git_fname}.tar.gz
124-
(cd ${git_fname} && make -j$(nproc) install prefix=/usr/local NO_GETTEXT=1 NO_TCLTK=1 > /dev/null)
110+
(cd ${git_fname} && make -j$(nproc) install prefix=/usr/local NO_GETTEXT=1 NO_TCLTK=1 DESTDIR=/manylinux-rootfs > /dev/null)
125111
rm -rf ${git_fname} ${git_fname}.tar.gz
126112
}
127113

0 commit comments

Comments
 (0)