make-w32
[Top][All Lists]

## Re: Bug: make fails to execute .BAT files with space in the path, with S

 From: Erik Carstensen Subject: Re: Bug: make fails to execute .BAT files with space in the path, with SHELL=cmd.exe Date: Thu, 2 May 2013 10:26:50 +0200

On Wed, May 1, 2013 at 5:39 PM, Eli Zaretskii wrote:

So now commands that use quotes go through the fast path, instead of
being submitted to cmd.exe via a batch file, which exposed these
commands to this (very old) bug.

I fixed that in the repository; the patch is below if you want to try
it.

I think this fix deserves an item in NEWS. The change breaks makefiles like this one (succeeds with 3.82, fails with master):

SHELL=cmd.exe
X=C:\Program\ Files
default: \$(X)
ls.exe \$(X)

As far as I can see, this construct looks like the easiest way to short-circuit the CMD.EXE invocation in 3.82 with a path that contains space; it's the solution I ended up with after some trial-and-error.

Please also tell me if your original problem was fixed by the patches
I sent earlier.  Thanks.

It does not! With the following makefile:

SHELL=cmd.exe
default:
"a b\x.bat"

I get this most of the time:
make/gnumake.exe --debug=j
"a b\x.bat"
CreateProcess(NULL,"C:\cygwin\tmp\a b\x.bat",...)
(and make exits with code 127)

Sometimes (1 in 5), the bat file is actually executed before make exits with 127.

The machine runs Windows 7 Enterprise.

We have exactly the same bug in one of our tools. An engineer is working on it, and I showed him your suggested solution. His response:

```I don't like calling CreateProcess with NULL as the first parameter - it will
actually first look for cmd.exe in cwd, with interesting results. Using COMSPEC
directly is more likely to be correct. The CreateProcess documentation
suggests:

To run a batch file, you must start the command interpreter; set
lpApplicationName to cmd.exe and set lpCommandLine to the following
arguments: /c plus the name of the batch file.

Unfortunately this says nothing at all about how to quote the batch file name
and its arguments. Here cmd.exe reveals itself to be excentric yet again, and
manages to violate Microsoft's own quirky quoting conventions:

If you specify /c or /k, cmd processes the remainder of string and
quotation marks are preserved only if all of the following conditions
are met:

• You do not use /s.
• You use exactly one set of quotation marks.
• You do not use any special characters within the quotation marks (for
example: &<>( ) @ ^ |).
• You use one or more white-space characters within the quotation marks.
• The string within quotation marks is the name of an executable file.

If the previous conditions are not met, string is processed by examining
the first character to verify whether or not it is an opening quotation
mark. If the first character is an opening quotation mark, it is stripped
along with the closing quotation mark. Any text following the closing
quotation marks is preserved.

This means that the right way to run a batch file with multiple arguments is to
run cmd.exe with the command line

/c "batch_file arg1 arg2 ..."

where any or all of batch_file and the arguments may be quoted in turn, such as

/c ""my file.bat" "one arg" "another arg""

since the outermost quotes are stripped away. This seems to be what
CreateProcess does when given a NULL first argument, although it also adds a
dummy "cmd" before the /c. This can be seen quite clearly in Process Monitor.```