GNU bug report logs -
#77430
compilation-start should remember shell-file-name
Previous Next
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.
Full log
View this message in rfc822 format
[Message part 1 (text/plain, inline)]
Your bug report
#77430: compilation-start should remember shell-file-name
which was filed against the emacs package, has been closed.
The explanation is attached below, along with your original report.
If you require more details, please reply to 77430 <at> debbugs.gnu.org.
--
77430: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=77430
GNU Bug Tracking System
Contact help-debbugs <at> gnu.org with problems
[Message part 2 (message/rfc822, inline)]
> 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.
[Message part 3 (message/rfc822, inline)]
[Message part 4 (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 5 (text/html, inline)]
[0001-Remember-the-original-shell-file-name-so-we-can-use-.patch (text/plain, attachment)]
This bug report was last modified 34 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.