ld: symbol(s) not found for architecture x86_64
“ld: symbol(s) not found for architecture x86_64” or “ld: symbol(s) not found for architecture arm64” are common errors people get on Apple Silicon Macs when installing Ruby itself, or when installing Ruby gems with bundle install
or gem install
.
The three main reasons for these errors are:
- Installing things with and without Rosetta (mixing and matching the arm64 and x86_64 architectures)
- Installing outdated gems that don’t work on Apple Silicon
- Using installation options like
ldflags
andcppflags
without understanding their effect
x86_64 vs arm64 (with and without Rosetta)
Apple Silicon Macs use the arm64
architecture, which is not compatible with the x86_64
architecture that would be used if you enable Rosetta, or run commands with arch -x86_64
, or if you try to install gems or other tools that were built for the x86_64
architecture.
You can’t mix and match architectures. For example, if you install Homebrew while using Rosetta or with arch -x86_64
, it will install things under /usr/local
. However, when installing Homebrew in native mode, it will be installed under /opt/homebrew
.
If you install a Ruby version manager (such as asdf, chruby, frum, rbenv, rvm) and Ruby in native mode (arm64), you can’t install a gem with arch -x86_64
or pass in installation options that point to /usr/local
(x86_64). You either have to do everything in native mode with the arm64
architecture (highly recommended), or do everything with the x86_64
architecture (not recommended).
If you don’t know what you’re doing, installing development tools with and without Rosetta (or with and without arch -x86_64
) can lead to lots of issues, such as “ld: symbol(s) not found for architecture x86_64”. To be sure you have a clean dev environment, I recommend completely removing all dev tools and starting over with a clean slate. At a minimum, remove everything that was installed with Rosetta and in /usr/local
.
Completely cleaning up your dev setup can take up to 60 steps that take 60 minutes to run manually. If you don’t feel like spending an hour or more cleaning things up, or if you’re not sure what all the steps are, you can buy Ruby on Mac, which comes with a “reset” mode that will safely back up your dev setup, then clean everything up in 1 minute. And then you can run it in “normal” mode to reinstall everything from scratch in native mode (arm64).
Using outdated gems that are not compatible with Apple Silicon
Another very common issue people run into on Apple Silicon Macs is not being able to install gems in existing projects that have old versions of gems. For example, if you try to run bundle install
in a Ruby project that has version 0.5.3 of mysql2
listed in the Gemfile.lock
, then it will fail because that version was released before the M1 Macs came out.
Most gems, tools, Mac apps, and other things you can install on a Mac had to be updated to work natively on Apple Silicon Macs. So, if a gem fails to install, the most common reason is because it’s an older version that doesn’t work on Apple Silicon. In most cases, there’s a newer version that does work on Apple Silicon, so the solution is simple: update the gem! For example:
bundle update mysql2
Then run bundle install
again, and if you get other installation failures, keep updating the gems that are failing to install.
Using Ruby installation flags like ldflags and cppflags
Over the past 11 years, I’ve helped hundreds of thousands of people set up a proper Ruby environment on their Mac. One thing I see often is people adding environment variables to their shell startup file, like LDFLAGS
, CPPFLAGS
, or installing gems with --with-ldflags
and --with-cppflags
. They do this blindly without understanding what these options do, and then are surprised when things go wrong.
I can assure you that when you have a proper Ruby dev setup, like the one Ruby on Mac sets up for you, none of these options are necessary in 2023 on any Mac, whether Intel or Apple Silicon.
Setting environment variables like LDFLAGS
and CPPFLAGS
in your shell startup file is especially problematic because it will affect any tool that uses those variables, not just Ruby-related tools. If you know what you’re doing and you know you need to set those flags to a particular value, it should only be done on the command line at the same time as installing a particular tool. They should never be set globally in your shell startup file.