Why don't I see a path to etags in PATH when running Emacs from http://emacsformacosx.com/ from the OS X dock? This is a follow-up question to the one at "Is /usr/bin/etags severely out of date in Yosemite?"

The Emacs in question is from http://emacsformacosx.com/ (GNU Emacs 24.4.1 (x86_64-apple-darwin13.4.0, NS apple-appkit-1265.21) of 2014-10-20 on builder10-9.porkrind.org).

If I start Emacs from the dock, then I don't see in PATH:

/Applications/Emacs.app/Contents/MacOS/bin-x86_64-10_9:/Applications/Emacs.app/Contents/MacOS/libexec-x86_64-10_9


If I use the script described at http://emacsformacosx.com/tips then I do see the above entries in PATH. But even in this case, /usr/bin comes first in PATH.  To use the etags found in /Applications/Emacs.app/Contents/MacOS/bin-x86_64-10_9 I have to give it precedence in some manner. I typically want to run etags in a shell script that is started in the Emacs shell buffer.

Why don't I see these PATH entries when I start Emacs from the OS X dock (I'm using OS X Yosemite)?

At /Applications/Emacs.app/Contents/MacOS/Emacs I read:

Emacs.app sticks Emacs.app/Contents/MacOS/{bin,libexec} on the end of
the PATH when it starts, so if we stick our own architecture dependent
paths on the end of the PATH then they will override Emacs's paths
while not affecting any user paths.
This looks like an OS X bug coupled with different undefined behavior in Ruby and Emacs.

The root cause is that when launching Emacs from Finder, OS X is passing the PATH environment variable to the process twice! I wrote a test case and submitted it to Apple's bug reporter (id 19801095). Here's my test case:

#!/bin/bash

mkdir -p /tmp/test.app/Contents/MacOS/

cat &gt; /tmp/test.app/Contents/MacOS/test &lt;&lt;EOF
#!/usr/bin/env ruby
\$stdout.reopen('/tmp/test.app.log', "w")
ENV.each_pair {|k,v| puts "#{k}=#{v}" if k == 'PATH' }
EOF
chmod +x /tmp/test.app/Contents/MacOS/test

launchctl setenv PATH "Extra PATH"
open -W /tmp/test.app
cat /tmp/test.app.log
launchctl unsetenv PATH


If you save that and then run it from the Terminal then it will print:

PATH=/usr/bin:/bin:/usr/sbin:/sbin
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
PATH=Extra PATH


This only happens on 10.10. 10.9 will only print one PATH.

So that is the root cause. What's actually happening? The Emacs from http://emacsformacosx.com uses a Ruby launcher script so that it can ship a binary that runs optimally on OS X installs from 10.6 to 10.10. This launcher script manipulates the PATH:

ENV['PATH'] += ':' + File.join(base_dir,     "bin-#{arch_version}") +
               ':' + File.join(base_dir, "libexec-#{arch_version}")


So ENV['PATH'] only manipulates the first instance of PATH in the list. When Emacs launches, it only pays attention to the last instance of PATH. Which on is right? Well, POSIX talks about this case in the spec:


  If more than one string in an environment of a process has the same name, the consequences are undefined.


That means that neither of these programs are technically in the wrong.

Ok, so why does it behave differently from Terminal? That's because something is filtering out the duplicate PATHs in the environment when you are running from Terminal. I suspect bash. But it could also be Terminal.app. Either way, there's only one PATH in the environment and so the Ruby launcher and Emacs communicate correctly.

So what's the solution then? I think the Ruby launcher needs to change to deal with this, since it appears to be the default behavior in 10.10. That's a shame, since it's just more cruft. Luckily (as you can see from the above test script), Ruby can get to both PATHs so it can filter out everything but the last instance which would make it work the same way Emacs works.

Edit: There's now a bug report on the Emacs build project

Edit: This is now fixed. Nightly builds after February 11th and releases beginning with 24.5 should work (24.5 is currently a pretest but should be released shortly).