asdf-vm / asdf-ruby

Ruby plugin for asdf version manager
https://github.com/asdf-vm/asdf
MIT License
657 stars 133 forks source link

bug: Unable to Build Native Gems on Mac with Ruby 3.1.0+ #332

Closed jcouball closed 1 year ago

jcouball commented 1 year ago

Describe the Bug

Note: I have also reported this issue on the Ruby issue tracker as Ruby Bug #19403 as I am not sure where the problem really occurs.

In Ruby 3.1 and later installed by rvm or asdf on a Mac, require 'mkmf' aborts the script and reports the following error (the reported path is different depending on the Ruby install manager and the version of Ruby):

mkmf.rb can't find header files for ruby at /Users/couballj/.asdf/installs/ruby/3.2.0/lib/ruby/include/ruby.h

You might have to install separate package for the ruby development
environment, ruby-dev or ruby-devel for example.

and RbConfig::CONFIG["rubyhdrdir"] is set to an incorrect path:

"/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/Users/couballj/.asdf/installs/ruby/3.2.0/include/ruby-3.2.0"

Steps to Reproduce

Install asdf and Ruby 3.2.0 and then run the following script:

require 'mkmf'

Expected Behaviour

Running require 'mkmf' should not abort and for my system/user using asdf installed Ruby 3.2.0 RbConfig::CONFIG["rubyhdrdir"] should be set to:

"/Users/couballj/.asdf/installs/ruby/3.2.0/include/ruby-3.2.0"

Actual Behaviour

In Ruby 3.1 and later installed by rvm or asdf on a Mac, require 'mkmf' aborts the script and reports the following error (the reported path is different depending on the Ruby installation manager and the version of Ruby):

mkmf.rb can't find header files for ruby at /Users/couballj/.asdf/installs/ruby/3.2.0/lib/ruby/include/ruby.h

You might have to install separate package for the ruby development
environment, ruby-dev or ruby-devel for example.

and RbConfig::CONFIG["rubyhdrdir"] is set to an incorrect path:

"/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/Users/couballj/.asdf/installs/ruby/3.2.0/include/ruby-3.2.0"

Environment

OS:
Darwin KL9NXR3KXY 22.3.0 Darwin Kernel Version 22.3.0: Thu Jan  5 20:48:54 PST 2023; root:xnu-8792.81.2~2/RELEASE_ARM64_T6000 arm64

SHELL:
zsh 5.8.1 (x86_64-apple-darwin22.0)

ASDF VERSION:
v0.11.1

ASDF ENVIRONMENT VARIABLES:
ASDF_DIR=/opt/homebrew/opt/asdf/libexec

ASDF INSTALLED PLUGINS:
nodejs                       https://github.com/asdf-vm/asdf-nodejs.git master c9e5df4
python                       https://github.com/danhper/asdf-python.git master 8505457
ruby                         https://github.com/asdf-vm/asdf-ruby.git master 13b395f
rust                         https://github.com/code-lever/asdf-rust.git master 0c88f99

asdf plugins affected (if relevant)

ruby

Details

In Ruby 3.1 and later I can no longer build native gems (like nokoguru or redcarpet) on my Mac.

I have tried this by installing Ruby with both rvm and asdf, both which have the same results.

I receive the following error when trying to install (and build) these gems. For example, here is the error message when I try to run gem install redcarpet:

mkmf.rb can't find header files for ruby at /Users/couballj/.asdf/installs/ruby/3.2.0/lib/ruby/include/ruby.h

You might have to install separate package for the ruby development
environment, ruby-dev or ruby-devel for example.

I found that this error could be triggered just by running a Ruby script that requires mkmf. If test.rb contains this:

require 'mkmf'

Running this script:

ruby test.rb

Results in this output:

mkmf.rb can't find header files for ruby at /Users/couballj/.asdf/installs/ruby/3.2.0/lib/ruby/include/ruby.h

You might have to install separate package for the ruby development
environment, ruby-dev or ruby-devel for example.

Curiously, the reported directory does not exist. On my system, the path to ruby.h is /Users/couballj/.asdf/installs/ruby/3.2.0/include/ruby-3.2.0/ruby.h

I found where in the Ruby code this error is reported in mkmf.rb line 233.

This code is trying to find ruby.h based on the value of RbConfig::CONFIG["rubyhdrdir"]. On my system, this value is:

"/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/Users/couballj/.asdf/installs/ruby/3.2.0/include/ruby-3.2.0"

This value is a combination of ENV['SDKROOT'] (which on my system is /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk) and the correct include directory path /Users/couballj/.asdf/installs/ruby/3.2.0/include/ruby-3.2.0.

When I run the same code with Ruby 2.7.7, RbConfig::CONFIG["rubyhdrdir"] is set to the correct path:

"/Users/couballj/.asdf/installs/ruby/3.2.0/include/ruby-3.2.0"

Possible Cause

I have found a possible cause in commit fd97862 in line 127 of mkconfig.rb. This change prepends ENV['SDKROOT'] to the include directory that is used to build RbConfig::CONFIG["rubyhdrdir"].

While there may have been good reason for that change, in my case this change causes require 'mkmf' to fail in my use case.

Work Around

I have been able to work around this issue by creating a symbolic link from /Users /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/Users to /Users with the following command:

sudo ln -s /Users /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/Users

This change will works for both rvm and asdf no matter what version of Ruby is installed.

monfresh commented 1 year ago

@jcouball I see that you reported this bug to the Ruby team, and that they fixed it: https://bugs.ruby-lang.org/issues/19403

You might already know this, but on a brand new Mac, the SDKROOT env var is not set. So, the fact that it's set on your machine either means you're exporting it in one of your shell startup files (such as ~/.zshrc or ~/.zprofile or ~/.zlogin), or some script in your shell startup file is doing that.

It's not recommended to set these types of env vars globally, and SDKROOT is not needed for Ruby installation. Instead, if you need to set SDKROOT for some other tool, it's recommended to set it on the command line while running the desired command.

jcouball commented 1 year ago

Hello, @monfresh! Thank you for your reply.

I did find this in my .zshrc file:

# Set the SDKROOT for building TruffleRuby
export SDKROOT=$(xcrun --show-sdk-path)

I agree with your assessment that it isn't recommended and I could remove this from my environment but I still think this was a bug in the Ruby builder that should be addressed so others don't hit this problem as well.

I am closing this issue since the problem was addressed in the Ruby build itself (thanks for reminding me about this issue).