>
> I don't know if there's any such thing as running an alternative libc on a
> macOS/Darwin system--maybe the system crashes; maybe Apple activates a kill
> switch in your Mac; or maybe things work more or less fine.


It's actually far worse than any of those possibilities, I'm afraid. All of
the standard Unix tools for building software (compiling, linking,
assembling, disassembling, etc) *appear* to be perfectly ordinary
executables in the /usr/bin directory. What they *actually* are, shockingly
enough, are pointers inside Xcode
<https://real-world-systems.com/docs/xcode-select.1.html> (which is both
Apple's bloated IDE they foist on you if you hope to publish to the App
Store, *and* a suite of tools for building both graphical and traditional
programs). That is, /usr/bin/cc actually calls upon Xcode to locate the
executable's actual path (according to the current version of Xcode's
toolchain the user has *configured*).

The lookup goes something like this:

*$ xcrun --find cc*
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc

And, no, neither /usr/bin/cc nor the monstrously long path xcrun(1)
<https://real-world-systems.com/docs/xcrun.1.html> coughs up are in anyway
linked directly, both in the ln(1) sense and in the more general sense.
When you call a tool like cc(1) or ld(1) or strings(1) or make(1), those
native binaries are really loading Xcode's cache, or building it if one
hasn't been created during the user's login session yet.

But I've saved the worst till last—you cannot—I repeat, you *cannot*—invoke
any of these commands without first agreeing to Xcode's EULA that Apple
forces you to accept if you want to build software. It doesn't matter if
it's through the Xcode IDE or when you're installing Homebrew
<https://brew.sh/> for the first time—there's a clear list of terms you
have to agree to to even use POSIX-standardised utilities that are
distributed and installed freely and openly on other platforms. You only
need to do this once per workstation (i.e., it won't nag you repeatedly to
reaccept the stupid EULA unless they've changed in some legally cumbersome
fashion).

Now, with all that out of the way, you can locate where Xcode is storing
its libraries (following the usual /usr directory structure)

*$ xcrun --show-sdk-path*
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk

*$ ls -alh "$(xcrun --show-sdk-path)"*
total 40
drwxr-xr-x  7 root  wheel   224B 13 Nov  2022 .
drwxr-xr-x  5 root  wheel   160B 14 Dec  2022 ..
-rw-r--r--  1 root  wheel   127B  5 Nov  2022 Entitlements.plist
-rw-r--r--  1 root  wheel   6.0K  5 Nov  2022 SDKSettings.json
-rw-r--r--  1 root  wheel   4.7K  5 Nov  2022 SDKSettings.plist
drwxr-xr-x  5 root  wheel   160B 13 Nov  2022 System
drwxr-xr-x  7 root  wheel   224B 13 Nov  2022 usr

However, I believe locating the actual library headers at build time is a
job handled by macOS's dyld(1)
<https://github.com/apple-oss-distributions/dyld/blob/637911768f664e38e7e50b4fbf17e303e14fdc01/doc/man/man1/dyld.1>
(dynamic library loader, which loads .dylib files that are Apple's
equivalent of a .so (shared object) file). In my experience, this only
makes building on macOS more complicated (especially when building for
different architectures or SDK versions).

All of these complexities are why building software on OpenBSD makes me
feel like I'm FLYING. macOS isn't a walled garden, it's a prison cell lined
with garden-wallpaper.

— John Gardner, self-certified garden-wallpaper-expert

On Tue, 24 Feb 2026 at 08:31, G. Branden Robinson <
[email protected]> wrote:

> [macOS/Darwin users: I have a libc question toward the end of this
> message.]
>
> Hi Alexis,
>
> At 2026-02-23T21:19:16+0100, Alexis (surryhill) wrote:
> > > I bumped into this commit log message and thought it might amuse you.
> >
> > Thanks for sharing =)
>
> I knew it was a land mine when I planted it.  It's now gone off.  :-O
>
> > > Any luck re-running the command with the corrected environment
> > > variable name?
> >
> > First of all let me say that I should've caught the LC_CALL typo, but
> > most of my open source / groff work happens in the evening I might not
> > be the most attentive after a long day, apologies.
>
> No worries; we're all human.
>
> Well, except for LLM chat bots...
>
> > Here's the output of the commands as requested:
> >
> > /usr/bin/env LC_ALL=C printf 'Eat at the caf\351.\n' | /usr/bin/od -x
> > 0000000      6145    2074    7461    7420    6568    6320    6661    2ee9
> > 0000020      000a
> > 0000021
> >
> > /usr/bin/env LC_ALL=C printf 'Eat at the caf\351.\n' | /usr/bin/od -c
> > 0000000    E   a   t       a   t       t   h   e       c   a   f 351   .
> > 0000020   \n
> > 0000021
>
> Okay.  Your system does not use glibc but _does_ use Latin-1 as the
> character encoding for the "C" locale.
>
> That's a foot pressing squarely on the land mine I set.
>
> > In a previous email you said:
> > > This automated test needs to both (1) set up the locale and (2) use
> > > a portable incantation of printf(1).  If we can achieve that on your
> > > system, then I think we have a path to resolving this test failure.
> >
> > So the (hopefully) good news is that while nixpkgs on Darwin uses
> > libSystem.dylib for its libc it does use printf from GNU's coreutils,
> > which seems more predictable / familiar in the context of a groff
> > build environment:
> >
> > which printf
> > /nix/store/hf6y9njhfwvigr25kzrwmsvmv6jpni5n-coreutils-9.9/bin/printf
> >
> > Does this help to open up a path to resolving this test failure?
>
> Partly.  What I need to know at this point is an easy way from a shell
> script to ask the system what its libc implementation is, when it's
> "libSystem.dylib" in particular.  I don't know if there's any such thing
> as running an alternative libc on a macOS/Darwin system--maybe the
> system crashes; maybe Apple activates a kill switch in your Mac; or
> maybe things work more or less fine.
>
> I'd prefer not to do a simple file existence test for wherever
> "libSystem.dylib" is installed, because that doesn't directly answer the
> question "what is my libc?"  Theoretically, you could have more than one
> libc on the system.  But that may have to do if there's no better way of
> getting this information.  Other libcs make this easy.[1]
>
> I can then update the logic in the test script[2] to handle this case.
>
> Regards,
> Branden
>
> [1] For example, you can run GNU libc as an executable.
>
> $ /lib/x86_64-linux-gnu/libc.so.6
> GNU C Library (Debian GLIBC 2.31-13+deb11u13) stable release version 2.31.
> Copyright (C) 2020 Free Software Foundation, Inc.
> This is free software; see the source for copying conditions.
> There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
> PARTICULAR PURPOSE.
> Compiled by GNU CC version 10.2.1 20210110.
> libc ABIs: UNIQUE IFUNC ABSOLUTE
> For bug reporting instructions, please see:
> <http://www.debian.org/Bugs/>.
>
> [2]
> https://cgit.git.savannah.gnu.org/cgit/groff.git/tree/src/preproc/preconv/tests/smoke-test.sh?h=1.24.0.rc4#n97
>
> has_glibc=
>
> if command -v locale > /dev/null
> then
>     has_glibc=yes
> fi
>
> # Fall back to the locale.
> #
> # On glibc systems, the 'C' locale uses "ANSI_X3.4-1968" for the
> # character set, but preconv assumes Latin-1 instead of US-ASCII.
> #
> # On non-glibc systems, who knows?  But at least some use UTF-8.
>
> if [ -n "$has_glibc" ]
> then
>     charset=ISO-8859-1
> else
>     charset=UTF-8
> fi
>

Reply via email to