Subject: bug#77430: compilation-start should remember shell-file-name

From: Siyuan Chen <[email-masked]>
Date: Tue, 1 Apr 2025 23:13:46 +0800

>  Why cannot your my/compile function do this:
>
>  (setq-local shell-file-name "C:/msys64/usr/bin/bash")
>
> instead of let-binding it?

This is only for the current file buffer.

For example, if you focus on a project file buffer (e.g. test.hs) and M-x
my/compile, it only sets `shell-file-name' for that file buffer. However,
the `compile` actually using the `shell-file-name' belongs to the
*compilation* buffer.

```
(defun compilation-start (command &optional mode name-function
highlight-regexp
                                  continue)
  ...
  (with-current-buffer outbuf ; <--- The `outbuf' is the *compilation*
buffer
    ...
    (comint-exec
     outbuf (compilation--downcase-mode-name mode-name)
     shell-file-name ; <--- use the buffer local variable shell-file-name
in the *compilation* buffer
     nil `(,shell-command-switch ,command))
    ...
    )
...
)
```

So the following code doesn't work:

```
(defun my/compile ()
  (interactive)
  (let (
        (compilation-environment
"PATH=/mingw64/bin:/usr/local/bin:/usr/bin:/bin:/c/Windows/System32:/c/Windows:/c/Windows/System32/Wbem:/c/Windows/System32/WindowsPowerShell/v1.0/:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl")
        )
    (setq-local shell-file-name "C:/msys64/usr/bin/bash")
    (compile "ls")
    ))
```

M-x my/compile

Compilation exited abnormally.

Best regards,
Siyuan Chen

On Tue, Apr 1, 2025 at 10:46 PM Eli Zaretskii <[email-masked]> wrote:

> > From: Siyuan Chen <[email-masked]>
> > Date: Tue, 1 Apr 2025 21:42:21 +0800
> >
> > Recently, I've been setting up a Haskell compilation environment with
> Emacs on Windows. The project
> > depends on diagrams-cairo, which depends on GTK+, so I have to build it
> via msys64 with MINGW. It works
> > well in a non Emacs environment, so I'd like to adapt it to the Emacs
> environment.
> >
> > Everything is OK, except when I press 'g' in the *compilation* buffer.
> >
> > To simplify the problem, below only the minimal test is provided.
> >
> > Reproduce steps:
> >
> > 1. Create a file test.el in E:/tmp
> >
> > 2. Open that file and paste the following code
> > ```
> > (defun my/compile ()
> >   (interactive)
> >   (let ((shell-file-name "C:/msys64/usr/bin/bash")
> >         (compilation-environment
> >
> "PATH=/mingw64/bin:/usr/local/bin:/usr/bin:/bin:/c/Windows/System32:/c/Windows:/c/Windows/System32/Wbem:/c/Windows/System32/WindowsPowerShell/v1.0/:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl")
> >
> >         )
> >     (compile "ls")
> >     ))
> > ```
>
> Why cannot your my/compile function do this:
>
>   (setq-local shell-file-name "C:/msys64/usr/bin/bash")
>
> instead of let-binding it?
>
> > I have created a patch to workaround the issue. It remembers the
> original `shell-file-name' in
> > `compilation-start', so we can use it when we `recompile'.
>
> Thanks, but I don't think it's TRT for 'compile' to record the shell
> by default.  In your case, you want to use the same shell each time,
> but that is not always true.  Since you already have a tailored
> compilation command, I suggest that the same command does this job
> for you.
>