Ambiente persistente per la compilazione di Mx


8

Quando M-x compilelo eseguo genera una nuova subshell per eseguire il mio comando di compilazione. Non appena ritorna il comando di compilazione, il processo di shell viene interrotto. Posso capire perché questo sarebbe auspicabile nella maggior parte dei casi, ma attualmente mi trovo in una situazione in cui non è utile.

Sto lavorando in un ambiente di build specializzato in questo momento che richiede che io faccia alcuni passi iniziali per impostare la build prima di eseguire il compilatore. Finché l'ambiente persiste, ho solo bisogno di eseguire i passaggi di installazione una volta. Ma quando lo uso M-x compilesignifica che devo fare i passaggi ogni volta che voglio compilare o ricompilare.

C'è un modo in cui posso generare una subshell che persisterà in background? Uno che M-x compilee M-x gdbpuò usare ogni volta che devono eseguire un processo di shell?


Motivazione:

Ho un programma (che chiameremo xcc) che costruisce il codice C per piattaforme speciali. Per compilare il mio codice, inizio innanzitutto xccdal tcshprompt:

$ xcc

Il caricamento del programma richiede 10+ secondi, quindi posso inserire i comandi al suo prompt interattivo

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

I passaggi precedenti possono essere integrati in una macro personalizzata in buildmyprog.macromodo che io possa eseguirlo direttamente dalla shell o da Emacs conM-x compile

$ xcc buildmyprog.macro

Il problema principale con questo approccio è il fatto che il xcccaricamento del programma richiede 10 secondi, prima ancora che inizi la compilazione. Mi sono stancato abbastanza di aspettare i 10 secondi in più ogni volta che ho compilato che ho iniziato a correre xccin un ansi-termbuffer separato. Ora dopo aver modificato e salvato il codice, passo al ansi-termbuffer ed eseguo

xcc>> build myprogram

Funziona bene, ma ogni volta che passo a quel buffer penso: "Non sarebbe fantastico se potessi semplicemente spingere F7e il mio comando di compilazione verrebbe inviato all'istanza già in esecuzione di xcc?"


Che effetto ha la tua configurazione sull'ambiente? Variabili d'ambiente, file temporanei?
T. Verron,

L'ambiente è il suo programma. Mentre fa un certo uso delle variabili di ambiente e dei file temporanei, il programma stesso mantiene i propri stati interni che scompaiono alla chiusura del programma.
nispio,

3
Sulla base della modifica, penso che tu abbia bisogno di una comintmodalità derivata per il tuo ambiente. Se ti senti avventuroso, ecco una guida per scriverne uno.
Vamsi,

@Vamsi Io sto sentite avventurosi, e che si presenta come un grande vantaggio. Grazie.
nispio,

1
Il modo più semplice e sporco per inviare un comando a un buffer comint è inserirlo nel buffer e chiamare comint-send-input. Questo è fondamentalmente quello che stai facendo a mano, convertirlo in elisp non dovrebbe essere molto difficile (soprattutto se paragonato all'impostazione del comando).
T. Verron,

Risposte:


2

Puoi fare il setup nella tua shell prima di avviare emacs? La compilesotto-shell dovrebbe ereditare l'ambiente dal nonno tramite emacs.


1
Immagina che "l'ambiente" che sto eseguendo sia Python. (Non è Python.) Anche se potrei essere in grado di avviare Emacs dall'interprete Python, M-x compilenon ha inviato i suoi comandi all'interprete Python.
nispio,

0

Usa quindi una shell reale all'interno di Emacs, come eshello ansi-term. È necessario utilizzare compileper la compilazione, sebbene possa essere utilizzato per eseguire qualsiasi comando.

Non credo sia possibile con il comando di compilazione, ma forse mi manca qualcosa. Altrimenti, è possibile inserire tutte le fasi di installazione in uno script di shell ed eseguire quello script con M-x compile.


3
Bene, sì, ma la domanda è come collegarlo M-x compileo qualche comando alternativo che compili il file corrente.
Gilles 'SO- smetti di essere malvagio' l'

@Gilles l'OP vuole un ambiente di shell coerente tra le M-x compilechiamate, ed è quello che fa una shell reale. Non credo sia possibile con il comando di compilazione, ma forse mi manca qualcosa. Altrimenti, l'OP potrebbe mettere tutte le fasi di installazione in uno script di shell ed eseguire quello script conM-x compile
Tu Do,

Non sono sicuro di aver capito il tuo primo suggerimento. Stai dicendo "Usa eshellper le cose shell e compileper compilare le cose"? Questo sconfigge il punto.
nispio,

Ho provato il secondo suggerimento, ma ho avuto alcuni problemi. (Il che mi ha portato a pubblicare questa domanda.) È troppo lento perché aggiunge un sovraccarico extra ad ogni compilazione. Questo è inutile, perché avrei dovuto impostare l'ambiente una sola volta. Inoltre finisce per non essere abbastanza dinamico, perché non posso semplicemente modificare una cosa nell'attuale rafforzamento e provare a compilare di nuovo. L'ambiente di compilazione è un programma, quindi non posso scrivere uno script di shell per controllarlo. Devo scrivere uno script di macro compilato per l'ambiente e includere il comando di compilazione stesso nella macro.
nispio,

0

Una possibile soluzione sarebbe quella di far vivere un interprete permanente in un buffer dedicato (un po 'come il *compilation*buffer, ma in cui il processo sottostante non ritornerebbe mai). È quindi possibile disporre di un recompilecomando simile per inviare un comando di compilazione predefinito all'interprete e visualizzare i risultati.

Di seguito è riportata un'implementazione provvisoria di tale strategia. Il persistent-compilecomando si occupa sia dell'inizializzazione del processo (quando viene chiamato per la prima volta o con un argomento prefisso), sia della ricompilazione (se il processo dell'interprete è già attivo e in esecuzione). I risultati della compilazione vengono visualizzati in un *persistent-compilation*buffer, sfruttati compilation-shell-minor-modeper sfruttare le solite compilation-modefunzionalità per navigare tra gli errori.

Ecco un esempio di utilizzo, insieme al contenuto risultante del *persistent-compilation*buffer:

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

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

    $ echo $FOO
    bar
    $
    

Attenzione, il seguente codice non è stato testato molto. Ad esempio, non sono sicuro di cosa accada quando si tenta di ricompilare prima della fine della compilazione precedente.

(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))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.