我在Emacs下编码OCaml,工作文件夹中有一个makefile
,还有几个包含.ml
个文件的子文件夹。如果我启动M-x compile
并且make
在makefile
的缓冲区上正常工作,但对.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
的文件夹始终设置为编译的默认目录?
答案 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
实现这个。)