Lingkungan persisten untuk kompilasi Mx


8

Ketika saya menjalankannya M-x compilememunculkan subkulit baru untuk menjalankan perintah kompilasi saya. Segera setelah perintah kompilasi kembali, proses shell terbunuh. Saya dapat melihat mengapa hal ini diinginkan dalam kebanyakan kasus, tetapi saya saat ini dalam situasi di mana itu tidak membantu.

Saya bekerja di lingkungan build khusus sekarang yang mengharuskan saya mengambil beberapa langkah awal untuk mengatur build sebelum menjalankan compiler. Selama lingkungan masih ada, saya hanya perlu melakukan langkah-langkah pengaturan sekali. Tetapi ketika saya menggunakannya M-x compileberarti saya harus melakukan langkah-langkah setiap kali saya ingin mengkompilasi atau mengkompilasi ulang.

Apakah ada cara agar saya dapat menelurkan subkulit yang akan bertahan di latar belakang? Satu itu M-x compiledan M-x gdbdapat menggunakan setiap kali mereka perlu menjalankan proses shell?


Motivasi:

Saya punya program (yang akan kita sebut xcc) yang membangun kode C untuk platform khusus. Untuk membangun kode saya, saya mulai xccdari tcshprompt:

$ xcc

Program ini membutuhkan waktu 10+ detik untuk memuat, dan kemudian saya dapat memasukkan perintah pada prompt interaktifnya

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

Langkah-langkah di atas dapat dibangun menjadi makro kustom buildmyprog.macrosehingga saya bisa menjalankannya langsung dari shell, atau dari emacs denganM-x compile

$ xcc buildmyprog.macro

Masalah utama dengan pendekatan ini adalah kenyataan bahwa xccprogram butuh 10 detik untuk memuat, bahkan sebelum kompilasi dimulai. Saya cukup lelah menunggu 10 detik tambahan setiap kali saya kompilasi bahwa saya sudah mulai berjalan xccdi ansi-termdalam buffer terpisah. Sekarang setelah saya memodifikasi dan menyimpan kode, saya beralih ke ansi-termbuffer dan menjalankan

xcc>> build myprogram

Ini berfungsi dengan baik, tetapi setiap kali saya beralih ke buffer itu saya pikir, "Bukankah lebih bagus jika saya bisa mendorong F7dan perintah kompilasi saya akan dikirim ke instance yang sudah berjalan xcc?"


Apa efek pengaturan Anda terhadap lingkungan? Variabel lingkungan, file sementara?
T. Verron

Lingkungan adalah programnya sendiri. Sementara itu memang menggunakan beberapa variabel lingkungan dan file sementara, program itu sendiri mempertahankan status intenral sendiri yang hilang ketika program ditutup.
nispio

3
Berdasarkan hasil edit, saya pikir Anda memerlukan comintmode turunan untuk lingkungan Anda. Jika Anda merasa ingin bertualang, berikut ini panduan untuk menulisnya.
Vamsi

@Vamsi Aku sedang merasa petualang, dan yang terlihat seperti memimpin besar. Terima kasih.
nispio

1
Cara termudah dan paling kotor untuk mengirim perintah ke buffer comint adalah memasukkannya ke buffer dan menelepon comint-send-input. Itu pada dasarnya apa yang Anda lakukan dengan tangan, mengubahnya menjadi elisp seharusnya tidak terlalu sulit (terutama dibandingkan dengan menyiapkan comint).
T. Verron

Jawaban:


2

Bisakah Anda melakukan pengaturan di shell Anda sebelum Anda memulai emacs? The compilesub-shell harus mewarisi lingkungan dari kakek-nenek nya melalui emacs.


1
Bayangkan bahwa "lingkungan" yang saya jalankan adalah Python. (Ini bukan Python.) Meskipun saya mungkin dapat memulai Emacs dari juru bahasa Python, M-x compiletidak mengirim perintahnya kembali ke juru bahasa python.
nispio

0

Gunakan shell aktual di dalam Emacs kemudian, suka eshellatau ansi-term. Anda harus menggunakannya compileuntuk kompilasi, meskipun itu dapat digunakan untuk menjalankan perintah apa pun.

Saya tidak berpikir itu mungkin dengan perintah kompilasi, tapi mungkin saya kehilangan sesuatu. Jika tidak, Anda bisa memasukkan setiap langkah pengaturan ke skrip shell dan menjalankan skrip itu bersama M-x compile.


3
Ya, tapi pertanyaannya adalah bagaimana menghubungkannya ke M-x compileatau beberapa perintah alternatif yang akan mengkompilasi file saat ini.
Gilles 'SANGAT berhenti menjadi jahat'

@Gilles OP menginginkan lingkungan shell yang konsisten antara M-x compilepanggilan, dan itulah yang dilakukan shell yang sebenarnya. Saya tidak berpikir itu mungkin dengan perintah kompilasi, tapi mungkin saya kehilangan sesuatu. Jika tidak, OP dapat menempatkan setiap langkah pengaturan ke dalam skrip shell dan menjalankan skrip itu denganM-x compile
Tu Do

Saya tidak yakin saya mengerti saran pertama Anda. Apakah Anda mengatakan "Gunakan eshelluntuk hal-hal shell, dan compileuntuk hal-hal kompilasi"? Itu mengalahkan seluruh intinya.
nispio

Saya sudah mencoba saran kedua, tetapi punya beberapa masalah. (Yang membuat saya memposting pertanyaan ini.) Terlalu lambat karena menambahkan banyak overhead tambahan untuk setiap kompilasi. Ini tidak perlu, karena saya hanya perlu mengatur lingkungan sekali. Itu juga berakhir tidak cukup dinamis, karena saya tidak bisa hanya men-tweak satu hal di lingkungan saat ini dan mencoba mengkompilasi lagi. Lingkungan build adalah sebuah program, jadi saya tidak bisa menulis skrip shell untuk mengendalikannya. Saya harus menulis skrip makro yang dikompilasi untuk lingkungan, dan memasukkan perintah kompilasi itu sendiri di makro.
nispio

0

Solusi yang mungkin adalah memiliki juru permanen yang tinggal di buffer khusus (semacam *compilation*buffer, tetapi di mana proses yang mendasarinya tidak akan pernah kembali). Anda kemudian dapat memiliki recompileperintah -seperti untuk mengirim perintah kompilasi yang telah ditentukan sebelumnya kepada juru bahasa, dan menampilkan hasilnya.

Di bawah ini adalah implementasi sementara dari strategi semacam itu. The persistent-compileperintah membutuhkan perawatan baik dari inisialisasi proses (ketika itu disebut untuk pertama kalinya atau dengan argumen awalan), dan kompilasi ulang (jika proses interpreter sudah bangun dan berjalan). Hasil kompilasi ditampilkan dalam *persistent-compilation*buffer, dimasukkan compilation-shell-minor-modeuntuk mengambil manfaat dari compilation-modefitur yang biasa untuk bernavigasi di antara kesalahan.

Berikut ini adalah contoh penggunaan, bersama dengan konten *persistent-compilation*buffer yang dihasilkan :

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

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

    $ echo $FOO
    bar
    $
    

Hati-hati, kode berikut tidak banyak diuji. Misalnya, saya tidak yakin apa yang terjadi ketika Anda mencoba mengkompilasi ulang sebelum penghentian kompilasi sebelumnya.

(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))
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.