EnvPane still works on OS X 10.11 "El Capitan". I haven't tried it on 10.12 "Sierra" yet. Apple reimplemented launchd in 10.10 and in the course of doing so deprecated the APIs used by EnvPane and even broke some of them (see issue #11). EnvPane v0.6 adds support for the new but undocumented APIs, addressing the deprecation and issue #11.
For convenience, the pre-built and code-signed binary of EnvPane can be downloaded from my blog Diary Products. Alternatively you might want to grab the source and build it yourself.
Mac OS X releases prior to Mountain Lion (10.8) included support for
~/.MacOSX/environment.plist
, a file that contained session-global, per-user
environment variables. Starting with Mountain Lion, support of this
well-documented and popular mechanism was dropped without an official
announcement or explanation by Apple. It may have been in [response]
flashback to the Flashback trojan which used that file to inject itself into
every process, but this is a wild guess, especially considering that there is a
relatively easy workaround, as demonstrated by the existence of this utility.
EnvPane includes (and automatically installs) a launchd
agent that runs 1)
early after login and 2) whenever the ~/.MacOSX/environment.plist
changes.
The agent reads ~/.MacOSX/environment.plist
and exports the environment
variables from that file to the current user's launchd
instance via the same
API that is used by launchctl setenv
and launchctl unsetenv
.
TODO: Mention /etc/launchd.conf and ~/.launchd.conf
Mac OS X 10.8, Mountain Lion or higher.
- Download the binary package
- Double-click
EnvPane.pref-pane
file - Choose Install for this user only
Do not use the Install for all users option. See the FAQ.
When you open the Environment Variables preference pane, you will see a
simple two-column table that lists the environment variables from your
~/.MacOSX/environment.plist
. If that file doesn't exist, the table will be
empty but the file will be created as soon as you you add an entry to the
table. To add an environment variable by clicking the +
button. Specifying
the name the new variable, hit TAB
and specify the value. Hit Enter. To
modify a variable, double-click its name or value. Make the desired changes and
hit Enter
. To delete an environment variable,
Changes are effective immediately in all subsequently launched applications. There is no need to reboot or log out and back in. Running applications will [not be affected] (#why-arent-running-applications-affected). You need to quit and relaunch the application, in order for your changes to take effect.
-
Open System Preferences
-
Right click Environment Variables
-
Select Remove Environment Variables Preference Pane
The uninstallation should be clean. I went to great lengths in ensuring that
removing the preference pane doesn't leave orphaned files on the system. The
~/.MacOSX/environment.plist
will not be removed.
-
Fix: Projects doesn't build with XCode 7 on OS X El Capitan (10.11)
-
Fix: envlib_unsetenv() is invoked unnecessarily with empty string if environment is empty (issue #3)
Ignore. They are releases made from a fork of this repository, not by the original author and inauspiciously using the EnvPane name.
Fix: Preference pane fails to load if ~/Library/LaunchAgents is missing (issue #2)
Fix: Preference pane fails to load if ~/.MacOSX or ~/.MacOSX/environment.plist are missing (issue #1).
Improved documentation.
Initial release.
-
Mac OS X 10.8, Mountain Lion
-
Xcode 4.5.x (I use 4.5.2)
-
A copy of Apple's
launchd
source tree, available on [Apple Open Source] apple_open_source under the Apache License 2.0. The current version of EnvPane was compiled against launchd-442.26.2 -
David Parsons' Discount C library by for processing John Gruber's Markdown. Install the library as described on the project page. Using the default installation prefix of
/usr/local
is recommended. The current version of EnvPane was statically linked against version 2.2.1 of that library. HomeBrew users can usebrew install discount
to install it.
-
Clone the EnvPane repository on Github
-
Open the Xcode project
-
At the project level, adjust the
launchd_source_dir
custom build setting to point to the copy of the launchd source tree -
Build the project
Linker complaints about libmarkdown. e.g.
ld: warning: object file (/usr/local/lib/libmarkdown.a(markdown.o)) was built for newer OSX version (10.11) than being linked (10.9)
are to be expected when linking against a HomeBrew-ed installation of that library on 10.10 or newer.
The -load_all
linker flag is needed to prevent errors like
exception:-[__NSCFDictionary writeToFile:atomically:createParent:createAncestors:error:]: unrecognized selector sent to instance
There are two reasons. The first one is a technicality: the environment
variables configured via the preference pane are actually set by a launchd
agent contained in the bundle. The agent uses launchd's WatchPath
mechanism
in order to be notified when the user's ~/.MacOSX/environment.plist
changes.
Unfortunately, there is no way to specify a WatchPath
that is relative to the
user's home directory. By installing the EnvPane preference pane for individual
users, each instance can use a separate copy of the agent configuration in
~/Library/LaunchAgents
as opposed to globally in /Library/LaunchAgents
. The
second reason is that cleanly uninstalling the agent would be more complex for
a preference pane that was installed globally for all users. Apple is eagerly
deprecating privilege escalation mechanism left and right, leaving the
half-baked SMJobBless
and the rudimentary authopen
. I'm not saying it
couldn't be done, I'm just not convinced it'd be worth the effort.
Say, you have a shell session running in the Terminal application. You might wonder why changes to the environment made with EnvPane don't show up in the shell's environment. The answer to this question lies in Unix' process model. When a process is forked, it inherits a copy of the environment from its parent process. The copy is independent, so changes in the parent aren't visible in the child and vice versa. Doing anything else would undoubtedly fling open Pandora's box of concurrency.
Applications launched via Finder are in fact forked by the per-user instance of
launchd
, and thus inherit their environment from it. EnvPane uses launchd
's
API to modify the environment of the user's launchd
instance which will then
pass a copy of its modified environment to subsequently launched applications.
The environment of running applications has already been copied and will not
be affected.
For applications other than Terminal the only workaround is to restart the application. In Terminal, you can update the shell's environment by running
eval `launchctl export`
This will update the shell's environment, not Terminal's. Terminal's environment is still unchanged and will be passed on to each new shell window or tab. This means you will have to run the above command in each subsequently opened Terminal tab or window. Ultimately it might be better to just restart Terminal.
Copyright 2012, 2016, 2017 Hannes Schmidt
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Copyright 2008 IconTexto
http://www.icontexto.com
Released under CC License Attribution-Noncommercial 3.0
http://creativecommons.org/licenses/by-nc/3.0/
Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
This product includes software developed by
David Loren Parsons <http://www.pell.portland.or.us/~orc>
Kudos to Jonathan Levin for his reversing of the new launchd and launchctl. I used the trial version of the Hopper Disassembler/debugger for OS X to figure out the rest.