This Post will harken back to Wandering in the Mojave with JavaScript, wherein we learned a great many things about Xcode 10 and libstdc++ support.

Having taken one day to rest after a harrowing experience with gyp, I awoke on Friday with the notion to document our experience. My Shiny New Blog is built atop Jekyll, which means I must now reconstruct my Ruby tooling.

The horse is refreshed, and we break camp on the heels of a peaceful dawn. Although the reinstallation of rvm goes smoothly, in my heart, I know that we’ve only updated some support scripting. The devil will be in the details.

A Road Previously Traveled

This procedure is a familiar one. I crack open my long-term notes on building Rubies from source under MacOS, and they tell me;

rvm autolibs packages # homebrew
rvm requirements      # may crap out on "apple-gcc42" or similar

rvm install ruby-2.3.4

But sigh. We’ve seen this before;

No binary rubies available for: osx/10.14/x86_64/ruby-2.3.4.
Continuing with compilation. Please read 'rvm help mount' to get more information on binary rubies.
You requested building with '/usr/bin/gcc-4.2' but it is not in your path.

A few lines below, my notes contain this cryptic block;

# https://github.com/rvm/rvm/issues/763
#   `rvm` makes some bad assumptions about "/usr/bin/gcc-4.2", so either
#   create a permanent symlink: `ln -s /usr/bin/gcc /usr/bin/gcc-4.2`
#   or use `--with-gcc=/usr/bin/gcc-4.2`
# https://github.com/rvm/rvm/issues/4200
#   `--with-gcc=gcc` for pre-2.x
rvm install ruby-2.3.4 --with-gcc=/usr/bin/gcc

The first approach I take is to create the symlink. Unfortunately, that’s no longer possible due to the mysteries of System Integrity Protection. Yet I am loathe to disable the feature; I trust that it serves me in ways that I don’t need to know about.

Our other recourse is --with-gcc – and it would seem that approach is going to work for us just dandy – until, suddenly;

Could not load OpenSSL.
You must recompile Ruby with OpenSSL support or change the sources in your Gemfile from 'https' to 'http'. Instructions for compiling with OpenSSL using RVM are available at http://rvm.io/packages/openssl.

Not so long ago, I’d wrestled with pip servers’ minimum TLS version using Python 2.7 and OpenSSL, and they’d nearly beat me. I brace myself for what could be a significant challenge. Fortunately, some six years past, this Stack Overflow had been authored with a solution.

From its wisdom, I derived;

# it does complain, it but works
#   "Do not know how to check/install gcc ..."
brew install openssl

# the modern variant of `rvm pkg install <PACKAGE>`, eg. 'openssl'
rvm autolibs homebrew

rvm install ruby-2.3.4 --with-openssl-dir=`brew --prefix openssl` --with-gcc=/usr/bin/gcc

# `bundler '~> 1.0'`
#   "Pessimistic Version" of last reliable version before 2.0
gem install bundler -v '~> 1.0'

We now have a magnificent build of Ruby 2.3.4. “I’ve really gotta up my scripts to use 2.6,” I think to myself as I take a long, cool drink from my canteen.

The Unbearable Parsing of Markup

I roll out a rugged woolen blanket and spread upon it the contents of my blog’s Git repo. The JavaScript gulp tooling is already stable, thanks to my Wandering earlier in the week.

Now, to install the Gems.

# works like butter
nvm use
npm install

# works not so much like butter
rvm use 2.3.4
bundle install

Nope, not like butter at all;

Installing nokogiri 1.7.2 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

current directory:
/Users/dfoley/REDACTED/ruby_gems/ruby/2.3.0/gems/nokogiri-1.7.2/ext/nokogiri
/usr/local/rvm/rubies/ruby-2.3.4/bin/ruby -r ./siteconf20190211-89093-1clvmz9.rb
extconf.rb
checking if the C compiler accepts ... yes
checking if the C compiler accepts
-Wno-error=unused-command-line-argument-hard-error-in-future... no
Building nokogiri using packaged libraries.
Using mini_portile version 2.1.0
checking for iconv.h... yes
checking for gzdopen() in -lz... yes
checking for iconv using --with-opt-* flags... yes
************************************************************************
IMPORTANT NOTICE:

Building Nokogiri with a packaged version of libxml2-2.9.4
with the following patches applied:
    - 0001-Fix-comparison-with-root-node-in-xmlXPathCmpNodes.patch
    - 0002-Fix-XPointer-paths-beginning-with-range-to.patch
    - 0003-Disallow-namespace-nodes-in-XPointer-ranges.patch

Team Nokogiri will keep on doing their best to provide security
updates in a timely manner, but if this is a concern for you and want
to use the system library instead; abort this installation process and
reinstall nokogiri as follows:

    gem install nokogiri -- --use-system-libraries
        [--with-xml2-config=/path/to/xml2-config]
        [--with-xslt-config=/path/to/xslt-config]

If you are using Bundler, tell it to use the option:

    bundle config build.nokogiri --use-system-libraries
    bundle install

Note, however, that nokogiri is not fully compatible with arbitrary
versions of libxml2 provided by OS/package vendors.
************************************************************************
Extracting libxml2-2.9.4.tar.gz into
tmp/x86_64-apple-darwin18.2.0/ports/libxml2/2.9.4... OK
Running git apply with
/Users/dfoley/REDACTED/ruby_gems/ruby/2.3.0/gems/nokogiri-1.7.2/patches/libxml2/0001-Fix-comparison-with-root-node-in-xmlXPathCmpNodes.patch...
OK
Running git apply with
/Users/dfoley/REDACTED/ruby_gems/ruby/2.3.0/gems/nokogiri-1.7.2/patches/libxml2/0002-Fix-XPointer-paths-beginning-with-range-to.patch...
OK
Running git apply with
/Users/dfoley/REDACTED/ruby_gems/ruby/2.3.0/gems/nokogiri-1.7.2/patches/libxml2/0003-Disallow-namespace-nodes-in-XPointer-ranges.patch...
OK
Running 'configure' for libxml2 2.9.4... ERROR, review
'/Users/dfoley/REDACTED/ruby_gems/ruby/2.3.0/gems/nokogiri-1.7.2/ext/nokogiri/tmp/x86_64-apple-darwin18.2.0/ports/libxml2/2.9.4/configure.log'
to see what happened. Last lines are:
========================================================================
checking whether to enable maintainer-specific portions of Makefiles... yes
checking build system type... x86_64-apple-darwin18.2.0
checking host system type... x86_64-apple-darwin18.2.0
checking for a BSD-compatible install... /usr/local/bin/ginstall -c
checking whether build environment is sane... yes
checking for x86_64-apple-darwin18.2.0-strip... no
checking for strip... strip
checking for a thread-safe mkdir -p... /usr/local/bin/gmkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking whether make supports nested variables... yes
checking whether make supports nested variables... (cached) yes
checking for x86_64-apple-darwin18.2.0-gcc... /usr/bin/gcc-4.2
checking whether the C compiler works... no
configure: error: in
`/Users/dfoley/REDACTED/ruby_gems/ruby/2.3.0/gems/nokogiri-1.7.2/ext/nokogiri/tmp/x86_64-apple-darwin18.2.0/ports/libxml2/2.9.4/libxml2-2.9.4':
configure: error: C compiler cannot create executables
See `config.log' for more details
========================================================================
*** 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.

Provided configuration options:
    --with-opt-dir
    --with-opt-include
    --without-opt-include=${opt-dir}/include
    --with-opt-lib
    --without-opt-lib=${opt-dir}/lib
    --with-make-prog
    --without-make-prog
    --srcdir=.
    --curdir
    --ruby=/usr/local/rvm/rubies/ruby-2.3.4/bin/$(RUBY_BASE_NAME)
    --help
    --clean
    --use-system-libraries
    --enable-static
    --disable-static
    --with-zlib-dir
    --without-zlib-dir
    --with-zlib-include
    --without-zlib-include=${zlib-dir}/include
    --with-zlib-lib
    --without-zlib-lib=${zlib-dir}/lib
    --enable-cross-build
    --disable-cross-build
/Users/dfoley/REDACTED/ruby_gems/ruby/2.3.0/gems/mini_portile2-2.1.0/lib/mini_portile2/mini_portile.rb:366:in `block in execute': Failed to complete configure task (RuntimeError)
from /Users/dfoley/REDACTED/ruby_gems/ruby/2.3.0/gems/mini_portile2-2.1.0/lib/mini_portile2/mini_portile.rb:337:in `chdir'
from /Users/dfoley/REDACTED/ruby_gems/ruby/2.3.0/gems/mini_portile2-2.1.0/lib/mini_portile2/mini_portile.rb:337:in `execute'
from /Users/dfoley/REDACTED/ruby_gems/ruby/2.3.0/gems/mini_portile2-2.1.0/lib/mini_portile2/mini_portile.rb:106:in `configure'
from /Users/dfoley/REDACTED/ruby_gems/ruby/2.3.0/gems/mini_portile2-2.1.0/lib/mini_portile2/mini_portile.rb:149:in `cook'
    from extconf.rb:364:in `block (2 levels) in process_recipe'
    from extconf.rb:257:in `block in chdir_for_build'
    from extconf.rb:256:in `chdir'
    from extconf.rb:256:in `chdir_for_build'
    from extconf.rb:363:in `block in process_recipe'
    from extconf.rb:262:in `tap'
    from extconf.rb:262:in `process_recipe'
    from extconf.rb:547:in `<main>'

To see why this extension failed to compile, please check the mkmf.log which can
be found here:

/Users/dfoley/REDACTED/ruby_gems/ruby/2.3.0/extensions/x86_64-darwin-18/2.3.0/nokogiri-1.7.2/mkmf.log

extconf failed, exit code 1

Gem files will remain installed in /Users/dfoley/REDACTED/ruby_gems/ruby/2.3.0/gems/nokogiri-1.7.2 for inspection.
Results logged to /Users/dfoley/REDACTED/ruby_gems/ruby/2.3.0/extensions/x86_64-darwin-18/2.3.0/nokogiri-1.7.2/gem_make.out

An error occurred while installing nokogiri (1.7.2), and Bundler cannot continue.
Make sure that `gem install nokogiri -v '1.7.2' --source 'http://rubygems.org/'` succeeds before bundling.

Something’s dreadfully wrong with nokogiri.

I gasp, catch myself, then back away and breathe for a moment under the mid-morning sun. In all directions, the expanse is a roiling sea of dirty browns and gold, with little to break the horizon save for the Funeral Mountains far to the north.

I steel myself with renewed dedication. I will cross this impasse.

No one can ever doubt my commitment to Sparkle Motion.

Scratching My Headers

Let’s check the mkmf.log, as our massive failure dump suggests;

"/usr/bin/gcc -o conftest -I/usr/local/rvm/rubies/ruby-2.3.4/include/ruby-2.3.0/x86_64-darwin18 -I/usr/local/rvm/rubies/ruby-2.3.4/include/ruby-2.3.0/ruby/backward -I/usr/local/rvm/rubies/ruby-2.3.4/include/ruby-2.3.0 -I. -I/usr/local/opt/openssl/include  -I/usr/local/opt/libyaml/include -I/usr/local/opt/readline/include -I/usr/local/opt/libksba/include -I/usr/local/opt/openssl@1.1/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT    -O3 -fno-fast-math -ggdb3 -Wall -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Wunused-variable -Wpointer-arith -Wwrite-strings -Wdeclaration-after-statement -Wshorten-64-to-32 -Wimplicit-function-declaration -Wdivision-by-zero -Wdeprecated-declarations -Wextra-tokens  -fno-common -pipe  -O3 -Wall -Wcast-qual -Wwrite-strings -Wconversion -Wmissing-noreturn -Winline conftest.c  -L. -L/usr/local/rvm/rubies/ruby-2.3.4/lib -L/usr/local/opt/libyaml/lib -L/usr/local/opt/readline/lib -L/usr/local/opt/libksba/lib -L/usr/local/opt/openssl@1.1/lib -L. -L/usr/local/opt/openssl/lib  -fstack-protector -L/usr/local/lib -L/usr/local/opt/libyaml/lib -L/usr/local/opt/readline/lib -L/usr/local/opt/libksba/lib -L/usr/local/opt/openssl@1.1/lib     -lruby.2.3.0  -lpthread -lgmp -ldl -lobjc  "
Undefined symbols for architecture x86_64:
  "_iconv", referenced from:
      _main in conftest-08b8ef.o
  "_iconv_open", referenced from:
      _main in conftest-08b8ef.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
checked program was:
/* begin */
 1: #include "ruby.h"
 2:
 3: #include <stdlib.h>
 4: #include <iconv.h>
 5:
 6: int main(void)
 7: {
 8:     iconv_t cd = iconv_open("", "");
 9:     iconv(cd, NULL, NULL, NULL, NULL);
10:     return EXIT_SUCCESS;
11: }
/* end */

Well, this seems curious;

Undefined symbols for architecture x86_64

Perhaps we’re dealing with the “include path for stdlibc++ headers not found” problem again, which would lead us back on the path to installing macOS_SDK_headers_for_macOS_10.14.pkg. I’d come across this Updated to Mojave article which suggested that very thing.

However, much as when I took this same approach on Wednesday, there is no relief to be found by simply installing the legacy macOS headers.

Appeal to the Natives

How about this callout in the massive failure dump?

    gem install nokogiri -- --use-system-libraries
        [--with-xml2-config=/path/to/xml2-config]
        [--with-xslt-config=/path/to/xslt-config]

If you are using Bundler, tell it to use the option:

Alright, I think I will. I’ll tell it to use that very option;

# https://bundler.io/v1.16/bundle_config.html#BUILD-OPTIONS
#   "flags to pass to the gem installer"
#   `bundle config build.<PACKAGE> "--flags"`
bundle config build.nokogiri "--use-system-libraries"

bundle install

Nope. It’s still not like butter at all;

Installing nokogiri 1.7.2 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

current directory:
/Users/dfoley/REDACTED/ruby_gems/ruby/2.3.0/gems/nokogiri-1.7.2/ext/nokogiri
/usr/local/rvm/rubies/ruby-2.3.4/bin/ruby -r ./siteconf20190210-21692-mv9hb1.rb
extconf.rb --use-system-libraries
checking if the C compiler accepts ... yes
checking if the C compiler accepts
-Wno-error=unused-command-line-argument-hard-error-in-future... no
Building nokogiri using system libraries.
checking for xmlParseDoc() in libxml/parser.h... yes
checking for xsltParseStylesheetDoc() in libxslt/xslt.h... yes
checking for exsltFuncRegister() in libexslt/exslt.h... yes
checking for xmlHasFeature()... yes
checking for xmlFirstElementChild()... yes
checking for xmlRelaxNGSetParserStructuredErrors()... yes
checking for xmlRelaxNGSetParserStructuredErrors()... yes
checking for xmlRelaxNGSetValidStructuredErrors()... yes
checking for xmlSchemaSetValidStructuredErrors()... yes
checking for xmlSchemaSetParserStructuredErrors()... yes
creating Makefile

current directory:
/Users/dfoley/REDACTED/ruby_gems/ruby/2.3.0/gems/nokogiri-1.7.2/ext/nokogiri
make "DESTDIR=" clean

current directory:
/Users/dfoley/REDACTED/ruby_gems/ruby/2.3.0/gems/nokogiri-1.7.2/ext/nokogiri
make "DESTDIR="
compiling xml_comment.c
make: /usr/bin/gcc-4.2: No such file or directory
make: *** [xml_comment.o] Error 1

make failed, exit code 2

Gem files will remain installed in
/Users/dfoley/REDACTED/ruby_gems/ruby/2.3.0/gems/nokogiri-1.7.2
for inspection.
Results logged to
/Users/dfoley/REDACTED/ruby_gems/ruby/2.3.0/extensions/x86_64-darwin-18/2.3.0/nokogiri-1.7.2/gem_make.out

An error occurred while installing nokogiri (1.7.2), and Bundler cannot
continue.
Make sure that `gem install nokogiri -v '1.7.2' --source 'http://rubygems.org/'`
succeeds before bundling.

Ahh, but what I do see is that the failure dump is much less massive. I dare say that something has improved.

A Conspiracy of Compilers

So, let’s examine the gem_make.out;

compiling xml_comment.c
make: /usr/bin/gcc-4.2: No such file or directory
make: *** [xml_comment.o] Error 1

make failed, exit code 2

Sigh. Yes, we’ve seen this before. /usr/bin/gcc-4.2 has shown up twice in this very Post. Huh, maybe I need one of the C++ Standard Libraries from Homebrew, just like I did on Wednesday.

I believe it’s time to call on our good old friends CC and CXX, once again. For by the grace of God, they are loyal, faithful and true.

brew install gcc
brew list gcc  # aaaaand what did we get?

# we got `gcc-8.2`
export CC=/usr/local/Cellar/gcc/8.2.0/bin/gcc-8
export CXX=/usr/local/Cellar/gcc/8.2.0/bin/g++-8

Now, those environment overrides are definitely having an effect;

compiling xml_comment.c
gcc-8: error: unrecognized command line option '-Wshorten-64-to-32'
gcc-8: error: unrecognized command line option '-Wdivision-by-zero'; did you mean '-Wdiv-by-zero'?
gcc-8: error: unrecognized command line option '-Wextra-tokens'; did you mean '-Wextra-semi'?
make: *** [xml_comment.o] Error 1

make failed, exit code 2

But we’re not quite out of the desert just yet.

However, new information has come to light. A little research on ‘-Wdivision-by-zero’, and I find this Github Issue in sparklemotion/nokogiri’s very own repo. It includes a massive failure dump that looks exactly like mine!

And there, towards the end, we find the solution we’ve been seeking;

CC=llvm-gcc bundle install worked for my use-case.

As always, we take that to the next level;

# works great
export CC=/usr/bin/llvm-gcc
export CXX=/usr/bin/llvm-g++

# also works great;
#   i should have tried that *before* the `brew`-installed version of `gcc`
export CC=/usr/bin/gcc
export CXX=/usr/bin/g++

And with those settings, we have finally achieved our goal;

Installing nokogiri 1.7.2 with native extensions
# ...
Bundle complete! 12 Gemfile dependencies, 46 gems now installed.
Bundled gems are installed into `./ruby_gems`

And Onto the Next

I have unearthed the tools I need to keep authoring these blog Posts – and even with all the associated crazy, the sun is not yet low in the sky.

Gathering the Github repo back into my knapsack, I sling the rugged blanket over my steed. We start a steady trot to the north – and as it happens, luck is with us – for we reach the next oasis by nightfall.

Later in the evening, I try out another possible variant, given the whole of what I’d written in this Post;

bundle config build.nokogiri "--use-system-libraries --with-gcc=/usr/bin/gcc"

But /usr/bin/gcc-4.2 rears its ugly head again. It is not to be.

Friends You Can Count On

Somtimes the native gcc compiler in Mojave is the right tool for the job.

I guess that just goes to show us, once again – even when the going gets rough, you can always rely on your trusty amigos, CC and CXX.

And that’s why we have standards & conventions, kids.