Skip to content

Minimal but open SDK for developing small command line tools.

Notifications You must be signed in to change notification settings

tinygo-org/macos-minimal-sdk

Repository files navigation

Minimal SDK for macOS

CI results

This repository provides the basis to build a cross compiler for macOS. With it, you can compile small command line tools from any operating system to macOS.

Features:

Example

Say you have a hello world C file, named hello.c:

#include <stdio.h>

int main(void) {
    printf("Hello world!\n");
    return 0;
}

You can then build it on any host with Clang 13+ installed like this (using clang-13 here as an example):

$ clang-13 --target=x86_64-apple-macos10.12 --sysroot=sysroot-macos-x86_64 -fuse-ld=lld -o hello hello.c
$ file hello
hello: Mach-O 64-bit x86_64 executable, flags:<NOUNDEFS|DYLDLINK|TWOLEVEL|PIE>

It can also compile to ARM64 (aka "Apple Silicon"):

$ clang-13 --target=arm64-apple-macos11 --sysroot=sysroot-macos-arm64 -fuse-ld=lld -o hello hello.c
$ file hello
hello: Mach-O 64-bit arm64 executable, flags:<NOUNDEFS|DYLDLINK|TWOLEVEL|PIE>

Note that Clang 13 or higher is required, as older versions do not have a usable MachO linker.

Building

Simply run:

make

This builds both the x86_64 and the arm64 sysroots and should therefore cover most Macs.

How it works

A libc comes in two parts: a set of header files and a binary libc that the linker will link against. Normally, you'd use the header files and a binary libc from your operating system. That of course won't work here: we will need to cross compile. Cross compiling usually means that you have to copy the important files (the header files and the libc) into a directory that you can then point your compiler and linker to. This is called a sysroot.

This is unfortunately not easily possible on macOS: while the header files are open source, the binary libc (called libSystem.B.dylib) probably is not.

The way this minimal SDK works around this is by first creating the header files from the individual libc components (downloaded from opensource.apple.com) and then constructing a fake libSystem.B.dylib that only contains a list of function names without an implementation. You can't use this libSystem.B.dylib to run an actual binary, but you can use it to link binaries against.

Why would you do this?

It may be useful when you develop software on Linux or Windows but want to build it for MacOS. One example might be CI: Linux is currently still more widely available (and usually cheaper!) than MacOS VMs.

Updating

To update the header files to a newer version, follow these steps.

  1. Update the version numbers in versions.inc.
  2. Run ./update.sh. This downloads the new headers. You may need to fix build breakage especially when moving to a newer macOS version.
  3. Run make to build the new sysroots. This should be very quick.

This is only rarely needed: macOS binaries will usually run just fine on a newer version of the OS.

License

This project is licensed under APSL 2.0, a variety of BSD style licenses, and public domain code:

  • src/usr/include is extracted from the Libc, xnu, libpthread, Libm, and CarbonHeaders. The source files are under a mix of the APSL 2.0 and a variety of BSD-style licenses. There are a few files that just say "all rights reserved". All those files have been replaced with a public domain version so they are also in effect open source.
  • src/*/libSystem.s is extracted from the above, but because it's only a list of function names I don't believe it is covered by copyright and therefore can be considered public domain. If it is covered by copyright (I'm not a lawyer), it is covered by the same copyright as src/usr/include above.
  • Other files like the various update scripts are placed in the public domain.

In other words, as far as I can see, this means that the resulting code can be freely shared and linked against.

More information