Skip to content

Conversation

@Klukec
Copy link

@Klukec Klukec commented Sep 30, 2025

On Windows the $(shell ...) function uses sh.exe (bash) if it is in PATH, otherwise it uses cmd.exe.

If sh is used then the /C option is interpreted as the C:\ drive and not the cmd option which tells the cmd to run the command and exit. Since /C is interpreted the wrong way cmd doesn't exit and the make process gets stuck (doesn't return an error or continue).

But if cmd is used then /C is interred correctly and the build continues.

sh can get added to PATH when installing git, but it depends on the selected options. It is also added if git is installed via the Scoop package manager or MSYS2 is installed.

The solution is to just use powershell to create the directory.

I tested both options when sh is in PATH and when it is not and it worked both times.

On Windows the $(shell ...) function uses sh.exe (BASH) if it is in PATH, otherwise it uses cmd.exe.
If SH is used then the "/C" option is interred as the C:\ drive and not the CMD option which tells the CMD to run the command and exit.
Since "/C" is interpreted the wrong way CMD doesn't exit and the MAKE process gets stuck (doesn't return an error or continue).
But if CMD is used then "/C" is interred correctly and the build continues.
sh.exe can get added to PATH when installing git, but it depends on the selected options.
The solution is to just use POWERSHELL to create the directory.
@kalvdans
Copy link
Contributor

Maybe a better option is to set `SHELL=cmd" somewhere in the Makefile, to disable make's search for a suitable shell.

@Klukec
Copy link
Author

Klukec commented Sep 30, 2025

I considered this option, but this was the only place in the Makefiles that explicitly called cmd /C and every where else powershell was used for windows specific shell commands.

But you are right. Adding SHELL=cmd would work and also would prevent future bugs if cmd /C would be used elsewhere. I implemented and tested the second option:

If it is preferred I can update this PR. Let me know.

@Klukec Klukec deleted the branch vedderb:master September 30, 2025 14:25
@Klukec Klukec closed this Sep 30, 2025
@Klukec Klukec deleted the master branch September 30, 2025 14:25
@Klukec Klukec restored the master branch September 30, 2025 14:26
@Klukec Klukec reopened this Sep 30, 2025
@Klukec Klukec deleted the branch vedderb:master September 30, 2025 14:27
@Klukec Klukec closed this Sep 30, 2025
@Klukec Klukec deleted the master branch September 30, 2025 14:27
@Klukec Klukec restored the master branch September 30, 2025 14:28
@Klukec
Copy link
Author

Klukec commented Sep 30, 2025

Sorry for the spam. I tried to rename the branch, but I guess I don't know how to do that :).

@Klukec Klukec reopened this Sep 30, 2025
@kalvdans
Copy link
Contributor

kalvdans commented Oct 1, 2025

Reading https://www.gnu.org/software/make/manual/html_node/Choosing-the-Shell.html it is a mess to set the shell. Perhaps export MAKESHELL=cmd will make recursive make invocations automatically pick up the right shell. I haven't tested...

On the other hand, creating directories when parsing a Makefile sounds really bad, so I'd prefer if it could be done via recipes instead. Is that what you mean with powershell solution?

@Klukec
Copy link
Author

Klukec commented Oct 2, 2025

I did some testing, using both make installed with chocolatey and Scoop.
In both cases make --version returns (Built for Windows32):

GNU Make 4.4.1
Built for Windows32
Copyright (C) 1988-2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

MAKESHELL

I tested MAKESHELL variable. It has no effect on the shell that is used, even if I set is in the environment. The documentation states:

On MS-DOS, if the setting of SHELL is not suitable for make, you can set the variable MAKESHELL to the shell that make should use; if set it will be used as the shell instead of the value of SHELL.

I think since Window 7/10/11 don't fall in the category MS-DOS, the MAKESHELL variable doesn't work.


EXPORT SHELL

I tried export SHELL = cmd. This didn't work. In the documentation it says that if you export a variable it will be set in the environment for any recipe command that is called. With some .bat scripts I saw that the SHELL variable gets exported correctly. This is written in the documentation:

However, on MS-DOS and MS-Windows the value of SHELL in the environment is used, since on those systems most users do not set this variable, and therefore it is most likely set specifically to be used by make.

But make didn't import the SHELL variable from the environment. For other variables the export worked as expeced. So I guess that make on windows import ever environment variable except for SHELL. I even tried the MINGW64 build of make from MSYS2 and and It didn't import. Maybe make imports the SHELL variable only for a certain builds.


MAKEOVERRIDE

In the documentation it says that if we set a variable in the command line it gets passed down to sub-make calls through the MAKEFLAGS and MAKEOVERRIDE variables. They get automatically exported. So by adding MAKEOVERRIDE += SHELL=cmd worked and it passed the SHELL variable to all sub-make calls. It works even if sub-make calls are multiple levels deep.

@Klukec
Copy link
Author

Klukec commented Oct 2, 2025

On the other hand, creating directories when parsing a Makefile sounds really bad, so I'd prefer if it could be done via recipes instead.

I can add so that .dep file is created via a target and recipie. But I guess it is created during parsing, because the creator of chibiOS wrote it that way. You can see it in this file

Is that what you mean with powershell solution?

Here is what I meant by the "powershell solution":

  1. If cmd.exe is used the line $(shell cmd /C if not exist "$(DEPPATH)" mkdir "$(DEPPATH)") works OK.
  2. If sh.exe is used the line doesn't work because /C is interpreted as the C:\ drive. So it has to be different. Options that would work are:
    $(shell cmd //C if not exist "$(DEPPATH)" mkdir "$(DEPPATH)")
    $(shell -p mkdir "$(DEPPATH)")
  3. The only command that works no matter if cmd.exe or sh.exe is used (that I found) is that powershell is used to create the directory.

@Klukec
Copy link
Author

Klukec commented Oct 21, 2025

Are there any other problems or reasons why this pull request can't be merged? The changes to makefiles only affect Windows users and I did a lot of testing to make sure everything works.

To summarize the problem only occurs if the shell sh.exe is in the environment PATH. make would default to using it and the command cmd /C would be interpreted the wrong way since it thinks that /C is the C drive and not a option. The solution was to force make to use cmd.exe. Whether or not sh.exe is added to the path depends on how and from where you install git.

I installed git and GNU make from different sources and tested if I could build the firmware. It worked for every option.

git GNU make
1. Official website chocolatey
2. Official website scoop
3. chocolatey chocolatey
4. chocolatey scoop
5. scoop chocolatey
6. scoop scoop
7. MSYS2 MSYS2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants