
*** 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@. 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@. -} {- ------------------------------------------------------------------------ - 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. ------------------------------------------------------------------------ ----- -}