GNU bug report logs - #77430
compilation-start should remember shell-file-name

Previous Next

Package: emacs;

Reported by: Siyuan Chen <chansey97 <at> gmail.com>

Date: Tue, 1 Apr 2025 13:43:06 UTC

Severity: normal

Done: Eli Zaretskii <eliz <at> gnu.org>

Bug is archived. No further changes may be made.

To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 77430 in the body.
You can then email your comments to 77430 AT debbugs.gnu.org in the normal way.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-gnu-emacs <at> gnu.org:
bug#77430; Package emacs. (Tue, 01 Apr 2025 13:43:08 GMT) Full text and rfc822 format available.

Acknowledgement sent to Siyuan Chen <chansey97 <at> gmail.com>:
New bug report received and forwarded. Copy sent to bug-gnu-emacs <at> gnu.org. (Tue, 01 Apr 2025 13:43:09 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Siyuan Chen <chansey97 <at> gmail.com>
To: bug-gnu-emacs <at> gnu.org
Subject: compilation-start should remember shell-file-name
Date: Tue, 1 Apr 2025 21:42:21 +0800
[Message part 1 (text/plain, inline)]
Background:

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")
    ))
```
NOTE: You can think of "ls" as a compilation command such as "stack build"
in Haskell.

3. Evaluate Last S-expression.

4. M-x my/compile

The *compilation* buffer lists the files normally.

5. Press 'g' in the *compilation* buffer, i.e. `recompile'.

The expected behavior: List the files again.

The actual behavior: Compilation exited abnormally.

The problem is that `recompile' does not realize that `shell-file-name' has
been updated to bash. It still uses the default cmdproxy.

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.

Best regards,
Siyuan Chen
[Message part 2 (text/html, inline)]
[0001-Remember-the-original-shell-file-name-so-we-can-use-.patch (text/plain, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#77430; Package emacs. (Tue, 01 Apr 2025 14:36:03 GMT) Full text and rfc822 format available.

Message #8 received at 77430 <at> debbugs.gnu.org (full text, mbox):

From: Siyuan Chen <chansey97 <at> gmail.com>
To: 77430 <at> debbugs.gnu.org
Subject: Re: bug#77430: compilation-start should remember shell-file-name
Date: Tue, 1 Apr 2025 22:34:49 +0800
[Message part 1 (text/plain, inline)]
I found another way to workaround:

```
(defun my/compile ()
  (interactive)
  (compile "C:/msys64/usr/bin/bash --login -c ls"))
```

Keep ·shell-file-name‘ unchanged.

This avoids having to set the `compilation-environment' manually. Except
that the *compilation* buffer will output the message:

which: no bash in ((null))

but it doesn't seem to affect compilation.

Best regards,
Siyuan Chen


On Tue, Apr 1, 2025 at 9:58 PM Siyuan Chen <chansey97 <at> gmail.com> wrote:

> Background:
>
> 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")
>     ))
> ```
> NOTE: You can think of "ls" as a compilation command such as "stack build"
> in Haskell.
>
> 3. Evaluate Last S-expression.
>
> 4. M-x my/compile
>
> The *compilation* buffer lists the files normally.
>
> 5. Press 'g' in the *compilation* buffer, i.e. `recompile'.
>
> The expected behavior: List the files again.
>
> The actual behavior: Compilation exited abnormally.
>
> The problem is that `recompile' does not realize that `shell-file-name'
> has been updated to bash. It still uses the default cmdproxy.
>
> 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.
>
> Best regards,
> Siyuan Chen
>
[Message part 2 (text/html, inline)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#77430; Package emacs. (Tue, 01 Apr 2025 14:47:20 GMT) Full text and rfc822 format available.

Message #11 received at 77430 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Siyuan Chen <chansey97 <at> gmail.com>
Cc: 77430 <at> debbugs.gnu.org
Subject: Re: bug#77430: compilation-start should remember shell-file-name
Date: Tue, 01 Apr 2025 17:46:37 +0300
> From: Siyuan Chen <chansey97 <at> 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.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#77430; Package emacs. (Tue, 01 Apr 2025 15:14:02 GMT) Full text and rfc822 format available.

Message #14 received at 77430 <at> debbugs.gnu.org (full text, mbox):

From: Siyuan Chen <chansey97 <at> gmail.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 77430 <at> debbugs.gnu.org
Subject: Re: bug#77430: compilation-start should remember shell-file-name
Date: Tue, 1 Apr 2025 23:13:46 +0800
[Message part 1 (text/plain, inline)]
>  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 <at> gnu.org> wrote:

> > From: Siyuan Chen <chansey97 <at> 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.
>
[Message part 2 (text/html, inline)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#77430; Package emacs. (Tue, 01 Apr 2025 15:51:01 GMT) Full text and rfc822 format available.

Message #17 received at 77430 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Siyuan Chen <chansey97 <at> gmail.com>
Cc: 77430 <at> debbugs.gnu.org
Subject: Re: bug#77430: compilation-start should remember shell-file-name
Date: Tue, 01 Apr 2025 18:50:36 +0300
> From: Siyuan Chen <chansey97 <at> gmail.com>
> Date: Tue, 1 Apr 2025 23:13:46 +0800
> Cc: 77430 <at> debbugs.gnu.org
> 
> >  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. 

Sorry, I don't understand: are you saying that you cannot arrange for
the buffer-local value of shell-file-name to point to Bash and stay
that way for the subsequent commands?  If you need to use
with-current-buffer or something similar, it should be easy no?

Or what am I missing?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#77430; Package emacs. (Tue, 01 Apr 2025 15:58:04 GMT) Full text and rfc822 format available.

Message #20 received at 77430 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: chansey97 <at> gmail.com
Cc: 77430 <at> debbugs.gnu.org
Subject: Re: bug#77430: compilation-start should remember shell-file-name
Date: Tue, 01 Apr 2025 18:57:06 +0300
> Cc: 77430 <at> debbugs.gnu.org
> Date: Tue, 01 Apr 2025 18:50:36 +0300
> From: Eli Zaretskii <eliz <at> gnu.org>
> 
> > From: Siyuan Chen <chansey97 <at> gmail.com>
> > Date: Tue, 1 Apr 2025 23:13:46 +0800
> > Cc: 77430 <at> debbugs.gnu.org
> > 
> > >  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. 
> 
> Sorry, I don't understand: are you saying that you cannot arrange for
> the buffer-local value of shell-file-name to point to Bash and stay
> that way for the subsequent commands?  If you need to use
> with-current-buffer or something similar, it should be easy no?

Alternatively, how about making a Windows batch file, which would
invoke the compilation command via Bash.  So you compile command would
look like this:

  M-x compile RET mycomp ls RET

where mycomp.bat is a batch file which does

  @echo off
  C:\msys64\usr\bin\bash --login -c %*

I think this is the cleanest solution for problems like this on
Windows, since you don't really want to override shell-file-name, you
just want to invoke the commands via Bash.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#77430; Package emacs. (Fri, 04 Apr 2025 08:16:03 GMT) Full text and rfc822 format available.

Message #23 received at 77430 <at> debbugs.gnu.org (full text, mbox):

From: Siyuan Chen <chansey97 <at> gmail.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 77430 <at> debbugs.gnu.org
Subject: Re: bug#77430: compilation-start should remember shell-file-name
Date: Fri, 4 Apr 2025 16:15:06 +0800
[Message part 1 (text/plain, inline)]
> Sorry, I don't understand: are you saying that you cannot arrange for
the buffer-local value of shell-file-name to point to Bash and stay
that way for the subsequent commands?  If you need to use
with-current-buffer or something similar, it should be easy no?

The original problem is not about `compile' but `recompile', i.e. press 'g'
in the *compilation* buffer. The *compilation* buffer doesn't know anything
about the last shell-file-name, so it uses cmdproxy by default.

Anyway, this is no longer a problem now, see below.

> I think this is the cleanest solution for problems like this on
Windows, since you don't really want to override shell-file-name, you
just want to invoke the commands via Bash.

Your method really inspired me. Thank you so much!

Based on it, I've redesigned my compilation workflow. Basically, whenever
users invoke `sc-haskell-projectile-stack-compile' (a tailored compile
command integrated with projectile), it firstly generates two files in the
Haskell project folder:

.emacs_stack_launch.bat
```
set MSYSTEM=MINGW32
"c:/Users/Chansey/AppData/Local/Programs/stack/x86_64-windows/msys2-20230526/usr/bin/bash"
--login "e:/my-haskell-project/.emacs_stack_launch_script.sh" %*
```

.emacs_stack_launch_script.sh
```
export STACK_ROOT=/c/sr
export
PATH=/c/env/haskell/stack/v2.15.1:/c/Users/Chansey/AppData/Roaming/local/bin:/c/PROGRA~1/Git/cmd:$PATH
$*
```

then it calls (compile ".emacs_stack_launch.bat stack build").

This method is working great so far. Plus, the file generation brings
several benefits:

1. We can set local variables in .dir-locals (e.g.
msys2-path, environment-variables) per project for fine-grained control
over compilation.

2. No need to tailored `recompile'. It just uses the last generated files.
So it works pretty well when users press 'g' in the *compilation* buffer.

3. Support all the compile commands and opts, like stack build, stack run,
stack build --test, etc.

4. Easy debugging with .emacs_stack_launch.bat and
.emacs_stack_launch_script.sh.

The code is something like this:

```
(defun sc-haskell-projectile-stack--run-project-cmd (command)
  (let* ((default-directory (projectile-compilation-dir))
         (command (projectile-read-command
                   "Compile command: "
                   (or projectile-project-compilation-cmd
                       command))))
    (sc-haskell-projectile-stack--gen-launch-file)
    (sc-haskell-projectile-stack--gen-launch-script-file)
    (compile (format "%s %s"
                     ".emacs_stack_launch.bat"
                     command)
             projectile-compile-use-comint-mode)))

(defun sc-haskell-projectile-stack-compile ()
  (sc-haskell-projectile-stack--run-project-cmd "stack build"))

(defun sc-haskell-projectile-stack-test ()
  (sc-haskell-projectile-stack--run-project-cmd "stack build --test"))

(defun sc-haskell-projectile-stack-run ()
  (sc-haskell-projectile-stack--run-project-cmd "stack run"))
```

Additionally, I also created a projectile-based shell command, which has to
be different from projectile-based compile command.

```
(defun sc-haskell-projectile-stack-shell ()
  (interactive)
  (let ((current-prefix-arg 4)
        (explicit-shell-file-name
         (expand-file-name "usr/bin/bash"
sc-haskell-projectile-stack-msys2-path))
        (explicit-bash-args
         '("--login" "--noediting" "-i")))
    (sc-haskell-projectile-stack--gen-msys2-bashrc-init-file)
    (with-environment-variables (("MSYSTEM" "MINGW32"))
      (call-interactively 'projectile-run-shell))))
```

Unlike the previous method, this one still rebinds
explicit-shell-file-name, otherwise we have to call "bash --login
--noediting -i" in the .emacs_stack_launch_script.sh, which would invoke
bash twice — something I'd rather avoid (it still can work though).

My solution is to add a hook in .bashrc

```
if [ -f $HOME/.bashrc_init.sh ]; then
    . $HOME/.bashrc_init.sh
    rm $HOME/.bashrc_init.sh
fi
```

Basically, whenever users invoke `sc-haskell-projectile-stack-shell, it
generates .bashrc_init.sh in the msys2 home USER folder. The commands in
.bashrc_init.sh are similar to those in emacs_stack_launch_script and can,
of course, be configured via .dir-locals.el. It might seem a bit unusual,
but it works well so far.

Just like to share my current design here — any suggestions would be
greatly appreciated.

Thank you!

On Tue, Apr 1, 2025 at 11:57 PM Eli Zaretskii <eliz <at> gnu.org> wrote:

> > Cc: 77430 <at> debbugs.gnu.org
> > Date: Tue, 01 Apr 2025 18:50:36 +0300
> > From: Eli Zaretskii <eliz <at> gnu.org>
> >
> > > From: Siyuan Chen <chansey97 <at> gmail.com>
> > > Date: Tue, 1 Apr 2025 23:13:46 +0800
> > > Cc: 77430 <at> debbugs.gnu.org
> > >
> > > >  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.
> >
> > Sorry, I don't understand: are you saying that you cannot arrange for
> > the buffer-local value of shell-file-name to point to Bash and stay
> > that way for the subsequent commands?  If you need to use
> > with-current-buffer or something similar, it should be easy no?
>
> Alternatively, how about making a Windows batch file, which would
> invoke the compilation command via Bash.  So you compile command would
> look like this:
>
>   M-x compile RET mycomp ls RET
>
> where mycomp.bat is a batch file which does
>
>   @echo off
>   C:\msys64\usr\bin\bash --login -c %*
>
> I think this is the cleanest solution for problems like this on
> Windows, since you don't really want to override shell-file-name, you
> just want to invoke the commands via Bash.
>
[Message part 2 (text/html, inline)]

Reply sent to Eli Zaretskii <eliz <at> gnu.org>:
You have taken responsibility. (Sat, 19 Apr 2025 13:50:03 GMT) Full text and rfc822 format available.

Notification sent to Siyuan Chen <chansey97 <at> gmail.com>:
bug acknowledged by developer. (Sat, 19 Apr 2025 13:50:04 GMT) Full text and rfc822 format available.

Message #28 received at 77430-done <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Siyuan Chen <chansey97 <at> gmail.com>
Cc: 77430-done <at> debbugs.gnu.org
Subject: Re: bug#77430: compilation-start should remember shell-file-name
Date: Sat, 19 Apr 2025 16:48:57 +0300
> From: Siyuan Chen <chansey97 <at> gmail.com>
> Date: Fri, 4 Apr 2025 16:15:06 +0800
> Cc: 77430 <at> debbugs.gnu.org
> 
> > Sorry, I don't understand: are you saying that you cannot arrange for
> the buffer-local value of shell-file-name to point to Bash and stay
> that way for the subsequent commands?  If you need to use
> with-current-buffer or something similar, it should be easy no?
> 
> The original problem is not about `compile' but `recompile', i.e. press 'g' in the *compilation* buffer. The
> *compilation* buffer doesn't know anything about the last shell-file-name, so it uses cmdproxy by default. 
> 
> Anyway, this is no longer a problem now, see below.
> 
> > I think this is the cleanest solution for problems like this on
> Windows, since you don't really want to override shell-file-name, you
> just want to invoke the commands via Bash.
> 
> Your method really inspired me. Thank you so much! 
> 
> Based on it, I've redesigned my compilation workflow. Basically, whenever users invoke
> `sc-haskell-projectile-stack-compile' (a tailored compile command integrated with projectile), it firstly
> generates two files in the Haskell project folder: 
> 
> .emacs_stack_launch.bat
> ```
> set MSYSTEM=MINGW32
> "c:/Users/Chansey/AppData/Local/Programs/stack/x86_64-windows/msys2-20230526/usr/bin/bash" --login
> "e:/my-haskell-project/.emacs_stack_launch_script.sh" %*
> ```
> 
> .emacs_stack_launch_script.sh
> ```
> export STACK_ROOT=/c/sr
> export
> PATH=/c/env/haskell/stack/v2.15.1:/c/Users/Chansey/AppData/Roaming/local/bin:/c/PROGRA~1/Git/cmd:$PATH
> 
> $*
> ```
> 
> then it calls (compile ".emacs_stack_launch.bat stack build").
> 
> This method is working great so far. Plus, the file generation brings several benefits:
> 
> 1. We can set local variables in .dir-locals (e.g. msys2-path, environment-variables) per project for
> fine-grained control over compilation.
> 
> 2. No need to tailored `recompile'. It just uses the last generated files. So it works pretty well when users
> press 'g' in the *compilation* buffer.
> 
> 3. Support all the compile commands and opts, like stack build, stack run, stack build --test, etc.
> 
> 4. Easy debugging with .emacs_stack_launch.bat and .emacs_stack_launch_script.sh. 
> 
> The code is something like this:
> 
> ```
> (defun sc-haskell-projectile-stack--run-project-cmd (command)
>   (let* ((default-directory (projectile-compilation-dir))
>          (command (projectile-read-command
>                    "Compile command: "
>                    (or projectile-project-compilation-cmd
>                        command))))
>     (sc-haskell-projectile-stack--gen-launch-file)
>     (sc-haskell-projectile-stack--gen-launch-script-file)
>     (compile (format "%s %s"
>                      ".emacs_stack_launch.bat"
>                      command)
>              projectile-compile-use-comint-mode)))
> 
> (defun sc-haskell-projectile-stack-compile ()
>   (sc-haskell-projectile-stack--run-project-cmd "stack build"))
> 
> (defun sc-haskell-projectile-stack-test ()
>   (sc-haskell-projectile-stack--run-project-cmd "stack build --test"))
> 
> (defun sc-haskell-projectile-stack-run ()
>   (sc-haskell-projectile-stack--run-project-cmd "stack run"))
> ```
> 
> Additionally, I also created a projectile-based shell command, which has to be different from projectile-based
> compile command.
> 
> ```
> (defun sc-haskell-projectile-stack-shell ()
>   (interactive)
>   (let ((current-prefix-arg 4)
>         (explicit-shell-file-name
>          (expand-file-name "usr/bin/bash" sc-haskell-projectile-stack-msys2-path))
>         (explicit-bash-args
>          '("--login" "--noediting" "-i")))
>     (sc-haskell-projectile-stack--gen-msys2-bashrc-init-file)
>     (with-environment-variables (("MSYSTEM" "MINGW32"))
>       (call-interactively 'projectile-run-shell))))
> ```
> 
> Unlike the previous method, this one still rebinds explicit-shell-file-name, otherwise we have to call "bash -
> -login --noediting -i" in the .emacs_stack_launch_script.sh, which would invoke bash twice — something I'd
> rather avoid (it still can work though).
> 
> My solution is to add a hook in .bashrc
> 
> ```
> if [ -f $HOME/.bashrc_init.sh ]; then
>     . $HOME/.bashrc_init.sh
>     rm $HOME/.bashrc_init.sh
> fi
> ```
> 
> Basically, whenever users invoke `sc-haskell-projectile-stack-shell, it generates .bashrc_init.sh in the msys2
> home USER folder. The commands in .bashrc_init.sh are similar to those in emacs_stack_launch_script and
> can, of course, be configured via .dir-locals.el. It might seem a bit unusual, but it works well so far. 
> 
> Just like to share my current design here — any suggestions would be greatly appreciated.

Thanks.

I guess we can close this bug now.




bug archived. Request was from Debbugs Internal Request <help-debbugs <at> gnu.org> to internal_control <at> debbugs.gnu.org. (Sun, 18 May 2025 11:24:08 GMT) Full text and rfc822 format available.

This bug report was last modified 33 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.