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.
| Layout | Status | What 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.
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.
| Artifact | Apple macOS (reference) | FreeBSD base (chosen) |
|---|---|---|
| Kernel module | n/a — Mach is part of XNU kernel proper, not loadable | /boot/kernel/mach.ko |
| loader.conf entry | n/a | /boot/loader.conf: mach_load="YES" |
| Module debug symbols | n/a | /usr/lib/debug/boot/kernel/mach.ko.debug (when built debug) |
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.
| Artifact | Apple macOS (reference) | /usr/lib/system/ (chosen) |
|---|---|---|
| Shared library | /usr/lib/system/libsystem_kernel.dylib (shared cache; logical) | /usr/lib/system/libsystem_kernel.so |
| Versioned symlink | n/a (cache) | /usr/lib/system/libsystem_kernel.so.0 |
| Headers | /usr/include/mach/*.h (SDK) | /usr/include/mach/*.h |
| pkg-config | n/a | /usr/libdata/pkgconfig/libsystem_kernel.pc |
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.
| Artifact | Apple macOS (reference) | /usr/lib/system/ (chosen) |
|---|---|---|
| Shared library | /usr/lib/system/libsystem_dispatch.dylib (cache) | /usr/lib/system/libsystem_dispatch.so |
| Versioned symlink | n/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 |
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.
| Artifact | Apple macOS (reference) | /usr/lib/system/ (chosen) |
|---|---|---|
| Shared library | /usr/lib/system/libsystem_xpc.dylib (cache) | /usr/lib/system/libsystem_xpc.so |
| Versioned symlink | n/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 binary | built into launchd | /usr/libexec/bootstrap_server if standalone (Phase 3 option) or absorbed into /sbin/launchd (Phase 5 option) |
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.
| Artifact | Apple 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.h | same dir as launch.h — /usr/include/ | |
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.
| Artifact | Apple 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.*.plist | same path (+ org.freebsd.* for ours) |
| System per-user agent plists | /System/Library/LaunchAgents/*.plist | same 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/*.plist | same path |
| launchd state directory | /var/db/launchd.db/ | same path |
| Bootstrap socket / port | Mach bootstrap port | Mach bootstrap port (via libmach) |
Decided Use FreeBSD base paths. Daemons + CLIs at Apple-Unix paths, libasl as flat /usr/lib/libasl.so, headers at /usr/include/.
| Artifact | Apple 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.conf | same path |
| asl per-module configs | /etc/asl/*.conf | same path |
| asl log storage | /var/log/asl/ | same path |
system.log | /var/log/system.log | same 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.plist | org.freebsd.aslmanager.plist |
| Man pages | /usr/share/man/man{1,3,5,8}/{asl,syslog,syslogd,aslmanager,notify}.* | same path |
Decided Use FreeBSD base paths. Daemon + CLI at Apple-Unix paths, libnotify as flat /usr/lib/libnotify.so, headers at /usr/include/.
| Artifact | Apple 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.h | same path |
| notify.conf | /etc/notify.conf | same 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 |
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.
| Artifact | Apple 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.8 | same path |
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).
| Artifact | Apple 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 headers | inside 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 deps | n/a | libdispatch, libBlocksRuntime (already in /usr/lib/system/); ICU (new dep, added via FreeBSD pkg) |
| SOVERSION | varies | 6 (matches Apple's CoreFoundation.framework version 6) |
What this is not:
CoreFoundation.framework — that's closed source; we ship swift-corelibs-foundation's Apache-2.0 open-source reimplementation derived from Apple's CF-Lite drops.libgnustep-corebase — that stays in gershwin's lane (next section), used by GNUstep apps in the desktop overlay. The two CFs coexist with the "one CF per binary" rule from the launchctl spike §10.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).
| Artifact | Apple 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.plist | same path; rename to org.freebsd.mDNSResponder.plist if shipping our own variant rather than importing Apple's verbatim |
| nss_mdns config integration | via configd | via configd or /etc/nsswitch.conf |
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).
| Artifact | Apple macOS (reference) | Chosen |
|---|---|---|
| IPConfiguration daemon | built 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/ | |
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.
| Artifact | Apple 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 framework | inside framework |
| diskarbitrationd launchd plist | /System/Library/LaunchDaemons/com.apple.diskarbitrationd.plist | same path; rename to org.freebsd.diskarbitrationd.plist if shipping our own variant |
| DA agent launchd plist | /System/Library/LaunchAgents/com.apple.DiskArbitrationAgent.plist | same 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) | |
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.
| Artifact | Apple 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 symlink | n/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:
llvm-project/compiler-rt/lib/BlocksRuntime/ (BSD-like / public-domain license; ~6 source files, ~500 LOC). Same upstream as FreeBSD's pkg.-fblocks implicitly hunts for libBlocksRuntime. The compatibility symlink at /usr/lib/libBlocksRuntime.so → libsystem_blocks.so keeps that working without flag changes for downstream consumers.FreeBSD-libblocksruntime from pkglist-base.txt. Build/install libsystem_blocks.so in the freebsd-launchd-mach build step (alongside the mach.ko build) before mkuzip./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.
| Artifact | Apple 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 headers | SDK /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 headers | n/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 headers | n/a | /System/Library/Headers/CoreFoundation/*.h | ||
| GNUstep makefiles | n/a | /System/Library/Makefiles/ | ||
| GNUstep tools (defaults, gdomap, gdnc, plutil, pl, plmerge, autogsdoc, etc.) | n/a | /System/Library/Tools/ | ||
| GNUstep config | n/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.
Three frameworks in our porting scope: SystemConfiguration.framework, DiskArbitration.framework, and the optional CoreFoundation.framework wrapper. For each, the choice is:
Foo.framework/Versions/A/Foo + Foo.framework/Headers/ + Foo.framework/Resources/ directory structure. Apple-shape source compiles unchanged with -framework Foo./usr/lib/libFoo.so + /usr/include/Foo/*.h + /usr/share/Foo/*.plist. Apple-shape source needs link-line and include-path rewrites.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.
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..
/Local/Library always, never /LibraryProject 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:
/Local/Library/LaunchDaemons/ — third-party launchd plists (replaces Apple's /Library/LaunchDaemons/)/Local/Library/LaunchAgents/ — third-party launchd agents (replaces Apple's /Library/LaunchAgents/)/Local/Library/Preferences/ — third-party preferences including SCPreferences (replaces Apple's /Library/Preferences/)/Local/Library/Frameworks/ — third-party frameworks (replaces Apple's /Library/Frameworks/)/Library/X Apple uses: becomes /Local/Library/X on our system/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.
/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 / CLI | Apple-Unix path (default in this spike) | Gershwin Tools path (alternative) |
|---|---|---|
| launchd | /sbin/launchd | no — 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 |
/usr/sbin/notifyd etc. Apple-source verbatim imports and any porting documentation reference those paths. Matching keeps source-level diffs minimal./usr/sbin/ for daemons and /usr/libexec/ for back-end daemons can navigate immediately./System/Library/Tools/ is for GNUstep helper CLIs. defaults, gdomap, gdnc, plutil — command-line tools that gershwin ships. Daemons launchd starts aren't conceptually GNUstep tools; they're system services. Mixing them dilutes the meaning of the Tools dir.ProgramArguments paths are flexible. launchd doesn't care where the daemon binary lives — the plist's Program or ProgramArguments[0] just needs an absolute path. So the choice is purely conventional, not technical./System/Library/Tools/ instead/System/Library/ with NOTHING in /usr/sbin or /usr/libexec — cleanest visual separation between Apple-source and FreeBSD-base./System/ — one mount, one tree, everything's there.notifyd at /usr/sbin/notifyd — we'd dodge the collision by being at /System/Library/Tools/notifyd 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 appsDistinct 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:
/System/Applications/ — system-shipped Apple-source .app bundles (DiskArbitrationAgent, future menu/menubar/finder-equivalent apps if any)/Applications/ — user-installed .app bundles (apps the end user drags in)/Local/Library/ at the filesystem root, per the project policy in §17.3, replaces Apple's /Library/ for third-party content, but /Applications/ stays the same name (it's not under /Library, so the policy doesn't apply)This mirrors Apple's modern (Catalina+) layout where Apple-system apps live at /System/Applications/ separate from user-installed apps at /Applications/.
The following paths are identical across every layout (daemons / CLIs / configs / runtime state don't depend on the library layout):
/sbin/launchd, /sbin/launchctl — launchd path/usr/sbin/{syslogd, aslmanager, notifyd, scutil, mDNSResponder, ipconfig, rtadvd} — or /System/Library/Tools/ per §17.4/usr/libexec/{configd, diskarbitrationd, IPConfiguration, bootpd, dhcp6d, IPConfigurationHelper, mDNSResponderHelper}/usr/bin/{launchctl, syslog, notifyutil, dns-sd}/etc/{asl.conf, asl/, notify.conf, bootpd.plist, bootptab, rtadvd.conf}/var/log/asl/, /var/log/system.log, /var/db/{launchd.db, dhcpclient, SystemConfiguration}//System/Library/LaunchDaemons/, /System/Library/LaunchAgents/ (system plists)/Local/Library/LaunchDaemons/, /Local/Library/LaunchAgents/, /Local/Library/Preferences/ (third-party content — our project policy, never plain /Library/)~/Library/LaunchAgents/, ~/Library/Preferences/ (per-user)/usr/share/man/manN/*.NThe four layouts diverge only on libraries, headers, and framework bundles.
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.
/System/Library/Libraries/libdispatch.so still find it — the symlink resolves to $LIBSYSTEM_DIR/libsystem_dispatch.so. Both call sites converge on the same binary./usr/include/Block.h — one source of truth on the system regardless of which built libdispatch.$LIBSYSTEM_DIR point?| Choice | Pros | Cons |
|---|---|---|
/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.
Phase 1: symlink layer (zero consumer change).
gershwin-developer/Library/Patches/. Same library gershwin builds today, with Mach support added.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.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 / setting | Current | After 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.
/usr/local/lib/system/ (or /usr/lib/system/) is interestingThe 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:
libsystem_* finds the right files.-L/usr/lib/system flag./usr/lib/)./System/Library/ hierarchy — lives within FreeBSD's standard /usr/lib./System/Library/Libraries/.libSystem.so reexporting all of them (the optional umbrella mentioned in the libxpc plan §10) would naturally live alongside.Cons:
/System/Library/Libraries/. Switching to /usr/lib/system/ means coordinated path updates.libsystem_ prefix on each filename is unusual for FreeBSD — sysadmins might not recognize "libsystem_xpc.so" as quickly as "libxpc.so."Recommended hybrid:
/System/Library/Libraries/ (the project's existing precedent)./sbin, /usr/sbin, /usr/libexec, /etc, /System/Library/LaunchDaemons) — universal across all layouts./System/Library/Frameworks/./usr/include/Block.h and /usr/lib/libBlocksRuntime.so. Patch swift-corelibs-libdispatch to skip its bundled copy./Local/Library/ convention for our additions.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:
| Move | Migration cost | Benefit |
|---|---|---|
| Stay at gershwin layout (no change) | 0 | Status 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 reorganization | Pkgbase-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.