Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarification of required dependencies on macOS #2023

Closed
codyrobbins opened this issue Aug 12, 2022 · 5 comments
Closed

Clarification of required dependencies on macOS #2023

codyrobbins opened this issue Aug 12, 2022 · 5 comments

Comments

@codyrobbins
Copy link

I’ve gone down a rabbithole of trying to figure out what the actual dependencies of ruby-build are on macOS and I’m seeing conflicting information in different places and I’d like to get some clarification of what the most up-to-date requirements are and then update the documentation and/or Homebrew formula to be consistent if possible.

The suggested build environment in the wiki lists openssl@1.1, readline, and libyaml from Homebrew as requirements. It also looks like @mislav maintains the Homebrew formula so I assume that this formula is officially supported.

Also, let me state up front that ruby-build is an amazing tool that has saved me and so many people countless hours, so nothing below is a criticism in any way. It’s mostly fact-finding and I’m definitely not versed enough in of the internals of anything here to be able to give an opinion from a perspective other than that of an end-user Ruby developer. I’d simply love to improve the documentation and/or Homebrew formula so these questions I had might be easier for other people to figure out. Thank you to all the maintainers who have put so much time and effort into developing this phenomenal utility!

readline

The Homebrew formula already depends on Homebrew’s readline package, so I think listing the need to install readline on the wiki page is superfluous?

libyaml

Since the wiki lists libyaml as a requirement, is there a reason the Homebrew formula isn’t simply listing it as a dependency just as readline is? From #1928/#1929 it looks like libyaml wasn’t being used from Homebrew anyways but this has since been corrected.

Perhaps unrelated but #1950 has some additional discussion of the libyaml requirement on Ubuntu/Debian/Mint and suggests removing it from the list of requirements in the wiki.

Unless I’m missing something, it looks to me like the suggested course of action here should be to add a dependency on libyaml to the Homebrew formula and remove the suggestion to install it manually from the wiki.

OpenSSL

This is the one that seems to have the most conflicting information and I’m not sure what is incorrect or simply outdated.

The wiki states that the openssl@1.1 Homebrew formula is a requirement and also mentions setting the RUBY_CONFIGURE_OPTS environment variable to cause Ruby to be built using Homebrew’s version. However, the formula states that each Ruby version packages its own non-Homebrew version of OpenSSL that’s never upgraded. So, I’m assuming the suggestion to use Homebrew’s version is made from a security vulnerability standpoint?

But installing Ruby 3.1.2 with ruby-build shows it installing OpenSSL 3.0.5 as part of the installation. So why are we pinning to OpenSSL 1.1 when newer Ruby versions need an OpenSSL version that’s two major versions ahead? It appears #2000 might confirm that suspicion. The Homebrew formula also mentions that this version pinning causes problems with Ruby versions below 2.4 that require a version of OpenSSL less than 1.1.

It seems like there are lots of interlocking issues at play here that I’m probably ignorant of, so I don’t pretend to know what the “correct” answer is—if, in fact, it’s even any different than what the documentation already states. But I’m going to take a guess that perhaps the best thing to do would be to update the documentation to point out that, instead of using OpenSSL 1.1 in all cases (which causes problems with old versions of Ruby and might be stale for newer versions), that instead different versions of Ruby require different versions of OpenSSL, e.g.

Ruby OpenSSL
Ruby < 2.2 openssl@0.9
Ruby 2.2–2.4 openssl@1.0
Ruby 2.4–3 openssl@1.1
Ruby > 3 openssl@3

I just made up those numbers as an example because I can’t actually seem to find a list anywhere that lays out what versions of Ruby require which versions of OpenSSL. In fact, I’m not even sure what in Ruby needs OpenSSL—is it because of openssl in the standard library?

And perhaps this is a can of worms, but shouldn’t the Homebrew formula just install all of these required formula and then worry about using the correct version of the lib for the particular version of Ruby being installed? That’s probably an obvious observation so I’m guessing it’s either impossible for some reason or easier said than done. But if it’s possible then it would basically sidestep the entire issue and allow all requirements to simply be listed as dependencies in the Homebrew formula and everything would happen automagically.

And finally, if it’s the case that the Homebrew version of OpenSSL is being suggested because of security, it would be good to update the documentation to point out that the packaged version is fine in environments where security is not a real concern, e.g. local development. Then developers could skip worrying about this at all and just use the packaged version where it doesn’t matter.

@eregon
Copy link
Member

eregon commented Aug 12, 2022

is it because of openssl in the standard library?

Yes.

The actual openssl requirements are here:

ruby-build/bin/ruby-build

Lines 1104 to 1129 in a753b24

# openssl gem 1.1.1
needs_openssl_096_102() {
[[ "$RUBY_CONFIGURE_OPTS" == *--with-openssl-dir=* ]] && return 1
has_broken_mac_openssl && return 0
local version=$(system_openssl_version)
(( $version < 96 || $version >= 110 ))
}
# openssl gem 2.2.1
needs_openssl_101_111() {
[[ "$RUBY_CONFIGURE_OPTS" == *--with-openssl-dir=* ]] && return 1
has_broken_mac_openssl && return 0
local version=$(system_openssl_version)
(( $version < 101 || $version >= 300 ))
}
# openssl gem 3.0.0
needs_openssl_102_300() {
[[ "$RUBY_CONFIGURE_OPTS" == *--with-openssl-dir=* ]] && return 1
has_broken_mac_openssl && return 0
local version=$(system_openssl_version)
(( $version < 102 || $version >= 400 ))
}

And you can find in which definitions there are used to find which Ruby versions use which (they are all correct and precise now).
So it's not simple as your table, but it would be useful to update the table for other readers.

Homebrew doesn't allow depending so dynamically on a given openssl version, so it could only depend on openssl@1.1 maybe but that wouldn't cover all Ruby versions.

And perhaps this is a can of worms, but shouldn’t the Homebrew formula just install all of these required formula

Probably some of these formula (especially the older ones) don't build on recent macOS, and rarely a good idea to install openssl 0.9/1.0 as they are EOL.

I think your main question/suggestion here is why ruby-build doesn't use Homebrew packages by default, except for readline.
First, libyaml is optional and there is a version bundled with Ruby, so I guess that's why it's not used by default.
For openssl I think it might make sense to try using some version of openssl from Homebrew by default if available, but it seems complex.
One messy thing is Homebrew being potentially installed on only one of the two architectures with M1 macs.

@mislav
Copy link
Member

mislav commented Sep 9, 2022

Thanks @codyrobbins for an excellent question and @eregon for chiming in.

The short answer to all of this is: the suggested build environment in the wiki has been unchanged for a long time and is outdated for newer Ruby versions. As previously mentioned, you don't actually want to use openssl@1.1 for Ruby 3.1 and above. Wiki edits to clarify this are welcome.

Even if you didn't specify --with-openssl-dir at all, ruby-build would still compile Ruby properly, but manually supplying --with-openssl-dir is recommended since it can vastly speed up Ruby installation by avoiding compiling a separate OpenSSL instance for each Ruby version installed.

The Homebrew formula already depends on Homebrew’s readline package, so I think listing the need to install readline on the wiki page is superfluous?

The suggested build environment listed on our wiki does not assume you've used Homebrew to install ruby-build, so it's still valuable to explicitly list readline. Readline is not a hard dependency for Ruby, but it's good to ensure that it's available so that interactive prompts like irb work with all their features.

@mislav
Copy link
Member

mislav commented Mar 6, 2023

Closing as resolved. If I missed anything, please let me know!

The Homebrew formula already depends on Homebrew’s readline package, so I think listing the need to install readline on the wiki page is superfluous?

True, but not everyone who installed ruby-build was using brew install ruby-build. Therefore, our suggested build environment will still suggest brew install readline. If it's already installed, the operation is a no-op.

it looks like libyaml wasn’t being used from Homebrew anyways but this has since been corrected.

I have just merged a change that automatically uses libyaml from Homebrew if found.

The wiki states that the openssl@1.1 Homebrew formula is a requirement and also mentions setting the RUBY_CONFIGURE_OPTS environment variable to cause Ruby to be built using Homebrew’s version.

The wiki now states: Using RUBY_CONFIGURE_OPTS to link to a specific OpenSSL installation like suggested above is not a strict requirement for installing Ruby on macOS, but it will speed up your Ruby installation and avoid any OpenSSL compilation issues. It also suggests using openssl@3 for newer Rubies, further clarifying the situation.

@mislav mislav closed this as completed Mar 6, 2023
@eregon
Copy link
Member

eregon commented Mar 6, 2023

I think it would make sense to default to Homebrew's openssl@correctVersion if it's installed. It would be consistent with readline, gmp and libyaml.
And also because Homebrew's openssl works for using any extension which uses a Homebrew formula which links against libssl, unlike the custom-built openssl (which would cause to load 2 libssl in the same process, which usually doesn't work well).

But that's probably worth another issue to track it.

@codyrobbins
Copy link
Author

Wow, thanks so much for the detailed reply—you answered all my questions and then some! And thanks for updating the readme with a more explicit explanation of the dependencies.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants