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. – Florian Margaine 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"))))
| improve this answer | |
  • 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. – Florian Margaine Jan 17 '15 at 21:00
  • Isn't there something similar to lisp's let? You're running locate-dominating-file twice. – Florian Margaine 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"))))
| improve this answer | |
  • Awesome! This is exactly what I wanted. – Florian Margaine 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? – Florian Margaine Jan 17 '15 at 18:23
  • Yeah I don't care about windows, but thanks for mentioning it. – Florian Margaine 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.