Converting relative paths to absolute ones correctly

Mar 1, 2013

Just a quick post about an annoying quirk that Emacs has and a way around it.

Similar to most interpreted languages (well, similar to python anyway, which is the other place where I recently faced this problem) elisp doesn’t really treat relative paths the way one might expect it to. Instinctively, I expect a relative path specified in a script to be relative to that script under all circumstances. However, in elisp and python both, the path is consistently relative to the CWD of the executing code. So, if I have a relative path in a function inside script A and I call that function from a script B, the path will be relative to B and not A.

The workaround to this in Python is the __FILE__ variable. And the corresponding workaround in Elisp is supposed to be load-file-name, but that one is only set when the file is being load-ed. Notice that I said load-ed and not just loaded. That’s because the load I’m referring to is what happens when you require or load-file that file. That’s the only point at which that variable is set, and at no other time does it have a useful value.

So, my first attempt to harness the power of load-file-name ended in disaster, because it would consistently be nil. The solution is to set it to a variable with defvar so that it’ll be initialized when the variable is declared, which is when the file is being loaded. And after that, you just use your local variable.

The code I’m using to get the path of my master script is as follows:

(defvar pyclang-path (file-name-directory load-file-name))

And after that, whenever I’m specifying paths relative to that master file, I just use concat. For example:

(require 'concurrent (concat pyclang-path "emacs-deferred/concurrent.el"))

Simple, but really hard to figure out on your own.