summaryrefslogtreecommitdiff
path: root/python-build-bin/python-build
diff options
context:
space:
mode:
Diffstat (limited to 'python-build-bin/python-build')
-rwxr-xr-xpython-build-bin/python-build2519
1 files changed, 2519 insertions, 0 deletions
diff --git a/python-build-bin/python-build b/python-build-bin/python-build
new file mode 100755
index 0000000..b8b1b92
--- /dev/null
+++ b/python-build-bin/python-build
@@ -0,0 +1,2519 @@
+#!/usr/bin/env bash
+#
+# Usage: python-build [-kpv] <definition> <prefix>
+# python-build --definitions
+# python-build --version
+#
+# -k/--keep Do not remove source tree after installation
+# -p/--patch Apply a patch from stdin before building
+# -v/--verbose Verbose mode: print compilation status to stdout
+# -4/--ipv4 Resolve names to IPv4 addresses only
+# -6/--ipv6 Resolve names to IPv6 addresses only
+# --definitions List all built-in definitions
+# --version Show version of python-build
+# -g/--debug Build a debug version
+#
+
+PYTHON_BUILD_VERSION="20180424"
+
+OLDIFS="$IFS"
+
+set -E
+shopt -s extglob
+[ -n "$PYENV_DEBUG" ] && {
+ export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
+ set -x
+}
+
+exec 3<&2 # preserve original stderr at fd 3
+
+
+lib() {
+ parse_options() {
+ OPTIONS=()
+ ARGUMENTS=()
+ local arg option index
+
+ for arg in "$@"; do
+ if [ "${arg:0:1}" = "-" ]; then
+ if [ "${arg:1:1}" = "-" ]; then
+ OPTIONS[${#OPTIONS[*]}]="${arg:2}"
+ else
+ index=1
+ while option="${arg:$index:1}"; do
+ [ -n "$option" ] || break
+ OPTIONS[${#OPTIONS[*]}]="$option"
+ index=$(($index+1))
+ done
+ fi
+ else
+ ARGUMENTS[${#ARGUMENTS[*]}]="$arg"
+ fi
+ done
+ }
+
+ if [ "$1" == "--$FUNCNAME" ]; then
+ declare -f "$FUNCNAME"
+ echo "$FUNCNAME \"\$1\";"
+ exit
+ fi
+}
+lib "$1"
+
+READLINK=$(type -P readlink)
+if [ -z "$READLINK" ]; then
+ echo "pyenv: cannot find readlink - are you missing GNU coreutils?" >&2
+ exit 1
+fi
+
+resolve_link() {
+ $READLINK "$1"
+}
+
+abs_dirname() {
+ local path="$1"
+
+ # Use a subshell to avoid changing the current path
+ (
+ while [ -n "$path" ]; do
+ cd_path="${path%/*}"
+ if [[ "$cd_path" != "$path" ]]; then
+ cd "$cd_path"
+ fi
+ name="${path##*/}"
+ path="$(resolve_link "$name" || true)"
+ done
+
+ echo "$PWD"
+ )
+}
+
+capitalize() {
+ printf "%s" "$1" | tr a-z A-Z
+}
+
+sanitize() {
+ printf "%s" "$1" | sed "s/[^A-Za-z0-9.-]/_/g; s/__*/_/g"
+}
+
+colorize() {
+ if [ -t 1 ]; then printf "\e[%sm%s\e[m" "$1" "$2"
+ else echo -n "$2"
+ fi
+}
+
+os_information() {
+ if type -p lsb_release >/dev/null; then
+ lsb_release -sir | xargs echo
+ elif type -p sw_vers >/dev/null; then
+ echo "OS X ${_PYTHON_BUILD_CACHE_SW_VERS:=$(sw_vers -productVersion)}"
+ elif [ -r /etc/os-release ]; then
+ source /etc/os-release
+ echo "$NAME" $VERSION_ID
+ else
+ local os="$(cat /etc/{centos,redhat,fedora,system}-release /etc/debian_version 2>/dev/null | head -n1)"
+ echo "${os:-$(uname -sr)}"
+ fi
+}
+
+is_mac() {
+ [ "${_PYTHON_BUILD_CACHE_UNAME_S:=$(uname -s)}" = "Darwin" ] || return 1
+ [ $# -eq 0 ] || [ "$(osx_version)" "$@" ]
+}
+
+can_use_homebrew() {
+ [[ -n "$PYTHON_BUILD_USE_HOMEBREW" && -n "$PYTHON_BUILD_SKIP_HOMEBREW" ]] && {
+ echo "error: mutually exclusive environment variables PYTHON_BUILD_USE_HOMEBREW and PYTHON_BUILD_SKIP_HOMEBREW are set" >&3
+ exit 1
+ }
+ [[ -n "$PYTHON_BUILD_USE_HOMEBREW" ]] && return 0
+ [[ -n "$PYTHON_BUILD_SKIP_HOMEBREW" ]] && return 1
+ is_mac && return 0
+ # In Linux, if Pyenv itself is installed with Homebrew,
+ # we assume the user wants to take dependencies from there as well by default
+ command -v brew &>/dev/null && [[ $(abs_dirname "${BASH_SOURCE}") == "$(abs_dirname "$(brew --prefix 2>/dev/null ||true)")"/* ]] && return 0
+ return 1
+}
+
+# 9.1 -> 901
+# 10.9 -> 1009
+# 10.10 -> 1010
+osx_version() {
+ local -a ver
+ IFS=. ver=( ${_PYTHON_BUILD_CACHE_SW_VERS:=$(sw_vers -productVersion)} )
+ IFS="$OLDIFS"
+ echo $(( ${ver[0]}*100 + ${ver[1]} ))
+}
+
+build_failed() {
+ { echo
+ colorize 1 "BUILD FAILED"
+ echo " ($(os_information) using $(version))"
+ echo
+
+ if ! rmdir "${BUILD_PATH}" 2>/dev/null; then
+ echo "Inspect or clean up the working tree at ${BUILD_PATH}"
+ fi
+
+ if file_is_not_empty "$LOG_PATH"; then
+ colorize 33 "Results logged to ${LOG_PATH}"
+ printf "\n\n"
+ echo "Last 10 log lines:"
+ tail -n 10 "$LOG_PATH"
+ fi
+ } >&3
+ exit 1
+}
+
+file_is_not_empty() {
+ local filename="$1"
+ local line_count="$(wc -l "$filename" 2>/dev/null || true)"
+
+ if [ -n "$line_count" ]; then
+ words=( $line_count )
+ [ "${words[0]}" -gt 0 ]
+ else
+ return 1
+ fi
+}
+
+num_cpu_cores() {
+ local num
+ case "${_PYTHON_BUILD_CACHE_UNAME_S:=$(uname -s)}" in
+ Darwin | *BSD )
+ num="$(sysctl -n hw.ncpu 2>/dev/null || true)"
+ ;;
+ SunOS )
+ num="$(getconf NPROCESSORS_ONLN 2>/dev/null || true)"
+ ;;
+ * )
+ num="$({ getconf _NPROCESSORS_ONLN ||
+ grep -c ^processor /proc/cpuinfo; } 2>/dev/null)"
+ num="${num#0}"
+ ;;
+ esac
+ echo "${num:-2}"
+}
+
+install_package() {
+ install_package_using "tarball" 1 "$@"
+}
+
+install_nightly_package() {
+ install_package_using "nightly_tarball" 2 "$@"
+}
+
+install_git() {
+ install_package_using "git" 2 "$@"
+}
+
+install_hg() {
+ install_package_using "hg" 2 "$@"
+}
+
+install_svn() {
+ install_package_using "svn" 2 "$@"
+}
+
+install_jar() {
+ install_package_using "jar" 1 "$@"
+}
+
+install_zip() {
+ install_package_using "zip" 1 "$@"
+}
+
+install_script() {
+ install_package_using "script" 1 "$@"
+}
+
+install_package_using() {
+ local package_type="$1"
+ local package_type_nargs="$2"
+ local package_name="$3"
+ shift 3
+
+ local fetch_args=( "$package_name" "${@:1:$package_type_nargs}" )
+ local make_args=( "$package_name" )
+ local arg last_arg
+
+ for arg in "${@:$(( $package_type_nargs + 1 ))}"; do
+ if [ "$last_arg" = "--if" ]; then
+ "$arg" || return 0
+ elif [ "$arg" != "--if" ]; then
+ make_args["${#make_args[@]}"]="$arg"
+ fi
+ last_arg="$arg"
+ done
+
+ pushd "$BUILD_PATH" >&4
+ "fetch_${package_type}" "${fetch_args[@]}"
+ make_package "${make_args[@]}"
+ popd >&4
+
+ echo "Installed ${package_name} to ${PREFIX_PATH}" >&2
+}
+
+make_package() {
+ local package_name="$1"
+ shift
+
+ pushd "$package_name" >&4
+ setup_builtin_patches "$package_name"
+ before_install_package "$package_name"
+ build_package "$package_name" $*
+ after_install_package "$package_name"
+ cleanup_builtin_patches "$package_name"
+ fix_directory_permissions
+ popd >&4
+}
+
+compute_sha2() {
+ local output
+ if type shasum &>/dev/null; then
+ output="$(shasum -a 256 -b)" || return 1
+ echo "${output% *}"
+ elif type openssl &>/dev/null; then
+ local openssl="$(command -v "$(brew --prefix openssl 2>/dev/null || true)"/bin/openssl openssl | head -n1)"
+ output="$("$openssl" dgst -sha256 2>/dev/null)" || return 1
+ echo "${output##* }"
+ elif type sha256sum &>/dev/null; then
+ output="$(sha256sum -b)" || return 1
+ echo "${output%% *}"
+ else
+ return 1
+ fi
+}
+
+compute_md5() {
+ local output
+ if type md5 &>/dev/null; then
+ md5 -q
+ elif type openssl &>/dev/null; then
+ output="$(openssl md5)" || return 1
+ echo "${output##* }"
+ elif type md5sum &>/dev/null; then
+ output="$(md5sum -b)" || return 1
+ echo "${output%% *}"
+ else
+ return 1
+ fi
+}
+
+has_checksum_support() {
+ local checksum_command="$1"
+ local has_checksum_var="HAS_CHECKSUM_SUPPORT_${checksum_command}"
+
+ if [ -z "${!has_checksum_var+defined}" ]; then
+ printf -v "$has_checksum_var" "$(echo test | "$checksum_command" >/dev/null; echo $?)"
+ fi
+ return "${!has_checksum_var}"
+}
+
+verify_checksum() {
+ local checksum_command
+ local filename="$1"
+ local expected_checksum="$(echo "$2" | tr [A-Z] [a-z])"
+
+ # If the specified filename doesn't exist, return success
+ [ -e "$filename" ] || return 0
+
+ case "${#expected_checksum}" in
+ 0) return 0 ;; # empty checksum; return success
+ 32) checksum_command="compute_md5" ;;
+ 64) checksum_command="compute_sha2" ;;
+ *)
+ { echo
+ echo "unexpected checksum length: ${#expected_checksum} (${expected_checksum})"
+ echo "expected 0 (no checksum), 32 (MD5), or 64 (SHA2-256)"
+ echo
+ } >&4
+ return 1 ;;
+ esac
+
+ # If chosen provided checksum algorithm isn't supported, return success
+ has_checksum_support "$checksum_command" || return 0
+
+ # If the computed checksum is empty, return failure
+ local computed_checksum=`echo "$($checksum_command < "$filename")" | tr [A-Z] [a-z]`
+ [ -n "$computed_checksum" ] || return 1
+
+ if [ "$expected_checksum" != "$computed_checksum" ]; then
+ { echo
+ echo "checksum mismatch: ${filename} (file is corrupt)"
+ echo "expected $expected_checksum, got $computed_checksum"
+ echo
+ } >&4
+ return 1
+ fi
+}
+
+http() {
+ local method="$1"
+ [ -n "$2" ] || return 1
+ shift 1
+
+ PYTHON_BUILD_HTTP_CLIENT="${PYTHON_BUILD_HTTP_CLIENT:-$(detect_http_client)}"
+ [ -n "$PYTHON_BUILD_HTTP_CLIENT" ] || return 1
+
+ "http_${method}_${PYTHON_BUILD_HTTP_CLIENT}" "$@"
+}
+
+detect_http_client() {
+ local client
+ for client in aria2c curl wget; do
+ if type "$client" &>/dev/null; then
+ echo "$client"
+ return
+ fi
+ done
+ echo "error: please install \`aria2c\`, \`curl\`, or \`wget\` and try again" >&2
+ return 1
+}
+
+http_head_aria2c() {
+ aria2c --dry-run --no-conf=true ${ARIA2_OPTS} "$1" >&4 2>&1
+}
+
+http_get_aria2c() {
+ # aria2c always treats -o argument as a relative path
+ local out dir_out;
+ if [[ -n "$2" ]]; then
+ out="$(basename $2)";
+ dir_out="$(dirname $2)";
+ else
+ out="$(mktemp "out.XXXXXX")";
+ dir_out="$TMPDIR";
+ fi
+
+ # In Ubuntu, aria2c is only available as a snap. Snaps cannot read or write /tmp
+ # (files cannot be found, any write result is silently discarded).
+ local aria2c_is_snap;
+ if [[ $(command -v aria2c) == "/snap/"* ]]; then aria2c_is_snap=1; fi
+
+ if [[ -n $aria2c_is_snap ]]; then
+ local real_dir_out="$dir_out"
+ # presumably, snaps can always write to under $HOME
+ dir_out="$HOME"
+ fi
+
+ if aria2c --allow-overwrite=true --no-conf=true -d "${dir_out}" -o "${out}" ${ARIA2_OPTS} "$1" >&4; then
+ [ -n "$2" ] || cat "${dir_out:-.}/${out}"
+ else
+ false
+ fi
+ ret=$?
+
+ if [[ -n "$2" && -n $aria2c_is_snap ]]; then
+ mv "$dir_out/$out" "$real_dir_out/$out"
+ fi
+ return "$ret"
+}
+
+http_head_curl() {
+ curl -qsILf ${CURL_OPTS} "$1" >&4 2>&1
+}
+
+http_get_curl() {
+ curl -q -o "${2:--}" -sSLf ${CURL_OPTS} "$1"
+}
+
+http_head_wget() {
+ wget -q --spider ${WGET_OPTS} "$1" >&4 2>&1
+}
+
+http_get_wget() {
+ wget -nv ${WGET_OPTS} -O "${2:--}" "$1"
+}
+
+fetch_tarball() {
+ local package_name="$1"
+ local package_url="$2"
+ local mirror_url
+ local checksum
+ local extracted_dir
+
+ if [ "$package_url" != "${package_url/\#}" ]; then
+ checksum="${package_url#*#}"
+ package_url="${package_url%%#*}"
+
+ if [ -n "$PYTHON_BUILD_MIRROR_URL" ]; then
+ if [[ -z "$PYTHON_BUILD_DEFAULT_MIRROR" || $package_url != */www.python.org/* ]]; then
+ mirror_url="${PYTHON_BUILD_MIRROR_URL}/$checksum"
+ fi
+ fi
+ fi
+
+ local tar_args="xzf"
+ local package_filename="${package_name}.tar.gz"
+
+ if [ "$package_url" != "${package_url%bz2}" ]; then
+ if ! type -p bzip2 >/dev/null; then
+ echo "warning: bzip2 not found; consider installing \`bzip2\` package" >&4
+ fi
+ package_filename="${package_filename%.gz}.bz2"
+ tar_args="${tar_args/z/j}"
+ fi
+
+ if [ "$package_url" != "${package_url%xz}" ]; then
+ if ! type -p xz >/dev/null; then
+ echo "warning: xz not found; consider installing \`xz\` package" >&4
+ fi
+ package_filename="${package_filename%.gz}.xz"
+ tar_args="${tar_args/z/J}"
+ fi
+
+ if ! reuse_existing_tarball "$package_filename" "$checksum"; then
+ # Report the cached file name -- sometimes, it's useful to know (#1743)
+ echo "Downloading ${package_filename}..." >&2
+ http head "$mirror_url" &&
+ download_tarball "$mirror_url" "$package_filename" "$checksum" ||
+ download_tarball "$package_url" "$package_filename" "$checksum"
+ fi
+
+ { if tar $tar_args "$package_filename"; then
+ if [ ! -d "$package_name" ]; then
+ extracted_dir="$(find_extracted_directory)"
+ mv "$extracted_dir" "$package_name"
+ fi
+
+ if [ -z "$KEEP_BUILD_PATH" ]; then
+ rm -f "$package_filename"
+ else
+ true
+ fi
+ fi
+ } >&4 2>&1
+}
+
+find_extracted_directory() {
+ for f in *; do
+ if [ -d "$f" ]; then
+ echo "$f"
+ return
+ fi
+ done
+ echo "Extracted directory not found" >&2
+ return 1
+}
+
+fetch_nightly_tarball() {
+ local package_name="$1"
+ local package_url="$2"
+ local package_pattern="$3"
+ fetch_tarball "$1" "$2"
+ if [ ! -e "${package_name}" ]; then
+ local nightly_package_name="$(echo ${package_pattern})"
+ if [ -e "${nightly_package_name}" ]; then
+ ln -fs "${nightly_package_name}" "${package_name}"
+ fi
+ fi
+}
+
+reuse_existing_tarball() {
+ local package_filename="$1"
+ local checksum="$2"
+
+ # Reuse existing file in build location
+ if [ -e "$package_filename" ] && verify_checksum "$package_filename" "$checksum"; then
+ return 0
+ fi
+
+ # Reuse previously downloaded file in cache location
+ [ -n "$PYTHON_BUILD_CACHE_PATH" ] || return 1
+ local cached_package_filename="${PYTHON_BUILD_CACHE_PATH}/$package_filename"
+
+ [ -e "$cached_package_filename" ] || return 1
+ verify_checksum "$cached_package_filename" "$checksum" >&4 2>&1 || return 1
+ ln -s "$cached_package_filename" "$package_filename" >&4 2>&1 || return 1
+}
+
+download_tarball() {
+ local official_source="www.python.org/ftp/python"
+ if [ -n "$PYTHON_BUILD_MIRROR_URL_SKIP_CHECKSUM" ]; then
+ local package_url="$(echo "$1" | sed -e "s|.*//${URL_BASE:-$official_source}|$PYTHON_BUILD_MIRROR_URL|g")"
+ else
+ local package_url="$1"
+ fi
+ [ -n "$package_url" ] || return 1
+
+ local package_filename="$2"
+ local checksum="$3"
+
+ echo "-> $package_url" >&2
+
+ if http get "$package_url" "$package_filename" >&4 2>&1; then
+ verify_checksum "$package_filename" "$checksum" >&4 2>&1 || return 1
+ else
+ echo "error: failed to download $package_filename" >&2
+ return 1
+ fi
+
+ if [ -n "$PYTHON_BUILD_CACHE_PATH" ]; then
+ local cached_package_filename="${PYTHON_BUILD_CACHE_PATH}/$package_filename"
+ { mv "$package_filename" "$cached_package_filename"
+ ln -s "$cached_package_filename" "$package_filename"
+ } >&4 2>&1 || return 1
+ fi
+}
+
+has_tar_xz_support() {
+ [[ -z $_PYTHON_BUILD_FORCE_SKIP_XZ ]] && tar Jcf - /dev/null 1>/dev/null 2>&1
+}
+
+fetch_git() {
+ local package_name="$1"
+ local git_url="$2"
+ local git_ref="$3"
+
+ echo "Cloning ${git_url}..." >&2
+
+ if type git &>/dev/null; then
+ if [ -n "$PYTHON_BUILD_CACHE_PATH" ]; then
+ pushd "$PYTHON_BUILD_CACHE_PATH" >&4
+ local clone_name="$(sanitize "$git_url")"
+ if [ -e "${clone_name}" ]; then
+ { cd "${clone_name}"
+ git fetch --force "$git_url" "+${git_ref}:${git_ref}"
+ } >&4 2>&1
+ else
+ git clone --bare --branch "$git_ref" "$git_url" "${clone_name}" >&4 2>&1
+ fi
+ git_url="$PYTHON_BUILD_CACHE_PATH/${clone_name}"
+ popd >&4
+ fi
+
+ if [ -e "${package_name}" ]; then
+ ( cd "${package_name}"
+ git fetch --depth 1 origin "+${git_ref}"
+ git checkout -q -B "$git_ref" "origin/${git_ref}"
+ ) >&4 2>&1
+ else
+ git clone --depth 1 --branch "$git_ref" "$git_url" "${package_name}" >&4 2>&1
+ fi
+ else
+ echo "error: please install \`git\` and try again" >&2
+ exit 1
+ fi
+}
+
+fetch_hg() {
+ local package_name="$1"
+ local hg_url="$2"
+ local hg_ref="$3"
+
+ echo "Cloning ${hg_url}..." >&2
+
+ if type hg &>/dev/null; then
+ if [ -n "$PYTHON_BUILD_CACHE_PATH" ]; then
+ pushd "$PYTHON_BUILD_CACHE_PATH" >&4
+ local clone_name="$(sanitize "$hg_url")"
+ if [ -e "${clone_name}" ]; then
+ { cd "${clone_name}"
+ hg pull --force "$hg_url"
+ } >&4 2>&1
+ else
+ { hg clone --branch "$hg_ref" "$hg_url" "${clone_name}"
+ cd "${clone_name}"
+ hg update null
+ } >&4 2>&1
+ fi
+ hg_url="$PYTHON_BUILD_CACHE_PATH/${clone_name}"
+ popd >&4
+ fi
+
+ hg clone --branch "$hg_ref" "$hg_url" "${package_name}" >&4 2>&1
+ else
+ echo "error: please install \`mercurial\` and try again" >&2
+ exit 1
+ fi
+}
+
+fetch_svn() {
+ local package_name="$1"
+ local svn_url="$2"
+ local svn_rev="$3"
+
+ echo "Checking out ${svn_url}..." >&2
+
+ if type svn &>/dev/null; then
+ svn co -r "$svn_rev" "$svn_url" "${package_name}" >&4 2>&1
+ elif type svnlite &>/dev/null; then
+ svnlite co -r "$svn_rev" "$svn_url" "${package_name}" >&4 2>&1
+ else
+ echo "error: please install Subversion and try again" >&2
+ exit 1
+ fi
+}
+
+fetch_jar() {
+ local package_name="$1"
+ local package_url="$2"
+ local mirror_url
+ local checksum
+
+ if [ "$package_url" != "${package_url/\#}" ]; then
+ checksum="${package_url#*#}"
+ package_url="${package_url%%#*}"
+
+ if [ -n "$PYTHON_BUILD_MIRROR_URL" ]; then
+ mirror_url="${PYTHON_BUILD_MIRROR_URL}/$checksum"
+ fi
+ fi
+
+ local package_filename="${package_name}.jar"
+
+ if ! reuse_existing_tarball "$package_filename" "$checksum"; then
+ echo "Downloading ${package_filename}..." >&2
+ http head "$mirror_url" &&
+ download_tarball "$mirror_url" "$package_filename" "$checksum" ||
+ download_tarball "$package_url" "$package_filename" "$checksum"
+ fi
+
+ # Must use full path to jar and destination directory:
+ # http://bugs.jython.org/issue2350
+ { if $JAVA -jar "$PWD/${package_name}.jar" -s -d "$PWD/${package_name}"; then
+ if [ -z "$KEEP_BUILD_PATH" ]; then
+ rm -f "$package_filename"
+ else
+ true
+ fi
+ fi
+ } >&4 2>&1
+}
+
+fetch_zip() {
+ local package_name="$1"
+ local package_url="$2"
+ local mirror_url
+ local checksum
+
+ if [ "$package_url" != "${package_url/\#}" ]; then
+ checksum="${package_url#*#}"
+ package_url="${package_url%%#*}"
+
+ if [ -n "$PYTHON_BUILD_MIRROR_URL" ]; then
+ mirror_url="${PYTHON_BUILD_MIRROR_URL}/$checksum"
+ fi
+ fi
+
+ local package_filename="${package_name}.zip"
+
+ if ! reuse_existing_tarball "$package_filename" "$checksum"; then
+ echo "Downloading ${package_filename}..." >&2
+ http head "$mirror_url" &&
+ download_tarball "$mirror_url" "$package_filename" "$checksum" ||
+ download_tarball "$package_url" "$package_filename" "$checksum"
+ fi
+
+ { if unzip "$package_filename"; then
+ if [ -z "$KEEP_BUILD_PATH" ]; then
+ rm -f "$package_filename"
+ else
+ true
+ fi
+ fi
+ } >&4 2>&1
+}
+
+fetch_script() {
+ local package_name="$1"
+ local package_url="$2"
+ local mirror_url
+ local checksum
+
+ if [ "$package_url" != "${package_url/\#}" ]; then
+ checksum="${package_url#*#}"
+ package_url="${package_url%%#*}"
+
+ if [ -n "$PYTHON_BUILD_MIRROR_URL" ]; then
+ mirror_url="${PYTHON_BUILD_MIRROR_URL}/$checksum"
+ fi
+ fi
+
+ local package_filename="${package_name}.sh" # TODO: extract suffix from ${package_url}
+
+ if ! reuse_existing_tarball "$package_filename" "$checksum"; then
+ echo "Downloading ${package_filename}..." >&2
+ http head "$mirror_url" &&
+ download_tarball "$mirror_url" "$package_filename" "$checksum" ||
+ download_tarball "$package_url" "$package_filename" "$checksum"
+ fi
+
+ mkdir -p "$(dirname "${package_name}/${package_filename}")"
+ mv -f "${package_filename}" "${package_name}/${package_filename}"
+}
+
+build_package() {
+ local package_name="$1"
+ shift
+
+ if [ "$#" -eq 0 ]; then
+ local commands="standard"
+ else
+ local commands="$*"
+ fi
+
+ echo "Installing ${package_name}..." >&2
+
+ [ -n "$HAS_PATCH" ] && apply_patch "$package_name" <(cat "${package_name}.patch")
+
+ for command in $commands; do
+ "build_package_${command}" "$package_name"
+ done
+}
+
+package_option() {
+ local package_name="$1"
+ local command_name="$2"
+ local variable="$(capitalize "${package_name}_${command_name}")_OPTS_ARRAY"
+ local array="$variable[@]"
+ shift 2
+ local value=( "${!array}" "$@" )
+ eval "$variable=( \"\${value[@]}\" )"
+}
+
+build_package_warn_eol() {
+ local package_name="$1"
+
+ { echo
+ echo "WARNING: $package_name is past its end of life and is now unsupported."
+ echo "It no longer receives bug fixes or critical security updates."
+ echo
+ } >&3
+}
+
+build_package_warn_unsupported() {
+ local package_name="$1"
+
+ { echo
+ echo "WARNING: $package_name is nearing its end of life."
+ echo "It only receives critical security updates, no bug fixes."
+ echo
+ } >&3
+}
+
+build_package_standard_build() {
+ local package_name="$1"
+
+ if [ "${MAKEOPTS+defined}" ]; then
+ MAKE_OPTS="$MAKEOPTS"
+ elif [ -z "${MAKE_OPTS+defined}" ]; then
+ MAKE_OPTS="-j $(num_cpu_cores)"
+ fi
+
+ # Support YAML_CONFIGURE_OPTS, PYTHON_CONFIGURE_OPTS, etc.
+ local package_var_name="$(capitalize "${package_name%%-*}")"
+ local PACKAGE_CONFIGURE="${package_var_name}_CONFIGURE"
+ local PACKAGE_PREFIX_PATH="${package_var_name}_PREFIX_PATH"
+ local PACKAGE_CONFIGURE_OPTS="${package_var_name}_CONFIGURE_OPTS"
+ local PACKAGE_CONFIGURE_OPTS_ARRAY="${package_var_name}_CONFIGURE_OPTS_ARRAY[@]"
+ local PACKAGE_MAKE_OPTS="${package_var_name}_MAKE_OPTS"
+ local PACKAGE_MAKE_OPTS_ARRAY="${package_var_name}_MAKE_OPTS_ARRAY[@]"
+ local PACKAGE_CFLAGS="${package_var_name}_CFLAGS"
+ local PACKAGE_CPPFLAGS="${package_var_name}_CPPFLAGS"
+ local PACKAGE_LDFLAGS="${package_var_name}_LDFLAGS"
+
+ if [ "$package_var_name" = "PYTHON" ]; then
+ use_homebrew || true
+ use_custom_tcltk || use_homebrew_tcltk || true
+ use_homebrew_readline || use_freebsd_pkg || true
+ use_homebrew_ncurses || true
+ if is_mac -ge 1014; then
+ use_xcode_sdk_zlib || use_homebrew_zlib || true
+ else
+ use_homebrew_zlib || true
+ fi
+ use_dsymutil || true
+ use_free_threading || true
+ fi
+
+ ( if [[ -n "${!PACKAGE_CFLAGS}" ]]; then
+ export CFLAGS="${CFLAGS:+$CFLAGS }${!PACKAGE_CFLAGS}"
+ fi
+ if [[ -n "${!PACKAGE_CPPFLAGS}" ]]; then
+ export CPPFLAGS="${CPPFLAGS:+$CPPFLAGS }${!PACKAGE_CPPFLAGS}"
+ fi
+ if [[ -n "${!PACKAGE_LDFLAGS}" ]]; then
+ export LDFLAGS="${LDFLAGS:+$LDFLAGS }${!PACKAGE_LDFLAGS}"
+ fi
+ if [ -z "$CC" ] && is_mac -ge 1010; then
+ export CC=clang
+ fi
+ ${!PACKAGE_CONFIGURE:-./configure} --prefix="${!PACKAGE_PREFIX_PATH:-$PREFIX_PATH}" \
+ "${!PACKAGE_CONFIGURE_OPTS_ARRAY}" $CONFIGURE_OPTS ${!PACKAGE_CONFIGURE_OPTS} || return 1
+ ) >&4 2>&1
+
+ { "$MAKE" "${!PACKAGE_MAKE_OPTS_ARRAY}" $MAKE_OPTS ${!PACKAGE_MAKE_OPTS}
+ } >&4 2>&1
+}
+
+build_package_standard_install() {
+ local package_name="$1"
+ local package_var_name="$(capitalize "${package_name%%-*}")"
+
+ local PACKAGE_MAKE_INSTALL_OPTS="${package_var_name}_MAKE_INSTALL_OPTS"
+ local PACKAGE_MAKE_INSTALL_OPTS_ARRAY="${package_var_name}_MAKE_INSTALL_OPTS_ARRAY[@]"
+ local PACKAGE_MAKE_INSTALL_TARGET="${package_var_name}_MAKE_INSTALL_TARGET"
+
+ { "$MAKE" "${!PACKAGE_MAKE_INSTALL_TARGET:-install}" $MAKE_INSTALL_OPTS ${!PACKAGE_MAKE_INSTALL_OPTS} "${!PACKAGE_MAKE_INSTALL_OPTS_ARRAY}"
+ } >&4 2>&1
+}
+
+# Backward Compatibility for standard function
+build_package_standard() {
+ build_package_standard_build "$@"
+ build_package_standard_install "$@"
+}
+
+build_package_autoconf() {
+ { autoreconf
+ } >&4 2>&1
+}
+
+build_package_python() {
+ local package_name="$1"
+
+ { "$PYTHON_BIN" setup.py install
+ } >&4 2>&1
+}
+
+remove_windows_files() {
+ cd "$PREFIX_PATH"
+ rm -f bin/*.exe bin/*.dll bin/*.bat
+}
+
+build_package_jython() {
+ build_package_copy
+ { if [ -x "${PREFIX_PATH}/bin/jython" ] && [ ! -x "${PREFIX_PATH}/bin/python" ]; then
+ ( cd "${PREFIX_PATH}/bin" && ln -fs jython python )
+ fi
+ } >&4 2>&1
+ fix_jython_shebangs
+}
+
+fix_jython_shebangs() {
+ # Workaround for Jython 2.7+ (#458)
+ for file in "${PREFIX_PATH}/bin"/*; do
+ case "$(head -n1 "${file}")" in
+ "#!"*"/bin/jython" )
+ sed -i.bak "1 s:.*:#\!${PREFIX_PATH}\/bin\/jython:" "${file}"
+ ;;
+ "#!"*"/bin/python2.7"* )
+ sed -i.bak "1 s:.*:#\!\/usr\/bin\/env python:" "${file}"
+ ;;
+ esac
+ rm -f "${file}.bak"
+ done
+}
+
+build_package_jython_builder() {
+ ant >&4 2>&1
+ ( cd "dist" && build_package_jython )
+}
+
+build_package_pyston2_2() {
+ # currently supported version 2.2 and 2.3
+ build_package_copy
+ mkdir -p "${PREFIX_PATH}/bin" "${PREFIX_PATH}/lib"
+ local bin
+ shopt -s nullglob
+ for bin in "bin/"*; do
+ if [ -f "${bin}" ] && [ -x "${bin}" ] && [ ! -L "${bin}" ]; then
+ case "${bin##*/}" in
+ "pyston"* )
+ ( cd "${PREFIX_PATH}/bin" && ln -fs "${bin##*/}" "python" )
+ ;;
+ esac
+ fi
+ done
+ shopt -u nullglob
+}
+
+build_package_pyston() {
+ # currently supported version 2.3.1v2 and higher
+ build_package_copy
+}
+
+build_package_ironpython() {
+ mkdir -p "${PREFIX_PATH}/bin"
+ cp -fR . "${PREFIX_PATH}/bin"
+ chmod +x "${PREFIX_PATH}/bin/"*.exe
+ ( cd "${PREFIX_PATH}/bin" && ln -fs ipy.exe python )
+}
+
+build_package_ironpython_builder() {
+ xbuild Build.proj /t:Stage "/p:Mono=true;BaseConfiguration=Release" >&4 2>&1
+ ( cd "Stage/Release/IronPython-"* && build_package_ironpython )
+}
+
+build_package_micropython_1_9() {
+ # supported version 1.9.3 and 1.9.4
+ build_package_micropython "with_axtls"
+}
+
+build_package_micropython() {
+ # supported version 1.10 and higher
+ if [ "${MAKEOPTS+defined}" ]; then
+ MAKE_OPTS="$MAKEOPTS"
+ elif [ -z "${MAKE_OPTS+defined}" ]; then
+ MAKE_OPTS="-j $(num_cpu_cores)"
+ fi
+ { cd mpy-cross
+ "$MAKE" $MAKE_OPTS
+ cd ../ports/unix
+ [ "$1" = "with_axtls" ] && "$MAKE" $MAKE_OPTS axtls
+ "$MAKE" $MAKE_OPTS CFLAGS_EXTRA="-DMICROPY_PY_SYS_PATH_DEFAULT='\".frozen:${PREFIX_PATH}/lib/micropython\"' $CFLAGS_EXTRA"
+ "$MAKE" install $MAKE_INSTALL_OPTS PREFIX="${PREFIX_PATH}"
+ ln -fs micropython "${PREFIX_PATH}/bin/python"
+ mkdir -p "${PREFIX_PATH}/lib/micropython"
+ }>&4 2>&1
+}
+
+pypy_architecture() {
+ case "${_PYTHON_BUILD_CACHE_UNAME_S:=$(uname -s)}" in
+ "Darwin" )
+ case "$(uname -m)" in
+ "arm64" ) echo "osarm64" ;;
+ "x86_64" ) echo "osx64" ;;
+ * ) return 1 ;;
+ esac
+ ;;
+ "Linux" )
+ case "$(uname -m)" in
+ "armel" ) echo "linux-armel" ;;
+ "armhf" | "armv6l" | "armv7l" ) echo "linux-armhf" ;;
+ "i386" | "i486" | "i586" | "i686" | "i786" ) echo "linux" ;;
+ "ppc64" ) echo "linux-ppc64" ;;
+ "ppc64le" ) echo "linux-ppc64le" ;;
+ "x86_64" ) echo "linux64" ;;
+ "aarch64" ) echo "linux-aarch64" ;;
+ * ) return 1 ;;
+ esac
+ ;;
+ "CYGWIN"* | "MINGW"* ) echo "win32" ;;
+ "FreeBSD" )
+ case "$(uname -m)" in
+ "x86_64" ) echo "freebsd64" ;;
+ * ) return 1 ;;
+ esac
+ ;;
+ * ) return 1 ;;
+ esac
+}
+
+graalpy_architecture() {
+ case "${_PYTHON_BUILD_CACHE_UNAME_S:=$(uname -s)}" in
+ "Darwin" )
+ case "$(uname -m)" in
+ "x86_64" ) echo "macos-amd64" ;;
+ "arm64" ) echo "macos-aarch64" ;;
+ * ) return 1 ;;
+ esac
+ ;;
+ "Linux" )
+ case "$(uname -m)" in
+ "x86_64" ) echo "linux-amd64" ;;
+ "aarch64" ) echo "linux-aarch64" ;;
+ * ) return 1 ;;
+ esac
+ ;;
+ esac
+}
+
+pyston_architecture() {
+ pypy_architecture
+}
+
+# Note: not used by graalpy >= 23.3.0 anymore
+build_package_graalpython() {
+ build_package_copy
+ ln -fs "${PREFIX_PATH}/bin/graalpython" "${PREFIX_PATH}/bin/python"
+}
+
+build_package_pypy() {
+ build_package_copy
+ mkdir -p "${PREFIX_PATH}/bin" "${PREFIX_PATH}/lib"
+ local bin
+ shopt -s nullglob
+ for bin in "bin/"*; do
+ if [ -f "${bin}" ] && [ -x "${bin}" ] && [ ! -L "${bin}" ]; then
+ case "${bin##*/}" in
+ "libpypy"* )
+ ( cd "${PREFIX_PATH}/lib" && ln -fs "../bin/${bin##*/}" "${bin##*/}" )
+ ;;
+ "pypy"* )
+ ( cd "${PREFIX_PATH}/bin" && ln -fs "${bin##*/}" "python" )
+ ;;
+ esac
+ fi
+ done
+ shopt -u nullglob
+}
+
+build_package_pypy_builder() {
+ if [ -f "rpython/bin/rpython" ]; then # pypy 2.x
+ if [ -z "${PYPY_OPTS}" ]; then
+ local PYPY_OPTS="--opt=jit --batch --make-jobs=$(num_cpu_cores)"
+ fi
+ python "rpython/bin/rpython" ${PYPY_OPTS} "pypy/goal/targetpypystandalone.py" >&4 2>&1
+ elif [ -f "pypy/translator/goal/translate.py" ]; then # pypy 1.x
+ if [ -z "${PYPY_OPTS}" ]; then
+ local PYPY_OPTS="--opt=jit"
+ fi
+ ( cd "pypy/translator/goal" && python "translate.py" ${PYPY_OPTS} "targetpypystandalone.py" ) 1>&4 2>&1
+ else
+ echo "not a pypy source tree" 1>&3
+ return 1
+ fi
+ { mkdir -p "bin" "lib"
+ local pypy
+ for pypy in "pypy"*; do
+ if [ -f "${pypy}" ] && [ -x "${pypy}" ] && [ ! -L "${pypy}" ]; then
+ mv -f "${pypy}" "bin/${pypy##*/}"
+ fi
+ done
+ local libpypy
+ for libpypy in "libpypy"*; do
+ if [ -f "${libpypy}" ] && [ -x "${libpypy}" ] && [ ! -L "${libpypy}" ]; then
+ mv -f "${libpypy}" "bin/${libpypy##*/}"
+ fi
+ done
+ } >&4 2>&1
+ build_package_pypy
+}
+
+activepython_architecture() {
+ case "${_PYTHON_BUILD_CACHE_UNAME_S:=$(uname -s)}" in
+ "Darwin" ) echo "macosx10.9-i386-x86_64" ;;
+ "Linux" )
+ case "$(uname -m)" in
+ "i386" | "i486" | "i586" | "i686" | "i786" ) echo "linux-x86" ;;
+ "x86_64" ) echo "linux-x86_64" ;;
+ * ) return 1 ;;
+ esac
+ ;;
+ * ) return 1 ;;
+ esac
+}
+
+build_package_activepython() {
+ local package_name="$1"
+ { bash "install.sh" --install-dir "${PREFIX_PATH}"
+ } >&4 2>&1
+}
+
+anaconda_architecture() {
+ case "${_PYTHON_BUILD_CACHE_UNAME_S:=$(uname -s)}" in
+ "Darwin" )
+ case "$(uname -m)" in
+ "arm64" ) echo "MacOSX-arm64" ;;
+ * ) echo "MacOSX-x86_64" ;;
+ esac
+ ;;
+ "Linux" )
+ case "$(uname -m)" in
+ "armv7l" ) echo "Linux-armv7l" ;;
+ "aarch64" ) echo "Linux-aarch64" ;;
+ "i386" | "i486" | "i586" | "i686" | "i786" ) echo "Linux-x86" ;;
+ "ppc64le" ) echo "Linux-ppc64le" ;;
+ "x86_64" ) echo "Linux-x86_64" ;;
+ * ) return 1 ;;
+ esac
+ ;;
+ * ) return 1 ;;
+ esac
+}
+
+build_package_anaconda() {
+ local package_name="$1"
+ { bash "${package_name}.sh" -f -b -p "${PREFIX_PATH}"
+ } >&4 2>&1
+}
+
+build_package_miniconda() {
+ build_package_anaconda "$@"
+ # Workaround to not upgrade conda when installing pip
+ # see https://github.com/pyenv/pyenv/issues/2070
+ "${PREFIX_PATH}/bin/conda" install --yes "pip" "conda=$(${PREFIX_PATH}/bin/conda --version | cut -d ' ' -f 2)"
+}
+
+build_package_copy() {
+ mkdir -p "$PREFIX_PATH"
+ cp -fR . "$PREFIX_PATH"
+}
+
+before_install_package() {
+ local stub=1
+}
+
+after_install_package() {
+ local stub=1
+}
+
+setup_builtin_patches() {
+ local package_name="$1"
+ local package_patch_path="${DEFINITION_PATH%/*}/patches/${DEFINITION_PATH##*/}/${package_name}"
+
+# Apply built-in patches if patch was not given from stdin
+ if [[ -n "$HAS_STDIN_PATCH" ]] && package_is_python "${package_name}"; then
+ cat >"${package_name}.patch"
+ HAS_PATCH=true
+ elif [[ -d "${package_patch_path}" ]]; then
+ { find "${package_patch_path}" -maxdepth 1 -type f
+ } 2>/dev/null | sort | xargs cat 1>"${package_name}.patch"
+ HAS_PATCH=true
+ fi
+}
+
+cleanup_builtin_patches() {
+ local package_name="$1"
+ rm -f "${package_name}.patch"
+ unset HAS_PATCH
+}
+
+fix_directory_permissions() {
+ # Ensure installed directories are not world-writable
+ find "$PREFIX_PATH" -type d \( -perm -020 -o -perm -002 \) -exec chmod go-w {} \;
+}
+
+require_java7() {
+ local version="$(java -version 2>&1 | grep '\(java\|openjdk\) version' | head -n1)"
+ if [[ $version != *[789]* ]]; then
+ colorize 1 "ERROR" >&3
+ echo ": Java 7 required. Please install a 1.7-compatible JRE." >&3
+ return 1
+ fi
+}
+
+require_gcc() {
+ local gcc="$(locate_gcc || true)"
+
+ if [ -z "$gcc" ]; then
+ { echo
+ colorize 1 "ERROR"
+ echo ": This package must be compiled with GCC, but python-build couldn't"
+ echo "find a suitable \`gcc\` executable on your system. Please install GCC"
+ echo "and try again."
+ echo
+
+ if is_mac; then
+ colorize 1 "DETAILS"
+ echo ": Apple no longer includes the official GCC compiler with Xcode"
+ echo "as of version 4.2. Instead, the \`gcc\` executable is a symlink to"
+ echo "\`llvm-gcc\`, a modified version of GCC which outputs LLVM bytecode."
+ echo
+ echo "For most programs the \`llvm-gcc\` compiler works fine. However,"
+ echo "versions of CPython newer than 3.3.0 are incompatible with"
+ echo "\`llvm-gcc\`. To build newer versions of CPython you must have the official"
+ echo "GCC compiler installed on your system."
+ echo
+
+ colorize 1 "TO FIX THE PROBLEM"
+ if type brew &>/dev/null; then
+ echo ": Install Homebrew's GCC package with this"
+ echo -n "command: "
+ colorize 4 "brew install gcc@4.9"
+ else
+ echo ": Install the official GCC compiler using these"
+ echo -n "packages: "
+ colorize 4 "https://github.com/kennethreitz/osx-gcc-installer/downloads"
+ fi
+
+ echo
+ echo
+ echo "You will need to install the official GCC compiler to build newer"
+ echo "versions of CPython even if you have installed Apple's Command Line Tools"
+ echo "for Xcode package. The Command Line Tools for Xcode package only"
+ echo "includes \`llvm-gcc\`."
+ fi
+ } >&3
+ return 1
+ fi
+
+ export CC="$gcc"
+ if is_mac -ge 1010; then
+ export MACOSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET:-10.9}
+ fi
+}
+
+locate_gcc() {
+ local gcc gccs
+ IFS=: gccs=($(gccs_in_path))
+ IFS="$OLDIFS"
+
+ verify_gcc "$CC" ||
+ verify_gcc "$(command -v gcc || true)" || {
+ for gcc in "${gccs[@]}"; do
+ verify_gcc "$gcc" && break || true
+ done
+ }
+
+ return 1
+}
+
+gccs_in_path() {
+ local gcc path paths
+ local gccs=()
+ IFS=: paths=($PATH)
+ IFS="$OLDIFS"
+
+ shopt -s nullglob
+ for path in "${paths[@]}"; do
+ for gcc in "$path"/gcc-*; do
+ gccs["${#gccs[@]}"]="$gcc"
+ done
+ done
+ shopt -u nullglob
+
+ printf :%s "${gccs[@]}"
+}
+
+verify_gcc() {
+ local gcc="$1"
+ if [ -z "$gcc" ]; then
+ return 1
+ fi
+
+ local version="$("$gcc" --version 2>/dev/null || true)"
+ if [ -z "$version" ]; then
+ return 1
+ fi
+
+ if echo "$version" | grep LLVM >/dev/null; then
+ return 1
+ fi
+
+ echo "$gcc"
+}
+
+require_llvm() {
+ local llvm_version="$1"
+ if is_mac -ge 1010; then
+ if [[ "$PYTHON_CONFIGURE_OPTS" != *--llvm-* ]]; then
+ case "$llvm_version" in
+ 3.2 )
+ package_option python configure --prebuilt-name="llvm-3.2-x86_64-apple-darwin13.tar.bz2"
+ ;;
+ 3.[56] )
+ local llvm_config="$(locate_llvm "$llvm_version")"
+ if [ -n "$llvm_config" ]; then
+ package_option python configure --llvm-config="$llvm_config"
+ else
+ local homebrew_package="llvm@$llvm_version"
+ { echo
+ colorize 1 "ERROR"
+ echo ": Rubinius will not be able to compile using Apple's LLVM-based "
+ echo "build tools on OS X. You will need to install LLVM $llvm_version first."
+ echo
+ colorize 1 "TO FIX THE PROBLEM"
+ echo ": Install Homebrew's llvm package with this"
+ echo -n "command: "
+ colorize 4 "brew install $homebrew_package"
+ echo
+ } >&3
+ return 1
+ fi
+ ;;
+ esac
+ fi
+ fi
+}
+
+locate_llvm() {
+ local llvm_version="$1"
+ local package llvm_config
+ shopt -s nullglob
+ for package in `brew list 2>/dev/null | grep "^llvm"`; do
+ llvm_config="$(echo "$(brew --prefix "$package")/bin/llvm-config"*)"
+ if [ -n "$llvm_config" ] && [[ "$("$llvm_config" --version)" = "$llvm_version"* ]]; then
+ echo "$llvm_config"
+ break
+ fi
+ done
+ shopt -u nullglob
+}
+
+require_java() {
+ local java="$(command -v java || true)"
+
+ if [ -z "$java" ]; then
+ { echo
+ colorize 1 "ERROR"
+ echo ": This package must be installed with java, but python-build couldn't"
+ echo "find a suitable \`java\` executable on your system. Please install Java"
+ echo "and try again."
+ echo
+ } >&3
+ return 1
+ fi
+
+ export JAVA="$java"
+}
+
+# Let Jython installer to generate shell script instead of python script even if there's `python2.7` available in `$PATH` (#800)
+# FIXME: better function naming
+unrequire_python27() {
+ export PATH="${BUILD_PATH}/bin:${PATH}"
+ mkdir -p "${BUILD_PATH}/bin"
+ if command -v python2.7 1>/dev/null 2>&1; then
+ echo false > "${BUILD_PATH}/bin/python2.7"
+ chmod +x "${BUILD_PATH}/bin/python2.7"
+ fi
+}
+
+require_distro() {
+ for arg; do
+ if [[ "$(cat /etc/issue 2>/dev/null || true)" == "$arg"* ]]; then
+ return 0
+ fi
+ done
+ { echo
+ colorize 1 "WARNING"
+ echo ": This binary distribution is built for the following distro(s): $@."
+ echo "installed binary may not run expectedly on other platforms."
+ echo
+ } >&2
+ return 1
+}
+
+require_osx_version() {
+ function version { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; }
+
+ local required_version="$@"
+ local osx_version="${_PYTHON_BUILD_CACHE_SW_VERS:=$(sw_vers -productVersion)}"
+ if [[ $(version $osx_version) -ge $(version $required_version) ]]; then
+ return 0
+ fi
+ return 1
+}
+
+configured_with_package_dir() {
+ local package_var_name="$(capitalize "$1")"
+ shift 1
+ local PACKAGE_CONFIGURE_OPTS="${package_var_name}_CONFIGURE_OPTS"
+ local PACKAGE_CONFIGURE_OPTS_ARRAY="${package_var_name}_MAKE_OPTS_ARRAY[@]"
+ local arg flag
+ for arg in ${CONFIGURE_OPTS} ${!PACKAGE_CONFIGURE_OPTS} "${!PACKAGE_CONFIGURE_OPTS_ARRAY}"; do
+ if [[ "$arg" == "CPPFLAGS="* ]]; then
+ for flag in ${CPPFLAGS} ${arg##CPPFLAGS=}; do
+ if [[ "$flag" == "-I"* ]]; then
+ local header
+ for header in "$@"; do
+ if [ -e "${flag##-I}/${header#/}" ]; then
+ return 0
+ fi
+ done
+ fi
+ done
+ fi
+ done
+ return 1
+}
+
+# `python-config` ignores LDFLAGS envvar. Adding to LIBS is the only way to add extra stuff
+# to `python-config --ldflags` output
+append_ldflags_libs() {
+ local args="$1"
+ export LDFLAGS="${LDFLAGS:+$LDFLAGS }$args"
+ export LIBS="${LIBS:+${LIBS% } }$args"
+}
+prepend_ldflags_libs() {
+ local args="$1"
+ export LDFLAGS="$args${LDFLAGS:+ $LDFLAGS}"
+ export LIBS="$args${LIBS:+ $LIBS}"
+}
+
+use_homebrew() {
+ can_use_homebrew || return 1
+ # unless Homebrew is at the default /usr/local, need to add its paths to
+ # compiler search to be able to use non-keg-only deps from there
+ if command -v brew &>/dev/null; then
+ local brew_prefix="$(brew --prefix 2>/dev/null || true)"
+ # /usr/local/lib:/usr/lib is the default library search path
+ if [[ -n $brew_prefix && $brew_prefix != "/usr" && $brew_prefix != "/usr/local" ]]; then
+ export CPPFLAGS="${CPPFLAGS:+$CPPFLAGS }-I${brew_prefix}/include"
+ append_ldflags_libs "-L${brew_prefix}/lib -Wl,-rpath,${brew_prefix}/lib"
+ fi
+ fi
+}
+
+needs_yaml() {
+ ! configured_with_package_dir "python" "yaml.h" &&
+ ! use_homebrew_yaml
+}
+
+use_homebrew_yaml() {
+ can_use_homebrew || return 1
+ local libdir="$(brew --prefix libyaml 2>/dev/null || true)"
+ if [ -d "$libdir" ]; then
+ echo "python-build: use libyaml from homebrew"
+ export CPPFLAGS="-I$libdir/include${CPPFLAGS:+ $CPPFLAGS}"
+ export LDFLAGS="-L$libdir/lib${LDFLAGS:+ ${LDFLAGS% }}"
+ else
+ return 1
+ fi
+}
+
+use_freebsd_pkg() {
+ # check if FreeBSD
+ if [ "FreeBSD" = "${_PYTHON_BUILD_CACHE_UNAME_S:=$(uname -s)}" ]; then
+ # use openssl if installed from Ports Collection
+ if pkg info -e openssl; then
+ package_option python configure --with-openssl="/usr/local"
+ fi
+
+ # check if 11-R or later
+ release="${_PYTHON_BUILD_CACHE_UNAME_R:=$(uname -r)}"
+ if [ "${release%%.*}" -ge 11 ]; then
+ # Use packages from Ports Collection.
+ #
+ # Unlike Linux, BSD's cc does not look in /usr/local by default
+ # where Ports-installed packages are, but they are available via pkg-config.
+ # Surprisingly, CPython's Configure only uses pkg-config
+ # to locate some of the dependencies and not others.
+ # Here we detect those that are (as of this writing) known
+ # to not be searched via pkg-config.
+ #
+ # XXX: As a side effect, this would pick up any other libs from Ports
+ # that are searched via compiler
+ if pkg info -e readline || pkg info -e sqlite3; then
+ export CPPFLAGS="${CPPFLAGS:+$CPPFLAGS }-I/usr/local/include"
+ export LDFLAGS="${LDFLAGS:+$LDFLAGS }-L/usr/local/lib -Wl,-rpath,/usr/local/lib"
+ fi
+ fi
+ fi
+}
+
+has_broken_mac_readline() {
+ # Mac OS X 10.4 has broken readline.
+ # https://github.com/pyenv/pyenv/issues/23
+ is_mac &&
+ ! configured_with_package_dir "python" "readline/rlconf.h" &&
+ ! use_homebrew_readline
+}
+
+use_homebrew_readline() {
+ can_use_homebrew || return 1
+ if ! configured_with_package_dir "python" "readline/rlconf.h"; then
+ local libdir="$(brew --prefix readline 2>/dev/null || true)"
+ if [ -d "$libdir" ]; then
+ echo "python-build: use readline from homebrew"
+ export CPPFLAGS="-I$libdir/include${CPPFLAGS:+ $CPPFLAGS}"
+ export LDFLAGS="-L$libdir/lib${LDFLAGS:+ $LDFLAGS}"
+ else
+ return 1
+ fi
+ fi
+}
+
+use_homebrew_ncurses() {
+ can_use_homebrew || return 1
+ local libdir="$(brew --prefix ncurses 2>/dev/null || true)"
+ if [ -d "$libdir" ]; then
+ echo "python-build: use ncurses from homebrew"
+ export CPPFLAGS="-I$libdir/include${CPPFLAGS:+ $CPPFLAGS}"
+ export LDFLAGS="-L$libdir/lib${LDFLAGS:+ $LDFLAGS}"
+ else
+ return 1
+ fi
+}
+
+prefer_openssl11() {
+ # Allow overriding the preference of OpenSSL version per definition basis (#1302, #1325, #1326)
+ PYTHON_BUILD_HOMEBREW_OPENSSL_FORMULA="${PYTHON_BUILD_HOMEBREW_OPENSSL_FORMULA:-openssl@1.1 openssl}"
+ export PYTHON_BUILD_HOMEBREW_OPENSSL_FORMULA
+}
+
+prefer_openssl3() {
+ # Allow overriding the preference of OpenSSL version per definition basis (#1302, #1325, #1326)
+ PYTHON_BUILD_HOMEBREW_OPENSSL_FORMULA="${PYTHON_BUILD_HOMEBREW_OPENSSL_FORMULA:-openssl@3 openssl@1.1 openssl}"
+ export PYTHON_BUILD_HOMEBREW_OPENSSL_FORMULA
+}
+
+build_package_mac_readline() {
+ # Install to a subdirectory since we don't want shims for bin/readline.
+ READLINE_PREFIX_PATH="${PREFIX_PATH}/readline"
+
+ # Tell Python to use this readline for its extension.
+ export CPPFLAGS="-I${READLINE_PREFIX_PATH}/include${CPPFLAGS:+ $CPPFLAGS}"
+ export LDFLAGS="-L${READLINE_PREFIX_PATH}/lib${LDFLAGS:+ $LDFLAGS}"
+
+ # Make sure pkg-config finds our build first.
+ export PKG_CONFIG_PATH="${READLINE_PREFIX_PATH}/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}"
+
+ build_package_standard "$@"
+}
+
+has_broken_mac_openssl() {
+ is_mac || return 1
+ local openssl_version="$(/usr/bin/openssl version 2>/dev/null || true)"
+ [[ $openssl_version = "OpenSSL 0.9.8"?* || $openssl_version = "LibreSSL"* ]] &&
+ ! use_homebrew_openssl
+}
+
+use_homebrew_openssl() {
+ can_use_homebrew || return 1
+ command -v brew >/dev/null || return 1
+ for openssl in ${PYTHON_BUILD_HOMEBREW_OPENSSL_FORMULA:-openssl}; do
+ local ssldir="$(brew --prefix "${openssl}" || true)"
+ if [ -d "$ssldir" ]; then
+ echo "python-build: use ${openssl} from homebrew"
+ if [[ -n "${PYTHON_BUILD_CONFIGURE_WITH_OPENSSL:-}" ]]; then
+ # configure script of newer CPython versions support `--with-openssl`
+ # https://bugs.python.org/issue21541
+ package_option python configure --with-openssl="${ssldir}"
+ else
+ export CPPFLAGS="-I$ssldir/include ${CPPFLAGS:+ $CPPFLAGS}"
+ export LDFLAGS="-L$ssldir/lib${LDFLAGS:+ $LDFLAGS}"
+ fi
+ export PKG_CONFIG_PATH="$ssldir/lib/pkgconfig/:${PKG_CONFIG_PATH}"
+ return
+ fi
+ done
+ return 1
+}
+
+build_package_mac_openssl() {
+ # Install to a subdirectory since we don't want shims for bin/openssl.
+ OPENSSL_PREFIX_PATH="${PREFIX_PATH}/openssl"
+
+ # Put openssl.conf, certs, etc in ~/.pyenv/versions/*/openssl/ssl
+ OPENSSLDIR="${OPENSSLDIR:-$OPENSSL_PREFIX_PATH/ssl}"
+
+ # Tell Python to use this openssl for its extension.
+ if [[ -n "${PYTHON_BUILD_CONFIGURE_WITH_OPENSSL:-}" ]]; then
+ # configure script of newer CPython versions support `--with-openssl`
+ # https://bugs.python.org/issue21541
+ package_option python configure --with-openssl="${OPENSSL_PREFIX_PATH}"
+ else
+ export CPPFLAGS="-I${OPENSSL_PREFIX_PATH}/include ${CPPFLAGS:+ $CPPFLAGS}"
+ export LDFLAGS="-L${OPENSSL_PREFIX_PATH}/lib${LDFLAGS:+ $LDFLAGS}"
+ fi
+
+ # Make sure pkg-config finds our build first.
+ export PKG_CONFIG_PATH="${OPENSSL_PREFIX_PATH}/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}"
+
+ # Hint OpenSSL that we prefer a 64-bit build.
+ export KERNEL_BITS="64"
+ OPENSSL_CONFIGURE="${OPENSSL_CONFIGURE:-./config}"
+
+ local nokerberos
+ [[ "$1" != openssl-1.0.* ]] || nokerberos=1
+
+ # switches introduced in OpenSSL 3.2
+ local extra_no_features
+ [[ $(openssl_version $1) -ge 30200 ]] && extra_no_features=1
+
+ # Compile a shared lib with zlib dynamically linked.
+ package_option openssl configure --openssldir="$OPENSSLDIR" zlib-dynamic no-ssl3 shared ${nokerberos:+no-ssl2 no-krb5} ${extra_no_features:+no-docs no-apps} no-tests
+
+ build_package_standard "$@"
+
+ # Extract root certs from the system keychain in .pem format and rehash.
+ local pem_file="$OPENSSLDIR/cert.pem"
+ security find-certificate -a -p /Library/Keychains/System.keychain > "$pem_file"
+ security find-certificate -a -p /System/Library/Keychains/SystemRootCertificates.keychain >> "$pem_file"
+}
+
+# openssl-1.0.1k -> 10001
+# openssl-3.2.1 -> 30201
+openssl_version() {
+ local -a ver
+ IFS=- ver=( ${1:?} )
+ IFS=. ver=( ${ver[1]} )
+ [[ ${ver[2]} =~ ^([[:digit:]]+)[[:alpha:]]$ ]] && ver[2]="${BASH_REMATCH[1]}"
+ echo $(( ${ver[0]}*10000 + ${ver[1]}*100 + ${ver[2]} ))
+}
+
+# Post-install check that the openssl extension was built.
+build_package_verify_openssl() {
+ "$RUBY_BIN" -e '
+ manager = ARGV[0]
+ packages = {
+ "apt-get" => Hash.new {|h,k| "lib#{k}-dev" }.update(
+ "openssl" => "libssl-dev",
+ "zlib" => "zlib1g-dev"
+ ),
+ "yum" => Hash.new {|h,k| "#{k}-devel" }.update(
+ "yaml" => "libyaml-devel"
+ )
+ }
+
+ failed = %w[openssl readline zlib yaml].reject do |lib|
+ begin
+ require lib
+ rescue LoadError
+ $stderr.puts "The Ruby #{lib} extension was not compiled."
+ end
+ end
+
+ if failed.size > 0
+ $stderr.puts "ERROR: Ruby install aborted due to missing extensions"
+ $stderr.print "Try running `%s install -y %s` to fetch missing dependencies.\n\n" % [
+ manager,
+ failed.map { |lib| packages.fetch(manager)[lib] }.join(" ")
+ ] unless manager.empty?
+ $stderr.puts "Configure options used:"
+ require "rbconfig"; require "shellwords"
+ RbConfig::CONFIG.fetch("configure_args").shellsplit.each { |arg| $stderr.puts " #{arg}" }
+ exit 1
+ end
+ ' "$(basename "$(type -P yum apt-get | head -n1)")" >&4 2>&1
+}
+
+use_homebrew_zlib() {
+ can_use_homebrew || return 1
+ local brew_zlib="$(brew --prefix zlib 2>/dev/null || true)"
+ if [ -d "$brew_zlib" ]; then
+ echo "python-build: use zlib from homebrew"
+ export CFLAGS="-I${brew_zlib} ${CFLAGS}"
+ fi
+}
+
+use_xcode_sdk_zlib() {
+ # If a custom compiler is used, including XCode SDK will likely break it
+ [[ "${CC:-clang}" != "clang" || "$(command -v clang 2>/dev/null || true)" != "/usr/bin/clang" ]] && return 1
+ local xc_sdk_path="$(xcrun --show-sdk-path 2>/dev/null || true)"
+ if [ -d "$xc_sdk_path" ]; then
+ echo "python-build: use zlib from xcode sdk"
+ # Even though SDK's compiler uses the SDK dirs implicitly,
+ # CPython's setup.py has to have nonstandard paths specified explicitly
+ # to search for zlib.h in them
+ export CPPFLAGS="${CPPFLAGS:+$CPPFLAGS }-I${xc_sdk_path}/usr/include"
+ if is_mac -ge 1100; then
+ export LDFLAGS="${LDFLAGS:+$LDFLAGS }-L${xc_sdk_path}/usr/lib"
+ fi
+ fi
+}
+
+use_homebrew_tcltk() {
+ can_use_homebrew || return 1
+ # Since https://github.com/Homebrew/homebrew-core/commit/f10e88617b41555193c22fdcba6109fe82155ee2 (10.11.2024),
+ # tcl-tk is 9.0 which is not compatible with CPython as of this writing
+ # but we'll keep it as backup for cases like non-updated Homebrew
+ local tcltk
+ for tcltk in "tcl-tk@8" "tcl-tk"; do
+ local tcltk_libdir="$(brew --prefix "${tcltk}" 2>/dev/null || true)"
+ if [ -d "$tcltk_libdir" ]; then
+ echo "python-build: use tcl-tk from homebrew"
+ if [[ -z "$PYTHON_BUILD_TCLTK_USE_PKGCONFIG" ]]; then
+ local tcltk_version="$(sh -c '. '"$tcltk_libdir"'/lib/tclConfig.sh; echo $TCL_VERSION')"
+ package_option python configure --with-tcltk-libs="-L$tcltk_libdir/lib -ltcl$tcltk_version -ltk$tcltk_version"
+ # In Homebrew Tcl/Tk 8.6.13, headers have been moved to the 'tcl-tk' subdir.
+ # We're not using tclConfig.sh here 'cuz it produces the version-specific path to <brew prefix>/Cellar
+ # and we'd rather have rpath set to <brew prefix>/opt/<...> to allow micro release upgrades without rebuilding
+ # XXX: do use tclConfig.sh and translate the paths if more path shenanigans appear in later releases
+ if [ -d "$tcltk_libdir/include/tcl-tk" ]; then
+ package_option python configure --with-tcltk-includes="-I$tcltk_libdir/include/tcl-tk"
+ else
+ package_option python configure --with-tcltk-includes="-I$tcltk_libdir/include"
+ fi
+ fi
+ export PKG_CONFIG_PATH="${tcltk_libdir}/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}"
+ return 0
+ fi
+ done
+ return 1
+}
+
+# FIXME: this function is a workaround for #1125
+# once fixed, it should be removed.
+# if tcltk_ops_flag is in PYTHON_CONFIGURE_OPTS, use user provided tcltk
+use_custom_tcltk() {
+ local tcltk_ops="$(get_tcltk_flag_from "$PYTHON_CONFIGURE_OPTS")"
+
+ if [[ -z "$tcltk_ops" ]]; then
+ return 1
+ fi
+ local tcltk_ops_flag="--with-tcltk-libs="
+ # get tcltk libs
+ local tcltk_libs="${tcltk_ops//$tcltk_ops_flag/}"
+ # remove tcltk-flag from configure_opts
+ # this allows for weird input such as
+ # --with-tcltk-libs=' -L/custom-tcl-tk/lib -ltcl8.6 -ltk8.4 '
+ PYTHON_CONFIGURE_OPTS="${PYTHON_CONFIGURE_OPTS//"$tcltk_ops_flag"/}"
+ PYTHON_CONFIGURE_OPTS="${PYTHON_CONFIGURE_OPTS//$tcltk_libs/}"
+
+ # remove quotes, because there mess up compilations
+ PYTHON_CONFIGURE_OPTS="${PYTHON_CONFIGURE_OPTS//"''"/}"
+ PYTHON_CONFIGURE_OPTS="${PYTHON_CONFIGURE_OPTS//'""'/}"
+
+ echo "python-build: use tcl-tk from \$PYTHON_CONFIGURE_OPTS"
+ # echo "PYTHON_CONFIGURE_OPTS=${PYTHON_CONFIGURE_OPTS}"
+ package_option python configure --with-tcltk-libs="${tcltk_libs}"
+ # IFS="$OLDIFS"
+}
+
+# FIXME: this function is a workaround for #1125
+# once fixed, it should be removed.
+# Get tcltk-flag and options from `$1`
+# expects one argument containing a string of configure opts, eg. `PYTHON_CONFIGURE_OPTS`
+# returns tcl_tk flag or an empty string if nothing was found.
+get_tcltk_flag_from() {
+ IFS=$'\n'
+ # parse input string into array
+ local opts_arr=( $(xargs -n1 <<<"$1") )
+
+ # iterate through `opts_arr`, break if `--with-tcltk-libs=` was found.
+ for opts in ${opts_arr[@]}; do
+ # `--with-tcltk-libs=` must be the prefix.
+ if [[ "$opts" == "--with-tcltk-libs="* ]]; then
+ # return
+ echo "$opts"
+ break
+ fi
+ done
+
+ IFS="$OLDIFS"
+}
+
+# Since 3.12, CPython can add DWARF debug information in MacOS
+# using Apple's nonstandard way, `dsymutil', that creates a "dSYM bundle"
+# that's supposed to be installed alongside executables
+# (https://github.com/python/cpython/issues/95973).
+use_dsymutil() {
+ if [[ -n "$PYTHON_BUILD_CONFIGURE_WITH_DSYMUTIL" ]] && is_mac; then
+ package_option python configure --with-dsymutil
+ fi
+}
+
+use_free_threading() {
+ if [[ -n "$PYTHON_BUILD_FREE_THREADING" ]]; then
+ package_option python configure --disable-gil
+ fi
+}
+
+build_package_enable_shared() {
+ package_option python configure --enable-shared
+}
+
+build_package_auto_tcltk() {
+ if is_mac && [ ! -d /usr/include/X11 ]; then
+ if [ -d /opt/X11/include ]; then
+ if [[ "$CPPFLAGS" != *-I/opt/X11/include* ]]; then
+ export CPPFLAGS="-I/opt/X11/include${CPPFLAGS:+ $CPPFLAGS}"
+ fi
+ else
+ package_option python configure --without-tk
+ fi
+ fi
+}
+
+package_is_python() {
+ case "$1" in
+ Python-* | jython-* | pypy-* | pypy[0-9].+([0-9])-* | stackless-* )
+ return 0
+ ;;
+ esac
+ return 1
+}
+
+apply_patch() {
+ local package_name="$1"
+ local patchfile
+ patchfile="$(mktemp "${TMP}/python-patch.XXXXXX")"
+ cat "${2:--}" >"$patchfile"
+
+ local striplevel=0
+ grep -q '^diff --git a/' "$patchfile" && striplevel=1
+ patch -p$striplevel --force -i "$patchfile"
+}
+
+
+build_package_symlink_version_suffix() {
+ if [[ "${PYTHON_CONFIGURE_OPTS_ARRAY[*]} $CONFIGURE_OPTS $PYTHON_CONFIGURE_OPTS" == *"--enable-framework"* ]]; then
+ if [ -e "${PREFIX_PATH}/bin" ]; then
+ # Always create `bin` as symlink to framework path if the version was built with `--enable-framework` (#590)
+ rm -rf "${PREFIX_PATH}/bin.orig"
+ mv -f "${PREFIX_PATH}/bin" "${PREFIX_PATH}/bin.orig"
+ fi
+ # Only symlinks are installed in ${PREFIX_PATH}/bin
+ ln -fs "${PREFIX_PATH}/Library/Frameworks/Python.framework/Versions/Current/bin" "${PREFIX_PATH}/bin"
+ fi
+
+ # Not create symlinks on `altinstall` (#255)
+ if [[ "$PYTHON_MAKE_INSTALL_TARGET" != *"altinstall"* ]]; then
+ shopt -s nullglob
+ local version_bin="$(ls -1 "${PREFIX_PATH}/bin/python"* | grep '[0-9]$' | sort | tail -1)"
+ suffix="$(basename "${version_bin}" | sed -e 's/^python//')"
+ if [ -n "${suffix}" ]; then
+ local file link
+ for file in "${PREFIX_PATH}/bin"/*; do
+ unset link
+ case "${file}" in
+ */"python${suffix}-config" )
+ # Symlink `pythonX.Y-config` to `python-config` if `python-config` is missing (#296)
+ link="${file%/*}/python-config"
+ ;;
+ */*"-${suffix}" )
+ link="${file%%-${suffix}}"
+ ;;
+ */*"${suffix}" )
+ link="${file%%${suffix}}"
+ ;;
+ esac
+ if [ -n "$link" ] && [ ! -e "$link" ]; then
+ ( cd "${file%/*}" && ln -fs "${file##*/}" "${link##*/}" )
+ fi
+ done
+ fi
+ shopt -u nullglob
+ fi
+}
+
+verify_python() {
+ build_package_symlink_version_suffix
+
+ if [ ! -x "${PYTHON_BIN}" ]; then
+ { colorize 1 "ERROR"
+ echo ": invalid Python executable: ${PYTHON_BIN}"
+ echo
+ echo "The python-build could not find proper executable of Python after successful build."
+ echo "Please open an issue for future improvements."
+ echo "https://github.com/pyenv/pyenv/issues"
+ return 1
+ } >&3
+ fi
+}
+
+try_python_module() {
+ if ! "$PYTHON_BIN" -c "import $1"; then
+ { colorize 1 "WARNING"
+ echo ": The Python $1 extension was not compiled${3:+ $3}. Missing the ${2:-$1}?"
+ return 0
+ } >&3
+ fi
+}
+
+verify_python_module() {
+ if ! "$PYTHON_BIN" -c "import $1"; then
+ { colorize 1 "ERROR"
+ echo ": The Python $1 extension was not compiled. Missing the ${2:-$1}?"
+ echo
+ echo "Please consult to the Wiki page to fix the problem."
+ echo "https://github.com/pyenv/pyenv/wiki/Common-build-problems"
+ echo
+ return 1
+ } >&3
+ fi
+}
+
+# Post-install check for Python 2.1.x
+build_package_verify_py21() {
+ verify_python "${2:-python2.1}"
+ try_python_module "readline" "GNU readline lib"
+ verify_python_module "binascii" "binascii"
+ # fixme: zlib doesn't link correctly on 64-bit Linux, due to being in
+ # /usr/x86_64-linux-gnu instead of /usr/lib
+ try_python_module "zlib" "zlib"
+ try_python_module "bz2" "bzip2 lib"
+}
+
+# Post-install check for Python 2.2.x
+build_package_verify_py22() {
+ verify_python "${2:-python2.2}"
+ try_python_module "readline" "GNU readline lib"
+ verify_python_module "binascii" "binascii"
+ # fixme: zlib doesn't link correctly on 64-bit Linux, due to being in
+ # /usr/x86_64-linux-gnu instead of /usr/lib
+ try_python_module "zlib" "zlib"
+ try_python_module "bz2" "bzip2 lib"
+}
+
+# Post-install check for Python 2.3.x
+build_package_verify_py23() {
+ verify_python "${2:-python2.3}"
+ try_python_module "readline" "GNU readline lib"
+ verify_python_module "binascii" "binascii"
+ # fixme: zlib doesn't link correctly on 64-bit Linux, due to being in
+ # /usr/x86_64-linux-gnu instead of /usr/lib
+ try_python_module "zlib" "zlib"
+ try_python_module "bz2" "bzip2 lib"
+}
+
+# Post-install check for Python 2.4.x
+build_package_verify_py24() {
+ verify_python "${2:-2.4}"
+ try_python_module "readline" "GNU readline lib"
+ verify_python_module "zlib" "zlib"
+ try_python_module "bz2" "bzip2 lib"
+}
+
+# Post-install check for Python 2.5.x
+build_package_verify_py25() {
+ build_package_verify_py24 "$1" "${2:-2.5}"
+ try_python_module "sqlite3" "SQLite3 lib"
+}
+
+# Post-install check for Python 2.6.x
+build_package_verify_py26() {
+ build_package_verify_py25 "$1" "${2:-2.6}"
+ verify_python_module "ssl" "OpenSSL lib"
+}
+
+# Post-install check for Python 2.7.x
+build_package_verify_py27() {
+ build_package_verify_py26 "$1" "${2:-2.7}"
+}
+
+# Post-install check for Python 3.0.x
+build_package_verify_py30() {
+ verify_python "${2:-3.0}"
+ try_python_module "bz2" "bzip2 lib"
+ try_python_module "curses" "ncurses lib"
+ try_python_module "ctypes" "libffi lib"
+ try_python_module "readline" "GNU readline lib"
+ verify_python_module "ssl" "OpenSSL lib"
+ try_python_module "sqlite3" "SQLite3 lib"
+ if [[ -n $DISPLAY ]]; then
+ try_python_module "tkinter" "Tk toolkit" "and GUI subsystem has been detected"
+ fi
+ verify_python_module "zlib" "zlib"
+}
+
+# Post-install check for Python 3.1.x
+build_package_verify_py31() {
+ build_package_verify_py30 "$1" "${2:-3.1}"
+}
+
+# Post-install check for Python 3.2.x
+build_package_verify_py32() {
+ build_package_verify_py31 "$1" "${2:-3.2}"
+}
+
+# Post-install check for Python 3.3.x
+build_package_verify_py33() {
+ build_package_verify_py32 "$1" "${2:-3.3}"
+ try_python_module "lzma" "lzma lib"
+}
+
+# Post-install check for Python 3.4.x
+build_package_verify_py34() {
+ build_package_verify_py33 "$1" "${2:-3.4}"
+}
+
+# Post-install check for Python 3.5.x
+build_package_verify_py35() {
+ build_package_verify_py34 "$1" "${2:-3.5}"
+}
+
+# Post-install check for Python 3.6.x
+build_package_verify_py36() {
+ build_package_verify_py35 "$1" "${2:-3.6}"
+}
+
+# Post-install check for Python 3.7.x
+build_package_verify_py37() {
+ build_package_verify_py36 "$1" "${2:-3.7}"
+}
+
+# Post-install check for Python 3.8.x
+build_package_verify_py38() {
+ build_package_verify_py37 "$1" "${2:-3.8}"
+}
+
+# Post-install check for Python 3.9.x
+build_package_verify_py39() {
+ build_package_verify_py38 "$1" "${2:-3.9}"
+}
+
+# Post-install check for Python 3.10.x
+build_package_verify_py310() {
+ build_package_verify_py39 "$1" "${2:-3.10}"
+}
+
+# Post-install check for Python 3.11.x
+build_package_verify_py311() {
+ build_package_verify_py310 "$1" "${2:-3.11}"
+}
+
+# Post-install check for Python 3.12.x
+build_package_verify_py312() {
+ build_package_verify_py311 "$1" "${2:-3.12}"
+}
+
+# Post-install check for Python 3.13.x
+build_package_verify_py313() {
+ build_package_verify_py312 "$1" "${2:-3.13}"
+}
+
+# Post-install check for Python 3.14.x
+build_package_verify_py314() {
+ build_package_verify_py313 "$1" "${2:-3.14}"
+}
+
+# Post-install check for Python 3.15.x
+build_package_verify_py315() {
+ build_package_verify_py314 "$1" "${2:-3.15}"
+}
+
+# Post-install check for Python 3.x rolling release scripts
+# XXX: Will need splitting into project-specific ones if there emerge
+# multiple rolling-release scripts with different checks needed
+build_package_verify_py3_latest() {
+ build_package_verify_py311 "$1" "3"
+}
+
+# Copy Tools/gdb/libpython.py to pythonX.Y-gdb.py (#1190)
+build_package_copy_python_gdb() {
+ if [ -e "$BUILD_PATH/$1/Tools/gdb/libpython.py" ]; then
+ local version_re='-([0-9]\.[0-9]+)'
+ [[ "$1" =~ $version_re ]]
+ local python_bin="$PREFIX_PATH/bin/python${BASH_REMATCH[1]}"
+ cp "$BUILD_PATH/$1/Tools/gdb/libpython.py" "$python_bin-gdb.py"
+ fi
+}
+
+build_package_ez_setup() {
+ local ez_setup="ez_setup.py"
+ rm -f "${ez_setup}"
+ { if [ "${EZ_SETUP+defined}" ] && [ -f "${EZ_SETUP}" ]; then
+ echo "Installing setuptools from ${EZ_SETUP}..." 1>&2
+ cat "${EZ_SETUP}"
+ else
+ [ -n "${EZ_SETUP_URL}" ]
+ echo "Installing setuptools from ${EZ_SETUP_URL}..." 1>&2
+ http get "${EZ_SETUP_URL}"
+ fi
+ } 1> "${ez_setup}"
+ "${PYTHON_BIN}" "${ez_setup}" ${EZ_SETUP_OPTS} 1>&4 2>&1 || {
+ echo "error: failed to install setuptools via ez_setup.py" >&2
+ return 1
+ }
+ build_package_symlink_version_suffix
+}
+
+build_package_get_pip() {
+ local get_pip="get-pip.py"
+ rm -f "${get_pip}"
+ { if [ "${GET_PIP+defined}" ] && [ -f "${GET_PIP}" ]; then
+ echo "Installing pip from ${GET_PIP}..." 1>&2
+ cat "${GET_PIP}"
+ else
+ [ -n "${GET_PIP_URL}" ]
+ echo "Installing pip from ${GET_PIP_URL}..." 1>&2
+ http get "${GET_PIP_URL}"
+ fi
+ } 1> "${get_pip}"
+ "${PYTHON_BIN}" -s "${get_pip}" ${GET_PIP_OPTS} 1>&4 2>&1 || {
+ echo "error: failed to install pip via get-pip.py" >&2
+ return 1
+ }
+ build_package_symlink_version_suffix
+}
+
+# Pip <21 (in 2.7 and derivatives like PyPy-2.7) doesn't support -I
+build_package_ensurepip_lt21() {
+ build_package_ensurepip lt21
+}
+
+build_package_ensurepip() {
+ local mode="$1"
+ local ensurepip_opts
+ # Install as `--altinstall` if the Python is installed as `altinstall` (#255)
+ if [[ "$PYTHON_MAKE_INSTALL_TARGET" == *"altinstall"* ]]; then
+ ensurepip_opts="--altinstall"
+ fi
+ local python_opts="-I"
+ if [[ $mode == "lt21" ]]; then python_opts="-s"; fi
+
+ # FIXME: `--altinstall` with `get-pip.py`
+ "$PYTHON_BIN" $python_opts -m ensurepip ${ensurepip_opts} 1>/dev/null 2>&1 || build_package_get_pip "$@" || return 1
+ build_package_symlink_version_suffix
+}
+
+version() {
+ local git_revision
+ # Read the revision from git if the remote points to "python-build" repository
+ if GIT_DIR="$PYTHON_BUILD_INSTALL_PREFIX/../../.git" git remote -v 2>/dev/null | grep -q /pyenv; then
+ git_revision="$(GIT_DIR="$PYTHON_BUILD_INSTALL_PREFIX/../../.git" git describe --tags HEAD 2>/dev/null || true)"
+ git_revision="${git_revision#v}"
+ fi
+ echo "python-build ${git_revision:-$PYTHON_BUILD_VERSION}"
+}
+
+usage() {
+ sed -ne '/^#/!q;s/.\{1,2\}//;1,2d;p' < "$0"
+ [ -z "$1" ] || exit "$1"
+}
+
+list_definitions() {
+ { for DEFINITION_DIR in "${PYTHON_BUILD_DEFINITIONS[@]}"; do
+ [ -d "$DEFINITION_DIR" ] && ls "$DEFINITION_DIR" | grep -xv patches
+ done
+ } | sort_versions | uniq
+}
+
+sort_versions() {
+ sed 'h; s/[+-]/./g; s/.p\([[:digit:]]\)/.z.\1/; s/$/.z/; G; s/\n/ /' | \
+ LC_ALL=C sort -t. -k 1,1 -k 2,2n -k 3,3n -k 4,4n -k 5,5n | awk '{print $2}'
+}
+
+
+unset VERBOSE
+unset KEEP_BUILD_PATH
+unset HAS_PATCH
+unset DEBUG
+unset IPV4
+unset IPV6
+
+PYTHON_BUILD_INSTALL_PREFIX="$(abs_dirname "$0")/.."
+
+IFS=: PYTHON_BUILD_DEFINITIONS=($PYTHON_BUILD_DEFINITIONS ${PYTHON_BUILD_ROOT:-$PYTHON_BUILD_INSTALL_PREFIX}/share/python-build)
+IFS="$OLDIFS"
+
+parse_options "$@"
+
+for option in "${OPTIONS[@]}"; do
+ case "$option" in
+ "h" | "help" )
+ version
+ echo
+ usage 0
+ ;;
+ "definitions" )
+ list_definitions
+ exit 0
+ ;;
+ "k" | "keep" )
+ KEEP_BUILD_PATH=true
+ ;;
+ "v" | "verbose" )
+ VERBOSE=true
+ ;;
+ "p" | "patch" )
+ HAS_STDIN_PATCH=true
+ ;;
+ "g" | "debug" )
+ DEBUG=true
+ # Disable optimization (#808)
+ PYTHON_CFLAGS="-O0 ${PYTHON_CFLAGS}"
+ ;;
+ "4" | "ipv4")
+ IPV4=true
+ ;;
+ "6" | "ipv6")
+ IPV6=true
+ ;;
+ "version" )
+ version
+ exit 0
+ ;;
+ esac
+done
+
+[ "${#ARGUMENTS[@]}" -eq 2 ] || usage 1 >&2
+
+DEFINITION_PATH="${ARGUMENTS[0]}"
+if [ -z "$DEFINITION_PATH" ]; then
+ usage 1 >&2
+elif [ ! -f "$DEFINITION_PATH" ]; then
+ for DEFINITION_DIR in "${PYTHON_BUILD_DEFINITIONS[@]}"; do
+ if [ -f "${DEFINITION_DIR}/${DEFINITION_PATH}" ]; then
+ DEFINITION_PATH="${DEFINITION_DIR}/${DEFINITION_PATH}"
+ break
+ fi
+ done
+
+ if [ ! -f "$DEFINITION_PATH" ]; then
+ echo "python-build: definition not found: ${DEFINITION_PATH}" >&2
+ exit 2
+ fi
+fi
+
+PREFIX_PATH="${ARGUMENTS[1]}"
+if [ -z "$PREFIX_PATH" ]; then
+ usage 1 >&2
+elif [ "${PREFIX_PATH#/}" = "$PREFIX_PATH" ]; then
+ PREFIX_PATH="${PWD}/${PREFIX_PATH}"
+fi
+
+if [ -z "$TMPDIR" ]; then
+ TMP="/tmp"
+else
+ TMP="${TMPDIR%/}"
+fi
+
+# Check if TMPDIR is accessible and can hold executables.
+tmp_executable="${TMP}/python-build-test.$$"
+noexec=""
+if mkdir -p "$TMP" && touch "$tmp_executable" 2>/dev/null; then
+ cat > "$tmp_executable" <<-EOF
+ #!${BASH}
+ exit 0
+ EOF
+ chmod +x "$tmp_executable"
+else
+ echo "python-build: TMPDIR=$TMP is set to a non-accessible location" >&2
+ exit 1
+fi
+"$tmp_executable" 2>/dev/null || noexec=1
+rm -f "$tmp_executable"
+if [ -n "$noexec" ]; then
+ echo "python-build: TMPDIR=$TMP cannot hold executables (partition possibly mounted with \`noexec\`)" >&2
+ exit 1
+fi
+
+if [ -z "$MAKE" ]; then
+ if [ "FreeBSD" = "${_PYTHON_BUILD_CACHE_UNAME_S:=$(uname -s)}" ]; then
+ if [ "$(echo $1 | sed 's/-.*$//')" = "jruby" ]; then
+ export MAKE="gmake"
+ else
+ # var assignment inside $() does not propagate due to being in subshell
+ : "${_PYTHON_BUILD_CACHE_UNAME_R:=$(uname -r)}"
+ if [ "$(echo "$_PYTHON_BUILD_CACHE_UNAME_R" | sed 's/[^[:digit:]].*//')" -lt 10 ]; then
+ export MAKE="gmake"
+ else
+ export MAKE="make"
+ fi
+ fi
+ else
+ export MAKE="make"
+ fi
+fi
+
+if [ -n "$PYTHON_BUILD_CACHE_PATH" ] && [ -d "$PYTHON_BUILD_CACHE_PATH" ]; then
+ PYTHON_BUILD_CACHE_PATH="${PYTHON_BUILD_CACHE_PATH%/}"
+else
+ unset PYTHON_BUILD_CACHE_PATH
+fi
+
+if [ -z "$PYTHON_BUILD_MIRROR_URL" ]; then
+ PYTHON_BUILD_MIRROR_URL="https://pyenv.github.io/pythons"
+ PYTHON_BUILD_DEFAULT_MIRROR=1
+else
+ PYTHON_BUILD_MIRROR_URL="${PYTHON_BUILD_MIRROR_URL%/}"
+ PYTHON_BUILD_DEFAULT_MIRROR=
+fi
+
+if [ -n "$PYTHON_BUILD_SKIP_MIRROR" ]; then
+ unset PYTHON_BUILD_MIRROR_URL
+fi
+
+if ! has_checksum_support compute_sha2 && ! [ -n "$PYTHON_BUILD_MIRROR_URL_SKIP_CHECKSUM" ] ; then
+ unset PYTHON_BUILD_MIRROR_URL
+fi
+
+ARIA2_OPTS="${PYTHON_BUILD_ARIA2_OPTS} ${IPV4+--disable-ipv6=true} ${IPV6+--disable-ipv6=false}"
+CURL_OPTS="${PYTHON_BUILD_CURL_OPTS} ${IPV4+--ipv4} ${IPV6+--ipv6}"
+WGET_OPTS="${PYTHON_BUILD_WGET_OPTS} ${IPV4+--inet4-only} ${IPV6+--inet6-only}"
+
+# Add an option to build a debug version of Python (#11)
+if [ -n "$DEBUG" ]; then
+ package_option python configure --with-pydebug
+fi
+
+if [[ "$CONFIGURE_OPTS $PYTHON_CONFIGURE_OPTS" != *"--enable-framework"* && "$CONFIGURE_OPTS $PYTHON_CONFIGURE_OPTS" != *"--disable-shared"* ]]; then
+ package_option python configure --enable-shared
+fi
+
+# python-build: Specify `--libdir` on configure to fix build on openSUSE (#36)
+package_option python configure --libdir="${PREFIX_PATH}/lib"
+
+# python-build: Set `RPATH` if `--enable-shared` was given (#65, #66, #82)
+if [[ "$CONFIGURE_OPTS $PYTHON_CONFIGURE_OPTS ${PYTHON_CONFIGURE_OPTS_ARRAY[@]}" == *"--enable-shared"* ]]; then
+ # The ld on Darwin embeds the full paths to each dylib by default
+ if [[ "$LDFLAGS" != *"-rpath="* ]] ; then
+ prepend_ldflags_libs "-Wl,-rpath,${PREFIX_PATH}/lib"
+ fi
+fi
+
+# python-build: Set `RPATH` if --shared` was given for PyPy (#244)
+if [[ "$PYPY_OPTS" == *"--shared"* ]]; then
+ prepend_ldflags_libs "-Wl,-rpath=${PREFIX_PATH}/lib"
+fi
+
+# Add support for framework installation (`--enable-framework`) of CPython (#55, #99)
+if [[ "$CONFIGURE_OPTS $PYTHON_CONFIGURE_OPTS" == *"--enable-framework"* ]]; then
+ if ! is_mac; then
+ echo "python-build: framework installation is not supported outside of MacOS." >&2
+ exit 1
+ fi
+ create_framework_dirs() {
+ local version="$(echo "$1" | sed -E 's/^[^0-9]*([0-9]+\.[0-9]+).*$/\1/')"
+ mkdir -p "${PREFIX_PATH}/Library/Frameworks/Python.framework/Versions/${version}"
+ ( cd "${PREFIX_PATH}/Library/Frameworks/Python.framework/Versions" && ln -fs "${version}" "Current")
+ local path
+ for path in include lib share; do
+ mkdir -p "${PREFIX_PATH}/Library/Frameworks/Python.framework/Versions/Current/${path}"
+ ln -fs "${PREFIX_PATH}/Library/Frameworks/Python.framework/Versions/Current/${path}" "${PREFIX_PATH}/${path}"
+ done
+ }
+ create_framework_dirs "${DEFINITION_PATH##*/}"
+ # the `/Library/Frameworks` suffix makes CPython build install apps under prefix rather than into /Applications (#1003)
+ package_option python configure --enable-framework="${PREFIX_PATH}/Library/Frameworks"
+
+ #FIXME: doesn't properly handle paths with spaces. Fix by parsing *OPTS into arrays.
+ CONFIGURE_OPTS="${CONFIGURE_OPTS//--enable-framework?(=*([^ ]))?( )/}";
+ CONFIGURE_OPTS="${CONFIGURE_OPTS% }"
+ PYTHON_CONFIGURE_OPTS="${PYTHON_CONFIGURE_OPTS//--enable-framework?(=*([^ ]))?( )/}";
+ PYTHON_CONFIGURE_OPTS="${PYTHON_CONFIGURE_OPTS% }"
+fi
+
+# Build against universal SDK
+if [[ "$CONFIGURE_OPTS $PYTHON_CONFIGURE_OPTS" == *"--enable-universalsdk"* ]]; then
+ if ! is_mac; then
+ echo "python-build: universal installation is not supported outside of MacOS." >&2
+ exit 1
+ fi
+ package_option python configure --enable-universalsdk=/
+ #FIXME: doesn't properly handle paths with spaces. Fix by parsing *OPTS into arrays.
+ CONFIGURE_OPTS="${CONFIGURE_OPTS//--enable-universalsdk?(=*([^ ]))?( )/}"
+ CONFIGURE_OPTS="${CONFIGURE_OPTS% }"
+ PYTHON_CONFIGURE_OPTS="${PYTHON_CONFIGURE_OPTS//--enable-universalsdk?(=*([^ ]))?( )/}"
+ PYTHON_CONFIGURE_OPTS="${PYTHON_CONFIGURE_OPTS% }"
+
+ if [[ "$CONFIGURE_OPTS $PYTHON_CONFIGURE_OPTS" != *"--with-universal-archs"* ]]; then
+ # in CPython's configure.ac, --with-universal-archs defaults to 'intel' which means i386 + x86_64
+ # since 2.7.5 and 3.3.0 -- i.e. in all non-EOL versions
+ # Apple Silicon cannot build these, in it, it rather makes sense to default to Universal2 binaries
+ if [[ $(arch) == "arm64" ]]; then
+ package_option python configure --with-universal-archs=universal2
+ fi
+ fi
+fi
+
+# Compile with `--enable-unicode=ucs4` by default (#257)
+if [[ "$PYTHON_CONFIGURE_OPTS" != *"--enable-unicode="* ]]; then
+ if ! is_mac; then
+ # Skip specifying `--enable-unicode` for CPython 3.3+ (#912)
+ case "${DEFINITION_PATH##*/}" in
+ "2."* | \
+ "3.0" | "3.0."* | "3.0-"* | \
+ "3.1" | "3.1."* | "3.1-"* | \
+ "3.2" | "3.2."* | "3.2-"* )
+ package_option python configure --enable-unicode=ucs4
+ ;;
+ esac
+ fi
+fi
+
+# Unset `PIP_REQUIRE_VENV` during build (#216)
+unset PIP_REQUIRE_VENV
+unset PIP_REQUIRE_VIRTUALENV
+
+# pydistutils.cfg may corrupt install location of Python libraries (#35, #111)
+if [ -e "$HOME/.pydistutils.cfg" ]; then
+ { colorize 1 "WARNING"
+ echo ": Please make sure you remove any previous custom paths from your $HOME/.pydistutils.cfg file."
+ } >&2
+fi
+
+# Download specified version of ez_setup.py/get-pip.py (#202)
+if [ -z "${EZ_SETUP_URL}" ]; then
+ if [ -n "${SETUPTOOLS_VERSION}" ]; then
+ EZ_SETUP_URL="https://bitbucket.org/pypa/setuptools/raw/${SETUPTOOLS_VERSION}/ez_setup.py"
+ unset SETUPTOOLS_VERSION
+ else
+ EZ_SETUP_URL="https://bootstrap.pypa.io/ez_setup.py"
+ fi
+fi
+if [ -z "${GET_PIP_URL}" ]; then
+ if [ -n "${PIP_VERSION}" ]; then
+ { colorize 1 "WARNING"
+ echo ": Setting PIP_VERSION=${PIP_VERSION} is no longer supported and may cause failures during the install process."
+ } 1>&2
+ GET_PIP_URL="https://raw.githubusercontent.com/pypa/pip/${PIP_VERSION}/contrib/get-pip.py"
+ # Unset `PIP_VERSION` from environment before invoking `get-pip.py` to deal with "ValueError: invalid truth value" (pypa/pip#4528)
+ unset PIP_VERSION
+ else
+ # Use custom get-pip URL based on the target version (#1127)
+ case "${DEFINITION_PATH##*/}" in
+ 2.6 | 2.6.* )
+ GET_PIP_URL="https://bootstrap.pypa.io/pip/2.6/get-pip.py"
+ ;;
+ 2.7 | 2.7.* | pypy2.7 | pypy2.7-* )
+ GET_PIP_URL="https://bootstrap.pypa.io/pip/2.7/get-pip.py"
+ ;;
+ 3.2 | 3.2.* )
+ GET_PIP_URL="https://bootstrap.pypa.io/pip/3.2/get-pip.py"
+ ;;
+ 3.3 | 3.3.* )
+ GET_PIP_URL="https://bootstrap.pypa.io/pip/3.3/get-pip.py"
+ ;;
+ 3.4 | 3.4.* )
+ GET_PIP_URL="https://bootstrap.pypa.io/pip/3.4/get-pip.py"
+ ;;
+ 3.5 | 3.5.* | pypy3.5 | pypy3.5-* )
+ GET_PIP_URL="https://bootstrap.pypa.io/pip/3.5/get-pip.py"
+ ;;
+ 3.6 | 3.6.* | pypy3.6 | pypy3.6-* )
+ GET_PIP_URL="https://bootstrap.pypa.io/pip/3.6/get-pip.py"
+ ;;
+ 3.7 | 3.7.* | pypy3.7 | pypy3.7-* )
+ GET_PIP_URL="https://bootstrap.pypa.io/pip/3.7/get-pip.py"
+ ;;
+ 3.8 | 3.8.* | pypy3.8 | pypy3.8-* | pyston* )
+ GET_PIP_URL="https://bootstrap.pypa.io/pip/3.8/get-pip.py"
+ ;;
+ * )
+ GET_PIP_URL="https://bootstrap.pypa.io/get-pip.py"
+ ;;
+ esac
+ fi
+fi
+
+# Set MACOSX_DEPLOYMENT_TARGET from the product version of OS X (#219, #220)
+if is_mac; then
+ if [ -z "${MACOSX_DEPLOYMENT_TARGET}" ]; then
+ MACOS_VERSION="${_PYTHON_BUILD_CACHE_SW_VERS:=$(sw_vers -productVersion)}"
+ MACOS_VERSION_ARRAY=(${MACOS_VERSION//\./ })
+ if [ "${#MACOS_VERSION_ARRAY[@]}" -ge 2 ]; then
+ export MACOSX_DEPLOYMENT_TARGET="${MACOS_VERSION_ARRAY[0]}.${MACOS_VERSION_ARRAY[1]}"
+ fi
+ fi
+fi
+
+python_bin_suffix() {
+ local version_name version_info
+ case "$1" in
+ 2.* | 3.* )
+ version_name="$1"
+ version_name="${version_name%-dev}"
+ version_name="${version_name%-rc*}"
+ version_name="${version_name%rc*}"
+ version_name="${version_name%%*([^0-9])}"
+ version_info=(${version_name//./ })
+ echo "${version_info[0]}.${version_info[1]}"
+ ;;
+ stackless-2.* | stackless-3.* )
+ version_name="${1#stackless-}"
+ version_name="${version_name%-dev}"
+ version_name="${version_name%-rc*}"
+ version_name="${version_name%rc*}"
+ version_info=(${version_name//./ })
+ echo "${version_info[0]}.${version_info[1]}"
+ ;;
+ esac
+}
+
+SEED="$(date "+%Y%m%d%H%M%S").$$"
+LOG_PATH="${TMP}/python-build.${SEED}.log"
+PYTHON_BIN="${PREFIX_PATH}/bin/python$(python_bin_suffix "${DEFINITION_PATH##*/}")"
+CWD="$(pwd)"
+
+if [ -z "$PYTHON_BUILD_BUILD_PATH" ]; then
+ BUILD_PATH="${TMP}/python-build.${SEED}"
+else
+ BUILD_PATH="$PYTHON_BUILD_BUILD_PATH"
+fi
+
+exec 4<> "$LOG_PATH" # open the log file at fd 4
+if [ -n "$VERBOSE" ]; then
+ tail -f "$LOG_PATH" &
+ TAIL_PID=$!
+ trap "kill $TAIL_PID" SIGINT SIGTERM EXIT
+fi
+
+prepend_ldflags_libs "-L${PREFIX_PATH}/lib"
+export CPPFLAGS="-I${PREFIX_PATH}/include${CPPFLAGS:+ $CPPFLAGS}"
+
+unset PYTHONHOME
+unset PYTHONPATH
+
+trap build_failed ERR
+mkdir -p "$BUILD_PATH"
+source "$DEFINITION_PATH"
+[ -z "${KEEP_BUILD_PATH}" ] && rm -fr "$BUILD_PATH"
+trap - ERR