Как установить default-каталог компиляции в Emacs? - PullRequest
17 голосов
/ 27 января 2012

Я кодирую 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 всегда как каталог по умолчанию для компиляции?

Ответы [ 5 ]

17 голосов
/ 27 января 2012

Вы можете позвонить make с правильными аргументами:

make -C .. -k

где .. - путь к вашему Makefile

8 голосов
/ 28 января 2012

Вы можете управлять этим изнутри 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 голосов
/ 30 января 2012

Вот что у меня есть в некоторых моих конфигах :)

(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 голосов
/ 27 января 2012

Я использую такой скрипт, который позволяет мне запускать 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 "$@"
1 голос
/ 14 марта 2015

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") в качестве самого внутреннего бита.

...