Home / Alt manpages / llvm-lipo-20(1)

  • llvm-lipo-20(1)
  • User command
  • linux

Build and Check a Universal Mach-O with llvm-lipo-20

You will combine thin x86_64 and arm64 Mach-O files into one universal file, inspect the architectures it contains, and extract a thin file again. The examples use llvm-lipo-20 from Debian package llvm-20, version 20.1.8, installed on this machine. Allow about fifteen minutes if you already have the two input files. The commands only write files in the named output paths; none needs elevated privileges.

1. Check the installed tool

Start by confirming that the command on your PATH is the one you intend to use:

$ command -v llvm-lipo-20
/usr/bin/llvm-lipo-20
$ llvm-lipo-20 -version
llvm-lipo
Ubuntu LLVM version 20.1.8
  Optimized build.

llvm-lipo handles Mach-O files. It can describe thin and universal files, verify architectures, create a universal file, make a thin output from a universal input, and replace one architecture slice. It does not compile source code or link an executable.

Checkpoint: confirm that your inputs are Mach-O files for architectures you actually intend to distribute. An ELF object from a normal Linux build is not a substitute.

2. Inspect the thin inputs first

Use -info with one or more input files. Put the file names before the operation options. The following names are placeholders:

$ llvm-lipo-20 /path/to/program-x86_64.o /path/to/program-arm64.o -info
Non-fat file: /path/to/program-x86_64.o is architecture: x86_64
Non-fat file: /path/to/program-arm64.o is architecture: arm64

The exact spacing and path text can vary, but each input should be reported as a non-fat file with the expected architecture. For a script or a compact check, -archs prints the architecture names separated by whitespace:

$ llvm-lipo-20 /path/to/program-x86_64.o -archs
x86_64

Do not continue if an input is reported as the wrong architecture. Rebuild it for the intended target and inspect it again. This avoids producing a valid universal container whose slices do not match their labels.

3. Create the universal file

Pass at least one input to -create and provide a separate output path with -output. Two different architectures are the useful case:

$ llvm-lipo-20 \
    /path/to/program-x86_64.o \
    /path/to/program-arm64.o \
    -create \
    -output /path/to/program-universal.o

A successful command normally prints nothing. The output path is created or replaced, so treat it as a state-changing step even though it does not require sudo. Do not point it at an input you need to preserve.

Verify the result immediately:

$ llvm-lipo-20 /path/to/program-universal.o -info
Architectures in the fat file: /path/to/program-universal.o are: x86_64 arm64
$ llvm-lipo-20 /path/to/program-universal.o -archs
x86_64 arm64

Universal Mach-O files are also called fat files in the tool's diagnostics. That wording does not mean the file contains source code or two complete application installations; it contains architecture-specific Mach-O slices.

4. Check an architecture without parsing output

-verify_arch exits with status 0 when every architecture named in the check is present, and status 1 otherwise. Put the input file before the option:

$ llvm-lipo-20 /path/to/program-universal.o -verify_arch x86_64 arm64
$ printf 'status=%s\n' "$?"
status=0
$ llvm-lipo-20 /path/to/program-universal.o -verify_arch arm64 ppc
$ printf 'status=%s\n' "$?"
status=1

Use the exit status in build or packaging automation rather than grepping the human-readable -info text. With set -e, a deliberate negative test will stop the shell, so capture or branch on the status when failure is expected.

5. Extract a thin slice safely

When a downstream tool needs one architecture, -thin writes a new thin file. It requires a universal input and an output path:

$ llvm-lipo-20 \
    /path/to/program-universal.o \
    -thin arm64 \
    -output /path/to/program-arm64-thin.o
$ llvm-lipo-20 /path/to/program-arm64-thin.o -info
Non-fat file: /path/to/program-arm64-thin.o is architecture: arm64

This does not remove the arm64 slice from the original. It creates a separate file. Keep the original until the extracted file has passed the consumer's checks.

6. Replace a slice only with a verified input

-replace takes an architecture, a thin input file, and a universal input, then writes another universal output. Verify the replacement file before using it:

$ llvm-lipo-20 /path/to/program-arm64-new.o -verify_arch arm64
$ llvm-lipo-20 \
    /path/to/program-universal.o \
    -replace arm64 /path/to/program-arm64-new.o \
    -output /path/to/program-universal-new.o
$ llvm-lipo-20 /path/to/program-universal-new.o -verify_arch x86_64 arm64

Do not replace in place while diagnosing a build. A mistaken architecture, stale object, or incompatible ABI can make the output unusable, and llvm-lipo-20 cannot restore the previous file. Write a new name, compare or test it, then promote it with your normal atomic deployment procedure. If you did overwrite a file accidentally, restore it from the build artefact or backup; there is no undo option in llvm-lipo-20.

7. Use segment alignment only when required

-segalign applies to -create and -replace. Its value is hexadecimal and must be a non-zero power of two. In this installed version, write the hexadecimal digits without a 0x prefix:

$ llvm-lipo-20 \
    /path/to/program-x86_64.o \
    /path/to/program-arm64.o \
    -create \
    -segalign x86_64 1000 \
    -output /path/to/program-aligned.o

Here 1000 means hexadecimal 0x1000. Do not add alignment speculatively. Use the value required by the consumer or by the object-producing tool, then inspect and test the resulting file. A value such as 3 is rejected because it is not a power of two.

Common failure traps

  • Options before inputs: the installed command's usage is input files followed by options. If it says that no input file was specified, move the file names before -info, -archs or -verify_arch.
  • Missing output: -create, -thin and -replace require -output. Choose a new path while testing.
  • Wrong file kind: llvm-lipo-20 is for Mach-O. Check the producer and target instead of trying to force an ELF file into a universal file.
  • Assuming success proves compatibility: an architecture list proves container structure, not that the slices link, load, or behave correctly. Run the relevant linker, loader and application tests afterwards.

Done means

  • The installed command reports LLVM 20.1.8 and the expected binary path.
  • Each thin input reports the intended Mach-O architecture.
  • The universal output reports every required architecture with -info or -archs.
  • Automation uses -verify_arch exit status rather than parsing display text.
  • Thin extraction and slice replacement write new paths until the result is tested.
  • Any segment alignment was required, hexadecimal, and a non-zero power of two.