Using a Linux-style shell on Windows

With the default makefile, make will always use cmd-style commands when started from Embeetle.

It is possible to override this behavior by adding a few lines near the beginning of the makefile. For example, to use an MSYS shell on windows, add these lines (assuming MSYS is installed at C:\msys64):

ifeq ($(SHELL),sh.exe)
export SHELL = C:/msys64/usr/bin/sh.exe
PATH := C:/msys64/usr/bin;$(PATH)

To help you understand Embeetle’s behavior and fine-tune it to your liking, this post gives some technical background below.

Which commands does a makefile use?

Most makefiles do not only use compilation commands to build a project. Typical other commands are rm to remove files for make clean and mkdir to create subdirectories in the build directory. Sophisticated makefiles may use a lot of other commands as well.

Commands like rm and mkdir are Linux (or Unix) commands; they either do not exist on Windows by default (rm), or have a different syntax (mkdir). To make makefiles portable between Linux and Windows - like Embeetle does - there are two options:

  1. the makefile can detect automatically whether it is running on WIndows, and substitute appropriate commands, or
  2. you can install additional software, such as MSYS or WSL, to emulate Linux commands on Windows.

Embeetle uses the first approach by default; you can override this by adding a few lines to the makefile, and installing the necessary software yourself (Embeetle does not do this for you; there are too many options to consider)

Why make needs a shell to execute commands

A shell is a program that parses and executes commands. Examples are cmd on Windows, or sh (bash or bourne shell) on Linux. Typically, a shell can expand wildcards (e.g. *.c expands to all C files in the current directly), or combine multiple commands on a single single in different ways, etc.

make can execute simple commands directly, without using a shell, but as soon as the command contains characters with a special meaning for the shell, it will use a shell to interpret the command. It does not have a built-in parser for commands.

How make chooses a shell

You can set the shell to be used explicitly in the makefiles, using export SHELL = .... If you don’t, it will try to find a shell using the rules given here: Choosing the Shell (GNU make).

On Linux, sh (bourne or bash shell) will be used in almost all cases.

On Windows, if one of the directories on PATH contains an executable file sh.exe, that will be used. SHELL will be set to the full path of sh.exe, for example C:/msys64/usr/bin/sh.exe if you have installed MSYS and PATH contains C:/msys64/usr/bin.

Otherwise, the Windows built-in shell cmd will be used, and SHELL is set to sh.exe (no path).

The default Embeetle makefile compares the value of SHELL to sh.exe; if equal, it assumes Windows cmd style commands are required; otherwise, it assumes linux or unix bourne shell commands.

Why and how Embeetle enforces cmd-style commands on Windows

Some Windows PC’s, especially those used by software developers, have a linux style shell installed somewhere on PATH. make will detect this (as described in the previous section) and try to use that shell.

Unfortunately, some of these shells do not work as expected. One example is WinAVR, a toolchain used to develop firmware for some microcontrollers. The problem is described in this post: Error -1073741502 or 0xc0000142 when using "clean" on Windows.

To make sure that Embeetle works out-of-the-box for all users, without forcing them to manually change their PATH or uninstall software, Embeetle versions above 1.3.2 will remove all directories from PATH that contain an executable file sh.exe. This change is local to Embeetle and programs started from Embeetle, such as make; it has no effect on the global setting for PATH.

As a result, make started from Embeetle will always use cmd style commands, unless you explicitly override the shell to be used in the project’s makefile.

How to override the shell in the makefile

You can override the shell to be used by adding a few lines to the project’s makefile. For example, if you have MSYS installed at C:\msys64, you can add these lines:

ifeq ($(SHELL),sh.exe)
export SHELL = C:/msys64/usr/bin/sh.exe
PATH := C:/msys64/usr/bin;$(PATH)

The condition ifeq ($(SHELL),sh.exe) around these lines makes sure that the shell is only changed on Windows, when no sh.exe was detected on PATH. You most probably do not want to change the shell on Linux. On Windows, if you use this makefile outside Embeetle, another shell may already have been found on PATH; this will be preferred over the one set here. Whether you want that or not is your choice; feel free to change the condition accordingly.

The export keyword before the definition of SHELL makes sure that the value of SHELL is exported to any sub-make you may be using. Whether you want that or not is your choice. The default Embeetle makefile does not use sub-makes; the reason why is documented here: Recursive Make Considered Harmful

Finally, PATH must be modified for this makefile to work inside Embeetle. Embeetle removes C:/msys64/usr/bin from PATH because it contains a shell sh.exe, but the shell relies on C:/msys64/usr/bin begin on PATH to find its commands.

1 Like