mirror of
https://github.com/rbenv/ruby-build.git
synced 2025-06-17 09:18:06 +02:00
Automatically link to Homebrew OpenSSL
If a system OpenSSL version was not found or is at version that is incompatible with a Ruby being installed, ruby-build would typically download and compile a new OpenSSL version scoped to that Ruby installation. Now the `needs_openssl` condition will also check for Homebrew-installed OpenSSL and automatically link to the first one found that satisfies the version requirement. This primarily helps speed up Ruby installation on macOS where the system OpenSSL is never compatible and where Homebrew is a de-facto standard package manager.
This commit is contained in:
parent
8f294c43ad
commit
31e53468b6
3 changed files with 170 additions and 32 deletions
118
bin/ruby-build
118
bin/ruby-build
|
@ -1023,6 +1023,8 @@ use_freebsd_libffi() {
|
|||
fi
|
||||
}
|
||||
|
||||
# macOS prevents linking to its system OpenSSL/LibreSSL installation, so
|
||||
# it's basically useless for Ruby purposes.
|
||||
has_broken_mac_openssl() {
|
||||
is_mac || return 1
|
||||
local openssl_version
|
||||
|
@ -1030,47 +1032,103 @@ has_broken_mac_openssl() {
|
|||
[[ $openssl_version = "OpenSSL 0.9.8"?* || $openssl_version = "LibreSSL"* ]]
|
||||
}
|
||||
|
||||
# Detect the OpenSSL version that a compiler can reasonably link to.
|
||||
system_openssl_version() {
|
||||
local version_text
|
||||
version_text=$(printf '#include <openssl/opensslv.h>\nOPENSSL_VERSION_TEXT\n' | cc -xc -E - 2>/dev/null || true)
|
||||
if [[ $version_text == *"OpenSSL "* ]]; then
|
||||
local version=${version_text#*OpenSSL }
|
||||
# shellcheck disable=SC2001
|
||||
sed 's/[^0-9]//g' <<<"${version%% *}" | sed 's/^0*//'
|
||||
else
|
||||
echo "No system openssl version was found, ensure openssl headers are installed (https://github.com/rbenv/ruby-build/wiki#suggested-build-environment)" >&2
|
||||
echo 000
|
||||
cc -xc -E - <<EOF 2>/dev/null | sed -n 's/OpenSSL \([0-9][0-9.]*\).*/\1/p'
|
||||
#include <openssl/opensslv.h>
|
||||
OPENSSL_VERSION_TEXT
|
||||
EOF
|
||||
}
|
||||
|
||||
# List all Homebrew-installed OpenSSL versions and their filesystem prefixes.
|
||||
homebrew_openssl_versions() {
|
||||
local formula version prefix
|
||||
# https://github.com/orgs/Homebrew/discussions/4845
|
||||
brew list 2>/dev/null | grep '^openssl@' | while read -r formula; do
|
||||
prefix="$(brew --prefix "$formula" 2>/dev/null || true)"
|
||||
[ -n "$prefix" ] || continue
|
||||
version="$("$prefix"/bin/openssl version 2>/dev/null | sed -n 's/OpenSSL \([0-9][0-9.]*\).*/\1/p')"
|
||||
[ -z "$version" ] || printf '%s %s %s\n' "$formula" "$version" "$prefix"
|
||||
done
|
||||
}
|
||||
|
||||
# Normalizes "X.Y.Z" into a comparable numeric value. Does not support prereleases.
|
||||
# See also osx_version, require_java
|
||||
normalize_semver() {
|
||||
local ver
|
||||
IFS=. read -d "" -r -a ver <<<"$1" || true
|
||||
IFS="$OLDIFS"
|
||||
# 3.1.23 -> 300_123
|
||||
echo $(( ver[0]*100000 + ver[1]*100 + ver[2] ))
|
||||
}
|
||||
|
||||
# Checks if system OpenSSL does NOT satisfy the version requirement
|
||||
# between lower and upper bounds. This is used by build definitions to
|
||||
# conditionally install per-ruby OpenSSL.
|
||||
#
|
||||
# If a compatible Homebrew-installed OpenSSL version is found during
|
||||
# checking, Ruby will be linked to it and the check will return false.
|
||||
needs_openssl() {
|
||||
[[ "$RUBY_CONFIGURE_OPTS ${RUBY_CONFIGURE_OPTS_ARRAY[*]}" != *--with-openssl-dir=* ]] || return 1
|
||||
|
||||
local system_version
|
||||
if ! has_broken_mac_openssl; then
|
||||
system_version="$(system_openssl_version)"
|
||||
fi
|
||||
|
||||
# With no arguments, any system OpenSSL satisfies the check.
|
||||
if [ $# -lt 2 ]; then
|
||||
[ -z "$system_version" ] || return 1
|
||||
return 0
|
||||
fi
|
||||
|
||||
local lower_bound upper_bound
|
||||
lower_bound="$(normalize_semver "${2%-*}")"
|
||||
upper_bound="${2#*-}"
|
||||
upper_bound="$(normalize_semver "${upper_bound//.x/.99}")"
|
||||
system_version="$(normalize_semver "$system_version")"
|
||||
|
||||
# Return early if system openssl satisfies the requirement.
|
||||
(( system_version < lower_bound || system_version >= upper_bound )) || return 1
|
||||
|
||||
# Look for the latest Homebrew-installed OpenSSL that satisfies the requirement
|
||||
local brew_installs
|
||||
brew_installs="$(homebrew_openssl_versions)"
|
||||
[ -n "$brew_installs" ] || return 0
|
||||
|
||||
# Link to the highest-matching Homebrew OpenSSL
|
||||
local versions homebrew_version formula version prefix
|
||||
# shellcheck disable=SC2207
|
||||
versions=( $(awk '{print $2}' <<<"$brew_installs" | sort_versions) )
|
||||
local index="${#versions[@]}"
|
||||
while [ $((index--)) -ge 0 ]; do
|
||||
homebrew_version="$(normalize_semver "${versions[index]}")"
|
||||
(( homebrew_version >= lower_bound && homebrew_version < upper_bound )) || continue
|
||||
while read -r formula version prefix; do
|
||||
[ "$version" = "${versions[index]}" ] || continue
|
||||
echo "ruby-build: using $formula from homebrew"
|
||||
package_option ruby configure --with-openssl-dir="$prefix"
|
||||
return 1
|
||||
done <<<"$brew_installs"
|
||||
done
|
||||
}
|
||||
|
||||
# openssl gem 1.1.1
|
||||
# Kept for backward compatibility with 3rd-party Ruby definitions.
|
||||
needs_openssl_096_102() {
|
||||
[[ "$RUBY_CONFIGURE_OPTS ${RUBY_CONFIGURE_OPTS_ARRAY[*]}" == *--with-openssl-dir=* ]] && return 1
|
||||
has_broken_mac_openssl && return 0
|
||||
|
||||
local version
|
||||
version="$(system_openssl_version)"
|
||||
(( version < 96 || version >= 110 ))
|
||||
# openssl gem 1.1.1
|
||||
needs_openssl "$1" "0.9.6-1.0.x"
|
||||
}
|
||||
|
||||
# openssl gem 2.2.1
|
||||
# Kept for backward compatibility with 3rd-party Ruby definitions.
|
||||
needs_openssl_101_111() {
|
||||
[[ "$RUBY_CONFIGURE_OPTS ${RUBY_CONFIGURE_OPTS_ARRAY[*]}" == *--with-openssl-dir=* ]] && return 1
|
||||
has_broken_mac_openssl && return 0
|
||||
|
||||
local version
|
||||
version="$(system_openssl_version)"
|
||||
(( version < 101 || version >= 300 ))
|
||||
# openssl gem 2.2.1
|
||||
needs_openssl "$1" "1.0.1-1.x.x"
|
||||
}
|
||||
|
||||
# openssl gem 3.0.0
|
||||
# Kept for backward compatibility with 3rd-party Ruby definitions.
|
||||
needs_openssl_102_300() {
|
||||
[[ "$RUBY_CONFIGURE_OPTS ${RUBY_CONFIGURE_OPTS_ARRAY[*]}" == *--with-openssl-dir=* ]] && return 1
|
||||
has_broken_mac_openssl && return 0
|
||||
|
||||
local version
|
||||
version="$(system_openssl_version)"
|
||||
(( version < 102 || version >= 400 ))
|
||||
# openssl gem 3.0.0
|
||||
needs_openssl "$1" "1.0.2-3.x.x"
|
||||
}
|
||||
|
||||
# Kept for backward compatibility with 3rd-party Ruby definitions.
|
||||
|
|
|
@ -316,6 +316,33 @@ make install
|
|||
OUT
|
||||
}
|
||||
|
||||
@test "use system OpenSSL" {
|
||||
cached_tarball "ruby-2.0.0" configure
|
||||
|
||||
stub_repeated uname '-s : echo Linux'
|
||||
stub_repeated brew false
|
||||
# shellcheck disable=SC2016
|
||||
stub cc '-xc -E - : [[ "$(cat)" == *OPENSSL_VERSION_TEXT* ]] && printf "# <unrelated> 4.0.2\nOpenSSL 1.0.3a 1 Aug 202\n0 errors.\n"'
|
||||
stub_make_install
|
||||
|
||||
mkdir -p "$INSTALL_ROOT"/openssl/ssl # OPENSSLDIR
|
||||
run_inline_definition <<DEF
|
||||
install_package "openssl-1.1.1w" "https://www.openssl.org/source/openssl-1.1.1w.tar.gz" openssl --if needs_openssl_102_300
|
||||
install_package "ruby-2.0.0" "http://ruby-lang.org/ruby/2.0/ruby-2.0.0.tar.gz"
|
||||
DEF
|
||||
assert_success
|
||||
|
||||
unstub uname
|
||||
unstub brew
|
||||
unstub make
|
||||
|
||||
assert_build_log <<OUT
|
||||
ruby-2.0.0: [--prefix=$INSTALL_ROOT]
|
||||
make -j 2
|
||||
make install
|
||||
OUT
|
||||
}
|
||||
|
||||
@test "install bundled OpenSSL" {
|
||||
cached_tarball "openssl-1.1.1w" config
|
||||
cached_tarball "ruby-2.0.0" configure
|
||||
|
@ -339,6 +366,8 @@ DEF
|
|||
|
||||
unstub uname
|
||||
unstub brew
|
||||
unstub cc
|
||||
# unstub openssl
|
||||
unstub make
|
||||
|
||||
assert_build_log <<OUT
|
||||
|
@ -375,6 +404,56 @@ make install
|
|||
OUT
|
||||
}
|
||||
|
||||
@test "link to Homebrew OpenSSL" {
|
||||
cached_tarball "ruby-2.0.0" configure
|
||||
|
||||
local homebrew_prefix="${TMP}/homebrew"
|
||||
executable "${homebrew_prefix}/opt/openssl@3/bin/openssl" <<EXE
|
||||
#!/$BASH
|
||||
[ "\$1" = "version" ] || exit 1
|
||||
echo 'OpenSSL 3.2.1 20 Dec 2019'
|
||||
EXE
|
||||
executable "${homebrew_prefix}/opt/openssl@3.1/bin/openssl" <<EXE
|
||||
#!/$BASH
|
||||
[ "\$1" = "version" ] || exit 1
|
||||
echo 'OpenSSL 3.1.22 20 Dec 2019'
|
||||
EXE
|
||||
executable "${homebrew_prefix}/opt/openssl@3.0/bin/openssl" <<EXE
|
||||
#!/$BASH
|
||||
[ "\$1" = "version" ] || exit 1
|
||||
echo 'OpenSSL 3.0.2 20 Dec 2019'
|
||||
EXE
|
||||
executable "${homebrew_prefix}/opt/openssl@1.1/bin/openssl" <<EXE
|
||||
#!/$BASH
|
||||
[ "\$1" = "version" ] || exit 1
|
||||
echo 'OpenSSL 1.1.1v 20 Dec 2019'
|
||||
EXE
|
||||
|
||||
stub_repeated uname '-s : echo Linux'
|
||||
stub cc '-xc -E - : echo "OpenSSL 1.0.1a 1 Aug 2023"'
|
||||
stub_repeated brew \
|
||||
'list : printf "git\nopenssl@3\nopenssl-utils\nopenssl@1.1\nopenssl@3.0\nwget\nopenssl@3.1"' \
|
||||
"--prefix : echo '$homebrew_prefix'/opt/\$2 "
|
||||
stub_make_install
|
||||
|
||||
run_inline_definition <<DEF
|
||||
install_package "openssl-1.1.1w" "https://www.openssl.org/source/openssl-1.1.1w.tar.gz" openssl --if needs_openssl:1.1.0-3.0.x
|
||||
install_package "ruby-2.0.0" "http://ruby-lang.org/ruby/2.0/ruby-2.0.0.tar.gz"
|
||||
DEF
|
||||
assert_success
|
||||
|
||||
unstub uname
|
||||
unstub cc
|
||||
unstub brew
|
||||
unstub make
|
||||
|
||||
assert_build_log <<OUT
|
||||
ruby-2.0.0: [--prefix=$INSTALL_ROOT,--with-openssl-dir=$TMP/homebrew/opt/openssl@3.0]
|
||||
make -j 2
|
||||
make install
|
||||
OUT
|
||||
}
|
||||
|
||||
@test "forward extra command-line arguments as configure flags" {
|
||||
cached_tarball "ruby-2.0.0" configure
|
||||
|
||||
|
|
|
@ -44,8 +44,9 @@ inspect_args() {
|
|||
}
|
||||
|
||||
# Loop over each line in the plan.
|
||||
IFS=$'\n' read -d '' -r -a lines < "${!_STUB_PLAN}" || true
|
||||
index=0
|
||||
while IFS= read -r line; do
|
||||
for line in "${lines[@]}"; do
|
||||
index=$(($index + 1))
|
||||
|
||||
if [[ -z "${!_STUB_END}" && -n "${!_STUB_NOINDEX}" || $index -eq "${!_STUB_INDEX}" ]]; then
|
||||
|
@ -93,7 +94,7 @@ while IFS= read -r line; do
|
|||
eval "${_STUB_RESULT}"=1
|
||||
fi
|
||||
fi
|
||||
done < "${!_STUB_PLAN}"
|
||||
done
|
||||
|
||||
|
||||
if [ -n "${!_STUB_END}" ]; then
|
||||
|
|
Loading…
Reference in a new issue