Môi trường bền bỉ cho biên dịch Mx


8

Khi tôi chạy M-x compilenó sẽ sinh ra một lớp con mới để thực thi lệnh biên dịch của tôi. Ngay khi lệnh biên dịch trở lại, tiến trình shell bị hủy. Tôi có thể thấy lý do tại sao điều này sẽ được mong muốn trong hầu hết các trường hợp, nhưng tôi hiện đang ở trong một tình huống mà nó không hữu ích.

Tôi đang làm việc trong một môi trường xây dựng chuyên biệt ngay bây giờ đòi hỏi tôi phải thực hiện một số bước ban đầu để thiết lập bản dựng trước khi chạy trình biên dịch. Miễn là môi trường vẫn tồn tại, tôi chỉ cần thực hiện các bước thiết lập một lần. Nhưng khi tôi sử dụng M-x compilenó có nghĩa là tôi phải thực hiện các bước mỗi lần tôi muốn biên dịch hoặc biên dịch lại.

Có cách nào để tôi có thể sinh ra một lớp con sẽ tồn tại trong nền không? Một cái M-x compileM-x gdbcó thể sử dụng mỗi lần họ cần chạy tiến trình shell?


Động lực:

Tôi có một chương trình (mà chúng tôi sẽ gọi xcc) xây dựng mã C cho các nền tảng đặc biệt. Để xây dựng mã của tôi, trước tiên tôi bắt đầu xcctừ tcshdấu nhắc:

$ xcc

Chương trình mất hơn 10 giây để tải và sau đó tôi có thể nhập các lệnh tại dấu nhắc tương tác của nó

xcc>> add target myprogram
xcc>> set source myprogram $PROJDIR/src/
xcc>> set includes myprogram $PROJDIR/include/
xcc>> set type myprogram primitive
xcc>> set inputs myprogram int8,int8
xcc>> set outputs myprogram fix16,fix16
xcc>> build myprogram

Các bước trên có thể được xây dựng thành một macro tùy chỉnh buildmyprog.macrođể tôi có thể chạy nó trực tiếp từ trình bao hoặc từ emacs vớiM-x compile

$ xcc buildmyprog.macro

Vấn đề chính với cách tiếp cận này là thực tế là phải mất xcc10 giây để tải chương trình, trước khi quá trình biên dịch bắt đầu. Tôi đã quá mệt mỏi khi phải chờ thêm 10 giây mỗi lần tôi biên dịch rằng tôi đã bắt đầu chạy xcctrong một ansi-termbộ đệm riêng. Bây giờ sau khi tôi sửa đổi và lưu mã, tôi chuyển sang ansi-termbộ đệm và chạy

xcc>> build myprogram

Điều này hoạt động tốt, nhưng mỗi khi tôi chuyển sang bộ đệm đó, tôi nghĩ, "Sẽ không hay nếu tôi có thể đẩy F7và lệnh biên dịch của tôi sẽ được gửi đến phiên bản đã chạy của xcc?"


Thiết lập của bạn có ảnh hưởng gì đến môi trường? Biến môi trường, file tạm thời?
T. Verron

Môi trường là chương trình riêng của nó. Mặc dù nó sử dụng một số biến môi trường và các tệp tạm thời, nhưng chương trình tự duy trì các trạng thái nội bộ của chính nó sẽ biến mất khi chương trình đóng lại.
nispio

3
Dựa trên chỉnh sửa, tôi nghĩ bạn cần một comintchế độ dẫn xuất cho môi trường của bạn. Nếu bạn đang cảm thấy phiêu lưu, đây là một hướng dẫn để viết.
Vamsi

@Vamsi Tôi đang cảm thấy mạo hiểm, và đó có vẻ là một người dẫn tuyệt vời. Cảm ơn.
nispio

1
Cách dễ nhất và bẩn nhất để gửi lệnh đến bộ đệm comint là chèn nó vào bộ đệm và gọi comint-send-input. Về cơ bản, đó là những gì bạn đang làm bằng tay, chuyển đổi nó thành elisp không nên rất khó khăn (đặc biệt là so với việc thiết lập comint).
T. Verron

Câu trả lời:


2

Bạn có thể thực hiện thiết lập trong shell của bạn trước khi bạn bắt đầu emacs không? Vỏ compilephụ nên kế thừa môi trường từ ông bà của nó thông qua emacs.


1
Hãy tưởng tượng rằng "môi trường" mà tôi đang chạy là Python. (Nó không phải là Python.) Mặc dù tôi có thể bắt đầu Emacs tạo trình thông dịch Python, M-x compilenhưng không gửi các lệnh của nó trở lại trình thông dịch python.
nispio

0

Sử dụng một vỏ thực tế bên trong Emacs sau đó, như eshellhoặc ansi-term. Bạn nên sử dụng compileđể biên dịch, mặc dù nó có thể được sử dụng để thực thi bất kỳ lệnh nào.

Tôi không nghĩ rằng nó có thể với lệnh biên dịch, nhưng có lẽ tôi đang thiếu một cái gì đó. Nếu không, bạn có thể đặt mọi bước thiết lập vào tập lệnh shell và thực thi tập lệnh đó với M-x compile.


3
Vâng, có, nhưng câu hỏi là làm thế nào để nối nó với M-x compilehoặc một số lệnh thay thế sẽ biên dịch tệp hiện tại.
Gilles 'SO- ngừng trở nên xấu xa'

@Gilles OP muốn có một môi trường shell nhất quán giữa M-x compilecác cuộc gọi và đó là những gì một shell thực sự làm. Tôi không nghĩ rằng nó có thể với lệnh biên dịch, nhưng có lẽ tôi đang thiếu một cái gì đó. Mặt khác, OP có thể đặt mọi bước thiết lập vào tập lệnh shell và thực thi tập lệnh đó vớiM-x compile
Tu Do

Tôi không chắc tôi hiểu đề nghị đầu tiên của bạn. Bạn đang nói "Sử dụng eshellcho những thứ vỏ và compilecho những thứ biên dịch"? Điều đó đánh bại toàn bộ điểm.
nispio

Tôi đã thử đề nghị thứ hai, nhưng có một vài vấn đề. (Điều này dẫn tôi đến việc đăng câu hỏi này.) Nó quá chậm vì nó thêm rất nhiều chi phí phụ cho mỗi lần biên dịch. Điều này là không cần thiết, bởi vì tôi chỉ phải thiết lập môi trường một lần. Nó cũng kết thúc không đủ năng động, bởi vì tôi không thể điều chỉnh một điều trong enConnionment hiện tại và thử biên dịch lại. Môi trường xây dựng là một chương trình, vì vậy tôi không thể viết một kịch bản shell để kiểm soát nó. Tôi phải viết một kịch bản macro được biên dịch cho môi trường và bao gồm chính lệnh biên dịch trong macro.
nispio

0

Một giải pháp khả thi là có một trình thông dịch cố định sống trong một bộ đệm chuyên dụng (giống như *compilation*bộ đệm, nhưng trong đó quy trình cơ bản sẽ không bao giờ quay trở lại). Sau đó, bạn có thể có một recompilelệnh giống như để gửi một lệnh biên dịch được xác định trước cho trình thông dịch và hiển thị kết quả.

Dưới đây là một thực hiện dự kiến ​​của một chiến lược như vậy. Các persistent-compilelệnh cần chăm sóc cả hai khởi của quá trình này (khi nó được gọi là lần đầu tiên hoặc với một đối số tiền tố), và biên dịch lại (nếu quá trình thông dịch viên đã được lên và chạy). Kết quả biên dịch được hiển thị trong *persistent-compilation*bộ đệm, đưa vào compilation-shell-minor-modeđể hưởng lợi từ các compilation-modetính năng thông thường để điều hướng giữa các lỗi.

Dưới đây là một ví dụ sử dụng, cùng với nội dung kết quả của *persistent-compilation*bộ đệm:

  1. M-xpersistent-compileRET /bin/bashRET FOO=barRET echo $FOORET

    $ FOO=bar
    $ echo $FOO
    bar
    $
    
  2. M-xpersistent-compileRET

    $ echo $FOO
    bar
    $
    

Coi chừng, đoạn mã sau không được kiểm tra nhiều. Ví dụ: tôi không chắc điều gì sẽ xảy ra khi bạn thử biên dịch lại trước khi kết thúc quá trình biên dịch trước đó.

(defvar persistent-compile-interpreter "/bin/bash"
  "Interpreter to be used for persistent compilations.")

(defvar persistent-compile-init ""
  "Initialization command for persistent compilations.")

(defvar persistent-compile-command "make -k"
  "Compilation command for persistent compilations.")

;; Local variable in the persistent compilation buffer
(defvar persistent-compile--next-action)

(defun persistent-compile (&optional edit-command)
  "(Re-)run a persistent compilation.

The first time a persistent compilation is run, the user is asked
for an interpreter, an initialization command and a compilation
command.
The interpreter is started and optionally set up with the
initialization command.  The compilation command is then sent to
the interpreter.

All subsequent recompilations are sent to the same,
already-initialized interpreter, so as to keep the customized
environment.

If EDIT-COMMAND is non-nil, the user can edit the
parameters (interpreter, initialization command and compilation
command) and the interpreter is restarted."
  (interactive "P")
  (when (or edit-command
            (null (get-buffer "*persistent-compilation*"))
            (not persistent-compile-interpreter)
            (not persistent-compile-init)
            (not persistent-compile-command))
    (setq persistent-compile-interpreter (read-from-minibuffer "Interpreter: "
                                                               persistent-compile-interpreter)
          persistent-compile-init        (read-from-minibuffer "Initialization command: "
                                                               persistent-compile-init)
          persistent-compile-command     (read-from-minibuffer "Command: "
                                                               persistent-compile-command)))
  (with-current-buffer (get-buffer-create "*persistent-compilation*")
    (if (and edit-command
             (get-buffer-process (current-buffer)))
        ;; Kill an existing process and schedule for a recompilation with
        ;; the new parameters
        (progn
          (set-process-sentinel
           (get-buffer-process (current-buffer))
           (lambda (process event)
             (persistent-recompile nil)))
          (kill-process (get-buffer-process (current-buffer))))

      (if (not (get-buffer-process (current-buffer)))
          ;; Start and initialize a new process
          (progn
            (erase-buffer)
            (make-comint-in-buffer "persistent-compile" (current-buffer) persistent-compile-interpreter)
            (compilation-shell-minor-mode 1)
            (make-local-variable 'persistent-compile--next-action)
            (setq persistent-compile--next-action 'persistent-compile--initialize)
            (add-hook 'comint-output-filter-functions 'persistent-compile--at-prompt))

        ;; Run command
        (erase-buffer)
        (persistent-compile--send-command)))))

(defun persistent-compile--at-prompt (&optional output)
  (when persistent-compile--next-action
    ;; There is probably a better way of checking whether we are
    ;; just after a prompt, but I didn't find it...
    (let ((p1 (point))
          (p2 (save-excursion (comint-bol))))
      (unless (= p1 p2)
        (let ((action persistent-compile--next-action))
          (setq persistent-compile--next-action nil)
          (funcall action))))))

(defun persistent-compile--initialize ()
  (setq persistent-compile--next-action 'persistent-compile--send-command)
  (display-buffer (current-buffer))
  (insert persistent-compile-init)
  (comint-send-input nil t))

(defun persistent-compile--send-command ()
  (display-buffer (current-buffer))
  (insert persistent-compile-command)
  (comint-send-input nil t))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.