Apple's BSD command line tools, built as a single coherent package — the Darwin counterpart to GNU coreutils.
The sources are Apple's own open-source userland (file_cmds, text_cmds,
shell_cmds, system_cmds, diskdev_cmds, network_cmds, …) and the
libraries it links (libutil, libmd, libtelnet, …), carried as submodules
under src/ that track apple-oss-distributions directly. What this project
adds is a build system: Apple ships these as a scattering of Xcode projects
that expect the internal SDK, and apple-core replaces that with one bmake
tree that builds against the public SDK on a stock macOS install.
A handful of tools missing from Apple's set are vendored from FreeBSD in
src/bsd_additions/ (factor, indent, ee, timeout).
Requires Xcode (or the Command Line Tools) and bmake.
git clone --recurse-submodules https://github.com/xnuports/apple-core.git
cd apple-core && bmake && bmake checkEverything lands in build/release/, laid out as the root of a stock macOS
install — bin, sbin, usr/bin, usr/sbin, usr/libexec, usr/lib —
with each file where macOS keeps its own copy. There is no install target:
the release tree is the product.
Useful targets:
bmake # libraries, then ports (if enabled), then programs
bmake check # every inventory entry produced its files; nothing stale
bmake list-progs # the program inventory with install locations
bmake list-libs # the library inventory
bmake list-ports # the port inventory
bmake clean # remove build/, keeping the ports work directories
bmake clean-ports # remove the ports work directories
bmake distclean # remove build/ entirelyRun bmake check after any build you care about. One entry failing does not
stop the rest, so without it a broken tool simply goes missing from the
release tree.
The default build is the strict coreutils-like set. Four groups are gated off, each enabled independently:
bmake MK_DIAGNOSTICS=yes # fs_usage, latency, zprint, vm_stat, gcore, …
bmake MK_DAEMONS=yes # telnetd, tftpd, rtadvd, getty, …
bmake MK_PRIVATE_FRAMEWORKS=yes # tools needing FSKit/APFS/kextmanager
bmake MK_PORTS=yes # zsh, tcsh, uucp, lsof, xar, pcre: their own build systemskext_tools and autofs are not part of this tree; they are OS components and live in the LibreDarwin OS repository.
The default set builds clean: all 253 programs and all 20
libraries, eight of them also installed as dylibs under Apple's names
(libutil, libz, libbz2, libmd, libtidy, libipsec, and
libcopyfile and libremovefile in usr/lib/system). With MK_PORTS=yes,
zsh (with its pcre module), tcsh (with csh), uucp, lsof,
xar, pcre and ncurses (clear, infocmp, tic, toe, tput,
tset, linked against the system's libncurses.5.4 as stock macOS's are)
build through their own build systems too. No entry is left unbuilt.
Where no header is published at all, what the build needs is recovered from
Apple's shipped binaries and says so where it lives: the quarantine SPI;
libxpc's pipe, entitlement and os_transaction SPI (xpc/private.h,
os/transaction_private.h); Network's network/conninfo.h; APFS's
purgeable-file ioctl; the log-pack types; PowerManagement's libIOReport,
LockdownMode, SkyLight, MobileGestalt, Apple vendor HID usages and the
newer power-source types IOKitUser-100231.120.3 predates;
KernelManagementClient; and the ifconfig netem models. Apple open source
supplies the rest where it exists: IOKitUser-100231.120.3's power headers,
configd-1405.120.5's SystemConfiguration private headers,
libdispatch-1542.0.4's private headers, and xnu's corecrypto, IOReport and
hibernation headers.
The diagnostics, daemons and private-frameworks tiers add 41 entries, and
all of them build too: the diagnostics (fs_usage, gcore, latency,
lsmp, stackshot, zlog, …), the daemons, and PowerManagement's pmset
and ioupsd. What they need beyond the public SDK comes from
xnu, libmalloc and dyld where Apple publish it, and is recovered from the
shipped binaries where they do not (ktrace session SPI, Background Task
Management, CoreSymbolication, process responsibility, the os_log hook,
task_read_for_pid()). vm_stat joined them with system_cmds-1042.120.1,
which reads memory-tagging counters from a newer struct vm_statistics64 than
the SDK declares.
A few build with caveats rather than as exact ports, each documented in its
own mk/tool.d/<tool>.mk: timeout cannot follow descendants past its direct
child (Darwin has no subreaper API), the FSKit-backed tools report FSKit as
unavailable — Apple's own fallback for that case, ifconfig's two newer
netem model values are recovered from the shipped binary rather than any
published header, and tiffutil -info differs cosmetically from the stock
binary's because we link the installed libtiff rather than a patched one
(-dump is byte-identical). libutil carries FreeBSD's login_cap/getcap
and sbuf families, which Apple's does not; su, login, newgrp, getty
and atrun need them. libz is plain zlib, without Apple's vectorised
AddOn, which the drop does not wire up to the files that use it.
ioupsd carries a patch declaring needsMerge, which the published
upsd.m tests but never declares: stock ioupsd sets it only when an
"Inductive In-Band" battery case reuses an already-registered record, so
merging those cases is left undone and every other device behaves as stock.
rtadvd's sources are gone from network_cmds-741.100.2, which
keeps only its run-rtadvd script while macOS still ships the daemon;
mk/patches/rtadvd restores them verbatim from network_cmds-705.100.5.
telnetd builds Apple's eight-file target, leaving out authenc.c, which
the target never compiled and which does not compile. talkd installs as
/usr/libexec/ntalkd, the name and place stock macOS gives it.
fs_usage, latency, sc_usage and zprint link libutil statically
where stock links libutil.dylib.
bmake, with two engines driven by flat inventories — the same architecture
as the sibling xcode-tools project:
mk/tool.mk |
compiles a program or a library from sources; driven by mk/progs.mk and mk/libs.mk |
mk/port.mk |
drives a component's own build system (autoconf, CMake, make); driven by mk/ports.mk |
mk/tool.d/, mk/port.d/ |
per-entry flags |
mk/with-*.mk |
reusable link bundles |
mk/patches/<name>/ |
patches to an entry's sources |
mk/scripts/pbxinfo.py |
prints an Apple target's sources and settings from its .xcodeproj |
Adding a tool is one line in mk/progs.mk, plus a mk/tool.d/<tool>.mk only
if it needs flags — sources are discovered automatically.
Submodules are never written to. Every Makefile lives outside them and
reaches in read-only. A source that has to change does so through a patch in
mk/patches/<name>/, written against the submodule root (as git format-patch in the submodule produces it) and applied to a private copy
under build/src/ or build/ports/.
Libraries always produce build/lib/<name>.a, which is what the programs
link, so the release tree runs in place. Those Apple ships as dylibs are also
linked into build/release/usr/lib, under Apple's install names.
| Path | |
|---|---|
src/ |
tool and library sources (submodules) |
lib/ |
libxo, and the driver for mk/libs.mk |
ports/ |
the driver for mk/ports.mk |
include/ |
private headers vendored where the SDK ships none |
frameworks/ |
private framework headers, reached with -F |
mk/ |
the build system |
docs/ |
progress notes and the submodule audit |
tools/ |
helper scripts |
Apple's sources are APSL-2.0 and BSD; the FreeBSD additions are BSD; a few
files are MIT. LICENSE collects the full texts, with per-license copies in
LICENSE.APSL-2.0, LICENSE.BSD-2, LICENSE.BSD-3 and LICENSE.MIT.
Submodules under src/ and lib/ keep their own upstream licences.