    {-# LANGUAGE DeriveDataTypeable #-}
    {-# LANGUAGE DeriveGeneric #-}

    module Distribution.Types.Library (
        Library(..),
        emptyLibrary,
        explicitLibModules,
        libModulesAutogen,
        libModules,
    ) where

    import Prelude ()
    import Distribution.Compat.Prelude

    import Distribution.Types.BuildInfo
    import Distribution.Types.ModuleReexport
    import Distribution.Types.UnqualComponentName
    import Distribution.ModuleName

    import qualified Distribution.Types.BuildInfo.Lens as L

    data Library = Library
        { libName           :: Maybe UnqualComponentName
        , exposedModules    :: [ModuleName]
        , reexportedModules :: [ModuleReexport]
        , signatures        :: [ModuleName]   -- ^ What sigs need implementations?
        , libExposed        :: Bool           -- ^ Is the lib to be exposed by default?
        , libBuildInfo      :: BuildInfo
        }
        deriving (Generic, Show, Eq, Read, Typeable, Data)

    instance L.HasBuildInfo Library where
        buildInfo f l = (\x -> l { libBuildInfo = x }) <$> f (libBuildInfo l)

    instance Binary Library

    instance NFData Library where rnf = genericRnf

    instance Monoid Library where
      mempty = Library {
        libName = mempty,
        exposedModules = mempty,
        reexportedModules = mempty,
        signatures = mempty,
        libExposed     = True,
        libBuildInfo   = mempty
      }
      mappend = (<>)

    instance Semigroup Library where
      a <> b = Library {
        libName = combine libName,
        exposedModules = combine exposedModules,
        reexportedModules = combine reexportedModules,
        signatures = combine signatures,
        libExposed     = libExposed a && libExposed b, -- so False propagates
        libBuildInfo   = combine libBuildInfo
      }
        where combine field = field a `mappend` field b

    emptyLibrary :: Library
    emptyLibrary = mempty

    -- | Get all the module names from the library (exposed and internal modules)
    -- which are explicitly listed in the package description which would
    -- need to be compiled.  (This does not include reexports, which
    -- do not need to be compiled.)  This may not include all modules for which
    -- GHC generated interface files (i.e., implicit modules.)
    explicitLibModules :: Library -> [ModuleName]
    explicitLibModules lib = exposedModules lib
                  ++ otherModules (libBuildInfo lib)
                  ++ signatures lib

    -- | Get all the auto generated module names from the library, exposed or not.
    -- This are a subset of 'libModules'.
    libModulesAutogen :: Library -> [ModuleName]
    libModulesAutogen lib = autogenModules (libBuildInfo lib)

    -- | Backwards-compatibility shim for 'explicitLibModules'.  In most cases,
    -- you actually want 'allLibModules', which returns all modules that will
    -- actually be compiled, as opposed to those which are explicitly listed
    -- in the package description ('explicitLibModules'); unfortunately, the
    -- type signature for 'allLibModules' is incompatible since we need a
    -- 'ComponentLocalBuildInfo'.
    {-# DEPRECATED libModules "If you want all modules that are built with a library, use 'allLibModules'.  Otherwise, use 'explicitLibModules' for ONLY the modules explicitly mentioned in the package description. This symbol will be removed in Cabal-3.0 (est. Oct 2018)." #-}
    libModules :: Library -> [ModuleName]
    libModules = explicitLibModules