RE: Problem with ghc on Windows ME

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

rawSystem :: FilePath -> [String] -> IO ExitCode
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.
This comment is puzzling me: I tend to use System.system a lot - this is probably not implemented in terms of rawSystem, with a shell as FilePath, but via a separate system-call? For system, I do need doublequotes in arguments (e.g., when passing complex option flags to the programs invoked, or when the arguments contain strings). Can that really always be avoided for rawSystem? Btw, I do have a win98 box, but it is in no state to compile big programs, let alone ghc (apart from speed, or the lack of it, I have to delete stuff whenever I want to recompile my own projects..). So if you could post a small test case (a Haskell file defining rawSystem and its ffi call/translation, and the kind of call you need to execute through it) that could be run through ghc-6.0.1 (binary release), it would be a lot easier to help with initial testing, even though that wouldn't guarantee successful bootstraps. Claus PS quoting issues are notoriously tricky, especially in programs that are meant to run on multiple platforms. I'm still hunting a case of quoting that works under win98, but not under winXP, where apart from Haskell code, several other progs and shells are involved, and even ridiculously small changes can break things there (e.g., because the example suddenly no longer fits a special case and is treated completely differently). I can't see a problem with removing double escapes for backslashes, but would recommend testing in all cases.

Simon Peyton-Jones (simonpj@microsoft.com) wrote:
Simon and I spent an hour getting to the bottom of Gour's problem.
Thank you very much for taking the issue. It's very much appreciated.
Simon M sent round a source patch yesterday. It'd be great if someone could confirm that it really works.
I applied your patch to my 6.2 source tree in my attempt to build 6.2 from source in MSYS/MinGW environment and so far - it looks good. I can invoke ghc-inplace and get: $ /ghc/ghc-6.2/ghc/compiler/stage1/ghc-inplace Glasgow Haskell Compiler, Version 6.2, for Haskell 98, compiled by GHC version 6.0.1 Using package config file: c:\ghc\ghc-6.2\ghc\driver\package.conf.inplace ==================== Packages ==================== Package {name = "rts", auto = False, import_dirs = [], source_dirs = [], library_dirs = ["c:/ghc/ghc-6.2/ghc/rts", "c:/ghc/ghc-6.2/ghc/rts/gmp"], hs_libraries = ["HSrts"], extra_libraries = ["m", "gmp", "wsock32", "mingwex"], include_dirs = ["c:/ghc/ghc-6.2/ghc/includes"], c_includes = ["Stg.h"], package_deps = [], extra_ghc_opts = [], extra_cc_opts = [], extra_ld_opts = ["-u", "_GHCziStable_StablePtr_con_info", "-u", "_GHCziBase_False_closure", "-u", "_GHCziBase_True_closure", "-u", "_GHCziPack_unpackCString_closure", "-u", "_GHCziIOBase_stackOverflow_closure", "-u", "_GHCziIOBase_heapOverflow_closure", "-u", "_GHCziIOBase_NonTermination_closure", "-u", "_GHCziIOBase_BlockedOnDeadMVar_closure", "-u", "_GHCziIOBase_Deadlock_closure", "-u", "_GHCziWeak_runFinalizzerBatch_closure", "-u", "___stginit_Prelude"], framework_dirs = [], extra_frameworks = []} Hsc static flags: -static *** Deleting temp files Deleting: c:\ghc\ghc-6.2\ghc\compiler\stage1\ghc.exe: no input files Usage: For basic information, try the `--help' option. (I don't have cygwin installed so I'm waiting for a new *.msi to test more thoroughly.) However, I hit another problem in my build problem - pls. see "MSYS build" thread in cvs-ghc. Sincerely, Gour -- Gour gour@mail.inet.hr Registered Linux User #278493
participants (3)
-
Claus Reinke
-
Gour
-
Simon Peyton-Jones