Monday, July 09, 2007

Changing your PATH in Emacs' compilation mode

[UPDATE: This is not really wrong, but not really right either. See below.]

I was a bit surprised at this problem, but I suppose most people use standard make or gcc to build... I want to build my project with a version of OMake that I have compiled and installed in my home directory. I have ~/tools/bin in my PATH, but for some reason M-x compile still gives me

/bin/bash: omake: command not found

The trick is that Emacs invokes the compile command in a non-interactive, non-login shell, which means that neither your .bash_profile nor your .bashrc (or any variations thereof) are going to get read.* The workaround is to set BASH_ENV to point to a script file that sets your PATHbash reads the file pointed-to by BASH_ENV in non-interactive mode. Here's my solution:

~/.bash_profile:
. ~/.bashrc

~/.bashrc:
export BASH_ENV=~/.bash_env
. "$BASH_ENV"

~/.bash_env:
export PATH=/home/chris/tools/bin:$PATH

There's probably a good reason why this is a bad idea, but it works.

* A quick refresher course: .bash_profile is for login shells; .bashrc is for interactive, non-login shells; BASH_ENV is for non-interactive, non-login shells (which, confusingly, will probably be a sub-process of an interactive and/or login shell, which is why the above example works).

[UPDATE] The compilation shell being non-interactive and non-login is a red herring. While this is certainly the case, a non-interactive, non-login shell will inherit the environment of it's parent process. So, for instance, if your PATH is properly set in your shell and you invoke Emacs from the command line, things should be fine.

What was really causing my problem is that I was invoking Emacs from the Gnome Panel. The environment that Emacs inherits in this case is Gnome's, not Bash's. How do you change the PATH in the Gnome environment? Um... Eh... gnome-session-properties? .gnomerc?

The solution I've settled on is to create a .xsession file as follows,
~/.xsession:
#! /usr/bin/bash

if [ -f ~/.bash_env ]; then
. ~/.bash_env
fi

exec gnome-session

where .bash_env is as above.

NOTE: If you leave off the last line, your X session will end before it begins. The .xsession script is the X process: when it ends, the X process ends. Execing gnome-session replaces the script process with the Gnome session process.

[UPDATE 2] Of course, another option is to just use setenv in your .emacs file. TMTOWTDI, in Emacs and Perl alike.

2 comments:

Anonymous said...

of course the goal of this should be to have the path you want in one place, i.e. not repeated in .bashrc and .emacs. I'd therefore slightly favor the sourcing of .bashrc from your .xsession but that sure seems heavy handed.

Chris said...

Craig, I agree: .xsession is the way to go. The only thing in my .bash_env is some path munging, so heavy-handedness really isn't a problem.