LocalBuildInfo.hs 17 KB
Newer Older
ijones's avatar
ijones committed
1
2
3
4
-----------------------------------------------------------------------------
-- |
-- Module      :  Distribution.Simple.LocalBuildInfo
-- Copyright   :  Isaac Jones 2003-2004
5
-- License     :  BSD3
6
--
Duncan Coutts's avatar
Duncan Coutts committed
7
-- Maintainer  :  cabal-devel@haskell.org
ijones's avatar
ijones committed
8
-- Portability :  portable
ijones's avatar
ijones committed
9
--
Duncan Coutts's avatar
Duncan Coutts committed
10
11
12
13
14
-- Once a package has been configured we have resolved conditionals and
-- dependencies, configured the compiler and other needed external programs.
-- The 'LocalBuildInfo' is used to hold all this information. It holds the
-- install dirs, the compiler, the exact package dependencies, the configured
-- programs, the package database to use and a bunch of miscellaneous configure
15
-- flags. It gets saved and reloaded from a file (@dist\/setup-config@). It gets
Duncan Coutts's avatar
Duncan Coutts committed
16
-- passed in to very many subsequent build actions.
ijones's avatar
ijones committed
17

18
19
module Distribution.Simple.LocalBuildInfo (
        LocalBuildInfo(..),
20
        externalPackageDeps,
21
        inplacePackageId,
22
23
24
25

        -- * Buildable package components
        Component(..),
        ComponentName(..),
26
        showComponentName,
27
        ComponentLocalBuildInfo(..),
28
        LibraryName(..),
29
30
31
        foldComponent,
        componentName,
        componentBuildInfo,
32
33
34
        componentEnabled,
        componentDisabledReason,
        ComponentDisabledReason(..),
35
36
        pkgComponents,
        pkgEnabledComponents,
37
        lookupComponent,
38
39
40
41
42
43
44
45
        getComponent,
        getComponentLocalBuildInfo,
        allComponentsInBuildOrder,
        componentsInBuildOrder,
        checkComponentsCyclic,

        withAllComponentsInBuildOrder,
        withComponentsInBuildOrder,
46
        withComponentsLBI,
47
48
        withLibLBI,
        withExeLBI,
49
        withTestLBI,
50

51
52
        -- * Installation directories
        module Distribution.Simple.InstallDirs,
53
        absoluteInstallDirs, prefixRelativeInstallDirs,
54
        substPathTemplate
55
  ) where
ijones's avatar
ijones committed
56

ijones's avatar
ijones committed
57

58
import Distribution.Simple.InstallDirs hiding (absoluteInstallDirs,
59
60
                                               prefixRelativeInstallDirs,
                                               substPathTemplate, )
61
import qualified Distribution.Simple.InstallDirs as InstallDirs
62
import Distribution.Simple.Program (ProgramConfiguration)
63
import Distribution.PackageDescription
64
65
         ( PackageDescription(..), withLib, Library(libBuildInfo), withExe
         , Executable(exeName, buildInfo), withTest, TestSuite(..)
66
         , BuildInfo(buildable), Benchmark(..) )
67
import Distribution.Package
68
         ( PackageId, Package(..), InstalledPackageId(..), PackageKey )
69
import Distribution.Simple.Compiler
70
         ( Compiler(..), PackageDBStack, OptimisationLevel )
71
import Distribution.Simple.PackageIndex
72
         ( PackageIndex )
73
74
import Distribution.Simple.Setup
         ( ConfigFlags )
75
76
import Distribution.Text
         ( display )
77
78
import Distribution.System
          ( Platform )
79
import Data.List (nub, find)
80
81
82
83
import Data.Graph
import Data.Tree  (flatten)
import Data.Array ((!))
import Data.Maybe
84

Duncan Coutts's avatar
Duncan Coutts committed
85
86
-- | Data cached after configuration step.  See also
-- 'Distribution.Simple.Setup.ConfigFlags'.
ijones's avatar
ijones committed
87
data LocalBuildInfo = LocalBuildInfo {
88
        configFlags   :: ConfigFlags,
89
        -- ^ Options passed to the configuration step.
90
        -- Needed to re-run configuration when .cabal is out of date
91
92
        extraConfigArgs     :: [String],
        -- ^ Extra args on the command line for the configuration step.
93
        -- Needed to re-run configuration when .cabal is out of date
94
        installDirTemplates :: InstallDirTemplates,
Ian D. Bollinger's avatar
Ian D. Bollinger committed
95
                -- ^ The installation directories for the various different
96
                -- kinds of files
Duncan Coutts's avatar
Duncan Coutts committed
97
        --TODO: inplaceDirTemplates :: InstallDirs FilePath
98
99
        compiler      :: Compiler,
                -- ^ The compiler we're building with
100
101
        hostPlatform  :: Platform,
                -- ^ The platform we're building for
102
103
        buildDir      :: FilePath,
                -- ^ Where to build the package.
Duncan Coutts's avatar
Duncan Coutts committed
104
        --TODO: eliminate hugs's scratchDir, use builddir
105
106
        scratchDir    :: FilePath,
                -- ^ Where to put the result of the Hugs build.
107
108
        componentsConfigs   :: [(ComponentName, ComponentLocalBuildInfo, [ComponentName])],
                -- ^ All the components to build, ordered by topological sort, and with their dependencies
109
                -- over the intrapackage dependency graph
Duncan Coutts's avatar
Duncan Coutts committed
110
        installedPkgs :: PackageIndex,
111
112
                -- ^ All the info about the installed packages that the
                -- current package depends on (directly or indirectly).
113
114
        pkgDescrFile  :: Maybe FilePath,
                -- ^ the filename containing the .cabal file, if available
115
116
117
        localPkgDescr :: PackageDescription,
                -- ^ The resolved package description, that does not contain
                -- any conditionals.
118
119
120
        pkgKey        :: PackageKey,
                -- ^ The package key for the current build, calculated from
                -- the package ID and the dependency graph.
Duncan Coutts's avatar
Duncan Coutts committed
121
        withPrograms  :: ProgramConfiguration, -- ^Location and args for all programs
122
        withPackageDB :: PackageDBStack,  -- ^What package database to use, global\/user
123
124
        withVanillaLib:: Bool,  -- ^Whether to build normal libs.
        withProfLib   :: Bool,  -- ^Whether to build profiling versions of libs.
125
        withSharedLib :: Bool,  -- ^Whether to build shared versions of libs.
126
        withDynExe    :: Bool,  -- ^Whether to link executables dynamically
127
        withProfExe   :: Bool,  -- ^Whether to build executables for profiling.
128
        withOptimization :: OptimisationLevel, -- ^Whether to build with optimization (if available).
129
        withGHCiLib   :: Bool,  -- ^Whether to build libs suitable for use with GHCi.
130
        splitObjs     :: Bool,  -- ^Use -split-objs with GHC, if available
131
        stripExes     :: Bool,  -- ^Whether to strip executables during install
132
        stripLibs     :: Bool,  -- ^Whether to strip libraries during install
133
134
        progPrefix    :: PathTemplate, -- ^Prefix to be prepended to installed executables
        progSuffix    :: PathTemplate -- ^Suffix to be appended to installed executables
135
  } deriving (Read, Show)
136

137
138
-- | External package dependencies for the package as a whole. This is the
-- union of the individual 'componentPackageDeps', less any internal deps.
139
externalPackageDeps :: LocalBuildInfo -> [(InstalledPackageId, PackageId)]
140
141
142
143
144
145
externalPackageDeps lbi =
    -- TODO:  what about non-buildable components?
    nub [ (ipkgid, pkgid)
        | (_,clbi,_)      <- componentsConfigs lbi
        , (ipkgid, pkgid) <- componentPackageDeps clbi
        , not (internal pkgid) ]
146
147
148
149
  where
    -- True if this dependency is an internal one (depends on the library
    -- defined in the same package).
    internal pkgid = pkgid == packageId (localPkgDescr lbi)
ijones's avatar
ijones committed
150

151
152
153
154
155
156
-- | The installed package Id we use for local packages registered in the local
-- package db. This is what is used for intra-package deps between components.
--
inplacePackageId :: PackageId -> InstalledPackageId
inplacePackageId pkgid = InstalledPackageId (display pkgid ++ "-inplace")

157
158
159
-- -----------------------------------------------------------------------------
-- Buildable components

160
161
162
163
data Component = CLib   Library
               | CExe   Executable
               | CTest  TestSuite
               | CBench Benchmark
164
165
               deriving (Show, Eq, Read)

166
167
168
169
data ComponentName = CLibName   -- currently only a single lib
                   | CExeName   String
                   | CTestName  String
                   | CBenchName String
170
                   deriving (Show, Eq, Ord, Read)
171

172
173
174
175
176
177
showComponentName :: ComponentName -> String
showComponentName CLibName          = "library"
showComponentName (CExeName   name) = "executable '" ++ name ++ "'"
showComponentName (CTestName  name) = "test suite '" ++ name ++ "'"
showComponentName (CBenchName name) = "benchmark '" ++ name ++ "'"

178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
data ComponentLocalBuildInfo
  = LibComponentLocalBuildInfo {
    -- | Resolved internal and external package dependencies for this component.
    -- The 'BuildInfo' specifies a set of build dependencies that must be
    -- satisfied in terms of version ranges. This field fixes those dependencies
    -- to the specific versions available on this machine for this compiler.
    componentPackageDeps :: [(InstalledPackageId, PackageId)],
    componentLibraries :: [LibraryName]
  }
  | ExeComponentLocalBuildInfo {
    componentPackageDeps :: [(InstalledPackageId, PackageId)]
  }
  | TestComponentLocalBuildInfo {
    componentPackageDeps :: [(InstalledPackageId, PackageId)]
  }
  | BenchComponentLocalBuildInfo {
194
195
196
197
198
199
200
    componentPackageDeps :: [(InstalledPackageId, PackageId)]
  }
  deriving (Read, Show)

foldComponent :: (Library -> a)
              -> (Executable -> a)
              -> (TestSuite -> a)
201
              -> (Benchmark -> a)
202
203
              -> Component
              -> a
204
205
206
207
foldComponent f _ _ _ (CLib   lib) = f lib
foldComponent _ f _ _ (CExe   exe) = f exe
foldComponent _ _ f _ (CTest  tst) = f tst
foldComponent _ _ _ f (CBench bch) = f bch
208

209
210
211
data LibraryName = LibraryName String
    deriving (Read, Show)

212
213
214
215
componentBuildInfo :: Component -> BuildInfo
componentBuildInfo =
  foldComponent libBuildInfo buildInfo testBuildInfo benchmarkBuildInfo

216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
componentName :: Component -> ComponentName
componentName =
  foldComponent (const CLibName)
                (CExeName . exeName)
                (CTestName . testName)
                (CBenchName . benchmarkName)

-- | All the components in the package (libs, exes, or test suites).
--
pkgComponents :: PackageDescription -> [Component]
pkgComponents pkg =
    [ CLib  lib | Just lib <- [library pkg] ]
 ++ [ CExe  exe | exe <- executables pkg ]
 ++ [ CTest tst | tst <- testSuites  pkg ]
 ++ [ CBench bm | bm  <- benchmarks  pkg ]

-- | All the components in the package that are buildable and enabled.
-- Thus this excludes non-buildable components and test suites or benchmarks
-- that have been disabled.
--
pkgEnabledComponents :: PackageDescription -> [Component]
237
238
239
240
241
242
243
244
245
246
247
248
pkgEnabledComponents = filter componentEnabled . pkgComponents

componentEnabled :: Component -> Bool
componentEnabled = isNothing . componentDisabledReason

data ComponentDisabledReason = DisabledComponent
                             | DisabledAllTests
                             | DisabledAllBenchmarks

componentDisabledReason :: Component -> Maybe ComponentDisabledReason
componentDisabledReason (CLib  lib)
  | not (buildable (libBuildInfo lib))      = Just DisabledComponent
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
249
componentDisabledReason (CExe  exe)
250
251
252
253
254
255
256
257
  | not (buildable (buildInfo exe))         = Just DisabledComponent
componentDisabledReason (CTest tst)
  | not (buildable (testBuildInfo tst))     = Just DisabledComponent
  | not (testEnabled tst)                   = Just DisabledAllTests
componentDisabledReason (CBench bm)
  | not (buildable (benchmarkBuildInfo bm)) = Just DisabledComponent
  | not (benchmarkEnabled bm)               = Just DisabledAllBenchmarks
componentDisabledReason _                   = Nothing
258

259
260
261
262
263
264
265
266
267
lookupComponent :: PackageDescription -> ComponentName -> Maybe Component
lookupComponent pkg CLibName =
    fmap CLib $ library pkg
lookupComponent pkg (CExeName name) =
    fmap CExe $ find ((name ==) . exeName) (executables pkg)
lookupComponent pkg (CTestName name) =
    fmap CTest $ find ((name ==) . testName) (testSuites pkg)
lookupComponent pkg (CBenchName name) =
    fmap CBench $ find ((name ==) . benchmarkName) (benchmarks pkg)
268
269
270

getComponent :: PackageDescription -> ComponentName -> Component
getComponent pkg cname =
271
272
273
    case lookupComponent pkg cname of
      Just cpnt -> cpnt
      Nothing   -> missingComponent
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
  where
    missingComponent =
      error $ "internal error: the package description contains no "
           ++ "component corresponding to " ++ show cname


getComponentLocalBuildInfo :: LocalBuildInfo -> ComponentName -> ComponentLocalBuildInfo
getComponentLocalBuildInfo lbi cname =
    case [ clbi
         | (cname', clbi, _) <- componentsConfigs lbi
         , cname == cname' ] of
      [clbi] -> clbi
      _      -> missingComponent
  where
    missingComponent =
      error $ "internal error: there is no configuration data "
           ++ "for component " ++ show cname

292

293
294
295
296
297
-- |If the package description has a library section, call the given
--  function with the library build info as argument.  Extended version of
-- 'withLib' that also gives corresponding build info.
withLibLBI :: PackageDescription -> LocalBuildInfo
           -> (Library -> ComponentLocalBuildInfo -> IO ()) -> IO ()
298
299
300
withLibLBI pkg_descr lbi f =
    withLib pkg_descr $ \lib ->
      f lib (getComponentLocalBuildInfo lbi CLibName)
301
302
303
304
305
306

-- | Perform the action on each buildable 'Executable' in the package
-- description.  Extended version of 'withExe' that also gives corresponding
-- build info.
withExeLBI :: PackageDescription -> LocalBuildInfo
           -> (Executable -> ComponentLocalBuildInfo -> IO ()) -> IO ()
307
308
309
withExeLBI pkg_descr lbi f =
    withExe pkg_descr $ \exe ->
      f exe (getComponentLocalBuildInfo lbi (CExeName (exeName exe)))
310
311
312

withTestLBI :: PackageDescription -> LocalBuildInfo
            -> (TestSuite -> ComponentLocalBuildInfo -> IO ()) -> IO ()
313
314
315
withTestLBI pkg_descr lbi f =
    withTest pkg_descr $ \test ->
      f test (getComponentLocalBuildInfo lbi (CTestName (testName test)))
316

317
{-# DEPRECATED withComponentsLBI "Use withAllComponentsInBuildOrder" #-}
318
withComponentsLBI :: PackageDescription -> LocalBuildInfo
319
320
                  -> (Component -> ComponentLocalBuildInfo -> IO ())
                  -> IO ()
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
withComponentsLBI = withAllComponentsInBuildOrder

-- | Perform the action on each buildable 'Library' or 'Executable' (Component)
-- in the PackageDescription, subject to the build order specified by the
-- 'compBuildOrder' field of the given 'LocalBuildInfo'
withAllComponentsInBuildOrder :: PackageDescription -> LocalBuildInfo
                              -> (Component -> ComponentLocalBuildInfo -> IO ())
                              -> IO ()
withAllComponentsInBuildOrder pkg lbi f =
    sequence_
      [ f (getComponent pkg cname) clbi
      | (cname, clbi) <- allComponentsInBuildOrder lbi ]

withComponentsInBuildOrder :: PackageDescription -> LocalBuildInfo
                                  -> [ComponentName]
                                  -> (Component -> ComponentLocalBuildInfo -> IO ())
                                  -> IO ()
withComponentsInBuildOrder pkg lbi cnames f =
    sequence_
      [ f (getComponent pkg cname') clbi
      | (cname', clbi) <- componentsInBuildOrder lbi cnames ]

allComponentsInBuildOrder :: LocalBuildInfo
                          -> [(ComponentName, ComponentLocalBuildInfo)]
allComponentsInBuildOrder lbi =
    componentsInBuildOrder lbi
      [ cname | (cname, _, _) <- componentsConfigs lbi ]

componentsInBuildOrder :: LocalBuildInfo -> [ComponentName]
                       -> [(ComponentName, ComponentLocalBuildInfo)]
componentsInBuildOrder lbi cnames =
      map ((\(clbi,cname,_) -> (cname,clbi)) . vertexToNode)
    . postOrder graph
    . map (\cname -> fromMaybe (noSuchComp cname) (keyToVertex cname))
    $ cnames
356
  where
357
358
    (graph, vertexToNode, keyToVertex) =
      graphFromEdges (map (\(a,b,c) -> (b,a,c)) (componentsConfigs lbi))
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
359

360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
    noSuchComp cname = error $ "internal error: componentsInBuildOrder: "
                            ++ "no such component: " ++ show cname

    postOrder :: Graph -> [Vertex] -> [Vertex]
    postOrder g vs = postorderF (dfs g vs) []

    postorderF   :: Forest a -> [a] -> [a]
    postorderF ts = foldr (.) id $ map postorderT ts

    postorderT :: Tree a -> [a] -> [a]
    postorderT (Node a ts) = postorderF ts . (a :)

checkComponentsCyclic :: Ord key => [(node, key, [key])]
                      -> Maybe [(node, key, [key])]
checkComponentsCyclic es =
    let (graph, vertexToNode, _) = graphFromEdges es
        cycles                   = [ flatten c | c <- scc graph, isCycle c ]
        isCycle (Node v [])      = selfCyclic v
        isCycle _                = True
        selfCyclic v             = v `elem` graph ! v
     in case cycles of
         []    -> Nothing
         (c:_) -> Just (map vertexToNode c)
383

384

385
-- -----------------------------------------------------------------------------
386
387
388
-- Wrappers for a couple functions from InstallDirs

-- |See 'InstallDirs.absoluteInstallDirs'
389
absoluteInstallDirs :: PackageDescription -> LocalBuildInfo -> CopyDest
390
                    -> InstallDirs FilePath
391
absoluteInstallDirs pkg lbi copydest =
392
  InstallDirs.absoluteInstallDirs
393
    (packageId pkg)
394
395
    (compilerId (compiler lbi))
    copydest
396
    (hostPlatform lbi)
397
398
399
    (installDirTemplates lbi)

-- |See 'InstallDirs.prefixRelativeInstallDirs'
400
prefixRelativeInstallDirs :: PackageId -> LocalBuildInfo
401
402
403
                          -> InstallDirs (Maybe FilePath)
prefixRelativeInstallDirs pkg_descr lbi =
  InstallDirs.prefixRelativeInstallDirs
404
    (packageId pkg_descr)
405
    (compilerId (compiler lbi))
406
    (hostPlatform lbi)
407
    (installDirTemplates lbi)
408

409
substPathTemplate :: PackageId -> LocalBuildInfo
410
                  -> PathTemplate -> FilePath
411
substPathTemplate pkgid lbi = fromPathTemplate
412
                                . ( InstallDirs.substPathTemplate env )
413
    where env = initialPathTemplateEnv
414
                   pkgid
415
                   (compilerId (compiler lbi))
416
                   (hostPlatform lbi)