Make GHC install libraries to e.g. xhtml-3000.2.1-0ACfOp3hebWD9jGWE4v4Gh.
[ghc.git] / utils / ghc-cabal / Main.hs
1
2 module Main (main) where
3
4 import qualified Distribution.ModuleName as ModuleName
5 import Distribution.PackageDescription
6 import Distribution.PackageDescription.Check hiding (doesFileExist)
7 import Distribution.PackageDescription.Configuration
8 import Distribution.PackageDescription.Parse
9 import Distribution.Package
10 import Distribution.System
11 import Distribution.Simple
12 import Distribution.Simple.Configure
13 import Distribution.Simple.LocalBuildInfo
14 import Distribution.Simple.GHC
15 import Distribution.Simple.Program
16 import Distribution.Simple.Program.HcPkg
17 import Distribution.Simple.Setup (ConfigFlags(configStripLibs), fromFlag, toFlag)
18 import Distribution.Simple.Utils (defaultPackageDesc, writeFileAtomic, toUTF8)
19 import Distribution.Simple.Build (writeAutogenFiles)
20 import Distribution.Simple.Register
21 import Distribution.Text
22 import Distribution.Verbosity
23 import qualified Distribution.InstalledPackageInfo as Installed
24 import qualified Distribution.Simple.PackageIndex as PackageIndex
25
26 import Control.Exception (bracket)
27 import Control.Monad
28 import qualified Data.ByteString.Lazy.Char8 as BS
29 import Data.List
30 import Data.Maybe
31 import System.IO
32 import System.Directory
33 import System.Environment
34 import System.Exit (exitWith, ExitCode(..))
35 import System.FilePath
36
37 main :: IO ()
38 main = do hSetBuffering stdout LineBuffering
39 args <- getArgs
40 case args of
41 "hscolour" : dir : distDir : args' ->
42 runHsColour dir distDir args'
43 "check" : dir : [] ->
44 doCheck dir
45 "copy" : dir : distDir
46 : strip : myDestDir : myPrefix : myLibdir : myDocdir
47 : ghcLibWays : args' ->
48 doCopy dir distDir
49 strip myDestDir myPrefix myLibdir myDocdir
50 ("dyn" `elem` words ghcLibWays)
51 args'
52 "register" : dir : distDir : ghc : ghcpkg : topdir
53 : myDestDir : myPrefix : myLibdir : myDocdir
54 : relocatableBuild : args' ->
55 doRegister dir distDir ghc ghcpkg topdir
56 myDestDir myPrefix myLibdir myDocdir
57 relocatableBuild args'
58 "configure" : dir : distDir : dll0Modules : config_args ->
59 generate dir distDir dll0Modules config_args
60 "sdist" : dir : distDir : [] ->
61 doSdist dir distDir
62 ["--version"] ->
63 defaultMainArgs ["--version"]
64 _ -> die syntax_error
65
66 syntax_error :: [String]
67 syntax_error =
68 ["syntax: ghc-cabal configure <configure-args> -- <distdir> <directory>...",
69 " ghc-cabal install <ghc-pkg> <directory> <distdir> <destdir> <prefix> <args>...",
70 " ghc-cabal hscolour <distdir> <directory> <args>..."]
71
72 die :: [String] -> IO a
73 die errs = do mapM_ (hPutStrLn stderr) errs
74 exitWith (ExitFailure 1)
75
76 withCurrentDirectory :: FilePath -> IO a -> IO a
77 withCurrentDirectory directory io
78 = bracket (getCurrentDirectory) (setCurrentDirectory)
79 (const (setCurrentDirectory directory >> io))
80
81 -- We need to use the autoconfUserHooks, as the packages that use
82 -- configure can create a .buildinfo file, and we need any info that
83 -- ends up in it.
84 userHooks :: UserHooks
85 userHooks = autoconfUserHooks
86
87 runDefaultMain :: IO ()
88 runDefaultMain
89 = do let verbosity = normal
90 gpdFile <- defaultPackageDesc verbosity
91 gpd <- readPackageDescription verbosity gpdFile
92 case buildType (flattenPackageDescription gpd) of
93 Just Configure -> defaultMainWithHooks autoconfUserHooks
94 -- time has a "Custom" Setup.hs, but it's actually Configure
95 -- plus a "./Setup test" hook. However, Cabal is also
96 -- "Custom", but doesn't have a configure script.
97 Just Custom ->
98 do configureExists <- doesFileExist "configure"
99 if configureExists
100 then defaultMainWithHooks autoconfUserHooks
101 else defaultMain
102 -- not quite right, but good enough for us:
103 _ -> defaultMain
104
105 doSdist :: FilePath -> FilePath -> IO ()
106 doSdist directory distDir
107 = withCurrentDirectory directory
108 $ withArgs (["sdist", "--builddir", distDir])
109 runDefaultMain
110
111 doCheck :: FilePath -> IO ()
112 doCheck directory
113 = withCurrentDirectory directory
114 $ do let verbosity = normal
115 gpdFile <- defaultPackageDesc verbosity
116 gpd <- readPackageDescription verbosity gpdFile
117 case filter isFailure $ checkPackage gpd Nothing of
118 [] -> return ()
119 errs -> mapM_ print errs >> exitWith (ExitFailure 1)
120 where isFailure (PackageDistSuspicious {}) = False
121 isFailure (PackageDistSuspiciousWarn {}) = False
122 isFailure _ = True
123
124 runHsColour :: FilePath -> FilePath -> [String] -> IO ()
125 runHsColour directory distdir args
126 = withCurrentDirectory directory
127 $ defaultMainArgs ("hscolour" : "--builddir" : distdir : args)
128
129 doCopy :: FilePath -> FilePath
130 -> FilePath -> FilePath -> FilePath -> FilePath -> FilePath -> Bool
131 -> [String]
132 -> IO ()
133 doCopy directory distDir
134 strip myDestDir myPrefix myLibdir myDocdir withSharedLibs
135 args
136 = withCurrentDirectory directory $ do
137 let copyArgs = ["copy", "--builddir", distDir]
138 ++ (if null myDestDir
139 then []
140 else ["--destdir", myDestDir])
141 ++ args
142 copyHooks = userHooks {
143 copyHook = noGhcPrimHook
144 $ modHook False
145 $ copyHook userHooks
146 }
147
148 defaultMainWithHooksArgs copyHooks copyArgs
149 where
150 noGhcPrimHook f pd lbi us flags
151 = let pd'
152 | packageName pd == PackageName "ghc-prim" =
153 case library pd of
154 Just lib ->
155 let ghcPrim = fromJust (simpleParse "GHC.Prim")
156 ems = filter (ghcPrim /=) (exposedModules lib)
157 lib' = lib { exposedModules = ems }
158 in pd { library = Just lib' }
159 Nothing ->
160 error "Expected a library, but none found"
161 | otherwise = pd
162 in f pd' lbi us flags
163 modHook relocatableBuild f pd lbi us flags
164 = do let verbosity = normal
165 idts = updateInstallDirTemplates relocatableBuild
166 myPrefix myLibdir myDocdir
167 (installDirTemplates lbi)
168 progs = withPrograms lbi
169 stripProgram' = stripProgram {
170 programFindLocation = \_ _ -> return (Just strip) }
171
172 progs' <- configureProgram verbosity stripProgram' progs
173 let lbi' = lbi {
174 withPrograms = progs',
175 installDirTemplates = idts,
176 configFlags = cfg,
177 stripLibs = fromFlag (configStripLibs cfg),
178 withSharedLib = withSharedLibs
179 }
180
181 -- This hack allows to interpret the "strip"
182 -- command-line argument being set to ':' to signify
183 -- disabled library stripping
184 cfg | strip == ":" = (configFlags lbi) { configStripLibs = toFlag False }
185 | otherwise = configFlags lbi
186
187 f pd lbi' us flags
188
189 doRegister :: FilePath -> FilePath -> FilePath -> FilePath
190 -> FilePath -> FilePath -> FilePath -> FilePath -> FilePath
191 -> String -> [String]
192 -> IO ()
193 doRegister directory distDir ghc ghcpkg topdir
194 myDestDir myPrefix myLibdir myDocdir
195 relocatableBuildStr args
196 = withCurrentDirectory directory $ do
197 relocatableBuild <- case relocatableBuildStr of
198 "YES" -> return True
199 "NO" -> return False
200 _ -> die ["Bad relocatableBuildStr: " ++
201 show relocatableBuildStr]
202 let regArgs = "register" : "--builddir" : distDir : args
203 regHooks = userHooks {
204 regHook = modHook relocatableBuild
205 $ regHook userHooks
206 }
207
208 defaultMainWithHooksArgs regHooks regArgs
209 where
210 modHook relocatableBuild f pd lbi us flags
211 = do let verbosity = normal
212 idts = updateInstallDirTemplates relocatableBuild
213 myPrefix myLibdir myDocdir
214 (installDirTemplates lbi)
215 progs = withPrograms lbi
216 ghcpkgconf = topdir </> "package.conf.d"
217 ghcProgram' = ghcProgram {
218 programPostConf = \_ cp -> return cp { programDefaultArgs = ["-B" ++ topdir] },
219 programFindLocation = \_ _ -> return (Just ghc) }
220 ghcPkgProgram' = ghcPkgProgram {
221 programPostConf = \_ cp -> return cp { programDefaultArgs =
222 ["--global-package-db", ghcpkgconf]
223 ++ ["--force" | not (null myDestDir) ] },
224 programFindLocation = \_ _ -> return (Just ghcpkg) }
225 configurePrograms ps conf = foldM (flip (configureProgram verbosity)) conf ps
226
227 progs' <- configurePrograms [ghcProgram', ghcPkgProgram'] progs
228 instInfos <- dump (hcPkgInfo progs') verbosity GlobalPackageDB
229 let installedPkgs' = PackageIndex.fromList instInfos
230 let updateComponentConfig (cn, clbi, deps)
231 = (cn, updateComponentLocalBuildInfo clbi, deps)
232 updateComponentLocalBuildInfo clbi
233 = clbi {
234 componentPackageDeps =
235 [ (fixupPackageId instInfos ipid, pid)
236 | (ipid,pid) <- componentPackageDeps clbi ]
237 }
238 ccs' = map updateComponentConfig (componentsConfigs lbi)
239 lbi' = lbi {
240 componentsConfigs = ccs',
241 installedPkgs = installedPkgs',
242 installDirTemplates = idts,
243 withPrograms = progs'
244 }
245 f pd lbi' us flags
246
247 updateInstallDirTemplates :: Bool -> FilePath -> FilePath -> FilePath
248 -> InstallDirTemplates
249 -> InstallDirTemplates
250 updateInstallDirTemplates relocatableBuild myPrefix myLibdir myDocdir idts
251 = idts {
252 prefix = toPathTemplate $
253 if relocatableBuild
254 then "$topdir"
255 else myPrefix,
256 libdir = toPathTemplate $
257 if relocatableBuild
258 then "$topdir"
259 else myLibdir,
260 libsubdir = toPathTemplate "$libname",
261 docdir = toPathTemplate $
262 if relocatableBuild
263 then "$topdir/../doc/html/libraries/$pkgid"
264 else (myDocdir </> "$pkgid"),
265 htmldir = toPathTemplate "$docdir"
266 }
267
268 -- The packages are built with the package ID ending in "-inplace", but
269 -- when they're installed they get the package hash appended. We need to
270 -- fix up the package deps so that they use the hash package IDs, not
271 -- the inplace package IDs.
272 fixupPackageId :: [Installed.InstalledPackageInfo]
273 -> InstalledPackageId
274 -> InstalledPackageId
275 fixupPackageId _ x@(InstalledPackageId ipi)
276 | "builtin_" `isPrefixOf` ipi = x
277 fixupPackageId ipinfos (InstalledPackageId ipi)
278 = case stripPrefix (reverse "-inplace") $ reverse ipi of
279 Nothing ->
280 error ("Installed package ID doesn't end in -inplace: " ++ show ipi)
281 Just x ->
282 let ipi' = reverse ('-' : x)
283 f (ipinfo : ipinfos') = case Installed.installedPackageId ipinfo of
284 y@(InstalledPackageId ipinfoid)
285 | ipi' `isPrefixOf` ipinfoid ->
286 y
287 _ ->
288 f ipinfos'
289 f [] = error ("Installed package ID not registered: " ++ show ipi)
290 in f ipinfos
291
292 -- On Windows we need to split the ghc package into 2 pieces, or the
293 -- DLL that it makes contains too many symbols (#5987). There are
294 -- therefore 2 libraries, not just the 1 that Cabal assumes.
295 mangleLbi :: FilePath -> FilePath -> LocalBuildInfo -> LocalBuildInfo
296 mangleLbi "compiler" "stage2" lbi
297 | isWindows =
298 let ccs' = [ (cn, updateComponentLocalBuildInfo clbi, cns)
299 | (cn, clbi, cns) <- componentsConfigs lbi ]
300 updateComponentLocalBuildInfo clbi@(LibComponentLocalBuildInfo {})
301 = let cls' = concat [ [ LibraryName n, LibraryName (n ++ "-0") ]
302 | LibraryName n <- componentLibraries clbi ]
303 in clbi { componentLibraries = cls' }
304 updateComponentLocalBuildInfo clbi = clbi
305 in lbi { componentsConfigs = ccs' }
306 where isWindows = case hostPlatform lbi of
307 Platform _ Windows -> True
308 _ -> False
309 mangleLbi _ _ lbi = lbi
310
311 generate :: FilePath -> FilePath -> String -> [String] -> IO ()
312 generate directory distdir dll0Modules config_args
313 = withCurrentDirectory directory
314 $ do let verbosity = normal
315 -- XXX We shouldn't just configure with the default flags
316 -- XXX And this, and thus the "getPersistBuildConfig distdir" below,
317 -- aren't going to work when the deps aren't built yet
318 withArgs (["configure", "--distdir", distdir] ++ config_args)
319 runDefaultMain
320
321 lbi0 <- getPersistBuildConfig distdir
322 let lbi = mangleLbi directory distdir lbi0
323 pd0 = localPkgDescr lbi
324
325 writePersistBuildConfig distdir lbi
326
327 hooked_bi <-
328 if (buildType pd0 == Just Configure) || (buildType pd0 == Just Custom)
329 then do
330 maybe_infoFile <- defaultHookedPackageDesc
331 case maybe_infoFile of
332 Nothing -> return emptyHookedBuildInfo
333 Just infoFile -> readHookedBuildInfo verbosity infoFile
334 else
335 return emptyHookedBuildInfo
336
337 let pd = updatePackageDescription hooked_bi pd0
338
339 -- generate Paths_<pkg>.hs and cabal-macros.h
340 writeAutogenFiles verbosity pd lbi
341
342 -- generate inplace-pkg-config
343 withLibLBI pd lbi $ \lib clbi ->
344 do cwd <- getCurrentDirectory
345 let ipid = InstalledPackageId (display (packageId pd) ++ "-inplace")
346 let installedPkgInfo = inplaceInstalledPackageInfo cwd distdir
347 pd ipid lib lbi clbi
348 final_ipi = installedPkgInfo {
349 Installed.installedPackageId = ipid,
350 Installed.haddockHTMLs = []
351 }
352 content = Installed.showInstalledPackageInfo final_ipi ++ "\n"
353 writeFileAtomic (distdir </> "inplace-pkg-config") (BS.pack $ toUTF8 content)
354
355 let
356 comp = compiler lbi
357 libBiModules lib = (libBuildInfo lib, libModules lib)
358 exeBiModules exe = (buildInfo exe, ModuleName.main : exeModules exe)
359 biModuless = (maybeToList $ fmap libBiModules $ library pd)
360 ++ (map exeBiModules $ executables pd)
361 buildableBiModuless = filter isBuildable biModuless
362 where isBuildable (bi', _) = buildable bi'
363 (bi, modules) = case buildableBiModuless of
364 [] -> error "No buildable component found"
365 [biModules] -> biModules
366 _ -> error ("XXX ghc-cabal can't handle " ++
367 "more than one buildinfo yet")
368 -- XXX Another Just...
369 Just ghcProg = lookupProgram ghcProgram (withPrograms lbi)
370
371 dep_pkgs = PackageIndex.topologicalOrder (packageHacks (installedPkgs lbi))
372 forDeps f = concatMap f dep_pkgs
373
374 -- copied from Distribution.Simple.PreProcess.ppHsc2Hs
375 packageHacks = case compilerFlavor (compiler lbi) of
376 GHC -> hackRtsPackage
377 _ -> id
378 -- We don't link in the actual Haskell libraries of our
379 -- dependencies, so the -u flags in the ldOptions of the rts
380 -- package mean linking fails on OS X (it's ld is a tad
381 -- stricter than gnu ld). Thus we remove the ldOptions for
382 -- GHC's rts package:
383 hackRtsPackage index =
384 case PackageIndex.lookupPackageName index (PackageName "rts") of
385 [(_,[rts])] ->
386 PackageIndex.insert rts{
387 Installed.ldOptions = [],
388 Installed.libraryDirs = filter (not . ("gcc-lib" `isSuffixOf`)) (Installed.libraryDirs rts)} index
389 -- GHC <= 6.12 had $topdir/gcc-lib in their
390 -- library-dirs for the rts package, which causes
391 -- problems when we try to use the in-tree mingw,
392 -- due to accidentally picking up the incompatible
393 -- libraries there. So we filter out gcc-lib from
394 -- the RTS's library-dirs here.
395 _ -> error "No (or multiple) ghc rts package is registered!!"
396
397 dep_ids = map snd (externalPackageDeps lbi)
398 deps = map display dep_ids
399 dep_keys
400 | packageKeySupported comp
401 = map (display
402 . Installed.packageKey
403 . fromMaybe (error "ghc-cabal: dep_keys failed")
404 . PackageIndex.lookupInstalledPackageId
405 (installedPkgs lbi)
406 . fst)
407 . externalPackageDeps
408 $ lbi
409 | otherwise = deps
410 depNames = map (display . packageName) dep_ids
411
412 transitive_dep_ids = map Installed.sourcePackageId dep_pkgs
413 transitiveDeps = map display transitive_dep_ids
414 transitiveDepKeys
415 | packageKeySupported comp
416 = map (display . Installed.packageKey) dep_pkgs
417 | otherwise = transitiveDeps
418 transitiveDepLibNames
419 | packageKeySupported comp
420 = map (\p -> packageKeyLibraryName
421 (Installed.sourcePackageId p)
422 (Installed.packageKey p)) dep_pkgs
423 | otherwise = transitiveDeps
424 transitiveDepNames = map (display . packageName) transitive_dep_ids
425
426 libraryDirs = forDeps Installed.libraryDirs
427 -- The mkLibraryRelDir function is a bit of a hack.
428 -- Ideally it should be handled in the makefiles instead.
429 mkLibraryRelDir "rts" = "rts/dist/build"
430 mkLibraryRelDir "ghc" = "compiler/stage2/build"
431 mkLibraryRelDir "Cabal" = "libraries/Cabal/Cabal/dist-install/build"
432 mkLibraryRelDir l = "libraries/" ++ l ++ "/dist-install/build"
433 libraryRelDirs = map mkLibraryRelDir transitiveDepNames
434 wrappedIncludeDirs <- wrap $ forDeps Installed.includeDirs
435 wrappedLibraryDirs <- wrap libraryDirs
436
437 let variablePrefix = directory ++ '_':distdir
438 mods = map display modules
439 otherMods = map display (otherModules bi)
440 allMods = mods ++ otherMods
441 let xs = [variablePrefix ++ "_VERSION = " ++ display (pkgVersion (package pd)),
442 variablePrefix ++ "_PACKAGE_KEY = " ++ display (pkgKey lbi),
443 -- copied from mkComponentsLocalBuildInfo
444 variablePrefix ++ "_LIB_NAME = " ++ packageKeyLibraryName (package pd) (pkgKey lbi),
445 variablePrefix ++ "_MODULES = " ++ unwords mods,
446 variablePrefix ++ "_HIDDEN_MODULES = " ++ unwords otherMods,
447 variablePrefix ++ "_SYNOPSIS =" ++ synopsis pd,
448 variablePrefix ++ "_HS_SRC_DIRS = " ++ unwords (hsSourceDirs bi),
449 variablePrefix ++ "_DEPS = " ++ unwords deps,
450 variablePrefix ++ "_DEP_KEYS = " ++ unwords dep_keys,
451 variablePrefix ++ "_DEP_NAMES = " ++ unwords depNames,
452 variablePrefix ++ "_TRANSITIVE_DEPS = " ++ unwords transitiveDeps,
453 variablePrefix ++ "_TRANSITIVE_DEP_KEYS = " ++ unwords transitiveDepKeys,
454 variablePrefix ++ "_TRANSITIVE_DEP_LIB_NAMES = " ++ unwords transitiveDepLibNames,
455 variablePrefix ++ "_TRANSITIVE_DEP_NAMES = " ++ unwords transitiveDepNames,
456 variablePrefix ++ "_INCLUDE_DIRS = " ++ unwords (includeDirs bi),
457 variablePrefix ++ "_INCLUDES = " ++ unwords (includes bi),
458 variablePrefix ++ "_INSTALL_INCLUDES = " ++ unwords (installIncludes bi),
459 variablePrefix ++ "_EXTRA_LIBRARIES = " ++ unwords (extraLibs bi),
460 variablePrefix ++ "_EXTRA_LIBDIRS = " ++ unwords (extraLibDirs bi),
461 variablePrefix ++ "_C_SRCS = " ++ unwords (cSources bi),
462 variablePrefix ++ "_CMM_SRCS := $(addprefix cbits/,$(notdir $(wildcard " ++ directory ++ "/cbits/*.cmm)))",
463 variablePrefix ++ "_DATA_FILES = " ++ unwords (dataFiles pd),
464 -- XXX This includes things it shouldn't, like:
465 -- -odir dist-bootstrapping/build
466 variablePrefix ++ "_HC_OPTS = " ++ escape (unwords
467 ( programDefaultArgs ghcProg
468 ++ hcOptions GHC bi
469 ++ languageToFlags (compiler lbi) (defaultLanguage bi)
470 ++ extensionsToFlags (compiler lbi) (usedExtensions bi)
471 ++ programOverrideArgs ghcProg)),
472 variablePrefix ++ "_CC_OPTS = " ++ unwords (ccOptions bi),
473 variablePrefix ++ "_CPP_OPTS = " ++ unwords (cppOptions bi),
474 variablePrefix ++ "_LD_OPTS = " ++ unwords (ldOptions bi),
475 variablePrefix ++ "_DEP_INCLUDE_DIRS_SINGLE_QUOTED = " ++ unwords wrappedIncludeDirs,
476 variablePrefix ++ "_DEP_CC_OPTS = " ++ unwords (forDeps Installed.ccOptions),
477 variablePrefix ++ "_DEP_LIB_DIRS_SINGLE_QUOTED = " ++ unwords wrappedLibraryDirs,
478 variablePrefix ++ "_DEP_LIB_DIRS_SEARCHPATH = " ++ mkSearchPath libraryDirs,
479 variablePrefix ++ "_DEP_LIB_REL_DIRS = " ++ unwords libraryRelDirs,
480 variablePrefix ++ "_DEP_LIB_REL_DIRS_SEARCHPATH = " ++ mkSearchPath libraryRelDirs,
481 variablePrefix ++ "_DEP_EXTRA_LIBS = " ++ unwords (forDeps Installed.extraLibraries),
482 variablePrefix ++ "_DEP_LD_OPTS = " ++ unwords (forDeps Installed.ldOptions),
483 variablePrefix ++ "_BUILD_GHCI_LIB = " ++ boolToYesNo (withGHCiLib lbi),
484 "",
485 -- Sometimes we need to modify the automatically-generated package-data.mk
486 -- bindings in a special way for the GHC build system, so allow that here:
487 "$(eval $(" ++ directory ++ "_PACKAGE_MAGIC))"
488 ]
489 writeFile (distdir ++ "/package-data.mk") $ unlines xs
490
491 writeFileUtf8 (distdir ++ "/haddock-prologue.txt") $
492 if null (description pd) then synopsis pd
493 else description pd
494 unless (null dll0Modules) $
495 do let dll0Mods = words dll0Modules
496 dllMods = allMods \\ dll0Mods
497 dllModSets = map unwords [dll0Mods, dllMods]
498 writeFile (distdir ++ "/dll-split") $ unlines dllModSets
499 where
500 escape = foldr (\c xs -> if c == '#' then '\\':'#':xs else c:xs) []
501 wrap = mapM wrap1
502 wrap1 s
503 | null s = die ["Wrapping empty value"]
504 | '\'' `elem` s = die ["Single quote in value to be wrapped:", s]
505 -- We want to be able to assume things like <space><quote> is the
506 -- start of a value, so check there are no spaces in confusing
507 -- positions
508 | head s == ' ' = die ["Leading space in value to be wrapped:", s]
509 | last s == ' ' = die ["Trailing space in value to be wrapped:", s]
510 | otherwise = return ("\'" ++ s ++ "\'")
511 mkSearchPath = intercalate [searchPathSeparator]
512 boolToYesNo True = "YES"
513 boolToYesNo False = "NO"
514
515 -- | Version of 'writeFile' that always uses UTF8 encoding
516 writeFileUtf8 f txt = withFile f WriteMode $ \hdl -> do
517 hSetEncoding hdl utf8
518 hPutStr hdl txt