14

I'm trying to get a compile command (rake cucumber) to run with a specific ruby version on my Mac OS X system, I use rvm to do this currently in the terminal. My ~/.MacOSX/environment.plist has the correct path in it, but emacs insists on prepending to this path and therefore making it useless. I've also tried:

(when (equal system-type 'darwin)
  (setenv "PATH" (concat "/Users/fearoffish/.rvm/bin:/Users/fearoffish/.rvm/rubies/ruby-1.8.7-p249/bin:/Users/fearoffish/.rvm/gems/ruby-1.8.7-p249/bin:/Users/fearoffish/.rvm/gems/ruby-1.8.7-p249%global/bin:/Users/fearoffish/.rvm/bin"))
  (push "/Users/fearoffish/.rvm/bin" exec-path)
  (push "/Users/fearoffish/.rvm/rubies/ruby-1.8.7-p249/bin" exec-path)
  (push "/Users/fearoffish/.rvm/gems/ruby-1.8.7-p249/bin" exec-path)
  (push "/Users/fearoffish/.rvm/gems/ruby-1.8.7-p249%global/bin" exec-path)
  (push "/Users/fearoffish/.rvm/bin" exec-path))

It was the desperate attempt of an emacs beginner to get what I wanted. It still prepends in front of it, so my path ends up being:

/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin:/Users/fearoffish/.rvm/bin:/Users/fearoffish/.rvm/rubies/ruby-1.8.7-p249/bin:/Users/fearoffish/.rvm/gems/ruby-1.8.7-p249/bin:/Users/fearoffish/.rvm/gems/ruby-1.8.7-p249%global/bin

I don't want /usr/bin and others prepending, I want my path first and the emacs prepended path to be at the end, I reckon this would fix my problem.

I test this by simply opening Aquamacs and running meta-x compile and then echo $PATH.

Any ideas?

Luke Girvin
  • 13,221
  • 9
  • 64
  • 84
Jamie van Dyke
  • 231
  • 2
  • 8

8 Answers8

10

A small modification to the solution by sanityinc (couldn't find a way to enter it in the comments above -- is that just me?)

  • I use -l option to the shell to force a login shell (which reads .profile or .bash_profile), rather than an interactive shell (which only reads .bashrc).
  • I do some string trimming on the returned path (as inspection shows a newline sneaking in).

Modified code:

(defun set-exec-path-from-shell-PATH ()
  (let ((path-from-shell 
      (replace-regexp-in-string "[[:space:]\n]*$" "" 
        (shell-command-to-string "$SHELL -l -c 'echo $PATH'"))))
    (setenv "PATH" path-from-shell)
    (setq exec-path (split-string path-from-shell path-separator))))
(when (equal system-type 'darwin) (set-exec-path-from-shell-PATH))
Janus
  • 5,421
  • 2
  • 26
  • 37
  • Nice! I tried sanityinc's and was perplexed but your changes fixed it for me! – okonomichiyaki Nov 23 '10 at 20:34
  • @spacemanaki: Actually, I've since switched from Carbon Emacs to Aquamacs (http://aquamacs.org/) which, among many other niceties, gets this right out of the box. It's doesn't feel quite emacsy at first, but it has certainly grown on me. – Janus Nov 24 '10 at 01:26
  • I actually started with Aquamacs when I first got this Macbook in August, but I switched to Carbon Emacs for some reason but I can't remember why. Going back and trying this in Aquamacs was actually what lead to me to check what Emacs thought the PATH was. Thanks again! – okonomichiyaki Nov 25 '10 at 17:04
  • 1
    Yep, the problem with the code in my answer was the trailing whitespace in the shell command output. `string-rtrim` tidies it up more concisely than `replace-regexp-in-string`. For future reference, my up-to-date code for this lives here: https://github.com/purcell/emacs.d/blob/master/init-exec-path.el – sanityinc Dec 07 '11 at 21:10
  • 1
    I'm confused; how does this function affect the compile shell? I'm in a situation where my exec-path is already _right_, but the PATH in the *compilation* buffer is wrong. – Chris R Jan 05 '12 at 05:20
  • `echo` from `gnu coreutils` has `-n` option for trailing newline not to show up. – Mirzhan Irkegulov Jul 26 '12 at 10:56
  • An improved and modified version of the code snippet is now published as elisp library called [exec-path-from-shell](https://github.com/purcell/exec-path-from-shell); installable packages are available in Marmalade and [Melpa](http://melpa.milkbox.net/). – sanityinc Sep 13 '12 at 09:53
10

Everyone seems to have misunderstood the original issue: the path is already setup correctly in Emacs, and the correct path is already passed to the shell started by the compile command! So what gives? Here is the answer:

In MacOS X, there is a small tool called path_helper(1). It is called by default from /etc/profile, which is executed by Bash on shell startup. When you start a compilation from Emacs, it launches a shell (which by default is Bash on MacOS X), and therefore executes this path_helper tool. And here comes the key point: path_helper rearranges your path, moving the standard directories like /usr/bin in front of your custom added directories, no matter where you originally added them. Try this yourself by opening a shell and first having a look at what PATH is, and then execute /usr/lib/path_helper and have look at the resulting PATH!

The brute force solution for you might be to simply comment out the call to path_helper in /etc/profile. Note however that then you won't automatically get the paths in /etc/paths.d setup by path_helper, which is the tool's main purpose.

Markus Miller
  • 3,695
  • 2
  • 29
  • 33
  • 1
    This problem still exists and this answer is correct. I had to edit /etc/zshenv but same idea. To see the distinction, check this out: `(defun my-compile-test () "tests path in compile" (interactive) (compile "echo $SHELL; echo $PATH; exit 1") )` If you define that function and run it, you can get a picture of what is happening _inside_ the *compilation* buffer. Recommend! – Ian Apr 23 '15 at 06:11
  • Sorry about the formatting. Bizarre markdown engine. – Ian Apr 23 '15 at 06:18
2

I don't have a Mac, so I cannot test this directly, but this can all be found in the *info* page Interactive Inferior Shell.

When you start a shell in Emacs, the process that gets spawned is the program in the Emacs variable explicit-shell-file-name (and if that is nil, the environment variables ESHELL and SHELL are used).

It then sends the contents of ~/.emacs_*shellname* (e.g. if your shell is csh, then ~/.emacs_csh would be sent over. Also, the appropriate .rc files for csh program is sourced, so you can update that as well (in my case .cshrc). Additionally, you can wrap customizations in the .rc file with a check for the environment variable INSIDE_EMACS (which which Emacs sets before it runs a shell).

You need to update those files to change the path in the shell, not the Emacs variable exec-path. exec-path - which is just a list of directories Emacs uses to find executable programs. The behavior of the executables are not affected by changes to exec-path.

Trey Jackson
  • 73,529
  • 11
  • 197
  • 229
2

I find the environment.plist scheme on Macs pretty ugly, so I use the following snippet, which assumes you want Emacs to use the same PATH that you see in your Terminal.app:

(defun set-exec-path-from-shell-PATH ()
  (let ((path-from-shell (shell-command-to-string "$SHELL -i -c 'echo $PATH'")))
    (setenv "PATH" path-from-shell)
    (setq exec-path (split-string path-from-shell path-separator))))

(This works for me in Emacs 23; haven't tried it in other versions, but I'd expect it to work.)

sanityinc
  • 15,002
  • 2
  • 49
  • 43
0

I have tried so many different approaches to this that ended up not using emacs to setup my compilation command environment.

What I do now is to create a run_helper.sh file that simply initializes a clean environment and then uses exec $* to execute the command passed as argument to run_helper.sh

This run_helper.sh is usually project specific, but I keep a template which I use to start with when I create a new project.

Then I simple run compile from emacs like bash run_helper.sh rspec path/to/tests for example.

If I am using this to run ruby tests, my helper initializes RVM to use the proper ruby and gemset. If I am using some other language it may just export required environment variables or perform some other initialization, but this way I can do it in bash script instead of always having to mess with emacs paths and elisp every time I start a new project.

Here's an example of a run_helper.sh file

#!/bin/bash

cd /Users/simao/Documents/sp

export DYLD_LIBRARY_PATH="/usr/local/mysql/lib:$DYLD_LIBRARY_PATH"

source "$HOME/.rvm/scripts/rvm" # This loads the proper ruby and gemset from .rvmrc

export RAILS_ENV=test

exec $*

This also makes my tests run faster because I have lots of stuff in my .zshrc that I don't want to load just to run some tests.

simao
  • 14,491
  • 9
  • 55
  • 66
0

It worked for me with two things.

First I followed sanityinc advice

An improved and modified version of the code snippet is now published as elisp library called exec-path-from-shell; installable packages are available in Marmalade and Melpa

I still had a problem with compile commands. Valko Sipuli is right there was a problem involving path_helper.

I commented the corresponding line in /etc/profile and it did not help. Problem still there. I don't use bash but zsh. Digging a little I found /etc/zshenv. This file also calls path_helper.

After commenting the path_helper section in /etc/zshenv my path is finally correct

Aurélien Bottazini
  • 3,249
  • 17
  • 26
0

try this maybe. replace path string with yours.

(add-to-list 'load-path "~/opt/swank-clojure/src/emacs")

Dmitry
  • 89
  • 3
0

As far as I observed, Emacs takes the path variable from the shell it is launched from, so one solution is to change $PATH in the shell before you launch Emacs.

One other approach I used, which is more flexible, is to use a Makefile and append a "source ~/script_that_set_path" in front of each make commands you have.

polyglot
  • 9,945
  • 10
  • 49
  • 63
  • 1
    On a Mac, that's not the case; GUI programs launched from Finder don't inherit the environment of the desktop or the user's shell. – sanityinc Feb 16 '10 at 17:47
  • Ah sorry but I never used a Mac; my observation only pertains to windows and linux. Does starting Emacs from terminal (or equivalents in Mac) work? I would (again) suggest trying the Makefile method since that's the only way I found that reliably works (I also struggled a lots with getting PATH right for compilation). – polyglot Feb 16 '10 at 17:59