Skip to content

Commit

Permalink
docker: Add ability to build shared library flavours of CPython.
Browse files Browse the repository at this point in the history
Enable via:

    MANYLINUX_BUILD_EXTRA="--build-arg PY_SHARED=1" \
    PLATFORM=$(uname -m) POLICY=manylinux2014 COMMIT_SHA=latest \
    ./build.sh

If set, builds both static & shared versions of CPython into the images.
Shared versions end up in (eg) /opt/python/cp37-cp37m-shared/ alongside the
existing static /opt/python/cp37-cp37m/, with a Python binary as
/usr/local/bin/python3.7-shared.
  • Loading branch information
rcoup committed Sep 15, 2021
1 parent b124c44 commit 232bd84
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 33 deletions.
2 changes: 2 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export LD_LIBRARY_PATH_ARG
BUILD_ARGS_COMMON="
--build-arg POLICY --build-arg PLATFORM --build-arg BASEIMAGE
--build-arg DEVTOOLSET_ROOTPATH --build-arg PREPEND_PATH --build-arg LD_LIBRARY_PATH_ARG
${MANYLINUX_BUILD_EXTRA-}
--rm -t quay.io/pypa/${POLICY}_${PLATFORM}:${COMMIT_SHA}
-f docker/Dockerfile docker/
"
Expand All @@ -95,6 +96,7 @@ elif [ "${MANYLINUX_BUILD_FRONTEND}" == "buildkit" ]; then
--export-cache type=local,dest=$(pwd)/.buildx-cache-staging-${POLICY}_${PLATFORM} \
--opt build-arg:POLICY=${POLICY} --opt build-arg:PLATFORM=${PLATFORM} --opt build-arg:BASEIMAGE=${BASEIMAGE} \
--opt "build-arg:DEVTOOLSET_ROOTPATH=${DEVTOOLSET_ROOTPATH}" --opt "build-arg:PREPEND_PATH=${PREPEND_PATH}" --opt "build-arg:LD_LIBRARY_PATH_ARG=${LD_LIBRARY_PATH_ARG}" \
${MANYLINUX_BUILD_EXTRA-} \
--output type=docker,name=quay.io/pypa/${POLICY}_${PLATFORM}:${COMMIT_SHA} | docker load
else
echo "Unsupported build frontend: '${MANYLINUX_BUILD_FRONTEND}'"
Expand Down
2 changes: 2 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ ARG PLATFORM=x86_64
ARG DEVTOOLSET_ROOTPATH=
ARG LD_LIBRARY_PATH_ARG=
ARG PREPEND_PATH=
ARG PY_SHARED=0

FROM $BASEIMAGE AS runtime_base
ARG POLICY
ARG PLATFORM
ARG DEVTOOLSET_ROOTPATH
ARG LD_LIBRARY_PATH_ARG
ARG PREPEND_PATH
ARG PY_SHARED
LABEL maintainer="The ManyLinux project"

ENV AUDITWHEEL_POLICY=${POLICY} AUDITWHEEL_ARCH=${PLATFORM} AUDITWHEEL_PLAT=${POLICY}_${PLATFORM}
Expand Down
83 changes: 53 additions & 30 deletions docker/build_scripts/build-cpython.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,36 +30,59 @@ fetch_source Python-${CPYTHON_VERSION}.tgz.asc ${CPYTHON_DOWNLOAD_URL}/${CPYTHON
gpg --import ${MY_DIR}/cpython-pubkeys.txt
gpg --verify Python-${CPYTHON_VERSION}.tgz.asc
tar -xzf Python-${CPYTHON_VERSION}.tgz
pushd Python-${CPYTHON_VERSION}
PREFIX="/opt/_internal/cpython-${CPYTHON_VERSION}"
mkdir -p ${PREFIX}/lib
if [ "${AUDITWHEEL_POLICY}" == "manylinux2010" ]; then
# The _ctypes stdlib module build started to fail with 3.10.0rc1
# No clue what changed exactly yet
# This workaround fixes the build
LIBFFI_INCLUDEDIR=$(pkg-config --cflags-only-I libffi | tr -d '[:space:]')
LIBFFI_INCLUDEDIR=${LIBFFI_INCLUDEDIR:2}
cp ${LIBFFI_INCLUDEDIR}/ffi.h ${LIBFFI_INCLUDEDIR}/ffitarget.h /usr/include/
fi
# configure with hardening options only for the interpreter & stdlib C extensions
# do not change the default for user built extension (yet?)
./configure \
CFLAGS_NODIST="${MANYLINUX_CFLAGS} ${MANYLINUX_CPPFLAGS}" \
LDFLAGS_NODIST="${MANYLINUX_LDFLAGS}" \
--prefix=${PREFIX} --disable-shared --with-ensurepip=no > /dev/null
make > /dev/null
make install > /dev/null
if [ "${AUDITWHEEL_POLICY}" == "manylinux2010" ]; then
rm -f /usr/include/ffi.h /usr/include/ffitarget.h
fi
popd
rm -rf Python-${CPYTHON_VERSION} Python-${CPYTHON_VERSION}.tgz Python-${CPYTHON_VERSION}.tgz.asc

# we don't need libpython*.a, and they're many megabytes
find ${PREFIX} -name '*.a' -print0 | xargs -0 rm -f
function build {
IS_SHARED=$1
pushd Python-${CPYTHON_VERSION}
PREFIX="/opt/_internal/cpython-${CPYTHON_VERSION}"
if [ ${IS_SHARED} -eq 1 ]; then
PREFIX="${PREFIX}-shared"
fi
mkdir -p ${PREFIX}/lib
if [ "${AUDITWHEEL_POLICY}" == "manylinux2010" ]; then
# The _ctypes stdlib module build started to fail with 3.10.0rc1
# No clue what changed exactly yet
# This workaround fixes the build
LIBFFI_INCLUDEDIR=$(pkg-config --cflags-only-I libffi | tr -d '[:space:]')
LIBFFI_INCLUDEDIR=${LIBFFI_INCLUDEDIR:2}
cp ${LIBFFI_INCLUDEDIR}/ffi.h ${LIBFFI_INCLUDEDIR}/ffitarget.h /usr/include/
fi
# configure with hardening options only for the interpreter & stdlib C extensions
# do not change the default for user built extension (yet?)
if [ ${IS_SHARED} -eq 1 ]; then
FLAVOR="--enable-shared"
FLAVOR_LDFLAGS="-Wl,-rpath=${PREFIX}/lib"
else
FLAVOR="--disable-shared"
FLAVOR_LDFLAGS=
fi

./configure \
CFLAGS_NODIST="${MANYLINUX_CFLAGS} ${MANYLINUX_CPPFLAGS}" \
LDFLAGS_NODIST="${MANYLINUX_LDFLAGS} ${FLAVOR_LDFLAGS}" \
--prefix=${PREFIX} ${FLAVOR} --with-ensurepip=no > /dev/null
make > /dev/null
make install > /dev/null
if [ "${AUDITWHEEL_POLICY}" == "manylinux2010" ]; then
rm -f /usr/include/ffi.h /usr/include/ffitarget.h
fi
popd

if [ ${IS_SHARED} -eq 0 ]; then
# we don't need libpython*.a, and they're many megabytes
find ${PREFIX} -name '*.a' -print0 | xargs -0 rm -f
fi

# We do not need precompiled .pyc and .pyo files.
clean_pyc ${PREFIX}
# We do not need precompiled .pyc and .pyo files.
clean_pyc ${PREFIX}

# Strip ELF files found in ${PREFIX}
strip_ ${PREFIX}
# Strip ELF files found in ${PREFIX}
strip_ ${PREFIX}
}

build 0
if [ ${PY_SHARED-0} -eq 1 ]; then
build 1
fi

rm -rf Python-${CPYTHON_VERSION} Python-${CPYTHON_VERSION}.tgz Python-${CPYTHON_VERSION}.tgz.asc
14 changes: 11 additions & 3 deletions docker/build_scripts/finalize.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ source $MY_DIR/build_utils.sh

mkdir /opt/python
for PREFIX in $(find /opt/_internal/ -mindepth 1 -maxdepth 1 \( -name 'cpython*' -o -name 'pypy*' \)); do
if [[ "${PREFIX}" =~ -shared$ ]]; then
SUFFIX=-shared
else
SUFFIX=
fi

# Some python's install as bin/python3. Make them available as
# bin/python.
if [ -e ${PREFIX}/bin/python3 ] && [ ! -e ${PREFIX}/bin/python ]; then
Expand All @@ -24,14 +30,16 @@ for PREFIX in $(find /opt/_internal/ -mindepth 1 -maxdepth 1 \( -name 'cpython*'
# Since we fall back on a canned copy of pip, we might not have
# the latest pip and friends. Upgrade them to make sure.
${PREFIX}/bin/pip install -U --require-hashes -r ${MY_DIR}/requirements${PY_VER}.txt

# Create a symlink to PREFIX using the ABI_TAG in /opt/python/

ABI_TAG=$(${PREFIX}/bin/python ${MY_DIR}/python-tag-abi-tag.py)
ln -s ${PREFIX} /opt/python/${ABI_TAG}
ln -s ${PREFIX} /opt/python/${ABI_TAG}${SUFFIX:-}
# Make versioned python commands available directly in environment.
if [[ "${PREFIX}" == *"/pypy"* ]]; then
ln -s ${PREFIX}/bin/python /usr/local/bin/pypy${PY_VER}
ln -s ${PREFIX}/bin/python /usr/local/bin/pypy${PY_VER}${SUFFIX}
else
ln -s ${PREFIX}/bin/python /usr/local/bin/python${PY_VER}
ln -s ${PREFIX}/bin/python /usr/local/bin/python${PY_VER}${SUFFIX}
fi
done

Expand Down

0 comments on commit 232bd84

Please sign in to comment.