2 module Main (main) where
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.Simple
10 import Distribution.Simple.Configure
11 import Distribution.Simple.LocalBuildInfo
12 import Distribution.Simple.Program
13 import Distribution.Simple.Utils (defaultPackageDesc, writeFileAtomic)
14 import Distribution.Simple.Build (writeAutogenFiles)
15 import Distribution.Simple.Register
16 import Distribution.Text
17 import Distribution.Verbosity
18 import qualified Distribution.InstalledPackageInfo as Installed
19 import qualified Distribution.Simple.PackageIndex as PackageIndex
24 import System.Directory
25 import System.Environment
27 import System.FilePath
31 main = do args <- getArgs
33 "haddock" : distDir : dir : args' ->
34 runHaddock distDir dir args'
37 "install" : ghcpkg : ghcpkgconfig : directory : distDir
38 : myDestDir : myPrefix : myLibdir : myDocdir : args' ->
39 doInstall ghcpkg ghcpkgconfig directory distDir
40 myDestDir myPrefix myLibdir myDocdir args'
41 "configure" : args' -> case break (== "--") args' of
42 (config_args, "--" : distdir : directories) ->
43 mapM_ (generate config_args distdir) directories
47 syntax_error :: [String]
49 ["syntax: ghc-cabal configure <configure-args> -- <distdir> <directory>...",
50 " ghc-cabal install <ghc-pkg> <directory> <distdir> <destdir> <prefix> <args>...",
51 " ghc-cabal haddock <distdir> <directory> <args>..."]
53 die :: [String] -> IO ()
54 die errs = do mapM_ (hPutStrLn stderr) errs
55 exitWith (ExitFailure 1)
57 -- XXX Should use bracket
58 withCurrentDirectory :: FilePath -> IO a -> IO a
59 withCurrentDirectory directory io
60 = do curDirectory <- getCurrentDirectory
61 setCurrentDirectory directory
63 setCurrentDirectory curDirectory
66 -- We need to use the autoconfUserHooks, as the packages that use
67 -- configure can create a .buildinfo file, and we need any info that
69 userHooks :: UserHooks
70 userHooks = autoconfUserHooks
72 doCheck :: FilePath -> IO ()
74 = withCurrentDirectory directory
75 $ do let verbosity = normal
76 gpdFile <- defaultPackageDesc verbosity
77 gpd <- readPackageDescription verbosity gpdFile
78 case partition isFailure $ checkPackage gpd Nothing of
80 ([], warnings) -> mapM_ print warnings
81 (errs, _) -> do mapM_ print errs
82 exitWith (ExitFailure 1)
83 where isFailure (PackageDistSuspicious {}) = False
86 runHaddock :: FilePath -> FilePath -> [String] -> IO ()
87 runHaddock distdir directory args
88 = withCurrentDirectory directory
89 $ defaultMainWithHooksArgs hooks ("haddock" : "--builddir" : distdir : args)
92 haddockHook = modHook (haddockHook userHooks)
94 modHook f pd lbi us flags
95 | packageName pd == PackageName "ghc-prim"
96 = let pd' = case library pd of
98 let ghcPrim = fromJust (simpleParse "GHC.Prim")
99 ems = filter (ghcPrim /=)
101 lib' = lib { exposedModules = ems }
102 in pd { library = Just lib' }
104 error "Expected a library, but none found"
105 pc = withPrograms lbi
106 pc' = userSpecifyArgs "haddock"
107 ["dist-install/build/autogen/GHC/Prim.hs"] pc
108 lbi' = lbi { withPrograms = pc' }
109 in f pd' lbi' us flags
113 doInstall :: FilePath -> FilePath -> FilePath -> FilePath -> FilePath
114 -> FilePath -> FilePath -> FilePath -> [String] -> IO ()
115 doInstall ghcpkg ghcpkgconf directory distDir myDestDir myPrefix myLibdir myDocdir args
116 = withCurrentDirectory directory $ do
117 defaultMainWithHooksArgs hooks (["copy", "--builddir", distDir]
118 ++ (if null myDestDir then []
119 else ["--destdir", myDestDir])
121 defaultMainWithHooksArgs hooks ("register" : "--builddir" : distDir : args)
124 copyHook = noGhcPrimHook (modHook (copyHook userHooks)),
125 regHook = modHook (regHook userHooks)
128 noGhcPrimHook f pd lbi us flags
130 | packageName pd == PackageName "ghc-prim" =
133 let ghcPrim = fromJust (simpleParse "GHC.Prim")
134 ems = filter (ghcPrim /=) (exposedModules lib)
135 lib' = lib { exposedModules = ems }
136 in pd { library = Just lib' }
138 error "Expected a library, but none found"
140 in f pd' lbi us flags
141 modHook f pd lbi us flags
142 = let idts = installDirTemplates lbi
143 idts' = idts { prefix = toPathTemplate myPrefix,
144 libdir = toPathTemplate myLibdir,
145 libsubdir = toPathTemplate "$pkgid",
146 docdir = toPathTemplate (myDocdir </> "$pkg"),
147 htmldir = toPathTemplate "$docdir" }
148 progs = withPrograms lbi
149 prog = ConfiguredProgram {
150 programId = programName ghcPkgProgram,
151 programVersion = Nothing,
152 programArgs = ["--global-conf", ghcpkgconf]
153 ++ if not (null myDestDir)
156 programLocation = UserSpecified ghcpkg
158 progs' = updateProgram prog progs
160 installDirTemplates = idts',
161 withPrograms = progs'
163 in f pd lbi' us flags
165 generate :: [String] -> FilePath -> FilePath -> IO ()
166 generate config_args distdir directory
167 = withCurrentDirectory directory
168 $ do let verbosity = normal
169 gpdFile <- defaultPackageDesc verbosity
170 gpd <- readPackageDescription verbosity gpdFile
172 -- XXX We shouldn't just configure with the default flags
173 -- XXX And this, and thus the "getPersistBuildConfig distdir" below,
174 -- aren't going to work when the deps aren't built yet
175 withArgs (["configure", "--distdir", distdir] ++ config_args)
176 (case buildType (flattenPackageDescription gpd) of
177 Just Configure -> defaultMainWithHooks autoconfUserHooks
178 -- time has a "Custom" Setup.hs, but it's actually Configure
179 -- plus a "./Setup test" hook. However, Cabal is also
180 -- "Custom", but doesn't have a configure script.
182 do configureExists <- doesFileExist "configure"
184 then defaultMainWithHooks autoconfUserHooks
186 -- not quite right, but good enough for us:
189 lbi <- getPersistBuildConfig distdir
190 let pd0 = localPkgDescr lbi
193 if (buildType pd0 == Just Configure) || (buildType pd0 == Just Custom)
195 maybe_infoFile <- defaultHookedPackageDesc
196 case maybe_infoFile of
197 Nothing -> return emptyHookedBuildInfo
198 Just infoFile -> readHookedBuildInfo verbosity infoFile
200 return emptyHookedBuildInfo
202 let pd = updatePackageDescription hooked_bi pd0
204 -- generate Paths_<pkg>.hs and cabal-macros.h
205 writeAutogenFiles verbosity pd lbi
207 -- generate inplace-pkg-config
208 case (library pd, libraryConfig lbi) of
209 (Nothing, Nothing) -> return ()
210 (Just lib, Just clbi) -> do
211 cwd <- getCurrentDirectory
212 let ipid = InstalledPackageId (display (packageId pd) ++ "-inplace")
213 let installedPkgInfo = inplaceInstalledPackageInfo cwd distdir
215 final_ipi = installedPkgInfo{ Installed.installedPackageId = ipid }
216 content = Installed.showInstalledPackageInfo final_ipi ++ "\n"
217 writeFileAtomic (distdir </> "inplace-pkg-config") content
218 _ -> error "Inconsistent lib components; can't happen?"
221 libBiModules lib = (libBuildInfo lib, libModules lib)
222 exeBiModules exe = (buildInfo exe, ModuleName.main : exeModules exe)
223 biModuless = (maybeToList $ fmap libBiModules $ library pd)
224 ++ (map exeBiModules $ executables pd)
225 buildableBiModuless = filter isBuildable biModuless
226 where isBuildable (bi', _) = buildable bi'
227 (bi, modules) = case buildableBiModuless of
228 [] -> error "No buildable component found"
229 [biModules] -> biModules
230 _ -> error ("XXX ghc-cabal can't handle " ++
231 "more than one buildinfo yet")
232 -- XXX Another Just...
233 Just ghcProg = lookupProgram ghcProgram (withPrograms lbi)
235 dep_pkgs = PackageIndex.topologicalOrder (packageHacks (installedPkgs lbi))
236 forDeps f = concatMap f dep_pkgs
238 -- copied from Distribution.Simple.PreProcess.ppHsc2Hs
239 packageHacks = case compilerFlavor (compiler lbi) of
240 GHC -> hackRtsPackage
242 -- We don't link in the actual Haskell libraries of our
243 -- dependencies, so the -u flags in the ldOptions of the rts
244 -- package mean linking fails on OS X (it's ld is a tad
245 -- stricter than gnu ld). Thus we remove the ldOptions for
246 -- GHC's rts package:
247 hackRtsPackage index =
248 case PackageIndex.lookupInstalledPackageByName index (PackageName "rts") of
249 [rts] -> PackageIndex.addToInstalledPackageIndex rts { Installed.ldOptions = [] } index
250 _ -> error "No (or multiple) ghc rts package is registered!!"
252 dep_ids = map (packageId.getLocalPackageInfo lbi) $
253 externalPackageDeps lbi
255 let variablePrefix = directory ++ '_':distdir
256 let xs = [variablePrefix ++ "_VERSION = " ++ display (pkgVersion (package pd)),
257 variablePrefix ++ "_MODULES = " ++ unwords (map display modules),
258 variablePrefix ++ "_HS_SRC_DIRS = " ++ unwords (hsSourceDirs bi),
259 variablePrefix ++ "_DEPS = " ++ unwords (map display dep_ids),
260 variablePrefix ++ "_DEP_NAMES = " ++ unwords (map (display . packageName) dep_ids),
261 variablePrefix ++ "_INCLUDE_DIRS = " ++ unwords (includeDirs bi),
262 variablePrefix ++ "_INCLUDES = " ++ unwords (includes bi),
263 variablePrefix ++ "_INSTALL_INCLUDES = " ++ unwords (installIncludes bi),
264 variablePrefix ++ "_EXTRA_LIBRARIES = " ++ unwords (extraLibs bi),
265 variablePrefix ++ "_EXTRA_LIBDIRS = " ++ unwords (extraLibDirs bi),
266 variablePrefix ++ "_C_SRCS = " ++ unwords (cSources bi),
267 variablePrefix ++ "_CMM_SRCS = $(addprefix cbits/,$(notdir $(wildcard " ++ directory ++ "/cbits/*.cmm)))",
268 -- XXX This includes things it shouldn't, like:
269 -- -odir dist-bootstrapping/build
270 variablePrefix ++ "_HC_OPTS = " ++ escape (unwords
273 ++ extensionsToFlags (compiler lbi) (extensions bi))),
274 variablePrefix ++ "_CC_OPTS = " ++ unwords (ccOptions bi),
275 variablePrefix ++ "_CPP_OPTS = " ++ unwords (cppOptions bi),
276 variablePrefix ++ "_LD_OPTS = " ++ unwords (ldOptions bi),
277 variablePrefix ++ "_DEP_INCLUDE_DIRS = " ++ unwords (forDeps Installed.includeDirs),
278 variablePrefix ++ "_DEP_CC_OPTS = " ++ unwords (forDeps Installed.ccOptions),
279 variablePrefix ++ "_DEP_LIB_DIRS = " ++ unwords (forDeps Installed.libraryDirs),
280 variablePrefix ++ "_DEP_EXTRA_LIBS = " ++ unwords (forDeps Installed.extraLibraries),
281 variablePrefix ++ "_DEP_LD_OPTS = " ++ unwords (forDeps Installed.ldOptions)]
282 writeFile (distdir ++ "/package-data.mk") $ unlines xs
284 escape = foldr (\c xs -> if c == '#' then '\\':'#':xs else c:xs) []