Library / SDK
tpoechtrager/cctools-port avatar
tpoechtrager/cctools-port

cctools-port: running Apple's ld64 and cctools off macOS

Apple cctools port for Linux and *BSD

815 stars192 forksCLicense varies

At a glance

What is it?
cctools-port builds Apple's cctools and the ld64 Mach-O linker on Linux, the BSDs and macOS, so a machine without Xcode can still produce Apple platform binaries. It is a source port with a long dependency chain, a version-named default branch and a release history that stopped in 2016 while the repository itself kept moving.
Who is it for?
Adopt cctools-port if you need Apple's own Mach-O tooling on a Linux or BSD host, for example to produce Apple platform binaries without a Mac, and you are prepared to build Clang, libdispatch, libTAPI and the port itself from source. Do not adopt it if upstream LLVM tooling is enough for your target, since ld64-specific options and the exact Apple toolchain semantics are what this port is for and what it costs you.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Apple's linker on a machine that is not a Mac

cctools-port is an Apple cctools and ld64 port for Linux, the BSDs and macOS. The current versions named in the README are cctools 1030.6.3 and ld64 956.6, and the work was originally ported by cjacker.

Why anyone wants this is worth spelling out. The tools Apple ships in Xcode are the tools that define what a Mach-O binary produced for an Apple platform looks like. ld64 in particular is the linker, and a linker is not just an interchangeable implementation, because its option set, its diagnostics and its output structure are part of what a build system expects. The README lists specific ld64 options such as -random_uuid and -bitcode_bundle as features that need extra packages to work, which is a hint that this is about reproducing Apple's behaviour rather than just linking Mach-O files.

The supported host operating systems are Linux, FreeBSD, OpenBSD, macOS and iOS, and the supported host architectures are x86, x86_64, arm, arm64/AArch64, and PowerPC/PowerPC64. The inclusion of PowerPC alongside the ARM and x86 targets tells you the port is not tied to Apple's current hardware, and the inclusion of macOS and iOS as hosts means the same source tree can build the tools on the platform they are native to.

The repository layout is small: cctools/ holds the ported sources, tools/ holds the additional tools such as the TAPI and dispatch helpers, package.sh is for packaging, and usage_examples/ contains examples.

Target architectures and the Apple platform matrix

The target list is where this project earns its keep, and it is unusually broad for a link tool port.

The supported target architectures are armv6, armv7, armv7s, arm64, arm64e, arm64_32, i386, x86_64, x86_64h, armv6m, armv7k, armv7m and armv7em, with arm64_32 marked as untested. The set covers the full range of Apple silicon variants including the embedded and microcontroller profiles, and the classic Intel targets. The README also notes that ld64 appears to support riscv32, although its exact use case is unclear, which is an honest way to describe an undocumented capability.

The supported target operating systems are macOS, iOS, tvOS, watchOS, bridgeOS, Mac Catalyst, the iOS Simulator, the watchOS Simulator and DriverKit.

Two caveats sit right next to that list. Not all of the targets have been tested, and arm64_32 is explicitly flagged as untested. For a linker port, untested is a meaningful word, because the failure mode of a linker is a subtly malformed binary rather than a build that refuses to start.

The naming convention for the configuration is visible in the target examples given for the configure step, where the target values look like i386-apple-darwin11, x86_64-apple-darwin11 and arm-apple-darwin11, which is the classic Darwin triple form that the upstream cctools sources expect.

The dependency chain before you can build anything

This is where most of the effort goes, and the README is unusually precise about it.

The base requirement is Clang 10 or later, plus libstdc++ or libc++ with C++20 support depending on what your compiler uses. On top of that come libdispatch-dev and libblocksruntime, and the README links to the maintainer's own apple-libdispatch repository for the runtime.

The conditional requirement is TAPI. SDKs with .tdb stubs, which the README dates to Xcode 7 and later, require the TAPI library to be installed, and the link points to the maintainer's apple-libtapi project. The installation section states that this step is only required if you intend to use SDKs with .tdb stubs, which is a genuinely useful piece of scoping: if you do not need those stubs, you can skip an entire build dependency.

There is a musl-specific requirement too. musl-libc based systems require the musl-fts library, and the README links to the pullmoll project that provides it.

The optional extras are the ones worth reading carefully, because each gates a specific capability. llvm-devel is needed for link time optimisation support, uuid-devel is needed for the ld64 -random_uuid option, and llvm-devel together with xar-devel is needed for -bitcode_bundle support. The xar library itself comes from the maintainer's own xar repository, and the README warns not to install libxar-dev on Ubuntu because it is a different package.

Building it, in two stages

The installation has two stages, and the order matters.

If you need the TAPI library, it is built and installed first:

bash
    git clone https://github.com/tpoechtrager/apple-libtapi.git
    cd apple-libtapi
    [INSTALLPREFIX=/home/user/cctools] ./build.sh
    ./install.sh

Then cctools and ld64 are built on top of it:

bash
    git clone https://github.com/tpoechtrager/cctools-port.git
    cd cctools-port/cctools
    ./configure \
        [--prefix=/home/user/cctools] \
        [--with-libtapi=/home/user/cctools] \
        [--target=<target>] \
        [--with-llvm-config=...]
    make
    make install

The configure options map cleanly onto the dependencies listed above. The prefix says where the tools are installed, --with-libtapi points at the TAPI installation from the first stage, --target selects the Darwin triple such as i386-apple-darwin11, x86_64-apple-darwin11 or arm-apple-darwin11, and --with-llvm-config tells the build where to find the LLVM installation that provides the LTO and bitcode support.

The whole build is autotools style, with the usual configure, make and make install sequence, and it has been run under Travis CI according to the build badge in the README, though that badge points at an old branch name.

A version named default branch and an old release history

The repository's default branch is not master or main. It is named 1030.6.3-ld64-956.6, which is the cctools version and the ld64 version of the code you get by default, and that naming convention is a useful convention to know about when you are working across several versions of this port.

The tagged releases tell a different story about how this project distributes. The most recent one is cctools-877.8-ld64-253.9-1 from 2016-06-25, with two 2015 releases before it. Meanwhile the last push to the repository was on 2026-04-03.

The gap is explainable and worth explaining rather than treating as a warning sign. This is a port of upstream Apple source code, so what changes over time is the upstream version being tracked, and the work is in the patches that make that upstream build on a non-Apple host. The tags in the repository are not tracking that cadence, which means anyone installing from a tag gets a much older snapshot of the upstream sources than the branch head provides.

No licence is recorded for the repository, which is unusual for a project of this size and is worth raising with the maintainer before you build on it, particularly since the upstream sources it carries are Apple's.

Where this port is the wrong tool

Three situations point elsewhere.

The first is when upstream LLVM tooling is enough. If you are producing Mach-O files and your requirements are ordinary linking, then Clang with the LLVM linker plus the GNU binutils equivalents will build on Linux without any of this dependency chain. The difference in approach is that the upstream path gives you a linker that accepts Mach-O but not Apple's exact semantics, while this port gives you ld64 itself with its own option set, its own diagnostics and its own output behaviour. You pay for the fidelity with a source build of Apple's C code and a dependency list that includes libdispatch, libTAPI and possibly musl-fts.

The second is when you need a guarantee rather than a best effort. The README states plainly that not all of the targets have been tested, and arm64_32 is marked untested. A linker that silently produces a subtly wrong binary is a worse failure than a linker that refuses to run, so for a shipping product the untested targets are the ones to check first.

The third is a licensing question that the repository does not answer for you. Apple cctools carries Apple's own licence terms for the upstream portions, and this repository records no licence of its own. Teams that need a clear answer for redistribution have to raise it with the maintainer and read the upstream terms, which is a slower path than picking a tool that documents its terms.

For a hobbyist or a maintainer of an Apple platform toolchain on Linux, all of that is acceptable. For a product, the verification work is the adoption cost.

Editorial conclusion

Adopt cctools-port if you need Apple's own Mach-O tooling on a Linux or BSD host, for example to produce Apple platform binaries without a Mac, and you are prepared to build Clang, libdispatch, libTAPI and the port itself from source. Do not adopt it if upstream LLVM tooling is enough for your target, since ld64-specific options and the exact Apple toolchain semantics are what this port is for and what it costs you. Verify three things first: that the default branch you get matches the cctools and ld64 versions you need, because the default branch is version-named as 1030.6.3-ld64-956.6; whether you actually need the TAPI library, which the README says is only required for SDKs with .tdb stubs; and which optional packages you install, because llvm-devel, uuid-devel and xar-devel each gate a specific ld64 feature. No licence is recorded for the repository, the newest tagged release is from 2016, and the last push was on 2026-04-03.

Frequently asked questions

What does cctools-port provide?

It is a port of Apple's cctools and the ld64 Mach-O linker for Linux, the BSDs and macOS, with current versions of cctools 1030.6.3 and ld64 956.6. It was originally ported by cjacker.

Which host systems and architectures does cctools-port build on?

Supported host operating systems are Linux, FreeBSD, OpenBSD, macOS and iOS, and supported host architectures are x86, x86_64, arm, arm64/AArch64 and PowerPC/PowerPC64.

Do I need Apple's TAPI library to build cctools-port?

Only if you intend to use SDKs with .tdb stubs, which the README dates to Xcode 7 and later. Otherwise you can skip that stage and the --with-libtapi option.

What do the optional packages llvm-devel, uuid-devel and xar-devel enable?

llvm-devel is required for link time optimisation support, uuid-devel for the ld64 -random_uuid option, and llvm-devel together with xar-devel for -bitcode_bundle support. The README also warns not to install libxar-dev on Ubuntu, since it is a different package.

How do I build cctools-port?

Clone the repository, change into cctools-port/cctools and run ./configure with the prefix, --with-libtapi, --target and --with-llvm-config options as needed, then make and make install. The target values use the Darwin triple form, for example i386-apple-darwin11 or x86_64-apple-darwin11.

Official sources

  1. Issues
  2. README
  3. Releases
  4. tpoechtrager/cctools-port on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/tpoechtrager-cctools-port.svg)](https://hysenlabs.com/projects/tpoechtrager-cctools-port)

Was this useful?