generate :: FilePath -> FilePath -> String -> [String] -> IO ()
generate directory distdir dll0Modules config_args
 = withCurrentDirectory directory
 $ do let verbosity = normal
      -- XXX We shouldn't just configure with the default flags
      -- XXX And this, and thus the "getPersistBuildConfig distdir" below,
      -- aren't going to work when the deps aren't built yet
      withArgs (["configure", "--distdir", distdir] ++ config_args)
               runDefaultMain

      lbi <- getPersistBuildConfig distdir
      let pd0 = localPkgDescr lbi

      writePersistBuildConfig distdir lbi

      hooked_bi <-
           if (buildType pd0 == Just Configure) || (buildType pd0 == Just Custom)
           then do
              maybe_infoFile <- defaultHookedPackageDesc
              case maybe_infoFile of
                  Nothing       -> return emptyHookedBuildInfo
                  Just infoFile -> readHookedBuildInfo verbosity infoFile
           else
              return emptyHookedBuildInfo

      let pd = updatePackageDescription hooked_bi pd0

      -- generate Paths_<pkg>.hs and cabal-macros.h
      writeAutogenFiles verbosity pd lbi

      -- generate inplace-pkg-config
      withLibLBI pd lbi $ \lib clbi ->
          do cwd <- getCurrentDirectory
             let ipid = InstalledPackageId (display (packageId pd) ++ "-inplace")
             let installedPkgInfo = inplaceInstalledPackageInfo cwd distdir
                                        pd ipid lib lbi clbi
                 final_ipi = mangleIPI directory distdir lbi $ installedPkgInfo {
                                 Installed.installedPackageId = ipid,
                                 Installed.haddockHTMLs = []
                             }
                 content = Installed.showInstalledPackageInfo final_ipi ++ "\n"
             writeFileAtomic (distdir </> "inplace-pkg-config") (BS.pack $ toUTF8 content)

      let
          comp = compiler lbi
          libBiModules lib = (libBuildInfo lib, libModules lib)
          exeBiModules exe = (buildInfo exe, ModuleName.main : exeModules exe)
          biModuless = (maybeToList $ fmap libBiModules $ library pd)
                    ++ (map exeBiModules $ executables pd)
          buildableBiModuless = filter isBuildable biModuless
              where isBuildable (bi', _) = buildable bi'
          (bi, modules) = case buildableBiModuless of
                          [] -> error "No buildable component found"
                          [biModules] -> biModules
                          _ -> error ("XXX ghc-cabal can't handle " ++
                                      "more than one buildinfo yet")
          -- XXX Another Just...
          Just ghcProg = lookupProgram ghcProgram (withPrograms lbi)

          dep_pkgs = PackageIndex.topologicalOrder (packageHacks (installedPkgs lbi))
          forDeps f = concatMap f dep_pkgs

          -- copied from Distribution.Simple.PreProcess.ppHsc2Hs
          packageHacks = case compilerFlavor (compiler lbi) of
            GHC -> hackRtsPackage
            _   -> id
          -- We don't link in the actual Haskell libraries of our
          -- dependencies, so the -u flags in the ldOptions of the rts
          -- package mean linking fails on OS X (it's ld is a tad
          -- stricter than gnu ld). Thus we remove the ldOptions for
          -- GHC's rts package:
          hackRtsPackage index =
            case PackageIndex.lookupPackageName index (PackageName "rts") of
              [(_,[rts])] ->
                 PackageIndex.insert rts{
                     Installed.ldOptions = [],
                     Installed.libraryDirs = filter (not . ("gcc-lib" `isSuffixOf`)) (Installed.libraryDirs rts)} index
                        -- GHC <= 6.12 had $topdir/gcc-lib in their
                        -- library-dirs for the rts package, which causes
                        -- problems when we try to use the in-tree mingw,
                        -- due to accidentally picking up the incompatible
                        -- libraries there.  So we filter out gcc-lib from
                        -- the RTS's library-dirs here.
              _ -> error "No (or multiple) ghc rts package is registered!!"

          dep_ids  = map snd (externalPackageDeps lbi)
          deps     = map display dep_ids
          dep_direct = map (fromMaybe (error "ghc-cabal: dep_keys failed")
                           . PackageIndex.lookupInstalledPackageId
                                            (installedPkgs lbi)
                           . fst)
                       . externalPackageDeps
                       $ lbi
          dep_ipids = map (display . Installed.installedPackageId) dep_direct
          depLibNames
            | packageKeySupported comp
                = map (display . Installed.libraryName) dep_direct
            | otherwise = deps
          depNames = map (display . packageName) dep_ids

          transitive_dep_ids = map Installed.sourcePackageId dep_pkgs
          transitiveDeps = map display transitive_dep_ids
          transitiveDepLibNames
            | packageKeySupported comp
                = map (display . Installed.libraryName) dep_pkgs
            | otherwise = transitiveDeps
          transitiveDepNames = map (display . packageName) transitive_dep_ids

          libraryDirs = forDeps Installed.libraryDirs
          -- The mkLibraryRelDir function is a bit of a hack.
          -- Ideally it should be handled in the makefiles instead.
          mkLibraryRelDir "rts"   = "rts/dist/build"
          mkLibraryRelDir "ghc"   = "compiler/stage2/build"
          mkLibraryRelDir "Cabal" = "libraries/Cabal/Cabal/dist-install/build"
          mkLibraryRelDir l       = "libraries/" ++ l ++ "/dist-install/build"
          libraryRelDirs = map mkLibraryRelDir transitiveDepNames
      wrappedIncludeDirs <- wrap $ forDeps Installed.includeDirs
      wrappedLibraryDirs <- wrap libraryDirs

      let variablePrefix = directory ++ '_':distdir
          mods      = map display modules
          otherMods = map display (otherModules bi)
          allMods = mods ++ otherMods
      let xs = [variablePrefix ++ "_VERSION = " ++ display (pkgVersion (package pd)),
                -- TODO: move inside withLibLBI
                variablePrefix ++ "_PACKAGE_KEY = " ++ display (localPackageKey lbi),
                -- copied from mkComponentsLocalBuildInfo
                variablePrefix ++ "_LIB_NAME = " ++ display (localLibraryName lbi),
                variablePrefix ++ "_MODULES = " ++ unwords mods,
                variablePrefix ++ "_HIDDEN_MODULES = " ++ unwords otherMods,
                variablePrefix ++ "_SYNOPSIS =" ++ synopsis pd,
                variablePrefix ++ "_HS_SRC_DIRS = " ++ unwords (hsSourceDirs bi),
                variablePrefix ++ "_DEPS = " ++ unwords deps,
                variablePrefix ++ "_DEP_IPIDS = " ++ unwords dep_ipids,
                variablePrefix ++ "_DEP_NAMES = " ++ unwords depNames,
                variablePrefix ++ "_DEP_LIB_NAMES = " ++ unwords depLibNames,
                variablePrefix ++ "_TRANSITIVE_DEPS = " ++ unwords transitiveDeps,
                variablePrefix ++ "_TRANSITIVE_DEP_LIB_NAMES = " ++ unwords transitiveDepLibNames,
                variablePrefix ++ "_TRANSITIVE_DEP_NAMES = " ++ unwords transitiveDepNames,
                variablePrefix ++ "_INCLUDE_DIRS = " ++ unwords (includeDirs bi),
                variablePrefix ++ "_INCLUDES = " ++ unwords (includes bi),
                variablePrefix ++ "_INSTALL_INCLUDES = " ++ unwords (installIncludes bi),
                variablePrefix ++ "_EXTRA_LIBRARIES = " ++ unwords (extraLibs bi),
                variablePrefix ++ "_EXTRA_LIBDIRS = " ++ unwords (extraLibDirs bi),
                variablePrefix ++ "_C_SRCS  = " ++ unwords (cSources bi),
                variablePrefix ++ "_CMM_SRCS  := $(addprefix cbits/,$(notdir $(wildcard " ++ directory ++ "/cbits/*.cmm)))",
                variablePrefix ++ "_DATA_FILES = "    ++ unwords (dataFiles pd),
                -- XXX This includes things it shouldn't, like:
                -- -odir dist-bootstrapping/build
                variablePrefix ++ "_HC_OPTS = " ++ escape (unwords
                       (   programDefaultArgs ghcProg
                        ++ hcOptions GHC bi
                        ++ languageToFlags (compiler lbi) (defaultLanguage bi)
                        ++ extensionsToFlags (compiler lbi) (usedExtensions bi)
                        ++ programOverrideArgs ghcProg)),
                variablePrefix ++ "_CC_OPTS = "                        ++ unwords (ccOptions bi),
                variablePrefix ++ "_CPP_OPTS = "                       ++ unwords (cppOptions bi),
                variablePrefix ++ "_LD_OPTS = "                        ++ unwords (ldOptions bi),
                variablePrefix ++ "_DEP_INCLUDE_DIRS_SINGLE_QUOTED = " ++ unwords wrappedIncludeDirs,
                variablePrefix ++ "_DEP_CC_OPTS = "                    ++ unwords (forDeps Installed.ccOptions),
                variablePrefix ++ "_DEP_LIB_DIRS_SINGLE_QUOTED = "     ++ unwords wrappedLibraryDirs,
                variablePrefix ++ "_DEP_LIB_DIRS_SEARCHPATH = "        ++ mkSearchPath libraryDirs,
                variablePrefix ++ "_DEP_LIB_REL_DIRS = "               ++ unwords libraryRelDirs,
                variablePrefix ++ "_DEP_LIB_REL_DIRS_SEARCHPATH = "    ++ mkSearchPath libraryRelDirs,
                variablePrefix ++ "_DEP_EXTRA_LIBS = "                 ++ unwords (forDeps Installed.extraLibraries),
                variablePrefix ++ "_DEP_LD_OPTS = "                    ++ unwords (forDeps Installed.ldOptions),
                variablePrefix ++ "_BUILD_GHCI_LIB = "                 ++ boolToYesNo (withGHCiLib lbi),
                "",
                -- Sometimes we need to modify the automatically-generated package-data.mk
                -- bindings in a special way for the GHC build system, so allow that here:
                "$(eval $(" ++ directory ++ "_PACKAGE_MAGIC))"
                ]
      writeFile (distdir ++ "/package-data.mk") $ unlines xs

      writeFileUtf8 (distdir ++ "/haddock-prologue.txt") $
          if null (description pd) then synopsis pd
                                   else description pd
      unless (null dll0Modules) $
          do let dll0Mods = words dll0Modules
                 dllMods = allMods \\ dll0Mods
                 dllModSets = map unwords [dll0Mods, dllMods]
             writeFile (distdir ++ "/dll-split") $ unlines dllModSets
  where
     escape = foldr (\c xs -> if c == '#' then '\\':'#':xs else c:xs) []
     wrap = mapM wrap1
     wrap1 s
      | null s        = die ["Wrapping empty value"]
      | '\'' `elem` s = die ["Single quote in value to be wrapped:", s]
      -- We want to be able to assume things like <space><quote> is the
      -- start of a value, so check there are no spaces in confusing
      -- positions
      | head s == ' ' = die ["Leading space in value to be wrapped:", s]
      | last s == ' ' = die ["Trailing space in value to be wrapped:", s]
      | otherwise     = return ("\'" ++ s ++ "\'")
     mkSearchPath = intercalate [searchPathSeparator]
     boolToYesNo True = "YES"
     boolToYesNo False = "NO"

     -- | Version of 'writeFile' that always uses UTF8 encoding
     writeFileUtf8 f txt = withFile f WriteMode $ \hdl -> do
         hSetEncoding hdl utf8
         hPutStr hdl txt
generate :: FilePath -> FilePath -> String -> [String] -> IO ()
generate directory distdir dll0Modules config_args
 = withCurrentDirectory directory
 $ do let verbosity = normal
      -- XXX We shouldn't just configure with the default flags
      -- XXX And this, and thus the "getPersistBuildConfig distdir" below,
      -- aren't going to work when the deps aren't built yet
      withArgs (["configure", "--distdir", distdir] ++ config_args)
               runDefaultMain

      lbi <- getPersistBuildConfig distdir
      let pd0 = localPkgDescr lbi

      writePersistBuildConfig distdir lbi

      hooked_bi <-
           if (buildType pd0 == Just Configure) || (buildType pd0 == Just Custom)
           then do
              maybe_infoFile <- defaultHookedPackageDesc
              case maybe_infoFile of
                  Nothing       -> return emptyHookedBuildInfo
                  Just infoFile -> readHookedBuildInfo verbosity infoFile
           else
              return emptyHookedBuildInfo

      let pd = updatePackageDescription hooked_bi pd0

      -- generate Paths_<pkg>.hs and cabal-macros.h
      writeAutogenFiles verbosity pd lbi

      -- generate inplace-pkg-config
      withLibLBI pd lbi $ \lib clbi ->
          do cwd <- getCurrentDirectory
             let ipid = InstalledPackageId (display (packageId pd) ++ "-inplace")
             let installedPkgInfo = inplaceInstalledPackageInfo cwd distdir
                                        pd ipid lib lbi clbi
                 final_ipi = mangleIPI directory distdir lbi $ installedPkgInfo {
                                 Installed.installedPackageId = ipid,
                                 Installed.haddockHTMLs = []
                             }
                 content = Installed.showInstalledPackageInfo final_ipi ++ "\n"
             writeFileAtomic (distdir </> "inplace-pkg-config") (BS.pack $ toUTF8 content)

      let
          comp = compiler lbi
          libBiModules lib = (libBuildInfo lib, libModules lib)
          exeBiModules exe = (buildInfo exe, ModuleName.main : exeModules exe)
          biModuless = (maybeToList $ fmap libBiModules $ library pd)
                    ++ (map exeBiModules $ executables pd)
          buildableBiModuless = filter isBuildable biModuless
              where isBuildable (bi', _) = buildable bi'
          (bi, modules) = case buildableBiModuless of
                          [] -> error "No buildable component found"
                          [biModules] -> biModules
                          _ -> error ("XXX ghc-cabal can't handle " ++
                                      "more than one buildinfo yet")
          -- XXX Another Just...
          Just ghcProg = lookupProgram ghcProgram (withPrograms lbi)

          dep_pkgs = PackageIndex.topologicalOrder (packageHacks (installedPkgs lbi))
          forDeps f = concatMap f dep_pkgs

          -- copied from Distribution.Simple.PreProcess.ppHsc2Hs
          packageHacks = case compilerFlavor (compiler lbi) of
            GHC -> hackRtsPackage
            _   -> id
          -- We don't link in the actual Haskell libraries of our
          -- dependencies, so the -u flags in the ldOptions of the rts
          -- package mean linking fails on OS X (it's ld is a tad
          -- stricter than gnu ld). Thus we remove the ldOptions for
          -- GHC's rts package:
          hackRtsPackage index =
            case PackageIndex.lookupPackageName index (PackageName "rts") of
              [(_,[rts])] ->
                 PackageIndex.insert rts{
                     Installed.ldOptions = [],
                     Installed.libraryDirs = filter (not . ("gcc-lib" `isSuffixOf`)) (Installed.libraryDirs rts)} index
                        -- GHC <= 6.12 had $topdir/gcc-lib in their
                        -- library-dirs for the rts package, which causes
                        -- problems when we try to use the in-tree mingw,
                        -- due to accidentally picking up the incompatible
                        -- libraries there.  So we filter out gcc-lib from
                        -- the RTS's library-dirs here.
              _ -> error "No (or multiple) ghc rts package is registered!!"

          dep_ids  = map snd (externalPackageDeps lbi)
          deps     = map display dep_ids
          dep_direct = map (fromMaybe (error "ghc-cabal: dep_keys failed")
                           . PackageIndex.lookupInstalledPackageId
                                            (installedPkgs lbi)
                           . fst)
                       . externalPackageDeps
                       $ lbi
          dep_ipids = map (display . Installed.installedPackageId) dep_direct
          depLibNames
            | packageKeySupported comp
                = map (display . Installed.libraryName) dep_direct
            | otherwise = deps
          depNames = map (display . packageName) dep_ids

          transitive_dep_ids = map Installed.sourcePackageId dep_pkgs
          transitiveDeps = map display transitive_dep_ids
          transitiveDepLibNames
            | packageKeySupported comp
                = map (display . Installed.libraryName) dep_pkgs
            | otherwise = transitiveDeps
          transitiveDepNames = map (display . packageName) transitive_dep_ids

          libraryDirs = forDeps Installed.libraryDirs
          -- The mkLibraryRelDir function is a bit of a hack.
          -- Ideally it should be handled in the makefiles instead.
          mkLibraryRelDir "rts"   = "rts/dist/build"
          mkLibraryRelDir "ghc"   = "compiler/stage2/build"
          mkLibraryRelDir "Cabal" = "libraries/Cabal/Cabal/dist-install/build"
          mkLibraryRelDir l       = "libraries/" ++ l ++ "/dist-install/build"
          libraryRelDirs = map mkLibraryRelDir transitiveDepNames
      wrappedIncludeDirs <- wrap $ forDeps Installed.includeDirs
      wrappedLibraryDirs <- wrap libraryDirs

      let variablePrefix = directory ++ '_':distdir
          mods      = map display modules
          otherMods = map display (otherModules bi)
          allMods = mods ++ otherMods
      let xs = [variablePrefix ++ "_VERSION = " ++ display (pkgVersion (package pd)),
                -- TODO: move inside withLibLBI
                variablePrefix ++ "_PACKAGE_KEY = " ++ display (localPackageKey lbi),
                -- copied from mkComponentsLocalBuildInfo
                variablePrefix ++ "_LIB_NAME = " ++ display (localLibraryName lbi),
                variablePrefix ++ "_MODULES = " ++ unwords mods,
                variablePrefix ++ "_HIDDEN_MODULES = " ++ unwords otherMods,
                variablePrefix ++ "_SYNOPSIS =" ++ synopsis pd,
                variablePrefix ++ "_HS_SRC_DIRS = " ++ unwords (hsSourceDirs bi),
                variablePrefix ++ "_DEPS = " ++ unwords deps,
                variablePrefix ++ "_DEP_IPIDS = " ++ unwords dep_ipids,
                variablePrefix ++ "_DEP_NAMES = " ++ unwords depNames,
                variablePrefix ++ "_DEP_LIB_NAMES = " ++ unwords depLibNames,
                variablePrefix ++ "_TRANSITIVE_DEPS = " ++ unwords transitiveDeps,
                variablePrefix ++ "_TRANSITIVE_DEP_LIB_NAMES = " ++ unwords transitiveDepLibNames,
                variablePrefix ++ "_TRANSITIVE_DEP_NAMES = " ++ unwords transitiveDepNames,
                variablePrefix ++ "_INCLUDE_DIRS = " ++ unwords (includeDirs bi),
                variablePrefix ++ "_INCLUDES = " ++ unwords (includes bi),
                variablePrefix ++ "_INSTALL_INCLUDES = " ++ unwords (installIncludes bi),
                variablePrefix ++ "_EXTRA_LIBRARIES = " ++ unwords (extraLibs bi),
                variablePrefix ++ "_EXTRA_LIBDIRS = " ++ unwords (extraLibDirs bi),
                variablePrefix ++ "_C_SRCS  = " ++ unwords (cSources bi),
                variablePrefix ++ "_CMM_SRCS  := $(addprefix cbits/,$(notdir $(wildcard " ++ directory ++ "/cbits/*.cmm)))",
                variablePrefix ++ "_DATA_FILES = "    ++ unwords (dataFiles pd),
                -- XXX This includes things it shouldn't, like:
                -- -odir dist-bootstrapping/build
                variablePrefix ++ "_HC_OPTS = " ++ escape (unwords
                       (   programDefaultArgs ghcProg
                        ++ hcOptions GHC bi
                        ++ languageToFlags (compiler lbi) (defaultLanguage bi)
                        ++ extensionsToFlags (compiler lbi) (usedExtensions bi)
                        ++ programOverrideArgs ghcProg)),
                variablePrefix ++ "_CC_OPTS = "                        ++ unwords (ccOptions bi),
                variablePrefix ++ "_CPP_OPTS = "                       ++ unwords (cppOptions bi),
                variablePrefix ++ "_LD_OPTS = "                        ++ unwords (ldOptions bi),
                variablePrefix ++ "_DEP_INCLUDE_DIRS_SINGLE_QUOTED = " ++ unwords wrappedIncludeDirs,
                variablePrefix ++ "_DEP_CC_OPTS = "                    ++ unwords (forDeps Installed.ccOptions),
                variablePrefix ++ "_DEP_LIB_DIRS_SINGLE_QUOTED = "     ++ unwords wrappedLibraryDirs,
                variablePrefix ++ "_DEP_LIB_DIRS_SEARCHPATH = "        ++ mkSearchPath libraryDirs,
                variablePrefix ++ "_DEP_LIB_REL_DIRS = "               ++ unwords libraryRelDirs,
                variablePrefix ++ "_DEP_LIB_REL_DIRS_SEARCHPATH = "    ++ mkSearchPath libraryRelDirs,
                variablePrefix ++ "_DEP_EXTRA_LIBS = "                 ++ unwords (forDeps Installed.extraLibraries),
                variablePrefix ++ "_DEP_LD_OPTS = "                    ++ unwords (forDeps Installed.ldOptions),
                variablePrefix ++ "_BUILD_GHCI_LIB = "                 ++ boolToYesNo (withGHCiLib lbi),
                "",
                -- Sometimes we need to modify the automatically-generated package-data.mk
                -- bindings in a special way for the GHC build system, so allow that here:
                "$(eval $(" ++ directory ++ "_PACKAGE_MAGIC))"
                ]
      writeFile (distdir ++ "/package-data.mk") $ unlines xs

      writeFileUtf8 (distdir ++ "/haddock-prologue.txt") $
          if null (description pd) then synopsis pd
                                   else description pd
      unless (null dll0Modules) $
          do let dll0Mods = words dll0Modules
                 dllMods = allMods \\ dll0Mods
                 dllModSets = map unwords [dll0Mods, dllMods]
             writeFile (distdir ++ "/dll-split") $ unlines dllModSets
  where
     escape = foldr (\c xs -> if c == '#' then '\\':'#':xs else c:xs) []
     wrap = mapM wrap1
     wrap1 s
      | null s        = die ["Wrapping empty value"]
      | '\'' `elem` s = die ["Single quote in value to be wrapped:", s]
      -- We want to be able to assume things like <space><quote> is the
      -- start of a value, so check there are no spaces in confusing
      -- positions
      | head s == ' ' = die ["Leading space in value to be wrapped:", s]
      | last s == ' ' = die ["Trailing space in value to be wrapped:", s]
      | otherwise     = return ("\'" ++ s ++ "\'")
     mkSearchPath = intercalate [searchPathSeparator]
     boolToYesNo True = "YES"
     boolToYesNo False = "NO"

     -- | Version of 'writeFile' that always uses UTF8 encoding
     writeFileUtf8 f txt = withFile f WriteMode $ \hdl -> do
         hSetEncoding hdl utf8
         hPutStr hdl txt
generate directory distdir dll0Modules config_args
 = withCurrentDirectory directory
 $ do let verbosity = normal
      -- XXX We shouldn't just configure with the default flags
      -- XXX And this, and thus the "getPersistBuildConfig distdir" below,
      -- aren't going to work when the deps aren't built yet
      withArgs (["configure", "--distdir", distdir] ++ config_args)
               runDefaultMain

      lbi <- getPersistBuildConfig distdir
      let pd0 = localPkgDescr lbi

      writePersistBuildConfig distdir lbi

      hooked_bi <-
           if (buildType pd0 == Just Configure) || (buildType pd0 == Just Custom)
           then do
              maybe_infoFile <- defaultHookedPackageDesc
              case maybe_infoFile of
                  Nothing       -> return emptyHookedBuildInfo
                  Just infoFile -> readHookedBuildInfo verbosity infoFile
           else
              return emptyHookedBuildInfo

      let pd = updatePackageDescription hooked_bi pd0

      -- generate Paths_<pkg>.hs and cabal-macros.h
      writeAutogenFiles verbosity pd lbi

      -- generate inplace-pkg-config
      withLibLBI pd lbi $ \lib clbi ->
          do cwd <- getCurrentDirectory
             let ipid = InstalledPackageId (display (packageId pd) ++ "-inplace")
             let installedPkgInfo = inplaceInstalledPackageInfo cwd distdir
                                        pd ipid lib lbi clbi
                 final_ipi = mangleIPI directory distdir lbi $ installedPkgInfo {
                                 Installed.installedPackageId = ipid,
                                 Installed.haddockHTMLs = []
                             }
                 content = Installed.showInstalledPackageInfo final_ipi ++ "\n"
             writeFileAtomic (distdir </> "inplace-pkg-config") (BS.pack $ toUTF8 content)

      let
          comp = compiler lbi
          libBiModules lib = (libBuildInfo lib, libModules lib)
          exeBiModules exe = (buildInfo exe, ModuleName.main : exeModules exe)
          biModuless = (maybeToList $ fmap libBiModules $ library pd)
                    ++ (map exeBiModules $ executables pd)
          buildableBiModuless = filter isBuildable biModuless
              where isBuildable (bi', _) = buildable bi'
          (bi, modules) = case buildableBiModuless of
                          [] -> error "No buildable component found"
                          [biModules] -> biModules
                          _ -> error ("XXX ghc-cabal can't handle " ++
                                      "more than one buildinfo yet")
          -- XXX Another Just...
          Just ghcProg = lookupProgram ghcProgram (withPrograms lbi)

          dep_pkgs = PackageIndex.topologicalOrder (packageHacks (installedPkgs lbi))
          forDeps f = concatMap f dep_pkgs

          -- copied from Distribution.Simple.PreProcess.ppHsc2Hs
          packageHacks = case compilerFlavor (compiler lbi) of
            GHC -> hackRtsPackage
            _   -> id
          -- We don't link in the actual Haskell libraries of our
          -- dependencies, so the -u flags in the ldOptions of the rts
          -- package mean linking fails on OS X (it's ld is a tad
          -- stricter than gnu ld). Thus we remove the ldOptions for
          -- GHC's rts package:
          hackRtsPackage index =
            case PackageIndex.lookupPackageName index (PackageName "rts") of
              [(_,[rts])] ->
                 PackageIndex.insert rts{
                     Installed.ldOptions = [],
                     Installed.libraryDirs = filter (not . ("gcc-lib" `isSuffixOf`)) (Installed.libraryDirs rts)} index
                        -- GHC <= 6.12 had $topdir/gcc-lib in their
                        -- library-dirs for the rts package, which causes
                        -- problems when we try to use the in-tree mingw,
                        -- due to accidentally picking up the incompatible
                        -- libraries there.  So we filter out gcc-lib from
                        -- the RTS's library-dirs here.
              _ -> error "No (or multiple) ghc rts package is registered!!"

          dep_ids  = map snd (externalPackageDeps lbi)
          deps     = map display dep_ids
          dep_direct = map (fromMaybe (error "ghc-cabal: dep_keys failed")
                           . PackageIndex.lookupInstalledPackageId
                                            (installedPkgs lbi)
                           . fst)
                       . externalPackageDeps
                       $ lbi
          dep_ipids = map (display . Installed.installedPackageId) dep_direct
          depLibNames
            | packageKeySupported comp
                = map (display . Installed.libraryName) dep_direct
            | otherwise = deps
          depNames = map (display . packageName) dep_ids

          transitive_dep_ids = map Installed.sourcePackageId dep_pkgs
          transitiveDeps = map display transitive_dep_ids
          transitiveDepLibNames
            | packageKeySupported comp
                = map (display . Installed.libraryName) dep_pkgs
            | otherwise = transitiveDeps
          transitiveDepNames = map (display . packageName) transitive_dep_ids

          libraryDirs = forDeps Installed.libraryDirs
          -- The mkLibraryRelDir function is a bit of a hack.
          -- Ideally it should be handled in the makefiles instead.
          mkLibraryRelDir "rts"   = "rts/dist/build"
          mkLibraryRelDir "ghc"   = "compiler/stage2/build"
          mkLibraryRelDir "Cabal" = "libraries/Cabal/Cabal/dist-install/build"
          mkLibraryRelDir l       = "libraries/" ++ l ++ "/dist-install/build"
          libraryRelDirs = map mkLibraryRelDir transitiveDepNames
      wrappedIncludeDirs <- wrap $ forDeps Installed.includeDirs
      wrappedLibraryDirs <- wrap libraryDirs

      let variablePrefix = directory ++ '_':distdir
          mods      = map display modules
          otherMods = map display (otherModules bi)
          allMods = mods ++ otherMods
      let xs = [variablePrefix ++ "_VERSION = " ++ display (pkgVersion (package pd)),
                -- TODO: move inside withLibLBI
                variablePrefix ++ "_PACKAGE_KEY = " ++ display (localPackageKey lbi),
                -- copied from mkComponentsLocalBuildInfo
                variablePrefix ++ "_LIB_NAME = " ++ display (localLibraryName lbi),
                variablePrefix ++ "_MODULES = " ++ unwords mods,
                variablePrefix ++ "_HIDDEN_MODULES = " ++ unwords otherMods,
                variablePrefix ++ "_SYNOPSIS =" ++ synopsis pd,
                variablePrefix ++ "_HS_SRC_DIRS = " ++ unwords (hsSourceDirs bi),
                variablePrefix ++ "_DEPS = " ++ unwords deps,
                variablePrefix ++ "_DEP_IPIDS = " ++ unwords dep_ipids,
                variablePrefix ++ "_DEP_NAMES = " ++ unwords depNames,
                variablePrefix ++ "_DEP_LIB_NAMES = " ++ unwords depLibNames,
                variablePrefix ++ "_TRANSITIVE_DEPS = " ++ unwords transitiveDeps,
                variablePrefix ++ "_TRANSITIVE_DEP_LIB_NAMES = " ++ unwords transitiveDepLibNames,
                variablePrefix ++ "_TRANSITIVE_DEP_NAMES = " ++ unwords transitiveDepNames,
                variablePrefix ++ "_INCLUDE_DIRS = " ++ unwords (includeDirs bi),
                variablePrefix ++ "_INCLUDES = " ++ unwords (includes bi),
                variablePrefix ++ "_INSTALL_INCLUDES = " ++ unwords (installIncludes bi),
                variablePrefix ++ "_EXTRA_LIBRARIES = " ++ unwords (extraLibs bi),
                variablePrefix ++ "_EXTRA_LIBDIRS = " ++ unwords (extraLibDirs bi),
                variablePrefix ++ "_C_SRCS  = " ++ unwords (cSources bi),
                variablePrefix ++ "_CMM_SRCS  := $(addprefix cbits/,$(notdir $(wildcard " ++ directory ++ "/cbits/*.cmm)))",
                variablePrefix ++ "_DATA_FILES = "    ++ unwords (dataFiles pd),
                -- XXX This includes things it shouldn't, like:
                -- -odir dist-bootstrapping/build
                variablePrefix ++ "_HC_OPTS = " ++ escape (unwords
                       (   programDefaultArgs ghcProg
                        ++ hcOptions GHC bi
                        ++ languageToFlags (compiler lbi) (defaultLanguage bi)
                        ++ extensionsToFlags (compiler lbi) (usedExtensions bi)
                        ++ programOverrideArgs ghcProg)),
                variablePrefix ++ "_CC_OPTS = "                        ++ unwords (ccOptions bi),
                variablePrefix ++ "_CPP_OPTS = "                       ++ unwords (cppOptions bi),
                variablePrefix ++ "_LD_OPTS = "                        ++ unwords (ldOptions bi),
                variablePrefix ++ "_DEP_INCLUDE_DIRS_SINGLE_QUOTED = " ++ unwords wrappedIncludeDirs,
                variablePrefix ++ "_DEP_CC_OPTS = "                    ++ unwords (forDeps Installed.ccOptions),
                variablePrefix ++ "_DEP_LIB_DIRS_SINGLE_QUOTED = "     ++ unwords wrappedLibraryDirs,
                variablePrefix ++ "_DEP_LIB_DIRS_SEARCHPATH = "        ++ mkSearchPath libraryDirs,
                variablePrefix ++ "_DEP_LIB_REL_DIRS = "               ++ unwords libraryRelDirs,
                variablePrefix ++ "_DEP_LIB_REL_DIRS_SEARCHPATH = "    ++ mkSearchPath libraryRelDirs,
                variablePrefix ++ "_DEP_EXTRA_LIBS = "                 ++ unwords (forDeps Installed.extraLibraries),
                variablePrefix ++ "_DEP_LD_OPTS = "                    ++ unwords (forDeps Installed.ldOptions),
                variablePrefix ++ "_BUILD_GHCI_LIB = "                 ++ boolToYesNo (withGHCiLib lbi),
                "",
                -- Sometimes we need to modify the automatically-generated package-data.mk
                -- bindings in a special way for the GHC build system, so allow that here:
                "$(eval $(" ++ directory ++ "_PACKAGE_MAGIC))"
                ]
      writeFile (distdir ++ "/package-data.mk") $ unlines xs

      writeFileUtf8 (distdir ++ "/haddock-prologue.txt") $
          if null (description pd) then synopsis pd
                                   else description pd
      unless (null dll0Modules) $
          do let dll0Mods = words dll0Modules
                 dllMods = allMods \\ dll0Mods
                 dllModSets = map unwords [dll0Mods, dllMods]
             writeFile (distdir ++ "/dll-split") $ unlines dllModSets
  where
     escape = foldr (\c xs -> if c == '#' then '\\':'#':xs else c:xs) []
     wrap = mapM wrap1
     wrap1 s
      | null s        = die ["Wrapping empty value"]
      | '\'' `elem` s = die ["Single quote in value to be wrapped:", s]
      -- We want to be able to assume things like <space><quote> is the
      -- start of a value, so check there are no spaces in confusing
      -- positions
      | head s == ' ' = die ["Leading space in value to be wrapped:", s]
      | last s == ' ' = die ["Trailing space in value to be wrapped:", s]
      | otherwise     = return ("\'" ++ s ++ "\'")
     mkSearchPath = intercalate [searchPathSeparator]
     boolToYesNo True = "YES"
     boolToYesNo False = "NO"

     -- | Version of 'writeFile' that always uses UTF8 encoding
     writeFileUtf8 f txt = withFile f WriteMode $ \hdl -> do
         hSetEncoding hdl utf8
         hPutStr hdl txt