25

Having some issues with PATH settings on Emacs that are affecting my Haskell environment:

I'm using ZSH, and when I go to the command line and call echo $PATH, it returns: /Users/g/Library/Haskell/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin

This is coming from .zprofile configuration where I have:

# Set the list of directories that Zsh searches for programs.
path=(
  ~/Library/Haskell/bin
  /usr/local/{bin,sbin}
  $path
)

So, from command line, when I call which cabal, I correctly get: /Users/g/Library/Haskell/bin/cabal

When I start Emacs and go to the shell and call which cabal, I get: /usr/bin/cabal which is causing me issue since it's a different version.

When I inspect echo $PATH from the Emacs shell, I see: /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/g/Library/Haskell/bin:/usr/local/sbin

I've no idea how on earth the PATH can be different...

Anyone knows how to get my ZSH shell and Emacs to agree on the same PATH? I suspect that's what's controlling where cabal is being loaded from.

UPDATE: Running echo $SHELL from Emacs prints: /bin/zsh

UPDATE 2: This is on OSX.

UPDATE 3: I have tried to use exec-path-from-shell module and it does not work. I still have same issues, and as a side effect, it messes up my terminal theme colours :(

UPDATE 4: I've installed Emacs via brew install --cocoa --srgb emacs and I run emacs that's linked this way:

~ ❯❯❯ which emacs
/usr/local/bin/emacs
~ ❯❯❯ l /usr/local/bin/emacs
lrwxr-xr-x  1 g  admin    30B 29 Jan 18:34 /usr/local/bin/emacs -> ../Cellar/emacs/24.4/bin/emacs
~ ❯❯❯ l /usr/local/Cellar/emacs/24.4/bin/emacs
-r-xr-xr-x  1 g  admin    87B 29 Jan 18:34 /usr/local/Cellar/emacs/24.4/bin/emacs
Galder Zamarreño
  • 1,527
  • 2
  • 12
  • 21

7 Answers7

27

You can also install exec-path-from-shell package and add this to your init file:

(exec-path-from-shell-initialize)
Basak
  • 441
  • 1
  • 3
  • 8
11

This is an OSX annoying environment issue, the $PATH appearing in Emacs is coming from /etc/paths file, which then gets appended with whatever I've set in the shell. I added /Users/g/Library/Haskell/bin to the top of the /etc/paths file and it then worked fine.

Going into shell and calling echo $PATH in Emacs shows now: /Users/g/Library/Haskell/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/sbin

And cabal's version is indeed cabal-install version 1.22.2.0 :D

Thanks all!!

Galder Zamarreño
  • 1,527
  • 2
  • 12
  • 21
  • Thanks to beOn for his hints in this `$PATH` on OSX [post](http://stackoverflow.com/questions/9832770/where-is-the-default-terminal-path-located-on-mac). – Galder Zamarreño Apr 17 '15 at 07:18
  • 2
    A better solution is to modify path in `~/.zshenv`. Changes there are reflected in Emacs' PATH – Galder Zamarreño Apr 24 '15 at 15:57
  • I can confirm that simply doing `echo export PATH=$PATH > ~/.zshenv` makes Emacs' `M-x shell` pick it up on the next invocation. – Linus Arver Aug 16 '16 at 21:35
  • In 2020, OSX Mojave 10.14.6 doesn't appear to set the Mac Emacs path per the /etc/paths file. A Mac Emacs subshell does seem to have run ~/.bashrc but not ~/.profile_bash, so you could set it in ~/.bashrc – Dave X May 15 '20 at 01:31
6

If you start emacs from your GUI environment (gnome, kde, ...) your shell startup scripts will not be sourced into your environment. So the $PATH that you carefully set in your .zsh will not be loaded. GUI environments do not generally source these, though they may load your ~/.profile file.

You can try adding this to your .pam_environment:

PATH DEFAULT=${PATH}:/MYHOMEDIR/Library/Haskell/bin:/usr/local/bin:/usr/local/sbin

You will need to restart your GUI session to load it.

This document might help you to get your $PATH variable set properly:

https://help.ubuntu.com/community/EnvironmentVariables#Session-wide_environment_variables

I use the ~/.pam_environment file to managed environment variables that I need to be accessible from my shell or emacs processes.

PS: An astute commenter points out that you are probably on Mac. I don't know how to set up your $PATH in the Mac GUI, but the point still stands regarding the difference between your shell's environment and the GUI environment. How you set up the $PATH for the GUI seems to depend on the OS version. However you can use:

(setenv "PATH" (concat (getenv "PATH") ":/foo/bar"))

in your ~/.emacs.d/init if you just want a solution that should work.

PPS: If you want to run a shell in emacs, you are probably better off using ansi-term rather than shell.

Erik Hetzner
  • 765
  • 3
  • 6
3

If some part of the PATH gets lost then you can add it in your ~/.emacs

;;; We add /path/to/something/extra by appending it to the path
(setenv "PATH" (concat (getenv "PATH") ":/path/to/something/extra"))
;;; /path/to/something/extra is now at the end of the PATH.
;;; or you can use:
;(setenv "PATH" (concat "/path/to/something/extra:" (getenv "PATH")))
;;; /path/to/something/extra is now at the beginning of the PATH.

To avoid PATH issues, I always start emacs from the command line with the PATH exported from ~/.bashrc.

m43cap
  • 183
  • 4
3

Another way to accomplish this is to simply tell the shell that it's a login shell so that it sources all of the right files. I do this for bash by setting explicit-bash-args to ("--noediting" "--login"). It looks like the equivalent for zsh would be to set explicit-zsh-args to ("-l").

So in my .emacs:

(setq explicit-bash-args '("--noediting" "--login"))

In yours, something like:

(setq explicit-zsh-args '("-l"))

I think the "--noediting" is unnecessary, and there doesn't seem to be a way to tell zsh about this, but that might be something to investigate if this doesn't work as well as you'd hope.

Drew
  • 75,699
  • 9
  • 109
  • 225
Ted Lemon
  • 31
  • 2
  • 1
    This works for a shell run under Emacs. It does not work for commands run directly within Emacs, such as via `M-x shell-command`. – mernst Jul 30 '18 at 18:41
1

You can also set an OS X-wide default path by for example saving a property list like this as ~/Library/LaunchAgents/my.startup.plist:

<?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>my.startup</string>
  <key>ProgramArguments</key>
  <array>
    <string>sh</string>
    <string>-c</string>
    <string>launchctl setenv PATH /usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin</string>
  </array>
  <key>RunAtLoad</key>
  <true/>
</dict>
</plist>

The new path should be shown in shells, Emacs, and other applications after you log out and back in.

This method does not change the path in applications that are opened as login items or when applications are reopened at login after a forced shutdown. If you have Emacs, a terminal application, or other applications where you want to change the path in login items, you'll have to remove them.

In 10.9 and earlier you can also add a line like this to /etc/launchd.conf:

setenv PATH /usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin

However support for /etc/launchd.conf was removed in 10.10.

nisetama
  • 241
  • 2
  • 4
0

The given solutions didn't work for me. The reason is the latest Emacs compiled with --with-native-compilation picks up the PATH before loading init.el (to start compiling the packages with gcc).

This solution works if you put it into early-init.el.

(defun set-exec-path-from-shell-PATH ()
  "Set up Emacs' `exec-path' and PATH environment variable to match
that used by the user's shell.

This is particularly useful under Mac OS X and macOS, where GUI
apps are not started from a shell."
  (interactive)
  (let ((path-from-shell (replace-regexp-in-string
              "[ \t\n]*$" "" (shell-command-to-string
                      "$SHELL --login -c 'echo $PATH'"
                            ))))
    (setenv "PATH" path-from-shell)
    (setq exec-path (split-string path-from-shell path-separator))))

(set-exec-path-from-shell-PATH)

Taken from https://www.emacswiki.org/emacs/ExecPath.

Nek
  • 121
  • 2