Yet Again OS X Pokes Me In The Eye (or OS X Environment Variables)

I bought myself a Macbook Air last year to replace my ageing laptop. The theory was that I’d be using cross platform apps so the underlying system didn’t matter. Or rather it didn’t matter enough to outweigh the pretty 🙂

Anyway, not all of the niggles I have are down to OS X (Apple’s “we must have our own way” GB keyboard is bloody awful and seems designed to piss off developers), but many are and I’ve just come across another. Trying to set consistent environment variables across all apps, regardless of whether terminal based or launched from an icon is an absolute mess. Worse still, Apple doesn’t seem to offer any standard friendly configuration methods for environment variables. Pricks. Anyway, the best resource for troubleshooting these that I’ve found recently is this post on stackoverflow. I’ve reproduced it below in order to ensure it is captured and kept!

There are several places where you can set environment variables.

  • ~/.profile: use this for variables you want to set in all programs launched from the terminal (note that, unlike on Linux, all shells opened in Terminal.app are login shells).
  • ~/.bashrc: this is invoked for shells which are not login shells. Use this for aliases and other things which need to be redefined in subshells, not for environment variables that are inherited.
  • /etc/profile: this is loaded before ~/.profile, but is otherwise equivalent. Use it when you want the variable to apply to terminal programs launched by all users on the machine (assuming they use bash).
  • ~/.MacOSX/environment.plist: this is read by loginwindow on login. It applies to all applications, including GUI ones, except those launched by Spotlight in 10.5 (not 10.6). It requires you to logout and login again for changes to take effect. There is no reason to use this one any more.
  • ~/.launchd.conf: this is read by launchd when the user logs in. It applies to all programs launched by the user, GUI and CLI, on 10.5 and 10.6. Additionally, you can apply changes at any time by piping this file into launchctl (maybe grep ^setenv first if you have other commands you don’t want to run). Then the new variables apply to any application launched by launchd from that point on. This means you should restart Terminal.app for the new variables to cascade down into the shells it launches.
  • /etc/launchd.conf: this is read by launchd when the system starts up and when a user logs in. They affect every single process on the system, because launchd is the root process. Again, to apply changes to the running root launchd you can pipe the commands into sudo launchctl.

The fundamental things to understand are:

  • environment variables are inherited by a process’s children at the time they are forked.
  • the root process is a launchd instance, and there is also a separate launchd instance per user session.
  • launchd allows you to change its current environment variables using launchctl; the updated variables are then inherited by all new processes it forks from then on.

Sample setting an environment variable with launchd and storing it into your personal config so it works for your login even after your reboot:

echo setenv REPLACE_WITH_VAR REPLACE_WITH_VALUE >> ~/.launchd.conf
echo setenv REPLACE_WITH_VAR REPLACE_WITH_VALUE | launchctl

Now, launch your GUI app that uses the variable, and voila!

Leave a Reply

Your email address will not be published. Required fields are marked *