Problem with ghc on Windows ME

Simon Peyton-Jones simonpj at microsoft.com
Wed Jan 28 09:04:05 EST 2004


> *** Literate pre-processor C:\GHC\GHC-6.2\unlit.exe -h Demo.lhs
Demo.lhs
> C:\WINDOWS\TEMP\ghc-1160737.lpp
> 
> Failed: C:\GHC\GHC-6.2\unlit.exe -h Demo.lhs Demo.lhs
> C:\WINDOWS\TEMP\ghc-1160737.lpprawSystem: does not exist (No such file
or
> directory) *** Deleting temp files Deleting:
C:/WINDOWS/TEMP/ghc-1160737.lpp
> Warning: deleting non-existent C:/WINDOWS/TEMP/ghc-1160737.lpp

Simon and I spent an hour getting to the bottom of Gour's problem. 

Short answer: It's a bug in GHC6.2 that you really can't get round.  It
only shows up on Win ME/98/95, and it really makes GHC6.2 unusable on
those platforms.  We'll fix it in 6.2.1, but apart from that you'll have
to back up to 6.0.1.

Medium answer: an oversight meant that GHC6.2 invokes Win32 external
commands (like gcc, unlit etc) with double-backslashes in the arguments:
	cat foo\\baz
On NT and XP, these double-backslashes are harmless, but not on
WinME/98/95, which is why we didn't notice it.

The long answer is below for those who are interested, reproduced from
new comments in libraries/base/System/Cmd.hs

Simon M sent round a source patch yesterday.  It'd be great if someone
could confirm that it really works.

Simon

		LONG ANSWER

GHC uses 'rawSystem' to invoke gcc, unlit etc:

rawSystem :: FilePath -> [String] -> IO ExitCode
{- | 
The computation @rawSystem cmd args@ runs the operating system command
whose file name is @cmd@, passing it the arguments @args at .  It
bypasses the shell, so that @cmd@ should see precisely the argument
strings @args@, with no funny escaping or shell meta-syntax expansion.
(Unix users will recognise this behaviour 
as @execvp@, and indeed that's how it's implemented.)
It will therefore behave more portably between operating systems than
@system at .
-}

{-
------------------------------------------------------------------------
-
 	IMPORTANT IMPLEMENTATION NOTES
   (see also libraries/base/cbits/rawSystem.c)

On Unix, rawSystem is easy to implement: use execvp.

On Windows it's more tricky.  We use CreateProcess, passing a single
command-line string (lpCommandLine) as its argument.  (CreateProcess
is well documented on http://msdn.microsoft/com.)

  - It parses the beginning of the string to find the command. If the
	file name has embedded spaces, it must be quoted, using double
	quotes thus 
		"foo\this that\cmd" arg1 arg2

  - The invoked command can in turn access the entire lpCommandLine
string,
	and the C runtime does indeed do so, parsing it to generate the 
	traditional argument vector argv[0], argv[1], etc.  Again, to
	break it into argument items, any spaces must be quoted using
	double quote thus
		cmd "this is arg 1" "this is arg 2"

What if an argument itself contains double-quotes? (File names can't
can't, on Windows.)  Then the quote must be escaped with a backslash.
If we call Create Process with this lpArgument:
	cmd "Foo=\"baz\"" arg2
then cmd will see argv[1] as
	Foo="baz"
However, experiments show that backslashes themselves must *not* be
escaped.
That is, to get a backslash in an argument, just put backslash, even
inside
quotes.  For eaxmple, this works fine to show the contents of the file
foo\baz
	cat "foo\baz"
If you escape the backslash, thus
	cat "foo\\baz"
then @cat@ will see argument foo\\baz, and on WinME/98/95 you'll get
"can't find file foo\\baz".  (As it happens, WinNT/XP commands don't
mind double backslashes, but it's still a bug, given rawSystem's claim
to pass exactly args to the command.)

	[NOTE: this was the bug in 6.2.]

BOTTOM LINE: 
	1 We wrap the command, and each argument, in quotes
	2 Inside the quotes, we escape any double-quote characters
		(but nothing else)
	3 Then concatenate all these quoted things together, separated
with 
		spaces

Steps 1,2 are done by the function 'translate' below.

Question: how do you get the string \" into an argument?  Turns out that
the argument "\\"" does not do the job.  (This turns into a single \.)
Puzzling but probably not important in practice.

Note: CreateProcess does have a separate argument (lpApplicationName)
with which you can specify the command, but we have to slap the
command into lpCommandLine anyway, so that argv[0] is what a C program
expects (namely the application name).  So it seems simpler to just
use lpCommandLine alone, which CreateProcess supports.

------------------------------------------------------------------------
----- -}



More information about the Glasgow-haskell-users mailing list