I develop applications using the usual Unix tool set: a compiler, make, and shared libraries. The procedure is then traditionally something like

  • ./configure, which tailors the sources for the features of the machine it is run on,
  • make, which actually compiles the shared libs, executables, etc.,
  • make check, which runs the tests before we install the package,
  • make install, if the package behaves properly, and finally, optionally,
  • make installcheck, to make sure the installation works.

During make, the shared libs and executables are compiled in their final form: the executables are compiled with a dependency to the shared libs in their final destination (i.e., they depend on libraries in /usr/local/lib although they are not there yet, they are still in the build tree). Then make install is, roughly, just using cp to install libs and executables from the build tree to the final place.

During the make check phase, we are running the program uninstalled: the shared libs, executables and auxiliary files are still in the build tree. To run the tests you have to set up a few custom environment variables (for instance to tell your program that your auxiliary data files are not in /usr/local/share but in the source tree), and some system environment variables, to tell your share lib loader to look for the shared libs. The environment variables on traditional Unices is LD_LIBRARY_PATH, on OS X it is DYLD_LIBRARY_PATH. This has worked for (dozens of) years.

But now, El Capitan broke this.

$ (export FOO=foo; env) | grep foo
$ (export DYLDFOO=foo; env) | grep foo
$ (export DYLD_FOO=foo; env) | grep foo

now, when SIP is enabled, no DYLD_* is exported from a process to its children.

So my question is: How can we run programs that are not installed? What is the procedure to follow to be able to run the traditional Unix sequence ./configure && make && make check?

Please, no answer such as "run make install first". That's not the point. I am a developper, and running "make check" (and more generally running a non-installed version of a program) is something I do very frequently. Even installing to a dummy place is time consuming. I need something effective, and efficient. And disabling SIP will not fix the issue for users of my packages that want to run make check.

  • I still can use DYLD_INSERT_LIBRARIES=$HOME/.bin/lib/Apple80211 /Applications/Utilities/AirPort\ Utility\ 5.6.app/Contents/MacOS/AirPort\ Utility\ 5.6 to run the old APU (with the old library) under 10.11 (even though the variable doesn't show up in env). Strange (but it works).
    – nohillside
    Nov 16 '15 at 19:36

It seems like DYLD_* only gets stripped out for “protected” binaries (I’m not sure exactly what that means, but apparently anything in /bin and /usr/bin for starters) However, if you copy /usr/bin/env to somewhere else, it gets to keep its DYLD_* stuff:

$ cp /usr/bin/env ~/Desktop; (DYLD_FOO=bar ~/Desktop/env)|grep DY
dyld: warning, unknown environment variable: DYLD_FOO

I think make always runs commands via /bin/sh, so you can’t set “dangerous” variables in the makefile and have them affect the commands, but maybe you could move the test into a shell script, set the environment variables inside the script, and then invoke the script from make. Though obviously, this won’t help you if the tests, in turn, rely on shell scripts (or if the things tested are shell scripts!) because then they’re going to invoke /bin/sh and lose the variables again...

  • Thanks a lot! Now I can cp /bin/sh, and use that shell instead of the real one. Symlinks won't do, and hard links are "Operations not permitted", so I guess I have to live with cp.
    – akim
    Nov 23 '15 at 13:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .