man’s Special Xcode Support

The backstory: I use ManOpen to view Unix man pages on OS X. (schwa has a modernized fork on GitHub.)

It stopped working. Perhaps with 10.9 Mavericks or 10.8 Mountain Lion. I was too busy to track it down.

Today I was trying to look up memcmp’s page and it was still broken. I figured Apple just moved where man pages live and I needed to add the new search path to ManOpen’s prefs.

However, I couldn’t figure out the right path. I knew man memcmp somehow worked, and I used sudo find / -name 'memcmp.3' to locate where man was finding its page:

/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/share/man/man3/memcmp.3

I added that path to ManOpen and it worked, but I was troubled that 1) it seemed way too specific and 2) I didn’t know how man was finding the page in the first place.

I took a look at /etc/man.conf and /etc/manpaths and /etc/manpaths.d to no avail. They pointed me towards /usr/share/man (which is a ghost town on my system) and /usr/local/share/man (which was also incomplete (it didn’t have memcmp.3)).

So I tweeted:

rentzsch / @rentzsch:

what’s the deal with man pages on OS X 10.9? man memcmp works even though /usr/share/man is a ghost town and /u/l/s/man doesn’t have it

rentzsch / @rentzsch:

looks like it’s coming from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform /Developer/SDKs/MacOSX10.9.sdk/usr/share/man

rentzsch / @rentzsch:

but I don’t understand how

rentzsch / @rentzsch:

manpaths does list that Xcode SDK path, but I there’s no entry for it in /etc/man*

Kyle Sluder figured it out in short order:

Kyle S. / @optshiftk:

Ah, here’s the magic: opensource.apple.com/source/man/man…

That’s just the patch, man's full code is here (thanks to Tom Harrington).

So Apple’s man calls xcselect_get_manpaths() to dynamically add Xcode-specific paths to man’s search paths. Sneaky.

Dave DeLong also informed me about libxcselect.dylib:

Dave DeLong / @davedelong:

my guess: /usr/lib/man links libxcselect.dylib (otool -L) and it’s using that to find your Xcode SDK to look for more man pages

(typo corrected)

libxcselect.dylib is key to Apple’s technique of providing stubs binaries at standard locations that do little else but look up the actual tool locations inside /Applications/Xcode.app and execute them.

For example, let’s look at cc. /usr/bin/cc is just a symlink to /usr/bin/clang, which makes sense in modern terms. Let’s see what it links to:

otool -L /usr/bin/cc
/usr/bin/cc:
    /usr/lib/libxcselect.dylib (compatibility version 1.0.0, current version 1.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)

Your suspicions should be raised by our friend libxcselect.dylib. Also, /usr/bin/clang’s size:

$ ls -l /usr/bin/clang
-rwxr-xr-x  1 root  wheel  14224 Oct 24 08:41 /usr/bin/clang

clang is cool but I doubt Apple’s fitting an entire C/C++/Obj-C/Obj-C++ compiler into 14K. Let’s take a look at what it actually does:

$ otool -tV /usr/bin/clang
/usr/bin/clang:
(__TEXT,__text) section
_main:
0000000100000f5e    pushq   %rbp
0000000100000f5f    movq    %rsp, %rbp
0000000100000f62    movq    %rsi, %rax
0000000100000f65    leal    0xffffffffffffffff(%rdi), %esi
0000000100000f68    leaq    0x8(%rax), %rdx
0000000100000f6c    leaq    0x27(%rip), %rdi ## literal pool for: clang
0000000100000f73    xorl    %ecx, %ecx
0000000100000f75    callq   0x100000f7a ## symbol stub for: _xcselect_invoke_xcrun

It’s entire implementation is pretty much just

return xcselect_invoke_xcrun("clang");

FWIW I found the real clang binary in

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang

It’s 28MB.

Anyways, I’m sticking with just adding that Xcode SDK path to ManOpen for now, but perhaps someone will enhance ManOpen to call automatically manpath instead of having to explicitly specify such paths. ManOpen is open source (hint hint).

Update: Chris Cieslak has immediately stepped into the breach and added a quick and dirty fix to ManOpen. Thanks, Chris.

xcode man manpath Feb 4 2014