Install layout spike — per-component paths across four layouts

For every component we plan to port, here are all the installed files (executables, libraries, headers, plists, configs, man pages, bundles) across four candidate layouts: Apple's actual macOS paths, an Apple-like /usr/lib/system/ layout on FreeBSD, gershwin's /System/Library/ layout, and a FreeBSD-base-style /usr/lib layout. Companion to the libdispatch Mach spike's install-path discussion and the Foundation spike.

Contents

  1. Four layouts explained
  2. mach.ko
  3. libmach
  4. libdispatch
  5. libxpc
  6. liblaunch
  7. launchd (daemon + launchctl)
  8. asl (syslogd + aslmanager + libasl + syslog)
  9. notifyd + libnotify + notifyutil
  10. configd + scutil + SystemConfiguration framework + libSystemConfiguration + plugins
  11. CoreFoundation (swift-corelibs-foundation, non-Swift mode)
  12. mDNSResponder
  13. IPConfiguration (ipconfig + bootpd)
  14. DiskArbitration (framework + daemon + agent)
  15. Block.h / libBlocksRuntime
  16. GNUstep stack (libobjc2 + libgnustep-base)
  17. Cross-cutting concerns
  18. Recommendation

1. Four layouts explained

LayoutStatusWhat it means
Apple macOS reference Where Apple actually puts these on macOS. Note: since Big Sur most system .dylib files are not files on disk — they're entries in /System/Library/dyld/dyld_shared_cache_*. Paths shown are logical (what dlopen() resolves to) even when no physical file exists.
/usr/lib/system/ new option Apple-like layout on FreeBSD — mimics Apple's /usr/lib/system/ convention from pre-Big-Sur macOS. Each Libsystem sub-library lands as libsystem_<name>.so. Headers at the standard /usr/include/. Pitch: makes the Apple-source userland feel more Apple-shape without requiring the gershwin /System/Library/ hierarchy. Good fit for dispatch + xpc + kernel + notify + asl — the components Apple specifically calls "libsystem_*" on macOS.
Gershwin /System/Library/ project precedent What gershwin-developer's Install-System-Domain.sh and freebsd-launchd's build.sh use today. Libraries at /System/Library/Libraries/, headers at /System/Library/Headers/, frameworks preserved as bundles at /System/Library/Frameworks/. Visual separation of Apple-source-as-system-services.
FreeBSD base /usr/lib aspirational Where these would live if shipped through pkgbase. Standard /usr/lib, /usr/include, etc. Flat: no framework bundles, no /System hierarchy. Mixes with FreeBSD base.

Apple-Unix paths (/sbin, /usr/sbin, /usr/libexec, /usr/bin, /etc) are universal across all four layouts — daemons, CLIs, and config files don't change paths based on whether the library convention is gershwin or base. Only libraries, headers, and framework bundles differ.

2. mach.ko

mach.ko — kernel module

Decided Use the FreeBSD base location. mach.ko is a kernel module — the gershwin / /usr/lib/system/ debate is about userland library placement and doesn't apply here.

ArtifactApple macOS (reference)FreeBSD base (chosen)
Kernel modulen/a — Mach is part of XNU kernel proper, not loadable/boot/kernel/mach.ko
loader.conf entryn/a/boot/loader.conf: mach_load="YES"
Module debug symbolsn/a/usr/lib/debug/boot/kernel/mach.ko.debug (when built debug)

3. libmach

libmach — userland syscall shim (our Phase C1 library)

Decided Use /usr/lib/system/ with Apple-canonical libsystem_kernel naming. Coherent with libdispatch and libxpc which all live alongside as the canonical Apple Libsystem trio.

ArtifactApple macOS (reference)/usr/lib/system/ (chosen)
Shared library/usr/lib/system/libsystem_kernel.dylib (shared cache; logical)/usr/lib/system/libsystem_kernel.so
Versioned symlinkn/a (cache)/usr/lib/system/libsystem_kernel.so.0
Headers/usr/include/mach/*.h (SDK)/usr/include/mach/*.h
pkg-confign/a/usr/libdata/pkgconfig/libsystem_kernel.pc

4. libdispatch

libdispatch — concurrency primitives (swift-corelibs-libdispatch + Mach backend patch)

Decided Use /usr/lib/system/ with Apple-canonical libsystem_dispatch naming. Matches Apple's pre-Big-Sur convention exactly — libsystem_dispatch is literally what the file is named on macOS, and Apple-aware tooling (DTrace probes, debuggers) that searches for libsystem_* finds this immediately.

ArtifactApple macOS (reference)/usr/lib/system/ (chosen)
Shared library/usr/lib/system/libsystem_dispatch.dylib (cache)/usr/lib/system/libsystem_dispatch.so
Versioned symlinkn/a/usr/lib/system/libsystem_dispatch.so.0
Headers/usr/include/dispatch/*.h/usr/include/dispatch/*.h
os/ headers/usr/include/os/*.h/usr/include/os/*.h
Man pages/usr/share/man/man3/dispatch_*.3/usr/share/man/man3/dispatch_*.3

5. libxpc

libxpc — high-level IPC (this plan's primary deliverable)

Decided Use /usr/lib/system/ with Apple-canonical libsystem_xpc naming. Same reasoning as libdispatch — libsystem_xpc is the Apple-canonical name, coherent grouping with libdispatch and libmach as the Libsystem trio.

ArtifactApple macOS (reference)/usr/lib/system/ (chosen)
Shared library/usr/lib/system/libsystem_xpc.dylib (cache)/usr/lib/system/libsystem_xpc.so
Versioned symlinkn/a/usr/lib/system/libsystem_xpc.so.0
Headers (umbrella)/usr/include/xpc/xpc.h/usr/include/xpc/xpc.h
Headers (full set)xpc/{base,connection,activity,endpoint,debug,launchd}.h at /usr/include/xpc/
Bootstrap server binarybuilt into launchd/usr/libexec/bootstrap_server if standalone (Phase 3 option) or absorbed into /sbin/launchd (Phase 5 option)

6. liblaunch

liblaunch — launch_data_t client library

Decided Use /usr/lib/system/ with Apple-canonical libsystem_launch naming. Fourth member of the Apple Libsystem family alongside libmach, libdispatch, and libxpc — same coherence argument applies.

ArtifactApple macOS (reference)/usr/lib/system/ (chosen)
Shared library/usr/lib/system/libsystem_launch.dylib (cache)/usr/lib/system/libsystem_launch.so
launch.h/usr/include/launch.h/usr/include/launch.h
vproc.h / bootstrap.h / launch_priv.hsame dir as launch.h/usr/include/

7. launchd (daemon + launchctl)

launchd, launchctl — init system

Decided Use FreeBSD base paths. launchd is PID 1 and launchctl is its CLI — system services that belong on Apple-Unix paths regardless of where userland libraries live.

ArtifactApple macOS (reference)FreeBSD base (chosen)
launchd daemon (PID 1)/sbin/launchd/sbin/launchd
launchctl CLI/bin/launchctl/bin/launchctl (freebsd-launchd current ships at /sbin/launchctl; migrate to /bin/ to match Apple)
Man pages/usr/share/man/man{1,5,8}/launch{d,ctl}.*same path
System daemon plists (Apple's)/System/Library/LaunchDaemons/com.apple.*.plistsame path (+ org.freebsd.* for ours)
System per-user agent plists/System/Library/LaunchAgents/*.plistsame path
Third-party daemon plists/Library/LaunchDaemons/*.plist (Apple) / /Local/Library/LaunchDaemons/*.plist (our project policy)/Local/Library/LaunchDaemons/*.plist — this project does NOT use Apple's /Library; /Local/Library is the universal third-party prefix
Third-party agent plists/Library/LaunchAgents/*.plist (Apple) / /Local/Library/LaunchAgents/*.plist (our project policy)/Local/Library/LaunchAgents/*.plist
Per-user agent plists~/Library/LaunchAgents/*.plistsame path
launchd state directory/var/db/launchd.db/same path
Bootstrap socket / portMach bootstrap portMach bootstrap port (via libmach)

8. asl (syslogd + aslmanager + libasl + syslog)

Apple System Logger family

Decided Use FreeBSD base paths. Daemons + CLIs at Apple-Unix paths, libasl as flat /usr/lib/libasl.so, headers at /usr/include/.

ArtifactApple macOS (reference)FreeBSD base (chosen)
syslogd daemon (replaces FreeBSD's)/usr/sbin/syslogd/usr/sbin/syslogd — replaces FreeBSD's native syslogd
aslmanager (log rotation)/usr/sbin/aslmanager/usr/sbin/aslmanager
syslog CLI/usr/bin/syslog/usr/bin/syslog
libasl.so (client library)/usr/lib/system/libsystem_asl.dylib (cache)/usr/lib/libasl.so
asl.h header/usr/include/asl.h/usr/include/asl.h
asl.conf/etc/asl.confsame path
asl per-module configs/etc/asl/*.confsame path
asl log storage/var/log/asl/same path
system.log/var/log/system.logsame path (replaces FreeBSD's /var/log/messages)
syslogd launchd plist/System/Library/LaunchDaemons/com.apple.syslogd.plist/System/Library/LaunchDaemons/org.freebsd.syslogd.plist
aslmanager plist/System/Library/LaunchDaemons/com.apple.aslmanager.plistorg.freebsd.aslmanager.plist
Man pages/usr/share/man/man{1,3,5,8}/{asl,syslog,syslogd,aslmanager,notify}.*same path

9. notifyd + libnotify + notifyutil

Notification daemon family

Decided Use FreeBSD base paths. Daemon + CLI at Apple-Unix paths, libnotify as flat /usr/lib/libnotify.so, headers at /usr/include/.

ArtifactApple macOS (reference)FreeBSD base (chosen)
notifyd daemon/usr/sbin/notifyd/usr/sbin/notifyd
notifyutil CLI/usr/bin/notifyutil/usr/bin/notifyutil
libnotify.so/usr/lib/system/libsystem_notify.dylib (cache)/usr/lib/libnotify.so
notify.h header/usr/include/notify.h/usr/include/notify.h
notify_keys.h header/usr/include/notify_keys.hsame path
notify.conf/etc/notify.confsame path
notifyd launchd plist/System/Library/LaunchDaemons/com.apple.notifyd.plist/System/Library/LaunchDaemons/org.freebsd.notifyd.plist
Man pages/usr/share/man/man{1,3,8}/{notify,notifyd,notifyutil}.*same path

10. configd + scutil + SystemConfiguration.framework + libSystemConfiguration + plugins

configd family

Decided Use FreeBSD base paths — flat layout, no framework bundle. SystemConfiguration ships as a flat library + headers + flat plugin .so files. Source-level macOS imports that use -framework SystemConfiguration need link-line and include-path rewrites; trade-off is a much simpler install layout consistent with the rest of FreeBSD base.

ArtifactApple macOS (reference)FreeBSD base (chosen)
configd daemon/usr/libexec/configd/usr/libexec/configd
scutil CLI/usr/sbin/scutil/usr/sbin/scutil
scselect (legacy)/usr/sbin/scselect/usr/sbin/scselect
SystemConfiguration (framework on macOS, flat on FreeBSD)/System/Library/Frameworks/SystemConfiguration.framework/flat: /usr/lib/libSystemConfiguration.so + /usr/include/SystemConfiguration/*.h
libSystemConfiguration.so (client helper for the XPC bridge)inside framework or /usr/lib/libSystemConfiguration.dylib/usr/lib/libSystemConfiguration.so
configd plugin bundles (IPMonitor, KernelEventMonitor, PreferencesMonitor, LinkConfiguration)/System/Library/SystemConfiguration/*.bundle/flat: /usr/libexec/configd-plugins/*.so
SC preferences directory/Library/Preferences/SystemConfiguration/ (Apple) / /Local/Library/Preferences/SystemConfiguration/ (our project policy)/Local/Library/Preferences/SystemConfiguration/ — our project does NOT use Apple's /Library; /Local/Library is universal
Default preferences plists (read-only)/System/Library/SystemConfiguration/*.plist/usr/share/SystemConfiguration/*.plist
configd launchd plist/System/Library/LaunchDaemons/com.apple.configd.plist/System/Library/LaunchDaemons/org.freebsd.configd.plist
scutil man page/usr/share/man/man8/scutil.8same path

11. CoreFoundation (swift-corelibs-foundation, non-Swift mode)

CF on this ISO

Decided Use swift-corelibs-foundation's pure-C CoreFoundation as the CF engine for every system service on this ISO. Built with DEPLOYMENT_RUNTIME_SWIFT=0 to avoid pulling the Swift runtime onto every CF-using binary. The earlier "libCFRuntime + libgnustep-corebase hybrid" plan from freebsd-libxpc-foundation-spike is superseded — the current authoritative source is freebsd-launchctl-corefoundation-spike, which audited the three candidate CF implementations against actual launchctl.c usage and found that swift-corelibs CF is the only viable choice (libgnustep-corebase's plist parser is stubbed; libgnustep-base has zero CF C surface).

ArtifactApple macOS (reference)Apple-like FreeBSD (chosen)
libCoreFoundation.so (swift-corelibs CF, non-Swift mode)/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation/usr/lib/system/libCoreFoundation.so.6 — same Apple-libsystem lane as libdispatch / libxpc / liblaunch / libsystem_kernel / libBlocksRuntime
CoreFoundation public headersinside framework bundle/usr/include/CoreFoundation/{CoreFoundation,CFArray,CFDictionary,CFPropertyList,…}.h
CoreFoundation SPI headers (CFPriv.h, CFLogUtilities.h, CFBundlePriv.h, CFURLPriv.h, *_Private.h)inside framework bundle/usr/include/CoreFoundation/ — same dir as public; system services that need SPI surface get it transparently
Build depsn/alibdispatch, libBlocksRuntime (already in /usr/lib/system/); ICU (new dep, added via FreeBSD pkg)
SOVERSIONvaries6 (matches Apple's CoreFoundation.framework version 6)

What this is not:

12. mDNSResponder

mDNSResponder — multicast DNS / Bonjour daemon

Decided Use Apple-like FreeBSD paths — matches Apple's macOS layout exactly for daemons, helper, CLI, library, header, and plist. libdns_sd is not one of Apple's libsystem_* libraries on macOS, so it stays plain libdns_sd.so — no prefix added. Replaces FreeBSD's mdnsd (or coexists).

ArtifactApple macOS (reference)Apple-like FreeBSD (chosen)
mDNSResponder daemon/usr/sbin/mDNSResponder/usr/sbin/mDNSResponder
mDNSResponderHelper (privileged helper)/usr/sbin/mDNSResponderHelper/usr/sbin/mDNSResponderHelper
dns-sd CLI/usr/bin/dns-sd/usr/bin/dns-sd
libdns_sd.so (client library)/usr/lib/libdns_sd.dylib/usr/lib/libdns_sd.so
dns_sd.h header/usr/include/dns_sd.h/usr/include/dns_sd.h
mDNSResponder launchd plist/System/Library/LaunchDaemons/com.apple.mDNSResponder.plistsame path; rename to org.freebsd.mDNSResponder.plist if shipping our own variant rather than importing Apple's verbatim
nss_mdns config integrationvia configdvia configd or /etc/nsswitch.conf

13. IPConfiguration (ipconfig + bootpd)

IPConfiguration daemon family (Apple's bootp tarball)

Decided Hybrid layout. Daemons, helper, CLIs, configs, state: Apple-like FreeBSD — Apple-Unix paths exactly (/usr/libexec/IPConfiguration, /usr/sbin/ipconfig, etc.). IPConfiguration.framework: gershwin layout — preserves the .framework bundle at /System/Library/PrivateFrameworks/ so Apple-source code that does -framework IPConfiguration compiles unchanged. Replaces FreeBSD's rtadvd (or coexists).

ArtifactApple macOS (reference)Chosen
IPConfiguration daemonbuilt into configd as a plugin (modern) or /usr/libexec/IPConfiguration (historical)/usr/libexec/IPConfiguration
IPConfigurationHelper (XPC PvD-HTTPS helper)/usr/libexec/IPConfigurationHelper/usr/libexec/IPConfigurationHelper
ipconfig CLI/usr/sbin/ipconfig/usr/sbin/ipconfig
IPConfiguration framework (gershwin layout)/System/Library/PrivateFrameworks/IPConfiguration.framework//System/Library/PrivateFrameworks/IPConfiguration.framework/ — preserve bundle
bootpd (DHCP/BOOTP server, Apple's; replaces CMU bootpd)/usr/libexec/bootpd/usr/libexec/bootpd
bsdpc (NetBoot client)/usr/libexec/bsdpc/usr/libexec/bsdpc
dhcp6d (DHCPv6 server)/usr/libexec/dhcp6d/usr/libexec/dhcp6d
rtadvd (Apple's, separate from FreeBSD's)/usr/sbin/rtadvd/usr/sbin/rtadvd — replaces FreeBSD's native rtadvd
Configs/etc/bootpd.plist, /etc/bootptab, /etc/rtadvd.conf
State / lease files/var/db/dhcpclient/, /var/db/bootpd/

14. DiskArbitration (framework + daemon + agent)

DiskArbitration family

Decided Hybrid layout, same shape as IPConfiguration. Daemon, per-user agent, plists, configs: Apple-like FreeBSD — Apple-Unix paths; .app bundle for the agent goes to /System/Applications/ per project convention for system-shipped apps. DiskArbitration.framework + DA headers: gershwin layout — preserves the .framework bundle at /System/Library/Frameworks/ with headers inside it, so Apple-source code compiles unchanged with -framework DiskArbitration.

ArtifactApple macOS (reference)Chosen
diskarbitrationd daemon/usr/libexec/diskarbitrationd/usr/libexec/diskarbitrationd
DiskArbitrationAgent (per-user GUI helper)/System/Library/CoreServices/DiskArbitrationAgent.app//System/Applications/DiskArbitrationAgent.app/ — system-shipped .app bundles go under /System/Applications/, not user-installed /Applications/. Headless alternative: /usr/libexec/DiskArbitrationAgent
DiskArbitration framework (gershwin layout)/System/Library/Frameworks/DiskArbitration.framework//System/Library/Frameworks/DiskArbitration.framework/ — preserve bundle
DA headers (DADisk.h, DASession.h, DADissenter.h, etc.) (gershwin layout)inside frameworkinside framework
diskarbitrationd launchd plist/System/Library/LaunchDaemons/com.apple.diskarbitrationd.plistsame path; rename to org.freebsd.diskarbitrationd.plist if shipping our own variant
DA agent launchd plist/System/Library/LaunchAgents/com.apple.DiskArbitrationAgent.plistsame path; rename to org.freebsd.DiskArbitrationAgent.plist if shipping our own variant
diskarbitrationd config / approval rules/etc/fstab (mount preferences) plus /Local/Library/Preferences/SystemConfiguration/autodiskmount.plist (where applicable; /Local/Library universally, not Apple's /Library)

15. Block.h / libBlocksRuntime

Blocks runtime — ship our own as libsystem_blocks

Decided Build from Apple's compiler-rt source (the same upstream LLVM sources FreeBSD-libblocksruntime uses) and install as libsystem_blocks.so alongside the rest of our Libsystem family. Drop the FreeBSD-libblocksruntime pkg from pkglist-base.txt — we own this now.

Naming consistency wins: libsystem_kernel, libsystem_dispatch, libsystem_xpc, libsystem_launch, libsystem_blocks all live together at /usr/lib/system/ with Apple-canonical names. Matches what Apple actually calls this on macOS (libsystem_blocks.dylib). swift-corelibs-libdispatch's bundled Block.h still gets skipped via the existing build patch — single source of truth on the system, just provided by us instead of pkgbase.

ArtifactApple macOS (reference)Chosen (our build)
Block.h/usr/include/Block.h (SDK)/usr/include/Block.h
Block_private.h/usr/include/Block_private.h/usr/include/Block_private.h
libBlocksRuntime / libsystem_blocks/usr/lib/system/libsystem_blocks.dylib (cache)/usr/lib/system/libsystem_blocks.so
Versioned symlinkn/a (cache)/usr/lib/system/libsystem_blocks.so.0
Compatibility symlink (for clang's implicit -lBlocksRuntime)n/a/usr/lib/libBlocksRuntime.so/usr/lib/system/libsystem_blocks.so

Build / consumer notes:

16. GNUstep stack (libobjc2 + libgnustep-base + libgnustep-corebase + tools)

GNUstep stack — gershwin-owned, always at /System/Library/

Project policy: the GNUstep core libraries (libobjc2, libgnustep-base, libgnustep-corebase) and gershwin's tooling (tools-make, GNUstep.conf, helper CLIs) always live at /System/Library/. They are gershwin's domain — we don't relocate them to /usr/lib, /usr/local/lib, or /usr/lib/system/ regardless of what layout we pick for the Apple-source-userland libraries. Cross-layout choice does not apply to the GNUstep stack.

Scope: the GNUstep stack lives in the gershwin desktop overlay — a separate fork/overlay on top of the freebsd-launchd-mach ISO. It is not installed by the freebsd-launchd-mach ISO itself. The launchd-adjacent system services (launchctl, configd, IPConfiguration, mDNSResponder, asl, notifyd, DiskArbitration) are all pure C with CoreFoundation by Apple's original design and link /usr/lib/system/libCoreFoundation.so.6 (swift-corelibs CF), not libgnustep-corebase. See the launchctl-corefoundation-spike for the audit and reasoning. The GNUstep paths below are still authoritative for gershwin once that overlay lands.

ArtifactApple macOS (reference)Our project (all layouts, no choice)
libobjc2 (ObjC runtime)Apple's libobjc at /usr/lib/libobjc.A.dylib (cache) — different runtime (Apple's, not libobjc2)/System/Library/Libraries/libobjc.so
libobjc2 headersSDK /usr/include/objc/*.h/System/Library/Headers/objc/*.h
libgnustep-base (Foundation reimpl)n/a — Apple's Foundation is closed-source/System/Library/Libraries/libgnustep-base.so
libgnustep-base headersn/a/System/Library/Headers/Foundation/*.h + /System/Library/Headers/GNUstepBase/*.h
libgnustep-corebase (CF value-types reimpl)n/a — Apple's CF is monolithic in CoreFoundation.framework/System/Library/Libraries/libgnustep-corebase.so
libgnustep-corebase headersn/a/System/Library/Headers/CoreFoundation/*.h
GNUstep makefilesn/a/System/Library/Makefiles/
GNUstep tools (defaults, gdomap, gdnc, plutil, pl, plmerge, autogsdoc, etc.)n/a/System/Library/Tools/
GNUstep confign/a/System/Library/Preferences/GNUstep.conf

The choice between Apple-like /usr/lib/system/, gershwin /System/Library/Libraries/, or FreeBSD-base /usr/lib/ applies only to Apple-source system-services libraries (libdispatch, libxpc, libmach, liblaunch, libnotify, libasl, libSystemConfiguration, libCoreFoundation). GNUstep core libraries are out of scope for that choice — they live in the gershwin desktop overlay, not on this ISO.

17. Cross-cutting concerns

17.1. Framework bundles vs flat layout

Three frameworks in our porting scope: SystemConfiguration.framework, DiskArbitration.framework, and the optional CoreFoundation.framework wrapper. For each, the choice is:

The bundle layout costs about 200 lines of build-system fiddling per framework (CMake's framework target or hand-rolled symlinks). Worth it for source compatibility with Apple imports; not worth it if we deeply rework each framework anyway.

17.2. Reverse-DNS plist naming

Apple uses com.apple.<name>.plist. Our project uses org.freebsd.<name>.plist for new daemons. Both coexist in the same directories — launchd loads any .plist regardless of prefix. If we import Apple's verbatim plists for daemons that don't conflict with FreeBSD-native ones (e.g. notifyd, mDNSResponder), we keep their com.apple. prefix; if we ship our own (org.freebsd.syslogd because we're replacing FreeBSD's syslogd), we use org.freebsd..

17.3. Project policy: /Local/Library always, never /Library

Project policy: /Library/... at the filesystem root is not used in this project. The third-party / shared-content root is always /Local/Library/..., regardless of which Apple-source component we're porting and regardless of how Apple itself layouts /Library on macOS.

This applies to:

/System/Library/ is unchanged. That's where Apple's own system-level content lives, and we follow that convention for our Apple-source-userland's system content (libraries, headers, frameworks, system LaunchDaemons). The policy applies ONLY to the third-party root, not the system root.

~/Library/ (per-user) is unchanged. Per-user home-directory content stays in ~/Library/; gershwin already follows Apple's convention here. Per-user agent plists at ~/Library/LaunchAgents/, per-user preferences at ~/Library/Preferences/.

Apple-source verbatim imports (configd, DiskArbitration, IPConfiguration) that reference /Library/Preferences/SystemConfiguration/ internally need a small patch or runtime configuration substituting /Local/Library/Preferences/SystemConfiguration/. Handled per-port; small impact.

17.4. Apple-Unix paths are (mostly) universal — daemons could move to /System/Library/Tools/

The spike presents daemons at Apple-conventional Unix paths (/usr/sbin/notifyd, /usr/sbin/syslogd, /usr/libexec/configd, etc.) across all four columns. That's a choice, not a hard requirement. Gershwin has its own convention for "tools that the gershwin environment owns" via /System/Library/Tools/ — where GNUstep helper utilities (defaults, gdomap, gdnc, plutil) already live.

Daemon / CLIApple-Unix path (default in this spike)Gershwin Tools path (alternative)
launchd/sbin/launchdno — PID 1 must be on the boot partition root for the kernel; /sbin/launchd is effectively required
launchctl/bin/launchctl/System/Library/Tools/launchctl — possible; matches GNUstep CLI convention
syslogd, notifyd, scutil, mDNSResponder, ipconfig, rtadvd, aslmanager/usr/sbin/<name>/System/Library/Tools/<name> — possible per daemon
configd, diskarbitrationd, IPConfiguration, bootpd, dhcp6d, IPConfigurationHelper, mDNSResponderHelper/usr/libexec/<name>/System/Library/Tools/<name> — possible but loses the /usr/libexec "implementation-detail-daemon" signal
syslog, notifyutil, dns-sd CLIs/usr/bin/<name>/System/Library/Tools/<name> — possible; matches GNUstep tools precedent most closely

Why the spike defaults to Apple-Unix paths

When you'd want /System/Library/Tools/ instead

Decision (current spike default, revisable): stick with Apple-Unix paths for daemons. Move to /System/Library/Tools/ only if a concrete reason emerges. The launchd plist abstraction makes this revisable at any time without breaking consumers.

.app bundles — /System/Applications/ for system-shipped apps

Distinct from CLI tools / daemons: any Apple-source component that ships as a .app bundle (DiskArbitrationAgent, future Apple-source GUI helpers, ...) lives at /System/Applications/Foo.app/ on our system, not /Applications/Foo.app/. The convention:

This mirrors Apple's modern (Catalina+) layout where Apple-system apps live at /System/Applications/ separate from user-installed apps at /Applications/.

17.5. Universal paths across all four layouts

The following paths are identical across every layout (daemons / CLIs / configs / runtime state don't depend on the library layout):

The four layouts diverge only on libraries, headers, and framework bundles.

17.5. Gershwin conditional-skip pattern

If freebsd-launchd-mach installs its libsystem_* libraries to a known location, gershwin-developer's Install-System-Domain.sh can detect their presence and skip the corresponding build entirely — deferring to our project's binaries. This avoids the dual-build / dual-install problem and gives our project ownership of the Apple-source-userland libraries when it's installed.

Pattern, added to gershwin-developer/Library/Scripts/Install-System-Domain.sh near the top:

LIBSYSTEM_DIR="/usr/local/lib/system"   # or /usr/lib/system

# --- libdispatch ---
if [ -f "$LIBSYSTEM_DIR/libsystem_dispatch.so" ]; then
    echo "==> freebsd-launchd-mach libsystem_dispatch.so detected — skipping libdispatch build"
    mkdir -p /System/Library/Libraries /System/Library/Headers
    ln -sf "$LIBSYSTEM_DIR/libsystem_dispatch.so" /System/Library/Libraries/libdispatch.so
    ln -sf /usr/include/dispatch /System/Library/Headers/dispatch
    ln -sf /usr/include/os       /System/Library/Headers/os
    # Block.h coordination automatic — both projects defer to base's /usr/include/Block.h
else
    # ... existing gershwin libdispatch build ...
fi

# --- libxpc (when freebsd-launchd-mach starts shipping it) ---
if [ -f "$LIBSYSTEM_DIR/libsystem_xpc.so" ]; then
    echo "==> freebsd-launchd-mach libsystem_xpc.so detected — skipping libxpc"
    ln -sf "$LIBSYSTEM_DIR/libsystem_xpc.so" /System/Library/Libraries/libxpc.so
    ln -sf /usr/include/xpc /System/Library/Headers/xpc
fi

# --- libmach, libnotify, libasl, libsystem_launch, libsystem_configuration ---
# Same pattern for each.

Why this is the right coordination model

Where does $LIBSYSTEM_DIR point?

ChoiceProsCons
/usr/lib/system/ Exact match to Apple's pre-Big-Sur layout. Most Apple-canonical pitch. Lives in FreeBSD base namespace. Latent pkgbase-collision risk if FreeBSD ever ships its own libsystem_* (unlikely but possible).
/usr/local/lib/system/ Standard FreeBSD ports placement. Clean separation from base. No pkgbase-collision risk. Where freebsd-launchd-mach's ports package would install by default. Slightly less Apple-canonical (Apple uses /usr/lib/system/). The "libsystem_" prefix under /usr/local/ is mildly incongruous.

Recommended: /usr/local/lib/system/. The pkgbase-collision risk argues against /usr/lib/system/; ports placement matches how our project would actually ship as a FreeBSD package; and the coordination pattern doesn't care about the exact path. Gershwin just looks for the file.

Migration path — two phases

Phase 1: symlink layer (zero consumer change).

  1. Phase 0 of the libxpc plan commits to a libdispatch Mach-backend patch in gershwin-developer/Library/Patches/. Same library gershwin builds today, with Mach support added.
  2. When freebsd-launchd-mach starts shipping libsystem_dispatch.so standalone (out of the same patched source), add the conditional-skip block to Install-System-Domain.sh + symlinks at /System/Library/Libraries/ and /System/Library/Headers/. Consumers' existing -ldispatch / -I/System/Library/Headers keep working unchanged.
  3. Gershwin-on-freebsd ISO builds automatically pick up freebsd-launchd-mach's version when the package is installed first in the build pipeline.

Phase 2 (optional, later): reconfigure consumers to reference /usr/local/lib/system/ directly.

Once Phase 1 is stable, gershwin's downstream parts can be updated to point at /usr/local/lib/system/ directly and retire the symlink layer. Concrete places that need updating:

File / settingCurrentAfter reconfigure
tools-make/FilesystemLayouts/gershwin — defines GNUSTEP_SYSTEM_LIBRARIES /System/Library/Libraries still /System/Library/Libraries for GNUstep stack; add /usr/local/lib/system to the search path for Apple-source libraries
tools-make/Makefiles/Library/library.make — library link flags -L/System/Library/Libraries -ldispatch add conditional: $(if -f /usr/local/lib/system/libsystem_dispatch.so, -L/usr/local/lib/system -lsystem_dispatch, -L/System/Library/Libraries -ldispatch)
GNUstep.conf at /System/Library/Preferences/GNUstep.conf library/header dir vars all point to /System/Library/ add GNUSTEP_LIBSYSTEM_LIBRARIES=/usr/local/lib/system + GNUSTEP_LIBSYSTEM_HEADERS=/usr/include; GNUstep-aware tools read these
gershwin component build scripts (windowmanager, terminal, workspace, systempreferences, etc.) — their GNUmakefile / configure invocations implicit -L/System/Library/Libraries via tools-make inherits new search path automatically once tools-make is updated; no per-component change needed
ldconfig drop-in at /usr/local/libdata/ldconfig/freebsd-launchd only lists /System/Library/Libraries also list /usr/local/lib/system so runtime dlopen finds the libsystem_* binaries
pkg-config files each .pc hardcodes /System/Library/Libraries each libsystem_*.pc in /usr/local/libdata/pkgconfig/ hardcodes /usr/local/lib/system; gershwin's libdispatch.pc stays for fallback

The pattern for each consumer: pkg-config-driven where possible (pkg-config --libs libsystem_dispatch returns the right flags) plus ldconfig updates so runtime resolution works. Apps that link via the GNUstep build system inherit the new search path through tools-make; apps that build standalone use pkg-config.

Optional libSystem.so umbrella (mentioned in the libxpc plan §10): if we ever ship a single /usr/local/lib/system/libSystem.so that reexports all the libsystem_* libraries, consumers can just link -lSystem and get the whole Apple-userland surface in one symbol — closest to Apple's macOS link-line ergonomics. Ten-line linker script, deferrable until ergonomics matter.

Decision point: Phase 1 (symlinks only) is the right starting state — gives us the coordination without forcing gershwin-wide consumer changes. Phase 2 is a later cleanup, done if/when the symlink layer becomes operationally annoying. Many production projects stop at the symlink layer permanently.

17.6. Why /usr/local/lib/system/ (or /usr/lib/system/) is interesting

The new column added in this spike: instead of putting Apple-source libraries at /System/Library/Libraries/ (gershwin) or /usr/lib/ (base), put them under /usr/lib/system/ with Apple's macOS naming convention — libsystem_dispatch.so, libsystem_xpc.so, libsystem_kernel.so, libsystem_notify.so, libsystem_asl.so, libsystem_launch.so, libsystem_configuration.so.

This mimics Apple's /usr/lib/system/libsystem_*.dylib layout that existed on macOS before the Big-Sur dyld-shared-cache consolidation. Pros:

Cons:

18. Recommendation

Recommended hybrid:

The /usr/lib/system/ path is a strong alternative — mimics Apple's actual macOS layout more closely than gershwin's /System/Library/Libraries/ does. If we ever revisit the project's overall path strategy (e.g. for pkgbase distribution), /usr/lib/system/ is the natural target. For now, the gershwin precedent wins on lower migration cost: our existing repos and build scripts already install to /System/Library/Libraries/.

If we revisited this decision later in the project's life:

MoveMigration costBenefit
Stay at gershwin layout (no change)0Status quo
Move to /usr/lib/system/Medium — update gershwin-developer install scripts, freebsd-launchd build.sh, all consumer Makefiles. Possibly a coordinated gershwin patch.Closer to Apple's layout; cleaner pkgbase migration story
Move to /usr/lib/ (flat base)High — same as above plus framework-bundle teardown, header reorganizationPkgbase-native

Last updated 2026-05-12. Per-component layout derived from grep over the local NextBSD, ravynOS, freebsd-launchd, freebsd-launchd-mach trees plus apple-oss-distributions repos for components not locally cloned (DiskArbitration, mDNSResponder, IPConfiguration / bootp). Apple paths verified against macOS SDK conventions; pre-Big-Sur paths preferred since FreeBSD has no dyld shared cache. Recommendations align with the project's existing freebsd-launchd build.sh and gershwin-developer Install-System-Domain.sh while documenting /usr/lib/system/ as a coherent alternative.