Don't use cmd.exe when generating with Ninja on Windows

Is there any way to use a different shell when generating a ninja file? Currently when ninja generates a run command it uses cmd.exe /c …

Looking through the cmake code, it seems that’s hard coded and cannot be changed as an option. Is there any other way to get around this limitation?

Is there a supported way to alter the ninja file as a last step of configuration?

No, I don’t believe there is a way to change it. The code that gets written to the ninja file is an implementation detail. What is your use case for changing it?

The most obscure of them all: I’m trying to cross compile llvm targeting arm on a windows host: for this, clang needs a bash environment to run the generated commands. I was just hoping I could avoid running the whole process through msys/mingw.

Why does clang need a bash environment?

Because of this little colon here:

Note that I’m building on Windows but I’m targeting Linux ARM

I’ve just learned about COMSPEC - Wikipedia It would be awesome if cmake supported that!

I feel like that would be far better as a CMake script or an explicit shell script rather than trying to embed shell syntax into CMake’s language. I think that FIXME would also be a lot easier if it were a full shell or CMake script too.

The basic issue is that the command is assuming a bash command environment. CMake does not have any way to guarantee that such an environment is available.

I’ll revive this as I have another use case to add: running “cmake.exe -G Ninja” inside WSL2 fails due to cmd.exe. The exact reason is

CMD.EXE was started with the above path as the current directory.
UNC paths are not supported. Defaulting to Windows directory.
Fatal error[La001]: could not open file
“C:\Windows\CMakeFiles\cmTC_4fcd9.dir\CMakeCCompilerABI.c.o”

Powershell, for example, wouldn’t have this issue AFAIK and I would really like to change cmd.exe → powershell.exe in this case.

Searching cmd.exe references from Gitlab doesn’t produce that much hits and most of them seem to be comments about the limitations of cmd.exe. Having a way to override this, e.g. the mentioned COMSPEC, would be great.

Use a Linux CMake inside of WSL2 when targeting Linux compilations, not a Windows one. CMake binaries are platform-specific (that is, CMake is not a “cross-compiler” so to speak). This is also seen where CMake for Windows, CMake for MinGW, and CMake for Cygwin are three different things. Yes, they all run on “Windows”, but they use and target different runtimes. It’s all the same codebase, but the compilation target changes behaviors that are important to the platform at hand.

I definitely would use a Linux CMake if my toolchain was running on Linux. Unfortunately, I’m stuck with IAR Windows-only toolchain for now. I probably wasn’t too clear about my setup previously but basically I’m targeting

  1. ARM using IAR running on Windows (application) → cmake.exe
  2. Linux x86-64 using GCC / Clang (unit tests and such) → cmake

and use WSL since switching between targets is easy and managing tools is a breeze on the Linux side of things.

WSL doesn’t provide an environment where cmake.exe is expected to work though does it?

In any case, the Ninja generator uses cmd.exe to execute commands. I don’t think there’s a mechanism to change that.

Cc: @brad.king

WSL doesn’t provide an environment where cmake.exe is expected to work though does it?

I know it doesn’t, that’s why I revived this topic :slight_smile:. However, it sort of kind of almost works, but the UNC paths at least aren’t compatible.

In any case, the Ninja generator uses cmd.exe to execute commands. I don’t think there’s a mechanism to change that.

Point being that maybe it would be good to have that mechanism, unless there are technical restrictions of course. I’m not well versed in CMake internals, but a quick glance produced just a few hits that explicitly reference cmd.exe:

find […] -exec grep --color -i -nH --null -e cmd.exe \{\} +
./Source/cmExecProgramCommand.cxx:149:    // GetShortPathName, the cmd.exe program in windows which
./Source/cmGlobalGhsMultiGenerator.cxx:238:          "cmd.exe"
./Source/cmGlobalNinjaGenerator.cxx:381:        cmd = "cmd.exe /c";
./Source/cmLocalNinjaGenerator.cxx:523:      cmd << "cmd.exe /C \"";
./Source/cmLocalNinjaGenerator.cxx:526:    // higher precedence than "&&" in cmd.exe
./Source/cmLocalUnixMakefileGenerator3.cxx:643:    makefileStream << "SHELL = cmd.exe\n"
./Source/cmSystemTools.cxx:528:    // However, cmd.exe itself can only handle 8191 WCHARs and Ninja for

So it might be viable to add some kind of override.

I tried replacing all explicit references to cmd.exe /c with pwsh.exe -Command, which did work to some extent. pwsh.exe is powershell 7 and is distinct from powershell.exe (version 5, installed by default on modern Windows machines). Powershell 7 has support for && syntax in chaining commands. However, Ninja has issues with at least UNC paths that contain a literal $, for example: \\wsl$\fedora\home\foo. So all in all, the feature isn’t as trivial to implement as I’d hoped.