With Apple moving to Apple Silicon for all of their new products, software developers are having to figure out how to support both Intel and Apple Silicon devices. Like some of our customers, you may not be ready to move to Apple Silicon. Unfortunately, that doesn't necessarily exempt you from dealing with universal binaries, especially when it comes to third party dependencies.
One of our customers has recently started to see the following error in their package builds for macOS:
$ install_name_tool -delete_rpath /usr/local/lib <app bundle>/Contents/Python3/dist-packages/scipy/odr/__odrpack.cpython-39-darwin.so
error: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/install_name_tool: no LC_RPATH load command with path: /usr/local/lib found in: <app bundle>/Contents/Python3/dist-packages/scipy/odr/__odrpack.cpython-39-darwin.so (for architecture arm64), required for specified option "-delete_rpath /usr/local/lib"
The customer project packages the SciPy python module and, as part of the packaging step, it uses install_name_tool to strip away any unwanted RPATHs.
If we read the error message closely, we can see that the path /usr/local/lib is not found "for architecture arm64." We don't care about Apple Silicon for this project, so why is this affecting us?
It turns out that SciPy has started distributing universal binaries -- binaries that support both Intel (x86_64) and Apple Silicon (arm64) architectures:
We can't make install_name_tool ignore the missing path for arm64. Instead, we can strip away the unwanted arm64 parts, making install_name_tool happy with our request:
# Rename the original library$ mv<app bundle>/Contents/Python3/dist-packages/scipy/odr/__odrpack.cpython-39-darwin.so <app bundle>/Contents/Python3/dist-packages/scipy/odr/__odrpack.cpython-39-darwin.so.universal
# Extract the x86_64 parts$ lipo -thin x86_64 -output<app bundle>/Contents/Python3/dist-packages/scipy/odr/__odrpack.cpython-39-darwin.so <app bundle>/Contents/Python3/dist-packages/scipy/odr/__odrpack.cpython-39-darwin.so.universal
# Clean up the original$ rm-f<app bundle>/Contents/Python3/dist-packages/scipy/odr/__odrpack.cpython-39-darwin.so.universal
Now we've seen how a new architecture that we don't yet support has affected an existing application. As universal binaries are becoming more pervasive in our dependency chains, we expect to see more of this kind of problem in the future. However, the tooling aims to resolve these kinds of issues. We hope that our simple solution helps anyone else who encounters this kind of issue.
The KDAB Group is a globally recognized provider for software consulting, development and training, specializing in embedded devices and complex cross-platform desktop applications. In addition to being leading experts in Qt, C++ and 3D technologies for over two decades, KDAB provides deep expertise across the stack, including Linux, Rust and modern UI frameworks. With 100+ employees from 20 countries and offices in Sweden, Germany, USA, France and UK, we serve clients around the world.
Nathan Collins
Senior Software Engineer
Nathan Collins is a Senior Software Engineer at KDAB