>  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 <eliz@gnu.org> wrote:
> From: Siyuan Chen <chansey97@gmail.com>
> 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.