Skip to content

Instantly share code, notes, and snippets.

@jacky9813
Last active June 26, 2024 12:36
Show Gist options
  • Save jacky9813/619d2eff88c080de9402924e46fc55f7 to your computer and use it in GitHub Desktop.
Save jacky9813/619d2eff88c080de9402924e46fc55f7 to your computer and use it in GitHub Desktop.

Building Python 3.11

This article focuses on building CPython for common Linux server operating systems.

These scripts will be tested in fresh Docker container.

I'll install dependencies from package manager if possible, or I'll try compile myself if that makes sense.

The dependencies doesn't change much between these CPython versions, so Python 3.12 and 3.10 may have the exact same process. (Obviously the link and the filename in the script must be changed.)

All examples, unless --prefix is set, uses altinstall target for installing Python onto the system, which will install CPython into /usr/local by default and will not affect default python or python3 command.

Operating Systems

Distro Note
Debian 10+, Ubuntu 18.04+ (For Ubuntu 18.04) Additional info required by pkgconfig.
CentOS 7 Additional info required by pkgconfig.
CentOS uses tk 8.5, while Python 3.10 and later uses tk 8.6 by default.
Rocky Linux 8
Rocky Linux 9
openSUSE Leap 15
openSUSE Leap 42 Building OpenSSL 1.1.1 or later version is required.
Alpine Linux 3.18

Debian 10+, Ubuntu 18.04+

Normal Install

Tested in debian:buster and ubuntu:18.04.

#!/bin/bash
PYTHON_VERSION=3.12.0
TZ=Etc/UTC
source /etc/os-release

ln -s /usr/share/zoneinfo/$TZ /etc/localtime
echo $TZ > /etc/timezone

apt update
echo "" | apt upgrade -y
echo "" | apt install -y libncurses-dev libbz2-dev libgdbm-dev liblzma-dev libssl-dev tk-dev \
               uuid-dev libreadline-dev libsqlite3-dev libffi-dev gcc make automake \
               wget libgdbm-dev libgdbm-compat-dev

wget https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz
tar -xvf Python-${PYTHON_VERSION}.tgz
cd Python-${PYTHON_VERSION}

if [ "$ID" == "ubuntu" ] && [ "$VERSION_ID" == "18.04" ]; then
# For some reason, both tk-dev and tcl-dev doesn't include their pkgconfig files.
# Although I can make a PR to the Python repo, it just doesn't make any sense for creating an
# PR for an unsupported verison of Ubuntu. Hence I just post it here.
mkdir -p Misc/ubuntu18.04
cat << EOF > Misc/ubuntu18.04/tcl.pc
# tcl pkg-config source file

prefix=/usr
exec_prefix=/usr
libdir=/usr/lib/$(dpkg-architecture -q DEB_BUILD_GNU_TYPE)
includedir=/usr/include/tcl8.6

Name: Tool Command Language
Description: Tcl is a powerful, easy-to-learn dynamic programming language, suitable for a wide range of uses.
URL: http://www.tcl.tk/
Version: 8.6
Requires.private: zlib >= 1.2.3
Libs: -L\${libdir} -ltcl8.6 -ltclstub8.6
Libs.private: -ldl -lz  -lpthread -lm
Cflags: -I\${includedir}
EOF

cat << EOF > Misc/ubuntu18.04/tk.pc
# tk pkg-config source file

prefix=/usr
exec_prefix=/usr
libdir=/usr/lib/$(dpkg-architecture -q DEB_BUILD_GNU_TYPE)
includedir=/usr/include/tcl8.6

Name: The Tk Toolkit
Description: Tk is a cross-platform graphical user interface toolkit, the standard GUI not only for Tcl, but for many other dynamic languages as well.
URL: https://www.tcl-lang.org/
Version: 8.6
Requires: tcl >= 8.6
Libs: -L\${libdir} -ltk8.6 -ltkstub8.6
Libs.private: -lXft -lfontconfig -lfreetype -lfontconfig -lX11 -lXss -lXext
Cflags: -I\${includedir}
EOF

export PKG_CONFIG_PATH=$(pwd)/Misc/ubuntu18.04

fi

./configure --enable-loadable-sqlite-extensions
make -j$(nproc)
make altinstall

Testing (Before make altinstall)

#!/bin/bash
apt install -y locales locales-all gdb g++
make test
== Tests result: SUCCESS ==

466 tests OK.

11 tests skipped:
    test.test_asyncio.test_windows_events
    test.test_asyncio.test_windows_utils test_devpoll test_ioctl
    test_kqueue test_launcher test_msilib test_startfile
    test_winconsoleio test_winreg test_wmi

6 tests skipped (resource denied):
    test_ossaudiodev test_tix test_tkinter test_ttk test_winsound
    test_zipfile64

Total duration: 1 min 15 sec
Total tests: run=41,575 skipped=1,482
Total test files: run=477/483 skipped=11 resource_denied=6
Result: SUCCESS

CentOS 7

Tested on centos:7

The script should work with RHEL7 based systems.

Update on Jun 26, 2023: Thanks to the decision from Red Hat, I'm no longer sure if RHEL-derived system will work anymore since I have no intension to apply Red Hat developer subscription. Also, well done to someone that came up with that decision, making Canonical's Ubuntu Server more attractive for enterprise users than ever.

  • Note: _tkinter module is not available because Python 3.11 requires tk 8.6, while package tk-devel is using tk 8.5.

Build RPM

Checkout my repo about building Python 3.10 for EL7.

That being said, since that is focus on Python 3.10, it may require changes here and there, so use it carefully.

Normal Install

#!/bin/bash
PYTHON_VERSION=3.11.5

yum install -y epel-release
yum install -y ncurses-devel bzip2-devel gdbm-devel libnsl2-devel xz-devel \
                    libuuid-devel readline-devel sqlite-devel libffi-devel \
                    openssl11-devel gcc make automake wget perl-core pkgconfig
wget https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz
tar -xvf Python-${PYTHON_VERSION}.tgz
pushd Python-${PYTHON_VERSION}
# Hats off to Yebolin https://github.com/pyenv/pyenv/issues/2416#issuecomment-1207579730
# openssl11-devel is in epel
export CFLAGS="$CFLAGS $(pkg-config --cflags openssl11)"
export LDFLAGS="$LDFLAGS $(pkg-config --libs openssl11)"
./configure --enable-loadable-sqlite-extensions
make -j$(nproc)
make altinstall
popd

Testing (Before make altinstall)

#!/bin/bash

yum install -y gcc-c++

pushd /usr/share/i18n/charmaps
for charmap_file in $(ls *.gz); do
    gzip -d $charmap_file
done
popd

pushd Lib/test
TESTED_LOCALES=$(../../python -c 'import test__locale; print(" ".join(test__locale.candidate_locales))')
popd

# Building Locales for testing
for locale_id in $TESTED_LOCALES; do
    locale=$(echo $locale_id | sed 's/\..*//')
    charmap=$(echo $locale_id | grep '\.' | sed 's/^.*\.//' | sed 's/@.*//')
    variant=$(echo $locale_id | grep '@' | sed 's/.*@//')
    charmap=${charmap:-UTF-8}
    
    if echo $charmap | grep -E '^euc[A-Z]+$' &>/dev/null ; then
        charmap=$(echo $charmap | sed -E 's/euc([A-Z]+)/EUC-\1/')
    fi
    
    if echo $charmap | grep -E 'ISO[0-9]+.*' &>/dev/null ; then
        charmap=$(echo $charmap | sed 's/^ISO/ISO-/')
    fi
    
    echo "Building locale $locale_id"
    if ! [ -z "$variant" ]; then 
        localedef -f ${charmap} -i ${locale}@${variant} $locale_id
    else
        localedef -f ${charmap} -i $locale $locale_id
    fi
done

make test
== Tests result: FAILURE then SUCCESS ==

415 tests OK.

19 tests skipped:
    test_devpoll test_gdb test_idle test_ioctl test_kqueue
    test_launcher test_msilib test_ossaudiodev test_startfile test_tcl
    test_tix test_tk test_ttk_guionly test_ttk_textonly test_turtle
    test_winconsoleio test_winreg test_winsound test_zipfile64

1 re-run test:
    test_nntplib

Total duration: 4 min 6 sec
Tests result: FAILURE then SUCCESS
  • test_gdb will be ignored as test script detects CentOS 7 official gdb package is compiled with Python 2.

Distributable Tarball

Build

#!/bin/bash
source /etc/os-release
PYTHON_VERSION=3.11.5
OPENSSL_VERSION=1.1.1w
OPENSSL_SHA256=cf3098950cb4d853ad95c0841f1f9c6d3dc102dccfcacd521d93925208b76ac8

yum install -y epel-release
yum install -y ncurses-devel bzip2-devel gdbm-devel xz-devel zlib-devel \
                    libuuid-devel readline-devel sqlite-devel libffi-devel \
                    gcc make automake perl-core pkgconfig nasm curl
                    
# For unknown reason, build process wouldn't pick up openssl11-devel package
# when prefix is set.
# I have to build my own OpenSSL here.

# Also, the certificate for www.openssl.org cannot be verified by
# curl or wget for some reason.
curl -Ok https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz
if echo "${OPENSSL_SHA256}  openssl-${OPENSSL_VERSION}.tar.gz" | sha256sum -c; then
    tar xvf openssl-${OPENSSL_VERSION}.tar.gz
    pushd openssl-${OPENSSL_VERSION}
    ./config --prefix=/opt/python/${PYTHON_VERSION}-el${VERSION_ID}.$(uname -m) --openssldir=/opt/python/${PYTHON_VERSION}-el${VERSION_ID}.$(uname -m)
    make -j$(nproc)
    make install_sw
    popd
else
    echo "SHA256 check failed"
    exit 1
fi
              
# Build Python
curl -O https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz
tar -xvf Python-${PYTHON_VERSION}.tgz
pushd Python-${PYTHON_VERSION}
./configure \
    --enable-loadable-sqlite-extensions \
    --prefix=/opt/python/${PYTHON_VERSION}-el${VERSION_ID}.$(uname -m) \
    --with-openssl=/opt/python/${PYTHON_VERSION}-el${VERSION_ID}.$(uname -m) \
    --with-openssl-rpath=auto
make -j$(nproc)
make install
popd

Install

#!/bin/bash

# Basic setup
source /etc/os-release
PYTHON_INSTALL_BASE=/opt/python
PYTHON_VERSION=3.10
PYTHON_FULL_VERSION=${PYTHON_VERSION}.13
PYTHON_INSTALL_VERSION=${PYTHON_FULL_VERSION}-el${VERSION_ID}.$(uname -m)

# Make this variable empty for not to create symbolic link to installed Python
# MKLINK_TO_LOCAL_BIN=
MKLINK_TO_LOCAL_BIN=1

if ! [ -d ${PYTHON_INSTALL_BASE}/${PYTHON_INSTALL_VERSION} ]; then
    # Installing dependencies
    yum install -y epel-release
    # It is not required to install openssl11-libs as OpenSSL 1.1.1 came bundled.
    yum install -y ncurses-libs bzip2-libs gdbm xz-libs libuuid readline sqlite libffi

    # Install Python
    install -d ${PYTHON_INSTALL_BASE}
    tar xvf python-${PYTHON_INSTALL_VERSION}.tar.gz -C ${PYTHON_INSTALL_BASE}

    # Configure PATH
    echo "export PATH=\"\$PATH:${PYTHON_INSTALL_BASE}/${PYTHON_INSTALL_VERSION}/bin\"" | tee /etc/profile.d/python3.10.sh
    . /etc/profile
    if [ -f ~/.bashrc ]; then
        . ~/.bashrc
    fi
    
    if ! [ -z "$MKLINK_TO_LOCAL_BIN" ]; then
        for program in 2to3-3.10 pip3.10 pydoc3.10 python3.10 python3.10-config; do
            if [ -L /usr/local/bin/${program} ] ; then
                rm -rv /usr/local/bin/${program}
            fi
            ln -sv ${PYTHON_INSTALL_BASE}/${PYTHON_INSTALL_VERSION}/bin/${program} /usr/local/bin/${program}
        done
    fi
    
    # Links for pkgconfig
    LIB=lib
    if uname -m | grep 64 > /dev/null && [ -d /usr/lib64/pkgconfig ] ; then
        LIB=lib64
    fi
    ln -sv ${PYTHON_INSTALL_BASE}/${PYTHON_INSTALL_VERSION}/lib/pkgconfig/python-3.10.pc /usr/${LIB}/pkgconfig/python-3.10.pc
    
    # Links for includes
    if [ -L /usr/local/include/python${PYTHON_VERSION} ]; then
        rm -fv /usr/local/include/python${PYTHON_VERSION}
    fi
    ln -sv ${PYTHON_INSTALL_BASE}/${PYTHON_INSTALL_VERSION}/include/python${PYTHON_VERSION} /usr/local/include/python${PYTHON_VERSION}
    
    # Install man page for python if system has man and no python pages available.
    if which man &> /dev/null && ! man -k python &> /dev/null ; then
        ln -sv $(find ${PYTHON_INSTALL_BASE}/${PYTHON_INSTALL_VERSION}/share/man/man1 -type f) /usr/local/share/man/man1/python${PYTHON_VERSION}
    fi
else
    echo ${PYTHON_INSTALL_VERSION} has already been installed.
fi

Rocky Linux 8

IMPORTANT: EL8, or at least Rocky Linux 8, has python3.11 package in App Stream repo. BEWARE THAT IT MAY GET VERY CONFUSING IF MULTIPLE PYTHON 3.11 BUILDS ARE INSTALLED.

Tested in rockylinux:8

The script should work in RHEL8 based systems.

Update on Jun 26, 2023: Thanks to the decision from Red Hat, I'm no longer sure if RHEL-derived system will work anymore since I have no intension to apply Red Hat developer subscription. Also, well done to someone that came up with that decision, making Canonical's Ubuntu Server more attractive for enterprise users than ever.

#!/bin/bash
PYTHON_VERSION=3.11.5

# libnsl2-devel in PowerTools for Rocky Linux 8
dnf install -y 'dnf-command(config-manager)'
dnf config-manager --set-enabled powertools
dnf install -y ncurses-devel bzip2-devel gdbm-devel libnsl2-devel xz-devel \
                    openssl-devel tk-devel libuuid-devel readline-devel sqlite-devel \
                    libffi-devel gcc make automake wget
wget https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz
tar -xvf Python-${PYTHON_VERSION}.tgz
cd Python-${PYTHON_VERSION}
./configure --enable-loadable-sqlite-extensions
make -j$(nproc)
make altinstall

Testing (Before make altinstall)

dnf install -y gdb gcc-c++ glibc-locale-source findutils

pushd /usr/share/i18n/charmaps
for charmap_file in $(ls *.gz); do
    gzip -d $charmap_file
done
popd

pushd Lib/test
TESTED_LOCALES=$(../../python -c 'import test__locale; print(" ".join(test__locale.candidate_locales))')
popd

# Building Locales for testing
for locale_id in $TESTED_LOCALES; do
    locale=$(echo $locale_id | sed 's/\..*//')
    charmap=$(echo $locale_id | grep '\.' | sed 's/^.*\.//' | sed 's/@.*//')
    variant=$(echo $locale_id | grep '@' | sed 's/.*@//')
    charmap=${charmap:-UTF-8}
    
    if echo $charmap | grep -E '^euc[A-Z]+$' &>/dev/null ; then
        charmap=$(echo $charmap | sed -E 's/euc([A-Z]+)/EUC-\1/')
    fi
    
    if echo $charmap | grep -E 'ISO[0-9]+.*' &>/dev/null ; then
        charmap=$(echo $charmap | sed 's/^ISO/ISO-/')
    fi
    
    echo "Building locale $locale_id"
    if ! [ -z "$variant" ]; then 
        localedef -f ${charmap} -i ${locale}@${variant} $locale_id
    else
        localedef -f ${charmap} -i $locale $locale_id
    fi
done

dnf install -y glibc-langpack-*

make test
== Tests result: FAILURE then FAILURE ==

419 tests OK.

1 test failed:
    test__locale

14 tests skipped:
    test_devpoll test_ioctl test_kqueue test_launcher test_msilib
    test_ossaudiodev test_startfile test_tix test_tk test_ttk_guionly
    test_winconsoleio test_winreg test_winsound test_zipfile64

2 re-run tests:
    test__locale test_tools

Total duration: 3 min 2 sec
Tests result: FAILURE then FAILURE
  • I'm having problem getting test__locale working, with or without glibc-langpack-* installed.

Rocky Linux 9

IMPORTANT: EL9, or at least Rocky Linux 9, has python3.11 package in App Stream repo. BEWARE THAT IT MAY GET VERY CONFUSING IF MULTIPLE PYTHON 3.11 BUILDS ARE INSTALLED.

Tested in rockylinux:9

The script should work in RHEL9 based systems.

Update on Jun 26, 2023: Thanks to the decision from Red Hat, I'm no longer sure if RHEL-derived system will work anymore since I have no intension to apply Red Hat developer subscription. Also, well done to someone that came up with that decision, making Canonical's Ubuntu Server more attractive for enterprise users than ever.

#!/bin/bash
PYTHON_VERSION=3.11.5

# gdbm-devel and libnsl2-devel in CRB for Rocky Linux 9
dnf install -y 'dnf-command(config-manager)'
dnf config-manager --set-enabled crb
dnf install -y ncurses-devel bzip2-devel gdbm-devel libnsl2-devel xz-devel \
               openssl-devel tk-devel libuuid-devel readline-devel sqlite-devel \
               libffi-devel gcc make automake wget
wget https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz
tar -xvf Python-${PYTHON_VERSION}.tgz
cd Python-${PYTHON_VERSION}
./configure --enable-loadable-sqlite-extensions
make -j$(nproc)
make altinstall

Testing (before make install)

dnf install -y gdb gcc-c++ findutils glibc-locale-source

pushd /usr/share/i18n/charmaps
for charmap_file in $(ls *.gz); do
    gzip -d $charmap_file
done
popd

pushd Lib/test
TESTED_LOCALES=$(../../python -c 'import test__locale; print(" ".join(test__locale.candidate_locales))')
popd

# Building Locales for testing
for locale_id in $TESTED_LOCALES; do
    locale=$(echo $locale_id | sed 's/\..*//')
    charmap=$(echo $locale_id | grep '\.' | sed 's/^.*\.//' | sed 's/@.*//')
    variant=$(echo $locale_id | grep '@' | sed 's/.*@//')
    charmap=${charmap:-UTF-8}
    
    if echo $charmap | grep -E '^euc[A-Z]+$' &>/dev/null ; then
        charmap=$(echo $charmap | sed -E 's/euc([A-Z]+)/EUC-\1/')
    fi
    
    if echo $charmap | grep -E 'ISO[0-9]+.*' &>/dev/null ; then
        charmap=$(echo $charmap | sed 's/^ISO/ISO-/')
    fi
    
    echo "Building locale $locale_id"
    if ! [ -z "$variant" ]; then 
        localedef -f ${charmap} -i ${locale}@${variant} $locale_id
    else
        localedef -f ${charmap} -i $locale $locale_id
    fi
done

dnf install -y glibc-langpack-*

make test
== Tests result: FAILURE then FAILURE ==

419 tests OK.

1 test failed:
    test__locale

14 tests skipped:
    test_devpoll test_ioctl test_kqueue test_launcher test_msilib
    test_ossaudiodev test_startfile test_tix test_tk test_ttk_guionly
    test_winconsoleio test_winreg test_winsound test_zipfile64

1 re-run test:
    test__locale

Total duration: 2 min 39 sec
Tests result: FAILURE then FAILURE
  • Just like Rocky Linux 8, having problem getting test__locale working.

openSUSE Leap 15

IMPORTANT: SUSE 15 has python311 package in Updates from SLES 15 repo. BEWARE THAT IT MAY GET VERY CONFUSING IF MULTIPLE PYTHON 3.11 BUILDS ARE INSTALLED.

Tested in opensuse/leap:15.5.

PYTHON_VERSION=3.11.5

zypper install -y ncurses-devel libbz2-devel gdbm-devel libnsl-devel xz-devel \
                       libopenssl-3-devel tk-devel libuuid-devel readline-devel \
                       sqlite3-devel libffi-devel gcc make automake wget tar gzip
wget https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz
tar -xvf Python-${PYTHON_VERSION}.tgz
cd Python-${PYTHON_VERSION}
./configure --enable-loadable-sqlite-extensions
make -j$(nproc)

make altinstall

Test

#!/bin/bash
# within compiled source directory
zypper install -y gdb glibc-locale gcc-c++
make test
== Tests result: FAILURE then SUCCESS ==

420 tests OK.

14 tests skipped:
    test_devpoll test_ioctl test_kqueue test_launcher test_msilib
    test_ossaudiodev test_startfile test_tix test_tk test_ttk_guionly
    test_winconsoleio test_winreg test_winsound test_zipfile64

3 re-run tests:
    test___all__ test_nntplib test_tools

Total duration: 5 min 22 sec
Tests result: FAILURE then SUCCESS

openSUSE Leap 42

Tested in Docker image opensuse/leap:42.3.

openSUSE Leap 42 doesn't have OpenSSL 1.1.1 in its official repository, thus we'll build our own OpenSSL.

Normal Install

#!/bin/bash
PYTHON_VERSION=3.11.5

zypper install -y libffi-devel-gcc5 ncurses-devel libbz2-devel gdbm-devel libnsl-devel \
                  xz-devel tk-devel libuuid-devel readline-devel sqlite3-devel gcc make \
                  automake tar gzip curl nasm

curl -LOk https://www.openssl.org/source/openssl-1.1.1w.tar.gz
tar xf openssl-1.1.1w.tar.gz
pushd openssl-1.1.1w
./config
make -j$(nproc)
make install_sw
popd

curl -LO https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz
tar xf Python-${PYTHON_VERSION}.tgz
pushd Python-${PYTHON_VERSION}
./configure \
    --enable-loadable-sqlite-extensions \
    --with-openssl=/usr/local/ssl \
    --with-openssl-rpath=auto
make -j$(nproc)
make install
popd

Testing

#!/bin/bash
# within compiled source directory
zypper install -y glibc-locale gcc-c++
make test
== Tests result: FAILURE then SUCCESS ==

419 tests OK.

15 tests skipped:
    test_devpoll test_gdb test_ioctl test_kqueue test_launcher
    test_msilib test_ossaudiodev test_startfile test_tix test_tk
    test_ttk_guionly test_winconsoleio test_winreg test_winsound
    test_zipfile64

1 re-run test:
    test_nntplib

Total duration: 4 min 54 sec
Tests result: FAILURE then SUCCESS
  • test_gdb will be ignored as test script detects openSUSE official gdb package is compiled with Python 2.

TAR ball

#!/bin/bash
PYTHON_VERSION=3.11.5
PYTHON_BUILD=opensuse42-$(uname -m)
PYTHON_PREFIX=/opt/python/${PYTHON_VERSION}-${PYTHON_BUILD}

zypper install -y libffi-devel-gcc5 ncurses-devel libbz2-devel gdbm-devel libnsl-devel \
                  xz-devel tk-devel libuuid-devel readline-devel sqlite3-devel gcc make \
                  automake tar gzip curl nasm

curl -LOk https://www.openssl.org/source/openssl-1.1.1w.tar.gz
tar xf openssl-1.1.1w.tar.gz
pushd openssl-1.1.1w
./config --prefix=${PYTHON_PREFIX} --openssldir=${PYTHON_PREFIX}
make -j$(nproc)
make install_sw
popd

curl -LO https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz
tar xf Python-${PYTHON_VERSION}.tgz
pushd Python-${PYTHON_VERSION}
./configure \
    --enable-loadable-sqlite-extensions \
    --with-openssl=${PYTHON_PREFIX} \
    --with-openssl-rpath=auto \
    --prefix=${PYTHON_PREFIX}
make -j$(nproc)
make install
popd

CURRENT_DIR="$(pwd)"
pushd ${PYTHON_PREFIX}/..
tar czf "${CURRENT_DIR}/python-${PYTHON_VERSION}-${PYTHON_BUILD}.tar.gz" ${PYTHON_VERSION}-${PYTHON_BUILD}
popd

When unpacking python-${PYTHON_VERSION}-${PYTHON_BUILD}.tar.gz, user should always unpack it into /opt/python to prevent shared objects not being found.

Also, the target system may require install libffi4 package.

For example:

#!/bin/bash
zypper install -y libffi4
mkdir -p /opt/python
tar -xzvf python-3.11.5-opensuse42-x86_64.tar.gz -C /opt/python
export PATH="$PATH:/opt/python/3.11.5-opensuse42-x86_64/bin"

Alpine Linux 3.18

IMPORTANT: Alpine has python3 package that can be Python 3.11. BEWARE THAT IT MAY GET VERY CONFUSING IF MULTIPLE PYTHON 3.11 BUILDS ARE INSTALLED.

Tested with alpine:3.18.

The package release cycle for Alpine Linux is really fast, consider using apk add python3 to install officially supported Python.

apk add musl-dev ncurses-dev bzip2-dev gdbm-dev libnsl-dev xz-dev openssl3-dev tk-dev libuuid \
        readline-dev sqlite-dev libffi-dev gcc make automake wget tar gzip
wget https://www.python.org/ftp/python/3.11.0/Python-3.11.0.tgz
tar -xvf Python-3.11.0.tgz
cd Python-3.11.0
./configure --enable-loadable-sqlite-extensions
make -j$(nproc)
make altinstall

Testing (before make altinstall)

#!/bin/sh
apk add gdb g++ musl-locales musl-locales-lang
make test
== Tests result: FAILURE then FAILURE ==

415 tests OK.

5 tests failed:
    test__locale test_c_locale_coercion test_locale test_os test_re

14 tests skipped:
    test_devpoll test_ioctl test_kqueue test_launcher test_msilib
    test_ossaudiodev test_startfile test_tix test_tk test_ttk_guionly
    test_winconsoleio test_winreg test_winsound test_zipfile64

6 re-run tests:
    test__locale test_c_locale_coercion test_locale test_os test_re
    test_tools

Total duration: 3 min 26 sec
Tests result: FAILURE then FAILURE
  • Seems like CPython doesn't like i18n implementation in musl, all failures are related to locales and charmaps.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment