RAKSUL TechBlog

ラクスルグループのエンジニアが技術トピックを発信するブログです

Rails development environment troubleshooting on Mac with M1 chip

Hi everyone! My name is Thanh, I’m working in the Area-Marketing team at RAKSUL.

Raksul’s services are built on several technologies, including Ruby on Rails. Setting up Ruby and Gems is the first step to working with the Rails environment, but it’s not a frequent task. So I have lost so many hours fighting compilers to install Ruby and related gems on macOS Monterey M1. In this post, I will share my experience to help you avoid and fix the issues.

Contents

  1. Detecting macOS CPU architecture
  2. Homebrew
  3. Ruby issue
  4. Gem issues
  5. Reference
  6. Recap

Detecting macOS CPU architecture

On macOS, two architectures are supported

  • x86_64 is the architecture of Intel's 64-bit CPUs, aka x64. It was shipped between 2005 and 2021.
  • arm64 is the architecture used by newer Macs built on Apple Silicon, shipped in late 2020.

To know current architecture is the first step before starting to install compatible libraries/tools.

<arm64>
% uname -m
arm64
<x86_64>
% uname -m
x86_64

Homebrew

Issue: The current project has an installation script to collect all required tools in one place. Meanwhile, setting up the development environment got an issue with both versions of homebrew installed (arm64 and x86).

How to solve it: To reinstall Homebrew using the official method, it will correct the referenced prefix. The below info help you confirm Homebrew on your PC.

Installation

% /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Homebrew location

<arm64>
% which brew
/opt/homebrew/bin/brew
<x86_64>
% which brew
/usr/local/bin/brew

What is the reason that Homebrew has changed the prefix instead of /usr/local for Macs Apple Silicon?

  • The path /usr/local is also used by other tools, not only Homebrew. This can make conflict
  • Homebrew tools might be used by default without configuration to avoid the above issues making an alternate prefix would be easier.

You can find the detail of the Homebrew discussion at here

Tips:

You will do bundle install later on, knowing the Homebrew prefix and location of tools help you run the correct reference libraries.

Ex: brew info openssl@1.1

The command show detail of the installed library that helps to know the configuration of OpenSSL, such as LDFLAGS, CPPFLAGS, and PKG_CONFIG_PATH etc.,

% brew info openssl@1.1
==> openssl@1.1: stable 1.1.1q (bottled) [keg-only]
Cryptography and SSL/TLS Toolkit
https://openssl.org/
/opt/homebrew/Cellar/openssl@1.1/1.1.1q (8,097 files, 18MB)
  Poured from bottle on 2022-10-04 at 07:33:33
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/openssl@1.1.rb
License: OpenSSL
==> Dependencies
Required: ca-certificates ✔
==> Caveats
A CA file has been bootstrapped using certificates from the system
keychain. To add additional certificates, place .pem files in
  /opt/homebrew/etc/openssl@1.1/certs

and run
  /opt/homebrew/opt/openssl@1.1/bin/c_rehash

openssl@1.1 is keg-only, which means it was not symlinked into /opt/homebrew,
because macOS provides LibreSSL.

If you need to have openssl@1.1 first in your PATH, run:
  echo 'export PATH="/opt/homebrew/opt/openssl@1.1/bin:$PATH"' >> ~/.zshrc

For compilers to find openssl@1.1 you may need to set:
  export LDFLAGS="-L/opt/homebrew/opt/openssl@1.1/lib"
  export CPPFLAGS="-I/opt/homebrew/opt/openssl@1.1/include"

For pkg-config to find openssl@1.1 you may need to set:
  export PKG_CONFIG_PATH="/opt/homebrew/opt/openssl@1.1/lib/pkgconfig"

==> Analytics
install: 1,158,119 (30 days), 2,567,700 (90 days), 11,370,947 (365 days)
install-on-request: 52,608 (30 days), 103,510 (90 days), 418,568 (365 days)
build-error: 1,533 (30 days)

Ruby issue

I got the issue when installing ruby 2.6.6

Issue:

% rbenv install 2.6.6
To follow progress, use 'tail -f /var/folders/rd/r2g0jzln74s6t3636gb6m8dh0000gq/T/ruby-build.20221110172716.6727.log' or pass --verbose
Downloading ruby-2.6.6.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.6.tar.bz2
Installing ruby-2.6.6...
ruby-build: using readline from homebrew

BUILD FAILED (macOS 12.6.1 using ruby-build 20220930)

Inspect or clean up the working tree at /var/folders/rd/r2g0jzln74s6t3636gb6m8dh0000gq/T/ruby-build.20221110172716.6727.iLaZEA
Results logged to /var/folders/rd/r2g0jzln74s6t3636gb6m8dh0000gq/T/ruby-build.20221110172716.6727.log

How to solve it:

After confirming the logs, disable the warning by set RUBY_CFLAGS="-w" to fix the issue. Also, Github issue solved a similar error with set environment variables.

% RUBY_CFLAGS="-w" rbenv install 2.6.6

To follow progress, use 'tail -f /var/folders/rd/r2g0jzln74s6t3636gb6m8dh0000gq/T/ruby-build.20221110174033.21130.log' or pass --verbose
Downloading ruby-2.6.6.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.6.tar.bz2
Installing ruby-2.6.6...
ruby-build: using readline from homebrew
Installed ruby-2.6.6 to /Users/XYZ/.rbenv/versions/2.6.6

Tips:

Tip 1: correct OpenSSL installation

When you install openssl via brew, let set a specific version for it, otherwise openssl@3 will be installed on Monterey

https://formulae.brew.sh/formula/openssl@1.1

brew install openssl@1.1

https://formulae.brew.sh/formula/openssl@3

brew install openssl@3

Tip 2: Ruby version required different OpenSSL version

For Ruby versions 2.x ~ 3.0

brew install openssl@1.1 readline libyaml gmp
export RUBY_CONFIGURE_OPTS="--with-openssl-dir=$(brew --prefix openssl@1.1)"

For Ruby versions 3.1 ~ above

brew install openssl@3 readline libyaml gmp
export RUBY_CONFIGURE_OPTS="--with-openssl-dir=$(brew --prefix openssl@3)"

Gem issues

Issue 1:

Using gem version still does not support arm64. Currently, using twirp (1.7.2)

/Users/XYZ/R/github/r/vendor/bundle/ruby/2.7.0/gems/zeitwerk-2.5.4/lib/zeitwerk/kernel.rb:35:in 
`require': cannot load such file -- google/protobuf_c (LoadError)

How to solve it:

Check the gem-released version and upgrade it.

gem 'twirp', '~> 1.9.0'

Issue 2:

OpenSSL didn't match reference environment variables

ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [rubyeventmachine.bundle] Error 1

make failed, exit code 2

Gem files will remain installed in /Users/XYZ/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/eventmachine-1.2.7 for inspection.
Results logged to /Users/XYZ/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/extensions/arm64-darwin-21/2.7.0/eventmachine-1.2.7/gem_make.out                

How to solve it:

Follow steps to correct environment variables for OpenSSL

  1. Confirm the installation of openssl brew info openssl@1.1
  2. Export environment variables
% export PATH="/opt/homebrew/opt/openssl@1.1/bin:$PATH"
// For compilers to find openssl@1.1
% export LDFLAGS="-L/opt/homebrew/opt/openssl@1.1/lib"
% export CPPFLAGS="-I/opt/homebrew/opt/openssl@1.1/include"
% export PKG_CONFIG_PATH="/opt/homebrew/opt/openssl@1.1/lib/pkgconfig"

Or you can add it to the bundle local config

% bundle config --local build.eventmachine --with-openssl-dir=$(brew --prefix openssl@1.1)

3.Runbundle install

Reference

To learn more, refer to the following resources

  • Some influential environment variables:
  CC          C compiler command
  CFLAGS      C or C++ compiler flags
  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
              nonstandard directory <lib dir>
  LIBS        libraries to pass to the linker, e.g. -l<library>
  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
              you have headers in a nonstandard directory <include dir>
  CXX         C++ compiler command
  CXXFLAGS    C++ compiler flags
  CPP         C preprocessor

Recap

When you are facing installation issues check the environment health, by following the commands

  • uname -m: to know your architecture
  • brew doctor: confirm the output of brew config
  • check ruby installation
% ruby -e 'require "rbconfig"; pp RbConfig::CONFIG' | grep "host"
 "host_os"=>"darwin21",
 "host_vendor"=>"apple",
 "host_cpu"=>"arm64",
 "host"=>"arm64-apple-darwin21",
 "host_alias"=>"",
  • check bundle platform
% bundle platform
Your platform is: arm64-darwin21

Should collect the current environment first before executing the commands that you search from google or GitHub issues. Otherwise apply the wrong parameter or environment variables the error is always the same and it seems to have no effect.