如何在Emacs中设置编译的默认目录?

时间:2012-01-27 17:58:17

标签: emacs compilation ocaml

我在Emacs下编码OCaml,工作文件夹中有一个makefile,还有几个包含.ml个文件的子文件夹。如果我启动M-x compile并且makemakefile的缓冲区上正常工作,但对.ml文件的缓冲区无效,则会出错:

-*- mode: compilation; default-directory: "..." -*-
Compilation started at Fri Jan 27 18:51:35

make -k
make: *** No targets specified and no makefile found.  Stop.

Compilation exited abnormally with code 2 at Fri Jan 27 18:51:35

这是可以理解的,因为default-directory是不包含makefile的子文件夹。有谁知道如何将makefile的文件夹始终设置为编译的默认目录?

6 个答案:

答案 0 :(得分:17)

您可以使用正确的参数调用make

make -C .. -k

其中..Makefile

的路径

答案 1 :(得分:8)

您可以通过编写(暂时)设置default-directory并调用compile的函数,在emacs中对此进行控制。

(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))

使用compile-in-parent-directory时,所有ml个文件都将在父目录中编译。当然,如果它们嵌套得更深,你可以改变逻辑来反映这一点。实际上有一个version on the EmacsWiki搜索父目录,直到找到一个makefile。在我写完这个答案之后我发现了这个,否则我会在那里指出你。 叹息。关于我的方法的好处是它不是make特有的,所以你可以对其他命令使用相同的“技巧”。

如果您确切知道命令的内容,也可以将编译调用更改为非交互式。如果它绑定到适当模式钩子中的键,这将特别有效。

答案 2 :(得分:4)

我使用这样的脚本,允许我从任何子目录运行make(假设你处于类似posix的环境中)。只需将此脚本放在PATH中,就像“sub_make.sh”一样,并以调用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 "$@"

答案 3 :(得分:4)

这就是我在我的一些配置中所拥有的:)

(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)))))))

答案 4 :(得分:1)

Matthias Puech在项目根目录中有solution.dir-local文件:

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

大概也可以使用类似(shell-command-to-string "git rev-parse --show-toplevel")之类的东西作为最里面的位。

答案 5 :(得分:0)

不是一个完全通用的解决方案 w.r.t makefile 位置,而是将其添加到此处以供后代使用,因为它解决了我的特定用例。

如果您使用 projectile 并且您的 makefile 始终位于项目目录的根目录中,那么您可以使用 projectile-compile-project

(就我而言,我想对我的项目进行 lint,因此调用 (compile "flake8") 只会从当前缓冲区的目录向下剥落,而我真正想要的是对整个项目进行 linting。projectile-compile-project 实现这个。)