#!/bin/bash # Copyright 2026, Kay Hayen, mailto:kay.hayen@gmail.com find license text at end of file set -e # Exit immediately if a command exits with a non-zero status. # --- Configuration --- # Set the Python version you want to build. # Using a specific, stable patch release is recommended. PY_VER="3.11.9" # Default set after arguments if not provided INSTALL_PREFIX="" PY_MAJOR_MINOR=$(echo "$PY_VER" | cut -d. -f1-2) # e.g., 3.11 TARBALL="Python-$PY_VER.tar.xz" SOURCE_DIR="Python-$PY_VER" BUILD_CONFIG="Release" BUILD_TARGET="Build" EXTRA_CONFIGURE_OPTS="--enable-optimizations --with-lto" CLEANUP=false while [[ "$#" -gt 0 ]]; do case $1 in --*=*) # Convert --key=value to --key value KEY="${1%%=*}" VALUE="${1#*=}" shift 1 set -- "$KEY" "$VALUE" "$@" continue ;; --debug) BUILD_CONFIG="Debug" # In debug mode, we disable PGO/LTO and enable pydebug, which includes assertions EXTRA_CONFIGURE_OPTS="--with-pydebug --without-lto" shift ;; --rebuild) BUILD_TARGET="Rebuild" shift ;; --version|--python-version) PY_VER="$2" TARBALL="Python-$PY_VER.tar.xz" SOURCE_DIR="Python-$PY_VER" shift 2 ;; --prefix) if [[ "$2" == /* ]]; then INSTALL_PREFIX="$2" elif [[ "$2" == ~* ]]; then INSTALL_PREFIX="${2/#\~/$HOME}" else INSTALL_PREFIX="$PWD/$2" fi shift 2 ;; --cleanup) CLEANUP=true shift ;; --help|-h) echo "Usage: $0 [OPTIONS]" echo "" echo "Options:" echo " --help, -h Show this help message and exit" echo " --version Specify the Python version to build (default: 3.11.9)" echo " --prefix Installation directory (default: /opt/python)" echo " --debug Build with pydebug and without PGO/LTO" echo " --rebuild Clean existing build before compiling" echo " --cleanup Remove the downloaded archive and source directory after successful build" exit 0 ;; *) echo "Unknown parameter passed: $1" echo "Use --help for usage information." exit 1 ;; esac done echo "--- Starting static Python $PY_VER build for Nuitka ---" echo "Configuration: $BUILD_CONFIG" if [[ "$BUILD_CONFIG" == "Release" ]]; then echo "PGO is Enabled." else echo "PGO is Disabled. Assertions are Enabled." fi if [[ "$(uname)" == "Linux" ]]; then SUDO="" if [ "$(id -u)" -ne 0 ] && command -v sudo >/dev/null 2>&1; then SUDO="sudo" fi # --- Linux Dependencies --- if command -v apt-get >/dev/null 2>&1; then echo "Installing Linux dependencies via apt-get..." $SUDO apt-get update && $SUDO apt-get install -y curl wget build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libsqlite3-dev libssl-dev libreadline-dev libffi-dev gdb ccache elif command -v yum >/dev/null 2>&1; then echo "Installing Linux dependencies via yum..." $SUDO yum -y install curl wget gcc gcc-c++ make zlib-devel ncurses-devel gdbm-devel nss-devel sqlite-devel openssl-devel readline-devel libffi-devel gdb ccache elif command -v dnf >/dev/null 2>&1; then echo "Installing Linux dependencies via dnf..." $SUDO dnf -y install curl wget gcc gcc-c++ make zlib-devel ncurses-devel gdbm-devel nss-devel sqlite-devel openssl-devel readline-devel libffi-devel gdb ccache else echo "Warning: Could not detect package manager. Please ensure build dependencies are installed." fi # Set flags for Linux if needed export MAKE_JOBS=$(nproc) if [ -n "$INSTALL_PREFIX" ]; then export PYTHON_BINARY="$INSTALL_PREFIX/bin/python3" else export PYTHON_BINARY="$PWD/$SOURCE_DIR/python" fi else echo "Unsupported OS: $(uname)" exit 1 fi # --- 2. Download and Extract Source --- if [ ! -f "$TARBALL" ]; then echo "Downloading $TARBALL..." URL="https://www.python.org/ftp/python/$PY_VER/$TARBALL" if command -v wget >/dev/null 2>&1; then echo "Using wget to download..." wget -q -O "$TARBALL" "$URL" elif command -v curl >/dev/null 2>&1; then echo "wget not found. Using curl to download..." curl -sL -o "$TARBALL" "$URL" else echo "Error: Neither wget nor curl is available on this system." >&2 exit 1 fi else echo "Using existing $TARBALL..." fi if [ -d "$SOURCE_DIR" ]; then echo "Using existing source directory $SOURCE_DIR..." else echo "Extracting $TARBALL..." tar -xf "$TARBALL" fi # --- 3. Configure Build --- cd "$SOURCE_DIR" if [ "$BUILD_TARGET" == "Rebuild" ] && [ -f "Makefile" ]; then echo "Rebuild requested. Cleaning existing build..." make clean || true rm -f Makefile fi if [ ! -f "Makefile" ]; then echo "Configuring build with optimizations and static linking..." PY_MAJOR=$(echo "$PY_VER" | cut -d. -f1) PY_MINOR=$(echo "$PY_VER" | cut -d. -f2) if [ "$PY_MAJOR" -gt 3 ] || { [ "$PY_MAJOR" -eq 3 ] && [ "$PY_MINOR" -ge 6 ]; }; then if [[ "$BUILD_CONFIG" == "Release" ]]; then EXTRA_CONFIGURE_OPTS="$EXTRA_CONFIGURE_OPTS --with-assertions" fi fi if [ -n "$INSTALL_PREFIX" ]; then CONFIGURE_PREFIX_OPTS="--prefix=$INSTALL_PREFIX" else CONFIGURE_PREFIX_OPTS="" fi ./configure \ $CONFIGURE_PREFIX_OPTS \ --disable-shared \ --enable-ipv6 \ LDFLAGS="-Xlinker -export-dynamic -rdynamic" \ $EXTRA_CONFIGURE_OPTS else echo "Makefile exists, skipping configure for incremental build..." fi # --- 4. Build and Install --- echo "Building Python... This will take a long time due to PGO." make -j$MAKE_JOBS LDFLAGS="-Xlinker -export-dynamic -rdynamic" if [ -n "$INSTALL_PREFIX" ]; then if [ -w "$INSTALL_PREFIX" ] || [ -w "$(dirname "$INSTALL_PREFIX")" ]; then make install else $SUDO make install fi fi cd .. echo "--- Installing ensurepip and requirements ---" $PYTHON_BINARY -m ensurepip || echo "Warning: ensurepip failed" $PYTHON_BINARY -m pip install -r /dev/stdin <= 0.15; python_version >= '3.5' and python_version < '3.14' # Wheels wheel EOF if [ "$CLEANUP" = true ]; then echo "--- Cleaning up ---" rm -rf "$SOURCE_DIR" "$TARBALL" fi echo "--- Build Complete ---" # Part of "Nuitka", an optimizing Python compiler that is compatible and # integrates with CPython, but also works on its own. # # Licensed under the GNU Affero General Public License, Version 3 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.gnu.org/licenses/agpl-3.0.txt # # See also: "Nuitka Runtime Library Exception, Version 1.0" in file # "LICENSE-RUNTIME.txt" for additional permissions granted under Section 7. # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License.