5

Sorry, there's a bit of background necessary — you could try skipping to the Question heading.

Since time immemorial (somewhere in the previous millennium, anyway), I've created directories such as /usr/gnu and /usr/gcc to hold custom-compiled GNU software, separate from anything in the system directories. This has worked well for me, on a wide variety of Unix-based systems, including Mac OS X since 2002 (Jaguar, 10.2). (One reason for not using /usr/local was that the IT management maintained it, and it always contained archaic code — it had Perl 4 available until about 5 years ago, for example. Using other names avoided run-ins with them.)

With Mac OS X 10.11 El Capitan, Apple has introduced the SIP (System Integrity Protection) system (described at What is the "rootless" feature of El Capitan, really? on 'Ask Different'). It means that I can no longer create directories such as /usr/gnu or /usr/gcc, even though they're disjoint from anything that Apple has.

I found that the software previously in those directories had been quarantined in directories like these (where the UUIDs will be different on your machine, and I probably have two because getting El Capitan onto this machine was a multi-step operation — a separate long and boring story):

$ ls -1 /Library/SystemMigration/History/
Migration-7D74B534-AA54-4A4A-8DCC-A5C2F28E1A39
Migration-9C0FE7A4-3445-4BD6-A512-35464EECCBC3
$

and then in sub-directories under QuarantineRoot:

$ ls /Library/SystemMigration/History/Migration-9C0FE7A4-3445-4BD6-A512-35464EECCBC3/QuarantineRoot/usr:
gcc      gnu32    gnu64
$

However, the binaries were compiled with GCC and various libraries, so they don't run at the moment. For example:

$ otool -L bison
bison:
    /usr/gnu64/lib/libintl.8.dylib (compatibility version 10.0.0, current version 10.1.0)
    /usr/gnu64/lib/libiconv.2.dylib (compatibility version 8.0.0, current version 8.1.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 169.3.0)
    /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 744.18.0)
    /usr/gcc/v4.7.1/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
$ ./bison
dyld: Library not loaded: /usr/gnu64/lib/libintl.8.dylib
  Referenced from: /Library/SystemMigration/History/Migration-9C0FE7A4-3445-4BD6-A512-35464EECCBC3/QuarantineRoot/usr/gnu64/bin/./bison
  Reason: image not found
Trace/BPT trap: 5
$

AFAIK, I can't even create symlinks in /usr such that gcc or gnu64 points somewhere else (not even running with root privileges). That's one of the techniques I've used to create software on MachineA with spare space in /work1 for use on another MachineB with spare space in /work5; a symlink in /usr allows the code to sit in /work1/gcc or /work5/gcc and it works correctly as long as /usr/gcc points to where the files are actually installed. So, this SIP system seems to kill all the mechanisms used successfully for a couple of decades which are predicated on being able to create at least some sort of directory entry in /usr.

Question

  • Is there a sensible way to get the old binaries to run without disabling SIP and without having to recompile everything immediately?

The fall-back position is "recompile the software — avoiding /usr as an install location". Over time, I plan to use /opt/gcc and /opt/gnu64 instead of the equivalents under /usr. I'm even contemplating using space under my home directory, even though I'd rather not; it is 'system' software.

However, I have quite a lot of software already compiled, including multiple versions of GCC (from 4.4.2 through 5.2.0), which it will be a nuisance to recompile. In fact, I'll have to abandon the old versions of GCC, which I don't use all that often, but which are useful when I do need them.


Oh, and I've got a problem with the configure script for GNU Tar (1.28 and 1.26). It tests how deep a directory tree it can create, and then is unable to clean-up. And neither rm nor rmdir can clean up either, even if I cd down the hierarchy to the bottom. It gets an 'out of disk space' error, even though there's lots of space left. I can use Finder to move the hierarchy to Trash. But Finder can't remove them either. Bash has a tizzy because it can't work out what the current directory is. It is all kinda painful! So recompiling and reinstalling some of the software is not going to be trivial. I may even end up using stuff compiled by other people (MacPorts, HomeBrew, etc), but I like to be able to compile my own. I get the error 'The operation can’t be completed because the item “confdir-14B---” is in use'; a reboot may be in order, but I'm not confident it will fix that problem.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 1
    One Tumbleweed badge later (which wasn't the intention at the outset), I'm ready to assume that the answer is "No, there isn't a way around the problem that is reasonably sane", so the complete set of rebuilds is in order. The tar issue has been reported to the GNU tar maintainers; there's an action item response to me that I've not yet taken the necessary steps on. (I don't believe this would have been on-topic at [Ask Different](http://apple.stackexchange.com/) — I looked before asking here and it seemed to be explicitly excluded from their list of on-topic items.) – Jonathan Leffler Oct 19 '15 at 08:16
  • I just came across [this web page](http://digitizor.com/fix-homebrew-permissions-osx-el-capitan/) that might provide a route to resolving this. I haven't tested it yet, but It appears to use `csrutil disable` temporarily to allow creation of a new directory, changing the permissions on that directory to allow "rootless" access, then re-enabling the SIP afterwards. If nobody else does it first, I'll come back with an actual answer after I've tested it for myself. – Graham Klyne Mar 20 '16 at 06:54
  • @GrahamKlyne: thanks for the link. It doesn't solve my problem, which was that I had software configured to live under `/usr/gnu64` and `/usr/gcc`. I didn't have a problem with `/usr/local` except that my software wasn't using it — the directory existed OK and had acceptable permissions, and I was able to install software in it when necessary. – Jonathan Leffler Mar 20 '16 at 06:58
  • My thought was that you could use the procedure described to create accessible directories `/usr/gnu64` and `/usr/gcc`, then proceed as before. But I could still be missing something. – Graham Klyne Mar 20 '16 at 07:20
  • Yes, but they'll be removed at the next upgrade, if not the next update. – Jonathan Leffler Mar 20 '16 at 07:23
  • Ah, I didn't know that. I was assuming that if it worked for homebrew's `/usr/local` then it could also work for other directories in `/usr`. Oh well, it was a hopeful thought - I have a similar problem with my (recently upgraded) setup that I was hoping to resolve. – Graham Klyne Mar 20 '16 at 07:26
  • Well, I'm fairly sure one of the places I read implied if not stated that any unexpected directories in `/usr` will be moved on upgrade/update. You're allowed `/usr/local` and sub-directories under it — that won't be a problem, even across upgrades and updates. But other pre-existing unexpected directories under `/usr` are 'migrated' out of the way during the upgrade to El Capitan (and other upgrades, I think) and not allowed back unless you go dinking with `csrutil` on each time. All that 'AFAIK' and 'TTBOMK', of course — and unless Apple change the rules again. – Jonathan Leffler Mar 20 '16 at 07:30
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/106830/discussion-between-graham-klyne-and-jonathan-leffler). – Graham Klyne Mar 20 '16 at 07:52
  • 1
    Have you tried using the DYLD_LIBRARY_PATH environment variable ? You could run your program like this: DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:/new/lgnu/library/path programname – Peter Skarpetis Aug 28 '16 at 01:33

1 Answers1

0

Just for the sake of closure:

  • No; there doesn't seem to be a way to avoid recompiling code.

If you want to follow the chat link, by all means do so, but it ends up at the same conclusion.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • You can avoid recompilation using `install_name_tool -change` to update rpath. – Amadan Jul 05 '19 at 01:44
  • For the specific example above, e.g. `install_name_tool -change /usr/gcc/v4.7.1/lib/libgcc_s.1.dylib /usr/lib/libgcc_s.1.dylib bison` should make it work (assuming you have `libgcc_s.1.dylib` in `/usr/lib`). – Amadan Jul 05 '19 at 01:53