Creating a single universal shared lib or executable file for macOS Intel and Silicon using lipo


As macOS developers, creating universal binaries and shared libraries that work seamlessly across both Intel (x86_64
) and Apple Silicon (arm64
) architectures is critical. Whether you’re building standalone executables or .so` shared libraries, combining architecture-specific builds into a single universal file simplifies distribution and ensures compatibility.
This post will guide you through the process of using lipo
to create universal shared libraries and binaries.
What Are Shared Libraries?
Shared libraries (.so
, .dylib
) are reusable collections of code that multiple programs can use. On macOS, they are often used to encapsulate functionality like graphics processing, data manipulation, or custom algorithms.
Advantages:
Code re-usability across applications.
Reduced memory usage since multiple applications can share a single copy of the library.
Challenges:
- Need to ensure compatibility across different system architectures.
What Are Universal Binaries?
Universal binaries are executables or shared libraries containing code for multiple architectures. On macOS, this means supporting both Intel and Apple Silicon architectures in a single file. Example: A universal .so
or .dylib
file can run natively on any Mac, regardless of its CPU architecture.
Creating a sample executable targeting different architectures
Let us create a simple hello world program named hello_world.c
and compile it for different architectures.
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0;
}
Compile the above program to target Intel x86_64
as below:
clang -arch x86_64 -o hello_world_intel hello_world.c
If you verify the file by running file hello_world_intel
, you see the output as hello_world_intel: Mach-O 64-bit executable x86_64
.
Next compile the above program to target Silicon arm64
as below:
clang -arch arm64 -o hello_world_arm64 hello_world.c
If you verify the file by running file hello_world_
arm64, you see the output as hello_world_arm64: Mach-O 64-bit executable arm64 .
Creating universal shared library/executable using lipo
Run the below command to create universal shared library which can be used in both Intel and Silicon machines.
lipo -create hello_world_intel hello_world_arm64 -output hello_world
Let us now verify the universal binary:
file hello_world
If you inspect the file using lipo -info hello_world
, you will see the output as below:
Architectures in the fat file: hello_world are: x86_64 arm64
In summary, this setup allows you to create a single, combined binary that can run on both Intel and Apple Silicon Macs!
Subscribe to my newsletter
Read articles from Babu Annamalai directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Babu Annamalai
Babu Annamalai
Hey 👋 I am Babu Annamalai, partner and co-founder at Radarleaf Technologies. A polyglot software developer based in Bengaluru, love to work with web technologies and OSS . I am a lifetime learner in exploration mode. I spend a plenty of time working on the following OSS projects as below: Co-maintainer of Marten. I am available in the project's gitter channel to help with any queries/questions on Marten. This is the most successful and active project in terms of user base. Creator and maintainer of ReverseMarkdown.NET, MysticMind.PostgresEmbed and .NET Sort Refs I also contribute to other OSS projects as well.