#!/usr/bin/env bash # # Usage: python-build [-kvp] # python-build --definitions # # -k/--keep Do not remove source tree after installation # -v/--verbose Verbose mode: print compilation status to stdout # -p/--patch Apply a patch from stdin before building # --definitions List all built-in definitions # -g/--debug Build a debug version # PYTHON_BUILD_VERSION="20141028" set -E 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" resolve_link() { $(type -p greadlink readlink | head -1) "$1" } abs_dirname() { local cwd="$(pwd)" local path="$1" while [ -n "$path" ]; do cd "${path%/*}" local name="${path##*/}" path="$(resolve_link "$name" || true)" done pwd cd "$cwd" } 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 $(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 -1)" echo "${os:-$(uname -sr)}" fi } # 9.1 -> 901 # 10.9 -> 1009 # 10.10 -> 1010 osx_version() { local -a ver IFS=. ver=( `sw_vers -productVersion` ) 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}" 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 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 "$(uname -s)" in Darwin | *BSD ) num="$(sysctl -n hw.ncpu 2>/dev/null || true)" ;; * ) num="$(grep ^processor /proc/cpuinfo 2>/dev/null | wc -l | xargs)" 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}" echo } >&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)"/bin/openssl openssl | head -1)" output="$("$openssl" dgst -sha256 2>/dev/null)" || return 1 echo "${output##* }" elif type sha256sum &>/dev/null; then output="$(sha256sum --quiet)" || 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 } verify_checksum() { # If there's no SHA2 support, return success [ -n "$HAS_SHA2_SUPPORT" ] || return 0 local checksum_command="compute_sha2" # If the specified filename doesn't exist, return success local filename="$1" [ -e "$filename" ] || return 0 # If there's no expected checksum, return success local expected_checksum=`echo "$2" | tr [A-Z] [a-z]` [ -n "$expected_checksum" ] || return 0 # If the checksum length is 32 chars, assume MD5, otherwise SHA2 if [ "${#expected_checksum}" -eq 32 ]; then [ -n "$HAS_MD5_SUPPORT" ] || return 0 checksum_command="compute_md5" fi # 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" local url="$2" local file="$3" [ -n "$url" ] || return 1 if type curl &>/dev/null; then "http_${method}_curl" "$url" "$file" elif type wget &>/dev/null; then "http_${method}_wget" "$url" "$file" else echo "error: please install \`curl\` or \`wget\` and try again" >&2 exit 1 fi } http_head_curl() { curl -qsILf "$1" >&4 2>&1 } http_get_curl() { curl -q -o "${2:--}" -sSLf "$1" } http_head_wget() { wget -q --spider "$1" >&4 2>&1 } http_get_wget() { wget -nv -O "${2:--}" "$1" } fetch_tarball() { 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 tar_args="xzf" local package_filename="${package_name}.tar.gz" if [ "$package_url" != "${package_url%tgz}" ]; then package_filename="${package_filename%tar.gz}tgz" fi if [ "$package_url" != "${package_url%bz2}" ]; then package_filename="${package_filename%.gz}.bz2" tar_args="${tar_args/z/j}" fi if [ "$package_url" != "${package_url%xz}" ]; then package_filename="${package_filename%.gz}.xz" tar_args="${tar_args/z/J}" fi if ! reuse_existing_tarball "$package_filename" "$checksum"; then local tarball_filename=$(basename $package_url) echo "Downloading ${tarball_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 [ -z "$KEEP_BUILD_PATH" ]; then rm -f "$package_filename" else true fi fi } >&4 2>&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 package_url="$1" [ -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 } 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 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 { if $JAVA -jar ${package_name}.jar -s -d ${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_python_patch "$package_name" 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_standard() { 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_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" local PACKAGE_CFLAGS="${package_var_name}_CFLAGS" [ "$package_var_name" = "PYTHON" ] && use_homebrew_readline || true ( if [ "${CFLAGS+defined}" ] || [ "${!PACKAGE_CFLAGS+defined}" ]; then export CFLAGS="$CFLAGS ${!PACKAGE_CFLAGS}" fi if [ -z "$CC" ] && [ "$(uname -s)" = "Darwin" ] && [ "$(osx_version)" -ge 1010 ]; then export CC=clang fi ${!PACKAGE_CONFIGURE:-./configure} --prefix="${!PACKAGE_PREFIX_PATH:-$PREFIX_PATH}" \ --libdir="${!PACKAGE_PREFIX_PATH:-$PREFIX_PATH}/lib" \ $CONFIGURE_OPTS ${!PACKAGE_CONFIGURE_OPTS} "${!PACKAGE_CONFIGURE_OPTS_ARRAY}" ) >&4 2>&1 { "$MAKE" $MAKE_OPTS ${!PACKAGE_MAKE_OPTS} "${!PACKAGE_MAKE_OPTS_ARRAY}" "$MAKE" "${!PACKAGE_MAKE_INSTALL_TARGET:-install}" $MAKE_INSTALL_OPTS ${!PACKAGE_MAKE_INSTALL_OPTS} "${!PACKAGE_MAKE_INSTALL_OPTS_ARRAY}" } >&4 2>&1 } build_package_autoconf() { { autoconf } >&4 2>&1 } build_package_ruby() { local package_name="$1" { "$RUBY_BIN" setup.rb } >&4 2>&1 } build_package_python() { local package_name="$1" { "$PYTHON_BIN" setup.py install } >&4 2>&1 } build_package_ree_installer() { build_package_auto_tcltk local options="" if [[ "Darwin" = "$(uname)" ]]; then options="--no-tcmalloc" fi local option for option in $RUBY_CONFIGURE_OPTS ${RUBY_CONFIGURE_OPTS_ARRAY[@]}; do options="$options -c $option" done # Work around install_useful_libraries crash with --dont-install-useful-gems mkdir -p "$PREFIX_PATH/lib/ruby/gems/1.8/gems" { ./installer --auto "$PREFIX_PATH" --dont-install-useful-gems $options $CONFIGURE_OPTS } >&4 2>&1 } build_package_rbx() { local package_name="$1" { [ ! -e "Gemfile" ] || bundle --path=vendor/bundle if [ -n "$RUBY_BUILD_CACHE_PATH" ]; then mkdir -p vendor ln -s "$RUBY_BUILD_CACHE_PATH" vendor/prebuilt fi RUBYOPT="-rubygems $RUBYOPT" ./configure --prefix="$PREFIX_PATH" $RUBY_CONFIGURE_OPTS "${RUBY_CONFIGURE_OPTS_ARRAY[@]}" rake install fix_rbx_gem_binstubs "$PREFIX_PATH" fix_rbx_irb "$PREFIX_PATH" } >&4 2>&1 } build_package_mruby() { local package_name="$1" { rake mkdir -p "$PREFIX_PATH" cp -fR build/host/* "$PREFIX_PATH" cd "$PREFIX_PATH/bin" ln -fs mruby ruby ln -fs mirb irb } >&4 2>&1 } build_package_maglev() { build_package_copy { cd "${PREFIX_PATH}" ./install.sh cd "${PREFIX_PATH}/bin" echo "Creating symlink for ruby*" ln -fs maglev-ruby ruby echo "Creating symlink for irb*" ln -fs maglev-irb irb } >&4 2>&1 echo echo "Run 'maglev start' to start up the stone before using 'ruby' or 'irb'" } build_package_topaz() { build_package_copy { cd "${PREFIX_PATH}/bin" echo "Creating symlink for ruby*" ln -fs topaz ruby } >&4 2>&1 } topaz_architecture() { case "$(uname -s)" in "Darwin") echo "osx64";; "Linux") [[ "$(uname -m)" = "x86_64" ]] && echo "linux64" || echo "linux32";; *) echo "no nightly builds available" >&2 exit 1;; esac } build_package_jruby() { build_package_copy cd "${PREFIX_PATH}/bin" ln -fs jruby ruby chmod +x ruby install_jruby_launcher remove_windows_files fix_jruby_shebangs } graal_architecture() { if [ "$(uname -m)" != "x86_64" ]; then echo "no nightly builds available" >&2 exit 1 fi case "$(uname -s)" in "Darwin") echo "macosx-x86_64";; "Linux") echo "linux-x86_64";; *) echo "no nightly builds available" >&2 exit 1;; esac } install_jruby_launcher() { # If this version of JRuby has been modified for Graal, don't overwrite the # launcher scripts if ! grep -q graalvm "${PREFIX_PATH}/bin/jruby"; then cd "${PREFIX_PATH}/bin" { ./ruby gem install jruby-launcher } >&4 2>&1 fi } fix_jruby_shebangs() { for file in "${PREFIX_PATH}/bin"/*; do if [ "$(head -c 20 "$file")" = "#!/usr/bin/env jruby" ]; then sed -i.bak "1 s:.*:#\!${PREFIX_PATH}\/bin\/jruby:" "$file" rm "$file".bak fi done } remove_windows_files() { cd "$PREFIX_PATH" rm -f bin/*.exe bin/*.dll bin/*.bat bin/jruby.sh } 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 } build_package_jython_builder() { ant >&4 2>&1 ( cd "dist" && build_package_jython ) } 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 ) } pypy_architecture() { case "$(uname -s)" in "Darwin" ) echo "osx64" ;; "Linux" ) case "$(uname -m)" in "armel" ) echo "linux-armel" ;; "armhf" | "armv6l" | "armv7l" ) echo "linux-armhf" ;; "i386" | "i486" | "i586" | "i686" | "i786" ) echo "linux" ;; "x86_64" ) echo "linux64" ;; * ) return 1 ;; esac ;; "CYGWIN"* | "MINGW"* ) echo "win32" ;; "FreeBSD" ) case "$(uname -m)" in "x86_64" ) echo "freebsd64" ;; * ) return 1 ;; esac ;; * ) return 1 ;; esac } build_package_pypy() { build_package_copy mkdir -p "${PREFIX_PATH}/bin" "${PREFIX_PATH}/lib" local pypy libpypy shopt -s nullglob for pypy in "bin/pypy"*; do ( cd "${PREFIX_PATH}/bin" && ln -fs "$(basename "${pypy}")" "$(basename "${pypy}" | sed -e 's/pypy/python/')" ) done for libpypy in "bin/libpypy-c."*; do ( cd "${PREFIX_PATH}/lib" && ln -fs "../bin/$(basename "${libpypy}")" "$(basename "${libpypy}")" ) done shopt -u nullglob } build_package_pypy_builder() { if [ -f "rpython/bin/rpython" ]; then # pypy 2.x python "rpython/bin/rpython" ${PYPY_OPTS:-"-Ojit"} "pypy/goal/targetpypystandalone.py" >&4 2>&1 elif [ -f "pypy/translator/goal/translate.py" ]; then # pypy 1.x ( cd "pypy/translator/goal" && python "translate.py" ${PYPY_OPTS:-"--opt=jit"} "targetpypystandalone.py" ) 1>&4 2>&1 else echo "not a pypy source tree" 1>&3 return 1 fi { mkdir -p "bin" "lib" if [ -x "pypy-c" ]; then mv -f "pypy-c" "bin/pypy" fi for libpypy in "libpypy-c."*; do mv -f "${libpypy}" "bin/" done } >&4 2>&1 build_package_pypy } anaconda_architecture() { case "$(uname -s)" in "Darwin" ) echo "MacOSX-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_anaconda() { local package_name="$1" { bash "${package_name}.sh" -b -p "${PREFIX_PATH}" } >&4 2>&1 } build_package_miniconda() { build_package_anaconda "$@" "${PREFIX_PATH}/bin/conda" install --yes "pip" } 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}" ORIG_HAS_PATCH="$HAS_PATCH" # Apply built-in patches if patch was not given from stdin if [ -z "$HAS_PATCH" ] && [ -d "${package_patch_path}" ]; then { find "${package_patch_path}" -maxdepth 1 -type f } 2>/dev/null | sort | xargs cat 1>"${package_name}.patch" exec <&- exec <"${package_name}.patch" HAS_PATCH=true fi } cleanup_builtin_patches() { local package_name="$1" rm -f "${package_name}.patch" HAS_PATCH="$ORIG_HAS_PATCH" } fix_directory_permissions() { # Ensure installed directories are not world-writable to avoid Bundler warnings find "$PREFIX_PATH" -type d \( -perm -020 -o -perm -002 \) -exec chmod go-w {} \; } fix_rbx_gem_binstubs() { local prefix="$1" local gemdir="${prefix}/gems/bin" local bindir="${prefix}/bin" local file binstub # Symlink Rubinius' `gems/bin/` into `bin/` if [ -d "$gemdir" ] && [ ! -L "$gemdir" ]; then for file in "$gemdir"/*; do binstub="${bindir}/${file##*/}" rm -f "$binstub" { echo "#!${bindir}/ruby" cat "$file" } > "$binstub" chmod +x "$binstub" done rm -rf "$gemdir" ln -s ../bin "$gemdir" fi } fix_rbx_irb() { local prefix="$1" "${prefix}/bin/irb" --version &>/dev/null || "${prefix}/bin/gem" install rubysl-tracer -v '~> 2.0' --no-rdoc --no-ri &>/dev/null || true } require_java7() { local version="$(java -version 2>&1 | head -1)" if [[ $version != *1.[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 [ "$(uname -s)" = "Darwin" ]; 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 apple-gcc42 package with this" echo -n "command: " colorize 4 "brew tap homebrew/dupes ; brew install apple-gcc42" 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 [ "$(uname -s)" = "Darwin" ] && [ "$(osx_version)" -ge 1010 ]; then export MACOSX_DEPLOYMENT_TARGET=10.9 fi } locate_gcc() { local gcc gccs IFS=: gccs=($(gccs_in_path)) 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) 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 [ "$(uname -s)" = "Darwin" ] && [ "$(osx_version)" -ge 1010 ]; then if [[ "$PYTHON_CONFIGURE_OPTS" != *--llvm-* ]]; then if [ "$llvm_version" = "3.2" ]; then package_option python configure --prebuilt-name="llvm-3.2-x86_64-apple-darwin13.tar.bz2" else local llvm_prefix="$(brew --prefix llvm 2>/dev/null || true)" local llvm_config="${llvm_prefix}/bin/llvm-config" if [ -x "$llvm_config" ]; then package_option python configure --llvm-config="$llvm_config" fi fi fi fi } 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" } 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 } needs_yaml() { [[ "$RUBY_CONFIGURE_OPTS" != *--with-libyaml-dir=* ]] && ! use_homebrew_yaml } use_homebrew_yaml() { local libdir="$(brew --prefix libyaml 2>/dev/null || true)" if [ -d "$libdir" ]; then export CPPFLAGS="-I$libdir/include ${CPPFLAGS}" export LDFLAGS="-L$libdir/lib ${LDFLAGS}" else return 1 fi } configured_with_readline_dir() { # Mac OS X 10.4 has broken readline. # https://github.com/yyuu/pyenv/issues/23 local arg flag for arg in ${CONFIGURE_OPTS} ${PYTHON_CONFIGURE_OPTS} "${PYTHON_CONFIGURE_OPTS_ARRAY[@]}"; do if [[ "$arg" == "CPPFLAGS="* ]]; then for flag in ${CPPFLAGS} ${arg##CPPFLAGS=}; do if [[ "$flag" == "-I"* ]] && [ -e "${flag##-I}/readline/rlconf.h" ]; then return 0 fi done fi done return 1 } has_broken_mac_readline() { [ "$(uname -s)" = "Darwin" ] && ! configured_with_readline_dir && ! use_homebrew_readline } use_homebrew_readline() { if ! configured_with_readline_dir; then local libdir="$(brew --prefix readline 2>/dev/null || true)" if [ -d "$libdir" ]; then export CPPFLAGS="-I$libdir/include ${CPPFLAGS}" export LDFLAGS="-L$libdir/lib ${LDFLAGS}" else return 1 fi fi } has_broken_mac_openssl() { [ "$(uname -s)" = "Darwin" ] && [[ "$(/usr/bin/openssl version 2>/dev/null || true)" = "OpenSSL 0.9.8"?* ]] && [[ "$RUBY_CONFIGURE_OPTS" != *--with-openssl-dir=* ]] && ! use_homebrew_openssl } use_homebrew_openssl() { local ssldir="$(brew --prefix openssl 2>/dev/null || true)" if [ -d "$ssldir" ]; then export CPPFLAGS="-I$ssldir/include ${CPPFLAGS}" export LDFLAGS="-L$ssldir/lib ${LDFLAGS}" else return 1 fi } 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. export CPPFLAGS="-I${OPENSSL_PREFIX_PATH}/include ${CPPFLAGS}" export LDFLAGS="-L${OPENSSL_PREFIX_PATH}/lib ${LDFLAGS}" # Hint OpenSSL that we prefer a 64-bit build. export KERNEL_BITS="64" OPENSSL_CONFIGURE="${OPENSSL_CONFIGURE:-./config}" # Compile a shared lib with zlib dynamically linked, no kerberos. package_option openssl configure --openssldir="$OPENSSLDIR" zlib-dynamic no-ssl2 no-ssl3 no-krb5 shared # Default MAKE_OPTS are -j 2 which can confuse the build. Thankfully, make # gives precedence to the last -j option, so we can override that. package_option openssl make -j 1 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" } # Post-install check that the openssl extension was built. build_package_verify_openssl() { "$RUBY_BIN" -e 'begin require "openssl" rescue LoadError $stderr.puts "The Ruby openssl extension was not compiled. Missing the OpenSSL lib?" $stderr.puts "Configure options used:" require "rbconfig"; require "shellwords" RbConfig::CONFIG.fetch("configure_args").shellsplit.each { |arg| $stderr.puts " #{arg}" } exit 1 end' >&4 2>&1 } # Ensure that directories listed in LDFLAGS exist build_package_ldflags_dirs() { local arg for arg in $LDFLAGS; do case "$arg" in -L* ) mkdir -p "${arg#-L}" ;; esac done } build_package_auto_tcltk() { if [ "Darwin" = "$(uname -s)" ] && [ ! -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" fi else package_option python configure --without-tk fi fi } rake() { if [ -e "./Gemfile" ]; then bundle exec rake "$@" else isolated_gem_dependency "rake --version" rake -v '~> 10.1.0' command rake "$@" fi } bundle() { isolated_gem_dependency "bundle --version" bundler -v '~> 1.3.5' command bundle "$@" } isolated_gem_dependency() { set +E ( command $1 &>/dev/null ) || { set -E shift 1 isolated_gem_install "$@" } set -E } isolated_gem_install() { export GEM_HOME="${PWD}/.gem" export PATH="${GEM_HOME}/bin:${PATH}" gem install "$@" } apply_python_patch() { local patchfile case "$1" in Python-* | jython-* | pypy-* ) 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" ;; esac } verify_python() { if [[ "$PYTHON_CONFIGURE_OPTS" == *"--enable-framework"* ]]; then # Only symlinks are installed in ${PREFIX_PATH}/bin rm -fr "${PREFIX_PATH}/bin" ln -fs "${PREFIX_PATH}/Python.framework/Versions/Current/bin" "${PREFIX_PATH}/bin" fi # Not create symlinks on `altinstall` (#255) if [[ "$PYTHON_MAKE_INSTALL_TARGET" != *"altinstall"* ]]; then local suffix="${1#python}" local file link shopt -s nullglob 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 shopt -u nullglob fi 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/yyuu/pyenv/issues" return 1 } >&3 fi } try_python_module() { if ! "$PYTHON_BIN" -c "import $1" 1>/dev/null 2>&1; then { colorize 1 "WARNING" echo ": The Python $1 extension was not compiled. Missing the ${2:-$1}?" return 0 } >&3 fi } verify_python_module() { if ! "$PYTHON_BIN" -c "import $1" 1>/dev/null 2>&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/yyuu/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 "readline" "GNU readline lib" verify_python_module "ssl" "OpenSSL lib" try_python_module "sqlite3" "SQLite3 lib" 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}" } # 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}" } build_package_ez_setup() { local ez_setup="${BUILD_PATH}/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}" ] || EZ_SETUP_URL="https://bootstrap.pypa.io/ez_setup.py" 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_get_pip() { local get_pip="${BUILD_PATH}/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}" ] || GET_PIP_URL="https://bootstrap.pypa.io/get-pip.py" echo "Installing pip from ${GET_PIP_URL}..." 1>&2 http get "${GET_PIP_URL}" fi } 1> "${get_pip}" "${PYTHON_BIN}" "${get_pip}" ${GET_PIP_OPTS} 1>&4 2>&1 || { echo "error: failed to install pip via get-pip.py" >&2 return 1 } } build_package_ensurepip() { local ensurepip_opts if [[ "$PYTHON_MAKE_INSTALL_TARGET" != *"altinstall"* ]]; then ensurepip_opts="--altinstall" fi "$PYTHON_BIN" -m ensurepip $ensurepip_opts 1>/dev/null 2>&1 || { build_package_ez_setup "$@" && build_package_get_pip "$@" } || return 1 } 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" ] && find "$DEFINITION_DIR" -maxdepth 1 -type f -print0 | xargs -0 -n 1 basename 2>/dev/null 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 PYTHON_BUILD_INSTALL_PREFIX="$(abs_dirname "$0")/.." OLDIFS="$IFS" 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_PATCH=true ;; "g" | "debug" ) DEBUG=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 # Work around warnings building Ruby 2.0 on Clang 2.x: # pass -Wno-error=shorten-64-to-32 if the compiler accepts it. # # When we set CFLAGS, Ruby won't apply its default flags, though. Since clang # builds 1.9.x and 2.x only, where -O3 is default, we can safely set that flag. # Ensure it's the first flag since later flags take precedence. #if "${CC:-cc}" -x c /dev/null -E -Wno-error=shorten-64-to-32 &>/dev/null; then # PYTHON_CFLAGS="-O3 -Wno-error=shorten-64-to-32 $PYTHON_CFLAGS" #fi if [ -z "$MAKE" ]; then if [ "FreeBSD" = "$(uname -s)" ] && [ "$(uname -r | sed 's/[^[:digit:]].*//')" -lt 10 ]; then export MAKE="gmake" 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://yyuu.github.io/pythons" else PYTHON_BUILD_MIRROR_URL="${PYTHON_BUILD_MIRROR_URL%/}" fi if [ -n "$PYTHON_BUILD_SKIP_MIRROR" ]; then unset PYTHON_BUILD_MIRROR_URL fi if echo test | compute_sha2 >/dev/null; then HAS_SHA2_SUPPORT=1 else unset HAS_SHA2_SUPPORT unset PYTHON_BUILD_MIRROR_URL fi if echo test | compute_md5 >/dev/null; then HAS_MD5_SUPPORT=1 else unset HAS_MD5_SUPPORT fi # Add an option to build a debug version of Python (#11) if [ -n "$DEBUG" ]; then package_option python configure --with-pydebug fi # python-build: Set `RPATH` if `--enable-shared` was given (#65, #66, #82) if [[ "$CONFIGURE_OPTS" == *"--enable-shared"* ]] || [[ "$PYTHON_CONFIGURE_OPTS" == *"--enable-shared"* ]]; then # The ld on Darwin embeds the full paths to each dylib by default if [[ "$LDFLAGS" != *"-rpath="* ]] && [[ "Darwin" != "$(uname -s)" ]]; then export LDFLAGS="-Wl,-rpath=${PREFIX_PATH}/lib ${LDFLAGS}" fi fi # python-build: Set `RPATH` if --shared` was given for PyPy (#244) if [[ "$PYPY_OPTS" == *"--shared"* ]]; then export LDFLAGS="-Wl,-rpath=${PREFIX_PATH}/lib ${LDFLAGS}" fi # Add support for framework installation (`--enable-framework`) of CPython (#55, #99) if [[ "$PYTHON_CONFIGURE_OPTS" == *"--enable-framework"* ]]; then if [[ "Darwin" != "$(uname -s)" ]]; then echo "python-build: framework installation is not supported." >&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}/Python.framework/Versions/${version}" ( cd "${PREFIX_PATH}/Python.framework/Versions" && ln -fs "${version}" "Current") local path for path in include lib share; do mkdir -p "${PREFIX_PATH}/Python.framework/Versions/Current/${path}" ln -fs "${PREFIX_PATH}/Python.framework/Versions/Current/${path}" "${PREFIX_PATH}/${path}" done } create_framework_dirs "${DEFINITION_PATH##*/}" package_option python configure --enable-framework="${PREFIX_PATH}" fi # Build against universal SDK (#219, #220) if [[ "$PYTHON_CONFIGURE_OPTS" == *"--enable-universalsdk"* ]]; then if [[ "Darwin" != "$(uname -s)" ]]; then echo "python-build: universal installation is not supported." >&2 exit 1 fi package_option python configure --enable-universalsdk=/ --with-universal-archs=intel fi # SSL Certificate error with older wget that does not support Server Name Indication (#60) if ! command -v curl 1>/dev/null 2>&1 && [[ "$(wget --version 2>/dev/null || true)" = "GNU Wget 1.1"[0-3]* ]]; then echo "python-build: wget (< 1.14) doesn't support Server Name Indication. Please install curl (>= 7.18.1) and try again" >&2 exit 1 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 [ -n "${SETUPTOOLS_VERSION}" ]; then EZ_SETUP_URL="https://bitbucket.org/pypa/setuptools/raw/${SETUPTOOLS_VERSION}/ez_setup.py" fi if [ -n "${PIP_VERSION}" ]; then GET_PIP_URL="https://raw.githubusercontent.com/pypa/pip/${PIP_VERSION}/contrib/get-pip.py" fi # Set MACOSX_DEPLOYMENT_TARGET from the product version of OS X (#219, #220) if [[ "Darwin" == "$(uname -s)" ]]; then MACOS_VERSION="$(sw_vers -productVersion 2>/dev/null || true)" 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 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_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 export LDFLAGS="-L${PREFIX_PATH}/lib ${LDFLAGS}" export CPPFLAGS="-I${PREFIX_PATH}/include ${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