ld: symbol(s) not found for architecture x86_64

Published by Moncef Belyamani on
Updated on

“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 and cppflags 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.

Having said that, even the latest version of mysql2 can either fail to install, or result in “dyld: missing symbol called” when trying to run Rails commands. The reason for these failures depends on one or more of these factors:

  • The version manager you used to install Ruby
  • The version of Ruby you’re using
  • The state of your development environment
  • Whether you’re on an Intel or Apple Silicon Mac
  • If you installed Homebrew using both arm64 and Rosetta on Apple Silicon

That’s why you’ll find tons of different “solutions” to this problem on GitHub and Stack Overflow. You could spend hours trying different solutions before finding one that works. Or you could buy Ruby on Mac Ultimate and be up and running in 15 minutes or less.

I spent 3 days testing 30+ scenarios on 3 different Macs just to find the perfect solution to these mysql2 installation and “dyld: missing symbol called” issues. If you’re currently experiencing these issues, you’ll run Ruby on Mac in reset mode, which will safely back up your dev setup then clean everything up. And then you’ll run it in normal mode to reinstall everything you need from scratch in 15 minutes or less. After that, mysql2 will just work. You won’t have to do anything special.

Using Ruby installation flags like ldflags and cppflags

Over the past 12 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.

In some cases, installing gems with options like --with-ldflags can fix issues, but what you set that option to depends on several factors, as mentioned above. And setting environment variables like LDFLAGS and CPPFLAGS in your shell startup file is especially problematic because it will apply those settings whenever you install 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 because they only apply to a specific scenario. Similarly, using bundle config --global build.mysq2 will tell Bundler to always use those settings whenever installing mysql2, even in situations where it doesn’t apply.

With Ruby on Mac Ultimate, you don’t have to worry about any of this. It automatically uses the best and correct settings for each scenario. Here are some examples of real-world scenarios that require different settings:

  • Using Ruby between 1.9.x and 2.2.x
  • Using Ruby 2.3.x, 2.4.x, or 2.5.x
  • Using Ruby 2.6.x
  • Using Ruby 2.7.x, 3.0.x
  • Using Ruby 3.1 or greater
  • Using Ruby on Apple Silicon with arm64 while also having Homebrew installed with Rosetta