Setting environment variables in OS X for GUI applications

How does one set up environment variables in Mac OS X such that they are available for GUI applications without using ~/.MacOSX/environment.plist or Login Hooks (since these are deprecated)?


Solution 1:

On Mountain Lion all the /etc/paths and /etc/launchd.conf editing doesn't take any effect!

Apple's Developer Forums say:

"Change the Info.plist of the .app itself to contain an "LSEnvironment" dictionary with the environment variables you want.

~/.MacOSX/environment.plist is no longer supported."

So I directly edited the app's Info.plist (right click on "AppName.app" (in this case SourceTree) and then "Show package contents")

Show Package Contents

and added a new key/dict pair called:

<key>LSEnvironment</key>
<dict>
     <key>PATH</key>
     <string>/Users/flori/.rvm/gems/ruby-1.9.3-p362/bin:/Users/flori/.rvm/gems/ruby-1.9.3-p362@global/bin:/Users/flori/.rvm/rubies/ruby-1.9.3-p326/bin:/Users/flori/.rvm/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:</string>
</dict>

(see: LaunchServicesKeys Documentation at Apple)

enter image description here

now the App (in my case SourceTree) uses the given path and works with git 1.9.3 :-)

PS: Of course you have to adjust the Path entry to your specific path needs.

Solution 2:

The solution uses the functionality of launchctl, combined with a Launch Agent to mimic the login hooks of old. For other solutions using the store of launchd, see this comparison. The launch agent used here is located in /Library/LaunchAgents/:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>user.conf.launchd</string>
    <key>Program</key>
    <string>/Users/Shared/conflaunchd.sh</string>
    <key>ProgramArguments</key>
    <array>
        <string>~/.conf.launchd</string>
    </array>
    <key>EnableGlobbing</key>
    <true/>
    <key>RunAtLoad</key>
    <true/>
    <key>LimitLoadToSessionType</key>
    <array>
        <string>Aqua</string>
        <string>StandardIO</string>
    </array>
</dict>
</plist>

One important thing is the RunAtLoad key so that the launch agent is executed at the earliest time possible. The real work is done in the shell script /Users/Shared/conflaunchd.sh, which reads ~/.conf.launchd and feeds it to launchctl:

#! /bin/bash

#filename="$1"
filename="$HOME/.conf.launchd"

if [ ! -r "$filename" ]; then
    exit
fi

eval $(/usr/libexec/path_helper -s)

while read line; do
    # skip lines that only contain whitespace or a comment
    if [ ! -n "$line" -o `expr "$line" : '#'` -gt 0 ]; then continue; fi

    eval launchctl $line
done <"$filename"

exit 0

Notice the call of path_helper to get PATH set up right. Finally, ~/.conf.launchd looks like that

setenv PATH ~/Applications:"${PATH}"

setenv TEXINPUTS .:~/Documents/texmf//:
setenv BIBINPUTS .:~/Documents/texmf/bibtex//:
setenv BSTINPUTS .:~/Documents/texmf/bibtex//:

# Locale
setenv LANG en_US.UTF-8

These are launchctl commands, see its manpage for further information. Works fine for me (I should mention that I'm still a Snow Leopard guy), GUI applications such as texstudio and TeXShop can see my own tex tree. Things that can be improved:

  1. The shell script has a #filename="$1" in it. This is not accidental, as the file name should be feeded to the script by the launch agent as an argument, but that doesn't work.

  2. As mentioned here (German and behind a paywall!), it is possible to put the script in the launch agent itsself.

  3. I am not sure how secure this solution is, as it uses eval with user provided strings.

  4. I think to remember that the definition of MANPATH using this method didn't work well, but I'm not sure.

It should be mentioned that Apple intended a somewhat similar approach by putting stuff in ∼/launchd.conf, but it is currently unsupported as to this date and OS (see the manpage of launchd.conf). I guess that things like globbing would not work as they do in this proposal. And of course one can put these files anywhere else, except the launch agent which must reside in /Library/LaunchAgents/ or ~/Library/LaunchAgents/.

Finally, I should mention the sources I used as information on Launch Agents: 1, 2, 3, 4.

Update: This does not work in version 10.8 at the moment. Workarounds on a per application basis are described here and here.

Solution 3:

The answer provided by @flori works for me on Maverick provided I run the following commands in Terminal after changing the plist file

/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -kill -r -domain local -domain system -domain user 

killall Finder