Как установить каталог компиляции по умолчанию в Emacs?
Я кодирую OCaml под Emacs, у меня есть один 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
Это понятно, потому что каталог по умолчанию - это подпапка, которая не содержит makefile
. Кто-нибудь знает, как установить папку makefile
всегда как каталог компиляции по умолчанию?
Ответы
Ответ 1
У Matthias Puech есть решение с участием файла .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")
как самый внутренний бит.
Ответ 2
Вы можете вызвать make
с помощью правильных аргументов:
make -C .. -k
где ..
- путь к вашему Makefile
Ответ 3
Вы можете управлять этим из emacs, написав функцию, которая (временно) устанавливает default-directory
и вызывает 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))
При использовании compile-in-parent-directory
все файлы ml
будут скомпилированы в родительском каталоге, где они есть. Конечно, если они вложены глубже, вы можете изменить логику, чтобы отразить это. На самом деле существует версия в EmacsWiki, которая ищет родительские каталоги, пока не найдет make файл. Я нашел это после того, как написал этот ответ, иначе я бы просто указал вам туда. вздох. Хорошая вещь о моем методе заключается в том, что он не специфичен для make
, так что вы можете использовать тот же "трюк" для других команд.
Вы также можете изменить вызов, чтобы компилировать, чтобы быть неинтерактивным, если вы точно знаете, какой именно должна быть команда. Это будет работать особенно хорошо, если оно связано с ключом в соответствующем режиме.
Ответ 4
Я использую script, как это, что позволяет мне запускать make из любого подкаталога (при условии, что вы находитесь в среде, подобной posix). просто поместите этот script в свой 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 "[email protected]"
# now run make for real
exec make "[email protected]"
Ответ 5
То, что у меня есть в некоторых моих конфигах:)
(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)))))))