The problem with M-x compile is that if the Makefile isn't in the current directory, it fails.

I'd like to have a function that recursively goes up to find a Makefile and run make from this directory.

I've seen this question, but it's path-specific, and it's something I have to think about running.

  • If you are using projectile there are ways to compile from projectile-project-root. For instance, github.com/abo-abo/helm-make
    – abo-abo
    Jan 17 '15 at 17:00
  • @abo-abo I hadn't tried projectile! It seems that projectile-compile-project does what I want. But I'd like to have something without this dependency, if possible. Jan 17 '15 at 17:20
  • thanks, projectile-compile-project works for me
    – netawater
    Jan 15 '19 at 6:05

You are looking for the function locate-dominating-file. Here is the emacs documentation for this function:

(locate-dominating-file FILE NAME)

Look up the directory hierarchy from FILE for a directory containing NAME. Stop at the first parent directory containing a file NAME, and return the directory. Return nil if not found. Instead of a string, NAME can also be a predicate taking one argument (a directory) and returning a non-nil value if that directory is the one for which we're looking.

Using this, abo-abo's answer can be shortened to

(defun desperately-compile ()
  "Traveling up the path, find a Makefile and `compile'."
  (when (locate-dominating-file default-directory "Makefile")
    (cd (locate-dominating-file default-directory "Makefile"))
    (compile "make -k"))))
  • Nice! This function does a similar thing to my loop, but in a well-documented and edge-case handling way. I'll make sure to add it to my recipe list, thanks.
    – abo-abo
    Jan 17 '15 at 20:32
  • Nice! vim has a similar function named findfile, I was surprised emacs didn't have it. Jan 17 '15 at 21:00
  • Isn't there something similar to lisp's let? You're running locate-dominating-file twice. Jan 17 '15 at 21:24
  • @FlorianMargaine Yes, you could use let. I was typing the answer in directly without testing and figured this was less likely to have misplaced parentheses :)
    – Pradhan
    Jan 18 '15 at 4:50
  • I wish I could up vote this answer more. Thank you.
    – Erik
    Aug 30 '16 at 20:53

Recursive compile, no dependencies attached:

(defun desperately-compile ()
  "Traveling up the path, find a Makefile and `compile'."
    (while (and (not (file-exists-p "Makefile"))
                (not (equal "/" default-directory)))
      (cd ".."))
    (when (file-exists-p "Makefile")
      (compile "make -k"))))
  • Awesome! This is exactly what I wanted. Jan 17 '15 at 18:20
  • OK, just be careful with the end condition of the loop. If you're on Windows, you might get an endless loop.
    – abo-abo
    Jan 17 '15 at 18:22
  • Side question: why are you using with-temp-buffer? Jan 17 '15 at 18:23
  • Yeah I don't care about windows, but thanks for mentioning it. Jan 17 '15 at 18:23
  • I use with-temp-buffer, because default-directory is buffer-local. I don't want to change it for the current file.
    – abo-abo
    Jan 17 '15 at 18:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.