Setting environment variables in OS X for GUI applications

18

13

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)?

Percival Ulysses

Posted 2012-09-18T21:00:26.247

Reputation: 461

@ersin-er The answer from StackOverflow "Solution for both command line and GUI apps from a single source (works with Yosemite & El Capitan)" may be of interest to people finding this question.

– l --marc l – 2016-01-07T07:15:41.197

Answers

8

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.

Percival Ulysses

Posted 2012-09-18T21:00:26.247

Reputation: 461

By the way, if one wants to define the PATH-Variable in a Terminal environment and uses this launch agent, I suggest to write export PATH=.:"$(launchctl getenv PATH)" in ~/.bash_profile (similarly for other shells). This is possible since path_helper is called in the shell script. For more details on the PATH variable in OS X, check this answer.

– Percival Ulysses – 2012-09-20T15:01:15.727

16

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.

Flori

Posted 2012-09-18T21:00:26.247

Reputation: 261

1

Thank you! This was perfect for me. On 10.11 (El Capitan) I did have to also run the commands provided by Matthew in order to see my changes to Info.plist take effect.

– dsedivec – 2018-01-02T23:07:00.597

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

Matthew

Posted 2012-09-18T21:00:26.247

Reputation: 183

I had the same behavior with El Capitan, and I have added your point to @flori's answer – Seki – 2016-08-30T17:35:18.910

2

The answer provided by @percival-ulysses works for me on 10.9 Mavericks with the following small change: edit /Users/Shared/conflaunchd.sh script right before exit 0 and add the lines

killall Dock
killall SystemUIServer

to restart the Dock and the menubar. After this the applications started from the Dock or from Spotlight will inherit the correct PATH. If you use Finder to start the PATH-critical applications, then killall Finder may be added too.

In the .bash_profile I use the line

export PATH=`launchctl getenv PATH`

to set the PATH for the Terminal, this way the PATH is controlled from the same location, the ~/.conf.launchd file.

Ury Marshak

Posted 2012-09-18T21:00:26.247

Reputation: 21

0

Another option is to use /etc/launchd.conf. For example I have changed the default PATH by adding this line to /etc/launchd.conf:

setenv PATH ~/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/libexec:/usr/texbin

You can apply changes to /etc/launchd.conf by either restarting, or by running launchctl < /etc/launchd.conf; sudo launchctl < /etc/launchd.conf and terminating and relaunching processes.

Settings in /etc/launchd.conf apply to both the root launchd process and per-user launchd processes. Environment variables set with setenv in /etc/launchd.conf are shown by both sudo launchctl export and launchctl export.

Lri

Posted 2012-09-18T21:00:26.247

Reputation: 34 501