How to set the default-directory of compilation in Emacs?

孤者浪人 提交于 2019-12-03 22:43:24

Matthias Puech has a solution involving a .dir-local file in the project root directory:

((nil . ((eval . (setq default-directory 
                  (locate-dominating-file buffer-file-name
                   ".dir-locals.el")
)))))

It is presumably also possible to use something like: (shell-command-to-string "git rev-parse --show-toplevel") as that innermost bit.

You can call make with the right arguments:

make -C .. -k

where .. is the path to your Makefile

You can control this from within emacs by writing a function that (temporarily) sets default-directory and calls compile.

(defun compile-in-parent-directory ()
  (interactive)
  (let ((default-directory
          (if (string= (file-name-extension buffer-file-name) "ml")
              (concat default-directory "..")
            default-directory))))
  (call-interactively #'compile))

When using compile-in-parent-directory all ml files will be compiled in the parent directory of where they are. Of course if they are nested deeper you can change the logic to reflect that. In fact there is a version on the EmacsWiki which searches parent directories until it finds a makefile. I found this after I wrote this answer, otherwise I would have just pointed you there. sigh. The good thing about my method is that it's not specific to make so that you can use the same "trick" for other commands.

You can also change the call to compile to be non-interactive if you know exactly what you want the command to be. This would work particularly well if it's bound to a key in the appropriate mode hook.

i use a script like this which allows me to run make from any sub-directory (assuming you are in a posix-like environment). just put this script in your PATH as something like "sub_make.sh" and invoke it the same way you would invoke make:

#!/bin/bash

# search for project base
INIT_DIR=`pwd`
while [ "$PWD" != "/" ] ; do
  if [ -e "makefile" ] ; then
    break
  fi

  cd ..
done

if [ ! -e "makefile" ] ; then
  echo "Couldn't find 'makefile'!"
  exit 1
fi

# indicate where we are now
echo "cd "`pwd`
echo make "$@"

# now run make for real
exec make "$@"

That's what I have in some of my configs :)

(defun* get-closest-pathname (&optional (max-level 3) (file "Makefile"))
  (let* ((root (expand-file-name "/"))
         (level 0)
         (dir (loop
               for d = default-directory then (expand-file-name ".." d)
                 do (setq level (+ level 1))
               if (file-exists-p (expand-file-name file d))
                 return d
               if (> level max-level)
                 return nil
               if (equal d root)
                 return nil)))
    (if dir
        (expand-file-name file dir)
      nil)))

(add-hook 'c-mode-hook
          (lambda ()
            (unless (file-exists-p "Makefile")
              (set (make-local-variable 'compile-command)
                   (let ((file (file-name-nondirectory buffer-file-name))
                         (mkfile (get-closest-pathname)))
                     (if mkfile
                         (progn (format "cd %s; make -f %s"
                            (file-name-directory mkfile) mkfile))
                       (format "%s -c -o %s.o %s %s %s"
                               (or (getenv "CC") "gcc")
                               (file-name-sans-extension file)
                               (or (getenv "CPPFLAGS") "-DDEBUG=9")
                               (or (getenv "CFLAGS") "-ansi -pedantic -Wall -g")
                               file)))))))
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!