Skip to content

Instantly share code, notes, and snippets.

@SteveBenner
Last active August 13, 2019 14:52
Show Gist options
  • Star 26 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save SteveBenner/de51738222e92d606487 to your computer and use it in GitHub Desktop.
Save SteveBenner/de51738222e92d606487 to your computer and use it in GitHub Desktop.
Mac fix - Install Nokogiri gem on OS X 10.9 Mavericks
#!/usr/bin/env ruby
#
# Mac fix 1 - Install the Nokogiri gem on Mac OS 10.9 Mavericks
#
# Usage: to configure and install using Bundler, pass in 'bundle' as an argument to the script.
#
# Nokogiri works at a very low level, so it has many issues on various platforms.
# As a result, the command `install gem nokogiri` often will fail. This fix is for
# errors involving 'libiconv', such as the following one I encountered:
#
# > libiconv is missing. please visit http://nokogiri.org/tutorials/installing_nokogiri.html
# > for help with installing dependencies.
# > -----
# > *** extconf.rb failed ***
# > Could not create Makefile due to some reason, probably lack of necessary
# > libraries and/or headers. Check the mkmf.log file for more details. You may
# > need configuration options.
#
# This script is basically just carrying out the install process illustrated on the
# Nokogiri website, specifically for OS X 10.9. Other systems are not covered.
# More information can be found at: http://nokogiri.org/tutorials/installing_nokogiri.html
#
# Some additional resources I came across while troubleshooting this issue:
# - http://stackoverflow.com/questions/5528839/why-does-installing-nokogiri-on-mac-os-fail-with-libiconv-is-missing
# - http://stackoverflow.com/questions/23401174/nokogiri-gem-fails-to-install-in-os-x-mavericks
# - http://stackoverflow.com/questions/19643153/error-to-install-nokogiri-on-osx-10-9-maverick
# - http://jasdeep.ca/2013/10/installing-nokogiri-fails-os-x-mavericks/
#
# NOTE:
# There are many factors involved in Nokogiri's installation. This script was tested
# on a system with the following characteristics and installations:
#
# - Mac OS X 10.9.4
# - 'xcode-select' installed
# - Homebrew 0.9.5
# - Ruby 2.1.2
# - Nokogiri 1.6.3.1
# There are three libraries required to compile Nokogiri's native extensions
libs = %w[libxml2 libxslt libiconv]
# Install and link them using Homebrew
`brew update`
%w[install link].each { |command| `brew #{command} #{libs.join(' ')}` }
# Use the latest versions of installed libraries from your Homebrew installation
paths = libs.inject({}) do |libs, lib|
# It's easy to find the library paths using the 'brew' executable, but keep in mind
# they are just symlinks; the real installation path may vary from system to system.
libs[lib.to_sym] = File.realpath `brew --prefix #{lib}`.chomp
libs
end
# If you have any Nokogiri gem files, they need to be removed obviously
`gem uninstall nokogiri`
# Install Nokogiri gem using either RubyGems or Bundler (defaults to RubyGems)
flags = [
'--',
"--with-xml2-dir=#{paths[:libxml2]}",
"--with-xslt-dir=#{paths[:libxslt]}",
"--with-iconv-dir=#{paths[:libxml2]}",
"--with-xml2-config=#{paths[:libxml2]}/bin/xml2-config",
"--with-xslt-config=#{paths[:libxslt]}/bin/xslt-config"
]
if ARGV[0] == 'bundle'
`bundle config build.nokogiri #{flags.drop(1).join(' ')}`
print `bundle exec install nokogiri`
else
print `gem install nokogiri #{flags.join(' ')}`
end
puts
puts "Mac 'Nokogiri installation' fix applied successfully! Latest version at:"\
"https://gist.github.com/SteveBenner/de51738222e92d606487"
@SteveBenner
Copy link
Author

You’ve really got to pick up your game, Apple! Installing one of the most essential gems in the Rubyverse has never been so complex and failure-prone as with the latest Mac OS releases… Luckily, we have amazing tools like Homebrew that come to our rescue. This script leverages the modern Homebrew ecosystem to fix Nokogiri installation issues in a few lines of Ruby—mostly a matter of pointing the gem installer at the modern libraries and tools provided by the open-source community, instead of Apple’s dated versions.

I hope this can be useful to others, as it has been to me. Contributions are welcomed!


Usage:

  • Firstly, the script of course requires execution privileges. You can make it executable for your user with: chmod u+x macfix1-install-nokogiri.rb.
  • You can run the script by executing it normally on the command line, which means either using the absolute path, e.g. /Users/you/macfix1-install-nokogiri.rb, or if the file is in your current working directory, you should use: ./macfix1-install-nokogiri.rb.
  • I like to keep my scripts organized in different places around my system, so to install one, I use a command such as: ln -s <path-to-script> /usr/local/bin/install-nokogiri to symbolically link it into my executables directory. Now I can just call install-nokogiri in the shell, like any other command.
Installing with Bundler

By default, the script installs Nokogiri with RubyGems. To configure and install with Bundler, simply pass bundle as an argument.

@dryaf
Copy link

dryaf commented Aug 28, 2014

latest ruby 2.1.2 via rvm gives

add-air:code add$ ./macfix1-install-nokogiri.rb

./macfix1-install-nokogiri.rb:44:in `block in <main>': undefined method `shelljoin' for ["libxml2", "libxslt", "libiconv"]:Array (NoMethodError)
    from ./macfix1-install-nokogiri.rb:44:in `each'
    from ./macfix1-install-nokogiri.rb:44:in `<main>'

@jamesingham
Copy link

Ruby 2.0.0p451, same issue.

james$ ./macfix1-install-nokogiri.rb bundle
./macfix1-install-nokogiri.rb:44:in `block in <main>': undefined method `shelljoin' for ["libxml2", "libxslt", "libiconv"]:Array (NoMethodError)
    from ./macfix1-install-nokogiri.rb:44:in `each'
    from ./macfix1-install-nokogiri.rb:44:in `<main>'

@zenspider
Copy link

So fork it, add the require, and send him a pull request. C'mon guys.

@SteveBenner
Copy link
Author

Haha, FAIL. I must have been up late writing this one; I know exactly what happened... I use the Shellwords module quite a bit, so dropping Array#shelljoin in there was just automatic for me. Before posting the script though, to polish it I went through and removed the dependency on shellwords, because less dependencies == better code… And of course I forgot that one method. Glancing at the arguments, you’ll notice that it’s totally unnecessary—they don’t contain any special characters or anything—so I just swapped it for regular Array#join.

@newton108
Copy link

Error: No available formula for libxml2libxsltlibiconv
Error: No such keg: /usr/local/Cellar/libxml2libxsltlibiconv
./macfix1-install-nokogiri.rb:50:in `block in <main>': undefined method `Pathname' for main:Object (NoMethodError)
    from ./macfix1-install-nokogiri.rb:47:in `each'
    from ./macfix1-install-nokogiri.rb:47:in `inject'
    from ./macfix1-install-nokogiri.rb:47:in `<main>'

@SteveBenner
Copy link
Author

Thanks @newton108 for discovering two more errors. I do want people to run the script flawlessly of course, but it’s a rather informal script and testing it is low on my priority list for now. Any errors should be _extremely_ easy to fix, and in fact I did note in a comment that Pathname was not required.

@imme5150
Copy link

I got this error:
Error: No available formula for libiconv Apple distributes libiconv with OS X, you can find it in /usr/lib. Some build scripts fail to detect it correctly, please check existing formulae for solutions. Error: No such keg: /usr/local/Cellar/libxml2 ./macfix1-install-nokogiri.rb:50:in 'realpath': No such file or directory @ realpath_rec - /usr/local/Cellar/libxml2 (Errno::ENOENT) from ./macfix1-install-nokogiri.rb:50:in 'block in <main>' from ./macfix1-install-nokogiri.rb:47:in 'each' from ./macfix1-install-nokogiri.rb:47:in 'inject' from ./macfix1-install-nokogiri.rb:47:in '<main>'
When running brew link libxml2 manually got:
Warning: libxml2 is keg-only and must be linked with --force Note that doing so can interfere with building software.

This is Ruby 2.1.5p273 (2014-11-13 revision 48405) [x86_64-darwin14.0]
on OS X 10.9.5

@imme5150
Copy link

Was able to get it working with this command: --use-system-libraries --with-xml2-config=/usr/local/opt/libxml2/bin/xml2-config

@duderonomy
Copy link

On new image of Yosemite (with no additional gcc from brew), nokogiri would not build.
It is likely only this command need be run: xcode-select --install
gem uninstall nokogiri was recommended by other sources but probably not necessary.
The only action taken previous to above command was brew install libxml2, however I imagine it was not necessary either. Nor part of the solution.

@jeremykohn
Copy link

Thanks imme550! That helped me too. Only the file paths were different (I'm on 10.6.8 instead of 10.9):

gem install nokogiri -- --use-system-libraries --with-xml2-config=/usr/bin/xml2-config --with-xslt-config=/usr/bin/xslt-config

@krzysztofmajewski
Copy link

Thanks Steve Benner, this (mostly) worked for me. I had to add --use-system-libraries and --with-xml2-include=/usr/local/opt/libxml2/include/libxml2 after the --, and I skipped the brew link [library].

The full command was:

sudo gem install nokogiri -- --use-system-libraries --with-xslt-dir=/usr/local/opt/libxslt --with-iconv-dir=/usr/local/opt/libiconv --with-xml2-dir=/usr/local/opt/libxml2 --with-xml2-config=/usr/local/opt/libxml2/bin/xml2-config --with-xml2-include=/usr/local/opt/libxml2/include/libxml2 --with-xslt-config=/usr/local/opt/libxslt/bin/xslt-config

@ramijames
Copy link

@krzysztofmajewski this was a working command for El Capitan. Thanks for that.

@visoft
Copy link

visoft commented Aug 13, 2019

Thanks @krzysztofmajewski! Worked great for install Nokogiri 1.6.6.2 (just had to add the version number to the command nokogiri -v 1.6.6.2

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