Cabal 1.20.0.4 → 1.22.0.0
raw patch · 107 files changed
+10717/−4358 lines, 107 filesdep +binarydep +ghc-primdep ~QuickCheckdep ~basedep ~containersbuild-type:Custom
Dependencies added: binary, ghc-prim
Dependency ranges changed: QuickCheck, base, containers, deepseq, process, time
Files
- Cabal.cabal +32/−17
- Distribution/Compat/CreatePipe.hs +8/−1
- Distribution/Compat/ReadP.hs +1/−1
- Distribution/Compat/TempFile.hs +3/−2
- Distribution/Compiler.hs +68/−4
- Distribution/InstalledPackageInfo.hs +139/−48
- Distribution/License.hs +20/−4
- Distribution/Make.hs +1/−1
- Distribution/ModuleName.hs +11/−5
- Distribution/Package.hs +154/−9
- Distribution/PackageDescription.hs +214/−57
- Distribution/PackageDescription/Check.hs +147/−66
- Distribution/PackageDescription/Configuration.hs +16/−7
- Distribution/PackageDescription/Parse.hs +75/−17
- Distribution/PackageDescription/PrettyPrint.hs +30/−15
- Distribution/ParseUtils.hs +7/−5
- Distribution/Simple.hs +7/−10
- Distribution/Simple/Bench.hs +5/−5
- Distribution/Simple/Build.hs +93/−62
- Distribution/Simple/Build/Macros.hs +13/−2
- Distribution/Simple/Build/PathsModule.hs +60/−25
- Distribution/Simple/BuildPaths.hs +2/−3
- Distribution/Simple/BuildTarget.hs +7/−3
- Distribution/Simple/Command.hs +72/−54
- Distribution/Simple/Compiler.hs +102/−12
- Distribution/Simple/Configure.hs +625/−190
- Distribution/Simple/GHC.hs +1046/−1313
- Distribution/Simple/GHC/IPI641.hs +13/−7
- Distribution/Simple/GHC/IPI642.hs +13/−7
- Distribution/Simple/GHC/ImplInfo.hs +108/−0
- Distribution/Simple/GHC/Internal.hs +489/−0
- Distribution/Simple/GHCJS.hs +898/−0
- Distribution/Simple/Haddock.hs +224/−134
- Distribution/Simple/HaskellSuite.hs +4/−1
- Distribution/Simple/Hpc.hs +40/−53
- Distribution/Simple/Hugs.hs +0/−609
- Distribution/Simple/Install.hs +11/−16
- Distribution/Simple/InstallDirs.hs +78/−34
- Distribution/Simple/JHC.hs +5/−3
- Distribution/Simple/LHC.hs +22/−9
- Distribution/Simple/LocalBuildInfo.hs +114/−23
- Distribution/Simple/NHC.hs +0/−406
- Distribution/Simple/PackageIndex.hs +192/−76
- Distribution/Simple/PreProcess.hs +36/−22
- Distribution/Simple/Program.hs +3/−3
- Distribution/Simple/Program/Ar.hs +1/−0
- Distribution/Simple/Program/Builtin.hs +65/−28
- Distribution/Simple/Program/Db.hs +55/−19
- Distribution/Simple/Program/Find.hs +1/−0
- Distribution/Simple/Program/GHC.hs +108/−57
- Distribution/Simple/Program/HcPkg.hs +109/−131
- Distribution/Simple/Program/Hpc.hs +1/−1
- Distribution/Simple/Program/Run.hs +2/−2
- Distribution/Simple/Program/Types.hs +18/−2
- Distribution/Simple/Register.hs +153/−82
- Distribution/Simple/Setup.hs +343/−157
- Distribution/Simple/SrcDist.hs +14/−9
- Distribution/Simple/Test.hs +13/−9
- Distribution/Simple/Test/ExeV10.hs +34/−18
- Distribution/Simple/Test/LibV09.hs +35/−16
- Distribution/Simple/Test/Log.hs +3/−3
- Distribution/Simple/UHC.hs +4/−2
- Distribution/Simple/UserHooks.hs +2/−2
- Distribution/Simple/Utils.hs +180/−93
- Distribution/System.hs +19/−5
- Distribution/Utils/NubList.hs +97/−0
- Distribution/Verbosity.hs +7/−1
- Distribution/Version.hs +25/−2
- Language/Haskell/Extension.hs +49/−13
- README +0/−179
- README.md +182/−0
- changelog +33/−7
- doc/developing-packages.markdown +2146/−0
- doc/index.markdown +200/−0
- doc/installing-packages.markdown +1067/−0
- doc/misc.markdown +109/−0
- tests/PackageTests.hs +19/−24
- tests/PackageTests/BenchmarkExeV10/Check.hs +1/−1
- tests/PackageTests/BenchmarkOptions/Check.hs +5/−2
- tests/PackageTests/BenchmarkStanza/Check.hs +7/−4
- tests/PackageTests/BuildDeps/InternalLibrary0/Check.hs +5/−1
- tests/PackageTests/BuildDeps/InternalLibrary1/Check.hs +5/−1
- tests/PackageTests/BuildDeps/InternalLibrary2/Check.hs +11/−3
- tests/PackageTests/BuildDeps/InternalLibrary3/Check.hs +11/−3
- tests/PackageTests/BuildDeps/InternalLibrary4/Check.hs +11/−3
- tests/PackageTests/BuildDeps/SameDepsAllRound/Check.hs +5/−1
- tests/PackageTests/BuildDeps/TargetSpecificDeps1/Check.hs +5/−1
- tests/PackageTests/BuildDeps/TargetSpecificDeps2/Check.hs +5/−1
- tests/PackageTests/BuildDeps/TargetSpecificDeps3/Check.hs +5/−1
- tests/PackageTests/CMain/Check.hs +5/−1
- tests/PackageTests/DeterministicAr/Check.hs +6/−2
- tests/PackageTests/EmptyLib/Check.hs +5/−2
- tests/PackageTests/Haddock/Check.hs +5/−1
- tests/PackageTests/OrderFlags/Check.hs +5/−1
- tests/PackageTests/PackageTester.hs +31/−30
- tests/PackageTests/PathsModule/Executable/Check.hs +5/−2
- tests/PackageTests/PathsModule/Library/Check.hs +5/−1
- tests/PackageTests/PreProcess/Check.hs +5/−2
- tests/PackageTests/TemplateHaskell/Check.hs +16/−7
- tests/PackageTests/TestOptions/Check.hs +10/−7
- tests/PackageTests/TestStanza/Check.hs +13/−4
- tests/PackageTests/TestSuiteExeV10/Check.hs +122/−49
- tests/README +0/−22
- tests/README.md +34/−0
- tests/UnitTests.hs +8/−2
- tests/UnitTests/Distribution/Compat/CreatePipe.hs +20/−0
- tests/UnitTests/Distribution/Utils/NubList.hs +44/−0
Cabal.cabal view
@@ -1,5 +1,5 @@ name: Cabal-version: 1.20.0.4+version: 1.22.0.0 copyright: 2003-2006, Isaac Jones 2005-2011, Duncan Coutts license: BSD3@@ -19,12 +19,15 @@ organizing, and cataloging Haskell libraries and tools. category: Distribution cabal-version: >=1.10-build-type: Simple+build-type: Custom -- Even though we do use the default Setup.lhs it's vital to bootstrapping -- that we build Setup.lhs using our own local Cabal source code. extra-source-files:- README tests/README changelog+ README.md tests/README.md changelog+ doc/developing-packages.markdown doc/index.markdown+ doc/installing-packages.markdown+ doc/misc.markdown -- Generated with 'misc/gen-extra-source-files.sh' & 'M-x sort-lines': tests/PackageTests/BenchmarkExeV10/Foo.hs@@ -124,17 +127,22 @@ library build-depends:- base >= 4 && < 5,- deepseq >= 1.3 && < 1.4,- filepath >= 1 && < 1.4,- directory >= 1 && < 1.3,- process >= 1.0.1.1 && < 1.3,- time >= 1.1 && < 1.5,- containers >= 0.1 && < 0.6,- array >= 0.1 && < 0.6,- pretty >= 1 && < 1.2,+ base >= 4.2 && < 5,+ binary >= 0.7 && < 0.8,+ deepseq >= 1.3 && < 1.5,+ filepath >= 1 && < 1.4,+ directory >= 1 && < 1.3,+ process >= 1.1.0.1 && < 1.3,+ time >= 1.1 && < 1.6,+ containers >= 0.1 && < 0.6,+ array >= 0.1 && < 0.6,+ pretty >= 1 && < 1.2, bytestring >= 0.9 + -- Needed for GHC.Generics before GHC 7.6+ if impl(ghc < 7.6)+ build-depends: ghc-prim >= 0.2 && < 0.3+ if !os(windows) build-depends: unix >= 2.0 && < 2.8@@ -172,16 +180,15 @@ Distribution.Simple.Compiler Distribution.Simple.Configure Distribution.Simple.GHC+ Distribution.Simple.GHCJS Distribution.Simple.Haddock Distribution.Simple.HaskellSuite Distribution.Simple.Hpc- Distribution.Simple.Hugs Distribution.Simple.Install Distribution.Simple.InstallDirs Distribution.Simple.JHC Distribution.Simple.LHC Distribution.Simple.LocalBuildInfo- Distribution.Simple.NHC Distribution.Simple.PackageIndex Distribution.Simple.PreProcess Distribution.Simple.PreProcess.Unlit@@ -211,6 +218,7 @@ Distribution.System Distribution.TestSuite Distribution.Text+ Distribution.Utils.NubList Distribution.Verbosity Distribution.Version Language.Haskell.Extension@@ -219,8 +227,10 @@ Distribution.Compat.CopyFile Distribution.Compat.TempFile Distribution.GetOpt+ Distribution.Simple.GHC.Internal Distribution.Simple.GHC.IPI641 Distribution.Simple.GHC.IPI642+ Distribution.Simple.GHC.ImplInfo Paths_Cabal default-language: Haskell98@@ -230,7 +240,10 @@ test-suite unit-tests type: exitcode-stdio-1.0 hs-source-dirs: tests- other-modules: UnitTests.Distribution.Compat.ReadP+ other-modules:+ UnitTests.Distribution.Compat.CreatePipe+ UnitTests.Distribution.Compat.ReadP+ UnitTests.Distribution.Utils.NubList main-is: UnitTests.hs build-depends: base,@@ -238,7 +251,7 @@ test-framework-hunit, test-framework-quickcheck2, HUnit,- QuickCheck < 2.7,+ QuickCheck < 2.8, Cabal ghc-options: -Wall default-language: Haskell98@@ -279,11 +292,13 @@ hs-source-dirs: tests build-depends: base,+ binary >= 0.7 && < 0.8,+ containers, test-framework, test-framework-quickcheck2 >= 0.2.12, test-framework-hunit, HUnit,- QuickCheck >= 2.1.0.1 && < 2.7,+ QuickCheck >= 2.1.0.1 && < 2.8, Cabal, process, directory,
Distribution/Compat/CreatePipe.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE CPP, ForeignFunctionInterface #-} module Distribution.Compat.CreatePipe (createPipe) where -import System.IO (Handle)+import System.IO (Handle, hSetEncoding, localeEncoding) -- The mingw32_HOST_OS CPP macro is GHC-specific #if mingw32_HOST_OS@@ -15,6 +15,7 @@ import GHC.IO.Device (IODeviceType(Stream)) import GHC.IO.Handle.FD (mkHandleFromFD) import System.IO (IOMode(ReadMode, WriteMode))+#elif ghcjs_HOST_OS #else import System.Posix.IO (fdToHandle) import qualified System.Posix.IO as Posix@@ -31,6 +32,8 @@ return (readfd, writefd) (do readh <- fdToHandle readfd ReadMode writeh <- fdToHandle writefd WriteMode+ hSetEncoding readh localeEncoding+ hSetEncoding writeh localeEncoding return (readh, writeh)) `onException` (close readfd >> close writefd) where fdToHandle :: CInt -> IOMode -> IO Handle@@ -46,10 +49,14 @@ foreign import ccall "io.h _close" c__close :: CInt -> IO CInt+#elif ghcjs_HOST_OS+createPipe = error "createPipe" #else createPipe = do (readfd, writefd) <- Posix.createPipe readh <- fdToHandle readfd writeh <- fdToHandle writefd+ hSetEncoding readh localeEncoding+ hSetEncoding writeh localeEncoding return (readh, writeh) #endif
Distribution/Compat/ReadP.hs view
@@ -14,7 +14,7 @@ -- it makes no difference which branch is \"shorter\". -- -- See also Koen's paper /Parallel Parsing Processes/--- (<http://www.cs.chalmers.se/~koen/publications.html>).+-- (<http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.19.9217>). -- -- This version of ReadP has been locally hacked to make it H98, by -- Martin Sjögren <mailto:msjogren@gmail.com>
Distribution/Compat/TempFile.hs view
@@ -25,7 +25,7 @@ import System.Posix.Internals (c_getpid) -#ifdef mingw32_HOST_OS+#if defined(mingw32_HOST_OS) || defined(ghcjs_HOST_OS) import System.Directory ( createDirectory ) #else import qualified System.Posix@@ -38,6 +38,7 @@ -- This is here for Haskell implementations that do not come with -- System.IO.openTempFile. This includes nhc-1.20, hugs-2006.9. -- TODO: Not sure about JHC+-- TODO: This file should probably be removed. -- This is a copy/paste of the openBinaryTempFile definition, but -- if uses 666 rather than 600 for the permissions. The base library@@ -120,7 +121,7 @@ | otherwise -> ioError e mkPrivateDir :: String -> IO ()-#ifdef mingw32_HOST_OS+#if defined(mingw32_HOST_OS) || defined(ghcjs_HOST_OS) mkPrivateDir s = createDirectory s #else mkPrivateDir s = System.Posix.createDirectory s 0o700
Distribution/Compiler.hs view
@@ -1,4 +1,6 @@ {-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+ ----------------------------------------------------------------------------- -- | -- Module : Distribution.Compiler@@ -33,13 +35,22 @@ -- * Compiler id CompilerId(..),++ -- * Compiler info+ CompilerInfo(..),+ unknownCompilerInfo,+ AbiTag(..), abiTagString ) where +import Data.Binary (Binary) import Data.Data (Data) import Data.Typeable (Typeable) import Data.Maybe (fromMaybe) import Distribution.Version (Version(..))+import GHC.Generics (Generic) +import Language.Haskell.Extension (Language, Extension)+ import qualified System.Info (compilerName, compilerVersion) import Distribution.Text (Text(..), display) import qualified Distribution.Compat.ReadP as Parse@@ -49,13 +60,15 @@ import qualified Data.Char as Char (toLower, isDigit, isAlphaNum) import Control.Monad (when) -data CompilerFlavor = GHC | NHC | YHC | Hugs | HBC | Helium | JHC | LHC | UHC+data CompilerFlavor = GHC | GHCJS | NHC | YHC | Hugs | HBC | Helium | JHC | LHC | UHC | HaskellSuite String -- string is the id of the actual compiler | OtherCompiler String- deriving (Show, Read, Eq, Ord, Typeable, Data)+ deriving (Generic, Show, Read, Eq, Ord, Typeable, Data) +instance Binary CompilerFlavor+ knownCompilerFlavors :: [CompilerFlavor]-knownCompilerFlavors = [GHC, NHC, YHC, Hugs, HBC, Helium, JHC, LHC, UHC]+knownCompilerFlavors = [GHC, GHCJS, NHC, YHC, Hugs, HBC, Helium, JHC, LHC, UHC] instance Text CompilerFlavor where disp (OtherCompiler name) = Disp.text name@@ -125,8 +138,10 @@ -- ------------------------------------------------------------ data CompilerId = CompilerId CompilerFlavor Version- deriving (Eq, Ord, Read, Show)+ deriving (Eq, Generic, Ord, Read, Show) +instance Binary CompilerId+ instance Text CompilerId where disp (CompilerId f (Version [] _)) = disp f disp (CompilerId f v) = disp f <> Disp.char '-' <> disp v@@ -138,3 +153,52 @@ lowercase :: String -> String lowercase = map Char.toLower++-- ------------------------------------------------------------+-- * Compiler Info+-- ------------------------------------------------------------++-- | Compiler information used for resolving configurations. Some fields can be+-- set to Nothing to indicate that the information is unknown.++data CompilerInfo = CompilerInfo {+ compilerInfoId :: CompilerId,+ -- ^ Compiler flavour and version.+ compilerInfoAbiTag :: AbiTag,+ -- ^ Tag for distinguishing incompatible ABI's on the same architecture/os.+ compilerInfoCompat :: Maybe [CompilerId],+ -- ^ Other implementations that this compiler claims to be compatible with, if known.+ compilerInfoLanguages :: Maybe [Language],+ -- ^ Supported language standards, if known.+ compilerInfoExtensions :: Maybe [Extension]+ -- ^ Supported extensions, if known.+ }+ deriving (Generic, Show, Read)++instance Binary CompilerInfo++data AbiTag+ = NoAbiTag+ | AbiTag String+ deriving (Generic, Show, Read)++instance Binary AbiTag++instance Text AbiTag where+ disp NoAbiTag = Disp.empty+ disp (AbiTag tag) = Disp.text tag++ parse = do+ tag <- Parse.munch (\c -> Char.isAlphaNum c || c == '_')+ if null tag then return NoAbiTag else return (AbiTag tag)++abiTagString :: AbiTag -> String+abiTagString NoAbiTag = ""+abiTagString (AbiTag tag) = tag++-- | Make a CompilerInfo of which only the known information is its CompilerId,+-- its AbiTag and that it does not claim to be compatible with other+-- compiler id's.+unknownCompilerInfo :: CompilerId -> AbiTag -> CompilerInfo+unknownCompilerInfo compilerId abiTag =+ CompilerInfo compilerId abiTag (Just []) Nothing Nothing
Distribution/InstalledPackageInfo.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE DeriveGeneric #-}+ ----------------------------------------------------------------------------- -- | -- Module : Distribution.InstalledPackageInfo@@ -22,40 +24,11 @@ -- textual format is rather simpler than the @.cabal@ format: there are no -- sections, for example. -{- All rights reserved.--Redistribution and use in source and binary forms, with or without-modification, are permitted provided that the following conditions are-met:-- * Redistributions of source code must retain the above copyright- notice, this list of conditions and the following disclaimer.-- * Redistributions in binary form must reproduce the above- copyright notice, this list of conditions and the following- disclaimer in the documentation and/or other materials provided- with the distribution.-- * Neither the name of the University nor the names of other- contributors may be used to endorse or promote products derived- from this software without specific prior written permission.--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -}- -- This module is meant to be local-only to Distribution... module Distribution.InstalledPackageInfo ( InstalledPackageInfo_(..), InstalledPackageInfo,+ OriginalModule(..), ExposedModule(..), ParseResult(..), PError(..), PWarning, emptyInstalledPackageInfo, parseInstalledPackageInfo,@@ -72,29 +45,36 @@ , parseFieldsFlat , parseFilePathQ, parseTokenQ, parseModuleNameQ, parsePackageNameQ , showFilePath, showToken, boolField, parseOptVersion- , parseFreeText, showFreeText )+ , parseFreeText, showFreeText, parseOptCommaList ) import Distribution.License ( License(..) ) import Distribution.Package ( PackageName(..), PackageIdentifier(..) , PackageId, InstalledPackageId(..)- , packageName, packageVersion )+ , packageName, packageVersion, PackageKey(..) ) import qualified Distribution.Package as Package- ( Package(..) ) import Distribution.ModuleName ( ModuleName ) import Distribution.Version ( Version(..) ) import Distribution.Text ( Text(disp, parse) )+import Text.PrettyPrint as Disp+import qualified Distribution.Compat.ReadP as Parse +import Data.Binary (Binary)+import Data.Maybe (fromMaybe)+import GHC.Generics (Generic)+ -- ----------------------------------------------------------------------------- -- The InstalledPackageInfo type + data InstalledPackageInfo_ m = InstalledPackageInfo { -- these parts are exactly the same as PackageDescription installedPackageId :: InstalledPackageId, sourcePackageId :: PackageId,+ packageKey :: PackageKey, license :: License, copyright :: String, maintainer :: String,@@ -107,30 +87,38 @@ category :: String, -- these parts are required by an installed package only: exposed :: Bool,- exposedModules :: [m],+ exposedModules :: [ExposedModule],+ instantiatedWith :: [(m, OriginalModule)], hiddenModules :: [m], trusted :: Bool,- importDirs :: [FilePath], -- contain sources in case of Hugs+ importDirs :: [FilePath], libraryDirs :: [FilePath],+ dataDir :: FilePath, hsLibraries :: [String], extraLibraries :: [String], extraGHCiLibraries:: [String], -- overrides extraLibraries for GHCi includeDirs :: [FilePath], includes :: [String], depends :: [InstalledPackageId],- hugsOptions :: [String], ccOptions :: [String], ldOptions :: [String], frameworkDirs :: [FilePath], frameworks :: [String], haddockInterfaces :: [FilePath],- haddockHTMLs :: [FilePath]+ haddockHTMLs :: [FilePath],+ pkgRoot :: Maybe FilePath }- deriving (Read, Show)+ deriving (Generic, Read, Show) +instance Binary m => Binary (InstalledPackageInfo_ m)+ instance Package.Package (InstalledPackageInfo_ str) where packageId = sourcePackageId +instance Package.PackageInstalled (InstalledPackageInfo_ str) where+ installedPackageId = installedPackageId+ installedDepends = depends+ type InstalledPackageInfo = InstalledPackageInfo_ ModuleName emptyInstalledPackageInfo :: InstalledPackageInfo_ m@@ -138,7 +126,9 @@ = InstalledPackageInfo { installedPackageId = InstalledPackageId "", sourcePackageId = PackageIdentifier (PackageName "") noVersion,- license = AllRightsReserved,+ packageKey = OldPackageKey (PackageIdentifier+ (PackageName "") noVersion),+ license = UnspecifiedLicense, copyright = "", maintainer = "", author = "",@@ -151,34 +141,116 @@ exposed = False, exposedModules = [], hiddenModules = [],+ instantiatedWith = [], trusted = False, importDirs = [], libraryDirs = [],+ dataDir = "", hsLibraries = [], extraLibraries = [], extraGHCiLibraries= [], includeDirs = [], includes = [], depends = [],- hugsOptions = [], ccOptions = [], ldOptions = [], frameworkDirs = [], frameworks = [], haddockInterfaces = [],- haddockHTMLs = []+ haddockHTMLs = [],+ pkgRoot = Nothing } noVersion :: Version-noVersion = Version{ versionBranch=[], versionTags=[] }+noVersion = Version [] [] -- -----------------------------------------------------------------------------+-- Exposed modules++data OriginalModule+ = OriginalModule {+ originalPackageId :: InstalledPackageId,+ originalModuleName :: ModuleName+ }+ deriving (Generic, Eq, Read, Show)++data ExposedModule+ = ExposedModule {+ exposedName :: ModuleName,+ exposedReexport :: Maybe OriginalModule,+ exposedSignature :: Maybe OriginalModule -- This field is unused for now.+ }+ deriving (Generic, Read, Show)++instance Text OriginalModule where+ disp (OriginalModule ipi m) =+ disp ipi <> Disp.char ':' <> disp m+ parse = do+ ipi <- parse+ _ <- Parse.char ':'+ m <- parse+ return (OriginalModule ipi m)++instance Text ExposedModule where+ disp (ExposedModule m reexport signature) =+ Disp.sep [ disp m+ , case reexport of+ Just m' -> Disp.sep [Disp.text "from", disp m']+ Nothing -> Disp.empty+ , case signature of+ Just m' -> Disp.sep [Disp.text "is", disp m']+ Nothing -> Disp.empty+ ]+ parse = do+ m <- parseModuleNameQ+ Parse.skipSpaces+ reexport <- Parse.option Nothing $ do+ _ <- Parse.string "from"+ Parse.skipSpaces+ fmap Just parse+ Parse.skipSpaces+ signature <- Parse.option Nothing $ do+ _ <- Parse.string "is"+ Parse.skipSpaces+ fmap Just parse+ return (ExposedModule m reexport signature)+++instance Binary OriginalModule++instance Binary ExposedModule++-- To maintain backwards-compatibility, we accept both comma/non-comma+-- separated variants of this field. You SHOULD use the comma syntax if you+-- use any new functions, although actually it's unambiguous due to a quirk+-- of the fact that modules must start with capital letters.++showExposedModules :: [ExposedModule] -> Disp.Doc+showExposedModules xs+ | all isExposedModule xs = fsep (map disp xs)+ | otherwise = fsep (Disp.punctuate comma (map disp xs))+ where isExposedModule (ExposedModule _ Nothing Nothing) = True+ isExposedModule _ = False++parseExposedModules :: Parse.ReadP r [ExposedModule]+parseExposedModules = parseOptCommaList parse++-- ----------------------------------------------------------------------------- -- Parsing parseInstalledPackageInfo :: String -> ParseResult InstalledPackageInfo parseInstalledPackageInfo =- parseFieldsFlat fieldsInstalledPackageInfo emptyInstalledPackageInfo+ parseFieldsFlat (fieldsInstalledPackageInfo ++ deprecatedFieldDescrs)+ emptyInstalledPackageInfo +parseInstantiatedWith :: Parse.ReadP r (ModuleName, OriginalModule)+parseInstantiatedWith = do k <- parse+ _ <- Parse.char '='+ n <- parse+ _ <- Parse.char '@'+ p <- parse+ return (k, OriginalModule p n)+ -- ----------------------------------------------------------------------------- -- Pretty-printing @@ -191,6 +263,9 @@ showSimpleInstalledPackageInfoField :: String -> Maybe (InstalledPackageInfo -> String) showSimpleInstalledPackageInfoField = showSimpleSingleNamedField fieldsInstalledPackageInfo +showInstantiatedWith :: (ModuleName, OriginalModule) -> Doc+showInstantiatedWith (k, OriginalModule p m) = disp k <> text "=" <> disp m <> text "@" <> disp p+ -- ----------------------------------------------------------------------------- -- Description of the fields, for parsing/printing @@ -208,6 +283,9 @@ , simpleField "id" disp parse installedPackageId (\ipid pkg -> pkg{installedPackageId=ipid})+ , simpleField "key"+ disp parse+ packageKey (\ipid pkg -> pkg{packageKey=ipid}) , simpleField "license" disp parseLicenseQ license (\l pkg -> pkg{license=l})@@ -244,12 +322,15 @@ installedFieldDescrs = [ boolField "exposed" exposed (\val pkg -> pkg{exposed=val})- , listField "exposed-modules"- disp parseModuleNameQ+ , simpleField "exposed-modules"+ showExposedModules parseExposedModules exposedModules (\xs pkg -> pkg{exposedModules=xs}) , listField "hidden-modules" disp parseModuleNameQ hiddenModules (\xs pkg -> pkg{hiddenModules=xs})+ , listField "instantiated-with"+ showInstantiatedWith parseInstantiatedWith+ instantiatedWith (\xs pkg -> pkg{instantiatedWith=xs}) , boolField "trusted" trusted (\val pkg -> pkg{trusted=val}) , listField "import-dirs"@@ -258,6 +339,9 @@ , listField "library-dirs" showFilePath parseFilePathQ libraryDirs (\xs pkg -> pkg{libraryDirs=xs})+ , simpleField "data-dir"+ showFilePath (parseFilePathQ Parse.<++ return "")+ dataDir (\val pkg -> pkg{dataDir=val}) , listField "hs-libraries" showFilePath parseTokenQ hsLibraries (\xs pkg -> pkg{hsLibraries=xs})@@ -276,9 +360,6 @@ , listField "depends" disp parse depends (\xs pkg -> pkg{depends=xs})- , listField "hugs-options"- showToken parseTokenQ- hugsOptions (\path pkg -> pkg{hugsOptions=path}) , listField "cc-options" showToken parseTokenQ ccOptions (\path pkg -> pkg{ccOptions=path})@@ -297,4 +378,14 @@ , listField "haddock-html" showFilePath parseFilePathQ haddockHTMLs (\xs pkg -> pkg{haddockHTMLs=xs})+ , simpleField "pkgroot"+ (const Disp.empty) parseFilePathQ+ (fromMaybe "" . pkgRoot) (\xs pkg -> pkg{pkgRoot=Just xs}) ]++deprecatedFieldDescrs :: [FieldDescr InstalledPackageInfo]+deprecatedFieldDescrs = [+ listField "hugs-options"+ showToken parseTokenQ+ (const []) (const id)+ ]
Distribution/License.hs view
@@ -1,4 +1,6 @@ {-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+ ----------------------------------------------------------------------------- -- | -- Module : Distribution.License@@ -51,9 +53,11 @@ import qualified Distribution.Compat.ReadP as Parse import qualified Text.PrettyPrint as Disp import Text.PrettyPrint ((<>))+import Data.Binary (Binary) import qualified Data.Char as Char (isAlphaNum) import Data.Data (Data) import Data.Typeable (Typeable)+import GHC.Generics (Generic) -- | Indicates the license under which a package's source code is released. -- Versions of the licenses not listed here will be rejected by Hackage and@@ -88,6 +92,9 @@ -- | <http://www.opensource.org/licenses/MIT MIT license>. | MIT + -- | <http://www.isc.org/downloads/software-support-policy/isc-license/ ISC license>+ | ISC+ -- | <https://www.mozilla.org/MPL/ Mozilla Public License, version 2.0>. | MPL Version @@ -101,23 +108,31 @@ -- jurisdiction necessarily in the public domain elsewhere. | PublicDomain - -- | No license. The package may not be legally modified or redistributed by- -- anyone but the rightsholder.+ -- | Explicitly 'All Rights Reserved', eg for proprietary software. The+ -- package may not be legally modified or redistributed by anyone but the+ -- rightsholder. | AllRightsReserved + -- | No license specified which legally defaults to 'All Rights Reserved'.+ -- The package may not be legally modified or redistributed by anyone but+ -- the rightsholder.+ | UnspecifiedLicense+ -- | Any other software license. | OtherLicense -- | Indicates an erroneous license name. | UnknownLicense String- deriving (Read, Show, Eq, Typeable, Data)+ deriving (Generic, Read, Show, Eq, Typeable, Data) +instance Binary License+ -- | The list of all currently recognised licenses. knownLicenses :: [License] knownLicenses = [ GPL unversioned, GPL (version [2]), GPL (version [3]) , LGPL unversioned, LGPL (version [2, 1]), LGPL (version [3]) , AGPL unversioned, AGPL (version [3])- , BSD2, BSD3, MIT+ , BSD2, BSD3, MIT, ISC , MPL (Version [2, 0] []) , Apache unversioned, Apache (version [2, 0]) , PublicDomain, AllRightsReserved, OtherLicense]@@ -144,6 +159,7 @@ ("BSD2", Nothing) -> BSD2 ("BSD3", Nothing) -> BSD3 ("BSD4", Nothing) -> BSD4+ ("ISC", Nothing) -> ISC ("MIT", Nothing) -> MIT ("MPL", Just version') -> MPL version' ("Apache", _ ) -> Apache version
Distribution/Make.hs view
@@ -92,7 +92,7 @@ defaultMainHelper :: [String] -> IO () defaultMainHelper args =- case commandsRun globalCommand commands args of+ case commandsRun (globalCommand commands) commands args of CommandHelp help -> printHelp help CommandList opts -> printOptionsList opts CommandErrors errs -> printErrors errs
Distribution/ModuleName.hs view
@@ -1,4 +1,6 @@ {-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+ ----------------------------------------------------------------------------- -- | -- Module : Distribution.ModuleName@@ -22,21 +24,25 @@ import Distribution.Text ( Text(..) ) +import Data.Binary (Binary)+import qualified Data.Char as Char+ ( isAlphaNum, isUpper ) import Data.Data (Data) import Data.Typeable (Typeable) import qualified Distribution.Compat.ReadP as Parse import qualified Text.PrettyPrint as Disp-import qualified Data.Char as Char- ( isAlphaNum, isUpper )-import System.FilePath- ( pathSeparator ) import Data.List ( intercalate, intersperse )+import GHC.Generics (Generic)+import System.FilePath+ ( pathSeparator ) -- | A valid Haskell module name. -- newtype ModuleName = ModuleName [String]- deriving (Eq, Ord, Read, Show, Typeable, Data)+ deriving (Eq, Generic, Ord, Read, Show, Typeable, Data)++instance Binary ModuleName instance Text ModuleName where disp (ModuleName ms) =
Distribution/Package.hs view
@@ -1,4 +1,6 @@ {-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+ ----------------------------------------------------------------------------- -- | -- Module : Distribution.Package@@ -22,6 +24,10 @@ -- * Installed package identifiers InstalledPackageId(..), + -- * Package keys (used for linker symbols)+ PackageKey(..),+ mkPackageKey,+ -- * Package source dependencies Dependency(..), thisPackageVersion,@@ -31,8 +37,10 @@ -- * Package classes Package(..), packageName, packageVersion, PackageFixedDeps(..),+ PackageInstalled(..), ) where +import Distribution.ModuleName ( ModuleName ) import Distribution.Version ( Version(..), VersionRange, anyVersion, thisVersion , notThisVersion, simplifyVersionRange )@@ -41,16 +49,25 @@ import qualified Distribution.Compat.ReadP as Parse import Distribution.Compat.ReadP ((<++)) import qualified Text.PrettyPrint as Disp-import Text.PrettyPrint ((<>), (<+>), text)+ import Control.DeepSeq (NFData(..))-import qualified Data.Char as Char ( isDigit, isAlphaNum )-import Data.List ( intercalate )+import Data.Binary (Binary)+import qualified Data.Char as Char+ ( isDigit, isAlphaNum, isUpper, isLower, ord, chr ) import Data.Data ( Data )+import Data.List ( intercalate, sort, foldl' ) import Data.Typeable ( Typeable )+import Data.Word ( Word64 )+import GHC.Fingerprint ( Fingerprint(..), fingerprintString )+import GHC.Generics (Generic)+import Numeric ( showIntAtBase )+import Text.PrettyPrint ((<>), (<+>), text) -newtype PackageName = PackageName String- deriving (Read, Show, Eq, Ord, Typeable, Data)+newtype PackageName = PackageName { unPackageName :: String }+ deriving (Generic, Read, Show, Eq, Ord, Typeable, Data) +instance Binary PackageName+ instance Text PackageName where disp (PackageName n) = Disp.text n parse = do@@ -75,8 +92,10 @@ pkgName :: PackageName, -- ^The name of this package, eg. foo pkgVersion :: Version -- ^the version of this package, eg 1.2 }- deriving (Read, Show, Eq, Ord, Typeable, Data)+ deriving (Generic, Read, Show, Eq, Ord, Typeable, Data) +instance Binary PackageIdentifier+ instance Text PackageIdentifier where disp (PackageIdentifier n v) = case v of Version [] _ -> disp n -- if no version, don't show version.@@ -99,23 +118,139 @@ -- in a package database, or overlay of databases. -- newtype InstalledPackageId = InstalledPackageId String- deriving (Read,Show,Eq,Ord,Typeable,Data)+ deriving (Generic, Read,Show,Eq,Ord,Typeable,Data) +instance Binary InstalledPackageId+ instance Text InstalledPackageId where disp (InstalledPackageId str) = text str parse = InstalledPackageId `fmap` Parse.munch1 abi_char- where abi_char c = Char.isAlphaNum c || c `elem` ":-_."+ where abi_char c = Char.isAlphaNum c || c `elem` "-_." -- ------------------------------------------------------------+-- * Package Keys+-- ------------------------------------------------------------++-- | A 'PackageKey' is the notion of "package ID" which is visible to the+-- compiler. Why is this not a 'PackageId'? The 'PackageId' is a user-visible+-- concept written explicity in Cabal files; on the other hand, a 'PackageKey'+-- may contain, for example, information about the transitive dependency+-- tree of a package. Why is this not an 'InstalledPackageId'? A 'PackageKey'+-- affects the ABI because it is used for linker symbols; however, an+-- 'InstalledPackageId' can be used to distinguish two ABI-compatible versions+-- of a library.+data PackageKey+ -- | Modern package key which is a hash of the PackageId and the transitive+ -- dependency key. Manually inline it here so we can get the instances+ -- we need. Also contains a short informative string+ = PackageKey !String {-# UNPACK #-} !Word64 {-# UNPACK #-} !Word64+ -- | Old-style package key which is just a 'PackageId'. Required because+ -- old versions of GHC assume that the 'sourcePackageId' recorded for an+ -- installed package coincides with the package key it was compiled with.+ | OldPackageKey !PackageId+ deriving (Generic, Read, Show, Eq, Ord, Typeable, Data)++instance Binary PackageKey++-- | Convenience function which converts a fingerprint into a new-style package+-- key.+fingerprintPackageKey :: String -> Fingerprint -> PackageKey+fingerprintPackageKey s (Fingerprint a b) = PackageKey s a b++-- | Generates a 'PackageKey' from a 'PackageId', sorted package keys of the+-- immediate dependencies.+mkPackageKey :: Bool -- are modern style package keys supported?+ -> PackageId+ -> [PackageKey] -- dependencies+ -> [(ModuleName, (PackageKey, ModuleName))] -- hole instantiations+ -> PackageKey+mkPackageKey True pid deps holes = fingerprintPackageKey stubName+ . fingerprintString+ . ((show pid ++ "\n") ++)+ . ((show (sort holes) ++ "\n") ++)+ $ show (sort deps)+ where stubName = take 5 (filter (/= '-') (unPackageName (pkgName pid)))+mkPackageKey False pid _ _ = OldPackageKey pid++-- The base-62 code is based off of 'locators'+-- ((c) Operational Dynamics Consulting, BSD3 licensed)++-- Note: Instead of base-62 encoding a single 128-bit integer+-- (ceil(21.49) characters), we'll base-62 a pair of 64-bit integers+-- (2 * ceil(10.75) characters). Luckily for us, it's the same number of+-- characters! In the long term, this should go in GHC.Fingerprint,+-- but not now...++-- | Size of a 64-bit word when written as a base-62 string+word64Base62Len :: Int+word64Base62Len = 11++-- | Converts a 64-bit word into a base-62 string+toBase62 :: Word64 -> String+toBase62 w = pad ++ str+ where+ pad = replicate len '0'+ len = word64Base62Len - length str -- 11 == ceil(64 / lg 62)+ str = showIntAtBase 62 represent w ""+ represent :: Int -> Char+ represent x+ | x < 10 = Char.chr (48 + x)+ | x < 36 = Char.chr (65 + x - 10)+ | x < 62 = Char.chr (97 + x - 36)+ | otherwise = error ("represent (base 62): impossible!")++-- | Parses a base-62 string into a 64-bit word+fromBase62 :: String -> Word64+fromBase62 ss = foldl' multiply 0 ss+ where+ value :: Char -> Int+ value c+ | Char.isDigit c = Char.ord c - 48+ | Char.isUpper c = Char.ord c - 65 + 10+ | Char.isLower c = Char.ord c - 97 + 36+ | otherwise = error ("value (base 62): impossible!")++ multiply :: Word64 -> Char -> Word64+ multiply acc c = acc * 62 + (fromIntegral $ value c)++-- | Parses a base-62 string into a fingerprint.+readBase62Fingerprint :: String -> Fingerprint+readBase62Fingerprint s = Fingerprint w1 w2+ where (s1,s2) = splitAt word64Base62Len s+ w1 = fromBase62 s1+ w2 = fromBase62 (take word64Base62Len s2)++instance Text PackageKey where+ disp (PackageKey prefix w1 w2) = Disp.text prefix <> Disp.char '_'+ <> Disp.text (toBase62 w1) <> Disp.text (toBase62 w2)+ disp (OldPackageKey pid) = disp pid++ parse = parseNew <++ parseOld+ where parseNew = do+ prefix <- Parse.munch1 (\c -> Char.isAlphaNum c || c `elem` "-")+ _ <- Parse.char '_' -- if we use '-' it's ambiguous+ fmap (fingerprintPackageKey prefix . readBase62Fingerprint)+ . Parse.count (word64Base62Len * 2)+ $ Parse.satisfy Char.isAlphaNum+ parseOld = do pid <- parse+ return (OldPackageKey pid)++instance NFData PackageKey where+ rnf (PackageKey prefix _ _) = rnf prefix+ rnf (OldPackageKey pid) = rnf pid++-- ------------------------------------------------------------ -- * Package source dependencies -- ------------------------------------------------------------ -- | Describes a dependency on a source package (API) -- data Dependency = Dependency PackageName VersionRange- deriving (Read, Show, Eq, Typeable, Data)+ deriving (Generic, Read, Show, Eq, Typeable, Data) +instance Binary Dependency+ instance Text Dependency where disp (Dependency name ver) = disp name <+> disp ver@@ -172,3 +307,13 @@ -- class Package pkg => PackageFixedDeps pkg where depends :: pkg -> [PackageIdentifier]++-- | Class of installed packages.+--+-- The primary data type which is an instance of this package is+-- 'InstalledPackageInfo', but when we are doing install plans in Cabal install+-- we may have other, installed package-like things which contain more metadata.+-- Installed packages have exact dependencies 'installedDepends'.+class Package pkg => PackageInstalled pkg where+ installedPackageId :: pkg -> InstalledPackageId+ installedDepends :: pkg -> [InstalledPackageId]
Distribution/PackageDescription.hs view
@@ -1,4 +1,6 @@ {-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+ ----------------------------------------------------------------------------- -- | -- Module : Distribution.PackageDescription@@ -31,8 +33,14 @@ BuildType(..), knownBuildTypes, + -- ** Renaming+ ModuleRenaming(..),+ defaultRenaming,+ lookupRenaming,+ -- ** Libraries Library(..),+ ModuleReexport(..), emptyLibrary, withLib, hasLibs,@@ -77,6 +85,8 @@ allExtensions, usedExtensions, hcOptions,+ hcProfOptions,+ hcSharedOptions, -- ** Supplementary build information HookedBuildInfo,@@ -95,24 +105,29 @@ knownRepoTypes, ) where +import Data.Binary (Binary) import Data.Data (Data) import Data.List (nub, intercalate) import Data.Maybe (fromMaybe, maybeToList) import Data.Monoid (Monoid(mempty, mappend)) import Data.Typeable ( Typeable ) import Control.Monad (MonadPlus(mplus))+import GHC.Generics (Generic) import Text.PrettyPrint as Disp import qualified Distribution.Compat.ReadP as Parse+import Distribution.Compat.ReadP ((<++)) import qualified Data.Char as Char (isAlphaNum, isDigit, toLower)+import qualified Data.Map as Map+import Data.Map (Map) import Distribution.Package ( PackageName(PackageName), PackageIdentifier(PackageIdentifier)- , Dependency, Package(..) )+ , Dependency, Package(..), PackageName, packageName ) import Distribution.ModuleName ( ModuleName ) import Distribution.Version ( Version(Version), VersionRange, anyVersion, orLaterVersion , asVersionIntervals, LowerBound(..) )-import Distribution.License (License(AllRightsReserved))+import Distribution.License (License(UnspecifiedLicense)) import Distribution.Compiler (CompilerFlavor) import Distribution.System (OS, Arch) import Distribution.Text@@ -150,6 +165,17 @@ customFieldsPD :: [(String,String)], -- ^Custom fields starting -- with x-, stored in a -- simple assoc-list.+ -- | YOU PROBABLY DON'T WANT TO USE THIS FIELD. This field is+ -- special! Depending on how far along processing the+ -- PackageDescription we are, the contents of this field are+ -- either nonsense, or the collected dependencies of *all* the+ -- components in this package. buildDepends is initialized by+ -- 'finalizePackageDescription' and 'flattenPackageDescription';+ -- prior to that, dependency info is stored in the 'CondTree'+ -- built around a 'GenericPackageDescription'. When this+ -- resolution is done, dependency info is written to the inner+ -- 'BuildInfo' and this field. This is all horrible, and #2066+ -- tracks progress to get rid of this field. buildDepends :: [Dependency], -- | The version of the Cabal spec that this package description uses. -- For historical reasons this is specified with a version range but@@ -168,8 +194,10 @@ extraTmpFiles :: [FilePath], extraDocFiles :: [FilePath] }- deriving (Show, Read, Eq, Typeable, Data)+ deriving (Generic, Show, Read, Eq, Typeable, Data) +instance Binary PackageDescription+ instance Package PackageDescription where packageId = package @@ -204,7 +232,7 @@ = PackageDescription { package = PackageIdentifier (PackageName "") (Version [] []),- license = AllRightsReserved,+ license = UnspecifiedLicense, licenseFiles = [], specVersionRaw = Right anyVersion, buildType = Nothing,@@ -246,8 +274,10 @@ -- be built. Doing it this way rather than just giving a -- parse error means we get better error messages and allows -- you to inspect the rest of the package description.- deriving (Show, Read, Eq, Typeable, Data)+ deriving (Generic, Show, Read, Eq, Typeable, Data) +instance Binary BuildType+ knownBuildTypes :: [BuildType] knownBuildTypes = [Simple, Configure, Make, Custom] @@ -265,23 +295,96 @@ _ -> UnknownBuildType name -- ---------------------------------------------------------------------------+-- Module renaming++-- | Renaming applied to the modules provided by a package.+-- The boolean indicates whether or not to also include all of the+-- original names of modules. Thus, @ModuleRenaming False []@ is+-- "don't expose any modules, and @ModuleRenaming True [("Data.Bool", "Bool")]@+-- is, "expose all modules, but also expose @Data.Bool@ as @Bool@".+--+data ModuleRenaming = ModuleRenaming Bool [(ModuleName, ModuleName)]+ deriving (Show, Read, Eq, Ord, Typeable, Data, Generic)++defaultRenaming :: ModuleRenaming+defaultRenaming = ModuleRenaming True []++lookupRenaming :: Package pkg => pkg -> Map PackageName ModuleRenaming -> ModuleRenaming+lookupRenaming pkg rns =+ Map.findWithDefault+ (error ("lookupRenaming: missing renaming for " ++ display (packageName pkg)))+ (packageName pkg) rns++instance Binary ModuleRenaming where++instance Monoid ModuleRenaming where+ ModuleRenaming b rns `mappend` ModuleRenaming b' rns'+ = ModuleRenaming (b || b') (rns ++ rns') -- ToDo: dedupe?+ mempty = ModuleRenaming False []++-- NB: parentheses are mandatory, because later we may extend this syntax+-- to allow "hiding (A, B)" or other modifier words.+instance Text ModuleRenaming where+ disp (ModuleRenaming True []) = Disp.empty+ disp (ModuleRenaming b vs) = (if b then text "with" else Disp.empty) <+> dispRns+ where dispRns = Disp.parens+ (Disp.hsep+ (Disp.punctuate Disp.comma (map dispEntry vs)))+ dispEntry (orig, new)+ | orig == new = disp orig+ | otherwise = disp orig <+> text "as" <+> disp new++ parse = do Parse.string "with" >> Parse.skipSpaces+ fmap (ModuleRenaming True) parseRns+ <++ fmap (ModuleRenaming False) parseRns+ <++ return (ModuleRenaming True [])+ where parseRns = do+ rns <- Parse.between (Parse.char '(') (Parse.char ')') parseList+ Parse.skipSpaces+ return rns+ parseList =+ Parse.sepBy parseEntry (Parse.char ',' >> Parse.skipSpaces)+ parseEntry :: Parse.ReadP r (ModuleName, ModuleName)+ parseEntry = do+ orig <- parse+ Parse.skipSpaces+ (do _ <- Parse.string "as"+ Parse.skipSpaces+ new <- parse+ Parse.skipSpaces+ return (orig, new)+ <+++ return (orig, orig))++-- --------------------------------------------------------------------------- -- The Library type data Library = Library { exposedModules :: [ModuleName],+ reexportedModules :: [ModuleReexport],+ requiredSignatures:: [ModuleName], -- ^ What sigs need implementations?+ exposedSignatures:: [ModuleName], -- ^ What sigs are visible to users? libExposed :: Bool, -- ^ Is the lib to be exposed by default? libBuildInfo :: BuildInfo }- deriving (Show, Eq, Read, Typeable, Data)+ deriving (Generic, Show, Eq, Read, Typeable, Data) +instance Binary Library+ instance Monoid Library where mempty = Library { exposedModules = mempty,+ reexportedModules = mempty,+ requiredSignatures = mempty,+ exposedSignatures = mempty, libExposed = True, libBuildInfo = mempty } mappend a b = Library { exposedModules = combine exposedModules,+ reexportedModules = combine reexportedModules,+ requiredSignatures = combine requiredSignatures,+ exposedSignatures = combine exposedSignatures, libExposed = libExposed a && libExposed b, -- so False propagates libBuildInfo = combine libBuildInfo }@@ -308,10 +411,47 @@ maybe (return ()) f (maybeHasLibs pkg_descr) -- | Get all the module names from the library (exposed and internal modules)+-- which need to be compiled. (This does not include reexports, which+-- do not need to be compiled.) libModules :: Library -> [ModuleName] libModules lib = exposedModules lib ++ otherModules (libBuildInfo lib)+ ++ exposedSignatures lib+ ++ requiredSignatures lib +-- -----------------------------------------------------------------------------+-- Module re-exports++data ModuleReexport = ModuleReexport {+ moduleReexportOriginalPackage :: Maybe PackageName,+ moduleReexportOriginalName :: ModuleName,+ moduleReexportName :: ModuleName+ }+ deriving (Eq, Generic, Read, Show, Typeable, Data)++instance Binary ModuleReexport++instance Text ModuleReexport where+ disp (ModuleReexport mpkgname origname newname) =+ maybe Disp.empty (\pkgname -> disp pkgname <> Disp.char ':') mpkgname+ <> disp origname+ <+> if newname == origname+ then Disp.empty+ else Disp.text "as" <+> disp newname++ parse = do+ mpkgname <- Parse.option Nothing $ do+ pkgname <- parse + _ <- Parse.char ':'+ return (Just pkgname)+ origname <- parse+ newname <- Parse.option origname $ do+ Parse.skipSpaces+ _ <- Parse.string "as"+ Parse.skipSpaces+ parse+ return (ModuleReexport mpkgname origname newname)+ -- --------------------------------------------------------------------------- -- The Executable type @@ -320,8 +460,10 @@ modulePath :: FilePath, buildInfo :: BuildInfo }- deriving (Show, Read, Eq, Typeable, Data)+ deriving (Generic, Show, Read, Eq, Typeable, Data) +instance Binary Executable+ instance Monoid Executable where mempty = Executable { exeName = mempty,@@ -374,8 +516,10 @@ -- a better solution is waiting on the next overhaul to the -- GenericPackageDescription -> PackageDescription resolution process. }- deriving (Show, Read, Eq, Typeable, Data)+ deriving (Generic, Show, Read, Eq, Typeable, Data) +instance Binary TestSuite+ -- | The test suite interfaces that are currently defined. Each test suite must -- specify which interface it supports. --@@ -400,8 +544,10 @@ -- the given reason (e.g. unknown test type). -- | TestSuiteUnsupported TestType- deriving (Eq, Read, Show, Typeable, Data)+ deriving (Eq, Generic, Read, Show, Typeable, Data) +instance Binary TestSuiteInterface+ instance Monoid TestSuite where mempty = TestSuite { testName = mempty,@@ -456,8 +602,10 @@ data TestType = TestTypeExe Version -- ^ \"type: exitcode-stdio-x.y\" | TestTypeLib Version -- ^ \"type: detailed-x.y\" | TestTypeUnknown String Version -- ^ Some unknown test type e.g. \"type: foo\"- deriving (Show, Read, Eq, Typeable, Data)+ deriving (Generic, Show, Read, Eq, Typeable, Data) +instance Binary TestType+ knownTestTypes :: [TestType] knownTestTypes = [ TestTypeExe (Version [1,0] []) , TestTypeLib (Version [0,9] []) ]@@ -505,8 +653,10 @@ benchmarkEnabled :: Bool -- TODO: See TODO for 'testEnabled'. }- deriving (Show, Read, Eq, Typeable, Data)+ deriving (Generic, Show, Read, Eq, Typeable, Data) +instance Binary Benchmark+ -- | The benchmark interfaces that are currently defined. Each -- benchmark must specify which interface it supports. --@@ -527,8 +677,10 @@ -- interfaces for the given reason (e.g. unknown benchmark type). -- | BenchmarkUnsupported BenchmarkType- deriving (Eq, Read, Show, Typeable, Data)+ deriving (Eq, Generic, Read, Show, Typeable, Data) +instance Binary BenchmarkInterface+ instance Monoid Benchmark where mempty = Benchmark { benchmarkName = mempty,@@ -581,8 +733,10 @@ -- ^ \"type: exitcode-stdio-x.y\" | BenchmarkTypeUnknown String Version -- ^ Some unknown benchmark type e.g. \"type: foo\"- deriving (Show, Read, Eq, Typeable, Data)+ deriving (Generic, Show, Read, Eq, Typeable, Data) +instance Binary BenchmarkType+ knownBenchmarkTypes :: [BenchmarkType] knownBenchmarkTypes = [ BenchmarkTypeExe (Version [1,0] []) ] @@ -613,6 +767,7 @@ pkgconfigDepends :: [Dependency], -- ^ pkg-config packages that are used frameworks :: [String], -- ^support frameworks for Mac OS X cSources :: [FilePath],+ jsSources :: [FilePath], hsSourceDirs :: [FilePath], -- ^ where to look for the Haskell module hierarchy otherModules :: [ModuleName], -- ^ non-exposed or non-main modules @@ -623,20 +778,24 @@ oldExtensions :: [Extension], -- ^ the old extensions field, treated same as 'defaultExtensions' extraLibs :: [String], -- ^ what libraries to link with when compiling a program that uses your package+ extraGHCiLibs :: [String], -- ^ if present, overrides extraLibs when package is loaded with GHCi. extraLibDirs :: [String], includeDirs :: [FilePath], -- ^directories to find .h files includes :: [FilePath], -- ^ The .h files to be found in includeDirs installIncludes :: [FilePath], -- ^ .h files to install with the package options :: [(CompilerFlavor,[String])],- ghcProfOptions :: [String],- ghcSharedOptions :: [String],+ profOptions :: [(CompilerFlavor,[String])],+ sharedOptions :: [(CompilerFlavor,[String])], customFieldsBI :: [(String,String)], -- ^Custom fields starting -- with x-, stored in a -- simple assoc-list.- targetBuildDepends :: [Dependency] -- ^ Dependencies specific to a library or executable target+ targetBuildDepends :: [Dependency], -- ^ Dependencies specific to a library or executable target+ targetBuildRenaming :: Map PackageName ModuleRenaming }- deriving (Show,Read,Eq,Typeable,Data)+ deriving (Generic, Show, Read, Eq, Typeable, Data) +instance Binary BuildInfo+ instance Monoid BuildInfo where mempty = BuildInfo { buildable = True,@@ -647,6 +806,7 @@ pkgconfigDepends = [], frameworks = [], cSources = [],+ jsSources = [], hsSourceDirs = [], otherModules = [], defaultLanguage = Nothing,@@ -655,15 +815,17 @@ otherExtensions = [], oldExtensions = [], extraLibs = [],+ extraGHCiLibs = [], extraLibDirs = [], includeDirs = [], includes = [], installIncludes = [], options = [],- ghcProfOptions = [],- ghcSharedOptions = [],+ profOptions = [],+ sharedOptions = [], customFieldsBI = [],- targetBuildDepends = []+ targetBuildDepends = [],+ targetBuildRenaming = Map.empty } mappend a b = BuildInfo { buildable = buildable a && buildable b,@@ -674,6 +836,7 @@ pkgconfigDepends = combine pkgconfigDepends, frameworks = combineNub frameworks, cSources = combineNub cSources,+ jsSources = combineNub jsSources, hsSourceDirs = combineNub hsSourceDirs, otherModules = combineNub otherModules, defaultLanguage = combineMby defaultLanguage,@@ -682,20 +845,23 @@ otherExtensions = combineNub otherExtensions, oldExtensions = combineNub oldExtensions, extraLibs = combine extraLibs,+ extraGHCiLibs = combine extraGHCiLibs, extraLibDirs = combineNub extraLibDirs, includeDirs = combineNub includeDirs, includes = combineNub includes, installIncludes = combineNub installIncludes, options = combine options,- ghcProfOptions = combine ghcProfOptions,- ghcSharedOptions = combine ghcSharedOptions,+ profOptions = combine profOptions,+ sharedOptions = combine sharedOptions, customFieldsBI = combine customFieldsBI,- targetBuildDepends = combineNub targetBuildDepends+ targetBuildDepends = combineNub targetBuildDepends,+ targetBuildRenaming = combineMap targetBuildRenaming } where combine field = field a `mappend` field b combineNub field = nub (combine field) combineMby field = field b `mplus` field a+ combineMap field = Map.unionWith mappend (field a) (field b) emptyBuildInfo :: BuildInfo emptyBuildInfo = mempty@@ -746,10 +912,20 @@ -- |Select options for a particular Haskell compiler. hcOptions :: CompilerFlavor -> BuildInfo -> [String]-hcOptions hc bi = [ opt | (hc',opts) <- options bi- , hc' == hc- , opt <- opts ]+hcOptions = lookupHcOptions options +hcProfOptions :: CompilerFlavor -> BuildInfo -> [String]+hcProfOptions = lookupHcOptions profOptions++hcSharedOptions :: CompilerFlavor -> BuildInfo -> [String]+hcSharedOptions = lookupHcOptions sharedOptions++lookupHcOptions :: (BuildInfo -> [(CompilerFlavor,[String])])+ -> CompilerFlavor -> BuildInfo -> [String]+lookupHcOptions f hc bi = [ opt | (hc',opts) <- f bi+ , hc' == hc+ , opt <- opts ]+ -- ------------------------------------------------------------ -- * Source repos -- ------------------------------------------------------------@@ -809,8 +985,10 @@ -- given the default is \".\" ie no subdirectory. repoSubdir :: Maybe FilePath }- deriving (Eq, Read, Show, Typeable, Data)+ deriving (Eq, Generic, Read, Show, Typeable, Data) +instance Binary SourceRepo+ -- | What this repo info is for, what it represents. -- data RepoKind =@@ -825,8 +1003,10 @@ | RepoThis | RepoKindUnknown String- deriving (Eq, Ord, Read, Show, Typeable, Data)+ deriving (Eq, Generic, Ord, Read, Show, Typeable, Data) +instance Binary RepoKind+ -- | An enumeration of common source control systems. The fields used in the -- 'SourceRepo' depend on the type of repo. The tools and methods used to -- obtain and track the repo depend on the repo type.@@ -834,8 +1014,10 @@ data RepoType = Darcs | Git | SVN | CVS | Mercurial | GnuArch | Bazaar | Monotone | OtherRepoType String- deriving (Eq, Ord, Read, Show, Typeable, Data)+ deriving (Eq, Generic, Ord, Read, Show, Typeable, Data) +instance Binary RepoType+ knownRepoTypes :: [RepoType] knownRepoTypes = [Darcs, Git, SVN, CVS ,Mercurial, GnuArch, Bazaar, Monotone]@@ -936,8 +1118,10 @@ -- | A 'FlagName' is the name of a user-defined configuration flag newtype FlagName = FlagName String- deriving (Eq, Ord, Show, Read, Typeable, Data)+ deriving (Eq, Generic, Ord, Show, Read, Typeable, Data) +instance Binary FlagName+ -- | A 'FlagAssignment' is a total or partial mapping of 'FlagName's to -- 'Bool' flag values. It represents the flags chosen by the user or -- discovered during configuration. For example @--flags=foo --flags=-bar@@@ -952,13 +1136,6 @@ | Impl CompilerFlavor VersionRange deriving (Eq, Show, Typeable, Data) ---instance Text ConfVar where--- disp (OS os) = "os(" ++ display os ++ ")"--- disp (Arch arch) = "arch(" ++ display arch ++ ")"--- disp (Flag (ConfFlag f)) = "flag(" ++ f ++ ")"--- disp (Impl c v) = "impl(" ++ display c--- ++ " " ++ display v ++ ")"- -- | A boolean expression parameterized over the variable type used. data Condition c = Var c | Lit Bool@@ -967,13 +1144,6 @@ | CAnd (Condition c) (Condition c) deriving (Show, Eq, Typeable, Data) ---instance Text c => Text (Condition c) where--- disp (Var x) = text (show x)--- disp (Lit b) = text (show b)--- disp (CNot c) = char '!' <> parens (ppCond c)--- disp (COr c1 c2) = parens $ sep [ppCond c1, text "||" <+> ppCond c2]--- disp (CAnd c1 c2) = parens $ sep [ppCond c1, text "&&" <+> ppCond c2]- data CondTree v c a = CondNode { condTreeData :: a , condTreeConstraints :: c@@ -982,16 +1152,3 @@ , Maybe (CondTree v c a))] } deriving (Show, Eq, Typeable, Data)----instance (Text v, Text c) => Text (CondTree v c a) where--- disp (CondNode _dat cs ifs) =--- (text "build-depends: " <+>--- disp cs)--- $+$--- (vcat $ map ppIf ifs)--- where--- ppIf (c,thenTree,mElseTree) =--- ((text "if" <+> ppCond c <> colon) $$--- nest 2 (ppCondTree thenTree disp))--- $+$ (maybe empty (\t -> text "else: " $$ nest 2 (ppCondTree t disp))--- mElseTree)
Distribution/PackageDescription/Check.hs view
@@ -40,12 +40,14 @@ ( filterM, liftM ) import qualified System.Directory as System ( doesFileExist, doesDirectoryExist )+import qualified Data.Map as Map import Distribution.PackageDescription import Distribution.PackageDescription.Configuration ( flattenPackageDescription, finalizePackageDescription ) import Distribution.Compiler- ( CompilerFlavor(..), buildCompilerFlavor, CompilerId(..) )+ ( CompilerFlavor(..), buildCompilerFlavor, CompilerId(..)+ , unknownCompilerInfo, AbiTag(..) ) import Distribution.System ( OS(..), Arch(..), buildPlatform ) import Distribution.License@@ -73,7 +75,8 @@ import qualified Language.Haskell.Extension as Extension (deprecatedExtensions) import Language.Haskell.Extension- ( Language(UnknownLanguage), knownLanguages, Extension(..), KnownExtension(..) )+ ( Language(UnknownLanguage), knownLanguages+ , Extension(..), KnownExtension(..) ) import System.FilePath ( (</>), takeExtension, isRelative, isAbsolute , splitDirectories, splitPath )@@ -119,7 +122,8 @@ check False _ = Nothing check True pc = Just pc -checkSpecVersion :: PackageDescription -> [Int] -> Bool -> PackageCheck -> Maybe PackageCheck+checkSpecVersion :: PackageDescription -> [Int] -> Bool -> PackageCheck+ -> Maybe PackageCheck checkSpecVersion pkg specver cond pc | specVersion pkg >= Version specver [] = Nothing | otherwise = check cond pc@@ -189,7 +193,8 @@ ++ ". The name of every executable, test suite, and benchmark section in" ++ " the package must be unique." ]- --TODO: check for name clashes case insensitively: windows file systems cannot cope.+ --TODO: check for name clashes case insensitively: windows file systems cannot+ --cope. ++ maybe [] (checkLibrary pkg) (library pkg) ++ concatMap (checkExecutable pkg) (executables pkg)@@ -211,18 +216,35 @@ duplicateNames = dups $ exeNames ++ testNames ++ bmNames checkLibrary :: PackageDescription -> Library -> [PackageCheck]-checkLibrary _pkg lib =+checkLibrary pkg lib = catMaybes [ check (not (null moduleDuplicates)) $ PackageBuildImpossible $ "Duplicate modules in library: " ++ commaSep (map display moduleDuplicates)++ -- check use of required-signatures/exposed-signatures sections+ , checkVersion [1,21] (not (null (requiredSignatures lib))) $+ PackageDistInexcusable $+ "To use the 'required-signatures' field the package needs to specify "+ ++ "at least 'cabal-version: >= 1.21'."++ , checkVersion [1,21] (not (null (exposedSignatures lib))) $+ PackageDistInexcusable $+ "To use the 'exposed-signatures' field the package needs to specify "+ ++ "at least 'cabal-version: >= 1.21'." ] where- moduleDuplicates = dups (libModules lib)+ checkVersion :: [Int] -> Bool -> PackageCheck -> Maybe PackageCheck+ checkVersion ver cond pc+ | specVersion pkg >= Version ver [] = Nothing+ | otherwise = check cond pc + moduleDuplicates = dups (libModules lib +++ map moduleReexportName (reexportedModules lib))+ checkExecutable :: PackageDescription -> Executable -> [PackageCheck] checkExecutable pkg exe = catMaybes [@@ -473,10 +495,13 @@ checkLicense pkg = catMaybes [ - check (license pkg == AllRightsReserved) $+ check (license pkg == UnspecifiedLicense) $ PackageDistInexcusable- "The 'license' field is missing or specified as AllRightsReserved."+ "The 'license' field is missing." + , check (license pkg == AllRightsReserved) $+ PackageDistSuspicious+ "The 'license' is AllRightsReserved. Is that really what you want?" , case license pkg of UnknownLicense l -> Just $ PackageBuildWarning $@@ -501,7 +526,8 @@ ++ "version then please file a ticket." _ -> Nothing - , check (license pkg `notElem` [AllRightsReserved, PublicDomain]+ , check (license pkg `notElem` [ AllRightsReserved+ , UnspecifiedLicense, PublicDomain] -- AllRightsReserved and PublicDomain are not strictly -- licenses so don't need license files. && null (licenseFiles pkg)) $@@ -595,9 +621,12 @@ PackageDistInexcusable $ "'ghc-options: -fhpc' is not appropriate for a distributed package." - , check (any ("-d" `isPrefixOf`) all_ghc_options) $+ -- -dynamic is not a debug flag+ , check (any (\opt -> "-d" `isPrefixOf` opt && opt /= "-dynamic")+ all_ghc_options) $ PackageDistInexcusable $- "'ghc-options: -d*' debug flags are not appropriate for a distributed package."+ "'ghc-options: -d*' debug flags are not appropriate "+ ++ "for a distributed package." , checkFlags ["-prof"] $ PackageBuildWarning $@@ -607,37 +636,43 @@ , checkFlags ["-o"] $ PackageBuildWarning $- "'ghc-options: -o' is not needed. The output files are named automatically."+ "'ghc-options: -o' is not needed. "+ ++ "The output files are named automatically." , checkFlags ["-hide-package"] $ PackageBuildWarning $- "'ghc-options: -hide-package' is never needed. Cabal hides all packages."+ "'ghc-options: -hide-package' is never needed. "+ ++ "Cabal hides all packages." , checkFlags ["--make"] $ PackageBuildWarning $- "'ghc-options: --make' is never needed. Cabal uses this automatically."+ "'ghc-options: --make' is never needed. Cabal uses this automatically." , checkFlags ["-main-is"] $ PackageDistSuspicious $- "'ghc-options: -main-is' is not portable."+ "'ghc-options: -main-is' is not portable." , checkFlags ["-O0", "-Onot"] $ PackageDistSuspicious $- "'ghc-options: -O0' is not needed. Use the --disable-optimization configure flag."+ "'ghc-options: -O0' is not needed. "+ ++ "Use the --disable-optimization configure flag." , checkFlags [ "-O", "-O1"] $ PackageDistInexcusable $- "'ghc-options: -O' is not needed. Cabal automatically adds the '-O' flag. "- ++ "Setting it yourself interferes with the --disable-optimization flag."+ "'ghc-options: -O' is not needed. "+ ++ "Cabal automatically adds the '-O' flag. "+ ++ "Setting it yourself interferes with the --disable-optimization flag." , checkFlags ["-O2"] $ PackageDistSuspicious $- "'ghc-options: -O2' is rarely needed. Check that it is giving a real benefit "- ++ "and not just imposing longer compile times on your users."+ "'ghc-options: -O2' is rarely needed. "+ ++ "Check that it is giving a real benefit "+ ++ "and not just imposing longer compile times on your users." , checkFlags ["-split-objs"] $ PackageBuildWarning $- "'ghc-options: -split-objs' is not needed. Use the --enable-split-objs configure flag."+ "'ghc-options: -split-objs' is not needed. "+ ++ "Use the --enable-split-objs configure flag." , checkFlags ["-optl-Wl,-s", "-optl-s"] $ PackageDistInexcusable $@@ -649,8 +684,14 @@ , checkFlags ["-fglasgow-exts"] $ PackageDistSuspicious $- "Instead of 'ghc-options: -fglasgow-exts' it is preferable to use the 'extensions' field."+ "Instead of 'ghc-options: -fglasgow-exts' it is preferable to use "+ ++ "the 'extensions' field." + , checkProfFlags ["-auto-all"] $+ PackageDistSuspicious $+ "'ghc-prof-options: -auto-all' is fine during development, but "+ ++ "not recommended in a distributed package. "+ , check ("-threaded" `elem` lib_ghc_options) $ PackageDistSuspicious $ "'ghc-options: -threaded' has no effect for libraries. It should "@@ -683,49 +724,57 @@ && ("-Wall" `elem` opts || "-W" `elem` opts) has_Werror = any (\opts -> "-Werror" `elem` opts) ghc_options - ghc_options = [ strs | bi <- allBuildInfo pkg- , (GHC, strs) <- options bi ]- all_ghc_options = concat ghc_options+ (ghc_options, ghc_prof_options) =+ unzip . map (\bi -> (hcOptions GHC bi, hcProfOptions GHC bi))+ $ (allBuildInfo pkg)+ all_ghc_options = concat ghc_options+ all_ghc_prof_options = concat ghc_prof_options lib_ghc_options = maybe [] (hcOptions GHC . libBuildInfo) (library pkg) - checkFlags :: [String] -> PackageCheck -> Maybe PackageCheck- checkFlags flags = check (any (`elem` flags) all_ghc_options)+ checkFlags,checkProfFlags :: [String] -> PackageCheck -> Maybe PackageCheck+ checkFlags flags = doCheckFlags flags all_ghc_options+ checkProfFlags flags = doCheckFlags flags all_ghc_prof_options + doCheckFlags flags opts = check (any (`elem` flags) opts)+ ghcExtension ('-':'f':name) = case name of- "allow-overlapping-instances" -> Just (EnableExtension OverlappingInstances)- "no-allow-overlapping-instances" -> Just (DisableExtension OverlappingInstances)- "th" -> Just (EnableExtension TemplateHaskell)- "no-th" -> Just (DisableExtension TemplateHaskell)- "ffi" -> Just (EnableExtension ForeignFunctionInterface)- "no-ffi" -> Just (DisableExtension ForeignFunctionInterface)- "fi" -> Just (EnableExtension ForeignFunctionInterface)- "no-fi" -> Just (DisableExtension ForeignFunctionInterface)- "monomorphism-restriction" -> Just (EnableExtension MonomorphismRestriction)- "no-monomorphism-restriction" -> Just (DisableExtension MonomorphismRestriction)- "mono-pat-binds" -> Just (EnableExtension MonoPatBinds)- "no-mono-pat-binds" -> Just (DisableExtension MonoPatBinds)- "allow-undecidable-instances" -> Just (EnableExtension UndecidableInstances)- "no-allow-undecidable-instances" -> Just (DisableExtension UndecidableInstances)- "allow-incoherent-instances" -> Just (EnableExtension IncoherentInstances)- "no-allow-incoherent-instances" -> Just (DisableExtension IncoherentInstances)- "arrows" -> Just (EnableExtension Arrows)- "no-arrows" -> Just (DisableExtension Arrows)- "generics" -> Just (EnableExtension Generics)- "no-generics" -> Just (DisableExtension Generics)- "implicit-prelude" -> Just (EnableExtension ImplicitPrelude)- "no-implicit-prelude" -> Just (DisableExtension ImplicitPrelude)- "implicit-params" -> Just (EnableExtension ImplicitParams)- "no-implicit-params" -> Just (DisableExtension ImplicitParams)- "bang-patterns" -> Just (EnableExtension BangPatterns)- "no-bang-patterns" -> Just (DisableExtension BangPatterns)- "scoped-type-variables" -> Just (EnableExtension ScopedTypeVariables)- "no-scoped-type-variables" -> Just (DisableExtension ScopedTypeVariables)- "extended-default-rules" -> Just (EnableExtension ExtendedDefaultRules)- "no-extended-default-rules" -> Just (DisableExtension ExtendedDefaultRules)+ "allow-overlapping-instances" -> enable OverlappingInstances+ "no-allow-overlapping-instances" -> disable OverlappingInstances+ "th" -> enable TemplateHaskell+ "no-th" -> disable TemplateHaskell+ "ffi" -> enable ForeignFunctionInterface+ "no-ffi" -> disable ForeignFunctionInterface+ "fi" -> enable ForeignFunctionInterface+ "no-fi" -> disable ForeignFunctionInterface+ "monomorphism-restriction" -> enable MonomorphismRestriction+ "no-monomorphism-restriction" -> disable MonomorphismRestriction+ "mono-pat-binds" -> enable MonoPatBinds+ "no-mono-pat-binds" -> disable MonoPatBinds+ "allow-undecidable-instances" -> enable UndecidableInstances+ "no-allow-undecidable-instances" -> disable UndecidableInstances+ "allow-incoherent-instances" -> enable IncoherentInstances+ "no-allow-incoherent-instances" -> disable IncoherentInstances+ "arrows" -> enable Arrows+ "no-arrows" -> disable Arrows+ "generics" -> enable Generics+ "no-generics" -> disable Generics+ "implicit-prelude" -> enable ImplicitPrelude+ "no-implicit-prelude" -> disable ImplicitPrelude+ "implicit-params" -> enable ImplicitParams+ "no-implicit-params" -> disable ImplicitParams+ "bang-patterns" -> enable BangPatterns+ "no-bang-patterns" -> disable BangPatterns+ "scoped-type-variables" -> enable ScopedTypeVariables+ "no-scoped-type-variables" -> disable ScopedTypeVariables+ "extended-default-rules" -> enable ExtendedDefaultRules+ "no-extended-default-rules" -> disable ExtendedDefaultRules _ -> Nothing- ghcExtension "-cpp" = Just (EnableExtension CPP)+ ghcExtension "-cpp" = enable CPP ghcExtension _ = Nothing + enable e = Just (EnableExtension e)+ disable e = Just (DisableExtension e)+ checkCCOptions :: PackageDescription -> [PackageCheck] checkCCOptions pkg = catMaybes [@@ -830,6 +879,7 @@ ++ [ (path, "data-dir") | path <- [dataDir pkg]] ++ concat [ [ (path, "c-sources") | path <- cSources bi ]+ ++ [ (path, "js-sources") | path <- jsSources bi ] ++ [ (path, "install-includes") | path <- installIncludes bi ] ++ [ (path, "hs-source-dirs") | path <- hsSourceDirs bi ] | bi <- allBuildInfo pkg ]@@ -902,6 +952,22 @@ ++ "different modules then list the other ones in the " ++ "'other-languages' field." + -- check use of reexported-modules sections+ , checkVersion [1,21]+ (maybe False (not.null.reexportedModules) (library pkg)) $+ PackageDistInexcusable $+ "To use the 'reexported-module' field the package needs to specify "+ ++ "at least 'cabal-version: >= 1.21'."++ -- check use of thinning and renaming+ , checkVersion [1,21] (not (null depsUsingThinningRenamingSyntax)) $+ PackageDistInexcusable $+ "The package uses "+ ++ "thinning and renaming in the 'build-depends' field: "+ ++ commaSep (map display depsUsingThinningRenamingSyntax)+ ++ ". To use this new syntax, the package needs to specify at least"+ ++ "'cabal-version: >= 1.21'."+ -- check use of default-extensions field -- don't need to do the equivalent check for other-extensions , checkVersion [1,10] (any (not . null) (buildInfoField defaultExtensions)) $@@ -1072,10 +1138,20 @@ depsUsingWildcardSyntax = [ dep | dep@(Dependency _ vr) <- buildDepends pkg , usesWildcardSyntax vr ] - testedWithUsingWildcardSyntax = [ Dependency (PackageName (display compiler)) vr- | (compiler, vr) <- testedWith pkg- , usesWildcardSyntax vr ]+ -- XXX: If the user writes build-depends: foo with (), this is+ -- indistinguishable from build-depends: foo, so there won't be an+ -- error even though there should be+ depsUsingThinningRenamingSyntax =+ [ name+ | bi <- allBuildInfo pkg+ , (name, rns) <- Map.toList (targetBuildRenaming bi)+ , rns /= ModuleRenaming True [] ] + testedWithUsingWildcardSyntax =+ [ Dependency (PackageName (display compiler)) vr+ | (compiler, vr) <- testedWith pkg+ , usesWildcardSyntax vr ]+ usesWildcardSyntax :: VersionRange -> Bool usesWildcardSyntax = foldVersionRange'@@ -1094,7 +1170,8 @@ intersectVersionRanges unionVersionRanges id compatLicenses = [ GPL Nothing, LGPL Nothing, AGPL Nothing, BSD3, BSD4- , PublicDomain, AllRightsReserved, OtherLicense ]+ , PublicDomain, AllRightsReserved+ , UnspecifiedLicense, OtherLicense ] mentionedExtensions = [ ext | bi <- allBuildInfo pkg , ext <- allExtensions bi ]@@ -1154,8 +1231,10 @@ (\v -> (Disp.text ">=" <> disp v , 0)) (\v -> (Disp.text "<=" <> disp v , 0)) (\v _ -> (Disp.text "==" <> dispWild v , 0))- (\(r1, p1) (r2, p2) -> (punct 2 p1 r1 <+> Disp.text "||" <+> punct 2 p2 r2 , 2))- (\(r1, p1) (r2, p2) -> (punct 1 p1 r1 <+> Disp.text "&&" <+> punct 1 p2 r2 , 1))+ (\(r1, p1) (r2, p2) ->+ (punct 2 p1 r1 <+> Disp.text "||" <+> punct 2 p2 r2 , 2))+ (\(r1, p1) (r2, p2) ->+ (punct 1 p1 r1 <+> Disp.text "&&" <+> punct 1 p2 r2 , 1)) (\(r, _ ) -> (Disp.parens r, 0)) -- parens where@@ -1208,7 +1287,8 @@ -- using no package index and the current platform. finalised = finalizePackageDescription [] (const True) buildPlatform- (CompilerId buildCompilerFlavor (Version [] []))+ (unknownCompilerInfo+ (CompilerId buildCompilerFlavor (Version [] [])) NoAbiTag) [] pkg baseDependency = case finalised of Right (pkg', _) | not (null baseDeps) ->@@ -1341,7 +1421,8 @@ exists <- doesFileExist ops "configure" return $ check (not exists) $ PackageBuildWarning $- "The 'build-type' is 'Configure' but there is no 'configure' script."+ "The 'build-type' is 'Configure' but there is no 'configure' script. "+ ++ "You probably need to run 'autoreconf -i' to generate it." checkConfigureExists _ _ = return Nothing checkLocalPathsExist :: Monad m => CheckPackageContentOps m
Distribution/PackageDescription/Configuration.hs view
@@ -46,6 +46,8 @@ ( Platform(..), OS, Arch ) import Distribution.Simple.Utils ( currentDir, lowercase )+import Distribution.Simple.Compiler+ ( CompilerInfo(..) ) import Distribution.Text ( Text(parse) )@@ -97,16 +99,23 @@ -- | Simplify a configuration condition using the OS and arch names. Returns -- the names of all the flags occurring in the condition.-simplifyWithSysParams :: OS -> Arch -> CompilerId -> Condition ConfVar+simplifyWithSysParams :: OS -> Arch -> CompilerInfo -> Condition ConfVar -> (Condition FlagName, [FlagName])-simplifyWithSysParams os arch (CompilerId comp compVer) cond = (cond', flags)+simplifyWithSysParams os arch cinfo cond = (cond', flags) where (cond', flags) = simplifyCondition cond interp interp (OS os') = Right $ os' == os interp (Arch arch') = Right $ arch' == arch- interp (Impl comp' vr) = Right $ comp' == comp- && compVer `withinRange` vr- interp (Flag f) = Left f+ interp (Impl comp vr)+ | matchImpl (compilerInfoId cinfo) = Right True+ | otherwise = case compilerInfoCompat cinfo of+ -- fixme: treat Nothing as unknown, rather than empty list once we+ -- support partial resolution of system parameters+ Nothing -> Right False+ Just compat -> Right (any matchImpl compat)+ where+ matchImpl (CompilerId c v) = comp == c && v `withinRange` vr+ interp (Flag f) = Left f -- TODO: Add instances and check --@@ -208,7 +217,7 @@ -- ^ Domain for each flag name, will be tested in order. -> OS -- ^ OS as returned by Distribution.System.buildOS -> Arch -- ^ Arch as returned by Distribution.System.buildArch- -> CompilerId -- ^ Compiler flavour + version+ -> CompilerInfo -- ^ Compiler information -> [Dependency] -- ^ Additional constraints -> [CondTree ConfVar [Dependency] PDTagged] -> ([Dependency] -> DepTestRslt [Dependency]) -- ^ Dependency test function.@@ -463,7 +472,7 @@ -- available packages? If this is unknown then use -- True. -> Platform -- ^ The 'Arch' and 'OS'- -> CompilerId -- ^ Compiler + Version+ -> CompilerInfo -- ^ Compiler information -> [Dependency] -- ^ Additional constraints -> GenericPackageDescription -> Either [Dependency]
Distribution/PackageDescription/Parse.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DeriveDataTypeable #-} ----------------------------------------------------------------------------- -- | -- Module : Distribution.PackageDescription.Parse@@ -48,11 +49,15 @@ import Control.Arrow (first) import System.Directory (doesFileExist) import qualified Data.ByteString.Lazy.Char8 as BS.Char8+import Data.Typeable+import Data.Data+import qualified Data.Map as Map import Distribution.Text ( Text(disp, parse), display, simpleParse ) import Distribution.Compat.ReadP ((+++), option)+import qualified Distribution.Compat.ReadP as Parse import Text.PrettyPrint import Distribution.ParseUtils hiding (parseFields)@@ -118,9 +123,6 @@ , simpleField "maintainer" showFreeText parseFreeText maintainer (\val pkg -> pkg{maintainer=val})- , commaListFieldWithSep vcat "build-depends"- disp parse- buildDepends (\xs pkg -> pkg{buildDepends=xs}) , simpleField "stability" showFreeText parseFreeText stability (\val pkg -> pkg{stability=val})@@ -181,6 +183,15 @@ [ listFieldWithSep vcat "exposed-modules" disp parseModuleNameQ exposedModules (\mods lib -> lib{exposedModules=mods}) + , commaListFieldWithSep vcat "reexported-modules" disp parse+ reexportedModules (\mods lib -> lib{reexportedModules=mods})++ , listFieldWithSep vcat "required-signatures" disp parseModuleNameQ+ requiredSignatures (\mods lib -> lib{requiredSignatures=mods})++ , listFieldWithSep vcat "exposed-signatures" disp parseModuleNameQ+ exposedSignatures (\mods lib -> lib{exposedSignatures=mods})+ , boolField "exposed" libExposed (\val lib -> lib{libExposed=val}) ] ++ map biToLib binfoFieldDescrs@@ -385,6 +396,10 @@ , commaListField "build-tools" disp parseBuildTool buildTools (\xs binfo -> binfo{buildTools=xs})+ , commaListFieldWithSep vcat "build-depends"+ disp parse+ buildDependsWithRenaming+ setBuildDependsWithRenaming , spaceListField "cpp-options" showToken parseTokenQ' cppOptions (\val binfo -> binfo{cppOptions=val})@@ -403,7 +418,9 @@ , listFieldWithSep vcat "c-sources" showFilePath parseFilePathQ cSources (\paths binfo -> binfo{cSources=paths})-+ , listFieldWithSep vcat "js-sources"+ showFilePath parseFilePathQ+ jsSources (\paths binfo -> binfo{jsSources=paths}) , simpleField "default-language" (maybe empty disp) (option Nothing (fmap Just parseLanguageQ)) defaultLanguage (\lang binfo -> binfo{defaultLanguage=lang})@@ -423,6 +440,9 @@ , listFieldWithSep vcat "extra-libraries" showToken parseTokenQ extraLibs (\xs binfo -> binfo{extraLibs=xs})+ , listFieldWithSep vcat "extra-ghci-libraries"+ showToken parseTokenQ+ extraGHCiLibs (\xs binfo -> binfo{extraGHCiLibs=xs}) , listField "extra-lib-dirs" showFilePath parseFilePathQ extraLibDirs (\xs binfo -> binfo{extraLibDirs=xs})@@ -441,20 +461,27 @@ , listFieldWithSep vcat "other-modules" disp parseModuleNameQ otherModules (\val binfo -> binfo{otherModules=val})- , listField "ghc-prof-options"- text parseTokenQ- ghcProfOptions (\val binfo -> binfo{ghcProfOptions=val})- , listField "ghc-shared-options"- text parseTokenQ- ghcSharedOptions (\val binfo -> binfo{ghcSharedOptions=val})+ , optsField "ghc-prof-options" GHC+ profOptions (\val binfo -> binfo{profOptions=val})+ , optsField "ghcjs-prof-options" GHCJS+ profOptions (\val binfo -> binfo{profOptions=val})+ , optsField "ghc-shared-options" GHC+ sharedOptions (\val binfo -> binfo{sharedOptions=val})+ , optsField "ghcjs-shared-options" GHCJS+ sharedOptions (\val binfo -> binfo{sharedOptions=val}) , optsField "ghc-options" GHC options (\path binfo -> binfo{options=path})- , optsField "hugs-options" Hugs- options (\path binfo -> binfo{options=path})- , optsField "nhc98-options" NHC+ , optsField "ghcjs-options" GHCJS options (\path binfo -> binfo{options=path}) , optsField "jhc-options" JHC options (\path binfo -> binfo{options=path})++ -- NOTE: Hugs and NHC are not supported anymore, but these fields are kept+ -- around for backwards compatibility.+ , optsField "hugs-options" Hugs+ options (const id)+ , optsField "nhc98-options" NHC+ options (const id) ] storeXFieldsBI :: UnrecFieldParser BuildInfo@@ -565,7 +592,7 @@ -- they add and define an accessor that specifies what the dependencies -- are. This way we would completely reuse the parsing knowledge from the -- field descriptor.-parseConstraint :: Field -> ParseResult [Dependency]+parseConstraint :: Field -> ParseResult [DependencyWithRenaming] parseConstraint (F l n v) | n == "build-depends" = runP l n (parseCommaList parse) v parseConstraint f = userBug $ "Constraint was expected (got: " ++ show f ++ ")"@@ -1002,15 +1029,17 @@ condFlds = [ f | f@IfBlock{} <- allflds ] sections = [ s | s@Section{} <- allflds ] - let (depFlds, dataFlds) = partition isConstraint simplFlds+ -- Put these through the normal parsing pass too, so that we+ -- collect the ModRenamings+ let depFlds = filter isConstraint simplFlds mapM_ (\(Section l n _ _) -> lift . warning $ "Unexpected section '" ++ n ++ "' on line " ++ show l) sections - a <- parser dataFlds- deps <- liftM concat . mapM (lift . parseConstraint) $ depFlds+ a <- parser simplFlds+ deps <- liftM concat . mapM (lift . fmap (map dependency) . parseConstraint) $ depFlds ifs <- mapM processIfs condFlds @@ -1214,3 +1243,32 @@ --test_findIndentTabs = findIndentTabs $ unlines $ -- [ "foo", " bar", " \t baz", "\t biz\t", "\t\t \t mib" ]++-- | Dependencies plus module renamings. This is what users specify; however,+-- renaming information is not used for dependency resolution.+data DependencyWithRenaming = DependencyWithRenaming Dependency ModuleRenaming+ deriving (Read, Show, Eq, Typeable, Data)++dependency :: DependencyWithRenaming -> Dependency+dependency (DependencyWithRenaming dep _) = dep++instance Text DependencyWithRenaming where+ disp (DependencyWithRenaming d rns) = disp d <+> disp rns+ parse = do d <- parse+ Parse.skipSpaces+ rns <- parse+ Parse.skipSpaces+ return (DependencyWithRenaming d rns)++buildDependsWithRenaming :: BuildInfo -> [DependencyWithRenaming]+buildDependsWithRenaming pkg =+ map (\dep@(Dependency n _) ->+ DependencyWithRenaming dep+ (Map.findWithDefault defaultRenaming n (targetBuildRenaming pkg)))+ (targetBuildDepends pkg)++setBuildDependsWithRenaming :: [DependencyWithRenaming] -> BuildInfo -> BuildInfo+setBuildDependsWithRenaming deps pkg = pkg {+ targetBuildDepends = map dependency deps,+ targetBuildRenaming = Map.fromList (map (\(DependencyWithRenaming (Dependency n _) rns) -> (n, rns)) deps)+ }
Distribution/PackageDescription/PrettyPrint.hs view
@@ -1,5 +1,5 @@ --------------------------------------------------------------------------------+-- | -- Module : Distribution.PackageDescription.PrettyPrint -- Copyright : Jürgen Nicklisch-Franken 2010 -- License : BSD3@@ -8,7 +8,7 @@ -- Stability : provisional -- Portability : portable ----- | Pretty printing for cabal files+-- Pretty printing for cabal files -- ----------------------------------------------------------------------------- @@ -32,7 +32,7 @@ import Distribution.Simple.Utils (writeUTF8File) import Distribution.ParseUtils (showFreeText, FieldDescr(..), indentWith, ppField, ppFields) import Distribution.PackageDescription.Parse (pkgDescrFieldDescrs,binfoFieldDescrs,libFieldDescrs,- sourceRepoFieldDescrs)+ sourceRepoFieldDescrs,flagFieldDescrs) import Distribution.Package (Dependency(..)) import Distribution.Text (Text(..)) import Data.Maybe (isJust, fromJust, isNothing)@@ -74,6 +74,23 @@ where sourceRepoFieldDescrs' = [fd | fd <- sourceRepoFieldDescrs, fieldName fd /= "kind"] +-- TODO: this is a temporary hack. Ideally, fields containing default values+-- would be filtered out when the @FieldDescr a@ list is generated.+ppFieldsFiltered :: [(String, String)] -> [FieldDescr a] -> a -> Doc+ppFieldsFiltered removable fields x = ppFields (filter nondefault fields) x+ where+ nondefault (FieldDescr name getter _) =+ maybe True (render (getter x) /=) (lookup name removable)++binfoDefaults :: [(String, String)]+binfoDefaults = [("buildable", "True")]++libDefaults :: [(String, String)]+libDefaults = ("exposed", "True") : binfoDefaults++flagDefaults :: [(String, String)]+flagDefaults = [("default", "True"), ("manual", "False")]+ ppDiffFields :: [FieldDescr a] -> a -> a -> Doc ppDiffFields fields x y = vcat [ ppField name (getter x)@@ -91,20 +108,17 @@ ppGenPackageFlags flds = vcat [ppFlag f | f <- flds] ppFlag :: Flag -> Doc-ppFlag (MkFlag name desc dflt manual) =- emptyLine $ text "flag" <+> ppFlagName name $+$- (nest indentWith ((if null desc- then empty- else text "description: " <+> showFreeText desc) $+$- (if dflt then empty else text "default: False") $+$- (if manual then text "manual: True" else empty)))+ppFlag flag@(MkFlag name _ _ _) =+ emptyLine $ text "flag" <+> ppFlagName name $+$ nest indentWith fields+ where+ fields = ppFieldsFiltered flagDefaults flagFieldDescrs flag ppLibrary :: (Maybe (CondTree ConfVar [Dependency] Library)) -> Doc ppLibrary Nothing = empty ppLibrary (Just condTree) = emptyLine $ text "library" $+$ nest indentWith (ppCondTree condTree Nothing ppLib) where- ppLib lib Nothing = ppFields libFieldDescrs lib+ ppLib lib Nothing = ppFieldsFiltered libDefaults libFieldDescrs lib $$ ppCustomFields (customFieldsBI (libBuildInfo lib)) ppLib lib (Just plib) = ppDiffFields libFieldDescrs lib plib $$ ppCustomFields (customFieldsBI (libBuildInfo lib))@@ -116,7 +130,7 @@ where ppExe (Executable _ modulePath' buildInfo') Nothing = (if modulePath' == "" then empty else text "main-is:" <+> text modulePath')- $+$ ppFields binfoFieldDescrs buildInfo'+ $+$ ppFieldsFiltered binfoDefaults binfoFieldDescrs buildInfo' $+$ ppCustomFields (customFieldsBI buildInfo') ppExe (Executable _ modulePath' buildInfo') (Just (Executable _ modulePath2 buildInfo2)) =@@ -138,7 +152,7 @@ (testSuiteMainIs testsuite) $+$ maybe empty (\m -> text "test-module:" <+> disp m) (testSuiteModule testsuite)- $+$ ppFields binfoFieldDescrs (testBuildInfo testsuite)+ $+$ ppFieldsFiltered binfoDefaults binfoFieldDescrs (testBuildInfo testsuite) $+$ ppCustomFields (customFieldsBI (testBuildInfo testsuite)) where maybeTestType | testInterface testsuite == mempty = Nothing@@ -168,7 +182,7 @@ maybeBenchmarkType $+$ maybe empty (\f -> text "main-is:" <+> text f) (benchmarkMainIs benchmark)- $+$ ppFields binfoFieldDescrs (benchmarkBuildInfo benchmark)+ $+$ ppFieldsFiltered binfoDefaults binfoFieldDescrs (benchmarkBuildInfo benchmark) $+$ ppCustomFields (customFieldsBI (benchmarkBuildInfo benchmark)) where maybeBenchmarkType | benchmarkInterface benchmark == mempty = Nothing@@ -209,6 +223,7 @@ then ppCondTree ct Nothing ppIt else res where+ -- TODO: this ends up printing trailing spaces when combined with nest. ppIf (c,thenTree,mElseTree) = ((emptyLine $ text "if" <+> ppCondition c) $$ nest indentWith (ppCondTree thenTree@@ -225,7 +240,7 @@ text "build-depends:" $+$ nest indentWith (vcat (punctuate comma (map disp deps))) emptyLine :: Doc -> Doc-emptyLine d = text " " $+$ d+emptyLine d = text "" $+$ d
Distribution/ParseUtils.hs view
@@ -50,7 +50,8 @@ import Distribution.Text ( Text(..) ) import Distribution.Simple.Utils- ( comparing, intercalate, lowercase, normaliseLineEndings )+ ( comparing, dropWhileEndLE, intercalate, lowercase+ , normaliseLineEndings ) import Language.Haskell.Extension ( Language, Extension ) @@ -198,7 +199,7 @@ where set' xs b = set (get b ++ xs) b showF' = separator . punctuate comma . map showF- + commaListField :: String -> (a -> Doc) -> ReadP [a] a -> (b -> [a]) -> ([a] -> b -> b) -> FieldDescr b commaListField = commaListFieldWithSep fsep@@ -267,7 +268,7 @@ vcat [ ppField name (getter x) | FieldDescr name getter _ <- fields ] ppField :: String -> Doc -> Doc-ppField name fielddoc +ppField name fielddoc | isEmpty fielddoc = empty | name `elem` nestedFields = text name <> colon $+$ nest indentWith fielddoc | otherwise = text name <> colon <+> fielddoc@@ -280,6 +281,7 @@ , "extra-tmp-files" , "exposed-modules" , "c-sources"+ , "js-sources" , "extra-libraries" , "includes" , "install-includes"@@ -477,7 +479,7 @@ trimLeading, trimTrailing :: String -> String trimLeading = dropWhile isSpace-trimTrailing = reverse . dropWhile isSpace . reverse+trimTrailing = dropWhileEndLE isSpace type SyntaxTree = Tree (LineNo, HasTabs, String)@@ -656,7 +658,7 @@ parseOptVersion = parseQuoted ver <++ ver where ver :: ReadP r Version ver = parse <++ return noVersion- noVersion = Version{ versionBranch=[], versionTags=[] }+ noVersion = Version [] [] parseTestedWithQ :: ReadP r (CompilerFlavor,VersionRange) parseTestedWithQ = parseQuoted tw <++ tw
Distribution/Simple.hs view
@@ -143,7 +143,7 @@ defaultMainHelper :: UserHooks -> Args -> IO () defaultMainHelper hooks args = topHandler $- case commandsRun globalCommand commands args of+ case commandsRun (globalCommand commands) commands args of CommandHelp help -> printHelp help CommandList opts -> printOptionsList opts CommandErrors errs -> printErrors errs@@ -347,12 +347,9 @@ -- default action is a no-op and if the package uses the old test interface -- the new handler will find no tests. runTests hooks args False pkg_descr localBuildInfo- --FIXME: this is a hack, passing the args inside the flags- -- it's because the args to not get passed to the main test hook- let flags' = flags { testList = Flag args }- hookedAction preTest testHook postTest+ hookedActionWithArgs preTest testHook postTest (getBuildConfig hooks verbosity distPref)- hooks flags' args+ hooks flags args benchAction :: UserHooks -> BenchmarkFlags -> Args -> IO () benchAction hooks flags args = do@@ -510,7 +507,7 @@ buildHook = defaultBuildHook, replHook = defaultReplHook, copyHook = \desc lbi _ f -> install desc lbi f, -- has correct 'copy' behavior with params- testHook = defaultTestHook,+ testHook = defaultTestHook, benchHook = defaultBenchHook, instHook = defaultInstallHook, sDistHook = \p l h f -> sdist p l f srcPref (allSuffixHandlers h),@@ -653,10 +650,10 @@ info verbosity $ "Reading parameters from " ++ infoFile readHookedBuildInfo verbosity infoFile -defaultTestHook :: PackageDescription -> LocalBuildInfo+defaultTestHook :: Args -> PackageDescription -> LocalBuildInfo -> UserHooks -> TestFlags -> IO ()-defaultTestHook pkg_descr localbuildinfo _ flags =- test pkg_descr localbuildinfo flags+defaultTestHook args pkg_descr localbuildinfo _ flags =+ test args pkg_descr localbuildinfo flags defaultBenchHook :: Args -> PackageDescription -> LocalBuildInfo -> UserHooks -> BenchmarkFlags -> IO ()
Distribution/Simple/Bench.hs view
@@ -19,7 +19,7 @@ ( PackageDescription(..), BuildInfo(buildable) , Benchmark(..), BenchmarkInterface(..), benchmarkType, hasBenchmarks ) import Distribution.Simple.BuildPaths ( exeExtension )-import Distribution.Simple.Compiler ( Compiler(..) )+import Distribution.Simple.Compiler ( compilerInfo ) import Distribution.Simple.InstallDirs ( fromPathTemplate, initialPathTemplateEnv, PathTemplateVariable(..) , substPathTemplate , toPathTemplate, PathTemplate )@@ -112,8 +112,8 @@ ExitFailure _ -> "ERROR") --- TODO: This is abusing the notion of a 'PathTemplate'. The result--- isn't neccesarily a path.+-- TODO: This is abusing the notion of a 'PathTemplate'. The result isn't+-- necessarily a path. benchOption :: PD.PackageDescription -> LBI.LocalBuildInfo -> PD.Benchmark@@ -123,6 +123,6 @@ fromPathTemplate $ substPathTemplate env template where env = initialPathTemplateEnv- (PD.package pkg_descr) (compilerId $ LBI.compiler lbi)- (LBI.hostPlatform lbi) +++ (PD.package pkg_descr) (LBI.pkgKey lbi)+ (compilerInfo $ LBI.compiler lbi) (LBI.hostPlatform lbi) ++ [(BenchmarkNameVar, toPathTemplate $ PD.benchmarkName bm)]
Distribution/Simple/Build.hs view
@@ -23,12 +23,11 @@ writeAutogenFiles, ) where -import qualified Distribution.Simple.GHC as GHC-import qualified Distribution.Simple.JHC as JHC-import qualified Distribution.Simple.LHC as LHC-import qualified Distribution.Simple.NHC as NHC-import qualified Distribution.Simple.Hugs as Hugs-import qualified Distribution.Simple.UHC as UHC+import qualified Distribution.Simple.GHC as GHC+import qualified Distribution.Simple.GHCJS as GHCJS+import qualified Distribution.Simple.JHC as JHC+import qualified Distribution.Simple.LHC as LHC+import qualified Distribution.Simple.UHC as UHC import qualified Distribution.Simple.HaskellSuite as HaskellSuite import qualified Distribution.Simple.Build.Macros as Build.Macros@@ -36,14 +35,14 @@ import Distribution.Package ( Package(..), PackageName(..), PackageIdentifier(..)- , Dependency(..), thisPackageVersion )+ , Dependency(..), thisPackageVersion, mkPackageKey, packageName ) import Distribution.Simple.Compiler ( Compiler, CompilerFlavor(..), compilerFlavor- , PackageDB(..), PackageDBStack )+ , PackageDB(..), PackageDBStack, packageKeySupported ) import Distribution.PackageDescription ( PackageDescription(..), BuildInfo(..), Library(..), Executable(..) , TestSuite(..), TestSuiteInterface(..), Benchmark(..)- , BenchmarkInterface(..) )+ , BenchmarkInterface(..), defaultRenaming ) import qualified Distribution.InstalledPackageInfo as IPI import qualified Distribution.ModuleName as ModuleName import Distribution.ModuleName (ModuleName)@@ -55,7 +54,7 @@ import Distribution.Simple.PreProcess ( preprocessComponent, PPSuffixHandler ) import Distribution.Simple.LocalBuildInfo- ( LocalBuildInfo(compiler, buildDir, withPackageDB, withPrograms)+ ( LocalBuildInfo(compiler, buildDir, withPackageDB, withPrograms, pkgKey) , Component(..), componentName, getComponent, componentBuildInfo , ComponentLocalBuildInfo(..), pkgEnabledComponents , withComponentsInBuildOrder, componentsInBuildOrder@@ -64,6 +63,7 @@ , inplacePackageId, LibraryName(..) ) import Distribution.Simple.Program.Types import Distribution.Simple.Program.Db+import qualified Distribution.Simple.Program.HcPkg as HcPkg import Distribution.Simple.BuildPaths ( autogenModulesDir, autogenModuleName, cppHeaderName, exeExtension ) import Distribution.Simple.Register@@ -78,6 +78,7 @@ import Distribution.Text ( display ) +import qualified Data.Map as Map import Data.Maybe ( maybeToList ) import Data.Either@@ -89,7 +90,7 @@ import System.FilePath ( (</>), (<.>) ) import System.Directory- ( getCurrentDirectory )+ ( getCurrentDirectory, removeDirectoryRecursive, doesDirectoryExist ) -- ----------------------------------------------------------------------------- -- |Build the libraries and executables in this package.@@ -114,7 +115,7 @@ -- Only bother with this message if we're building the whole package setupMessage verbosity "Building" (packageId pkg_descr) - internalPackageDB <- createInternalPackageDB distPref+ internalPackageDB <- createInternalPackageDB verbosity lbi distPref withComponentsInBuildOrder pkg_descr lbi componentsToBuild $ \comp clbi -> let bi = componentBuildInfo comp@@ -151,7 +152,8 @@ initialBuildSteps distPref pkg_descr lbi verbosity - internalPackageDB <- createInternalPackageDB distPref+ internalPackageDB <- createInternalPackageDB verbosity lbi distPref+ let lbiForComponent comp lbi' = lbi' { withPackageDB = withPackageDB lbi ++ [internalPackageDB],@@ -178,8 +180,9 @@ startInterpreter :: Verbosity -> ProgramDb -> Compiler -> PackageDBStack -> IO () startInterpreter verbosity programDb comp packageDBs = case compilerFlavor comp of- GHC -> GHC.startInterpreter verbosity programDb comp packageDBs- _ -> die "A REPL is not supported with this compiler."+ GHC -> GHC.startInterpreter verbosity programDb comp packageDBs+ GHCJS -> GHCJS.startInterpreter verbosity programDb comp packageDBs+ _ -> die "A REPL is not supported with this compiler." buildComponent :: Verbosity -> Flag (Maybe Int)@@ -199,12 +202,11 @@ -- Register the library in-place, so exes can depend -- on internally defined libraries. pwd <- getCurrentDirectory- let installedPkgInfo =- (inplaceInstalledPackageInfo pwd distPref pkg_descr lib lbi clbi) {- -- The in place registration uses the "-inplace" suffix,- -- not an ABI hash.- IPI.installedPackageId = inplacePackageId (packageId installedPkgInfo)- }+ let -- The in place registration uses the "-inplace" suffix, not an ABI hash+ ipkgid = inplacePackageId (packageId installedPkgInfo)+ installedPkgInfo = inplaceInstalledPackageInfo pwd distPref pkg_descr+ ipkgid lib lbi clbi+ registerPackage verbosity installedPkgInfo pkg_descr lbi True -- True meaning in place (withPackageDB lbi)@@ -226,7 +228,7 @@ buildExe verbosity numJobs pkg_descr lbi exe clbi -buildComponent verbosity numJobs pkg_descr lbi suffixes+buildComponent verbosity numJobs pkg_descr lbi0 suffixes comp@(CTest test@TestSuite { testInterface = TestSuiteLibV09{} }) clbi -- This ComponentLocalBuildInfo corresponds to a detailed@@ -236,8 +238,8 @@ -- built. distPref = do pwd <- getCurrentDirectory- let (pkg, lib, libClbi, ipi, exe, exeClbi) =- testSuiteLibV09AsLibAndExe pkg_descr lbi test clbi distPref pwd+ let (pkg, lib, libClbi, lbi, ipi, exe, exeClbi) =+ testSuiteLibV09AsLibAndExe pkg_descr test clbi lbi0 distPref pwd preprocessComponent pkg_descr comp lbi False verbosity suffixes info verbosity $ "Building test suite " ++ testName test ++ "..." buildLib verbosity numJobs pkg lbi lib libClbi@@ -293,13 +295,13 @@ replExe verbosity pkg_descr lbi exe clbi -replComponent verbosity pkg_descr lbi suffixes+replComponent verbosity pkg_descr lbi0 suffixes comp@(CTest test@TestSuite { testInterface = TestSuiteLibV09{} }) clbi distPref = do pwd <- getCurrentDirectory- let (pkg, lib, libClbi, _, _, _) =- testSuiteLibV09AsLibAndExe pkg_descr lbi test clbi distPref pwd+ let (pkg, lib, libClbi, lbi, _, _, _) =+ testSuiteLibV09AsLibAndExe pkg_descr test clbi lbi0 distPref pwd preprocessComponent pkg_descr comp lbi False verbosity suffixes replLib verbosity pkg lbi lib libClbi @@ -339,29 +341,35 @@ -- | Translate a lib-style 'TestSuite' component into a lib + exe for building testSuiteLibV09AsLibAndExe :: PackageDescription- -> LocalBuildInfo -> TestSuite -> ComponentLocalBuildInfo+ -> LocalBuildInfo -> FilePath -> FilePath -> (PackageDescription, Library, ComponentLocalBuildInfo,+ LocalBuildInfo, IPI.InstalledPackageInfo_ ModuleName, Executable, ComponentLocalBuildInfo)-testSuiteLibV09AsLibAndExe pkg_descr lbi+testSuiteLibV09AsLibAndExe pkg_descr test@TestSuite { testInterface = TestSuiteLibV09 _ m }- clbi distPref pwd =- (pkg, lib, libClbi, ipi, exe, exeClbi)+ clbi lbi distPref pwd =+ (pkg, lib, libClbi, lbi', ipi, exe, exeClbi) where bi = testBuildInfo test lib = Library { exposedModules = [ m ],+ reexportedModules = [],+ requiredSignatures = [],+ exposedSignatures = [], libExposed = True, libBuildInfo = bi } libClbi = LibComponentLocalBuildInfo { componentPackageDeps = componentPackageDeps clbi+ , componentPackageRenaming = componentPackageRenaming clbi , componentLibraries = [LibraryName (testName test)]+ , componentExposedModules = [IPI.ExposedModule m Nothing Nothing] } pkg = pkg_descr { package = (package pkg_descr) {@@ -372,9 +380,16 @@ , testSuites = [] , library = Just lib }- ipi = (inplaceInstalledPackageInfo pwd distPref pkg lib lbi libClbi) {- IPI.installedPackageId = inplacePackageId $ packageId ipi- }+ -- Hack to make the library compile with the right package key.+ -- Probably the "right" way to do this is move this information to+ -- the ComponentLocalBuildInfo, but it seems odd that a single package+ -- can define multiple actual packages.+ lbi' = lbi {+ pkgKey = mkPackageKey (packageKeySupported (compiler lbi))+ (package pkg) [] []+ }+ ipkgid = inplacePackageId (packageId pkg)+ ipi = inplaceInstalledPackageInfo pwd distPref pkg ipkgid lib lbi libClbi testDir = buildDir lbi </> stubName test </> stubName test ++ "-tmp" testLibDep = thisPackageVersion $ package pkg@@ -384,7 +399,10 @@ buildInfo = (testBuildInfo test) { hsSourceDirs = [ testDir ], targetBuildDepends = testLibDep- : (targetBuildDepends $ testBuildInfo test)+ : (targetBuildDepends $ testBuildInfo test),+ targetBuildRenaming =+ Map.insert (packageName pkg) defaultRenaming+ (targetBuildRenaming $ testBuildInfo test) } } -- | The stub executable needs a new 'ComponentLocalBuildInfo'@@ -394,9 +412,12 @@ (IPI.installedPackageId ipi, packageId ipi) : (filter (\(_, x) -> let PackageName name = pkgName x in name == "Cabal" || name == "base")- (componentPackageDeps clbi))+ (componentPackageDeps clbi)),+ componentPackageRenaming =+ Map.insert (packageName ipi) defaultRenaming+ (componentPackageRenaming clbi) }-testSuiteLibV09AsLibAndExe _ _ TestSuite{} _ _ _ = error "testSuiteLibV09AsLibAndExe: wrong kind"+testSuiteLibV09AsLibAndExe _ TestSuite{} _ _ _ _ = error "testSuiteLibV09AsLibAndExe: wrong kind" -- | Translate a exe-style 'Benchmark' component into an exe for building@@ -412,18 +433,29 @@ buildInfo = benchmarkBuildInfo bm } exeClbi = ExeComponentLocalBuildInfo {- componentPackageDeps = componentPackageDeps clbi+ componentPackageDeps = componentPackageDeps clbi,+ componentPackageRenaming = componentPackageRenaming clbi } benchmarkExeV10asExe Benchmark{} _ = error "benchmarkExeV10asExe: wrong kind" -- | Initialize a new package db file for libraries defined -- internally to the package.-createInternalPackageDB :: FilePath -> IO PackageDB-createInternalPackageDB distPref = do- let dbFile = distPref </> "package.conf.inplace"- packageDB = SpecificPackageDB dbFile- writeFile dbFile "[]"- return packageDB+createInternalPackageDB :: Verbosity -> LocalBuildInfo -> FilePath+ -> IO PackageDB+createInternalPackageDB verbosity lbi distPref = do+ case compilerFlavor (compiler lbi) of+ GHC -> createWith $ GHC.hcPkgInfo (withPrograms lbi)+ GHCJS -> createWith $ GHCJS.hcPkgInfo (withPrograms lbi)+ LHC -> createWith $ LHC.hcPkgInfo (withPrograms lbi)+ _ -> return packageDB+ where+ dbDir = distPref </> "package.conf.inplace"+ packageDB = SpecificPackageDB dbDir+ createWith hpi = do+ exists <- doesDirectoryExist dbDir+ when exists $ removeDirectoryRecursive dbDir+ HcPkg.init hpi verbosity dbDir+ return packageDB addInternalBuildTools :: PackageDescription -> LocalBuildInfo -> BuildInfo -> ProgramDb -> ProgramDb@@ -448,12 +480,11 @@ -> Library -> ComponentLocalBuildInfo -> IO () buildLib verbosity numJobs pkg_descr lbi lib clbi = case compilerFlavor (compiler lbi) of- GHC -> GHC.buildLib verbosity numJobs pkg_descr lbi lib clbi- JHC -> JHC.buildLib verbosity pkg_descr lbi lib clbi- LHC -> LHC.buildLib verbosity pkg_descr lbi lib clbi- Hugs -> Hugs.buildLib verbosity pkg_descr lbi lib clbi- NHC -> NHC.buildLib verbosity pkg_descr lbi lib clbi- UHC -> UHC.buildLib verbosity pkg_descr lbi lib clbi+ GHC -> GHC.buildLib verbosity numJobs pkg_descr lbi lib clbi+ GHCJS -> GHCJS.buildLib verbosity numJobs pkg_descr lbi lib clbi+ JHC -> JHC.buildLib verbosity pkg_descr lbi lib clbi+ LHC -> LHC.buildLib verbosity pkg_descr lbi lib clbi+ UHC -> UHC.buildLib verbosity pkg_descr lbi lib clbi HaskellSuite {} -> HaskellSuite.buildLib verbosity pkg_descr lbi lib clbi _ -> die "Building is not supported with this compiler." @@ -462,14 +493,12 @@ -> Executable -> ComponentLocalBuildInfo -> IO () buildExe verbosity numJobs pkg_descr lbi exe clbi = case compilerFlavor (compiler lbi) of- GHC -> GHC.buildExe verbosity numJobs pkg_descr lbi exe clbi- JHC -> JHC.buildExe verbosity pkg_descr lbi exe clbi- LHC -> LHC.buildExe verbosity pkg_descr lbi exe clbi- Hugs -> Hugs.buildExe verbosity pkg_descr lbi exe clbi- NHC -> NHC.buildExe verbosity pkg_descr lbi exe clbi- UHC -> UHC.buildExe verbosity pkg_descr lbi exe clbi- _ -> die "Building is not supported with this compiler."-+ GHC -> GHC.buildExe verbosity numJobs pkg_descr lbi exe clbi+ GHCJS -> GHCJS.buildExe verbosity numJobs pkg_descr lbi exe clbi+ JHC -> JHC.buildExe verbosity pkg_descr lbi exe clbi+ LHC -> LHC.buildExe verbosity pkg_descr lbi exe clbi+ UHC -> UHC.buildExe verbosity pkg_descr lbi exe clbi+ _ -> die "Building is not supported with this compiler." replLib :: Verbosity -> PackageDescription -> LocalBuildInfo -> Library -> ComponentLocalBuildInfo -> IO ()@@ -477,15 +506,17 @@ case compilerFlavor (compiler lbi) of -- 'cabal repl' doesn't need to support 'ghc --make -j', so we just pass -- NoFlag as the numJobs parameter.- GHC -> GHC.replLib verbosity NoFlag pkg_descr lbi lib clbi- _ -> die "A REPL is not supported for this compiler."+ GHC -> GHC.replLib verbosity NoFlag pkg_descr lbi lib clbi+ GHCJS -> GHCJS.replLib verbosity NoFlag pkg_descr lbi lib clbi+ _ -> die "A REPL is not supported for this compiler." replExe :: Verbosity -> PackageDescription -> LocalBuildInfo -> Executable -> ComponentLocalBuildInfo -> IO () replExe verbosity pkg_descr lbi exe clbi = case compilerFlavor (compiler lbi) of- GHC -> GHC.replExe verbosity NoFlag pkg_descr lbi exe clbi- _ -> die "A REPL is not supported for this compiler."+ GHC -> GHC.replExe verbosity NoFlag pkg_descr lbi exe clbi+ GHCJS -> GHCJS.replExe verbosity NoFlag pkg_descr lbi exe clbi+ _ -> die "A REPL is not supported for this compiler." initialBuildSteps :: FilePath -- ^"dist" prefix
Distribution/Simple/Build/Macros.hs view
@@ -30,8 +30,10 @@ ( Version(versionBranch) ) import Distribution.PackageDescription ( PackageDescription )+import Distribution.Simple.Compiler+ ( packageKeySupported ) import Distribution.Simple.LocalBuildInfo- ( LocalBuildInfo(withPrograms), externalPackageDeps )+ ( LocalBuildInfo(compiler, pkgKey, withPrograms), externalPackageDeps ) import Distribution.Simple.Program.Db ( configuredPrograms ) import Distribution.Simple.Program.Types@@ -49,7 +51,8 @@ generate _pkg_descr lbi = "/* DO NOT EDIT: This file is automatically generated by Cabal */\n\n" ++ generatePackageVersionMacros (map snd (externalPackageDeps lbi)) ++- generateToolVersionMacros (configuredPrograms . withPrograms $ lbi)+ generateToolVersionMacros (configuredPrograms . withPrograms $ lbi) +++ generatePackageKeyMacro lbi -- | Helper function that generates just the @VERSION_pkg@ and @MIN_VERSION_pkg@ -- macros for a list of package ids (usually used with the specific deps of@@ -92,6 +95,14 @@ ] where (major1:major2:minor:_) = map show (versionBranch version ++ repeat 0)++-- | Generate the @CURRENT_PACKAGE_KEY@ definition for the package key+-- of the current package, if supported by the compiler+generatePackageKeyMacro :: LocalBuildInfo -> String+generatePackageKeyMacro lbi+ | packageKeySupported (compiler lbi) =+ "#define CURRENT_PACKAGE_KEY \"" ++ display (pkgKey lbi) ++ "\"\n\n"+ | otherwise = "" fixchar :: Char -> Char fixchar '-' = '_'
Distribution/Simple/Build/PathsModule.hs view
@@ -32,6 +32,8 @@ import Distribution.Simple.Setup ( CopyDest(NoCopyDest) ) import Distribution.Simple.BuildPaths ( autogenModuleName )+import Distribution.Simple.Utils+ ( shortRelativePath ) import Distribution.Text ( display ) import Distribution.Version@@ -49,7 +51,7 @@ generate :: PackageDescription -> LocalBuildInfo -> String generate pkg_descr lbi = let pragmas- | absolute || isHugs = ""+ | absolute = "" | supports_language_pragma = "{-# LANGUAGE ForeignFunctionInterface #-}\n" | otherwise =@@ -58,11 +60,15 @@ foreign_imports | absolute = ""- | isHugs = "import System.Environment\n" | otherwise = "import Foreign\n"++ "import Foreign.C\n" + reloc_imports+ | reloc =+ "import System.Environment (getExecutablePath)\n"+ | otherwise = ""+ header = pragmas++ "module " ++ display paths_modulename ++ " (\n"++@@ -75,15 +81,36 @@ "import qualified Control.Exception as Exception\n"++ "import Data.Version (Version(..))\n"++ "import System.Environment (getEnv)\n"+++ reloc_imports ++ "import Prelude\n"++ "\n"++ "catchIO :: IO a -> (Exception.IOException -> IO a) -> IO a\n"++ "catchIO = Exception.catch\n" ++ "\n"++- "\nversion :: Version"++- "\nversion = " ++ show (packageVersion pkg_descr)+ "version :: Version"+++ "\nversion = Version " ++ show branch ++ " " ++ show tags+ where Version branch tags = packageVersion pkg_descr body+ | reloc =+ "\n\nbindirrel :: FilePath\n" +++ "bindirrel = " ++ show flat_bindirreloc +++ "\n"+++ "\ngetBinDir, getLibDir, getDataDir, getLibexecDir, getSysconfDir :: IO FilePath\n"+++ "getBinDir = "++mkGetEnvOrReloc "bindir" flat_bindirreloc++"\n"+++ "getLibDir = "++mkGetEnvOrReloc "libdir" flat_libdirreloc++"\n"+++ "getDataDir = "++mkGetEnvOrReloc "datadir" flat_datadirreloc++"\n"+++ "getLibexecDir = "++mkGetEnvOrReloc "libexecdir" flat_libexecdirreloc++"\n"+++ "getSysconfDir = "++mkGetEnvOrReloc "sysconfdir" flat_sysconfdirreloc++"\n"+++ "\n"+++ "getDataFileName :: FilePath -> IO FilePath\n"+++ "getDataFileName name = do\n"+++ " dir <- getDataDir\n"+++ " return (dir `joinFileName` name)\n"+++ "\n"+++ get_prefix_reloc_stuff+++ "\n"+++ filename_stuff | absolute = "\nbindir, libdir, datadir, libexecdir, sysconfdir :: FilePath\n"++ "\nbindir = " ++ show flat_bindir ++@@ -143,13 +170,23 @@ libdir = flat_libdirrel, datadir = flat_datadirrel, libexecdir = flat_libexecdirrel,- sysconfdir = flat_sysconfdirrel,- progdir = flat_progdirrel+ sysconfdir = flat_sysconfdirrel } = prefixRelativeInstallDirs (packageId pkg_descr) lbi + flat_bindirreloc = shortRelativePath flat_prefix flat_bindir+ flat_libdirreloc = shortRelativePath flat_prefix flat_libdir+ flat_datadirreloc = shortRelativePath flat_prefix flat_datadir+ flat_libexecdirreloc = shortRelativePath flat_prefix flat_libexecdir+ flat_sysconfdirreloc = shortRelativePath flat_prefix flat_sysconfdir+ mkGetDir _ (Just dirrel) = "getPrefixDirRel " ++ show dirrel mkGetDir dir Nothing = "return " ++ show dir + mkGetEnvOrReloc var dirrel = "catchIO (getEnv \""++var'++"\")" +++ " (\\_ -> getPrefixDirReloc \"" ++ dirrel +++ "\")"+ where var' = pkgPathEnvVar pkg_descr var+ mkGetEnvOr var expr = "catchIO (getEnv \""++var'++"\")"++ " (\\_ -> "++expr++")" where var' = pkgPathEnvVar pkg_descr var@@ -158,30 +195,29 @@ absolute = hasLibs pkg_descr -- we can only make progs relocatable || isNothing flat_bindirrel -- if the bin dir is an absolute path- || (isHugs && isNothing flat_progdirrel) || not (supportsRelocatableProgs (compilerFlavor (compiler lbi))) - supportsRelocatableProgs Hugs = True+ reloc = relocatable lbi+ supportsRelocatableProgs GHC = case buildOS of Windows -> True _ -> False+ supportsRelocatableProgs GHCJS = case buildOS of+ Windows -> True+ _ -> False supportsRelocatableProgs _ = False paths_modulename = autogenModuleName pkg_descr - isHugs = compilerFlavor (compiler lbi) == Hugs- get_prefix_stuff- | isHugs = "progdirrel :: String\n"++- "progdirrel = "++show (fromJust flat_progdirrel)++"\n\n"++- get_prefix_hugs- | otherwise = get_prefix_win32 buildArch+ get_prefix_stuff = get_prefix_win32 buildArch path_sep = show [pathSeparator] supports_language_pragma =- compilerFlavor (compiler lbi) == GHC &&+ (compilerFlavor (compiler lbi) == GHC && (compilerVersion (compiler lbi)- `withinRange` orLaterVersion (Version [6,6,1] []))+ `withinRange` orLaterVersion (Version [6,6,1] []))) ||+ compilerFlavor (compiler lbi) == GHCJS -- | Generates the name of the environment variable controlling the path -- component of interest.@@ -196,6 +232,14 @@ fixchar '-' = '_' fixchar c = c +get_prefix_reloc_stuff :: String+get_prefix_reloc_stuff =+ "getPrefixDirReloc :: FilePath -> IO FilePath\n"+++ "getPrefixDirReloc dirRel = do\n"+++ " exePath <- getExecutablePath\n"+++ " let (bindir,_) = splitFileName exePath\n"+++ " return ((bindir `minusFileName` bindirrel) `joinFileName` dirRel)\n"+ get_prefix_win32 :: Arch -> String get_prefix_win32 arch = "getPrefixDirRel :: FilePath -> IO FilePath\n"++@@ -217,15 +261,6 @@ I386 -> "stdcall" X86_64 -> "ccall" _ -> error "win32 supported only with I386, X86_64"--get_prefix_hugs :: String-get_prefix_hugs =- "getPrefixDirRel :: FilePath -> IO FilePath\n"++- "getPrefixDirRel dirRel = do\n"++- " mainPath <- getProgName\n"++- " let (progPath,_) = splitFileName mainPath\n"++- " let (progdir,_) = splitFileName progPath\n"++- " return ((progdir `minusFileName` progdirrel) `joinFileName` dirRel)\n" filename_stuff :: String filename_stuff =
Distribution/Simple/BuildPaths.hs view
@@ -107,9 +107,8 @@ Windows -> "exe" _ -> "" --- ToDo: This should be determined via autoconf (AC_OBJEXT)--- | Extension for object files. For GHC and NHC the extension is @\"o\"@.--- Hugs uses either @\"o\"@ or @\"obj\"@ depending on the used C compiler.+-- TODO: This should be determined via autoconf (AC_OBJEXT)+-- | Extension for object files. For GHC the extension is @\"o\"@. objExtension :: String objExtension = "o"
Distribution/Simple/BuildTarget.hs view
@@ -426,7 +426,8 @@ cinfoSrcDirs :: [FilePath], cinfoModules :: [ModuleName], cinfoHsFiles :: [FilePath], -- other hs files (like main.hs)- cinfoCFiles :: [FilePath]+ cinfoCFiles :: [FilePath],+ cinfoJsFiles :: [FilePath] } type ComponentStringName = String@@ -439,7 +440,8 @@ cinfoSrcDirs = hsSourceDirs bi, cinfoModules = componentModules c, cinfoHsFiles = componentHsFiles c,- cinfoCFiles = cSources bi+ cinfoCFiles = cSources bi,+ cinfoJsFiles = jsSources bi } | c <- pkgComponents pkg , let bi = componentBuildInfo c ]@@ -658,12 +660,14 @@ , matchOtherFileRooted dirs hsFiles str ]) (msum [ matchModuleFileUnrooted ms str , matchOtherFileUnrooted hsFiles str- , matchOtherFileUnrooted cFiles str ]))+ , matchOtherFileUnrooted cFiles str+ , matchOtherFileUnrooted jsFiles str ])) where dirs = cinfoSrcDirs c ms = cinfoModules c hsFiles = cinfoHsFiles c cFiles = cinfoCFiles c+ jsFiles = cinfoJsFiles c -- utils
Distribution/Simple/Command.hs view
@@ -22,10 +22,14 @@ commandShowOptions, CommandParse(..), commandParseArgs,+ getNormalCommandDescriptions,+ helpCommandUI, -- ** Constructing commands ShowOrParseArgs(..),- makeCommand,+ usageDefault,+ usageAlternatives,+ mkCommandUI, hiddenCommand, -- ** Associating actions with commands@@ -66,7 +70,8 @@ import Distribution.ParseUtils import Distribution.ReadE import Distribution.Simple.Utils (die, intercalate)-import Text.PrettyPrint ( punctuate, cat, comma, text, empty)+import Text.PrettyPrint ( punctuate, cat, comma, text )+import Text.PrettyPrint as PP ( empty ) data CommandUI flags = CommandUI { -- | The name of the command as it would be entered on the command line.@@ -79,6 +84,8 @@ commandUsage :: String -> String, -- | Additional explanation of the command to use in help texts. commandDescription :: Maybe (String -> String),+ -- | Post-Usage notes and examples in help texts+ commandNotes :: Maybe (String -> String), -- | Initial \/ empty flags commandDefaultFlags :: flags, -- | All the Option fields for this command@@ -258,15 +265,15 @@ (cat . punctuate comma . map text . ppr) t OptArg _ _ _ _ _ ppr ->- case ppr t of [] -> empty+ case ppr t of [] -> PP.empty (Nothing : _) -> text "True" (Just a : _) -> text a ChoiceOpt alts ->- fromMaybe empty $ listToMaybe+ fromMaybe PP.empty $ listToMaybe [ text lf | (_,(_,lf:_), _,enabled) <- alts, enabled t] - BoolOpt _ _ _ _ enabled -> (maybe empty disp . enabled) t+ BoolOpt _ _ _ _ enabled -> (maybe PP.empty disp . enabled) t -- set :: LineNo -> String -> a -> ParseResult a set line val a =@@ -371,32 +378,55 @@ -- | The help text for this command with descriptions of all the options. commandHelp :: CommandUI flags -> String -> String commandHelp command pname =- commandUsage command pname- ++ (GetOpt.usageInfo ""- . addCommonFlags ShowArgs- $ commandGetOpts ShowArgs command)- ++ case commandDescription command of- Nothing -> ""- Just desc -> '\n': desc pname+ commandSynopsis command+ ++ "\n\n"+ ++ commandUsage command pname+ ++ ( case commandDescription command of+ Nothing -> ""+ Just desc -> '\n': desc pname)+ ++ "\n"+ ++ ( if cname == ""+ then "Global flags:"+ else "Flags for " ++ cname ++ ":" )+ ++ ( GetOpt.usageInfo ""+ . addCommonFlags ShowArgs+ $ commandGetOpts ShowArgs command )+ ++ ( case commandNotes command of+ Nothing -> ""+ Just notes -> '\n': notes pname)+ where cname = commandName command +-- | Default "usage" documentation text for commands.+usageDefault :: String -> String -> String+usageDefault name pname =+ "Usage: " ++ pname ++ " " ++ name ++ " [FLAGS]\n\n"+ ++ "Flags for " ++ name ++ ":"++-- | Create "usage" documentation from a list of parameter+-- configurations.+usageAlternatives :: String -> [String] -> String -> String+usageAlternatives name strs pname = unlines+ [ start ++ pname ++ " " ++ name ++ " " ++ s+ | let starts = "Usage: " : repeat " or: "+ , (start, s) <- zip starts strs+ ]+ -- | Make a Command from standard 'GetOpt' options.-makeCommand :: String -- ^ name- -> String -- ^ short description- -> Maybe (String -> String) -- ^ long description- -> flags -- ^ initial\/empty flags+mkCommandUI :: String -- ^ name+ -> String -- ^ synopsis+ -> [String] -- ^ usage alternatives+ -> flags -- ^ initial\/empty flags -> (ShowOrParseArgs -> [OptionField flags]) -- ^ options -> CommandUI flags-makeCommand name shortDesc longDesc defaultFlags options =- CommandUI {- commandName = name,- commandSynopsis = shortDesc,- commandDescription = longDesc,- commandUsage = usage,- commandDefaultFlags = defaultFlags,- commandOptions = options+mkCommandUI name synopsis usages flags options = CommandUI+ { commandName = name+ , commandSynopsis = synopsis+ , commandDescription = Nothing+ , commandNotes = Nothing+ , commandUsage = usageAlternatives name usages+ , commandDefaultFlags = flags+ , commandOptions = options }- where usage pname = "Usage: " ++ pname ++ " " ++ name ++ " [FLAGS]\n\n"- ++ "Flags for " ++ name ++ ":" -- | Common flags that apply to every command data CommonFlag = HelpFlag | ListOptionsFlag@@ -501,7 +531,7 @@ -> [String] -> CommandParse (a, CommandParse action) commandsRun globalCommand commands args =- case commandParseArgs globalCommand' True args of+ case commandParseArgs globalCommand True args of CommandHelp help -> CommandHelp help CommandList opts -> CommandList (opts ++ commandNames) CommandErrors errs -> CommandErrors errs@@ -522,25 +552,6 @@ ++ " (try --help)\n"] commands' = commands ++ [commandAddAction helpCommandUI undefined] commandNames = [ name | (Command name _ _ NormalCommand) <- commands' ]- globalCommand' = globalCommand {- commandUsage = \pname ->- (case commandUsage globalCommand pname of- "" -> ""- original -> original ++ "\n")- ++ "Usage: " ++ pname ++ " COMMAND [FLAGS]\n"- ++ " or: " ++ pname ++ " [GLOBAL FLAGS]\n\n"- ++ "Global flags:",- commandDescription = Just $ \pname ->- "Commands:\n"- ++ unlines [ " " ++ align name ++ " " ++ description- | Command name description _ NormalCommand <- commands' ]- ++ case commandDescription globalCommand of- Nothing -> ""- Just desc -> '\n': desc pname- }- where maxlen = maximum- [ length name | Command name _ _ NormalCommand <- commands' ]- align str = str ++ replicate (maxlen - length str) ' ' -- A bit of a hack: support "prog help" as a synonym of "prog --help" -- furthermore, support "prog help command" as "prog command --help"@@ -559,14 +570,7 @@ _ -> CommandHelp globalHelp _ -> badCommand name - where globalHelp = commandHelp globalCommand'- helpCommandUI =- (makeCommand "help" "Help about commands." Nothing () (const [])) {- commandUsage = \pname ->- "Usage: " ++ pname ++ " help [FLAGS]\n"- ++ " or: " ++ pname ++ " help COMMAND [FLAGS]\n\n"- ++ "Flags for help:"- }+ where globalHelp = commandHelp globalCommand -- | Utility function, many commands do not accept additional flags. This -- action fails with a helpful error message if the user supplies any extra.@@ -577,3 +581,17 @@ die $ "Unrecognised flags: " ++ intercalate ", " extraFlags --TODO: eliminate this function and turn it into a variant on commandAddAction -- instead like commandAddActionNoArgs that doesn't supply the [String]++-- | Helper function for creating globalCommand description+getNormalCommandDescriptions :: [Command action] -> [(String, String)]+getNormalCommandDescriptions cmds = + [ (name, description)+ | Command name description _ NormalCommand <- cmds ]++helpCommandUI :: CommandUI ()+helpCommandUI = mkCommandUI+ "help"+ "Help about commands."+ ["[FLAGS]", "COMMAND [FLAGS]"]+ ()+ (const [])
Distribution/Simple/Compiler.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE DeriveGeneric #-}+ ----------------------------------------------------------------------------- -- | -- Module : Distribution.Simple.Compiler@@ -22,7 +24,10 @@ -- * Haskell implementations module Distribution.Compiler, Compiler(..),- showCompilerId, compilerFlavor, compilerVersion,+ showCompilerId, showCompilerIdWithAbi,+ compilerFlavor, compilerVersion,+ compilerCompatVersion,+ compilerInfo, -- * Support for package databases PackageDB(..),@@ -35,13 +40,20 @@ OptimisationLevel(..), flagToOptimisationLevel, + -- * Support for debug info levels+ DebugInfoLevel(..),+ flagToDebugInfoLevel,+ -- * Support for language extensions Flag, languageToFlags, unsupportedLanguages, extensionsToFlags, unsupportedExtensions,- parmakeSupported+ parmakeSupported,+ reexportedModulesSupported,+ renamingPackageFlagsSupported,+ packageKeySupported ) where import Distribution.Compiler@@ -50,14 +62,20 @@ import Language.Haskell.Extension (Language(Haskell98), Extension) import Control.Monad (liftM)+import Data.Binary (Binary) import Data.List (nub) import qualified Data.Map as M (Map, lookup)-import Data.Maybe (catMaybes, isNothing)+import Data.Maybe (catMaybes, isNothing, listToMaybe)+import GHC.Generics (Generic) import System.Directory (canonicalizePath) data Compiler = Compiler { compilerId :: CompilerId, -- ^ Compiler flavour and version.+ compilerAbiTag :: AbiTag,+ -- ^ Tag for distinguishing incompatible ABI's on the same architecture/os.+ compilerCompat :: [CompilerId],+ -- ^ Other implementations that this compiler claims to be compatible with. compilerLanguages :: [(Language, Flag)], -- ^ Supported language standards. compilerExtensions :: [(Extension, Flag)],@@ -65,17 +83,39 @@ compilerProperties :: M.Map String String -- ^ A key-value map for properties not covered by the above fields. }- deriving (Show, Read)+ deriving (Generic, Show, Read) +instance Binary Compiler+ showCompilerId :: Compiler -> String showCompilerId = display . compilerId +showCompilerIdWithAbi :: Compiler -> String+showCompilerIdWithAbi comp =+ display (compilerId comp) +++ case compilerAbiTag comp of+ NoAbiTag -> []+ AbiTag xs -> '-':xs+ compilerFlavor :: Compiler -> CompilerFlavor compilerFlavor = (\(CompilerId f _) -> f) . compilerId compilerVersion :: Compiler -> Version compilerVersion = (\(CompilerId _ v) -> v) . compilerId +compilerCompatVersion :: CompilerFlavor -> Compiler -> Maybe Version+compilerCompatVersion flavor comp+ | compilerFlavor comp == flavor = Just (compilerVersion comp)+ | otherwise =+ listToMaybe [ v | CompilerId fl v <- compilerCompat comp, fl == flavor ]++compilerInfo :: Compiler -> CompilerInfo+compilerInfo c = CompilerInfo (compilerId c)+ (compilerAbiTag c)+ (Just . compilerCompat $ c)+ (Just . map fst . compilerLanguages $ c)+ (Just . map fst . compilerExtensions $ c)+ -- ------------------------------------------------------------ -- * Package databases -- ------------------------------------------------------------@@ -90,8 +130,10 @@ data PackageDB = GlobalPackageDB | UserPackageDB | SpecificPackageDB FilePath- deriving (Eq, Ord, Show, Read)+ deriving (Eq, Generic, Ord, Show, Read) +instance Binary PackageDB+ -- | We typically get packages from several databases, and stack them -- together. This type lets us be explicit about that stacking. For example -- typical stacks include:@@ -134,14 +176,16 @@ -- ------------------------------------------------------------ -- | Some compilers support optimising. Some have different levels.--- For compliers that do not the level is just capped to the level+-- For compilers that do not the level is just capped to the level -- they do support. -- data OptimisationLevel = NoOptimisation | NormalOptimisation | MaximumOptimisation- deriving (Eq, Show, Read, Enum, Bounded)+ deriving (Bounded, Enum, Eq, Generic, Read, Show) +instance Binary OptimisationLevel+ flagToOptimisationLevel :: Maybe String -> OptimisationLevel flagToOptimisationLevel Nothing = NormalOptimisation flagToOptimisationLevel (Just s) = case reads s of@@ -154,6 +198,33 @@ _ -> error $ "Can't parse optimisation level " ++ s -- ------------------------------------------------------------+-- * Debug info levels+-- ------------------------------------------------------------++-- | Some compilers support emitting debug info. Some have different+-- levels. For compilers that do not the level is just capped to the+-- level they do support.+--+data DebugInfoLevel = NoDebugInfo+ | MinimalDebugInfo+ | NormalDebugInfo+ | MaximalDebugInfo+ deriving (Bounded, Enum, Eq, Generic, Read, Show)++instance Binary DebugInfoLevel++flagToDebugInfoLevel :: Maybe String -> DebugInfoLevel+flagToDebugInfoLevel Nothing = NormalDebugInfo+flagToDebugInfoLevel (Just s) = case reads s of+ [(i, "")]+ | i >= fromEnum (minBound :: DebugInfoLevel)+ && i <= fromEnum (maxBound :: DebugInfoLevel)+ -> toEnum i+ | otherwise -> error $ "Bad debug info level: " ++ show i+ ++ ". Valid values are 0..3"+ _ -> error $ "Can't parse debug info level " ++ s++-- ------------------------------------------------------------ -- * Languages and Extensions -- ------------------------------------------------------------ @@ -189,9 +260,28 @@ -- | Does this compiler support parallel --make mode? parmakeSupported :: Compiler -> Bool-parmakeSupported comp =+parmakeSupported = ghcSupported "Support parallel --make"++-- | Does this compiler support reexported-modules?+reexportedModulesSupported :: Compiler -> Bool+reexportedModulesSupported = ghcSupported "Support reexported-modules"++-- | Does this compiler support thinning/renaming on package flags?+renamingPackageFlagsSupported :: Compiler -> Bool+renamingPackageFlagsSupported = ghcSupported "Support thinning and renaming package flags"++-- | Does this compiler support package keys?+packageKeySupported :: Compiler -> Bool+packageKeySupported = ghcSupported "Uses package keys"++-- | Utility function for GHC only features+ghcSupported :: String -> Compiler -> Bool+ghcSupported key comp = case compilerFlavor comp of- GHC -> case M.lookup "Support parallel --make" (compilerProperties comp) of- Just "YES" -> True- _ -> False- _ -> False+ GHC -> checkProp+ GHCJS -> checkProp+ _ -> False+ where checkProp =+ case M.lookup key (compilerProperties comp) of+ Just "YES" -> True+ _ -> False
Distribution/Simple/Configure.hs view
@@ -1,3 +1,7 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+ ----------------------------------------------------------------------------- -- | -- Module : Distribution.Simple.Configure@@ -23,6 +27,7 @@ module Distribution.Simple.Configure (configure, writePersistBuildConfig,+ getConfigStateFile, getPersistBuildConfig, checkPersistBuildConfigOutdated, tryGetPersistBuildConfig,@@ -34,9 +39,7 @@ ccLdOptionsBuildInfo, checkForeignDeps, interpretPackageDbFlags,-- ConfigStateFileErrorType(..),- ConfigStateFileError,+ ConfigStateFileError(..), tryGetConfigStateFile, platformDefines, )@@ -44,41 +47,47 @@ import Distribution.Compiler ( CompilerId(..) )+import Distribution.Utils.NubList import Distribution.Simple.Compiler- ( CompilerFlavor(..), Compiler(compilerId), compilerFlavor, compilerVersion+ ( CompilerFlavor(..), Compiler(..), compilerFlavor, compilerVersion+ , compilerInfo , showCompilerId, unsupportedLanguages, unsupportedExtensions- , PackageDB(..), PackageDBStack )+ , PackageDB(..), PackageDBStack, reexportedModulesSupported+ , packageKeySupported, renamingPackageFlagsSupported ) import Distribution.Simple.PreProcess ( platformDefines ) import Distribution.Package ( PackageName(PackageName), PackageIdentifier(..), PackageId , packageName, packageVersion, Package(..) , Dependency(Dependency), simplifyDependency- , InstalledPackageId(..), thisPackageVersion )-import Distribution.InstalledPackageInfo as Installed- ( InstalledPackageInfo, InstalledPackageInfo_(..)- , emptyInstalledPackageInfo )+ , InstalledPackageId(..), thisPackageVersion+ , mkPackageKey, PackageKey(..) )+import qualified Distribution.InstalledPackageInfo as Installed+import Distribution.InstalledPackageInfo (InstalledPackageInfo, emptyInstalledPackageInfo) import qualified Distribution.Simple.PackageIndex as PackageIndex-import Distribution.Simple.PackageIndex (PackageIndex)+import Distribution.Simple.PackageIndex (InstalledPackageIndex) import Distribution.PackageDescription as PD ( PackageDescription(..), specVersion, GenericPackageDescription(..) , Library(..), hasLibs, Executable(..), BuildInfo(..), allExtensions , HookedBuildInfo, updatePackageDescription, allBuildInfo- , Flag(flagName), FlagName(..), TestSuite(..), Benchmark(..) )+ , Flag(flagName), FlagName(..), TestSuite(..), Benchmark(..)+ , ModuleReexport(..) , defaultRenaming )+import Distribution.ModuleName+ ( ModuleName ) import Distribution.PackageDescription.Configuration ( finalizePackageDescription, mapTreeData ) import Distribution.PackageDescription.Check ( PackageCheck(..), checkPackage, checkPackageFiles )-import Distribution.Simple.Hpc ( enableCoverage ) import Distribution.Simple.Program ( Program(..), ProgramLocation(..), ConfiguredProgram(..) , ProgramConfiguration, defaultProgramConfiguration , ProgramSearchPathEntry(..), getProgramSearchPath, setProgramSearchPath , configureAllKnownPrograms, knownPrograms, lookupKnownProgram , userSpecifyArgss, userSpecifyPaths- , requireProgram, requireProgramVersion+ , lookupProgram, requireProgram, requireProgramVersion , pkgConfigProgram, gccProgram, rawSystemProgramStdoutConf ) import Distribution.Simple.Setup- ( ConfigFlags(..), CopyDest(..), fromFlag, fromFlagOrDefault, flagToMaybe )+ ( ConfigFlags(..), CopyDest(..), Flag(..), fromFlag, fromFlagOrDefault+ , flagToMaybe ) import Distribution.Simple.InstallDirs ( InstallDirs(..), defaultInstallDirs, combineInstallDirs ) import Distribution.Simple.LocalBuildInfo@@ -93,33 +102,46 @@ ( die, warn, info, setupMessage , createDirectoryIfMissingVerbose, moreRecentFile , intercalate, cabalVersion- , withFileContents, writeFileAtomic+ , writeFileAtomic , withTempFile ) import Distribution.System- ( OS(..), buildOS, Platform, buildPlatform )+ ( OS(..), buildOS, Platform (..), buildPlatform ) import Distribution.Version ( Version(..), anyVersion, orLaterVersion, withinRange, isAnyVersion ) import Distribution.Verbosity ( Verbosity, lessVerbose ) -import qualified Distribution.Simple.GHC as GHC-import qualified Distribution.Simple.JHC as JHC-import qualified Distribution.Simple.LHC as LHC-import qualified Distribution.Simple.NHC as NHC-import qualified Distribution.Simple.Hugs as Hugs-import qualified Distribution.Simple.UHC as UHC+import qualified Distribution.Simple.GHC as GHC+import qualified Distribution.Simple.GHCJS as GHCJS+import qualified Distribution.Simple.JHC as JHC+import qualified Distribution.Simple.LHC as LHC+import qualified Distribution.Simple.UHC as UHC import qualified Distribution.Simple.HaskellSuite as HaskellSuite +-- Prefer the more generic Data.Traversable.mapM to Prelude.mapM+import Prelude hiding ( mapM )+import Control.Exception+ ( ErrorCall(..), Exception, evaluate, throw, throwIO, try ) import Control.Monad- ( when, unless, foldM, filterM )+ ( liftM, when, unless, foldM, filterM )+import Data.Binary ( decodeOrFail, encode )+import Data.ByteString.Lazy (ByteString)+import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy.Char8 as BLC8 import Data.List- ( (\\), nub, partition, isPrefixOf, inits )+ ( (\\), nub, partition, isPrefixOf, inits, stripPrefix ) import Data.Maybe- ( isNothing, catMaybes, fromMaybe )+ ( isNothing, catMaybes, fromMaybe, isJust )+import Data.Either+ ( partitionEithers )+import qualified Data.Set as Set import Data.Monoid ( Monoid(..) ) import qualified Data.Map as Map import Data.Map (Map)+import Data.Traversable+ ( mapM )+import Data.Typeable import System.Directory ( doesFileExist, createDirectoryIfMissing, getTemporaryDirectory ) import System.FilePath@@ -135,90 +157,97 @@ , quotes, punctuate, nest, sep, hsep ) import Distribution.Compat.Exception ( catchExit, catchIO ) -import qualified Data.ByteString.Lazy.Char8 as BS.Char8+data ConfigStateFileError+ = ConfigStateFileNoHeader+ | ConfigStateFileBadHeader+ | ConfigStateFileNoParse+ | ConfigStateFileMissing+ | ConfigStateFileBadVersion PackageIdentifier PackageIdentifier (Either ConfigStateFileError LocalBuildInfo)+ deriving (Typeable) -data ConfigStateFileErrorType = ConfigStateFileCantParse- | ConfigStateFileMissing- | ConfigStateFileBadVersion- deriving Eq-type ConfigStateFileError = (String, ConfigStateFileErrorType)+instance Show ConfigStateFileError where+ show ConfigStateFileNoHeader =+ "Saved package config file header is missing. "+ ++ "Try re-running the 'configure' command."+ show ConfigStateFileBadHeader =+ "Saved package config file header is corrupt. "+ ++ "Try re-running the 'configure' command."+ show ConfigStateFileNoParse =+ "Saved package config file body is corrupt. "+ ++ "Try re-running the 'configure' command."+ show ConfigStateFileMissing = "Run the 'configure' command first."+ show (ConfigStateFileBadVersion oldCabal oldCompiler _) =+ "You need to re-run the 'configure' command. "+ ++ "The version of Cabal being used has changed (was "+ ++ display oldCabal ++ ", now "+ ++ display currentCabalId ++ ")."+ ++ badCompiler+ where+ badCompiler+ | oldCompiler == currentCompilerId = ""+ | otherwise =+ " Additionally the compiler is different (was "+ ++ display oldCompiler ++ ", now "+ ++ display currentCompilerId+ ++ ") which is probably the cause of the problem." -tryGetConfigStateFile :: (Read a) => FilePath- -> IO (Either ConfigStateFileError a)-tryGetConfigStateFile filename = do- exists <- doesFileExist filename- if not exists- then return (Left (missing, ConfigStateFileMissing))- else withFileContents filename $ \str ->- case lines str of- [header, rest] -> case checkHeader header of- Just err -> return (Left err)- Nothing -> case reads rest of- [(bi,_)] -> return (Right bi)- _ -> return (Left (cantParse, ConfigStateFileCantParse))- _ -> return (Left (cantParse, ConfigStateFileCantParse))- where- checkHeader :: String -> Maybe ConfigStateFileError- checkHeader header = case parseHeader header of- Just (cabalId, compId)- | cabalId- == currentCabalId -> Nothing- | otherwise -> Just (badVersion cabalId compId- ,ConfigStateFileBadVersion)- Nothing -> Just (cantParse- ,ConfigStateFileCantParse)+instance Exception ConfigStateFileError - missing = "Run the 'configure' command first."- cantParse = "Saved package config file seems to be corrupt. "- ++ "Try re-running the 'configure' command."- badVersion cabalId compId- = "You need to re-run the 'configure' command. "- ++ "The version of Cabal being used has changed (was "- ++ display cabalId ++ ", now "- ++ display currentCabalId ++ ")."- ++ badcompiler compId- badcompiler compId | compId == currentCompilerId = ""- | otherwise- = " Additionally the compiler is different (was "- ++ display compId ++ ", now "- ++ display currentCompilerId- ++ ") which is probably the cause of the problem."+getConfigStateFile :: FilePath -> IO LocalBuildInfo+getConfigStateFile filename = do+ exists <- doesFileExist filename+ unless exists $ throwIO ConfigStateFileMissing+ -- Read the config file into a strict ByteString to avoid problems with+ -- lazy I/O, then convert to lazy because the binary package needs that.+ contents <- BS.readFile filename+ let (header, body) = BLC8.span (/='\n') (BLC8.fromChunks [contents]) + headerParseResult <- try $ evaluate $ parseHeader header+ let (cabalId, compId) =+ case headerParseResult of+ Left (ErrorCall _) -> throw ConfigStateFileBadHeader+ Right x -> x++ let getStoredValue = evaluate $+ case decodeOrFail (BLC8.tail body) of+ Left _ -> throw ConfigStateFileNoParse+ Right (_, _, x) -> x+ deferErrorIfBadVersion act+ | cabalId /= currentCabalId = do+ eResult <- try act+ throw $ ConfigStateFileBadVersion cabalId compId eResult+ | otherwise = act+ deferErrorIfBadVersion getStoredValue++tryGetConfigStateFile :: FilePath+ -> IO (Either ConfigStateFileError LocalBuildInfo)+tryGetConfigStateFile = try . getConfigStateFile+ -- |Try to read the 'localBuildInfoFile'. tryGetPersistBuildConfig :: FilePath- -> IO (Either ConfigStateFileError LocalBuildInfo)-tryGetPersistBuildConfig distPref- = tryGetConfigStateFile (localBuildInfoFile distPref)+ -> IO (Either ConfigStateFileError LocalBuildInfo)+tryGetPersistBuildConfig = try . getPersistBuildConfig --- |Read the 'localBuildInfoFile'. Error if it doesn't exist. Also--- fail if the file containing LocalBuildInfo is older than the .cabal--- file, indicating that a re-configure is required.+-- | Read the 'localBuildInfoFile'. Throw an exception if the file is+-- missing, if the file cannot be read, or if the file was created by an older+-- version of Cabal. getPersistBuildConfig :: FilePath -> IO LocalBuildInfo-getPersistBuildConfig distPref = do- lbi <- tryGetPersistBuildConfig distPref- either (die . fst) return lbi+getPersistBuildConfig = getConfigStateFile . localBuildInfoFile -- |Try to read the 'localBuildInfoFile'. maybeGetPersistBuildConfig :: FilePath -> IO (Maybe LocalBuildInfo)-maybeGetPersistBuildConfig distPref = do- lbi <- tryGetPersistBuildConfig distPref- return $ either (const Nothing) Just lbi+maybeGetPersistBuildConfig =+ liftM (either (const Nothing) Just) . tryGetPersistBuildConfig -- |After running configure, output the 'LocalBuildInfo' to the -- 'localBuildInfoFile'. writePersistBuildConfig :: FilePath -> LocalBuildInfo -> IO () writePersistBuildConfig distPref lbi = do- createDirectoryIfMissing False distPref- writeFileAtomic (localBuildInfoFile distPref)- (BS.Char8.pack $ showHeader pkgid ++ '\n' : show lbi)+ createDirectoryIfMissing False distPref+ writeFileAtomic (localBuildInfoFile distPref) $+ BLC8.unlines [showHeader pkgId, encode lbi] where- pkgid = packageId (localPkgDescr lbi)--showHeader :: PackageIdentifier -> String-showHeader pkgid =- "Saved package config for " ++ display pkgid- ++ " written by " ++ display currentCabalId- ++ " using " ++ display currentCompilerId+ pkgId = packageId $ localPkgDescr lbi currentCabalId :: PackageIdentifier currentCabalId = PackageIdentifier (PackageName "Cabal") cabalVersion@@ -227,19 +256,26 @@ currentCompilerId = PackageIdentifier (PackageName System.Info.compilerName) System.Info.compilerVersion -parseHeader :: String -> Maybe (PackageIdentifier, PackageIdentifier)-parseHeader header = case words header of- ["Saved", "package", "config", "for", pkgid,- "written", "by", cabalid, "using", compilerid]- -> case (simpleParse pkgid :: Maybe PackageIdentifier,- simpleParse cabalid,- simpleParse compilerid) of- (Just _,- Just cabalid',- Just compilerid') -> Just (cabalid', compilerid')- _ -> Nothing- _ -> Nothing+parseHeader :: ByteString -> (PackageIdentifier, PackageIdentifier)+parseHeader header = case BLC8.words header of+ ["Saved", "package", "config", "for", pkgId, "written", "by", cabalId, "using", compId] ->+ fromMaybe (throw ConfigStateFileBadHeader) $ do+ _ <- simpleParse (BLC8.unpack pkgId) :: Maybe PackageIdentifier+ cabalId' <- simpleParse (BLC8.unpack cabalId)+ compId' <- simpleParse (BLC8.unpack compId)+ return (cabalId', compId')+ _ -> throw ConfigStateFileNoHeader +showHeader :: PackageIdentifier -> ByteString+showHeader pkgId = BLC8.unwords+ [ "Saved", "package", "config", "for"+ , BLC8.pack $ display pkgId+ , "written", "by"+ , BLC8.pack $ display currentCabalId+ , "using"+ , BLC8.pack $ display currentCompilerId+ ]+ -- |Check that localBuildInfoFile is up-to-date with respect to the -- .cabal file. checkPersistBuildConfigOutdated :: FilePath -> FilePath -> IO Bool@@ -259,7 +295,13 @@ configure :: (GenericPackageDescription, HookedBuildInfo) -> ConfigFlags -> IO LocalBuildInfo configure (pkg_descr0, pbi) cfg- = do let distPref = fromFlag (configDistPref cfg)+ = do unless (configLibCoverage cfg == NoFlag) $ do+ let enable | fromFlag (configLibCoverage cfg) = "enable"+ | otherwise = "disable"+ die $ "Option --" ++ enable ++ "-library-coverage is obsolete! "+ ++ "Please use --" ++ enable ++ "-coverage instead."++ let distPref = fromFlag (configDistPref cfg) buildDir' = distPref </> "build" verbosity = fromFlag (configVerbosity cfg) @@ -353,7 +395,7 @@ (configConfigurationsFlags cfg) dependencySatisfiable compPlatform- (compilerId comp)+ (compilerInfo comp) allConstraints pkg_descr0'' of Right r -> return r@@ -376,18 +418,32 @@ -- add extra include/lib dirs as specified in cfg -- we do it here so that those get checked too- let pkg_descr =- enableCoverage (fromFlag (configLibCoverage cfg)) distPref- $ addExtraIncludeLibDirs pkg_descr0'+ let pkg_descr = addExtraIncludeLibDirs pkg_descr0' + unless (renamingPackageFlagsSupported comp ||+ and [ rn == defaultRenaming+ | bi <- allBuildInfo pkg_descr+ , rn <- Map.elems (targetBuildRenaming bi)]) $+ die $ "Your compiler does not support thinning and renaming on "+ ++ "package flags. To use this feature you probably must use "+ ++ "GHC 7.9 or later."+ when (not (null flags)) $ info verbosity $ "Flags chosen: " ++ intercalate ", " [ name ++ "=" ++ display value | (FlagName name, value) <- flags ] + when (maybe False (not.null.PD.reexportedModules) (PD.library pkg_descr)+ && not (reexportedModulesSupported comp)) $ do+ die $ "Your compiler does not support module re-exports. To use "+ ++ "this feature you probably must use GHC 7.9 or later."+ checkPackageProblems verbosity pkg_descr0 (updatePackageDescription pbi pkg_descr) + -- Handle hole instantiation+ (holeDeps, hole_insts) <- configureInstantiateWith pkg_descr cfg installedPackageSet+ let selectDependencies :: [Dependency] -> ([FailedDependency], [ResolvedDependency]) selectDependencies =@@ -414,9 +470,14 @@ reportFailedDependencies failedDeps reportSelectedDependencies verbosity allPkgDeps + let installDeps = Map.elems+ . Map.fromList+ . map (\v -> (Installed.installedPackageId v, v))+ $ externalPkgDeps ++ holeDeps+ packageDependsIndex <- case PackageIndex.dependencyClosure installedPackageSet- (map Installed.installedPackageId externalPkgDeps) of+ (map Installed.installedPackageId installDeps) of Left packageDependsIndex -> return packageDependsIndex Right broken -> die $ "The following installed packages are broken because other"@@ -433,7 +494,7 @@ InstalledPackageId (display (packageId pkg_descr)), Installed.sourcePackageId = packageId pkg_descr, Installed.depends =- map Installed.installedPackageId externalPkgDeps+ map Installed.installedPackageId installDeps } case PackageIndex.dependencyInconsistencies . PackageIndex.insert pseudoTopPkg@@ -448,12 +509,26 @@ | (name, uses) <- inconsistencies , (pkg, ver) <- uses ] + -- Calculate the package key. We're going to store it in LocalBuildInfo+ -- canonically, but ComponentsLocalBuildInfo also needs to know about it+ -- XXX Do we need the internal deps?+ -- NB: does *not* include holeDeps!+ let pkg_key = mkPackageKey (packageKeySupported comp)+ (package pkg_descr)+ (map Installed.packageKey externalPkgDeps)+ (map (\(k,(p,m)) -> (k,(Installed.packageKey p,m))) hole_insts)+ -- internal component graph buildComponents <-- case mkComponentsLocalBuildInfo pkg_descr- internalPkgDeps externalPkgDeps of+ case mkComponentsGraph pkg_descr internalPkgDeps of Left componentCycle -> reportComponentCycle componentCycle- Right components -> return components+ Right components ->+ case mkComponentsLocalBuildInfo packageDependsIndex pkg_descr+ internalPkgDeps externalPkgDeps holeDeps+ (Map.fromList hole_insts)+ pkg_key components of+ Left problems -> reportModuleReexportProblems problems+ Right components' -> return components' -- installation directories defaultDirs <- defaultInstallDirs flavor userInstall (hasLibs pkg_descr)@@ -504,19 +579,65 @@ then return False else case flavor of GHC | version >= Version [6,5] [] -> return True+ GHCJS -> return True _ -> do warn verbosity ("this compiler does not support " ++ "--enable-split-objs; ignoring") return False - let sharedLibsByDefault =+ let ghciLibByDefault = case compilerId comp of CompilerId GHC _ ->+ -- If ghc is non-dynamic, then ghci needs object files,+ -- so we build one by default.+ --+ -- Technically, archive files should be sufficient for ghci,+ -- but because of GHC bug #8942, it has never been safe to+ -- rely on them. By the time that bug was fixed, ghci had+ -- been changed to read shared libraries instead of archive+ -- files (see next code block).+ not (GHC.isDynamic comp)+ CompilerId GHCJS _ ->+ not (GHCJS.isDynamic comp)+ _ -> False++ let sharedLibsByDefault+ | fromFlag (configDynExe cfg) =+ -- build a shared library if dynamically-linked+ -- executables are requested+ True+ | otherwise = case compilerId comp of+ CompilerId GHC _ -> -- if ghc is dynamic, then ghci needs a shared -- library, so we build one by default.- GHC.ghcDynamic comp+ GHC.isDynamic comp+ CompilerId GHCJS _ ->+ GHCJS.isDynamic comp _ -> False+ withSharedLib_ =+ -- build shared libraries if required by GHC or by the+ -- executable linking mode, but allow the user to force+ -- building only static library archives with+ -- --disable-shared.+ fromFlagOrDefault sharedLibsByDefault $ configSharedLib cfg+ withDynExe_ = fromFlag $ configDynExe cfg+ when (withDynExe_ && not withSharedLib_) $ warn verbosity $+ "Executables will use dynamic linking, but a shared library "+ ++ "is not being built. Linking will fail if any executables "+ ++ "depend on the library." + let withProfExe_ = fromFlagOrDefault False $ configProfExe cfg+ withProfLib_ = fromFlagOrDefault withProfExe_ $ configProfLib cfg+ when (withProfExe_ && not withProfLib_) $ warn verbosity $+ "Executables will be built with profiling, but library "+ ++ "profiling is disabled. Linking will fail if any executables "+ ++ "depend on the library."++ reloc <-+ if not (fromFlag $ configRelocatable cfg)+ then return False+ else return True+ let lbi = LocalBuildInfo { configFlags = cfg, extraConfigArgs = [], -- Currently configure does not@@ -526,30 +647,33 @@ compiler = comp, hostPlatform = compPlatform, buildDir = buildDir',- scratchDir = fromFlagOrDefault- (distPref </> "scratch")- (configScratchDir cfg), componentsConfigs = buildComponents, installedPkgs = packageDependsIndex, pkgDescrFile = Nothing, localPkgDescr = pkg_descr',+ pkgKey = pkg_key,+ instantiatedWith = hole_insts, withPrograms = programsConfig''', withVanillaLib = fromFlag $ configVanillaLib cfg,- withProfLib = fromFlag $ configProfLib cfg,- withSharedLib = fromFlagOrDefault sharedLibsByDefault $- configSharedLib cfg,- withDynExe = fromFlag $ configDynExe cfg,- withProfExe = fromFlag $ configProfExe cfg,+ withProfLib = withProfLib_,+ withSharedLib = withSharedLib_,+ withDynExe = withDynExe_,+ withProfExe = withProfExe_, withOptimization = fromFlag $ configOptimization cfg,- withGHCiLib = fromFlag $ configGHCiLib cfg,+ withDebugInfo = fromFlag $ configDebugInfo cfg,+ withGHCiLib = fromFlagOrDefault ghciLibByDefault $+ configGHCiLib cfg, splitObjs = split_objs, stripExes = fromFlag $ configStripExes cfg, stripLibs = fromFlag $ configStripLibs cfg, withPackageDB = packageDbs, progPrefix = fromFlag $ configProgPrefix cfg,- progSuffix = fromFlag $ configProgSuffix cfg+ progSuffix = fromFlag $ configProgSuffix cfg,+ relocatable = reloc } + when reloc (checkRelocatable verbosity pkg_descr lbi)+ let dirs = absoluteInstallDirs pkg_descr lbi NoCopyDest relative = prefixRelativeInstallDirs (packageId pkg_descr) lbi @@ -601,7 +725,7 @@ . setProgramSearchPath searchpath $ initialProgramsConfig searchpath = getProgramSearchPath (initialProgramsConfig)- ++ map ProgramSearchPathDir (configProgramPathExtra cfg)+ ++ map ProgramSearchPathDir (fromNubList $ configProgramPathExtra cfg) -- ----------------------------------------------------------------------------- -- Configuring package dependencies@@ -623,14 +747,14 @@ data ResolvedDependency = ExternalDependency Dependency InstalledPackageInfo | InternalDependency Dependency PackageId -- should be a- -- lib name+ -- lib name data FailedDependency = DependencyNotExists PackageName | DependencyNoVersion Dependency -- | Test for a package dependency and record the version we have installed.-selectDependency :: PackageIndex -- ^ Internally defined packages- -> PackageIndex -- ^ Installed packages+selectDependency :: InstalledPackageIndex -- ^ Internally defined packages+ -> InstalledPackageIndex -- ^ Installed packages -> Map PackageName InstalledPackageInfo -- ^ Packages for which we have been given specific deps to use -> Dependency@@ -692,7 +816,7 @@ getInstalledPackages :: Verbosity -> Compiler -> PackageDBStack -> ProgramConfiguration- -> IO PackageIndex+ -> IO InstalledPackageIndex getInstalledPackages verbosity comp packageDBs progconf = do when (null packageDBs) $ die $ "No package databases have been specified. If you use "@@ -701,12 +825,11 @@ info verbosity "Reading installed packages..." case compilerFlavor comp of- GHC -> GHC.getInstalledPackages verbosity packageDBs progconf- Hugs->Hugs.getInstalledPackages verbosity packageDBs progconf- JHC -> JHC.getInstalledPackages verbosity packageDBs progconf- LHC -> LHC.getInstalledPackages verbosity packageDBs progconf- NHC -> NHC.getInstalledPackages verbosity packageDBs progconf- UHC -> UHC.getInstalledPackages verbosity comp packageDBs progconf+ GHC -> GHC.getInstalledPackages verbosity packageDBs progconf+ GHCJS -> GHCJS.getInstalledPackages verbosity packageDBs progconf+ JHC -> JHC.getInstalledPackages verbosity packageDBs progconf+ LHC -> LHC.getInstalledPackages verbosity packageDBs progconf+ UHC -> UHC.getInstalledPackages verbosity comp packageDBs progconf HaskellSuite {} -> HaskellSuite.getInstalledPackages verbosity packageDBs progconf flv -> die $ "don't know how to find the installed packages for "@@ -715,12 +838,12 @@ -- | Like 'getInstalledPackages', but for a single package DB. getPackageDBContents :: Verbosity -> Compiler -> PackageDB -> ProgramConfiguration- -> IO PackageIndex+ -> IO InstalledPackageIndex getPackageDBContents verbosity comp packageDB progconf = do info verbosity "Reading installed packages..." case compilerFlavor comp of GHC -> GHC.getPackageDBContents verbosity packageDB progconf-+ GHCJS -> GHCJS.getPackageDBContents verbosity packageDB progconf -- For other compilers, try to fall back on 'getInstalledPackages'. _ -> getInstalledPackages verbosity comp [packageDB] progconf @@ -742,8 +865,7 @@ extra dbs' (Just db:dbs) = extra (dbs' ++ [db]) dbs newPackageDepsBehaviourMinVersion :: Version-newPackageDepsBehaviourMinVersion = Version { versionBranch = [1,7,1],- versionTags = [] }+newPackageDepsBehaviourMinVersion = Version [1,7,1] [] -- In older cabal versions, there was only one set of package dependencies for -- the whole package. In this version, we can have separate dependencies per@@ -766,7 +888,7 @@ -- pick. combinedConstraints :: [Dependency] -> [(PackageName, InstalledPackageId)] ->- PackageIndex ->+ InstalledPackageIndex -> Either String ([Dependency], Map PackageName InstalledPackageInfo) combinedConstraints constraints dependencies installedPackages = do@@ -828,6 +950,58 @@ | (pkgname, ipkgid) <- deps ] -- -----------------------------------------------------------------------------+-- Configuring hole instantiation++configureInstantiateWith :: PackageDescription+ -> ConfigFlags+ -> InstalledPackageIndex -- ^ installed packages+ -> IO ([InstalledPackageInfo],+ [(ModuleName, (InstalledPackageInfo, ModuleName))])+configureInstantiateWith pkg_descr cfg installedPackageSet = do+ -- Holes: First, check and make sure the provided instantiation covers+ -- all the holes we know about. Indefinite package installation is+ -- not handled at all at this point.+ -- NB: We union together /all/ of the requirements when calculating+ -- the package key.+ -- NB: For now, we assume that dependencies don't contribute signatures.+ -- This will be handled by cabal-install; as far as ./Setup is+ -- concerned, the most important thing is to be provided correctly+ -- built dependencies.+ let signatures =+ maybe [] (\lib -> requiredSignatures lib ++ exposedSignatures lib)+ (PD.library pkg_descr)+ signatureSet = Set.fromList signatures+ instantiateMap = Map.fromList (configInstantiateWith cfg)+ missing_impls = filter (not . flip Map.member instantiateMap) signatures+ hole_insts0 = filter (\(k,_) -> Set.member k signatureSet) (configInstantiateWith cfg)++ when (not (null missing_impls)) $+ die $ "Missing signature implementations for these modules: "+ ++ intercalate ", " (map display missing_impls)++ -- Holes: Next, we need to make sure we have packages to actually+ -- provide the implementations we're talking about. This is on top+ -- of the normal dependency resolution process.+ -- TODO: internal dependencies (e.g. the test package depending on the+ -- main library) is not currently supported+ let selectHoleDependency (k,(i,m)) =+ case PackageIndex.lookupInstalledPackageId installedPackageSet i of+ Just pkginst -> Right (k,(pkginst, m))+ Nothing -> Left i+ (failed_hmap, hole_insts) = partitionEithers (map selectHoleDependency hole_insts0)+ holeDeps = map (fst.snd) hole_insts -- could have dups++ -- Holes: Finally, any dependencies selected this way have to be+ -- included in the allPkgs index, as well as the buildComponents.+ -- But don't report these as potential inconsistencies!++ when (not (null failed_hmap)) $+ die $ "Could not resolve these package IDs (from signature implementations): "+ ++ intercalate ", " (map display failed_hmap)++ return (holeDeps, hole_insts)++-- ----------------------------------------------------------------------------- -- Configuring program dependencies configureRequiredPrograms :: Verbosity -> [Dependency] -> ProgramConfiguration@@ -865,9 +1039,12 @@ (lessVerbose verbosity) pkgConfigProgram (orLaterVersion $ Version [0,9,0] []) conf mapM_ requirePkg allpkgs- lib' <- updateLibrary (library pkg_descr)- exes' <- mapM updateExecutable (executables pkg_descr)- let pkg_descr' = pkg_descr { library = lib', executables = exes' }+ lib' <- mapM addPkgConfigBILib (library pkg_descr)+ exes' <- mapM addPkgConfigBIExe (executables pkg_descr)+ tests' <- mapM addPkgConfigBITest (testSuites pkg_descr)+ benches' <- mapM addPkgConfigBIBench (benchmarks pkg_descr)+ let pkg_descr' = pkg_descr { library = lib', executables = exes',+ testSuites = tests', benchmarks = benches' } return (pkg_descr', conf') where@@ -898,15 +1075,27 @@ | isAnyVersion range = "" | otherwise = " version " ++ display range - updateLibrary Nothing = return Nothing- updateLibrary (Just lib) = do- bi <- pkgconfigBuildInfo (pkgconfigDepends (libBuildInfo lib))- return $ Just lib { libBuildInfo = libBuildInfo lib `mappend` bi }+ -- Adds pkgconfig dependencies to the build info for a component+ addPkgConfigBI compBI setCompBI comp = do+ bi <- pkgconfigBuildInfo (pkgconfigDepends (compBI comp))+ return $ setCompBI comp (compBI comp `mappend` bi) - updateExecutable exe = do- bi <- pkgconfigBuildInfo (pkgconfigDepends (buildInfo exe))- return exe { buildInfo = buildInfo exe `mappend` bi }+ -- Adds pkgconfig dependencies to the build info for a library+ addPkgConfigBILib = addPkgConfigBI libBuildInfo $+ \lib bi -> lib { libBuildInfo = bi } + -- Adds pkgconfig dependencies to the build info for an executable+ addPkgConfigBIExe = addPkgConfigBI buildInfo $+ \exe bi -> exe { buildInfo = bi }++ -- Adds pkgconfig dependencies to the build info for a test suite+ addPkgConfigBITest = addPkgConfigBI testBuildInfo $+ \test bi -> test { testBuildInfo = bi }++ -- Adds pkgconfig dependencies to the build info for a benchmark+ addPkgConfigBIBench = addPkgConfigBI benchmarkBuildInfo $+ \bench bi -> bench { benchmarkBuildInfo = bi }+ pkgconfigBuildInfo :: [Dependency] -> IO BuildInfo pkgconfigBuildInfo [] = return mempty pkgconfigBuildInfo pkgdeps = do@@ -957,13 +1146,12 @@ configCompilerEx Nothing _ _ _ _ = die "Unknown compiler" configCompilerEx (Just hcFlavor) hcPath hcPkg conf verbosity = do (comp, maybePlatform, programsConfig) <- case hcFlavor of- GHC -> GHC.configure verbosity hcPath hcPkg conf- JHC -> JHC.configure verbosity hcPath hcPkg conf- LHC -> do (_, _, ghcConf) <- GHC.configure verbosity Nothing hcPkg conf- LHC.configure verbosity hcPath Nothing ghcConf- Hugs -> Hugs.configure verbosity hcPath hcPkg conf- NHC -> NHC.configure verbosity hcPath hcPkg conf- UHC -> UHC.configure verbosity hcPath hcPkg conf+ GHC -> GHC.configure verbosity hcPath hcPkg conf+ GHCJS -> GHCJS.configure verbosity hcPath hcPkg conf+ JHC -> JHC.configure verbosity hcPath hcPkg conf+ LHC -> do (_, _, ghcConf) <- GHC.configure verbosity Nothing hcPkg conf+ LHC.configure verbosity hcPath Nothing ghcConf+ UHC -> UHC.configure verbosity hcPath hcPkg conf HaskellSuite {} -> HaskellSuite.configure verbosity hcPath hcPkg conf _ -> die "Unknown compiler" return (comp, fromMaybe buildPlatform maybePlatform, programsConfig)@@ -991,19 +1179,16 @@ -- Making the internal component graph -mkComponentsLocalBuildInfo :: PackageDescription- -> [PackageId] -> [InstalledPackageInfo]- -> Either [ComponentName]- [(ComponentName,- ComponentLocalBuildInfo, [ComponentName])]-mkComponentsLocalBuildInfo pkg_descr internalPkgDeps externalPkgDeps =+mkComponentsGraph :: PackageDescription+ -> [PackageId]+ -> Either [ComponentName]+ [(Component, [ComponentName])]+mkComponentsGraph pkg_descr internalPkgDeps = let graph = [ (c, componentName c, componentDeps c) | c <- pkgEnabledComponents pkg_descr ] in case checkComponentsCyclic graph of Just ccycle -> Left [ cname | (_,cname,_) <- ccycle ]- Nothing -> Right [ (cname, clbi, cdeps)- | (c, cname, cdeps) <- graph- , let clbi = componentLocalBuildInfo c ]+ Nothing -> Right [ (c, cdeps) | (c, _, cdeps) <- graph ] where -- The dependencies for the given component componentDeps component =@@ -1017,6 +1202,32 @@ where bi = componentBuildInfo component +reportComponentCycle :: [ComponentName] -> IO a+reportComponentCycle cnames =+ die $ "Components in the package depend on each other in a cyclic way:\n "+ ++ intercalate " depends on "+ [ "'" ++ showComponentName cname ++ "'"+ | cname <- cnames ++ [head cnames] ]++mkComponentsLocalBuildInfo :: InstalledPackageIndex+ -> PackageDescription+ -> [PackageId] -- internal package deps+ -> [InstalledPackageInfo] -- external package deps+ -> [InstalledPackageInfo] -- hole package deps+ -> Map ModuleName (InstalledPackageInfo, ModuleName)+ -> PackageKey+ -> [(Component, [ComponentName])]+ -> Either [(ModuleReexport, String)] -- errors+ [(ComponentName, ComponentLocalBuildInfo,+ [ComponentName])] -- ok+mkComponentsLocalBuildInfo installedPackages pkg_descr+ internalPkgDeps externalPkgDeps holePkgDeps hole_insts+ pkg_key graph =+ sequence+ [ do clbi <- componentLocalBuildInfo c+ return (componentName c, clbi, cdeps)+ | (c, cdeps) <- graph ]+ where -- The allPkgDeps contains all the package deps for the whole package -- but we need to select the subset for this specific component. -- we just take the subset for the package names this component@@ -1024,48 +1235,197 @@ -- versions of the same package. componentLocalBuildInfo component = case component of- CLib _ ->- LibComponentLocalBuildInfo {+ CLib lib -> do+ let exports = map (\n -> Installed.ExposedModule n Nothing Nothing)+ (PD.exposedModules lib)+ esigs = map (\n -> Installed.ExposedModule n Nothing+ (fmap (\(pkg,m) -> Installed.OriginalModule+ (Installed.installedPackageId pkg) m)+ (Map.lookup n hole_insts)))+ (PD.exposedSignatures lib)+ reexports <- resolveModuleReexports installedPackages+ (packageId pkg_descr)+ externalPkgDeps lib+ return LibComponentLocalBuildInfo { componentPackageDeps = cpds,- componentLibraries = [LibraryName- ("HS" ++ display (package pkg_descr))]+ componentLibraries = [LibraryName ("HS" ++ display pkg_key)],+ componentPackageRenaming = cprns,+ componentExposedModules = exports ++ reexports ++ esigs } CExe _ ->- ExeComponentLocalBuildInfo {- componentPackageDeps = cpds+ return ExeComponentLocalBuildInfo {+ componentPackageDeps = cpds,+ componentPackageRenaming = cprns } CTest _ ->- TestComponentLocalBuildInfo {- componentPackageDeps = cpds+ return TestComponentLocalBuildInfo {+ componentPackageDeps = cpds,+ componentPackageRenaming = cprns } CBench _ ->- BenchComponentLocalBuildInfo {- componentPackageDeps = cpds+ return BenchComponentLocalBuildInfo {+ componentPackageDeps = cpds,+ componentPackageRenaming = cprns } where bi = componentBuildInfo component+ dedup = Map.toList . Map.fromList cpds = if newPackageDepsBehaviour pkg_descr- then [ (installedPackageId pkg, packageId pkg)+ then dedup $+ [ (Installed.installedPackageId pkg, packageId pkg) | pkg <- selectSubset bi externalPkgDeps ] ++ [ (inplacePackageId pkgid, pkgid) | pkgid <- selectSubset bi internalPkgDeps ]- else [ (installedPackageId pkg, packageId pkg)+ ++ [ (Installed.installedPackageId pkg, packageId pkg)+ | pkg <- holePkgDeps ]+ else [ (Installed.installedPackageId pkg, packageId pkg) | pkg <- externalPkgDeps ]+ cprns = if newPackageDepsBehaviour pkg_descr+ then Map.unionWith mappend+ -- We need hole dependencies passed to GHC, so add them here+ -- (but note that they're fully thinned out. If they+ -- appeared legitimately the monoid instance will+ -- fill them out.+ (Map.fromList [(packageName pkg, mempty) | pkg <- holePkgDeps])+ (targetBuildRenaming bi)+ -- Hack: if we have old package-deps behavior, it's impossible+ -- for non-default renamings to be used, because the Cabal+ -- version is too early. This is a good, because while all the+ -- deps were bundled up in buildDepends, we didn't do this for+ -- renamings, so it's not even clear how to get the merged+ -- version. So just assume that all of them are the default..+ else Map.fromList (map (\(_,pid) -> (packageName pid, defaultRenaming)) cpds) selectSubset :: Package pkg => BuildInfo -> [pkg] -> [pkg] selectSubset bi pkgs =- [ pkg | pkg <- pkgs, packageName pkg `elem` names ]- where- names = [ name | Dependency name _ <- targetBuildDepends bi ]+ [ pkg | pkg <- pkgs, packageName pkg `elem` names bi ] -reportComponentCycle :: [ComponentName] -> IO a-reportComponentCycle cnames =- die $ "Components in the package depend on each other in a cyclic way:\n "- ++ intercalate " depends on "- [ "'" ++ showComponentName cname ++ "'"- | cname <- cnames ++ [head cnames] ]+ names bi = [ name | Dependency name _ <- targetBuildDepends bi ] +-- | Given the author-specified re-export declarations from the .cabal file,+-- resolve them to the form that we need for the package database.+--+-- An invariant of the package database is that we always link the re-export+-- directly to its original defining location (rather than indirectly via a+-- chain of re-exporting packages).+--+resolveModuleReexports :: InstalledPackageIndex+ -> PackageId+ -> [InstalledPackageInfo]+ -> Library+ -> Either [(ModuleReexport, String)] -- errors+ [Installed.ExposedModule] -- ok+resolveModuleReexports installedPackages srcpkgid externalPkgDeps lib =+ case partitionEithers (map resolveModuleReexport (PD.reexportedModules lib)) of+ ([], ok) -> Right ok+ (errs, _) -> Left errs+ where+ -- A mapping from visible module names to their original defining+ -- module name. We also record the package name of the package which+ -- *immediately* provided the module (not the original) to handle if the+ -- user explicitly says which build-depends they want to reexport from.+ visibleModules :: Map ModuleName [(PackageName, Installed.ExposedModule)]+ visibleModules =+ Map.fromListWith (++) $+ [ (Installed.exposedName exposedModule, [(exportingPackageName,+ exposedModule)])+ -- The package index here contains all the indirect deps of the+ -- package we're configuring, but we want just the direct deps+ | let directDeps = Set.fromList (map Installed.installedPackageId externalPkgDeps)+ , pkg <- PackageIndex.allPackages installedPackages+ , Installed.installedPackageId pkg `Set.member` directDeps+ , let exportingPackageName = packageName pkg+ , exposedModule <- visibleModuleDetails pkg+ ]+ ++ [ (visibleModuleName, [(exportingPackageName, exposedModule)])+ | visibleModuleName <- PD.exposedModules lib+ ++ otherModules (libBuildInfo lib)+ , let exportingPackageName = packageName srcpkgid+ definingModuleName = visibleModuleName+ -- we don't know the InstalledPackageId of this package yet+ -- we will fill it in later, before registration.+ definingPackageId = InstalledPackageId ""+ originalModule = Installed.OriginalModule definingPackageId+ definingModuleName+ exposedModule = Installed.ExposedModule visibleModuleName+ (Just originalModule)+ Nothing+ ] + -- All the modules exported from this package and their defining name and+ -- package (either defined here in this package or re-exported from some+ -- other package). Return an ExposedModule because we want to hold onto+ -- signature information.+ visibleModuleDetails :: InstalledPackageInfo -> [Installed.ExposedModule]+ visibleModuleDetails pkg = do+ exposedModule <- Installed.exposedModules pkg+ case Installed.exposedReexport exposedModule of+ -- The first case is the modules actually defined in this package.+ -- In this case the reexport will point to this package.+ Nothing -> return exposedModule { Installed.exposedReexport =+ Just (Installed.OriginalModule (Installed.installedPackageId pkg)+ (Installed.exposedName exposedModule)) }+ -- On the other hand, a visible module might actually be itself+ -- a re-export! In this case, the re-export info for the package+ -- doing the re-export will point us to the original defining+ -- module name and package, so we can reuse the entry.+ Just _ -> return exposedModule++ resolveModuleReexport reexport@ModuleReexport {+ moduleReexportOriginalPackage = moriginalPackageName,+ moduleReexportOriginalName = originalName,+ moduleReexportName = newName+ } =++ let filterForSpecificPackage =+ case moriginalPackageName of+ Nothing -> id+ Just originalPackageName ->+ filter (\(pkgname, _) -> pkgname == originalPackageName)++ matches = filterForSpecificPackage+ (Map.findWithDefault [] originalName visibleModules)+ in+ case (matches, moriginalPackageName) of+ ((_, exposedModule):rest, _)+ -- TODO: Refine this check for signatures+ | all (\(_, exposedModule') -> Installed.exposedReexport exposedModule+ == Installed.exposedReexport exposedModule') rest+ -> Right exposedModule { Installed.exposedName = newName }++ ([], Just originalPackageName)+ -> Left $ (,) reexport+ $ "The package " ++ display originalPackageName+ ++ " does not export a module " ++ display originalName++ ([], Nothing)+ -> Left $ (,) reexport+ $ "The module " ++ display originalName+ ++ " is not exported by any suitable package (this package "+ ++ "itself nor any of its 'build-depends' dependencies)."++ (ms, _)+ -> Left $ (,) reexport+ $ "The module " ++ display originalName ++ " is exported "+ ++ "by more than one package ("+ ++ intercalate ", " [ display pkgname | (pkgname,_) <- ms ]+ ++ ") and so the re-export is ambiguous. The ambiguity can "+ ++ "be resolved by qualifying by the package name. The "+ ++ "syntax is 'packagename:moduleName [as newname]'."++ -- Note: if in future Cabal allows directly depending on multiple+ -- instances of the same package (e.g. backpack) then an additional+ -- ambiguity case is possible here: (_, Just originalPackageName)+ -- with the module being ambigious despite being qualified by a+ -- package name. Presumably by that time we'll have a mechanism to+ -- qualify the instance we're referring to.++reportModuleReexportProblems :: [(ModuleReexport, String)] -> IO a+reportModuleReexportProblems reexportProblems =+ die $ unlines+ [ "Problem with the module re-export '" ++ display reexport ++ "': " ++ msg+ | (reexport, msg) <- reexportProblems ]+ -- ----------------------------------------------------------------------------- -- Testing C lib and header dependencies @@ -1159,11 +1519,20 @@ _ <- rawSystemProgramStdoutConf verbosity gccProgram (withPrograms lbi) (cName:"-o":oNname:args) return True- --TODO: need a better error in the case of not finding gcc! `catchIO` (\_ -> return False) `catchExit` (\_ -> return False) explainErrors Nothing [] = return () -- should be impossible!+ explainErrors _ _+ | isNothing . lookupProgram gccProgram . withPrograms $ lbi++ = die $ unlines $+ [ "No working gcc",+ "This package depends on foreign library but we cannot "+ ++ "find a working C compiler. If you have it in a "+ ++ "non-standard location you can use the --with-gcc "+ ++ "flag to specify it." ]+ explainErrors hdr libs = die $ unlines $ [ if plural then "Missing dependencies on foreign libraries:"@@ -1227,3 +1596,69 @@ if null errors then mapM_ (warn verbosity) warnings else die (intercalate "\n\n" errors)++-- | Preform checks if a relocatable build is allowed+checkRelocatable :: Verbosity+ -> PackageDescription+ -> LocalBuildInfo+ -> IO ()+checkRelocatable verbosity pkg lbi+ = sequence_ [ checkOS+ , checkCompiler+ , packagePrefixRelative+ , depsPrefixRelative+ ]+ where+ -- Check if the OS support relocatable builds.+ --+ -- If you add new OS' to this list, and your OS supports dynamic libraries+ -- and RPATH, make sure you add your OS to RPATH-support list of:+ -- Distribution.Simple.GHC.getRPaths+ checkOS+ = unless (os `elem` [ OSX, Linux ])+ $ die $ "Operating system: " ++ display os +++ ", does not support relocatable builds"+ where+ (Platform _ os) = hostPlatform lbi++ -- Check if the Compiler support relocatable builds+ checkCompiler+ = unless (compilerFlavor comp `elem` [ GHC ])+ $ die $ "Compiler: " ++ show comp +++ ", does not support relocatable builds"+ where+ comp = compiler lbi++ -- Check if all the install dirs are relative to same prefix+ packagePrefixRelative+ = unless (relativeInstallDirs installDirs)+ $ die $ "Installation directories are not prefix_relative:\n" +++ show installDirs+ where+ installDirs = absoluteInstallDirs pkg lbi NoCopyDest+ p = prefix installDirs+ relativeInstallDirs (InstallDirs {..}) =+ all isJust+ (fmap (stripPrefix p)+ [ bindir, libdir, dynlibdir, libexecdir, includedir, datadir+ , docdir, mandir, htmldir, haddockdir, sysconfdir] )++ -- Check if the library dirs of the dependencies that are in the package+ -- database to which the package is installed are relative to the+ -- prefix of the package+ depsPrefixRelative = do+ pkgr <- GHC.pkgRoot verbosity lbi (last (withPackageDB lbi))+ mapM_ (doCheck pkgr) ipkgs+ where+ doCheck pkgr ipkg+ | maybe False (== pkgr) (Installed.pkgRoot ipkg)+ = mapM_ (\l -> when (isNothing $ stripPrefix p l) (die (msg l)))+ (Installed.libraryDirs ipkg)+ | otherwise+ = return ()+ installDirs = absoluteInstallDirs pkg lbi NoCopyDest+ p = prefix installDirs+ ipkgs = PackageIndex.allPackages (installedPkgs lbi)+ msg l = "Library directory of a dependency: " ++ show l +++ "\nis not relative to the installation prefix:\n" +++ show p
Distribution/Simple/GHC.hs view
@@ -38,1316 +38,1049 @@ startInterpreter, installLib, installExe, libAbiHash,- initPackageDB,- invokeHcPkg,- registerPackage,- componentGhcOptions,- ghcLibDir,- ghcDynamic,- ghcGlobalPackageDB,- ) where--import qualified Distribution.Simple.GHC.IPI641 as IPI641-import qualified Distribution.Simple.GHC.IPI642 as IPI642-import Distribution.PackageDescription as PD- ( PackageDescription(..), BuildInfo(..), Executable(..)- , Library(..), libModules, exeModules, hcOptions- , usedExtensions, allExtensions )-import Distribution.InstalledPackageInfo- ( InstalledPackageInfo )-import qualified Distribution.InstalledPackageInfo as InstalledPackageInfo- ( InstalledPackageInfo_(..) )-import Distribution.Simple.PackageIndex (PackageIndex)-import qualified Distribution.Simple.PackageIndex as PackageIndex-import Distribution.Simple.LocalBuildInfo- ( LocalBuildInfo(..), ComponentLocalBuildInfo(..)- , LibraryName(..), absoluteInstallDirs )-import Distribution.Simple.InstallDirs hiding ( absoluteInstallDirs )-import Distribution.Simple.BuildPaths-import Distribution.Simple.Utils-import Distribution.Package- ( Package(..), PackageName(..) )-import qualified Distribution.ModuleName as ModuleName-import Distribution.Simple.Program- ( Program(..), ConfiguredProgram(..), ProgramConfiguration- , ProgramLocation(..), ProgramSearchPath, ProgramSearchPathEntry(..)- , rawSystemProgram- , rawSystemProgramStdout, rawSystemProgramStdoutConf- , getProgramOutput, getProgramInvocationOutput, suppressOverrideArgs- , requireProgramVersion, requireProgram- , userMaybeSpecifyPath, programPath, lookupProgram, addKnownProgram- , ghcProgram, ghcPkgProgram, hsc2hsProgram- , arProgram, ldProgram- , gccProgram, stripProgram )-import qualified Distribution.Simple.Program.HcPkg as HcPkg-import qualified Distribution.Simple.Program.Ar as Ar-import qualified Distribution.Simple.Program.Ld as Ld-import qualified Distribution.Simple.Program.Strip as Strip-import Distribution.Simple.Program.GHC-import Distribution.Simple.Setup- ( toFlag, fromFlag, fromFlagOrDefault )-import qualified Distribution.Simple.Setup as Cabal- ( Flag )-import Distribution.Simple.Compiler- ( CompilerFlavor(..), CompilerId(..), Compiler(..), compilerVersion- , OptimisationLevel(..), PackageDB(..), PackageDBStack- , Flag )-import Distribution.Version- ( Version(..), anyVersion, orLaterVersion )-import Distribution.System- ( Platform(..), OS(..), buildOS, platformFromTriple )-import Distribution.Verbosity-import Distribution.Text- ( display, simpleParse )-import Language.Haskell.Extension (Language(..), Extension(..)- ,KnownExtension(..))--import Control.Monad ( unless, when )-import Data.Char ( isSpace )-import Data.List-import qualified Data.Map as M ( Map, fromList, lookup )-import Data.Maybe ( catMaybes, fromMaybe, maybeToList )-import Data.Monoid ( Monoid(..) )-import System.Directory- ( getDirectoryContents, doesFileExist, getTemporaryDirectory )-import System.FilePath ( (</>), (<.>), takeExtension,- takeDirectory, replaceExtension,- splitExtension )-import System.IO (hClose, hPutStrLn)-import System.Environment (getEnv)-import Distribution.Compat.Exception (catchExit, catchIO)----- -------------------------------------------------------------------------------- Configuring--configure :: Verbosity -> Maybe FilePath -> Maybe FilePath- -> ProgramConfiguration- -> IO (Compiler, Maybe Platform, ProgramConfiguration)-configure verbosity hcPath hcPkgPath conf0 = do-- (ghcProg, ghcVersion, conf1) <-- requireProgramVersion verbosity ghcProgram- (orLaterVersion (Version [6,4] []))- (userMaybeSpecifyPath "ghc" hcPath conf0)-- -- This is slightly tricky, we have to configure ghc first, then we use the- -- location of ghc to help find ghc-pkg in the case that the user did not- -- specify the location of ghc-pkg directly:- (ghcPkgProg, ghcPkgVersion, conf2) <-- requireProgramVersion verbosity ghcPkgProgram {- programFindLocation = guessGhcPkgFromGhcPath ghcProg- }- anyVersion (userMaybeSpecifyPath "ghc-pkg" hcPkgPath conf1)-- when (ghcVersion /= ghcPkgVersion) $ die $- "Version mismatch between ghc and ghc-pkg: "- ++ programPath ghcProg ++ " is version " ++ display ghcVersion ++ " "- ++ programPath ghcPkgProg ++ " is version " ++ display ghcPkgVersion-- -- Likewise we try to find the matching hsc2hs program.- let hsc2hsProgram' = hsc2hsProgram {- programFindLocation = guessHsc2hsFromGhcPath ghcProg- }- conf3 = addKnownProgram hsc2hsProgram' conf2-- languages <- getLanguages verbosity ghcProg- extensions <- getExtensions verbosity ghcProg-- ghcInfo <- getGhcInfo verbosity ghcProg- let ghcInfoMap = M.fromList ghcInfo-- let comp = Compiler {- compilerId = CompilerId GHC ghcVersion,- compilerLanguages = languages,- compilerExtensions = extensions,- compilerProperties = ghcInfoMap- }- compPlatform = targetPlatform ghcInfo- conf4 = configureToolchain ghcProg ghcInfoMap conf3 -- configure gcc and ld- return (comp, compPlatform, conf4)--targetPlatform :: [(String, String)] -> Maybe Platform-targetPlatform ghcInfo = platformFromTriple =<< lookup "Target platform" ghcInfo---- | Given something like /usr/local/bin/ghc-6.6.1(.exe) we try and find--- the corresponding tool; e.g. if the tool is ghc-pkg, we try looking--- for a versioned or unversioned ghc-pkg in the same dir, that is:------ > /usr/local/bin/ghc-pkg-ghc-6.6.1(.exe)--- > /usr/local/bin/ghc-pkg-6.6.1(.exe)--- > /usr/local/bin/ghc-pkg(.exe)----guessToolFromGhcPath :: Program -> ConfiguredProgram- -> Verbosity -> ProgramSearchPath- -> IO (Maybe FilePath)-guessToolFromGhcPath tool ghcProg verbosity searchpath- = do let toolname = programName tool- path = programPath ghcProg- dir = takeDirectory path- versionSuffix = takeVersionSuffix (dropExeExtension path)- guessNormal = dir </> toolname <.> exeExtension- guessGhcVersioned = dir </> (toolname ++ "-ghc" ++ versionSuffix)- <.> exeExtension- guessVersioned = dir </> (toolname ++ versionSuffix)- <.> exeExtension- guesses | null versionSuffix = [guessNormal]- | otherwise = [guessGhcVersioned,- guessVersioned,- guessNormal]- info verbosity $ "looking for tool " ++ toolname- ++ " near compiler in " ++ dir- exists <- mapM doesFileExist guesses- case [ file | (file, True) <- zip guesses exists ] of- -- If we can't find it near ghc, fall back to the usual- -- method.- [] -> programFindLocation tool verbosity searchpath- (fp:_) -> do info verbosity $ "found " ++ toolname ++ " in " ++ fp- return (Just fp)-- where takeVersionSuffix :: FilePath -> String- takeVersionSuffix = reverse . takeWhile (`elem ` "0123456789.-") .- reverse-- dropExeExtension :: FilePath -> FilePath- dropExeExtension filepath =- case splitExtension filepath of- (filepath', extension) | extension == exeExtension -> filepath'- | otherwise -> filepath---- | Given something like /usr/local/bin/ghc-6.6.1(.exe) we try and find a--- corresponding ghc-pkg, we try looking for both a versioned and unversioned--- ghc-pkg in the same dir, that is:------ > /usr/local/bin/ghc-pkg-ghc-6.6.1(.exe)--- > /usr/local/bin/ghc-pkg-6.6.1(.exe)--- > /usr/local/bin/ghc-pkg(.exe)----guessGhcPkgFromGhcPath :: ConfiguredProgram- -> Verbosity -> ProgramSearchPath -> IO (Maybe FilePath)-guessGhcPkgFromGhcPath = guessToolFromGhcPath ghcPkgProgram---- | Given something like /usr/local/bin/ghc-6.6.1(.exe) we try and find a--- corresponding hsc2hs, we try looking for both a versioned and unversioned--- hsc2hs in the same dir, that is:------ > /usr/local/bin/hsc2hs-ghc-6.6.1(.exe)--- > /usr/local/bin/hsc2hs-6.6.1(.exe)--- > /usr/local/bin/hsc2hs(.exe)----guessHsc2hsFromGhcPath :: ConfiguredProgram- -> Verbosity -> ProgramSearchPath -> IO (Maybe FilePath)-guessHsc2hsFromGhcPath = guessToolFromGhcPath hsc2hsProgram---- | Adjust the way we find and configure gcc and ld----configureToolchain :: ConfiguredProgram -> M.Map String String- -> ProgramConfiguration- -> ProgramConfiguration-configureToolchain ghcProg ghcInfo =- addKnownProgram gccProgram {- programFindLocation = findProg gccProgram extraGccPath,- programPostConf = configureGcc- }- . addKnownProgram ldProgram {- programFindLocation = findProg ldProgram extraLdPath,- programPostConf = configureLd- }- . addKnownProgram arProgram {- programFindLocation = findProg arProgram extraArPath- }- . addKnownProgram stripProgram {- programFindLocation = findProg stripProgram extraStripPath- }- where- Just ghcVersion = programVersion ghcProg- compilerDir = takeDirectory (programPath ghcProg)- baseDir = takeDirectory compilerDir- mingwBinDir = baseDir </> "mingw" </> "bin"- libDir = baseDir </> "gcc-lib"- includeDir = baseDir </> "include" </> "mingw"- isWindows = case buildOS of Windows -> True; _ -> False- binPrefix = ""-- mkExtraPath :: Maybe FilePath -> FilePath -> [FilePath]- mkExtraPath mbPath mingwPath | isWindows = mbDir ++ [mingwPath]- | otherwise = mbDir- where- mbDir = maybeToList . fmap takeDirectory $ mbPath-- extraGccPath = mkExtraPath mbGccLocation windowsExtraGccDir- extraLdPath = mkExtraPath mbLdLocation windowsExtraLdDir- extraArPath = mkExtraPath mbArLocation windowsExtraArDir- extraStripPath = mkExtraPath mbStripLocation windowsExtraStripDir-- -- on Windows finding and configuring ghc's gcc & binutils is a bit special- windowsExtraGccDir- | ghcVersion >= Version [6,12] [] = mingwBinDir </> binPrefix- | otherwise = baseDir- windowsExtraLdDir- | ghcVersion >= Version [6,12] [] = mingwBinDir </> binPrefix- | otherwise = libDir- windowsExtraArDir- | ghcVersion >= Version [6,12] [] = mingwBinDir </> binPrefix- | otherwise = libDir- windowsExtraStripDir- | ghcVersion >= Version [6,12] [] = mingwBinDir </> binPrefix- | otherwise = libDir-- findProg :: Program -> [FilePath]- -> Verbosity -> ProgramSearchPath -> IO (Maybe FilePath)- findProg prog extraPath v searchpath =- programFindLocation prog v searchpath'- where- searchpath' = (map ProgramSearchPathDir extraPath) ++ searchpath-- -- Read tool locations from the 'ghc --info' output. Useful when- -- cross-compiling.- mbGccLocation = M.lookup "C compiler command" ghcInfo- mbLdLocation = M.lookup "ld command" ghcInfo- mbArLocation = M.lookup "ar command" ghcInfo- mbStripLocation = M.lookup "strip command" ghcInfo-- ccFlags = getFlags "C compiler flags"- gccLinkerFlags = getFlags "Gcc Linker flags"- ldLinkerFlags = getFlags "Ld Linker flags"-- getFlags key = case M.lookup key ghcInfo of- Nothing -> []- Just flags ->- case reads flags of- [(args, "")] -> args- _ -> [] -- XXX Should should be an error really-- configureGcc :: Verbosity -> ConfiguredProgram -> IO ConfiguredProgram- configureGcc v gccProg = do- gccProg' <- configureGcc' v gccProg- return gccProg' {- programDefaultArgs = programDefaultArgs gccProg'- ++ ccFlags ++ gccLinkerFlags- }-- configureGcc' :: Verbosity -> ConfiguredProgram -> IO ConfiguredProgram- configureGcc'- | isWindows = \_ gccProg -> case programLocation gccProg of- -- if it's found on system then it means we're using the result- -- of programFindLocation above rather than a user-supplied path- -- Pre GHC 6.12, that meant we should add these flags to tell- -- ghc's gcc where it lives and thus where gcc can find its- -- various files:- FoundOnSystem {}- | ghcVersion < Version [6,11] [] ->- return gccProg { programDefaultArgs = ["-B" ++ libDir,- "-I" ++ includeDir] }- _ -> return gccProg- | otherwise = \_ gccProg -> return gccProg-- configureLd :: Verbosity -> ConfiguredProgram -> IO ConfiguredProgram- configureLd v ldProg = do- ldProg' <- configureLd' v ldProg- return ldProg' {- programDefaultArgs = programDefaultArgs ldProg' ++ ldLinkerFlags- }-- -- we need to find out if ld supports the -x flag- configureLd' :: Verbosity -> ConfiguredProgram -> IO ConfiguredProgram- configureLd' verbosity ldProg = do- tempDir <- getTemporaryDirectory- ldx <- withTempFile tempDir ".c" $ \testcfile testchnd ->- withTempFile tempDir ".o" $ \testofile testohnd -> do- hPutStrLn testchnd "int foo() { return 0; }"- hClose testchnd; hClose testohnd- rawSystemProgram verbosity ghcProg ["-c", testcfile,- "-o", testofile]- withTempFile tempDir ".o" $ \testofile' testohnd' ->- do- hClose testohnd'- _ <- rawSystemProgramStdout verbosity ldProg- ["-x", "-r", testofile, "-o", testofile']- return True- `catchIO` (\_ -> return False)- `catchExit` (\_ -> return False)- if ldx- then return ldProg { programDefaultArgs = ["-x"] }- else return ldProg--getLanguages :: Verbosity -> ConfiguredProgram -> IO [(Language, Flag)]-getLanguages _ ghcProg- -- TODO: should be using --supported-languages rather than hard coding- | ghcVersion >= Version [7] [] = return [(Haskell98, "-XHaskell98")- ,(Haskell2010, "-XHaskell2010")]- | otherwise = return [(Haskell98, "")]- where- Just ghcVersion = programVersion ghcProg--getGhcInfo :: Verbosity -> ConfiguredProgram -> IO [(String, String)]-getGhcInfo verbosity ghcProg =- case programVersion ghcProg of- Just ghcVersion- | ghcVersion >= Version [6,7] [] ->- do xs <- getProgramOutput verbosity (suppressOverrideArgs ghcProg)- ["--info"]- case reads xs of- [(i, ss)]- | all isSpace ss ->- return i- _ ->- die "Can't parse --info output of GHC"- _ ->- return []--getExtensions :: Verbosity -> ConfiguredProgram -> IO [(Extension, Flag)]-getExtensions verbosity ghcProg- | ghcVersion >= Version [6,7] [] = do-- str <- getProgramOutput verbosity (suppressOverrideArgs ghcProg)- ["--supported-languages"]- let extStrs = if ghcVersion >= Version [7] []- then lines str- else -- Older GHCs only gave us either Foo or NoFoo,- -- so we have to work out the other one ourselves- [ extStr''- | extStr <- lines str- , let extStr' = case extStr of- 'N' : 'o' : xs -> xs- _ -> "No" ++ extStr- , extStr'' <- [extStr, extStr']- ]- let extensions0 = [ (ext, "-X" ++ display ext)- | Just ext <- map simpleParse extStrs ]- extensions1 = if ghcVersion >= Version [6,8] [] &&- ghcVersion < Version [6,10] []- then -- ghc-6.8 introduced RecordPuns however it- -- should have been NamedFieldPuns. We now- -- encourage packages to use NamedFieldPuns- -- so for compatibility we fake support for- -- it in ghc-6.8 by making it an alias for- -- the old RecordPuns extension.- (EnableExtension NamedFieldPuns, "-XRecordPuns") :- (DisableExtension NamedFieldPuns, "-XNoRecordPuns") :- extensions0- else extensions0- extensions2 = if ghcVersion < Version [7,1] []- then -- ghc-7.2 split NondecreasingIndentation off- -- into a proper extension. Before that it- -- was always on.- (EnableExtension NondecreasingIndentation, "") :- (DisableExtension NondecreasingIndentation, "") :- extensions1- else extensions1- return extensions2-- | otherwise = return oldLanguageExtensions-- where- Just ghcVersion = programVersion ghcProg---- | For GHC 6.6.x and earlier, the mapping from supported extensions to flags-oldLanguageExtensions :: [(Extension, Flag)]-oldLanguageExtensions =- let doFlag (f, (enable, disable)) = [(EnableExtension f, enable),- (DisableExtension f, disable)]- fglasgowExts = ("-fglasgow-exts",- "") -- This is wrong, but we don't want to turn- -- all the extensions off when asked to just- -- turn one off- fFlag flag = ("-f" ++ flag, "-fno-" ++ flag)- in concatMap doFlag- [(OverlappingInstances , fFlag "allow-overlapping-instances")- ,(TypeSynonymInstances , fglasgowExts)- ,(TemplateHaskell , fFlag "th")- ,(ForeignFunctionInterface , fFlag "ffi")- ,(MonomorphismRestriction , fFlag "monomorphism-restriction")- ,(MonoPatBinds , fFlag "mono-pat-binds")- ,(UndecidableInstances , fFlag "allow-undecidable-instances")- ,(IncoherentInstances , fFlag "allow-incoherent-instances")- ,(Arrows , fFlag "arrows")- ,(Generics , fFlag "generics")- ,(ImplicitPrelude , fFlag "implicit-prelude")- ,(ImplicitParams , fFlag "implicit-params")- ,(CPP , ("-cpp", ""{- Wrong -}))- ,(BangPatterns , fFlag "bang-patterns")- ,(KindSignatures , fglasgowExts)- ,(RecursiveDo , fglasgowExts)- ,(ParallelListComp , fglasgowExts)- ,(MultiParamTypeClasses , fglasgowExts)- ,(FunctionalDependencies , fglasgowExts)- ,(Rank2Types , fglasgowExts)- ,(RankNTypes , fglasgowExts)- ,(PolymorphicComponents , fglasgowExts)- ,(ExistentialQuantification , fglasgowExts)- ,(ScopedTypeVariables , fFlag "scoped-type-variables")- ,(FlexibleContexts , fglasgowExts)- ,(FlexibleInstances , fglasgowExts)- ,(EmptyDataDecls , fglasgowExts)- ,(PatternGuards , fglasgowExts)- ,(GeneralizedNewtypeDeriving , fglasgowExts)- ,(MagicHash , fglasgowExts)- ,(UnicodeSyntax , fglasgowExts)- ,(PatternSignatures , fglasgowExts)- ,(UnliftedFFITypes , fglasgowExts)- ,(LiberalTypeSynonyms , fglasgowExts)- ,(TypeOperators , fglasgowExts)- ,(GADTs , fglasgowExts)- ,(RelaxedPolyRec , fglasgowExts)- ,(ExtendedDefaultRules , fFlag "extended-default-rules")- ,(UnboxedTuples , fglasgowExts)- ,(DeriveDataTypeable , fglasgowExts)- ,(ConstrainedClassMethods , fglasgowExts)- ]--- | Given a single package DB, return all installed packages.-getPackageDBContents :: Verbosity -> PackageDB -> ProgramConfiguration- -> IO PackageIndex-getPackageDBContents verbosity packagedb conf = do- pkgss <- getInstalledPackages' verbosity [packagedb] conf- toPackageIndex verbosity pkgss conf---- | Given a package DB stack, return all installed packages.-getInstalledPackages :: Verbosity -> PackageDBStack -> ProgramConfiguration- -> IO PackageIndex-getInstalledPackages verbosity packagedbs conf = do- checkPackageDbEnvVar- checkPackageDbStack packagedbs- pkgss <- getInstalledPackages' verbosity packagedbs conf- index <- toPackageIndex verbosity pkgss conf- return $! hackRtsPackage index-- where- hackRtsPackage index =- case PackageIndex.lookupPackageName index (PackageName "rts") of- [(_,[rts])]- -> PackageIndex.insert (removeMingwIncludeDir rts) index- _ -> index -- No (or multiple) ghc rts package is registered!!- -- Feh, whatever, the ghc test suite does some crazy stuff.---- | Given a list of @(PackageDB, InstalledPackageInfo)@ pairs, produce a--- @PackageIndex@. Helper function used by 'getPackageDBContents' and--- 'getInstalledPackages'.-toPackageIndex :: Verbosity- -> [(PackageDB, [InstalledPackageInfo])]- -> ProgramConfiguration- -> IO PackageIndex-toPackageIndex verbosity pkgss conf = do- -- On Windows, various fields have $topdir/foo rather than full- -- paths. We need to substitute the right value in so that when- -- we, for example, call gcc, we have proper paths to give it.- topDir <- ghcLibDir' verbosity ghcProg- let indices = [ PackageIndex.fromList (map (substTopDir topDir) pkgs)- | (_, pkgs) <- pkgss ]- return $! (mconcat indices)-- where- Just ghcProg = lookupProgram ghcProgram conf--ghcLibDir :: Verbosity -> LocalBuildInfo -> IO FilePath-ghcLibDir verbosity lbi =- (reverse . dropWhile isSpace . reverse) `fmap`- rawSystemProgramStdoutConf verbosity ghcProgram- (withPrograms lbi) ["--print-libdir"]--ghcLibDir' :: Verbosity -> ConfiguredProgram -> IO FilePath-ghcLibDir' verbosity ghcProg =- (reverse . dropWhile isSpace . reverse) `fmap`- rawSystemProgramStdout verbosity ghcProg ["--print-libdir"]----- | Return the 'FilePath' to the global GHC package database.-ghcGlobalPackageDB :: Verbosity -> ConfiguredProgram -> IO FilePath-ghcGlobalPackageDB verbosity ghcProg =- (reverse . dropWhile isSpace . reverse) `fmap`- rawSystemProgramStdout verbosity ghcProg ["--print-global-package-db"]---- Cabal does not use the environment variable GHC_PACKAGE_PATH; let users--- know that this is the case. See ticket #335. Simply ignoring it is not a--- good idea, since then ghc and cabal are looking at different sets of--- package DBs and chaos is likely to ensue.-checkPackageDbEnvVar :: IO ()-checkPackageDbEnvVar = do- hasGPP <- (getEnv "GHC_PACKAGE_PATH" >> return True)- `catchIO` (\_ -> return False)- when hasGPP $- die $ "Use of GHC's environment variable GHC_PACKAGE_PATH is "- ++ "incompatible with Cabal. Use the flag --package-db to specify a "- ++ "package database (it can be used multiple times)."--checkPackageDbStack :: PackageDBStack -> IO ()-checkPackageDbStack (GlobalPackageDB:rest)- | GlobalPackageDB `notElem` rest = return ()-checkPackageDbStack rest- | GlobalPackageDB `notElem` rest =- die $ "With current ghc versions the global package db is always used "- ++ "and must be listed first. This ghc limitation may be lifted in "- ++ "future, see http://hackage.haskell.org/trac/ghc/ticket/5977"-checkPackageDbStack _ =- die $ "If the global package db is specified, it must be "- ++ "specified first and cannot be specified multiple times"---- GHC < 6.10 put "$topdir/include/mingw" in rts's installDirs. This--- breaks when you want to use a different gcc, so we need to filter--- it out.-removeMingwIncludeDir :: InstalledPackageInfo -> InstalledPackageInfo-removeMingwIncludeDir pkg =- let ids = InstalledPackageInfo.includeDirs pkg- ids' = filter (not . ("mingw" `isSuffixOf`)) ids- in pkg { InstalledPackageInfo.includeDirs = ids' }---- | Get the packages from specific PackageDBs, not cumulative.----getInstalledPackages' :: Verbosity -> [PackageDB] -> ProgramConfiguration- -> IO [(PackageDB, [InstalledPackageInfo])]-getInstalledPackages' verbosity packagedbs conf- | ghcVersion >= Version [6,9] [] =- sequence- [ do pkgs <- HcPkg.dump verbosity ghcPkgProg packagedb- return (packagedb, pkgs)- | packagedb <- packagedbs ]-- where- Just ghcPkgProg = lookupProgram ghcPkgProgram conf- Just ghcProg = lookupProgram ghcProgram conf- Just ghcVersion = programVersion ghcProg--getInstalledPackages' verbosity packagedbs conf = do- str <- rawSystemProgramStdoutConf verbosity ghcPkgProgram conf ["list"]- let pkgFiles = [ init line | line <- lines str, last line == ':' ]- dbFile packagedb = case (packagedb, pkgFiles) of- (GlobalPackageDB, global:_) -> return $ Just global- (UserPackageDB, _global:user:_) -> return $ Just user- (UserPackageDB, _global:_) -> return $ Nothing- (SpecificPackageDB specific, _) -> return $ Just specific- _ -> die "cannot read ghc-pkg package listing"- pkgFiles' <- mapM dbFile packagedbs- sequence [ withFileContents file $ \content -> do- pkgs <- readPackages file content- return (db, pkgs)- | (db , Just file) <- zip packagedbs pkgFiles' ]- where- -- Depending on the version of ghc we use a different type's Read- -- instance to parse the package file and then convert.- -- It's a bit yuck. But that's what we get for using Read/Show.- readPackages- | ghcVersion >= Version [6,4,2] []- = \file content -> case reads content of- [(pkgs, _)] -> return (map IPI642.toCurrent pkgs)- _ -> failToRead file- | otherwise- = \file content -> case reads content of- [(pkgs, _)] -> return (map IPI641.toCurrent pkgs)- _ -> failToRead file- Just ghcProg = lookupProgram ghcProgram conf- Just ghcVersion = programVersion ghcProg- failToRead file = die $ "cannot read ghc package database " ++ file--substTopDir :: FilePath -> InstalledPackageInfo -> InstalledPackageInfo-substTopDir topDir ipo- = ipo {- InstalledPackageInfo.importDirs- = map f (InstalledPackageInfo.importDirs ipo),- InstalledPackageInfo.libraryDirs- = map f (InstalledPackageInfo.libraryDirs ipo),- InstalledPackageInfo.includeDirs- = map f (InstalledPackageInfo.includeDirs ipo),- InstalledPackageInfo.frameworkDirs- = map f (InstalledPackageInfo.frameworkDirs ipo),- InstalledPackageInfo.haddockInterfaces- = map f (InstalledPackageInfo.haddockInterfaces ipo),- InstalledPackageInfo.haddockHTMLs- = map f (InstalledPackageInfo.haddockHTMLs ipo)- }- where f ('$':'t':'o':'p':'d':'i':'r':rest) = topDir ++ rest- f x = x---- -------------------------------------------------------------------------------- Building---- | Build a library with GHC.----buildLib, replLib :: Verbosity -> Cabal.Flag (Maybe Int)- -> PackageDescription -> LocalBuildInfo- -> Library -> ComponentLocalBuildInfo -> IO ()-buildLib = buildOrReplLib False-replLib = buildOrReplLib True--buildOrReplLib :: Bool -> Verbosity -> Cabal.Flag (Maybe Int)- -> PackageDescription -> LocalBuildInfo- -> Library -> ComponentLocalBuildInfo -> IO ()-buildOrReplLib forRepl verbosity numJobsFlag pkg_descr lbi lib clbi = do- libName <- case componentLibraries clbi of- [libName] -> return libName- [] -> die "No library name found when building library"- _ -> die "Multiple library names found when building library"-- let libTargetDir = buildDir lbi- numJobs = fromMaybe 1 $ fromFlagOrDefault Nothing numJobsFlag- pkgid = packageId pkg_descr- whenVanillaLib forceVanilla =- when (not forRepl && (forceVanilla || withVanillaLib lbi))- whenProfLib = when (not forRepl && withProfLib lbi)- whenSharedLib forceShared =- when (not forRepl && (forceShared || withSharedLib lbi))- whenGHCiLib = when (not forRepl && withGHCiLib lbi && withVanillaLib lbi)- ifReplLib = when forRepl- comp = compiler lbi- ghcVersion = compilerVersion comp- (Platform _hostArch hostOS) = hostPlatform lbi-- (ghcProg, _) <- requireProgram verbosity ghcProgram (withPrograms lbi)- let runGhcProg = runGHC verbosity ghcProg comp-- libBi <- hackThreadedFlag verbosity- comp (withProfLib lbi) (libBuildInfo lib)-- let isGhcDynamic = ghcDynamic comp- dynamicTooSupported = ghcSupportsDynamicToo comp- doingTH = EnableExtension TemplateHaskell `elem` allExtensions libBi- forceVanillaLib = doingTH && not isGhcDynamic- forceSharedLib = doingTH && isGhcDynamic- -- TH always needs default libs, even when building for profiling-- createDirectoryIfMissingVerbose verbosity True libTargetDir- -- TODO: do we need to put hs-boot files into place for mutually recursive- -- modules?- let cObjs = map (`replaceExtension` objExtension) (cSources libBi)- baseOpts = componentGhcOptions verbosity lbi libBi clbi libTargetDir- vanillaOpts = baseOpts `mappend` mempty {- ghcOptMode = toFlag GhcModeMake,- ghcOptNumJobs = toFlag numJobs,- ghcOptPackageName = toFlag pkgid,- ghcOptInputModules = libModules lib- }-- profOpts = vanillaOpts `mappend` mempty {- ghcOptProfilingMode = toFlag True,- ghcOptHiSuffix = toFlag "p_hi",- ghcOptObjSuffix = toFlag "p_o",- ghcOptExtra = ghcProfOptions libBi- }-- sharedOpts = vanillaOpts `mappend` mempty {- ghcOptDynLinkMode = toFlag GhcDynamicOnly,- ghcOptFPic = toFlag True,- ghcOptHiSuffix = toFlag "dyn_hi",- ghcOptObjSuffix = toFlag "dyn_o",- ghcOptExtra = ghcSharedOptions libBi- }- linkerOpts = mempty {- ghcOptLinkOptions = PD.ldOptions libBi,- ghcOptLinkLibs = extraLibs libBi,- ghcOptLinkLibPath = extraLibDirs libBi,- ghcOptLinkFrameworks = PD.frameworks libBi,- ghcOptInputFiles = [libTargetDir </> x | x <- cObjs]- }- replOpts = vanillaOpts {- ghcOptExtra = filterGhciFlags- (ghcOptExtra vanillaOpts),- ghcOptNumJobs = mempty- }- `mappend` linkerOpts- `mappend` mempty {- ghcOptMode = toFlag GhcModeInteractive,- ghcOptOptimisation = toFlag GhcNoOptimisation- }-- vanillaSharedOpts = vanillaOpts `mappend` mempty {- ghcOptDynLinkMode = toFlag GhcStaticAndDynamic,- ghcOptDynHiSuffix = toFlag "dyn_hi",- ghcOptDynObjSuffix = toFlag "dyn_o"- }-- unless (null (libModules lib)) $- do let vanilla = whenVanillaLib forceVanillaLib (runGhcProg vanillaOpts)- shared = whenSharedLib forceSharedLib (runGhcProg sharedOpts)- useDynToo = dynamicTooSupported &&- (forceVanillaLib || withVanillaLib lbi) &&- (forceSharedLib || withSharedLib lbi) &&- null (ghcSharedOptions libBi)- if useDynToo- then runGhcProg vanillaSharedOpts- else if isGhcDynamic then do shared; vanilla- else do vanilla; shared- whenProfLib (runGhcProg profOpts)-- -- build any C sources- unless (null (cSources libBi)) $ do- info verbosity "Building C Sources..."- sequence_- [ do let baseCcOpts = componentCcGhcOptions verbosity lbi- libBi clbi libTargetDir filename- vanillaCcOpts = if isGhcDynamic- -- Dynamic GHC requires C sources to be built- -- with -fPIC for REPL to work. See #2207.- then baseCcOpts { ghcOptFPic = toFlag True }- else baseCcOpts- profCcOpts = vanillaCcOpts `mappend` mempty {- ghcOptProfilingMode = toFlag True,- ghcOptObjSuffix = toFlag "p_o"- }- sharedCcOpts = vanillaCcOpts `mappend` mempty {- ghcOptFPic = toFlag True,- ghcOptDynLinkMode = toFlag GhcDynamicOnly,- ghcOptObjSuffix = toFlag "dyn_o"- }- odir = fromFlag (ghcOptObjDir vanillaCcOpts)- createDirectoryIfMissingVerbose verbosity True odir- runGhcProg vanillaCcOpts- whenSharedLib forceSharedLib (runGhcProg sharedCcOpts)- whenProfLib (runGhcProg profCcOpts)- | filename <- cSources libBi]-- -- TODO: problem here is we need the .c files built first, so we can load them- -- with ghci, but .c files can depend on .h files generated by ghc by ffi- -- exports.- unless (null (libModules lib)) $- ifReplLib (runGhcProg replOpts)--- -- link:- info verbosity "Linking..."- let cProfObjs = map (`replaceExtension` ("p_" ++ objExtension))- (cSources libBi)- cSharedObjs = map (`replaceExtension` ("dyn_" ++ objExtension))- (cSources libBi)- cid = compilerId (compiler lbi)- vanillaLibFilePath = libTargetDir </> mkLibName libName- profileLibFilePath = libTargetDir </> mkProfLibName libName- sharedLibFilePath = libTargetDir </> mkSharedLibName cid libName- ghciLibFilePath = libTargetDir </> mkGHCiLibName libName- libInstallPath = libdir $ absoluteInstallDirs pkg_descr lbi NoCopyDest- sharedLibInstallPath = libInstallPath </> mkSharedLibName cid libName-- stubObjs <- fmap catMaybes $ sequence- [ findFileWithExtension [objExtension] [libTargetDir]- (ModuleName.toFilePath x ++"_stub")- | ghcVersion < Version [7,2] [] -- ghc-7.2+ does not make _stub.o files- , x <- libModules lib ]- stubProfObjs <- fmap catMaybes $ sequence- [ findFileWithExtension ["p_" ++ objExtension] [libTargetDir]- (ModuleName.toFilePath x ++"_stub")- | ghcVersion < Version [7,2] [] -- ghc-7.2+ does not make _stub.o files- , x <- libModules lib ]- stubSharedObjs <- fmap catMaybes $ sequence- [ findFileWithExtension ["dyn_" ++ objExtension] [libTargetDir]- (ModuleName.toFilePath x ++"_stub")- | ghcVersion < Version [7,2] [] -- ghc-7.2+ does not make _stub.o files- , x <- libModules lib ]-- hObjs <- getHaskellObjects lib lbi- libTargetDir objExtension True- hProfObjs <-- if (withProfLib lbi)- then getHaskellObjects lib lbi- libTargetDir ("p_" ++ objExtension) True- else return []- hSharedObjs <-- if (withSharedLib lbi)- then getHaskellObjects lib lbi- libTargetDir ("dyn_" ++ objExtension) False- else return []-- unless (null hObjs && null cObjs && null stubObjs) $ do-- let staticObjectFiles =- hObjs- ++ map (libTargetDir </>) cObjs- ++ stubObjs- profObjectFiles =- hProfObjs- ++ map (libTargetDir </>) cProfObjs- ++ stubProfObjs- ghciObjFiles =- hObjs- ++ map (libTargetDir </>) cObjs- ++ stubObjs- dynamicObjectFiles =- hSharedObjs- ++ map (libTargetDir </>) cSharedObjs- ++ stubSharedObjs- -- After the relocation lib is created we invoke ghc -shared- -- with the dependencies spelled out as -package arguments- -- and ghc invokes the linker with the proper library paths- ghcSharedLinkArgs =- mempty {- ghcOptShared = toFlag True,- ghcOptDynLinkMode = toFlag GhcDynamicOnly,- ghcOptInputFiles = dynamicObjectFiles,- ghcOptOutputFile = toFlag sharedLibFilePath,- -- For dynamic libs, Mac OS/X needs to know the install location- -- at build time. This only applies to GHC < 7.8 - see the- -- discussion in #1660.- ghcOptDylibName = if (hostOS == OSX- && ghcVersion < Version [7,8] [])- then toFlag sharedLibInstallPath- else mempty,- ghcOptPackageName = toFlag pkgid,- ghcOptNoAutoLinkPackages = toFlag True,- ghcOptPackageDBs = withPackageDB lbi,- ghcOptPackages = componentPackageDeps clbi,- ghcOptLinkLibs = extraLibs libBi,- ghcOptLinkLibPath = extraLibDirs libBi- }-- whenVanillaLib False $ do- Ar.createArLibArchive verbosity lbi vanillaLibFilePath staticObjectFiles-- whenProfLib $ do- Ar.createArLibArchive verbosity lbi profileLibFilePath profObjectFiles-- whenGHCiLib $ do- (ldProg, _) <- requireProgram verbosity ldProgram (withPrograms lbi)- Ld.combineObjectFiles verbosity ldProg- ghciLibFilePath ghciObjFiles-- whenSharedLib False $- runGhcProg ghcSharedLinkArgs---- | Start a REPL without loading any source files.-startInterpreter :: Verbosity -> ProgramConfiguration -> Compiler- -> PackageDBStack -> IO ()-startInterpreter verbosity conf comp packageDBs = do- let replOpts = mempty {- ghcOptMode = toFlag GhcModeInteractive,- ghcOptPackageDBs = packageDBs- }- checkPackageDbStack packageDBs- (ghcProg, _) <- requireProgram verbosity ghcProgram conf- runGHC verbosity ghcProg comp replOpts---- | Build an executable with GHC.----buildExe, replExe :: Verbosity -> Cabal.Flag (Maybe Int)- -> PackageDescription -> LocalBuildInfo- -> Executable -> ComponentLocalBuildInfo -> IO ()-buildExe = buildOrReplExe False-replExe = buildOrReplExe True--buildOrReplExe :: Bool -> Verbosity -> Cabal.Flag (Maybe Int)- -> PackageDescription -> LocalBuildInfo- -> Executable -> ComponentLocalBuildInfo -> IO ()-buildOrReplExe forRepl verbosity numJobsFlag _pkg_descr lbi- exe@Executable { exeName = exeName', modulePath = modPath } clbi = do-- (ghcProg, _) <- requireProgram verbosity ghcProgram (withPrograms lbi)- let comp = compiler lbi- numJobs = fromMaybe 1 $- fromFlagOrDefault Nothing numJobsFlag- runGhcProg = runGHC verbosity ghcProg comp-- exeBi <- hackThreadedFlag verbosity- comp (withProfExe lbi) (buildInfo exe)-- -- exeNameReal, the name that GHC really uses (with .exe on Windows)- let exeNameReal = exeName' <.>- (if takeExtension exeName' /= ('.':exeExtension)- then exeExtension- else "")-- let targetDir = (buildDir lbi) </> exeName'- let exeDir = targetDir </> (exeName' ++ "-tmp")- createDirectoryIfMissingVerbose verbosity True targetDir- createDirectoryIfMissingVerbose verbosity True exeDir- -- TODO: do we need to put hs-boot files into place for mutually recursive- -- modules? FIX: what about exeName.hi-boot?-- -- build executables-- srcMainFile <- findFile (exeDir : hsSourceDirs exeBi) modPath- let isGhcDynamic = ghcDynamic comp- dynamicTooSupported = ghcSupportsDynamicToo comp- isHaskellMain = elem (takeExtension srcMainFile) [".hs", ".lhs"]- cSrcs = cSources exeBi ++ [srcMainFile | not isHaskellMain]- cObjs = map (`replaceExtension` objExtension) cSrcs- baseOpts = (componentGhcOptions verbosity lbi exeBi clbi exeDir)- `mappend` mempty {- ghcOptMode = toFlag GhcModeMake,- ghcOptInputFiles =- [ srcMainFile | isHaskellMain],- ghcOptInputModules =- [ m | not isHaskellMain, m <- exeModules exe]- }- staticOpts = baseOpts `mappend` mempty {- ghcOptDynLinkMode = toFlag GhcStaticOnly- }- profOpts = baseOpts `mappend` mempty {- ghcOptProfilingMode = toFlag True,- ghcOptHiSuffix = toFlag "p_hi",- ghcOptObjSuffix = toFlag "p_o",- ghcOptExtra = ghcProfOptions exeBi- }- dynOpts = baseOpts `mappend` mempty {- ghcOptDynLinkMode = toFlag GhcDynamicOnly,- ghcOptHiSuffix = toFlag "dyn_hi",- ghcOptObjSuffix = toFlag "dyn_o",- ghcOptExtra = ghcSharedOptions exeBi- }- dynTooOpts = staticOpts `mappend` mempty {- ghcOptDynLinkMode = toFlag GhcStaticAndDynamic,- ghcOptDynHiSuffix = toFlag "dyn_hi",- ghcOptDynObjSuffix = toFlag "dyn_o"- }- linkerOpts = mempty {- ghcOptLinkOptions = PD.ldOptions exeBi,- ghcOptLinkLibs = extraLibs exeBi,- ghcOptLinkLibPath = extraLibDirs exeBi,- ghcOptLinkFrameworks = PD.frameworks exeBi,- ghcOptInputFiles = [exeDir </> x | x <- cObjs]- }- replOpts = baseOpts {- ghcOptExtra = filterGhciFlags- (ghcOptExtra baseOpts)- }- -- For a normal compile we do separate invocations of ghc for- -- compiling as for linking. But for repl we have to do just- -- the one invocation, so that one has to include all the- -- linker stuff too, like -l flags and any .o files from C- -- files etc.- `mappend` linkerOpts- `mappend` mempty {- ghcOptMode = toFlag GhcModeInteractive,- ghcOptOptimisation = toFlag GhcNoOptimisation- }- commonOpts | withProfExe lbi = profOpts- | withDynExe lbi = dynOpts- | otherwise = staticOpts- compileOpts | useDynToo = dynTooOpts- | otherwise = commonOpts- withStaticExe = (not $ withProfExe lbi) && (not $ withDynExe lbi)-- -- For building exe's that use TH with -prof or -dynamic we actually have- -- to build twice, once without -prof/-dynamic and then again with- -- -prof/-dynamic. This is because the code that TH needs to run at- -- compile time needs to be the vanilla ABI so it can be loaded up and run- -- by the compiler.- -- With dynamic-by-default GHC the TH object files loaded at compile-time- -- need to be .dyn_o instead of .o.- doingTH = EnableExtension TemplateHaskell `elem` allExtensions exeBi- -- Should we use -dynamic-too instead of compiling twice?- useDynToo = dynamicTooSupported && isGhcDynamic- && doingTH && withStaticExe && null (ghcSharedOptions exeBi)- compileTHOpts | isGhcDynamic = dynOpts- | otherwise = staticOpts- compileForTH- | forRepl = False- | useDynToo = False- | isGhcDynamic = doingTH && (withProfExe lbi || withStaticExe)- | otherwise = doingTH && (withProfExe lbi || withDynExe lbi)-- linkOpts = commonOpts `mappend`- linkerOpts `mappend` mempty {- ghcOptLinkNoHsMain = toFlag (not isHaskellMain)- }-- -- Build static/dynamic object files for TH, if needed.- when compileForTH $- runGhcProg compileTHOpts { ghcOptNoLink = toFlag True- , ghcOptNumJobs = toFlag numJobs }-- unless forRepl $- runGhcProg compileOpts { ghcOptNoLink = toFlag True- , ghcOptNumJobs = toFlag numJobs }-- -- build any C sources- unless (null cSrcs) $ do- info verbosity "Building C Sources..."- sequence_- [ do let opts = (componentCcGhcOptions verbosity lbi exeBi clbi- exeDir filename) `mappend` mempty {- ghcOptDynLinkMode = toFlag (if withDynExe lbi- then GhcDynamicOnly- else GhcStaticOnly),- ghcOptProfilingMode = toFlag (withProfExe lbi)- }- odir = fromFlag (ghcOptObjDir opts)- createDirectoryIfMissingVerbose verbosity True odir- runGhcProg opts- | filename <- cSrcs ]-- -- TODO: problem here is we need the .c files built first, so we can load them- -- with ghci, but .c files can depend on .h files generated by ghc by ffi- -- exports.- when forRepl $ runGhcProg replOpts-- -- link:- unless forRepl $ do- info verbosity "Linking..."- runGhcProg linkOpts { ghcOptOutputFile = toFlag (targetDir </> exeNameReal) }----- | Filter the "-threaded" flag when profiling as it does not--- work with ghc-6.8 and older.-hackThreadedFlag :: Verbosity -> Compiler -> Bool -> BuildInfo -> IO BuildInfo-hackThreadedFlag verbosity comp prof bi- | not mustFilterThreaded = return bi- | otherwise = do- warn verbosity $ "The ghc flag '-threaded' is not compatible with "- ++ "profiling in ghc-6.8 and older. It will be disabled."- return bi { options = filterHcOptions (/= "-threaded") (options bi) }- where- mustFilterThreaded = prof && compilerVersion comp < Version [6, 10] []- && "-threaded" `elem` hcOptions GHC bi- filterHcOptions p hcoptss =- [ (hc, if hc == GHC then filter p opts else opts)- | (hc, opts) <- hcoptss ]---- | Strip out flags that are not supported in ghci-filterGhciFlags :: [String] -> [String]-filterGhciFlags = filter supported- where- supported ('-':'O':_) = False- supported "-debug" = False- supported "-threaded" = False- supported "-ticky" = False- supported "-eventlog" = False- supported "-prof" = False- supported "-unreg" = False- supported _ = True---- when using -split-objs, we need to search for object files in the--- Module_split directory for each module.-getHaskellObjects :: Library -> LocalBuildInfo- -> FilePath -> String -> Bool -> IO [FilePath]-getHaskellObjects lib lbi pref wanted_obj_ext allow_split_objs- | splitObjs lbi && allow_split_objs = do- let splitSuffix = if compilerVersion (compiler lbi) <- Version [6, 11] []- then "_split"- else "_" ++ wanted_obj_ext ++ "_split"- dirs = [ pref </> (ModuleName.toFilePath x ++ splitSuffix)- | x <- libModules lib ]- objss <- mapM getDirectoryContents dirs- let objs = [ dir </> obj- | (objs',dir) <- zip objss dirs, obj <- objs',- let obj_ext = takeExtension obj,- '.':wanted_obj_ext == obj_ext ]- return objs- | otherwise =- return [ pref </> ModuleName.toFilePath x <.> wanted_obj_ext- | x <- libModules lib ]---- | Extracts a String representing a hash of the ABI of a built--- library. It can fail if the library has not yet been built.----libAbiHash :: Verbosity -> PackageDescription -> LocalBuildInfo- -> Library -> ComponentLocalBuildInfo -> IO String-libAbiHash verbosity pkg_descr lbi lib clbi = do- libBi <- hackThreadedFlag verbosity- (compiler lbi) (withProfLib lbi) (libBuildInfo lib)- let- comp = compiler lbi- vanillaArgs =- (componentGhcOptions verbosity lbi libBi clbi (buildDir lbi))- `mappend` mempty {- ghcOptMode = toFlag GhcModeAbiHash,- ghcOptPackageName = toFlag (packageId pkg_descr),- ghcOptInputModules = exposedModules lib- }- sharedArgs = vanillaArgs `mappend` mempty {- ghcOptDynLinkMode = toFlag GhcDynamicOnly,- ghcOptFPic = toFlag True,- ghcOptHiSuffix = toFlag "dyn_hi",- ghcOptObjSuffix = toFlag "dyn_o",- ghcOptExtra = ghcSharedOptions libBi- }- profArgs = vanillaArgs `mappend` mempty {- ghcOptProfilingMode = toFlag True,- ghcOptHiSuffix = toFlag "p_hi",- ghcOptObjSuffix = toFlag "p_o",- ghcOptExtra = ghcProfOptions libBi- }- ghcArgs = if withVanillaLib lbi then vanillaArgs- else if withSharedLib lbi then sharedArgs- else if withProfLib lbi then profArgs- else error "libAbiHash: Can't find an enabled library way"- --- (ghcProg, _) <- requireProgram verbosity ghcProgram (withPrograms lbi)- getProgramInvocationOutput verbosity (ghcInvocation ghcProg comp ghcArgs)---componentGhcOptions :: Verbosity -> LocalBuildInfo- -> BuildInfo -> ComponentLocalBuildInfo -> FilePath- -> GhcOptions-componentGhcOptions verbosity lbi bi clbi odir =- mempty {- ghcOptVerbosity = toFlag verbosity,- ghcOptHideAllPackages = toFlag True,- ghcOptCabal = toFlag True,- ghcOptPackageDBs = withPackageDB lbi,- ghcOptPackages = componentPackageDeps clbi,- ghcOptSplitObjs = toFlag (splitObjs lbi),- ghcOptSourcePathClear = toFlag True,- ghcOptSourcePath = [odir] ++ nub (hsSourceDirs bi)- ++ [autogenModulesDir lbi],- ghcOptCppIncludePath = [autogenModulesDir lbi, odir]- ++ PD.includeDirs bi,- ghcOptCppOptions = cppOptions bi,- ghcOptCppIncludes = [autogenModulesDir lbi </> cppHeaderName],- ghcOptFfiIncludes = PD.includes bi,- ghcOptObjDir = toFlag odir,- ghcOptHiDir = toFlag odir,- ghcOptStubDir = toFlag odir,- ghcOptOutputDir = toFlag odir,- ghcOptOptimisation = toGhcOptimisation (withOptimization lbi),- ghcOptExtra = hcOptions GHC bi,- ghcOptLanguage = toFlag (fromMaybe Haskell98 (defaultLanguage bi)),- -- Unsupported extensions have already been checked by configure- ghcOptExtensions = usedExtensions bi,- ghcOptExtensionMap = compilerExtensions (compiler lbi)- }- where- toGhcOptimisation NoOptimisation = mempty --TODO perhaps override?- toGhcOptimisation NormalOptimisation = toFlag GhcNormalOptimisation- toGhcOptimisation MaximumOptimisation = toFlag GhcMaximumOptimisation---componentCcGhcOptions :: Verbosity -> LocalBuildInfo- -> BuildInfo -> ComponentLocalBuildInfo- -> FilePath -> FilePath- -> GhcOptions-componentCcGhcOptions verbosity lbi bi clbi pref filename =- mempty {- ghcOptVerbosity = toFlag verbosity,- ghcOptMode = toFlag GhcModeCompile,- ghcOptInputFiles = [filename],-- ghcOptCppIncludePath = [autogenModulesDir lbi, odir]- ++ PD.includeDirs bi,- ghcOptPackageDBs = withPackageDB lbi,- ghcOptPackages = componentPackageDeps clbi,- ghcOptCcOptions = PD.ccOptions bi- ++ case withOptimization lbi of- NoOptimisation -> []- _ -> ["-O2"],- ghcOptObjDir = toFlag odir- }- where- odir | compilerVersion (compiler lbi) >= Version [6,4,1] [] = pref- | otherwise = pref </> takeDirectory filename- -- ghc 6.4.0 had a bug in -odir handling for C compilations.--mkGHCiLibName :: LibraryName -> String-mkGHCiLibName (LibraryName lib) = lib <.> "o"---- -------------------------------------------------------------------------------- Installing---- |Install executables for GHC.-installExe :: Verbosity- -> LocalBuildInfo- -> InstallDirs FilePath -- ^Where to copy the files to- -> FilePath -- ^Build location- -> (FilePath, FilePath) -- ^Executable (prefix,suffix)- -> PackageDescription- -> Executable- -> IO ()-installExe verbosity lbi installDirs buildPref- (progprefix, progsuffix) _pkg exe = do- let binDir = bindir installDirs- createDirectoryIfMissingVerbose verbosity True binDir- let exeFileName = exeName exe <.> exeExtension- fixedExeBaseName = progprefix ++ exeName exe ++ progsuffix- installBinary dest = do- installExecutableFile verbosity- (buildPref </> exeName exe </> exeFileName)- (dest <.> exeExtension)- when (stripExes lbi) $- Strip.stripExe verbosity (hostPlatform lbi) (withPrograms lbi)- (dest <.> exeExtension)- installBinary (binDir </> fixedExeBaseName)---- |Install for ghc, .hi, .a and, if --with-ghci given, .o-installLib :: Verbosity- -> LocalBuildInfo- -> FilePath -- ^install location- -> FilePath -- ^install location for dynamic libraries- -> FilePath -- ^Build location- -> PackageDescription- -> Library- -> ComponentLocalBuildInfo- -> IO ()-installLib verbosity lbi targetDir dynlibTargetDir builtDir _pkg lib clbi = do- -- copy .hi files over:- whenVanilla $ copyModuleFiles "hi"- whenProf $ copyModuleFiles "p_hi"- whenShared $ copyModuleFiles "dyn_hi"-- -- copy the built library files over:- whenVanilla $ mapM_ (installOrdinary builtDir targetDir) vanillaLibNames- whenProf $ mapM_ (installOrdinary builtDir targetDir) profileLibNames- whenGHCi $ mapM_ (installOrdinary builtDir targetDir) ghciLibNames- whenShared $ mapM_ (installShared builtDir dynlibTargetDir) sharedLibNames-- where- install isShared srcDir dstDir name = do- let src = srcDir </> name- dst = dstDir </> name- createDirectoryIfMissingVerbose verbosity True dstDir- if isShared- then do when (stripLibs lbi) $ Strip.stripLib verbosity- (hostPlatform lbi) (withPrograms lbi) src- installExecutableFile verbosity src dst- else installOrdinaryFile verbosity src dst-- installOrdinary = install False- installShared = install True-- copyModuleFiles ext =- findModuleFiles [builtDir] [ext] (libModules lib)- >>= installOrdinaryFiles verbosity targetDir-- cid = compilerId (compiler lbi)- libNames = componentLibraries clbi- vanillaLibNames = map mkLibName libNames- profileLibNames = map mkProfLibName libNames- ghciLibNames = map mkGHCiLibName libNames- sharedLibNames = map (mkSharedLibName cid) libNames-- hasLib = not $ null (libModules lib)- && null (cSources (libBuildInfo lib))- whenVanilla = when (hasLib && withVanillaLib lbi)- whenProf = when (hasLib && withProfLib lbi)- whenGHCi = when (hasLib && withGHCiLib lbi)- whenShared = when (hasLib && withSharedLib lbi)---- -------------------------------------------------------------------------------- Registering---- | Create an empty package DB at the specified location.-initPackageDB :: Verbosity -> ProgramConfiguration -> FilePath -> IO ()-initPackageDB verbosity conf dbPath = HcPkg.init verbosity ghcPkgProg dbPath- where- Just ghcPkgProg = lookupProgram ghcPkgProgram conf---- | Run 'ghc-pkg' using a given package DB stack, directly forwarding the--- provided command-line arguments to it.-invokeHcPkg :: Verbosity -> ProgramConfiguration -> PackageDBStack -> [String]- -> IO ()-invokeHcPkg verbosity conf dbStack extraArgs =- HcPkg.invoke verbosity ghcPkgProg dbStack extraArgs- where- Just ghcPkgProg = lookupProgram ghcPkgProgram conf--registerPackage- :: Verbosity- -> InstalledPackageInfo- -> PackageDescription- -> LocalBuildInfo- -> Bool- -> PackageDBStack- -> IO ()-registerPackage verbosity installedPkgInfo _pkg lbi _inplace packageDbs = do- let Just ghcPkg = lookupProgram ghcPkgProgram (withPrograms lbi)- HcPkg.reregister verbosity ghcPkg packageDbs (Right installedPkgInfo)---- -------------------------------------------------------------------------------- Utils--ghcLookupProperty :: String -> Compiler -> Bool-ghcLookupProperty prop comp =- case M.lookup prop (compilerProperties comp) of- Just "YES" -> True- _ -> False--ghcDynamic :: Compiler -> Bool-ghcDynamic = ghcLookupProperty "GHC Dynamic"--ghcSupportsDynamicToo :: Compiler -> Bool-ghcSupportsDynamicToo = ghcLookupProperty "Support dynamic-too"+ hcPkgInfo,+ registerPackage,+ componentGhcOptions,+ getLibDir,+ isDynamic,+ getGlobalPackageDB,+ pkgRoot+ ) where++import qualified Distribution.Simple.GHC.IPI641 as IPI641+import qualified Distribution.Simple.GHC.IPI642 as IPI642+import qualified Distribution.Simple.GHC.Internal as Internal+import Distribution.Simple.GHC.ImplInfo+import Distribution.PackageDescription as PD+ ( PackageDescription(..), BuildInfo(..), Executable(..), Library(..)+ , allExtensions, libModules, exeModules+ , hcOptions, hcSharedOptions, hcProfOptions )+import Distribution.InstalledPackageInfo+ ( InstalledPackageInfo )+import qualified Distribution.InstalledPackageInfo as InstalledPackageInfo+ ( InstalledPackageInfo_(..) )+import Distribution.Simple.PackageIndex (InstalledPackageIndex)+import qualified Distribution.Simple.PackageIndex as PackageIndex+import Distribution.Simple.LocalBuildInfo+ ( LocalBuildInfo(..), ComponentLocalBuildInfo(..)+ , absoluteInstallDirs, depLibraryPaths )+import qualified Distribution.Simple.Hpc as Hpc+import Distribution.Simple.InstallDirs hiding ( absoluteInstallDirs )+import Distribution.Simple.BuildPaths+import Distribution.Simple.Utils+import Distribution.Package+ ( PackageName(..) )+import qualified Distribution.ModuleName as ModuleName+import Distribution.Simple.Program+ ( Program(..), ConfiguredProgram(..), ProgramConfiguration+ , ProgramSearchPath+ , rawSystemProgramStdout, rawSystemProgramStdoutConf+ , getProgramInvocationOutput, requireProgramVersion, requireProgram+ , userMaybeSpecifyPath, programPath, lookupProgram, addKnownProgram+ , ghcProgram, ghcPkgProgram, hsc2hsProgram, ldProgram )+import qualified Distribution.Simple.Program.HcPkg as HcPkg+import qualified Distribution.Simple.Program.Ar as Ar+import qualified Distribution.Simple.Program.Ld as Ld+import qualified Distribution.Simple.Program.Strip as Strip+import Distribution.Simple.Program.GHC+import Distribution.Simple.Setup+ ( toFlag, fromFlag, configCoverage, configDistPref )+import qualified Distribution.Simple.Setup as Cabal+ ( Flag(..) )+import Distribution.Simple.Compiler+ ( CompilerFlavor(..), CompilerId(..), Compiler(..), compilerVersion+ , PackageDB(..), PackageDBStack, AbiTag(..) )+import Distribution.Version+ ( Version(..), anyVersion, orLaterVersion )+import Distribution.System+ ( Platform(..), OS(..) )+import Distribution.Verbosity+import Distribution.Text+ ( display )+import Distribution.Utils.NubList+ ( NubListR, overNubListR, toNubListR )+import Language.Haskell.Extension (Extension(..), KnownExtension(..))++import Control.Monad ( unless, when )+import Data.Char ( isDigit, isSpace )+import Data.List+import qualified Data.Map as M ( fromList )+import Data.Maybe ( catMaybes )+import Data.Monoid ( Monoid(..) )+import Data.Version ( showVersion )+import System.Directory+ ( doesFileExist, getAppUserDataDirectory, createDirectoryIfMissing )+import System.FilePath ( (</>), (<.>), takeExtension,+ takeDirectory, replaceExtension,+ splitExtension, isRelative )+import qualified System.Info++-- -----------------------------------------------------------------------------+-- Configuring++configure :: Verbosity -> Maybe FilePath -> Maybe FilePath+ -> ProgramConfiguration+ -> IO (Compiler, Maybe Platform, ProgramConfiguration)+configure verbosity hcPath hcPkgPath conf0 = do++ (ghcProg, ghcVersion, conf1) <-+ requireProgramVersion verbosity ghcProgram+ (orLaterVersion (Version [6,4] []))+ (userMaybeSpecifyPath "ghc" hcPath conf0)+ let implInfo = ghcVersionImplInfo ghcVersion++ -- This is slightly tricky, we have to configure ghc first, then we use the+ -- location of ghc to help find ghc-pkg in the case that the user did not+ -- specify the location of ghc-pkg directly:+ (ghcPkgProg, ghcPkgVersion, conf2) <-+ requireProgramVersion verbosity ghcPkgProgram {+ programFindLocation = guessGhcPkgFromGhcPath ghcProg+ }+ anyVersion (userMaybeSpecifyPath "ghc-pkg" hcPkgPath conf1)++ when (ghcVersion /= ghcPkgVersion) $ die $+ "Version mismatch between ghc and ghc-pkg: "+ ++ programPath ghcProg ++ " is version " ++ display ghcVersion ++ " "+ ++ programPath ghcPkgProg ++ " is version " ++ display ghcPkgVersion++ -- Likewise we try to find the matching hsc2hs program.+ let hsc2hsProgram' = hsc2hsProgram {+ programFindLocation = guessHsc2hsFromGhcPath ghcProg+ }+ conf3 = addKnownProgram hsc2hsProgram' conf2++ languages <- Internal.getLanguages verbosity implInfo ghcProg+ extensions <- Internal.getExtensions verbosity implInfo ghcProg++ ghcInfo <- Internal.getGhcInfo verbosity implInfo ghcProg+ let ghcInfoMap = M.fromList ghcInfo++ let comp = Compiler {+ compilerId = CompilerId GHC ghcVersion,+ compilerAbiTag = NoAbiTag,+ compilerCompat = [],+ compilerLanguages = languages,+ compilerExtensions = extensions,+ compilerProperties = ghcInfoMap+ }+ compPlatform = Internal.targetPlatform ghcInfo+ conf4 = Internal.configureToolchain implInfo ghcProg ghcInfoMap conf3 -- configure gcc and ld+ return (comp, compPlatform, conf4)++-- | Given something like /usr/local/bin/ghc-6.6.1(.exe) we try and find+-- the corresponding tool; e.g. if the tool is ghc-pkg, we try looking+-- for a versioned or unversioned ghc-pkg in the same dir, that is:+--+-- > /usr/local/bin/ghc-pkg-ghc-6.6.1(.exe)+-- > /usr/local/bin/ghc-pkg-6.6.1(.exe)+-- > /usr/local/bin/ghc-pkg(.exe)+--+guessToolFromGhcPath :: Program -> ConfiguredProgram+ -> Verbosity -> ProgramSearchPath+ -> IO (Maybe FilePath)+guessToolFromGhcPath tool ghcProg verbosity searchpath+ = do let toolname = programName tool+ path = programPath ghcProg+ dir = takeDirectory path+ versionSuffix = takeVersionSuffix (dropExeExtension path)+ guessNormal = dir </> toolname <.> exeExtension+ guessGhcVersioned = dir </> (toolname ++ "-ghc" ++ versionSuffix)+ <.> exeExtension+ guessVersioned = dir </> (toolname ++ versionSuffix)+ <.> exeExtension+ guesses | null versionSuffix = [guessNormal]+ | otherwise = [guessGhcVersioned,+ guessVersioned,+ guessNormal]+ info verbosity $ "looking for tool " ++ toolname+ ++ " near compiler in " ++ dir+ exists <- mapM doesFileExist guesses+ case [ file | (file, True) <- zip guesses exists ] of+ -- If we can't find it near ghc, fall back to the usual+ -- method.+ [] -> programFindLocation tool verbosity searchpath+ (fp:_) -> do info verbosity $ "found " ++ toolname ++ " in " ++ fp+ return (Just fp)++ where takeVersionSuffix :: FilePath -> String+ takeVersionSuffix = takeWhileEndLE isSuffixChar++ isSuffixChar :: Char -> Bool+ isSuffixChar c = isDigit c || c == '.' || c == '-'++ dropExeExtension :: FilePath -> FilePath+ dropExeExtension filepath =+ case splitExtension filepath of+ (filepath', extension) | extension == exeExtension -> filepath'+ | otherwise -> filepath++-- | Given something like /usr/local/bin/ghc-6.6.1(.exe) we try and find a+-- corresponding ghc-pkg, we try looking for both a versioned and unversioned+-- ghc-pkg in the same dir, that is:+--+-- > /usr/local/bin/ghc-pkg-ghc-6.6.1(.exe)+-- > /usr/local/bin/ghc-pkg-6.6.1(.exe)+-- > /usr/local/bin/ghc-pkg(.exe)+--+guessGhcPkgFromGhcPath :: ConfiguredProgram+ -> Verbosity -> ProgramSearchPath -> IO (Maybe FilePath)+guessGhcPkgFromGhcPath = guessToolFromGhcPath ghcPkgProgram++-- | Given something like /usr/local/bin/ghc-6.6.1(.exe) we try and find a+-- corresponding hsc2hs, we try looking for both a versioned and unversioned+-- hsc2hs in the same dir, that is:+--+-- > /usr/local/bin/hsc2hs-ghc-6.6.1(.exe)+-- > /usr/local/bin/hsc2hs-6.6.1(.exe)+-- > /usr/local/bin/hsc2hs(.exe)+--+guessHsc2hsFromGhcPath :: ConfiguredProgram+ -> Verbosity -> ProgramSearchPath -> IO (Maybe FilePath)+guessHsc2hsFromGhcPath = guessToolFromGhcPath hsc2hsProgram++getGhcInfo :: Verbosity -> ConfiguredProgram -> IO [(String, String)]+getGhcInfo verbosity ghcProg = Internal.getGhcInfo verbosity implInfo ghcProg+ where+ Just version = programVersion ghcProg+ implInfo = ghcVersionImplInfo version++-- | Given a single package DB, return all installed packages.+getPackageDBContents :: Verbosity -> PackageDB -> ProgramConfiguration+ -> IO InstalledPackageIndex+getPackageDBContents verbosity packagedb conf = do+ pkgss <- getInstalledPackages' verbosity [packagedb] conf+ toPackageIndex verbosity pkgss conf++-- | Given a package DB stack, return all installed packages.+getInstalledPackages :: Verbosity -> PackageDBStack -> ProgramConfiguration+ -> IO InstalledPackageIndex+getInstalledPackages verbosity packagedbs conf = do+ checkPackageDbEnvVar+ checkPackageDbStack packagedbs+ pkgss <- getInstalledPackages' verbosity packagedbs conf+ index <- toPackageIndex verbosity pkgss conf+ return $! hackRtsPackage index++ where+ hackRtsPackage index =+ case PackageIndex.lookupPackageName index (PackageName "rts") of+ [(_,[rts])]+ -> PackageIndex.insert (removeMingwIncludeDir rts) index+ _ -> index -- No (or multiple) ghc rts package is registered!!+ -- Feh, whatever, the ghc test suite does some crazy stuff.++-- | Given a list of @(PackageDB, InstalledPackageInfo)@ pairs, produce a+-- @PackageIndex@. Helper function used by 'getPackageDBContents' and+-- 'getInstalledPackages'.+toPackageIndex :: Verbosity+ -> [(PackageDB, [InstalledPackageInfo])]+ -> ProgramConfiguration+ -> IO InstalledPackageIndex+toPackageIndex verbosity pkgss conf = do+ -- On Windows, various fields have $topdir/foo rather than full+ -- paths. We need to substitute the right value in so that when+ -- we, for example, call gcc, we have proper paths to give it.+ topDir <- getLibDir' verbosity ghcProg+ let indices = [ PackageIndex.fromList (map (Internal.substTopDir topDir) pkgs)+ | (_, pkgs) <- pkgss ]+ return $! (mconcat indices)++ where+ Just ghcProg = lookupProgram ghcProgram conf++getLibDir :: Verbosity -> LocalBuildInfo -> IO FilePath+getLibDir verbosity lbi =+ dropWhileEndLE isSpace `fmap`+ rawSystemProgramStdoutConf verbosity ghcProgram+ (withPrograms lbi) ["--print-libdir"]++getLibDir' :: Verbosity -> ConfiguredProgram -> IO FilePath+getLibDir' verbosity ghcProg =+ dropWhileEndLE isSpace `fmap`+ rawSystemProgramStdout verbosity ghcProg ["--print-libdir"]+++-- | Return the 'FilePath' to the global GHC package database.+getGlobalPackageDB :: Verbosity -> ConfiguredProgram -> IO FilePath+getGlobalPackageDB verbosity ghcProg =+ dropWhileEndLE isSpace `fmap`+ rawSystemProgramStdout verbosity ghcProg ["--print-global-package-db"]++checkPackageDbEnvVar :: IO ()+checkPackageDbEnvVar =+ Internal.checkPackageDbEnvVar "GHC" "GHC_PACKAGE_PATH"++checkPackageDbStack :: PackageDBStack -> IO ()+checkPackageDbStack (GlobalPackageDB:rest)+ | GlobalPackageDB `notElem` rest = return ()+checkPackageDbStack rest+ | GlobalPackageDB `notElem` rest =+ die $ "With current ghc versions the global package db is always used "+ ++ "and must be listed first. This ghc limitation may be lifted in "+ ++ "future, see http://hackage.haskell.org/trac/ghc/ticket/5977"+checkPackageDbStack _ =+ die $ "If the global package db is specified, it must be "+ ++ "specified first and cannot be specified multiple times"++-- GHC < 6.10 put "$topdir/include/mingw" in rts's installDirs. This+-- breaks when you want to use a different gcc, so we need to filter+-- it out.+removeMingwIncludeDir :: InstalledPackageInfo -> InstalledPackageInfo+removeMingwIncludeDir pkg =+ let ids = InstalledPackageInfo.includeDirs pkg+ ids' = filter (not . ("mingw" `isSuffixOf`)) ids+ in pkg { InstalledPackageInfo.includeDirs = ids' }++-- | Get the packages from specific PackageDBs, not cumulative.+--+getInstalledPackages' :: Verbosity -> [PackageDB] -> ProgramConfiguration+ -> IO [(PackageDB, [InstalledPackageInfo])]+getInstalledPackages' verbosity packagedbs conf+ | ghcVersion >= Version [6,9] [] =+ sequence+ [ do pkgs <- HcPkg.dump (hcPkgInfo conf) verbosity packagedb+ return (packagedb, pkgs)+ | packagedb <- packagedbs ]++ where+ Just ghcProg = lookupProgram ghcProgram conf+ Just ghcVersion = programVersion ghcProg++getInstalledPackages' verbosity packagedbs conf = do+ str <- rawSystemProgramStdoutConf verbosity ghcPkgProgram conf ["list"]+ let pkgFiles = [ init line | line <- lines str, last line == ':' ]+ dbFile packagedb = case (packagedb, pkgFiles) of+ (GlobalPackageDB, global:_) -> return $ Just global+ (UserPackageDB, _global:user:_) -> return $ Just user+ (UserPackageDB, _global:_) -> return $ Nothing+ (SpecificPackageDB specific, _) -> return $ Just specific+ _ -> die "cannot read ghc-pkg package listing"+ pkgFiles' <- mapM dbFile packagedbs+ sequence [ withFileContents file $ \content -> do+ pkgs <- readPackages file content+ return (db, pkgs)+ | (db , Just file) <- zip packagedbs pkgFiles' ]+ where+ -- Depending on the version of ghc we use a different type's Read+ -- instance to parse the package file and then convert.+ -- It's a bit yuck. But that's what we get for using Read/Show.+ readPackages+ | ghcVersion >= Version [6,4,2] []+ = \file content -> case reads content of+ [(pkgs, _)] -> return (map IPI642.toCurrent pkgs)+ _ -> failToRead file+ | otherwise+ = \file content -> case reads content of+ [(pkgs, _)] -> return (map IPI641.toCurrent pkgs)+ _ -> failToRead file+ Just ghcProg = lookupProgram ghcProgram conf+ Just ghcVersion = programVersion ghcProg+ failToRead file = die $ "cannot read ghc package database " ++ file++-- -----------------------------------------------------------------------------+-- Building++-- | Build a library with GHC.+--+buildLib, replLib :: Verbosity -> Cabal.Flag (Maybe Int)+ -> PackageDescription -> LocalBuildInfo+ -> Library -> ComponentLocalBuildInfo -> IO ()+buildLib = buildOrReplLib False+replLib = buildOrReplLib True++buildOrReplLib :: Bool -> Verbosity -> Cabal.Flag (Maybe Int)+ -> PackageDescription -> LocalBuildInfo+ -> Library -> ComponentLocalBuildInfo -> IO ()+buildOrReplLib forRepl verbosity numJobs pkg_descr lbi lib clbi = do+ libName <- case componentLibraries clbi of+ [libName] -> return libName+ [] -> die "No library name found when building library"+ _ -> die "Multiple library names found when building library"++ let libTargetDir = buildDir lbi+ whenVanillaLib forceVanilla =+ when (forceVanilla || withVanillaLib lbi)+ whenProfLib = when (withProfLib lbi)+ whenSharedLib forceShared =+ when (forceShared || withSharedLib lbi)+ whenGHCiLib = when (withGHCiLib lbi && withVanillaLib lbi)+ ifReplLib = when forRepl+ comp = compiler lbi+ ghcVersion = compilerVersion comp+ implInfo = getImplInfo comp+ (Platform _hostArch hostOS) = hostPlatform lbi+ hole_insts = map (\(k,(p,n)) -> (k,(InstalledPackageInfo.packageKey p,n))) (instantiatedWith lbi)++ (ghcProg, _) <- requireProgram verbosity ghcProgram (withPrograms lbi)+ let runGhcProg = runGHC verbosity ghcProg comp++ libBi <- hackThreadedFlag verbosity+ comp (withProfLib lbi) (libBuildInfo lib)++ let isGhcDynamic = isDynamic comp+ dynamicTooSupported = supportsDynamicToo comp+ doingTH = EnableExtension TemplateHaskell `elem` allExtensions libBi+ forceVanillaLib = doingTH && not isGhcDynamic+ forceSharedLib = doingTH && isGhcDynamic+ -- TH always needs default libs, even when building for profiling++ -- Determine if program coverage should be enabled and if so, what+ -- '-hpcdir' should be.+ let isCoverageEnabled = fromFlag $ configCoverage $ configFlags lbi+ -- Component name. Not 'libName' because that has the "HS" prefix+ -- that GHC gives Haskell libraries.+ cname = display $ PD.package $ localPkgDescr lbi+ distPref = fromFlag $ configDistPref $ configFlags lbi+ hpcdir way+ | isCoverageEnabled = toFlag $ Hpc.mixDir distPref way cname+ | otherwise = mempty++ createDirectoryIfMissingVerbose verbosity True libTargetDir+ -- TODO: do we need to put hs-boot files into place for mutually recursive+ -- modules?+ let cObjs = map (`replaceExtension` objExtension) (cSources libBi)+ baseOpts = componentGhcOptions verbosity lbi libBi clbi libTargetDir+ vanillaOpts = baseOpts `mappend` mempty {+ ghcOptMode = toFlag GhcModeMake,+ ghcOptNumJobs = numJobs,+ ghcOptPackageKey = toFlag (pkgKey lbi),+ ghcOptSigOf = hole_insts,+ ghcOptInputModules = toNubListR $ libModules lib,+ ghcOptHPCDir = hpcdir Hpc.Vanilla+ }++ profOpts = vanillaOpts `mappend` mempty {+ ghcOptProfilingMode = toFlag True,+ ghcOptHiSuffix = toFlag "p_hi",+ ghcOptObjSuffix = toFlag "p_o",+ ghcOptExtra = toNubListR $ hcProfOptions GHC libBi,+ ghcOptHPCDir = hpcdir Hpc.Prof+ }++ sharedOpts = vanillaOpts `mappend` mempty {+ ghcOptDynLinkMode = toFlag GhcDynamicOnly,+ ghcOptFPic = toFlag True,+ ghcOptHiSuffix = toFlag "dyn_hi",+ ghcOptObjSuffix = toFlag "dyn_o",+ ghcOptExtra = toNubListR $ hcSharedOptions GHC libBi,+ ghcOptHPCDir = hpcdir Hpc.Dyn+ }+ linkerOpts = mempty {+ ghcOptLinkOptions = toNubListR $ PD.ldOptions libBi,+ ghcOptLinkLibs = toNubListR $ extraLibs libBi,+ ghcOptLinkLibPath = toNubListR $ extraLibDirs libBi,+ ghcOptLinkFrameworks = toNubListR $ PD.frameworks libBi,+ ghcOptInputFiles = toNubListR+ [libTargetDir </> x | x <- cObjs]+ }+ replOpts = vanillaOpts {+ ghcOptExtra = overNubListR+ Internal.filterGhciFlags $+ (ghcOptExtra vanillaOpts),+ ghcOptNumJobs = mempty+ }+ `mappend` linkerOpts+ `mappend` mempty {+ ghcOptMode = toFlag GhcModeInteractive,+ ghcOptOptimisation = toFlag GhcNoOptimisation+ }++ vanillaSharedOpts = vanillaOpts `mappend` mempty {+ ghcOptDynLinkMode = toFlag GhcStaticAndDynamic,+ ghcOptDynHiSuffix = toFlag "dyn_hi",+ ghcOptDynObjSuffix = toFlag "dyn_o",+ ghcOptHPCDir = hpcdir Hpc.Dyn+ }++ unless (forRepl || null (libModules lib)) $+ do let vanilla = whenVanillaLib forceVanillaLib (runGhcProg vanillaOpts)+ shared = whenSharedLib forceSharedLib (runGhcProg sharedOpts)+ useDynToo = dynamicTooSupported &&+ (forceVanillaLib || withVanillaLib lbi) &&+ (forceSharedLib || withSharedLib lbi) &&+ null (hcSharedOptions GHC libBi)+ if useDynToo+ then do+ runGhcProg vanillaSharedOpts+ case (hpcdir Hpc.Dyn, hpcdir Hpc.Vanilla) of+ (Cabal.Flag dynDir, Cabal.Flag vanillaDir) -> do+ -- When the vanilla and shared library builds are done+ -- in one pass, only one set of HPC module interfaces+ -- are generated. This set should suffice for both+ -- static and dynamically linked executables. We copy+ -- the modules interfaces so they are available under+ -- both ways.+ copyDirectoryRecursive verbosity dynDir vanillaDir+ _ -> return ()+ else if isGhcDynamic+ then do shared; vanilla+ else do vanilla; shared+ whenProfLib (runGhcProg profOpts)++ -- build any C sources+ unless (null (cSources libBi)) $ do+ info verbosity "Building C Sources..."+ sequence_+ [ do let baseCcOpts = Internal.componentCcGhcOptions verbosity implInfo+ lbi libBi clbi libTargetDir filename+ vanillaCcOpts = if isGhcDynamic+ -- Dynamic GHC requires C sources to be built+ -- with -fPIC for REPL to work. See #2207.+ then baseCcOpts { ghcOptFPic = toFlag True }+ else baseCcOpts+ profCcOpts = vanillaCcOpts `mappend` mempty {+ ghcOptProfilingMode = toFlag True,+ ghcOptObjSuffix = toFlag "p_o"+ }+ sharedCcOpts = vanillaCcOpts `mappend` mempty {+ ghcOptFPic = toFlag True,+ ghcOptDynLinkMode = toFlag GhcDynamicOnly,+ ghcOptObjSuffix = toFlag "dyn_o"+ }+ odir = fromFlag (ghcOptObjDir vanillaCcOpts)+ createDirectoryIfMissingVerbose verbosity True odir+ runGhcProg vanillaCcOpts+ unless forRepl $+ whenSharedLib forceSharedLib (runGhcProg sharedCcOpts)+ unless forRepl $ whenProfLib (runGhcProg profCcOpts)+ | filename <- cSources libBi]++ -- TODO: problem here is we need the .c files built first, so we can load them+ -- with ghci, but .c files can depend on .h files generated by ghc by ffi+ -- exports.+ unless (null (libModules lib)) $+ ifReplLib (runGhcProg replOpts)++ -- link:+ unless forRepl $ do+ info verbosity "Linking..."+ let cProfObjs = map (`replaceExtension` ("p_" ++ objExtension))+ (cSources libBi)+ cSharedObjs = map (`replaceExtension` ("dyn_" ++ objExtension))+ (cSources libBi)+ cid = compilerId (compiler lbi)+ vanillaLibFilePath = libTargetDir </> mkLibName libName+ profileLibFilePath = libTargetDir </> mkProfLibName libName+ sharedLibFilePath = libTargetDir </> mkSharedLibName cid libName+ ghciLibFilePath = libTargetDir </> Internal.mkGHCiLibName libName+ libInstallPath = libdir $ absoluteInstallDirs pkg_descr lbi NoCopyDest+ sharedLibInstallPath = libInstallPath </> mkSharedLibName cid libName++ stubObjs <- fmap catMaybes $ sequence+ [ findFileWithExtension [objExtension] [libTargetDir]+ (ModuleName.toFilePath x ++"_stub")+ | ghcVersion < Version [7,2] [] -- ghc-7.2+ does not make _stub.o files+ , x <- libModules lib ]+ stubProfObjs <- fmap catMaybes $ sequence+ [ findFileWithExtension ["p_" ++ objExtension] [libTargetDir]+ (ModuleName.toFilePath x ++"_stub")+ | ghcVersion < Version [7,2] [] -- ghc-7.2+ does not make _stub.o files+ , x <- libModules lib ]+ stubSharedObjs <- fmap catMaybes $ sequence+ [ findFileWithExtension ["dyn_" ++ objExtension] [libTargetDir]+ (ModuleName.toFilePath x ++"_stub")+ | ghcVersion < Version [7,2] [] -- ghc-7.2+ does not make _stub.o files+ , x <- libModules lib ]++ hObjs <- Internal.getHaskellObjects implInfo lib lbi+ libTargetDir objExtension True+ hProfObjs <-+ if (withProfLib lbi)+ then Internal.getHaskellObjects implInfo lib lbi+ libTargetDir ("p_" ++ objExtension) True+ else return []+ hSharedObjs <-+ if (withSharedLib lbi)+ then Internal.getHaskellObjects implInfo lib lbi+ libTargetDir ("dyn_" ++ objExtension) False+ else return []++ unless (null hObjs && null cObjs && null stubObjs) $ do+ rpaths <- getRPaths lbi clbi++ let staticObjectFiles =+ hObjs+ ++ map (libTargetDir </>) cObjs+ ++ stubObjs+ profObjectFiles =+ hProfObjs+ ++ map (libTargetDir </>) cProfObjs+ ++ stubProfObjs+ ghciObjFiles =+ hObjs+ ++ map (libTargetDir </>) cObjs+ ++ stubObjs+ dynamicObjectFiles =+ hSharedObjs+ ++ map (libTargetDir </>) cSharedObjs+ ++ stubSharedObjs+ -- After the relocation lib is created we invoke ghc -shared+ -- with the dependencies spelled out as -package arguments+ -- and ghc invokes the linker with the proper library paths+ ghcSharedLinkArgs =+ mempty {+ ghcOptShared = toFlag True,+ ghcOptDynLinkMode = toFlag GhcDynamicOnly,+ ghcOptInputFiles = toNubListR dynamicObjectFiles,+ ghcOptOutputFile = toFlag sharedLibFilePath,+ -- For dynamic libs, Mac OS/X needs to know the install location+ -- at build time. This only applies to GHC < 7.8 - see the+ -- discussion in #1660.+ ghcOptDylibName = if (hostOS == OSX+ && ghcVersion < Version [7,8] [])+ then toFlag sharedLibInstallPath+ else mempty,+ ghcOptPackageKey = toFlag (pkgKey lbi),+ ghcOptNoAutoLinkPackages = toFlag True,+ ghcOptPackageDBs = withPackageDB lbi,+ ghcOptPackages = toNubListR $+ Internal.mkGhcOptPackages clbi ,+ ghcOptLinkLibs = toNubListR $ extraLibs libBi,+ ghcOptLinkLibPath = toNubListR $ extraLibDirs libBi,+ ghcOptRPaths = rpaths+ }++ info verbosity (show (ghcOptPackages ghcSharedLinkArgs))++ whenVanillaLib False $ do+ Ar.createArLibArchive verbosity lbi vanillaLibFilePath staticObjectFiles++ whenProfLib $ do+ Ar.createArLibArchive verbosity lbi profileLibFilePath profObjectFiles++ whenGHCiLib $ do+ (ldProg, _) <- requireProgram verbosity ldProgram (withPrograms lbi)+ Ld.combineObjectFiles verbosity ldProg+ ghciLibFilePath ghciObjFiles++ whenSharedLib False $+ runGhcProg ghcSharedLinkArgs++-- | Start a REPL without loading any source files.+startInterpreter :: Verbosity -> ProgramConfiguration -> Compiler+ -> PackageDBStack -> IO ()+startInterpreter verbosity conf comp packageDBs = do+ let replOpts = mempty {+ ghcOptMode = toFlag GhcModeInteractive,+ ghcOptPackageDBs = packageDBs+ }+ checkPackageDbStack packageDBs+ (ghcProg, _) <- requireProgram verbosity ghcProgram conf+ runGHC verbosity ghcProg comp replOpts++-- | Build an executable with GHC.+--+buildExe, replExe :: Verbosity -> Cabal.Flag (Maybe Int)+ -> PackageDescription -> LocalBuildInfo+ -> Executable -> ComponentLocalBuildInfo -> IO ()+buildExe = buildOrReplExe False+replExe = buildOrReplExe True++buildOrReplExe :: Bool -> Verbosity -> Cabal.Flag (Maybe Int)+ -> PackageDescription -> LocalBuildInfo+ -> Executable -> ComponentLocalBuildInfo -> IO ()+buildOrReplExe forRepl verbosity numJobs _pkg_descr lbi+ exe@Executable { exeName = exeName', modulePath = modPath } clbi = do++ (ghcProg, _) <- requireProgram verbosity ghcProgram (withPrograms lbi)+ let comp = compiler lbi+ implInfo = getImplInfo comp+ runGhcProg = runGHC verbosity ghcProg comp++ exeBi <- hackThreadedFlag verbosity+ comp (withProfExe lbi) (buildInfo exe)++ -- exeNameReal, the name that GHC really uses (with .exe on Windows)+ let exeNameReal = exeName' <.>+ (if takeExtension exeName' /= ('.':exeExtension)+ then exeExtension+ else "")++ let targetDir = (buildDir lbi) </> exeName'+ let exeDir = targetDir </> (exeName' ++ "-tmp")+ createDirectoryIfMissingVerbose verbosity True targetDir+ createDirectoryIfMissingVerbose verbosity True exeDir+ -- TODO: do we need to put hs-boot files into place for mutually recursive+ -- modules? FIX: what about exeName.hi-boot?++ -- Determine if program coverage should be enabled and if so, what+ -- '-hpcdir' should be.+ let isCoverageEnabled = fromFlag $ configCoverage $ configFlags lbi+ distPref = fromFlag $ configDistPref $ configFlags lbi+ hpcdir way+ | isCoverageEnabled = toFlag $ Hpc.mixDir distPref way exeName'+ | otherwise = mempty++ -- build executables++ srcMainFile <- findFile (exeDir : hsSourceDirs exeBi) modPath+ rpaths <- getRPaths lbi clbi++ let isGhcDynamic = isDynamic comp+ dynamicTooSupported = supportsDynamicToo comp+ isHaskellMain = elem (takeExtension srcMainFile) [".hs", ".lhs"]+ cSrcs = cSources exeBi ++ [srcMainFile | not isHaskellMain]+ cObjs = map (`replaceExtension` objExtension) cSrcs+ baseOpts = (componentGhcOptions verbosity lbi exeBi clbi exeDir)+ `mappend` mempty {+ ghcOptMode = toFlag GhcModeMake,+ ghcOptInputFiles = toNubListR+ [ srcMainFile | isHaskellMain],+ ghcOptInputModules = toNubListR+ [ m | not isHaskellMain, m <- exeModules exe]+ }+ staticOpts = baseOpts `mappend` mempty {+ ghcOptDynLinkMode = toFlag GhcStaticOnly,+ ghcOptHPCDir = hpcdir Hpc.Vanilla+ }+ profOpts = baseOpts `mappend` mempty {+ ghcOptProfilingMode = toFlag True,+ ghcOptHiSuffix = toFlag "p_hi",+ ghcOptObjSuffix = toFlag "p_o",+ ghcOptExtra = toNubListR $ hcProfOptions GHC exeBi,+ ghcOptHPCDir = hpcdir Hpc.Prof+ }+ dynOpts = baseOpts `mappend` mempty {+ ghcOptDynLinkMode = toFlag GhcDynamicOnly,+ ghcOptHiSuffix = toFlag "dyn_hi",+ ghcOptObjSuffix = toFlag "dyn_o",+ ghcOptExtra = toNubListR $+ hcSharedOptions GHC exeBi,+ ghcOptHPCDir = hpcdir Hpc.Dyn+ }+ dynTooOpts = staticOpts `mappend` mempty {+ ghcOptDynLinkMode = toFlag GhcStaticAndDynamic,+ ghcOptDynHiSuffix = toFlag "dyn_hi",+ ghcOptDynObjSuffix = toFlag "dyn_o",+ ghcOptHPCDir = hpcdir Hpc.Dyn+ }+ linkerOpts = mempty {+ ghcOptLinkOptions = toNubListR $ PD.ldOptions exeBi,+ ghcOptLinkLibs = toNubListR $ extraLibs exeBi,+ ghcOptLinkLibPath = toNubListR $ extraLibDirs exeBi,+ ghcOptLinkFrameworks = toNubListR $ PD.frameworks exeBi,+ ghcOptInputFiles = toNubListR+ [exeDir </> x | x <- cObjs],+ ghcOptRPaths = rpaths+ }+ replOpts = baseOpts {+ ghcOptExtra = overNubListR+ Internal.filterGhciFlags+ (ghcOptExtra baseOpts)+ }+ -- For a normal compile we do separate invocations of ghc for+ -- compiling as for linking. But for repl we have to do just+ -- the one invocation, so that one has to include all the+ -- linker stuff too, like -l flags and any .o files from C+ -- files etc.+ `mappend` linkerOpts+ `mappend` mempty {+ ghcOptMode = toFlag GhcModeInteractive,+ ghcOptOptimisation = toFlag GhcNoOptimisation+ }+ commonOpts | withProfExe lbi = profOpts+ | withDynExe lbi = dynOpts+ | otherwise = staticOpts+ compileOpts | useDynToo = dynTooOpts+ | otherwise = commonOpts+ withStaticExe = (not $ withProfExe lbi) && (not $ withDynExe lbi)++ -- For building exe's that use TH with -prof or -dynamic we actually have+ -- to build twice, once without -prof/-dynamic and then again with+ -- -prof/-dynamic. This is because the code that TH needs to run at+ -- compile time needs to be the vanilla ABI so it can be loaded up and run+ -- by the compiler.+ -- With dynamic-by-default GHC the TH object files loaded at compile-time+ -- need to be .dyn_o instead of .o.+ doingTH = EnableExtension TemplateHaskell `elem` allExtensions exeBi+ -- Should we use -dynamic-too instead of compiling twice?+ useDynToo = dynamicTooSupported && isGhcDynamic+ && doingTH && withStaticExe+ && null (hcSharedOptions GHC exeBi)+ compileTHOpts | isGhcDynamic = dynOpts+ | otherwise = staticOpts+ compileForTH+ | forRepl = False+ | useDynToo = False+ | isGhcDynamic = doingTH && (withProfExe lbi || withStaticExe)+ | otherwise = doingTH && (withProfExe lbi || withDynExe lbi)++ linkOpts = commonOpts `mappend`+ linkerOpts `mappend` mempty {+ ghcOptLinkNoHsMain = toFlag (not isHaskellMain)+ }++ -- Build static/dynamic object files for TH, if needed.+ when compileForTH $+ runGhcProg compileTHOpts { ghcOptNoLink = toFlag True+ , ghcOptNumJobs = numJobs }++ unless forRepl $+ runGhcProg compileOpts { ghcOptNoLink = toFlag True+ , ghcOptNumJobs = numJobs }++ -- build any C sources+ unless (null cSrcs) $ do+ info verbosity "Building C Sources..."+ sequence_+ [ do let opts = (Internal.componentCcGhcOptions verbosity implInfo lbi exeBi+ clbi exeDir filename) `mappend` mempty {+ ghcOptDynLinkMode = toFlag (if withDynExe lbi+ then GhcDynamicOnly+ else GhcStaticOnly),+ ghcOptProfilingMode = toFlag (withProfExe lbi)+ }+ odir = fromFlag (ghcOptObjDir opts)+ createDirectoryIfMissingVerbose verbosity True odir+ runGhcProg opts+ | filename <- cSrcs ]++ -- TODO: problem here is we need the .c files built first, so we can load them+ -- with ghci, but .c files can depend on .h files generated by ghc by ffi+ -- exports.+ when forRepl $ runGhcProg replOpts++ -- link:+ unless forRepl $ do+ info verbosity "Linking..."+ runGhcProg linkOpts { ghcOptOutputFile = toFlag (targetDir </> exeNameReal) }++-- | Calculate the RPATHs for the component we are building.+--+-- Calculates relative RPATHs when 'relocatable' is set.+getRPaths :: LocalBuildInfo+ -> ComponentLocalBuildInfo -- ^ Component we are building+ -> IO (NubListR FilePath)+getRPaths lbi clbi | supportRPaths hostOS = do+ libraryPaths <- depLibraryPaths False (relocatable lbi) lbi clbi+ let hostPref = case hostOS of+ OSX -> "@loader_path"+ _ -> "$ORIGIN"+ relPath p = if isRelative p then hostPref </> p else p+ rpaths = toNubListR (map relPath libraryPaths)+ return rpaths+ where+ (Platform _ hostOS) = hostPlatform lbi++ -- The list of RPath-supported operating systems below reflects the+ -- platforms on which Cabal's RPATH handling is tested. It does _NOT_+ -- reflect whether the OS supports RPATH.++ -- E.g. when this comment was written, the *BSD operating systems were+ -- untested with regards to Cabal RPATH handling, and were hence set to+ -- 'False', while those operating systems themselves do support RPATH.+ supportRPaths Linux = True+ supportRPaths Windows = False+ supportRPaths OSX = True+ supportRPaths FreeBSD = False+ supportRPaths OpenBSD = False+ supportRPaths NetBSD = False+ supportRPaths DragonFly = False+ supportRPaths Solaris = False+ supportRPaths AIX = False+ supportRPaths HPUX = False+ supportRPaths IRIX = False+ supportRPaths HaLVM = False+ supportRPaths IOS = False+ supportRPaths Ghcjs = False+ supportRPaths (OtherOS _) = False+ -- Do _not_ add a default case so that we get a warning here when a new OS+ -- is added.++getRPaths _ _ = return mempty++-- | Filter the "-threaded" flag when profiling as it does not+-- work with ghc-6.8 and older.+hackThreadedFlag :: Verbosity -> Compiler -> Bool -> BuildInfo -> IO BuildInfo+hackThreadedFlag verbosity comp prof bi+ | not mustFilterThreaded = return bi+ | otherwise = do+ warn verbosity $ "The ghc flag '-threaded' is not compatible with "+ ++ "profiling in ghc-6.8 and older. It will be disabled."+ return bi { options = filterHcOptions (/= "-threaded") (options bi) }+ where+ mustFilterThreaded = prof && compilerVersion comp < Version [6, 10] []+ && "-threaded" `elem` hcOptions GHC bi+ filterHcOptions p hcoptss =+ [ (hc, if hc == GHC then filter p opts else opts)+ | (hc, opts) <- hcoptss ]+++-- | Extracts a String representing a hash of the ABI of a built+-- library. It can fail if the library has not yet been built.+--+libAbiHash :: Verbosity -> PackageDescription -> LocalBuildInfo+ -> Library -> ComponentLocalBuildInfo -> IO String+libAbiHash verbosity _pkg_descr lbi lib clbi = do+ libBi <- hackThreadedFlag verbosity+ (compiler lbi) (withProfLib lbi) (libBuildInfo lib)+ let+ comp = compiler lbi+ vanillaArgs =+ (componentGhcOptions verbosity lbi libBi clbi (buildDir lbi))+ `mappend` mempty {+ ghcOptMode = toFlag GhcModeAbiHash,+ ghcOptPackageKey = toFlag (pkgKey lbi),+ ghcOptInputModules = toNubListR $ exposedModules lib+ }+ sharedArgs = vanillaArgs `mappend` mempty {+ ghcOptDynLinkMode = toFlag GhcDynamicOnly,+ ghcOptFPic = toFlag True,+ ghcOptHiSuffix = toFlag "dyn_hi",+ ghcOptObjSuffix = toFlag "dyn_o",+ ghcOptExtra = toNubListR $ hcSharedOptions GHC libBi+ }+ profArgs = vanillaArgs `mappend` mempty {+ ghcOptProfilingMode = toFlag True,+ ghcOptHiSuffix = toFlag "p_hi",+ ghcOptObjSuffix = toFlag "p_o",+ ghcOptExtra = toNubListR $ hcProfOptions GHC libBi+ }+ ghcArgs = if withVanillaLib lbi then vanillaArgs+ else if withSharedLib lbi then sharedArgs+ else if withProfLib lbi then profArgs+ else error "libAbiHash: Can't find an enabled library way"+ --+ (ghcProg, _) <- requireProgram verbosity ghcProgram (withPrograms lbi)+ hash <- getProgramInvocationOutput verbosity (ghcInvocation ghcProg comp ghcArgs)+ return (takeWhile (not . isSpace) hash)++componentGhcOptions :: Verbosity -> LocalBuildInfo+ -> BuildInfo -> ComponentLocalBuildInfo -> FilePath+ -> GhcOptions+componentGhcOptions = Internal.componentGhcOptions++-- -----------------------------------------------------------------------------+-- Installing++-- |Install executables for GHC.+installExe :: Verbosity+ -> LocalBuildInfo+ -> InstallDirs FilePath -- ^Where to copy the files to+ -> FilePath -- ^Build location+ -> (FilePath, FilePath) -- ^Executable (prefix,suffix)+ -> PackageDescription+ -> Executable+ -> IO ()+installExe verbosity lbi installDirs buildPref+ (progprefix, progsuffix) _pkg exe = do+ let binDir = bindir installDirs+ createDirectoryIfMissingVerbose verbosity True binDir+ let exeFileName = exeName exe <.> exeExtension+ fixedExeBaseName = progprefix ++ exeName exe ++ progsuffix+ installBinary dest = do+ installExecutableFile verbosity+ (buildPref </> exeName exe </> exeFileName)+ (dest <.> exeExtension)+ when (stripExes lbi) $+ Strip.stripExe verbosity (hostPlatform lbi) (withPrograms lbi)+ (dest <.> exeExtension)+ installBinary (binDir </> fixedExeBaseName)++-- |Install for ghc, .hi, .a and, if --with-ghci given, .o+installLib :: Verbosity+ -> LocalBuildInfo+ -> FilePath -- ^install location+ -> FilePath -- ^install location for dynamic libraries+ -> FilePath -- ^Build location+ -> PackageDescription+ -> Library+ -> ComponentLocalBuildInfo+ -> IO ()+installLib verbosity lbi targetDir dynlibTargetDir builtDir _pkg lib clbi = do+ -- copy .hi files over:+ whenVanilla $ copyModuleFiles "hi"+ whenProf $ copyModuleFiles "p_hi"+ whenShared $ copyModuleFiles "dyn_hi"++ -- copy the built library files over:+ whenVanilla $ mapM_ (installOrdinary builtDir targetDir) vanillaLibNames+ whenProf $ mapM_ (installOrdinary builtDir targetDir) profileLibNames+ whenGHCi $ mapM_ (installOrdinary builtDir targetDir) ghciLibNames+ whenShared $ mapM_ (installShared builtDir dynlibTargetDir) sharedLibNames++ where+ install isShared srcDir dstDir name = do+ let src = srcDir </> name+ dst = dstDir </> name+ createDirectoryIfMissingVerbose verbosity True dstDir+ if isShared+ then do when (stripLibs lbi) $ Strip.stripLib verbosity+ (hostPlatform lbi) (withPrograms lbi) src+ installExecutableFile verbosity src dst+ else installOrdinaryFile verbosity src dst++ installOrdinary = install False+ installShared = install True++ copyModuleFiles ext =+ findModuleFiles [builtDir] [ext] (libModules lib)+ >>= installOrdinaryFiles verbosity targetDir++ cid = compilerId (compiler lbi)+ libNames = componentLibraries clbi+ vanillaLibNames = map mkLibName libNames+ profileLibNames = map mkProfLibName libNames+ ghciLibNames = map Internal.mkGHCiLibName libNames+ sharedLibNames = map (mkSharedLibName cid) libNames++ hasLib = not $ null (libModules lib)+ && null (cSources (libBuildInfo lib))+ whenVanilla = when (hasLib && withVanillaLib lbi)+ whenProf = when (hasLib && withProfLib lbi)+ whenGHCi = when (hasLib && withGHCiLib lbi)+ whenShared = when (hasLib && withSharedLib lbi)++-- -----------------------------------------------------------------------------+-- Registering++hcPkgInfo :: ProgramConfiguration -> HcPkg.HcPkgInfo+hcPkgInfo conf = HcPkg.HcPkgInfo { HcPkg.hcPkgProgram = ghcPkgProg+ , HcPkg.noPkgDbStack = v < [6,9]+ , HcPkg.noVerboseFlag = v < [6,11]+ , HcPkg.flagPackageConf = v < [7,5]+ }+ where+ v = versionBranch ver+ Just ghcPkgProg = lookupProgram ghcPkgProgram conf+ Just ver = programVersion ghcPkgProg++registerPackage+ :: Verbosity+ -> InstalledPackageInfo+ -> PackageDescription+ -> LocalBuildInfo+ -> Bool+ -> PackageDBStack+ -> IO ()+registerPackage verbosity installedPkgInfo _pkg lbi _inplace packageDbs =+ HcPkg.reregister (hcPkgInfo $ withPrograms lbi) verbosity+ packageDbs (Right installedPkgInfo)++pkgRoot :: Verbosity -> LocalBuildInfo -> PackageDB -> IO FilePath+pkgRoot verbosity lbi = pkgRoot'+ where+ pkgRoot' GlobalPackageDB =+ let Just ghcProg = lookupProgram ghcProgram (withPrograms lbi)+ in fmap takeDirectory (getGlobalPackageDB verbosity ghcProg)+ pkgRoot' UserPackageDB = do+ appDir <- getAppUserDataDirectory "ghc"+ let ver = compilerVersion (compiler lbi)+ subdir = System.Info.arch ++ '-':System.Info.os ++ '-':showVersion ver+ rootDir = appDir </> subdir+ -- We must create the root directory for the user package database if it+ -- does not yet exists. Otherwise '${pkgroot}' will resolve to a+ -- directory at the time of 'ghc-pkg register', and registration will+ -- fail.+ createDirectoryIfMissing True rootDir+ return rootDir+ pkgRoot' (SpecificPackageDB fp) = return (takeDirectory fp)++-- -----------------------------------------------------------------------------+-- Utils++isDynamic :: Compiler -> Bool+isDynamic = Internal.ghcLookupProperty "GHC Dynamic"++supportsDynamicToo :: Compiler -> Bool+supportsDynamicToo = Internal.ghcLookupProperty "Support dynamic-too"
Distribution/Simple/GHC/IPI641.hs view
@@ -9,12 +9,12 @@ -- module Distribution.Simple.GHC.IPI641 (- InstalledPackageInfo,+ InstalledPackageInfo(..), toCurrent, ) where import qualified Distribution.InstalledPackageInfo as Current-import qualified Distribution.Package as Current hiding (depends)+import qualified Distribution.Package as Current hiding (depends, installedPackageId) import Distribution.Text (display) import Distribution.Simple.GHC.IPI642@@ -65,9 +65,13 @@ mkInstalledPackageId = Current.InstalledPackageId . display toCurrent :: InstalledPackageInfo -> Current.InstalledPackageInfo-toCurrent ipi@InstalledPackageInfo{} = Current.InstalledPackageInfo {+toCurrent ipi@InstalledPackageInfo{} =+ let pid = convertPackageId (package ipi)+ mkExposedModule m = Current.ExposedModule m Nothing Nothing+ in Current.InstalledPackageInfo { Current.installedPackageId = mkInstalledPackageId (convertPackageId (package ipi)),- Current.sourcePackageId = convertPackageId (package ipi),+ Current.sourcePackageId = pid,+ Current.packageKey = Current.OldPackageKey pid, Current.license = convertLicense (license ipi), Current.copyright = copyright ipi, Current.maintainer = maintainer ipi,@@ -79,22 +83,24 @@ Current.description = description ipi, Current.category = category ipi, Current.exposed = exposed ipi,- Current.exposedModules = map convertModuleName (exposedModules ipi),+ Current.exposedModules = map (mkExposedModule . convertModuleName) (exposedModules ipi),+ Current.instantiatedWith = [], Current.hiddenModules = map convertModuleName (hiddenModules ipi), Current.trusted = Current.trusted Current.emptyInstalledPackageInfo, Current.importDirs = importDirs ipi, Current.libraryDirs = libraryDirs ipi,+ Current.dataDir = "", Current.hsLibraries = hsLibraries ipi, Current.extraLibraries = extraLibraries ipi, Current.extraGHCiLibraries = [], Current.includeDirs = includeDirs ipi, Current.includes = includes ipi, Current.depends = map (mkInstalledPackageId.convertPackageId) (depends ipi),- Current.hugsOptions = hugsOptions ipi, Current.ccOptions = ccOptions ipi, Current.ldOptions = ldOptions ipi, Current.frameworkDirs = frameworkDirs ipi, Current.frameworks = frameworks ipi, Current.haddockInterfaces = haddockInterfaces ipi,- Current.haddockHTMLs = haddockHTMLs ipi+ Current.haddockHTMLs = haddockHTMLs ipi,+ Current.pkgRoot = Nothing }
Distribution/Simple/GHC/IPI642.hs view
@@ -9,7 +9,7 @@ -- module Distribution.Simple.GHC.IPI642 (- InstalledPackageInfo,+ InstalledPackageInfo(..), toCurrent, -- Don't use these, they're only for conversion purposes@@ -19,7 +19,7 @@ ) where import qualified Distribution.InstalledPackageInfo as Current-import qualified Distribution.Package as Current hiding (depends)+import qualified Distribution.Package as Current hiding (depends, installedPackageId) import qualified Distribution.License as Current import Distribution.Version (Version)@@ -100,9 +100,13 @@ convertLicense OtherLicense = Current.OtherLicense toCurrent :: InstalledPackageInfo -> Current.InstalledPackageInfo-toCurrent ipi@InstalledPackageInfo{} = Current.InstalledPackageInfo {+toCurrent ipi@InstalledPackageInfo{} =+ let pid = convertPackageId (package ipi)+ mkExposedModule m = Current.ExposedModule m Nothing Nothing+ in Current.InstalledPackageInfo { Current.installedPackageId = mkInstalledPackageId (convertPackageId (package ipi)),- Current.sourcePackageId = convertPackageId (package ipi),+ Current.sourcePackageId = pid,+ Current.packageKey = Current.OldPackageKey pid, Current.license = convertLicense (license ipi), Current.copyright = copyright ipi, Current.maintainer = maintainer ipi,@@ -114,22 +118,24 @@ Current.description = description ipi, Current.category = category ipi, Current.exposed = exposed ipi,- Current.exposedModules = map convertModuleName (exposedModules ipi),+ Current.exposedModules = map (mkExposedModule . convertModuleName) (exposedModules ipi), Current.hiddenModules = map convertModuleName (hiddenModules ipi),+ Current.instantiatedWith = [], Current.trusted = Current.trusted Current.emptyInstalledPackageInfo, Current.importDirs = importDirs ipi, Current.libraryDirs = libraryDirs ipi,+ Current.dataDir = "", Current.hsLibraries = hsLibraries ipi, Current.extraLibraries = extraLibraries ipi, Current.extraGHCiLibraries = extraGHCiLibraries ipi, Current.includeDirs = includeDirs ipi, Current.includes = includes ipi, Current.depends = map (mkInstalledPackageId.convertPackageId) (depends ipi),- Current.hugsOptions = hugsOptions ipi, Current.ccOptions = ccOptions ipi, Current.ldOptions = ldOptions ipi, Current.frameworkDirs = frameworkDirs ipi, Current.frameworks = frameworks ipi, Current.haddockInterfaces = haddockInterfaces ipi,- Current.haddockHTMLs = haddockHTMLs ipi+ Current.haddockHTMLs = haddockHTMLs ipi,+ Current.pkgRoot = Nothing }
+ Distribution/Simple/GHC/ImplInfo.hs view
@@ -0,0 +1,108 @@+-----------------------------------------------------------------------------+-- |+-- Module : Distribution.Simple.GHC.ImplInfo+--+-- Maintainer : cabal-devel@haskell.org+-- Portability : portable+--+-- This module contains the data structure describing invocation+-- details for a GHC or GHC-derived compiler, such as supported flags+-- and workarounds for bugs.++module Distribution.Simple.GHC.ImplInfo (+ GhcImplInfo(..), getImplInfo,+ ghcVersionImplInfo, ghcjsVersionImplInfo, lhcVersionImplInfo+ ) where++import Distribution.Simple.Compiler+ ( Compiler(..), CompilerId(..), CompilerFlavor(..)+ , compilerFlavor, compilerVersion, compilerCompatVersion )+import Distribution.Version ( Version(..) )++{- |+ Information about features and quirks of a GHC-based implementation.++ Compiler flavors based on GHC behave similarly enough that some of+ the support code for them is shared. Every implementation has its+ own peculiarities, that may or may not be a direct result of the+ underlying GHC version. This record keeps track of these differences.++ All shared code (i.e. everything not in the Distribution.Simple.FLAVOR+ module) should use implementation info rather than version numbers+ to test for supported features.+-}++data GhcImplInfo = GhcImplInfo+ { hasCcOdirBug :: Bool -- ^ bug in -odir handling for C compilations.+ , flagInfoLanguages :: Bool -- ^ --info and --supported-languages flags+ , fakeRecordPuns :: Bool -- ^ use -XRecordPuns for NamedFieldPuns+ , flagStubdir :: Bool -- ^ -stubdir flag supported+ , flagOutputDir :: Bool -- ^ -outputdir flag supported+ , noExtInSplitSuffix :: Bool -- ^ split-obj suffix does not contain p_o ext+ , flagFfiIncludes :: Bool -- ^ -#include on command line for FFI includes+ , flagBuildingCabalPkg :: Bool -- ^ -fbuilding-cabal-package flag supported+ , flagPackageId :: Bool -- ^ -package-id / -package flags supported+ , separateGccMingw :: Bool -- ^ mingw and gcc are in separate directories+ , supportsHaskell2010 :: Bool -- ^ -XHaskell2010 and -XHaskell98 flags+ , reportsNoExt :: Bool -- ^ --supported-languages gives Ext and NoExt+ , alwaysNondecIndent :: Bool -- ^ NondecreasingIndentation is always on+ , flagGhciScript :: Bool -- ^ -ghci-script flag supported+ , flagPackageConf :: Bool -- ^ use package-conf instead of package-db+ , flagDebugInfo :: Bool -- ^ -g flag supported+ }++getImplInfo :: Compiler -> GhcImplInfo+getImplInfo comp =+ case compilerFlavor comp of+ GHC -> ghcVersionImplInfo (compilerVersion comp)+ LHC -> lhcVersionImplInfo (compilerVersion comp)+ GHCJS -> case compilerCompatVersion GHC comp of+ Just ghcVer -> ghcjsVersionImplInfo (compilerVersion comp) ghcVer+ _ -> error ("Distribution.Simple.GHC.Props.getImplProps: " +++ "could not find GHC version for GHCJS compiler")+ x -> error ("Distribution.Simple.GHC.Props.getImplProps only works" +++ "for GHC-like compilers (GHC, GHCJS, LHC)" +++ ", but found " ++ show x)++ghcVersionImplInfo :: Version -> GhcImplInfo+ghcVersionImplInfo (Version v _) = GhcImplInfo+ { hasCcOdirBug = v < [6,4,1]+ , flagInfoLanguages = v >= [6,7]+ , fakeRecordPuns = v >= [6,8] && v < [6,10]+ , flagStubdir = v >= [6,8]+ , flagOutputDir = v >= [6,10]+ , noExtInSplitSuffix = v < [6,11]+ , flagFfiIncludes = v < [6,11]+ , flagBuildingCabalPkg = v >= [6,11]+ , flagPackageId = v > [6,11]+ , separateGccMingw = v < [6,12]+ , supportsHaskell2010 = v >= [7]+ , reportsNoExt = v >= [7]+ , alwaysNondecIndent = v < [7,1]+ , flagGhciScript = v >= [7,2]+ , flagPackageConf = v < [7,5]+ , flagDebugInfo = v >= [7,10]+ }++ghcjsVersionImplInfo :: Version -> Version -> GhcImplInfo+ghcjsVersionImplInfo _ghcjsVer _ghcVer = GhcImplInfo+ { hasCcOdirBug = False+ , flagInfoLanguages = True+ , fakeRecordPuns = False+ , flagStubdir = True+ , flagOutputDir = True+ , noExtInSplitSuffix = False+ , flagFfiIncludes = False+ , flagBuildingCabalPkg = True+ , flagPackageId = True+ , separateGccMingw = False+ , supportsHaskell2010 = True+ , reportsNoExt = True+ , alwaysNondecIndent = False+ , flagGhciScript = True+ , flagPackageConf = False+ , flagDebugInfo = False+ }++lhcVersionImplInfo :: Version -> GhcImplInfo+lhcVersionImplInfo = ghcVersionImplInfo
+ Distribution/Simple/GHC/Internal.hs view
@@ -0,0 +1,489 @@+-----------------------------------------------------------------------------+-- |+-- Module : Distribution.Simple.GHC.Internal+-- Copyright : Isaac Jones 2003-2007+--+-- Maintainer : cabal-devel@haskell.org+-- Portability : portable+--+-- This module contains functions shared by GHC (Distribution.Simple.GHC)+-- and GHC-derived compilers.++module Distribution.Simple.GHC.Internal (+ configureToolchain,+ getLanguages,+ getExtensions,+ targetPlatform,+ getGhcInfo,+ componentCcGhcOptions,+ componentGhcOptions,+ mkGHCiLibName,+ filterGhciFlags,+ ghcLookupProperty,+ getHaskellObjects,+ mkGhcOptPackages,+ substTopDir,+ checkPackageDbEnvVar+ ) where++import Distribution.Simple.GHC.ImplInfo ( GhcImplInfo (..) )+import Distribution.Package+ ( InstalledPackageId, PackageId )+import Distribution.InstalledPackageInfo+ ( InstalledPackageInfo )+import qualified Distribution.InstalledPackageInfo as InstalledPackageInfo+ ( InstalledPackageInfo_(..) )+import Distribution.PackageDescription as PD+ ( BuildInfo(..), Library(..), libModules+ , hcOptions, usedExtensions, ModuleRenaming, lookupRenaming )+import Distribution.Compat.Exception ( catchExit, catchIO )+import Distribution.Simple.Compiler+ ( CompilerFlavor(..), Compiler(..), DebugInfoLevel(..), OptimisationLevel(..) )+import Distribution.Simple.Program.GHC+import Distribution.Simple.Setup+ ( toFlag )+import qualified Distribution.ModuleName as ModuleName+import Distribution.Simple.Program+ ( Program(..), ConfiguredProgram(..), ProgramConfiguration+ , ProgramLocation(..), ProgramSearchPath, ProgramSearchPathEntry(..)+ , rawSystemProgram, rawSystemProgramStdout, programPath+ , addKnownProgram, arProgram, ldProgram, gccProgram, stripProgram+ , getProgramOutput )+import Distribution.Simple.Program.Types ( suppressOverrideArgs )+import Distribution.Simple.LocalBuildInfo+ ( LocalBuildInfo(..), ComponentLocalBuildInfo(..)+ , LibraryName(..) )+import Distribution.Simple.Utils+import Distribution.Simple.BuildPaths+import Distribution.System ( buildOS, OS(..), Platform, platformFromTriple )+import Distribution.Text ( display, simpleParse )+import Distribution.Utils.NubList ( toNubListR )+import Distribution.Verbosity+import Language.Haskell.Extension+ ( Language(..), Extension(..), KnownExtension(..) )++import qualified Data.Map as M+import Data.Char ( isSpace )+import Data.Maybe ( fromMaybe, maybeToList, isJust )+import Control.Monad ( unless, when )+import Data.Monoid ( Monoid(..) )+import System.Directory ( getDirectoryContents, getTemporaryDirectory )+import System.Environment ( getEnv )+import System.FilePath ( (</>), (<.>), takeExtension, takeDirectory )+import System.IO ( hClose, hPutStrLn )++targetPlatform :: [(String, String)] -> Maybe Platform+targetPlatform ghcInfo = platformFromTriple =<< lookup "Target platform" ghcInfo++-- | Adjust the way we find and configure gcc and ld+--+configureToolchain :: GhcImplInfo+ -> ConfiguredProgram+ -> M.Map String String+ -> ProgramConfiguration+ -> ProgramConfiguration+configureToolchain implInfo ghcProg ghcInfo =+ addKnownProgram gccProgram {+ programFindLocation = findProg gccProgram extraGccPath,+ programPostConf = configureGcc+ }+ . addKnownProgram ldProgram {+ programFindLocation = findProg ldProgram extraLdPath,+ programPostConf = configureLd+ }+ . addKnownProgram arProgram {+ programFindLocation = findProg arProgram extraArPath+ }+ . addKnownProgram stripProgram {+ programFindLocation = findProg stripProgram extraStripPath+ }+ where+ compilerDir = takeDirectory (programPath ghcProg)+ baseDir = takeDirectory compilerDir+ mingwBinDir = baseDir </> "mingw" </> "bin"+ libDir = baseDir </> "gcc-lib"+ includeDir = baseDir </> "include" </> "mingw"+ isWindows = case buildOS of Windows -> True; _ -> False+ binPrefix = ""++ mkExtraPath :: Maybe FilePath -> FilePath -> [FilePath]+ mkExtraPath mbPath mingwPath | isWindows = mbDir ++ [mingwPath]+ | otherwise = mbDir+ where+ mbDir = maybeToList . fmap takeDirectory $ mbPath++ extraGccPath = mkExtraPath mbGccLocation windowsExtraGccDir+ extraLdPath = mkExtraPath mbLdLocation windowsExtraLdDir+ extraArPath = mkExtraPath mbArLocation windowsExtraArDir+ extraStripPath = mkExtraPath mbStripLocation windowsExtraStripDir++ -- on Windows finding and configuring ghc's gcc & binutils is a bit special+ (windowsExtraGccDir, windowsExtraLdDir,+ windowsExtraArDir, windowsExtraStripDir)+ | separateGccMingw implInfo = (baseDir, libDir, libDir, libDir)+ | otherwise = -- GHC >= 6.12+ let b = mingwBinDir </> binPrefix+ in (b, b, b, b)++ findProg :: Program -> [FilePath]+ -> Verbosity -> ProgramSearchPath -> IO (Maybe FilePath)+ findProg prog extraPath v searchpath =+ programFindLocation prog v searchpath'+ where+ searchpath' = (map ProgramSearchPathDir extraPath) ++ searchpath++ -- Read tool locations from the 'ghc --info' output. Useful when+ -- cross-compiling.+ mbGccLocation = M.lookup "C compiler command" ghcInfo+ mbLdLocation = M.lookup "ld command" ghcInfo+ mbArLocation = M.lookup "ar command" ghcInfo+ mbStripLocation = M.lookup "strip command" ghcInfo++ ccFlags = getFlags "C compiler flags"+ gccLinkerFlags = getFlags "Gcc Linker flags"+ ldLinkerFlags = getFlags "Ld Linker flags"++ getFlags key = case M.lookup key ghcInfo of+ Nothing -> []+ Just flags ->+ case reads flags of+ [(args, "")] -> args+ _ -> [] -- XXX Should should be an error really++ configureGcc :: Verbosity -> ConfiguredProgram -> IO ConfiguredProgram+ configureGcc v gccProg = do+ gccProg' <- configureGcc' v gccProg+ return gccProg' {+ programDefaultArgs = programDefaultArgs gccProg'+ ++ ccFlags ++ gccLinkerFlags+ }++ configureGcc' :: Verbosity -> ConfiguredProgram -> IO ConfiguredProgram+ configureGcc'+ | isWindows = \_ gccProg -> case programLocation gccProg of+ -- if it's found on system then it means we're using the result+ -- of programFindLocation above rather than a user-supplied path+ -- Pre GHC 6.12, that meant we should add these flags to tell+ -- ghc's gcc where it lives and thus where gcc can find its+ -- various files:+ FoundOnSystem {}+ | separateGccMingw implInfo ->+ return gccProg { programDefaultArgs = ["-B" ++ libDir,+ "-I" ++ includeDir] }+ _ -> return gccProg+ | otherwise = \_ gccProg -> return gccProg++ configureLd :: Verbosity -> ConfiguredProgram -> IO ConfiguredProgram+ configureLd v ldProg = do+ ldProg' <- configureLd' v ldProg+ return ldProg' {+ programDefaultArgs = programDefaultArgs ldProg' ++ ldLinkerFlags+ }++ -- we need to find out if ld supports the -x flag+ configureLd' :: Verbosity -> ConfiguredProgram -> IO ConfiguredProgram+ configureLd' verbosity ldProg = do+ tempDir <- getTemporaryDirectory+ ldx <- withTempFile tempDir ".c" $ \testcfile testchnd ->+ withTempFile tempDir ".o" $ \testofile testohnd -> do+ hPutStrLn testchnd "int foo() { return 0; }"+ hClose testchnd; hClose testohnd+ rawSystemProgram verbosity ghcProg ["-c", testcfile,+ "-o", testofile]+ withTempFile tempDir ".o" $ \testofile' testohnd' ->+ do+ hClose testohnd'+ _ <- rawSystemProgramStdout verbosity ldProg+ ["-x", "-r", testofile, "-o", testofile']+ return True+ `catchIO` (\_ -> return False)+ `catchExit` (\_ -> return False)+ if ldx+ then return ldProg { programDefaultArgs = ["-x"] }+ else return ldProg++getLanguages :: Verbosity -> GhcImplInfo -> ConfiguredProgram+ -> IO [(Language, String)]+getLanguages _ implInfo _+ -- TODO: should be using --supported-languages rather than hard coding+ | supportsHaskell2010 implInfo = return [(Haskell98, "-XHaskell98")+ ,(Haskell2010, "-XHaskell2010")]+ | otherwise = return [(Haskell98, "")]++getGhcInfo :: Verbosity -> GhcImplInfo -> ConfiguredProgram+ -> IO [(String, String)]+getGhcInfo verbosity implInfo ghcProg+ | flagInfoLanguages implInfo = do+ xs <- getProgramOutput verbosity (suppressOverrideArgs ghcProg)+ ["--info"]+ case reads xs of+ [(i, ss)]+ | all isSpace ss ->+ return i+ _ ->+ die "Can't parse --info output of GHC"+ | otherwise =+ return []++getExtensions :: Verbosity -> GhcImplInfo -> ConfiguredProgram+ -> IO [(Extension, String)]+getExtensions verbosity implInfo ghcProg+ | flagInfoLanguages implInfo = do+ str <- getProgramOutput verbosity (suppressOverrideArgs ghcProg)+ ["--supported-languages"]+ let extStrs = if reportsNoExt implInfo+ then lines str+ else -- Older GHCs only gave us either Foo or NoFoo,+ -- so we have to work out the other one ourselves+ [ extStr''+ | extStr <- lines str+ , let extStr' = case extStr of+ 'N' : 'o' : xs -> xs+ _ -> "No" ++ extStr+ , extStr'' <- [extStr, extStr']+ ]+ let extensions0 = [ (ext, "-X" ++ display ext)+ | Just ext <- map simpleParse extStrs ]+ extensions1 = if fakeRecordPuns implInfo+ then -- ghc-6.8 introduced RecordPuns however it+ -- should have been NamedFieldPuns. We now+ -- encourage packages to use NamedFieldPuns+ -- so for compatibility we fake support for+ -- it in ghc-6.8 by making it an alias for+ -- the old RecordPuns extension.+ (EnableExtension NamedFieldPuns, "-XRecordPuns") :+ (DisableExtension NamedFieldPuns, "-XNoRecordPuns") :+ extensions0+ else extensions0+ extensions2 = if alwaysNondecIndent implInfo+ then -- ghc-7.2 split NondecreasingIndentation off+ -- into a proper extension. Before that it+ -- was always on.+ (EnableExtension NondecreasingIndentation, "") :+ (DisableExtension NondecreasingIndentation, "") :+ extensions1+ else extensions1+ return extensions2++ | otherwise = return oldLanguageExtensions++-- | For GHC 6.6.x and earlier, the mapping from supported extensions to flags+oldLanguageExtensions :: [(Extension, String)]+oldLanguageExtensions =+ let doFlag (f, (enable, disable)) = [(EnableExtension f, enable),+ (DisableExtension f, disable)]+ fglasgowExts = ("-fglasgow-exts",+ "") -- This is wrong, but we don't want to turn+ -- all the extensions off when asked to just+ -- turn one off+ fFlag flag = ("-f" ++ flag, "-fno-" ++ flag)+ in concatMap doFlag+ [(OverlappingInstances , fFlag "allow-overlapping-instances")+ ,(TypeSynonymInstances , fglasgowExts)+ ,(TemplateHaskell , fFlag "th")+ ,(ForeignFunctionInterface , fFlag "ffi")+ ,(MonomorphismRestriction , fFlag "monomorphism-restriction")+ ,(MonoPatBinds , fFlag "mono-pat-binds")+ ,(UndecidableInstances , fFlag "allow-undecidable-instances")+ ,(IncoherentInstances , fFlag "allow-incoherent-instances")+ ,(Arrows , fFlag "arrows")+ ,(Generics , fFlag "generics")+ ,(ImplicitPrelude , fFlag "implicit-prelude")+ ,(ImplicitParams , fFlag "implicit-params")+ ,(CPP , ("-cpp", ""{- Wrong -}))+ ,(BangPatterns , fFlag "bang-patterns")+ ,(KindSignatures , fglasgowExts)+ ,(RecursiveDo , fglasgowExts)+ ,(ParallelListComp , fglasgowExts)+ ,(MultiParamTypeClasses , fglasgowExts)+ ,(FunctionalDependencies , fglasgowExts)+ ,(Rank2Types , fglasgowExts)+ ,(RankNTypes , fglasgowExts)+ ,(PolymorphicComponents , fglasgowExts)+ ,(ExistentialQuantification , fglasgowExts)+ ,(ScopedTypeVariables , fFlag "scoped-type-variables")+ ,(FlexibleContexts , fglasgowExts)+ ,(FlexibleInstances , fglasgowExts)+ ,(EmptyDataDecls , fglasgowExts)+ ,(PatternGuards , fglasgowExts)+ ,(GeneralizedNewtypeDeriving , fglasgowExts)+ ,(MagicHash , fglasgowExts)+ ,(UnicodeSyntax , fglasgowExts)+ ,(PatternSignatures , fglasgowExts)+ ,(UnliftedFFITypes , fglasgowExts)+ ,(LiberalTypeSynonyms , fglasgowExts)+ ,(TypeOperators , fglasgowExts)+ ,(GADTs , fglasgowExts)+ ,(RelaxedPolyRec , fglasgowExts)+ ,(ExtendedDefaultRules , fFlag "extended-default-rules")+ ,(UnboxedTuples , fglasgowExts)+ ,(DeriveDataTypeable , fglasgowExts)+ ,(ConstrainedClassMethods , fglasgowExts)+ ]++componentCcGhcOptions :: Verbosity -> GhcImplInfo -> LocalBuildInfo+ -> BuildInfo -> ComponentLocalBuildInfo+ -> FilePath -> FilePath+ -> GhcOptions+componentCcGhcOptions verbosity implInfo lbi bi clbi pref filename =+ mempty {+ ghcOptVerbosity = toFlag verbosity,+ ghcOptMode = toFlag GhcModeCompile,+ ghcOptInputFiles = toNubListR [filename],++ ghcOptCppIncludePath = toNubListR $ [autogenModulesDir lbi, odir]+ ++ PD.includeDirs bi,+ ghcOptPackageDBs = withPackageDB lbi,+ ghcOptPackages = toNubListR $ mkGhcOptPackages clbi,+ ghcOptCcOptions = toNubListR $+ (case withOptimization lbi of+ NoOptimisation -> []+ _ -> ["-O2"]) +++ (case withDebugInfo lbi of+ NoDebugInfo -> []+ MinimalDebugInfo -> ["-g1"]+ NormalDebugInfo -> ["-g"]+ MaximalDebugInfo -> ["-g3"]) +++ PD.ccOptions bi,+ ghcOptObjDir = toFlag odir+ }+ where+ odir | hasCcOdirBug implInfo = pref </> takeDirectory filename+ | otherwise = pref+ -- ghc 6.4.0 had a bug in -odir handling for C compilations.++componentGhcOptions :: Verbosity -> LocalBuildInfo+ -> BuildInfo -> ComponentLocalBuildInfo -> FilePath+ -> GhcOptions+componentGhcOptions verbosity lbi bi clbi odir =+ mempty {+ ghcOptVerbosity = toFlag verbosity,+ ghcOptHideAllPackages = toFlag True,+ ghcOptCabal = toFlag True,+ ghcOptPackageDBs = withPackageDB lbi,+ ghcOptPackages = toNubListR $ mkGhcOptPackages clbi,+ ghcOptSplitObjs = toFlag (splitObjs lbi),+ ghcOptSourcePathClear = toFlag True,+ ghcOptSourcePath = toNubListR $ [odir] ++ (hsSourceDirs bi)+ ++ [autogenModulesDir lbi],+ ghcOptCppIncludePath = toNubListR $ [autogenModulesDir lbi, odir]+ ++ PD.includeDirs bi,+ ghcOptCppOptions = toNubListR $ cppOptions bi,+ ghcOptCppIncludes = toNubListR $+ [autogenModulesDir lbi </> cppHeaderName],+ ghcOptFfiIncludes = toNubListR $ PD.includes bi,+ ghcOptObjDir = toFlag odir,+ ghcOptHiDir = toFlag odir,+ ghcOptStubDir = toFlag odir,+ ghcOptOutputDir = toFlag odir,+ ghcOptOptimisation = toGhcOptimisation (withOptimization lbi),+ ghcOptDebugInfo = toGhcDebugInfo (withDebugInfo lbi),+ ghcOptExtra = toNubListR $ hcOptions GHC bi,+ ghcOptLanguage = toFlag (fromMaybe Haskell98 (defaultLanguage bi)),+ -- Unsupported extensions have already been checked by configure+ ghcOptExtensions = toNubListR $ usedExtensions bi,+ ghcOptExtensionMap = M.fromList . compilerExtensions $ (compiler lbi)+ }+ where+ toGhcOptimisation NoOptimisation = mempty --TODO perhaps override?+ toGhcOptimisation NormalOptimisation = toFlag GhcNormalOptimisation+ toGhcOptimisation MaximumOptimisation = toFlag GhcMaximumOptimisation++ -- GHC doesn't support debug info levels yet.+ toGhcDebugInfo NoDebugInfo = mempty+ toGhcDebugInfo MinimalDebugInfo = toFlag True+ toGhcDebugInfo NormalDebugInfo = toFlag True+ toGhcDebugInfo MaximalDebugInfo = toFlag True++-- | Strip out flags that are not supported in ghci+filterGhciFlags :: [String] -> [String]+filterGhciFlags = filter supported+ where+ supported ('-':'O':_) = False+ supported "-debug" = False+ supported "-threaded" = False+ supported "-ticky" = False+ supported "-eventlog" = False+ supported "-prof" = False+ supported "-unreg" = False+ supported _ = True++mkGHCiLibName :: LibraryName -> String+mkGHCiLibName (LibraryName lib) = lib <.> "o"++ghcLookupProperty :: String -> Compiler -> Bool+ghcLookupProperty prop comp =+ case M.lookup prop (compilerProperties comp) of+ Just "YES" -> True+ _ -> False++-- when using -split-objs, we need to search for object files in the+-- Module_split directory for each module.+getHaskellObjects :: GhcImplInfo -> Library -> LocalBuildInfo+ -> FilePath -> String -> Bool -> IO [FilePath]+getHaskellObjects implInfo lib lbi pref wanted_obj_ext allow_split_objs+ | splitObjs lbi && allow_split_objs = do+ let splitSuffix = if noExtInSplitSuffix implInfo+ then "_split"+ else "_" ++ wanted_obj_ext ++ "_split"+ dirs = [ pref </> (ModuleName.toFilePath x ++ splitSuffix)+ | x <- libModules lib ]+ objss <- mapM getDirectoryContents dirs+ let objs = [ dir </> obj+ | (objs',dir) <- zip objss dirs, obj <- objs',+ let obj_ext = takeExtension obj,+ '.':wanted_obj_ext == obj_ext ]+ return objs+ | otherwise =+ return [ pref </> ModuleName.toFilePath x <.> wanted_obj_ext+ | x <- libModules lib ]++mkGhcOptPackages :: ComponentLocalBuildInfo+ -> [(InstalledPackageId, PackageId, ModuleRenaming)]+mkGhcOptPackages clbi =+ map (\(i,p) -> (i,p,lookupRenaming p (componentPackageRenaming clbi)))+ (componentPackageDeps clbi)++substTopDir :: FilePath -> InstalledPackageInfo -> InstalledPackageInfo+substTopDir topDir ipo+ = ipo {+ InstalledPackageInfo.importDirs+ = map f (InstalledPackageInfo.importDirs ipo),+ InstalledPackageInfo.libraryDirs+ = map f (InstalledPackageInfo.libraryDirs ipo),+ InstalledPackageInfo.includeDirs+ = map f (InstalledPackageInfo.includeDirs ipo),+ InstalledPackageInfo.frameworkDirs+ = map f (InstalledPackageInfo.frameworkDirs ipo),+ InstalledPackageInfo.haddockInterfaces+ = map f (InstalledPackageInfo.haddockInterfaces ipo),+ InstalledPackageInfo.haddockHTMLs+ = map f (InstalledPackageInfo.haddockHTMLs ipo)+ }+ where f ('$':'t':'o':'p':'d':'i':'r':rest) = topDir ++ rest+ f x = x++-- Cabal does not use the environment variable GHC{,JS}_PACKAGE_PATH; let+-- users know that this is the case. See ticket #335. Simply ignoring it is+-- not a good idea, since then ghc and cabal are looking at different sets+-- of package DBs and chaos is likely to ensue.+--+-- An exception to this is when running cabal from within a `cabal exec`+-- environment. In this case, `cabal exec` will set the+-- CABAL_SANDBOX_PACKAGE_PATH to the same value that it set+-- GHC{,JS}_PACKAGE_PATH to. If that is the case it is OK to allow+-- GHC{,JS}_PACKAGE_PATH.+checkPackageDbEnvVar :: String -> String -> IO ()+checkPackageDbEnvVar compilerName packagePathEnvVar = do+ mPP <- lookupEnv packagePathEnvVar+ when (isJust mPP) $ do+ mcsPP <- lookupEnv "CABAL_SANDBOX_PACKAGE_PATH"+ unless (mPP == mcsPP) abort+ where+ lookupEnv :: String -> IO (Maybe String)+ lookupEnv name = (Just `fmap` getEnv name) `catchIO` const (return Nothing)+ abort =+ die $ "Use of " ++ compilerName ++ "'s environment variable "+ ++ packagePathEnvVar ++ " is incompatible with Cabal. Use the "+ ++ "flag --package-db to specify a package database (it can be "+ ++ "used multiple times)."
+ Distribution/Simple/GHCJS.hs view
@@ -0,0 +1,898 @@+module Distribution.Simple.GHCJS (+ configure, getInstalledPackages, getPackageDBContents,+ buildLib, buildExe,+ replLib, replExe,+ startInterpreter,+ installLib, installExe,+ libAbiHash,+ hcPkgInfo,+ registerPackage,+ componentGhcOptions,+ getLibDir,+ isDynamic,+ getGlobalPackageDB,+ runCmd+ ) where++import Distribution.Simple.GHC.ImplInfo ( getImplInfo, ghcjsVersionImplInfo )+import qualified Distribution.Simple.GHC.Internal as Internal+import Distribution.PackageDescription as PD+ ( PackageDescription(..), BuildInfo(..), Executable(..)+ , Library(..), libModules, exeModules+ , hcOptions, hcProfOptions, hcSharedOptions+ , allExtensions )+import Distribution.InstalledPackageInfo+ ( InstalledPackageInfo )+import qualified Distribution.InstalledPackageInfo as InstalledPackageInfo+ ( InstalledPackageInfo_(..) )+import Distribution.Simple.PackageIndex ( InstalledPackageIndex )+import qualified Distribution.Simple.PackageIndex as PackageIndex+import Distribution.Simple.LocalBuildInfo+ ( LocalBuildInfo(..), ComponentLocalBuildInfo(..)+ , LibraryName(..) )+import qualified Distribution.Simple.Hpc as Hpc+import Distribution.Simple.InstallDirs hiding ( absoluteInstallDirs )+import Distribution.Simple.BuildPaths+import Distribution.Simple.Utils+import Distribution.Simple.Program+ ( Program(..), ConfiguredProgram(..), ProgramConfiguration+ , ProgramSearchPath+ , rawSystemProgramConf+ , rawSystemProgramStdout, rawSystemProgramStdoutConf+ , getProgramInvocationOutput+ , requireProgramVersion, requireProgram+ , userMaybeSpecifyPath, programPath+ , lookupProgram, addKnownPrograms+ , ghcjsProgram, ghcjsPkgProgram, c2hsProgram, hsc2hsProgram+ , ldProgram, haddockProgram, stripProgram )+import qualified Distribution.Simple.Program.HcPkg as HcPkg+import qualified Distribution.Simple.Program.Ar as Ar+import qualified Distribution.Simple.Program.Ld as Ld+import qualified Distribution.Simple.Program.Strip as Strip+import Distribution.Simple.Program.GHC+import Distribution.Simple.Setup+ ( toFlag, fromFlag, configCoverage, configDistPref )+import qualified Distribution.Simple.Setup as Cabal+ ( Flag(..) )+import Distribution.Simple.Compiler+ ( CompilerFlavor(..), CompilerId(..), Compiler(..)+ , PackageDB(..), PackageDBStack, AbiTag(..) )+import Distribution.Version+ ( Version(..), anyVersion, orLaterVersion )+import Distribution.System+ ( Platform(..) )+import Distribution.Verbosity+import Distribution.Utils.NubList+ ( overNubListR, toNubListR )+import Distribution.Text ( display )+import Language.Haskell.Extension ( Extension(..)+ , KnownExtension(..))++import Control.Monad ( unless, when )+import Data.Char ( isSpace )+import qualified Data.Map as M ( fromList )+import Data.Monoid ( Monoid(..) )+import System.Directory ( doesFileExist )+import System.FilePath ( (</>), (<.>), takeExtension,+ takeDirectory, replaceExtension,+ splitExtension )+import Distribution.Compat.Exception (catchIO)++configure :: Verbosity -> Maybe FilePath -> Maybe FilePath+ -> ProgramConfiguration+ -> IO (Compiler, Maybe Platform, ProgramConfiguration)+configure verbosity hcPath hcPkgPath conf0 = do+ (ghcjsProg, ghcjsVersion, conf1) <-+ requireProgramVersion verbosity ghcjsProgram+ (orLaterVersion (Version [0,1] []))+ (userMaybeSpecifyPath "ghcjs" hcPath conf0)+ Just ghcjsGhcVersion <- findGhcjsGhcVersion verbosity (programPath ghcjsProg)+ let implInfo = ghcjsVersionImplInfo ghcjsVersion ghcjsGhcVersion++ -- This is slightly tricky, we have to configure ghcjs first, then we use the+ -- location of ghcjs to help find ghcjs-pkg in the case that the user did not+ -- specify the location of ghc-pkg directly:+ (ghcjsPkgProg, ghcjsPkgVersion, conf2) <-+ requireProgramVersion verbosity ghcjsPkgProgram {+ programFindLocation = guessGhcjsPkgFromGhcjsPath ghcjsProg+ }+ anyVersion (userMaybeSpecifyPath "ghcjs-pkg" hcPkgPath conf1)++ Just ghcjsPkgGhcVersion <- findGhcjsPkgGhcVersion+ verbosity (programPath ghcjsPkgProg)++ when (ghcjsVersion /= ghcjsPkgVersion) $ die $+ "Version mismatch between ghcjs and ghcjs-pkg: "+ ++ programPath ghcjsProg ++ " is version " ++ display ghcjsVersion ++ " "+ ++ programPath ghcjsPkgProg ++ " is version " ++ display ghcjsPkgVersion++ when (ghcjsGhcVersion /= ghcjsPkgGhcVersion) $ die $+ "Version mismatch between ghcjs and ghcjs-pkg: "+ ++ programPath ghcjsProg+ ++ " was built with GHC version " ++ display ghcjsGhcVersion ++ " "+ ++ programPath ghcjsPkgProg+ ++ " was built with GHC version " ++ display ghcjsPkgGhcVersion++ -- be sure to use our versions of hsc2hs, c2hs, haddock and ghc+ let hsc2hsProgram' =+ hsc2hsProgram { programFindLocation =+ guessHsc2hsFromGhcjsPath ghcjsProg }+ c2hsProgram' =+ c2hsProgram { programFindLocation =+ guessC2hsFromGhcjsPath ghcjsProg }++ haddockProgram' =+ haddockProgram { programFindLocation =+ guessHaddockFromGhcjsPath ghcjsProg }+ conf3 = addKnownPrograms [ hsc2hsProgram', c2hsProgram', haddockProgram' ] conf2++ languages <- Internal.getLanguages verbosity implInfo ghcjsProg+ extensions <- Internal.getExtensions verbosity implInfo ghcjsProg++ ghcInfo <- Internal.getGhcInfo verbosity implInfo ghcjsProg+ let ghcInfoMap = M.fromList ghcInfo++ let comp = Compiler {+ compilerId = CompilerId GHCJS ghcjsVersion,+ compilerAbiTag = AbiTag $+ "ghc" ++ intercalate "_" (map show . versionBranch $ ghcjsGhcVersion),+ compilerCompat = [CompilerId GHC ghcjsGhcVersion],+ compilerLanguages = languages,+ compilerExtensions = extensions,+ compilerProperties = ghcInfoMap+ }+ compPlatform = Internal.targetPlatform ghcInfo+ -- configure gcc and ld+ let conf4 = if ghcjsNativeToo comp+ then Internal.configureToolchain implInfo+ ghcjsProg ghcInfoMap conf3+ else conf3+ return (comp, compPlatform, conf4)++ghcjsNativeToo :: Compiler -> Bool+ghcjsNativeToo = Internal.ghcLookupProperty "Native Too"++guessGhcjsPkgFromGhcjsPath :: ConfiguredProgram -> Verbosity+ -> ProgramSearchPath -> IO (Maybe FilePath)+guessGhcjsPkgFromGhcjsPath = guessToolFromGhcjsPath ghcjsPkgProgram++guessHsc2hsFromGhcjsPath :: ConfiguredProgram -> Verbosity+ -> ProgramSearchPath -> IO (Maybe FilePath)+guessHsc2hsFromGhcjsPath = guessToolFromGhcjsPath hsc2hsProgram++guessC2hsFromGhcjsPath :: ConfiguredProgram -> Verbosity+ -> ProgramSearchPath -> IO (Maybe FilePath)+guessC2hsFromGhcjsPath = guessToolFromGhcjsPath c2hsProgram++guessHaddockFromGhcjsPath :: ConfiguredProgram -> Verbosity+ -> ProgramSearchPath -> IO (Maybe FilePath)+guessHaddockFromGhcjsPath = guessToolFromGhcjsPath haddockProgram++guessToolFromGhcjsPath :: Program -> ConfiguredProgram+ -> Verbosity -> ProgramSearchPath+ -> IO (Maybe FilePath)+guessToolFromGhcjsPath tool ghcjsProg verbosity searchpath+ = do let toolname = programName tool+ path = programPath ghcjsProg+ dir = takeDirectory path+ versionSuffix = takeVersionSuffix (dropExeExtension path)+ guessNormal = dir </> toolname <.> exeExtension+ guessGhcjsVersioned = dir </> (toolname ++ "-ghcjs" ++ versionSuffix)+ <.> exeExtension+ guessGhcjs = dir </> (toolname ++ "-ghcjs")+ <.> exeExtension+ guessVersioned = dir </> (toolname ++ versionSuffix) <.> exeExtension+ guesses | null versionSuffix = [guessGhcjs, guessNormal]+ | otherwise = [guessGhcjsVersioned,+ guessGhcjs,+ guessVersioned,+ guessNormal]+ info verbosity $ "looking for tool " ++ toolname+ ++ " near compiler in " ++ dir+ exists <- mapM doesFileExist guesses+ case [ file | (file, True) <- zip guesses exists ] of+ -- If we can't find it near ghc, fall back to the usual+ -- method.+ [] -> programFindLocation tool verbosity searchpath+ (fp:_) -> do info verbosity $ "found " ++ toolname ++ " in " ++ fp+ return (Just fp)++ where takeVersionSuffix :: FilePath -> String+ takeVersionSuffix = reverse . takeWhile (`elem ` "0123456789.-") .+ reverse++ dropExeExtension :: FilePath -> FilePath+ dropExeExtension filepath =+ case splitExtension filepath of+ (filepath', extension) | extension == exeExtension -> filepath'+ | otherwise -> filepath+++-- | Given a single package DB, return all installed packages.+getPackageDBContents :: Verbosity -> PackageDB -> ProgramConfiguration+ -> IO InstalledPackageIndex+getPackageDBContents verbosity packagedb conf = do+ pkgss <- getInstalledPackages' verbosity [packagedb] conf+ toPackageIndex verbosity pkgss conf++-- | Given a package DB stack, return all installed packages.+getInstalledPackages :: Verbosity -> PackageDBStack -> ProgramConfiguration+ -> IO InstalledPackageIndex+getInstalledPackages verbosity packagedbs conf = do+ checkPackageDbEnvVar+ checkPackageDbStack packagedbs+ pkgss <- getInstalledPackages' verbosity packagedbs conf+ index <- toPackageIndex verbosity pkgss conf+ return $! index++toPackageIndex :: Verbosity+ -> [(PackageDB, [InstalledPackageInfo])]+ -> ProgramConfiguration+ -> IO InstalledPackageIndex+toPackageIndex verbosity pkgss conf = do+ -- On Windows, various fields have $topdir/foo rather than full+ -- paths. We need to substitute the right value in so that when+ -- we, for example, call gcc, we have proper paths to give it.+ topDir <- getLibDir' verbosity ghcjsProg+ let indices = [ PackageIndex.fromList (map (Internal.substTopDir topDir) pkgs)+ | (_, pkgs) <- pkgss ]+ return $! (mconcat indices)++ where+ Just ghcjsProg = lookupProgram ghcjsProgram conf++checkPackageDbEnvVar :: IO ()+checkPackageDbEnvVar =+ Internal.checkPackageDbEnvVar "GHCJS" "GHCJS_PACKAGE_PATH"++checkPackageDbStack :: PackageDBStack -> IO ()+checkPackageDbStack (GlobalPackageDB:rest)+ | GlobalPackageDB `notElem` rest = return ()+checkPackageDbStack rest+ | GlobalPackageDB `notElem` rest =+ die $ "With current ghc versions the global package db is always used "+ ++ "and must be listed first. This ghc limitation may be lifted in "+ ++ "future, see http://hackage.haskell.org/trac/ghc/ticket/5977"+checkPackageDbStack _ =+ die $ "If the global package db is specified, it must be "+ ++ "specified first and cannot be specified multiple times"++getInstalledPackages' :: Verbosity -> [PackageDB] -> ProgramConfiguration+ -> IO [(PackageDB, [InstalledPackageInfo])]+getInstalledPackages' verbosity packagedbs conf =+ sequence+ [ do pkgs <- HcPkg.dump (hcPkgInfo conf) verbosity packagedb+ return (packagedb, pkgs)+ | packagedb <- packagedbs ]++getLibDir :: Verbosity -> LocalBuildInfo -> IO FilePath+getLibDir verbosity lbi =+ (reverse . dropWhile isSpace . reverse) `fmap`+ rawSystemProgramStdoutConf verbosity ghcjsProgram+ (withPrograms lbi) ["--print-libdir"]++getLibDir' :: Verbosity -> ConfiguredProgram -> IO FilePath+getLibDir' verbosity ghcjsProg =+ (reverse . dropWhile isSpace . reverse) `fmap`+ rawSystemProgramStdout verbosity ghcjsProg ["--print-libdir"]++-- | Return the 'FilePath' to the global GHC package database.+getGlobalPackageDB :: Verbosity -> ConfiguredProgram -> IO FilePath+getGlobalPackageDB verbosity ghcjsProg =+ (reverse . dropWhile isSpace . reverse) `fmap`+ rawSystemProgramStdout verbosity ghcjsProg ["--print-global-package-db"]++toJSLibName :: String -> String+toJSLibName lib+ | takeExtension lib `elem` [".dll",".dylib",".so"]+ = replaceExtension lib "js_so"+ | takeExtension lib == ".a" = replaceExtension lib "js_a"+ | otherwise = lib <.> "js_a"++buildLib, replLib :: Verbosity -> Cabal.Flag (Maybe Int) -> PackageDescription+ -> LocalBuildInfo -> Library -> ComponentLocalBuildInfo+ -> IO ()+buildLib = buildOrReplLib False+replLib = buildOrReplLib True++buildOrReplLib :: Bool -> Verbosity -> Cabal.Flag (Maybe Int)+ -> PackageDescription -> LocalBuildInfo+ -> Library -> ComponentLocalBuildInfo -> IO ()+buildOrReplLib forRepl verbosity numJobs _pkg_descr lbi lib clbi = do+ libName <- case componentLibraries clbi of+ [libName] -> return libName+ [] -> die "No library name found when building library"+ _ -> die "Multiple library names found when building library"+ let libTargetDir = buildDir lbi+ whenVanillaLib forceVanilla =+ when (not forRepl && (forceVanilla || withVanillaLib lbi))+ whenProfLib = when (not forRepl && withProfLib lbi)+ whenSharedLib forceShared =+ when (not forRepl && (forceShared || withSharedLib lbi))+ whenGHCiLib = when (not forRepl && withGHCiLib lbi && withVanillaLib lbi)+ ifReplLib = when forRepl+ comp = compiler lbi+ implInfo = getImplInfo comp+ hole_insts = map (\(k,(p,n)) -> (k,(InstalledPackageInfo.packageKey p,n)))+ (instantiatedWith lbi)+ nativeToo = ghcjsNativeToo comp++ (ghcjsProg, _) <- requireProgram verbosity ghcjsProgram (withPrograms lbi)+ let runGhcjsProg = runGHC verbosity ghcjsProg comp+ libBi = libBuildInfo lib+ isGhcjsDynamic = isDynamic comp+ dynamicTooSupported = supportsDynamicToo comp+ doingTH = EnableExtension TemplateHaskell `elem` allExtensions libBi+ forceVanillaLib = doingTH && not isGhcjsDynamic+ forceSharedLib = doingTH && isGhcjsDynamic+ -- TH always needs default libs, even when building for profiling++ -- Determine if program coverage should be enabled and if so, what+ -- '-hpcdir' should be.+ let isCoverageEnabled = fromFlag $ configCoverage $ configFlags lbi+ -- Component name. Not 'libName' because that has the "HS" prefix+ -- that GHC gives Haskell libraries.+ cname = display $ PD.package $ localPkgDescr lbi+ distPref = fromFlag $ configDistPref $ configFlags lbi+ hpcdir way+ | isCoverageEnabled = toFlag $ Hpc.mixDir distPref way cname+ | otherwise = mempty++ createDirectoryIfMissingVerbose verbosity True libTargetDir+ -- TODO: do we need to put hs-boot files into place for mutually recursive+ -- modules?+ let cObjs = map (`replaceExtension` objExtension) (cSources libBi)+ jsSrcs = jsSources libBi+ baseOpts = componentGhcOptions verbosity lbi libBi clbi libTargetDir+ linkJsLibOpts = mempty {+ ghcOptExtra = toNubListR $+ [ "-link-js-lib" , (\(LibraryName l) -> l) libName+ , "-js-lib-outputdir", libTargetDir ] +++ concatMap (\x -> ["-js-lib-src",x]) jsSrcs+ }+ vanillaOptsNoJsLib = baseOpts `mappend` mempty {+ ghcOptMode = toFlag GhcModeMake,+ ghcOptNumJobs = numJobs,+ ghcOptPackageKey = toFlag (pkgKey lbi),+ ghcOptSigOf = hole_insts,+ ghcOptInputModules = toNubListR $ libModules lib,+ ghcOptHPCDir = hpcdir Hpc.Vanilla+ }+ vanillaOpts = vanillaOptsNoJsLib `mappend` linkJsLibOpts++ profOpts = adjustExts "p_hi" "p_o" vanillaOpts `mappend` mempty {+ ghcOptProfilingMode = toFlag True,+ ghcOptExtra = toNubListR $+ ghcjsProfOptions libBi,+ ghcOptHPCDir = hpcdir Hpc.Prof+ }+ sharedOpts = adjustExts "dyn_hi" "dyn_o" vanillaOpts `mappend` mempty {+ ghcOptDynLinkMode = toFlag GhcDynamicOnly,+ ghcOptFPic = toFlag True,+ ghcOptExtra = toNubListR $+ ghcjsSharedOptions libBi,+ ghcOptHPCDir = hpcdir Hpc.Dyn+ }+ linkerOpts = mempty {+ ghcOptLinkOptions = toNubListR $ PD.ldOptions libBi,+ ghcOptLinkLibs = toNubListR $ extraLibs libBi,+ ghcOptLinkLibPath = toNubListR $ extraLibDirs libBi,+ ghcOptLinkFrameworks = toNubListR $ PD.frameworks libBi,+ ghcOptInputFiles =+ toNubListR $ [libTargetDir </> x | x <- cObjs] ++ jsSrcs+ }+ replOpts = vanillaOptsNoJsLib {+ ghcOptExtra = overNubListR+ Internal.filterGhciFlags+ (ghcOptExtra vanillaOpts),+ ghcOptNumJobs = mempty+ }+ `mappend` linkerOpts+ `mappend` mempty {+ ghcOptMode = toFlag GhcModeInteractive,+ ghcOptOptimisation = toFlag GhcNoOptimisation+ }++ vanillaSharedOpts = vanillaOpts `mappend`+ mempty {+ ghcOptDynLinkMode = toFlag GhcStaticAndDynamic,+ ghcOptDynHiSuffix = toFlag "dyn_hi",+ ghcOptDynObjSuffix = toFlag "dyn_o",+ ghcOptHPCDir = hpcdir Hpc.Dyn+ }++ unless (forRepl || (null (libModules lib) && null jsSrcs && null cObjs)) $+ do let vanilla = whenVanillaLib forceVanillaLib (runGhcjsProg vanillaOpts)+ shared = whenSharedLib forceSharedLib (runGhcjsProg sharedOpts)+ useDynToo = dynamicTooSupported &&+ (forceVanillaLib || withVanillaLib lbi) &&+ (forceSharedLib || withSharedLib lbi) &&+ null (ghcjsSharedOptions libBi)+ if useDynToo+ then do+ runGhcjsProg vanillaSharedOpts+ case (hpcdir Hpc.Dyn, hpcdir Hpc.Vanilla) of+ (Cabal.Flag dynDir, Cabal.Flag vanillaDir) -> do+ -- When the vanilla and shared library builds are done+ -- in one pass, only one set of HPC module interfaces+ -- are generated. This set should suffice for both+ -- static and dynamically linked executables. We copy+ -- the modules interfaces so they are available under+ -- both ways.+ copyDirectoryRecursive verbosity dynDir vanillaDir+ _ -> return ()+ else if isGhcjsDynamic+ then do shared; vanilla+ else do vanilla; shared+ whenProfLib (runGhcjsProg profOpts)++ -- build any C sources+ unless (null (cSources libBi) || not nativeToo) $ do+ info verbosity "Building C Sources..."+ sequence_+ [ do let vanillaCcOpts =+ (Internal.componentCcGhcOptions verbosity implInfo+ lbi libBi clbi libTargetDir filename)+ profCcOpts = vanillaCcOpts `mappend` mempty {+ ghcOptProfilingMode = toFlag True,+ ghcOptObjSuffix = toFlag "p_o"+ }+ sharedCcOpts = vanillaCcOpts `mappend` mempty {+ ghcOptFPic = toFlag True,+ ghcOptDynLinkMode = toFlag GhcDynamicOnly,+ ghcOptObjSuffix = toFlag "dyn_o"+ }+ odir = fromFlag (ghcOptObjDir vanillaCcOpts)+ createDirectoryIfMissingVerbose verbosity True odir+ runGhcjsProg vanillaCcOpts+ whenSharedLib forceSharedLib (runGhcjsProg sharedCcOpts)+ whenProfLib (runGhcjsProg profCcOpts)+ | filename <- cSources libBi]++ -- TODO: problem here is we need the .c files built first, so we can load them+ -- with ghci, but .c files can depend on .h files generated by ghc by ffi+ -- exports.+ unless (null (libModules lib)) $+ ifReplLib (runGhcjsProg replOpts)++ -- link:+ when (nativeToo && not forRepl) $ do+ info verbosity "Linking..."+ let cProfObjs = map (`replaceExtension` ("p_" ++ objExtension))+ (cSources libBi)+ cSharedObjs = map (`replaceExtension` ("dyn_" ++ objExtension))+ (cSources libBi)+ cid = compilerId (compiler lbi)+ vanillaLibFilePath = libTargetDir </> mkLibName libName+ profileLibFilePath = libTargetDir </> mkProfLibName libName+ sharedLibFilePath = libTargetDir </> mkSharedLibName cid libName+ ghciLibFilePath = libTargetDir </> Internal.mkGHCiLibName libName++ hObjs <- Internal.getHaskellObjects implInfo lib lbi+ libTargetDir objExtension True+ hProfObjs <-+ if (withProfLib lbi)+ then Internal.getHaskellObjects implInfo lib lbi+ libTargetDir ("p_" ++ objExtension) True+ else return []+ hSharedObjs <-+ if (withSharedLib lbi)+ then Internal.getHaskellObjects implInfo lib lbi+ libTargetDir ("dyn_" ++ objExtension) False+ else return []++ unless (null hObjs && null cObjs) $ do++ let staticObjectFiles =+ hObjs+ ++ map (libTargetDir </>) cObjs+ profObjectFiles =+ hProfObjs+ ++ map (libTargetDir </>) cProfObjs+ ghciObjFiles =+ hObjs+ ++ map (libTargetDir </>) cObjs+ dynamicObjectFiles =+ hSharedObjs+ ++ map (libTargetDir </>) cSharedObjs+ -- After the relocation lib is created we invoke ghc -shared+ -- with the dependencies spelled out as -package arguments+ -- and ghc invokes the linker with the proper library paths+ ghcSharedLinkArgs =+ mempty {+ ghcOptShared = toFlag True,+ ghcOptDynLinkMode = toFlag GhcDynamicOnly,+ ghcOptInputFiles = toNubListR dynamicObjectFiles,+ ghcOptOutputFile = toFlag sharedLibFilePath,+ ghcOptPackageKey = toFlag (pkgKey lbi),+ ghcOptNoAutoLinkPackages = toFlag True,+ ghcOptPackageDBs = withPackageDB lbi,+ ghcOptPackages = toNubListR $+ Internal.mkGhcOptPackages clbi,+ ghcOptLinkLibs = toNubListR $ extraLibs libBi,+ ghcOptLinkLibPath = toNubListR $ extraLibDirs libBi+ }++ whenVanillaLib False $ do+ Ar.createArLibArchive verbosity lbi vanillaLibFilePath staticObjectFiles++ whenProfLib $ do+ Ar.createArLibArchive verbosity lbi profileLibFilePath profObjectFiles++ whenGHCiLib $ do+ (ldProg, _) <- requireProgram verbosity ldProgram (withPrograms lbi)+ Ld.combineObjectFiles verbosity ldProg+ ghciLibFilePath ghciObjFiles++ whenSharedLib False $+ runGhcjsProg ghcSharedLinkArgs++-- | Start a REPL without loading any source files.+startInterpreter :: Verbosity -> ProgramConfiguration -> Compiler+ -> PackageDBStack -> IO ()+startInterpreter verbosity conf comp packageDBs = do+ let replOpts = mempty {+ ghcOptMode = toFlag GhcModeInteractive,+ ghcOptPackageDBs = packageDBs+ }+ checkPackageDbStack packageDBs+ (ghcjsProg, _) <- requireProgram verbosity ghcjsProgram conf+ runGHC verbosity ghcjsProg comp replOpts++buildExe, replExe :: Verbosity -> Cabal.Flag (Maybe Int)+ -> PackageDescription -> LocalBuildInfo+ -> Executable -> ComponentLocalBuildInfo -> IO ()+buildExe = buildOrReplExe False+replExe = buildOrReplExe True++buildOrReplExe :: Bool -> Verbosity -> Cabal.Flag (Maybe Int)+ -> PackageDescription -> LocalBuildInfo+ -> Executable -> ComponentLocalBuildInfo -> IO ()+buildOrReplExe forRepl verbosity numJobs _pkg_descr lbi+ exe@Executable { exeName = exeName', modulePath = modPath } clbi = do++ (ghcjsProg, _) <- requireProgram verbosity ghcjsProgram (withPrograms lbi)+ let comp = compiler lbi+ implInfo = getImplInfo comp+ runGhcjsProg = runGHC verbosity ghcjsProg comp+ exeBi = buildInfo exe++ -- exeNameReal, the name that GHC really uses (with .exe on Windows)+ let exeNameReal = exeName' <.>+ (if takeExtension exeName' /= ('.':exeExtension)+ then exeExtension+ else "")++ let targetDir = (buildDir lbi) </> exeName'+ let exeDir = targetDir </> (exeName' ++ "-tmp")+ createDirectoryIfMissingVerbose verbosity True targetDir+ createDirectoryIfMissingVerbose verbosity True exeDir+ -- TODO: do we need to put hs-boot files into place for mutually recursive+ -- modules? FIX: what about exeName.hi-boot?++ -- Determine if program coverage should be enabled and if so, what+ -- '-hpcdir' should be.+ let isCoverageEnabled = fromFlag $ configCoverage $ configFlags lbi+ distPref = fromFlag $ configDistPref $ configFlags lbi+ hpcdir way+ | isCoverageEnabled = toFlag $ Hpc.mixDir distPref way exeName'+ | otherwise = mempty++ -- build executables++ srcMainFile <- findFile (exeDir : hsSourceDirs exeBi) modPath+ let isGhcjsDynamic = isDynamic comp+ dynamicTooSupported = supportsDynamicToo comp+ buildRunner = case clbi of+ ExeComponentLocalBuildInfo {} -> False+ _ -> True+ isHaskellMain = elem (takeExtension srcMainFile) [".hs", ".lhs"]+ jsSrcs = jsSources exeBi+ cSrcs = cSources exeBi ++ [srcMainFile | not isHaskellMain]+ cObjs = map (`replaceExtension` objExtension) cSrcs+ nativeToo = ghcjsNativeToo comp+ baseOpts = (componentGhcOptions verbosity lbi exeBi clbi exeDir)+ `mappend` mempty {+ ghcOptMode = toFlag GhcModeMake,+ ghcOptInputFiles = toNubListR $+ [ srcMainFile | isHaskellMain],+ ghcOptInputModules = toNubListR $+ [ m | not isHaskellMain, m <- exeModules exe],+ ghcOptExtra =+ if buildRunner then toNubListR ["-build-runner"]+ else mempty+ }+ staticOpts = baseOpts `mappend` mempty {+ ghcOptDynLinkMode = toFlag GhcStaticOnly,+ ghcOptHPCDir = hpcdir Hpc.Vanilla+ }+ profOpts = adjustExts "p_hi" "p_o" baseOpts `mappend` mempty {+ ghcOptProfilingMode = toFlag True,+ ghcOptExtra = toNubListR $ ghcjsProfOptions exeBi,+ ghcOptHPCDir = hpcdir Hpc.Prof+ }+ dynOpts = adjustExts "dyn_hi" "dyn_o" baseOpts `mappend` mempty {+ ghcOptDynLinkMode = toFlag GhcDynamicOnly,+ ghcOptExtra = toNubListR $+ ghcjsSharedOptions exeBi,+ ghcOptHPCDir = hpcdir Hpc.Dyn+ }+ dynTooOpts = adjustExts "dyn_hi" "dyn_o" staticOpts `mappend` mempty {+ ghcOptDynLinkMode = toFlag GhcStaticAndDynamic,+ ghcOptHPCDir = hpcdir Hpc.Dyn+ }+ linkerOpts = mempty {+ ghcOptLinkOptions = toNubListR $ PD.ldOptions exeBi,+ ghcOptLinkLibs = toNubListR $ extraLibs exeBi,+ ghcOptLinkLibPath = toNubListR $ extraLibDirs exeBi,+ ghcOptLinkFrameworks = toNubListR $ PD.frameworks exeBi,+ ghcOptInputFiles = toNubListR $+ [exeDir </> x | x <- cObjs] ++ jsSrcs+ }+ replOpts = baseOpts {+ ghcOptExtra = overNubListR+ Internal.filterGhciFlags+ (ghcOptExtra baseOpts)+ }+ -- For a normal compile we do separate invocations of ghc for+ -- compiling as for linking. But for repl we have to do just+ -- the one invocation, so that one has to include all the+ -- linker stuff too, like -l flags and any .o files from C+ -- files etc.+ `mappend` linkerOpts+ `mappend` mempty {+ ghcOptMode = toFlag GhcModeInteractive,+ ghcOptOptimisation = toFlag GhcNoOptimisation+ }+ commonOpts | withProfExe lbi = profOpts+ | withDynExe lbi = dynOpts+ | otherwise = staticOpts+ compileOpts | useDynToo = dynTooOpts+ | otherwise = commonOpts+ withStaticExe = (not $ withProfExe lbi) && (not $ withDynExe lbi)++ -- For building exe's that use TH with -prof or -dynamic we actually have+ -- to build twice, once without -prof/-dynamic and then again with+ -- -prof/-dynamic. This is because the code that TH needs to run at+ -- compile time needs to be the vanilla ABI so it can be loaded up and run+ -- by the compiler.+ -- With dynamic-by-default GHC the TH object files loaded at compile-time+ -- need to be .dyn_o instead of .o.+ doingTH = EnableExtension TemplateHaskell `elem` allExtensions exeBi+ -- Should we use -dynamic-too instead of compiling twice?+ useDynToo = dynamicTooSupported && isGhcjsDynamic+ && doingTH && withStaticExe && null (ghcjsSharedOptions exeBi)+ compileTHOpts | isGhcjsDynamic = dynOpts+ | otherwise = staticOpts+ compileForTH+ | forRepl = False+ | useDynToo = False+ | isGhcjsDynamic = doingTH && (withProfExe lbi || withStaticExe)+ | otherwise = doingTH && (withProfExe lbi || withDynExe lbi)++ linkOpts = commonOpts `mappend`+ linkerOpts `mappend` mempty {+ ghcOptLinkNoHsMain = toFlag (not isHaskellMain)+ }++ -- Build static/dynamic object files for TH, if needed.+ when compileForTH $+ runGhcjsProg compileTHOpts { ghcOptNoLink = toFlag True+ , ghcOptNumJobs = numJobs }++ unless forRepl $+ runGhcjsProg compileOpts { ghcOptNoLink = toFlag True+ , ghcOptNumJobs = numJobs }++ -- build any C sources+ unless (null cSrcs || not nativeToo) $ do+ info verbosity "Building C Sources..."+ sequence_+ [ do let opts = (Internal.componentCcGhcOptions verbosity implInfo lbi exeBi+ clbi exeDir filename) `mappend` mempty {+ ghcOptDynLinkMode = toFlag (if withDynExe lbi+ then GhcDynamicOnly+ else GhcStaticOnly),+ ghcOptProfilingMode = toFlag (withProfExe lbi)+ }+ odir = fromFlag (ghcOptObjDir opts)+ createDirectoryIfMissingVerbose verbosity True odir+ runGhcjsProg opts+ | filename <- cSrcs ]++ -- TODO: problem here is we need the .c files built first, so we can load them+ -- with ghci, but .c files can depend on .h files generated by ghc by ffi+ -- exports.+ when forRepl $ runGhcjsProg replOpts++ -- link:+ unless forRepl $ do+ info verbosity "Linking..."+ runGhcjsProg linkOpts { ghcOptOutputFile = toFlag (targetDir </> exeNameReal) }++-- |Install for ghc, .hi, .a and, if --with-ghci given, .o+installLib :: Verbosity+ -> LocalBuildInfo+ -> FilePath -- ^install location+ -> FilePath -- ^install location for dynamic libraries+ -> FilePath -- ^Build location+ -> PackageDescription+ -> Library+ -> ComponentLocalBuildInfo+ -> IO ()+installLib verbosity lbi targetDir dynlibTargetDir builtDir _pkg lib clbi = do+ whenVanilla $ copyModuleFiles "js_hi"+ whenProf $ copyModuleFiles "js_p_hi"+ whenShared $ copyModuleFiles "js_dyn_hi"++ whenVanilla $ mapM_ (installOrdinary builtDir targetDir . toJSLibName) vanillaLibNames+ whenProf $ mapM_ (installOrdinary builtDir targetDir . toJSLibName) profileLibNames+ whenShared $ mapM_ (installShared builtDir dynlibTargetDir . toJSLibName) sharedLibNames++ when (ghcjsNativeToo $ compiler lbi) $ do+ -- copy .hi files over:+ whenVanilla $ copyModuleFiles "hi"+ whenProf $ copyModuleFiles "p_hi"+ whenShared $ copyModuleFiles "dyn_hi"++ -- copy the built library files over:+ whenVanilla $ mapM_ (installOrdinary builtDir targetDir) vanillaLibNames+ whenProf $ mapM_ (installOrdinary builtDir targetDir) profileLibNames+ whenGHCi $ mapM_ (installOrdinary builtDir targetDir) ghciLibNames+ whenShared $ mapM_ (installShared builtDir dynlibTargetDir) sharedLibNames++ where+ install isShared srcDir dstDir name = do+ let src = srcDir </> name+ dst = dstDir </> name+ createDirectoryIfMissingVerbose verbosity True dstDir+ if isShared+ then do when (stripLibs lbi) $ Strip.stripLib verbosity+ (hostPlatform lbi) (withPrograms lbi) src+ installExecutableFile verbosity src dst+ else installOrdinaryFile verbosity src dst++ installOrdinary = install False+ installShared = install True++ copyModuleFiles ext =+ findModuleFiles [builtDir] [ext] (libModules lib)+ >>= installOrdinaryFiles verbosity targetDir++ cid = compilerId (compiler lbi)+ libNames = componentLibraries clbi+ vanillaLibNames = map mkLibName libNames+ profileLibNames = map mkProfLibName libNames+ ghciLibNames = map Internal.mkGHCiLibName libNames+ sharedLibNames = map (mkSharedLibName cid) libNames++ hasLib = not $ null (libModules lib)+ && null (cSources (libBuildInfo lib))+ whenVanilla = when (hasLib && withVanillaLib lbi)+ whenProf = when (hasLib && withProfLib lbi)+ whenGHCi = when (hasLib && withGHCiLib lbi)+ whenShared = when (hasLib && withSharedLib lbi)++installExe :: Verbosity+ -> LocalBuildInfo+ -> InstallDirs FilePath -- ^Where to copy the files to+ -> FilePath -- ^Build location+ -> (FilePath, FilePath) -- ^Executable (prefix,suffix)+ -> PackageDescription+ -> Executable+ -> IO ()+installExe verbosity lbi installDirs buildPref+ (progprefix, progsuffix) _pkg exe = do+ let binDir = bindir installDirs+ createDirectoryIfMissingVerbose verbosity True binDir+ let exeFileName = exeName exe+ fixedExeBaseName = progprefix ++ exeName exe ++ progsuffix+ installBinary dest = do+ rawSystemProgramConf verbosity ghcjsProgram (withPrograms lbi) $+ [ "--install-executable"+ , buildPref </> exeName exe </> exeFileName+ , "-o", dest+ ] +++ case (stripExes lbi, lookupProgram stripProgram $ withPrograms lbi) of+ (True, Just strip) -> ["-strip-program", programPath strip]+ _ -> []+ installBinary (binDir </> fixedExeBaseName)++libAbiHash :: Verbosity -> PackageDescription -> LocalBuildInfo+ -> Library -> ComponentLocalBuildInfo -> IO String+libAbiHash verbosity _pkg_descr lbi lib clbi = do+ let+ libBi = libBuildInfo lib+ comp = compiler lbi+ vanillaArgs =+ (componentGhcOptions verbosity lbi libBi clbi (buildDir lbi))+ `mappend` mempty {+ ghcOptMode = toFlag GhcModeAbiHash,+ ghcOptPackageKey = toFlag (pkgKey lbi),+ ghcOptInputModules = toNubListR $ exposedModules lib+ }+ profArgs = adjustExts "js_p_hi" "js_p_o" vanillaArgs `mappend` mempty {+ ghcOptProfilingMode = toFlag True,+ ghcOptExtra = toNubListR (ghcjsProfOptions libBi)+ }+ ghcArgs = if withVanillaLib lbi then vanillaArgs+ else if withProfLib lbi then profArgs+ else error "libAbiHash: Can't find an enabled library way"+ --+ (ghcjsProg, _) <- requireProgram verbosity ghcjsProgram (withPrograms lbi)+ getProgramInvocationOutput verbosity (ghcInvocation ghcjsProg comp ghcArgs)++adjustExts :: String -> String -> GhcOptions -> GhcOptions+adjustExts hiSuf objSuf opts =+ opts `mappend` mempty {+ ghcOptHiSuffix = toFlag hiSuf,+ ghcOptObjSuffix = toFlag objSuf+ }++registerPackage :: Verbosity+ -> InstalledPackageInfo+ -> PackageDescription+ -> LocalBuildInfo+ -> Bool+ -> PackageDBStack+ -> IO ()+registerPackage verbosity installedPkgInfo _pkg lbi _inplace packageDbs =+ HcPkg.reregister (hcPkgInfo $ withPrograms lbi) verbosity packageDbs+ (Right installedPkgInfo)++componentGhcOptions :: Verbosity -> LocalBuildInfo+ -> BuildInfo -> ComponentLocalBuildInfo -> FilePath+ -> GhcOptions+componentGhcOptions verbosity lbi bi clbi odir =+ let opts = Internal.componentGhcOptions verbosity lbi bi clbi odir+ in opts { ghcOptExtra = ghcOptExtra opts `mappend` toNubListR+ (hcOptions GHCJS bi)+ }++ghcjsProfOptions :: BuildInfo -> [String]+ghcjsProfOptions bi =+ hcProfOptions GHC bi `mappend` hcProfOptions GHCJS bi++ghcjsSharedOptions :: BuildInfo -> [String]+ghcjsSharedOptions bi =+ hcSharedOptions GHC bi `mappend` hcSharedOptions GHCJS bi++isDynamic :: Compiler -> Bool+isDynamic = Internal.ghcLookupProperty "GHC Dynamic"++supportsDynamicToo :: Compiler -> Bool+supportsDynamicToo = Internal.ghcLookupProperty "Support dynamic-too"++findGhcjsGhcVersion :: Verbosity -> FilePath -> IO (Maybe Version)+findGhcjsGhcVersion verbosity pgm =+ findProgramVersion "--numeric-ghc-version" id verbosity pgm++findGhcjsPkgGhcVersion :: Verbosity -> FilePath -> IO (Maybe Version)+findGhcjsPkgGhcVersion verbosity pgm =+ findProgramVersion "--numeric-ghc-version" id verbosity pgm++-- -----------------------------------------------------------------------------+-- Registering++hcPkgInfo :: ProgramConfiguration -> HcPkg.HcPkgInfo+hcPkgInfo conf = HcPkg.HcPkgInfo { HcPkg.hcPkgProgram = ghcjsPkgProg+ , HcPkg.noPkgDbStack = False+ , HcPkg.noVerboseFlag = False+ , HcPkg.flagPackageConf = False+ }+ where+ Just ghcjsPkgProg = lookupProgram ghcjsPkgProgram conf++-- | Get the JavaScript file name and command and arguments to run a+-- program compiled by GHCJS+-- the exe should be the base program name without exe extension+runCmd :: ProgramConfiguration -> FilePath+ -> (FilePath, FilePath, [String])+runCmd conf exe =+ ( script+ , programPath ghcjsProg+ , programDefaultArgs ghcjsProg ++ programOverrideArgs ghcjsProg ++ ["--run"]+ )+ where+ script = exe <.> "jsexe" </> "all" <.> "js"+ Just ghcjsProg = lookupProgram ghcjsProgram conf
Distribution/Simple/Haddock.hs view
@@ -20,6 +20,9 @@ haddockPackagePaths ) where +import qualified Distribution.Simple.GHC as GHC+import qualified Distribution.Simple.GHCJS as GHCJS+ -- local import Distribution.Package ( PackageIdentifier(..)@@ -28,34 +31,36 @@ import qualified Distribution.ModuleName as ModuleName import Distribution.PackageDescription as PD ( PackageDescription(..), BuildInfo(..), usedExtensions+ , hcSharedOptions , Library(..), hasLibs, Executable(..) , TestSuite(..), TestSuiteInterface(..) , Benchmark(..), BenchmarkInterface(..) ) import Distribution.Simple.Compiler- ( Compiler(..), compilerVersion )-import Distribution.Simple.GHC ( componentGhcOptions, ghcLibDir )+ ( Compiler, compilerInfo, CompilerFlavor(..)+ , compilerFlavor, compilerCompatVersion ) import Distribution.Simple.Program.GHC ( GhcOptions(..), GhcDynLinkMode(..), renderGhcOptions ) import Distribution.Simple.Program- ( ConfiguredProgram(..), requireProgramVersion+ ( ConfiguredProgram(..), lookupProgramVersion, requireProgramVersion , rawSystemProgram, rawSystemProgramStdout , hscolourProgram, haddockProgram )-import Distribution.Simple.PreProcess (PPSuffixHandler- , preprocessComponent)+import Distribution.Simple.PreProcess+ ( PPSuffixHandler, preprocessComponent) import Distribution.Simple.Setup- ( defaultHscolourFlags, Flag(..), toFlag, flagToMaybe, flagToList, fromFlag- , HaddockFlags(..), HscolourFlags(..) )+ ( defaultHscolourFlags+ , Flag(..), toFlag, flagToMaybe, flagToList, fromFlag+ , HaddockFlags(..), HscolourFlags(..) ) import Distribution.Simple.Build (initialBuildSteps)-import Distribution.Simple.InstallDirs (InstallDirs(..), PathTemplateEnv, PathTemplate,- PathTemplateVariable(..),- toPathTemplate, fromPathTemplate,- substPathTemplate, initialPathTemplateEnv)+import Distribution.Simple.InstallDirs+ ( InstallDirs(..)+ , PathTemplateEnv, PathTemplate, PathTemplateVariable(..)+ , toPathTemplate, fromPathTemplate+ , substPathTemplate, initialPathTemplateEnv ) import Distribution.Simple.LocalBuildInfo ( LocalBuildInfo(..), Component(..), ComponentLocalBuildInfo(..) , withAllComponentsInBuildOrder )-import Distribution.Simple.BuildPaths ( haddockName,- hscolourPref, autogenModulesDir,- )+import Distribution.Simple.BuildPaths+ ( haddockName, hscolourPref, autogenModulesDir) import Distribution.Simple.PackageIndex (dependencyClosure) import qualified Distribution.Simple.PackageIndex as PackageIndex import qualified Distribution.InstalledPackageInfo as InstalledPackageInfo@@ -71,46 +76,64 @@ , findFileWithExtension, findFile ) import Distribution.Text ( display, simpleParse )+import Distribution.Utils.NubList+ ( toNubListR ) import Distribution.Verbosity import Language.Haskell.Extension--- Base-import System.Directory(doesFileExist) -import Control.Monad ( when, forM_ )-import Data.Either ( rights )++import Control.Monad ( when, forM_ )+import Data.Either ( rights ) import Data.Monoid-import Data.Maybe ( fromMaybe, listToMaybe )+import Data.Maybe ( fromMaybe, listToMaybe ) -import System.FilePath((</>), (<.>),- normalise, splitPath, joinPath, isAbsolute )-import System.IO (hClose, hPutStrLn, hSetEncoding, utf8)+import System.Directory (doesFileExist)+import System.FilePath ( (</>), (<.>)+ , normalise, splitPath, joinPath, isAbsolute )+import System.IO (hClose, hPutStrLn, hSetEncoding, utf8) import Distribution.Version -- ------------------------------------------------------------------------------ -- Types --- | record that represents the arguments to the haddock executable, a product monoid.+-- | A record that represents the arguments to the haddock executable, a product+-- monoid. data HaddockArgs = HaddockArgs {- argInterfaceFile :: Flag FilePath, -- ^ path of the interface file, relative to argOutputDir, required.- argPackageName :: Flag PackageIdentifier, -- ^ package name, required.- argHideModules :: (All,[ModuleName.ModuleName]), -- ^ (hide modules ?, modules to hide)- argIgnoreExports :: Any, -- ^ ignore export lists in modules?- argLinkSource :: Flag (Template,Template,Template), -- ^ (template for modules, template for symbols, template for lines)- argCssFile :: Flag FilePath, -- ^ optional custom CSS file.- argContents :: Flag String, -- ^ optional URL to contents page+ argInterfaceFile :: Flag FilePath,+ -- ^ Path to the interface file, relative to argOutputDir, required.+ argPackageName :: Flag PackageIdentifier,+ -- ^ Package name, required.+ argHideModules :: (All,[ModuleName.ModuleName]),+ -- ^ (Hide modules ?, modules to hide)+ argIgnoreExports :: Any,+ -- ^ Ignore export lists in modules?+ argLinkSource :: Flag (Template,Template,Template),+ -- ^ (Template for modules, template for symbols, template for lines).+ argCssFile :: Flag FilePath,+ -- ^ Optional custom CSS file.+ argContents :: Flag String,+ -- ^ Optional URL to contents page. argVerbose :: Any,- argOutput :: Flag [Output], -- ^ HTML or Hoogle doc or both? required.- argInterfaces :: [(FilePath, Maybe String)], -- ^ [(interface file, URL to the HTML docs for links)]- argOutputDir :: Directory, -- ^ where to generate the documentation.- argTitle :: Flag String, -- ^ page's title, required.- argPrologue :: Flag String, -- ^ prologue text, required.- argGhcOptions :: Flag (GhcOptions, Version), -- ^ additional flags to pass to ghc- argGhcLibDir :: Flag FilePath, -- ^ to find the correct ghc, required.- argTargets :: [FilePath] -- ^ modules to process.+ argOutput :: Flag [Output],+ -- ^ HTML or Hoogle doc or both? Required.+ argInterfaces :: [(FilePath, Maybe String)],+ -- ^ [(Interface file, URL to the HTML docs for links)].+ argOutputDir :: Directory,+ -- ^ Where to generate the documentation.+ argTitle :: Flag String,+ -- ^ Page title, required.+ argPrologue :: Flag String,+ -- ^ Prologue text, required.+ argGhcOptions :: Flag (GhcOptions, Version),+ -- ^ Additional flags to pass to GHC.+ argGhcLibDir :: Flag FilePath,+ -- ^ To find the correct GHC, required.+ argTargets :: [FilePath]+ -- ^ Modules to process. } --- | the FilePath of a directory, it's a monoid under (</>)+-- | The FilePath of a directory, it's a monoid under '(</>)'. newtype Directory = Dir { unDir' :: FilePath } deriving (Read,Show,Eq,Ord) unDir :: Directory -> FilePath@@ -123,7 +146,11 @@ -- ------------------------------------------------------------------------------ -- Haddock support -haddock :: PackageDescription -> LocalBuildInfo -> [PPSuffixHandler] -> HaddockFlags -> IO ()+haddock :: PackageDescription+ -> LocalBuildInfo+ -> [PPSuffixHandler]+ -> HaddockFlags+ -> IO () haddock pkg_descr _ _ haddockFlags | not (hasLibs pkg_descr) && not (fromFlag $ haddockExecutables haddockFlags)@@ -148,23 +175,24 @@ haddockGhcVersionStr <- rawSystemProgramStdout verbosity confHaddock ["--ghc-version"]- case simpleParse haddockGhcVersionStr of- Nothing -> die "Could not get GHC version from Haddock"- Just haddockGhcVersion+ case (simpleParse haddockGhcVersionStr, compilerCompatVersion GHC comp) of+ (Nothing, _) -> die "Could not get GHC version from Haddock"+ (_, Nothing) -> die "Could not get GHC version from compiler"+ (Just haddockGhcVersion, Just ghcVersion) | haddockGhcVersion == ghcVersion -> return () | otherwise -> die $ "Haddock's internal GHC version must match the configured " ++ "GHC version.\n" ++ "The GHC version is " ++ display ghcVersion ++ " but " ++ "haddock is using GHC version " ++ display haddockGhcVersion- where ghcVersion = compilerVersion comp -- the tools match the requests, we can proceed initialBuildSteps (flag haddockDistPref) pkg_descr lbi verbosity - when (flag haddockHscolour) $ hscolour' pkg_descr lbi suffixes $- defaultHscolourFlags `mappend` haddockToHscolour flags+ when (flag haddockHscolour) $+ hscolour' (warn verbosity) pkg_descr lbi suffixes+ (defaultHscolourFlags `mappend` haddockToHscolour flags) libdirArgs <- getGhcLibDir verbosity lbi let commonArgs = mconcat@@ -178,22 +206,24 @@ let doExe com = case (compToExe com) of Just exe -> do- withTempDirectoryEx verbosity tmpFileOpts (buildDir lbi) "tmp" $ \tmp -> do- exeArgs <- fromExecutable verbosity tmp lbi exe clbi htmlTemplate- version- let exeArgs' = commonArgs `mappend` exeArgs- runHaddock verbosity tmpFileOpts comp confHaddock exeArgs'+ withTempDirectoryEx verbosity tmpFileOpts (buildDir lbi) "tmp" $+ \tmp -> do+ exeArgs <- fromExecutable verbosity tmp lbi exe clbi htmlTemplate+ version+ let exeArgs' = commonArgs `mappend` exeArgs+ runHaddock verbosity tmpFileOpts comp confHaddock exeArgs' Nothing -> do warn (fromFlag $ haddockVerbosity flags) "Unsupported component, skipping..." return () case component of CLib lib -> do- withTempDirectoryEx verbosity tmpFileOpts (buildDir lbi) "tmp" $ \tmp -> do- libArgs <- fromLibrary verbosity tmp lbi lib clbi htmlTemplate- version- let libArgs' = commonArgs `mappend` libArgs- runHaddock verbosity tmpFileOpts comp confHaddock libArgs'+ withTempDirectoryEx verbosity tmpFileOpts (buildDir lbi) "tmp" $+ \tmp -> do+ libArgs <- fromLibrary verbosity tmp lbi lib clbi htmlTemplate+ version+ let libArgs' = commonArgs `mappend` libArgs+ runHaddock verbosity tmpFileOpts comp confHaddock libArgs' CExe _ -> when (flag haddockExecutables) $ doExe component CTest _ -> when (flag haddockTestSuites) $ doExe component CBench _ -> when (flag haddockBenchmarks) $ doExe component@@ -207,7 +237,8 @@ comp = compiler lbi tmpFileOpts = defaultTempFileOptions { optKeepTempFiles = keepTempFiles } flag f = fromFlag $ f flags- htmlTemplate = fmap toPathTemplate . flagToMaybe . haddockHtmlLocation $ flags+ htmlTemplate = fmap toPathTemplate . flagToMaybe . haddockHtmlLocation+ $ flags -- ------------------------------------------------------------------------------ -- Contributions to HaddockArgs.@@ -215,15 +246,18 @@ fromFlags :: PathTemplateEnv -> HaddockFlags -> HaddockArgs fromFlags env flags = mempty {- argHideModules = (maybe mempty (All . not) $ flagToMaybe (haddockInternal flags), mempty),+ argHideModules = (maybe mempty (All . not)+ $ flagToMaybe (haddockInternal flags), mempty), argLinkSource = if fromFlag (haddockHscolour flags) then Flag ("src/%{MODULE/./-}.html" ,"src/%{MODULE/./-}.html#%{NAME}" ,"src/%{MODULE/./-}.html#line-%{LINE}") else NoFlag, argCssFile = haddockCss flags,- argContents = fmap (fromPathTemplate . substPathTemplate env) (haddockContents flags),- argVerbose = maybe mempty (Any . (>= deafening)) . flagToMaybe $ haddockVerbosity flags,+ argContents = fmap (fromPathTemplate . substPathTemplate env)+ (haddockContents flags),+ argVerbose = maybe mempty (Any . (>= deafening))+ . flagToMaybe $ haddockVerbosity flags, argOutput = Flag $ case [ Html | Flag True <- [haddockHtml flags] ] ++ [ Hoogle | Flag True <- [haddockHoogle flags] ]@@ -234,12 +268,13 @@ fromPackageDescription :: PackageDescription -> HaddockArgs fromPackageDescription pkg_descr =- mempty {- argInterfaceFile = Flag $ haddockName pkg_descr,- argPackageName = Flag $ packageId $ pkg_descr,- argOutputDir = Dir $ "doc" </> "html" </> display (packageName pkg_descr),- argPrologue = Flag $ if null desc then synopsis pkg_descr else desc,- argTitle = Flag $ showPkg ++ subtitle+ mempty { argInterfaceFile = Flag $ haddockName pkg_descr,+ argPackageName = Flag $ packageId $ pkg_descr,+ argOutputDir = Dir $ "doc" </> "html"+ </> display (packageName pkg_descr),+ argPrologue = Flag $ if null desc then synopsis pkg_descr+ else desc,+ argTitle = Flag $ showPkg ++ subtitle } where desc = PD.description pkg_descr@@ -247,6 +282,18 @@ subtitle | null (synopsis pkg_descr) = "" | otherwise = ": " ++ synopsis pkg_descr +componentGhcOptions :: Verbosity -> LocalBuildInfo+ -> BuildInfo -> ComponentLocalBuildInfo -> FilePath+ -> GhcOptions+componentGhcOptions verbosity lbi bi clbi odir =+ let f = case compilerFlavor (compiler lbi) of+ GHC -> GHC.componentGhcOptions+ GHCJS -> GHCJS.componentGhcOptions+ _ -> error $+ "Distribution.Simple.Haddock.componentGhcOptions:" +++ "haddock only supports GHC and GHCJS"+ in f verbosity lbi bi clbi odir+ fromLibrary :: Verbosity -> FilePath -> LocalBuildInfo -> Library -> ComponentLocalBuildInfo@@ -270,13 +317,20 @@ ghcOptFPic = toFlag True, ghcOptHiSuffix = toFlag "dyn_hi", ghcOptObjSuffix = toFlag "dyn_o",- ghcOptExtra = ghcSharedOptions bi+ ghcOptExtra =+ toNubListR $ hcSharedOptions GHC bi+ } opts <- if withVanillaLib lbi then return vanillaOpts else if withSharedLib lbi then return sharedOpts- else die "Must have vanilla or shared libraries enabled in order to run haddock"+ else die $ "Must have vanilla or shared libraries "+ ++ "enabled in order to run haddock"+ ghcVersion <- maybe (die "Compiler has no GHC version")+ return+ (compilerCompatVersion GHC (compiler lbi))+ return ifaceArgs { argHideModules = (mempty,otherModules $ bi), argGhcOptions = toFlag (opts, ghcVersion),@@ -284,7 +338,6 @@ } where bi = libBuildInfo lib- ghcVersion = compilerVersion (compiler lbi) fromExecutable :: Verbosity -> FilePath@@ -309,13 +362,19 @@ ghcOptFPic = toFlag True, ghcOptHiSuffix = toFlag "dyn_hi", ghcOptObjSuffix = toFlag "dyn_o",- ghcOptExtra = ghcSharedOptions bi+ ghcOptExtra =+ toNubListR $ hcSharedOptions GHC bi } opts <- if withVanillaLib lbi then return vanillaOpts else if withSharedLib lbi then return sharedOpts- else die "Must have vanilla or shared libraries enabled in order to run haddock"+ else die $ "Must have vanilla or shared libraries "+ ++ "enabled in order to run haddock"+ ghcVersion <- maybe (die "Compiler has no GHC version")+ return+ (compilerCompatVersion GHC (compiler lbi))+ return ifaceArgs { argGhcOptions = toFlag (opts, ghcVersion), argOutputDir = Dir (exeName exe),@@ -324,7 +383,6 @@ } where bi = buildInfo exe- ghcVersion = compilerVersion (compiler lbi) compToExe :: Component -> Maybe Executable compToExe comp =@@ -361,8 +419,8 @@ -> GhcOptions getGhcCppOpts haddockVersion bi = mempty {- ghcOptExtensions = [EnableExtension CPP | needsCpp],- ghcOptCppOptions = defines+ ghcOptExtensions = toNubListR [EnableExtension CPP | needsCpp],+ ghcOptCppOptions = toNubListR defines } where needsCpp = EnableExtension CPP `elem` usedExtensions bi@@ -375,7 +433,10 @@ getGhcLibDir :: Verbosity -> LocalBuildInfo -> IO HaddockArgs getGhcLibDir verbosity lbi = do- l <- ghcLibDir verbosity lbi+ l <- case compilerFlavor (compiler lbi) of+ GHC -> GHC.getLibDir verbosity lbi+ GHCJS -> GHCJS.getLibDir verbosity lbi+ _ -> error "haddock only supports GHC and GHCJS" return $ mempty { argGhcLibDir = Flag l } -- ------------------------------------------------------------------------------@@ -406,12 +467,13 @@ -> IO a renderArgs verbosity tmpFileOpts version comp args k = do createDirectoryIfMissingVerbose verbosity True outputDir- withTempFileEx tmpFileOpts outputDir "haddock-prolog.txt" $ \prologFileName h -> do+ withTempFileEx tmpFileOpts outputDir "haddock-prologue.txt" $+ \prologueFileName h -> do do when (version >= Version [2,14,4] []) (hSetEncoding h utf8) hPutStrLn h $ fromFlag $ argPrologue args hClose h- let pflag = "--prologue=" ++ prologFileName+ let pflag = "--prologue=" ++ prologueFileName k (pflag : renderPureArgs version comp args, result) where outputDir = (unDir $ argOutputDir args)@@ -428,30 +490,49 @@ renderPureArgs :: Version -> Compiler -> HaddockArgs -> [String] renderPureArgs version comp args = concat- [- (:[]) . (\f -> "--dump-interface="++ unDir (argOutputDir args) </> f)- . fromFlag . argInterfaceFile $ args,- (\pname -> ["--optghc=-package-name", "--optghc=" ++ pname]- ) . display . fromFlag . argPackageName $ args,- (\(All b,xs) -> bool (map (("--hide=" ++). display) xs) [] b) . argHideModules $ args,- bool ["--ignore-all-exports"] [] . getAny . argIgnoreExports $ args,- maybe [] (\(m,e,l) -> ["--source-module=" ++ m- ,"--source-entity=" ++ e]- ++ if isVersion2_14 then ["--source-entity-line=" ++ l]- else []- ) . flagToMaybe . argLinkSource $ args,- maybe [] ((:[]).("--css="++)) . flagToMaybe . argCssFile $ args,- maybe [] ((:[]).("--use-contents="++)) . flagToMaybe . argContents $ args,- bool [] [verbosityFlag] . getAny . argVerbose $ args,- map (\o -> case o of Hoogle -> "--hoogle"; Html -> "--html") . fromFlag . argOutput $ args,- renderInterfaces . argInterfaces $ args,- (:[]).("--odir="++) . unDir . argOutputDir $ args,- (:[]).("--title="++) . (bool (++" (internal documentation)") id (getAny $ argIgnoreExports args))- . fromFlag . argTitle $ args,- [ "--optghc=" ++ opt | (opts, _ghcVer) <- flagToList (argGhcOptions args)- , opt <- renderGhcOptions comp opts ],- maybe [] (\l -> ["-B"++l]) $ flagToMaybe (argGhcLibDir args), -- error if Nothing?- argTargets $ args+ [ (:[]) . (\f -> "--dump-interface="++ unDir (argOutputDir args) </> f)+ . fromFlag . argInterfaceFile $ args++ , (\pname -> ["--optghc=-package-name", "--optghc=" ++ pname])+ . display . fromFlag . argPackageName $ args++ , (\(All b,xs) -> bool (map (("--hide=" ++). display) xs) [] b)+ . argHideModules $ args++ , bool ["--ignore-all-exports"] [] . getAny . argIgnoreExports $ args++ , maybe [] (\(m,e,l) ->+ ["--source-module=" ++ m+ ,"--source-entity=" ++ e]+ ++ if isVersion2_14 then ["--source-entity-line=" ++ l]+ else []+ ) . flagToMaybe . argLinkSource $ args++ , maybe [] ((:[]) . ("--css="++)) . flagToMaybe . argCssFile $ args++ , maybe [] ((:[]) . ("--use-contents="++)) . flagToMaybe . argContents $ args++ , bool [] [verbosityFlag] . getAny . argVerbose $ args++ , map (\o -> case o of Hoogle -> "--hoogle"; Html -> "--html")+ . fromFlag . argOutput $ args++ , renderInterfaces . argInterfaces $ args++ , (:[]) . ("--odir="++) . unDir . argOutputDir $ args++ , (:[]) . ("--title="++)+ . (bool (++" (internal documentation)")+ id (getAny $ argIgnoreExports args))+ . fromFlag . argTitle $ args++ , [ "--optghc=" ++ opt | (opts, _ghcVer) <- flagToList (argGhcOptions args)+ , opt <- renderGhcOptions comp opts ]++ , maybe [] (\l -> ["-B"++l]) $+ flagToMaybe (argGhcLibDir args) -- error if Nothing?++ , argTargets $ args ] where renderInterfaces =@@ -534,60 +615,68 @@ haddockTemplateEnv :: LocalBuildInfo -> PackageIdentifier -> PathTemplateEnv haddockTemplateEnv lbi pkg_id = (PrefixVar, prefix (installDirTemplates lbi))- : initialPathTemplateEnv pkg_id (compilerId (compiler lbi))+ : initialPathTemplateEnv pkg_id (pkgKey lbi) (compilerInfo (compiler lbi)) (hostPlatform lbi) -- ------------------------------------------------------------------------------ -- hscolour support. -hscolour :: PackageDescription -> LocalBuildInfo -> [PPSuffixHandler] -> HscolourFlags -> IO ()+hscolour :: PackageDescription+ -> LocalBuildInfo+ -> [PPSuffixHandler]+ -> HscolourFlags+ -> IO () hscolour pkg_descr lbi suffixes flags = do -- we preprocess even if hscolour won't be found on the machine -- will this upset someone? initialBuildSteps distPref pkg_descr lbi verbosity- hscolour' pkg_descr lbi suffixes flags+ hscolour' die pkg_descr lbi suffixes flags where verbosity = fromFlag (hscolourVerbosity flags) distPref = fromFlag $ hscolourDistPref flags -hscolour' :: PackageDescription+hscolour' :: (String -> IO ()) -- ^ Called when the 'hscolour' exe is not found.+ -> PackageDescription -> LocalBuildInfo -> [PPSuffixHandler] -> HscolourFlags -> IO ()-hscolour' pkg_descr lbi suffixes flags = do- let distPref = fromFlag $ hscolourDistPref flags- (hscolourProg, _, _) <-- requireProgramVersion- verbosity hscolourProgram- (orLaterVersion (Version [1,8] [])) (withPrograms lbi)+hscolour' onNoHsColour pkg_descr lbi suffixes flags =+ either onNoHsColour (\(hscolourProg, _, _) -> go hscolourProg) =<<+ lookupProgramVersion verbosity hscolourProgram+ (orLaterVersion (Version [1,8] [])) (withPrograms lbi)+ where+ go :: ConfiguredProgram -> IO ()+ go hscolourProg = do+ setupMessage verbosity "Running hscolour for" (packageId pkg_descr)+ createDirectoryIfMissingVerbose verbosity True $+ hscolourPref distPref pkg_descr - setupMessage verbosity "Running hscolour for" (packageId pkg_descr)- createDirectoryIfMissingVerbose verbosity True $ hscolourPref distPref pkg_descr+ let pre c = preprocessComponent pkg_descr c lbi False verbosity suffixes+ withAllComponentsInBuildOrder pkg_descr lbi $ \comp _ -> do+ pre comp+ let+ doExe com = case (compToExe com) of+ Just exe -> do+ let outputDir = hscolourPref distPref pkg_descr+ </> exeName exe </> "src"+ runHsColour hscolourProg outputDir =<< getExeSourceFiles lbi exe+ Nothing -> do+ warn (fromFlag $ hscolourVerbosity flags)+ "Unsupported component, skipping..."+ return ()+ case comp of+ CLib lib -> do+ let outputDir = hscolourPref distPref pkg_descr </> "src"+ runHsColour hscolourProg outputDir =<< getLibSourceFiles lbi lib+ CExe _ -> when (fromFlag (hscolourExecutables flags)) $ doExe comp+ CTest _ -> when (fromFlag (hscolourTestSuites flags)) $ doExe comp+ CBench _ -> when (fromFlag (hscolourBenchmarks flags)) $ doExe comp - let pre c = preprocessComponent pkg_descr c lbi False verbosity suffixes- withAllComponentsInBuildOrder pkg_descr lbi $ \comp _ -> do- pre comp- let- doExe com = case (compToExe com) of- Just exe -> do- let outputDir = hscolourPref distPref pkg_descr </> exeName exe </> "src"- runHsColour hscolourProg outputDir =<< getExeSourceFiles lbi exe- Nothing -> do- warn (fromFlag $ hscolourVerbosity flags)- "Unsupported component, skipping..."- return ()- case comp of- CLib lib -> do- let outputDir = hscolourPref distPref pkg_descr </> "src"- runHsColour hscolourProg outputDir =<< getLibSourceFiles lbi lib- CExe _ -> when (fromFlag (hscolourExecutables flags)) $ doExe comp- CTest _ -> when (fromFlag (hscolourTestSuites flags)) $ doExe comp- CBench _ -> when (fromFlag (hscolourBenchmarks flags)) $ doExe comp- where stylesheet = flagToMaybe (hscolourCSS flags) verbosity = fromFlag (hscolourVerbosity flags)+ distPref = fromFlag (hscolourDistPref flags) runHsColour prog outputDir moduleFiles = do createDirectoryIfMissingVerbose verbosity True outputDir@@ -603,7 +692,8 @@ rawSystemProgram verbosity prog ["-css", "-anchor", "-o" ++ outFile m, inFile] where- outFile m = outputDir </> intercalate "-" (ModuleName.components m) <.> "html"+ outFile m = outputDir </>+ intercalate "-" (ModuleName.components m) <.> "html" haddockToHscolour :: HaddockFlags -> HscolourFlags haddockToHscolour flags =
Distribution/Simple/HaskellSuite.hs view
@@ -73,6 +73,8 @@ let comp = Compiler { compilerId = CompilerId (HaskellSuite compName) compVersion,+ compilerAbiTag = Compiler.NoAbiTag,+ compilerCompat = [], compilerLanguages = languages, compilerExtensions = extensions, compilerProperties = M.empty@@ -117,7 +119,7 @@ -- Other compilers do some kind of a packagedb stack check here. Not sure -- if we need something like that as well. getInstalledPackages :: Verbosity -> PackageDBStack -> ProgramConfiguration- -> IO PackageIndex+ -> IO InstalledPackageIndex getInstalledPackages verbosity packagedbs conf = liftM (PackageIndex.fromList . concat) $ forM packagedbs $ \packagedb -> do str <-@@ -172,6 +174,7 @@ | (ipkgid, _) <- componentPackageDeps clbi ] ++ ["-G", display language] ++ concat [ ["-X", display ex] | ex <- usedExtensions bi ] +++ cppOptions (libBuildInfo lib) ++ [ display modu | modu <- libModules lib ]
Distribution/Simple/Hpc.hs view
@@ -12,8 +12,9 @@ -- build test suites with HPC enabled. module Distribution.Simple.Hpc- ( enableCoverage+ ( Way(..), guessWay , htmlDir+ , mixDir , tixDir , tixFilePath , markupPackage@@ -21,13 +22,9 @@ ) where import Control.Monad ( when )-import Distribution.Compiler ( CompilerFlavor(..) ) import Distribution.ModuleName ( main ) import Distribution.PackageDescription- ( BuildInfo(..)- , Library(..)- , PackageDescription(..)- , TestSuite(..)+ ( TestSuite(..) , testModules ) import Distribution.Simple.LocalBuildInfo ( LocalBuildInfo(..) )@@ -38,7 +35,6 @@ import Distribution.Simple.Program.Hpc ( markup, union ) import Distribution.Simple.Utils ( notice ) import Distribution.Version ( anyVersion )-import Distribution.Text import Distribution.Verbosity ( Verbosity() ) import System.Directory ( createDirectoryIfMissing, doesFileExist ) import System.FilePath@@ -46,63 +42,52 @@ -- ------------------------------------------------------------------------- -- Haskell Program Coverage --- | Conditionally enable Haskell Program Coverage by adding the necessary--- GHC options to a PackageDescription.------ TODO: do this differently in the build stage by constructing local build--- info, not by modifying the original PackageDescription.----enableCoverage :: Bool -- ^ Enable coverage?- -> String -- ^ \"dist/\" prefix- -> PackageDescription- -> PackageDescription-enableCoverage False _ x = x-enableCoverage True distPref p =- p { library = fmap enableLibCoverage (library p)- , testSuites = map enableTestCoverage (testSuites p)- }- where- enableBICoverage name oldBI =- let oldOptions = options oldBI- oldGHCOpts = lookup GHC oldOptions- newGHCOpts = case oldGHCOpts of- Just xs -> (GHC, hpcOpts ++ xs)- _ -> (GHC, hpcOpts)- newOptions = (:) newGHCOpts $ filter ((== GHC) . fst) oldOptions- hpcOpts = ["-fhpc", "-hpcdir", mixDir distPref name]- in oldBI { options = newOptions }- enableLibCoverage l =- l { libBuildInfo = enableBICoverage (display $ package p)- (libBuildInfo l)- }- enableTestCoverage t =- t { testBuildInfo = enableBICoverage (testName t) (testBuildInfo t) }+data Way = Vanilla | Prof | Dyn+ deriving (Bounded, Enum, Eq, Read, Show) hpcDir :: FilePath -- ^ \"dist/\" prefix+ -> Way -> FilePath -- ^ Directory containing component's HPC .mix files-hpcDir distPref = distPref </> "hpc"+hpcDir distPref way = distPref </> "hpc" </> wayDir+ where+ wayDir = case way of+ Vanilla -> "vanilla"+ Prof -> "prof"+ Dyn -> "dyn" mixDir :: FilePath -- ^ \"dist/\" prefix+ -> Way -> FilePath -- ^ Component name -> FilePath -- ^ Directory containing test suite's .mix files-mixDir distPref name = hpcDir distPref </> "mix" </> name+mixDir distPref way name = hpcDir distPref way </> "mix" </> name tixDir :: FilePath -- ^ \"dist/\" prefix+ -> Way -> FilePath -- ^ Component name -> FilePath -- ^ Directory containing test suite's .tix files-tixDir distPref name = hpcDir distPref </> "tix" </> name+tixDir distPref way name = hpcDir distPref way </> "tix" </> name -- | Path to the .tix file containing a test suite's sum statistics. tixFilePath :: FilePath -- ^ \"dist/\" prefix+ -> Way -> FilePath -- ^ Component name -> FilePath -- ^ Path to test suite's .tix file-tixFilePath distPref name = tixDir distPref name </> name <.> "tix"+tixFilePath distPref way name = tixDir distPref way name </> name <.> "tix" htmlDir :: FilePath -- ^ \"dist/\" prefix+ -> Way -> FilePath -- ^ Component name -> FilePath -- ^ Path to test suite's HTML markup directory-htmlDir distPref name = hpcDir distPref </> "html" </> name+htmlDir distPref way name = hpcDir distPref way </> "html" </> name +-- | Attempt to guess the way the test suites in this package were compiled+-- and linked with the library so the correct module interfaces are found.+guessWay :: LocalBuildInfo -> Way+guessWay lbi+ | withProfExe lbi = Prof+ | withDynExe lbi = Dyn+ | otherwise = Vanilla+ -- | Generate the HTML markup for a test suite. markupTest :: Verbosity -> LocalBuildInfo@@ -111,21 +96,22 @@ -> TestSuite -> IO () markupTest verbosity lbi distPref libName suite = do- tixFileExists <- doesFileExist $ tixFilePath distPref $ testName suite+ tixFileExists <- doesFileExist $ tixFilePath distPref way $ testName suite when tixFileExists $ do -- behaviour of 'markup' depends on version, so we need *a* version -- but no particular one (hpc, hpcVer, _) <- requireProgramVersion verbosity hpcProgram anyVersion (withPrograms lbi)+ let htmlDir_ = htmlDir distPref way $ testName suite markup hpc hpcVer verbosity- (tixFilePath distPref $ testName suite) mixDirs- (htmlDir distPref $ testName suite)+ (tixFilePath distPref way $ testName suite) mixDirs+ htmlDir_ (testModules suite ++ [ main ]) notice verbosity $ "Test coverage report written to "- ++ htmlDir distPref (testName suite)- </> "hpc_index" <.> "html"+ ++ htmlDir_ </> "hpc_index" <.> "html" where- mixDirs = map (mixDir distPref) [ testName suite, libName ]+ way = guessWay lbi+ mixDirs = map (mixDir distPref way) [ testName suite, libName ] -- | Generate the HTML markup for all of a package's test suites. markupPackage :: Verbosity@@ -135,15 +121,15 @@ -> [TestSuite] -> IO () markupPackage verbosity lbi distPref libName suites = do- let tixFiles = map (tixFilePath distPref . testName) suites+ let tixFiles = map (tixFilePath distPref way . testName) suites tixFilesExist <- mapM doesFileExist tixFiles when (and tixFilesExist) $ do -- behaviour of 'markup' depends on version, so we need *a* version -- but no particular one (hpc, hpcVer, _) <- requireProgramVersion verbosity hpcProgram anyVersion (withPrograms lbi)- let outFile = tixFilePath distPref libName- htmlDir' = htmlDir distPref libName+ let outFile = tixFilePath distPref way libName+ htmlDir' = htmlDir distPref way libName excluded = concatMap testModules suites ++ [ main ] createDirectoryIfMissing True $ takeDirectory outFile union hpc verbosity tixFiles outFile excluded@@ -151,4 +137,5 @@ notice verbosity $ "Package coverage report written to " ++ htmlDir' </> "hpc_index.html" where- mixDirs = map (mixDir distPref) $ libName : map testName suites+ way = guessWay lbi+ mixDirs = map (mixDir distPref way) $ libName : map testName suites
− Distribution/Simple/Hugs.hs
@@ -1,609 +0,0 @@--------------------------------------------------------------------------------- |--- Module : Distribution.Simple.Hugs--- Copyright : Isaac Jones 2003-2006--- Duncan Coutts 2009--- License : BSD3------ Maintainer : cabal-devel@haskell.org--- Portability : portable------ This module contains most of the NHC-specific code for configuring, building--- and installing packages.--module Distribution.Simple.Hugs (- configure,- getInstalledPackages,- buildLib,- buildExe,- install,- registerPackage,- ) where--import Distribution.Package- ( PackageName, PackageIdentifier(..), InstalledPackageId(..)- , packageName )-import Distribution.InstalledPackageInfo- ( InstalledPackageInfo, emptyInstalledPackageInfo- , InstalledPackageInfo_( InstalledPackageInfo, installedPackageId- , sourcePackageId )- , parseInstalledPackageInfo, showInstalledPackageInfo )-import Distribution.PackageDescription- ( PackageDescription(..), BuildInfo(..), hcOptions, allExtensions- , Executable(..), withExe, Library(..), withLib, libModules )-import Distribution.ModuleName (ModuleName)-import qualified Distribution.ModuleName as ModuleName-import Distribution.Simple.Compiler- ( CompilerFlavor(..), CompilerId(..)- , Compiler(..), Flag, languageToFlags, extensionsToFlags- , PackageDB(..), PackageDBStack )-import qualified Distribution.Simple.PackageIndex as PackageIndex-import Distribution.Simple.PackageIndex (PackageIndex)-import Distribution.Simple.Program- ( Program(programFindVersion)- , ProgramConfiguration, userMaybeSpecifyPath- , requireProgram, requireProgramVersion- , rawSystemProgramConf, programPath- , ffihugsProgram, hugsProgram )-import Distribution.Version- ( Version(..), orLaterVersion )-import Distribution.Simple.PreProcess ( ppCpp, runSimplePreProcessor )-import Distribution.Simple.PreProcess.Unlit- ( unlit )-import Distribution.Simple.LocalBuildInfo- ( LocalBuildInfo(..), ComponentLocalBuildInfo(..)- , InstallDirs(..), absoluteInstallDirs )-import Distribution.Simple.BuildPaths- ( autogenModuleName, autogenModulesDir,- dllExtension )-import Distribution.Simple.Setup- ( CopyDest(..) )-import Distribution.Simple.Utils- ( createDirectoryIfMissingVerbose- , installOrdinaryFiles, setFileExecutable- , withUTF8FileContents, writeFileAtomic, writeUTF8File- , copyFileVerbose, findFile, findFileWithExtension, findModuleFiles- , rawSystemStdInOut- , die, info, notice )-import Language.Haskell.Extension- ( Language(Haskell98), Extension(..), KnownExtension(..) )-import System.FilePath ( (</>), takeExtension, (<.>),- searchPathSeparator, normalise, takeDirectory )-import Distribution.System- ( OS(..), buildOS )-import Distribution.Text- ( display, simpleParse )-import Distribution.ParseUtils- ( ParseResult(..) )-import Distribution.Verbosity--import Data.Char ( isSpace )-import qualified Data.Map as M ( empty )-import Data.Maybe ( mapMaybe, catMaybes )-import Data.Monoid ( Monoid(..) )-import Control.Monad ( unless, when, filterM )-import Data.List ( nub, sort, isSuffixOf )-import System.Directory- ( doesFileExist, doesDirectoryExist, getDirectoryContents- , removeDirectoryRecursive, getHomeDirectory )-import System.Exit- ( ExitCode(ExitSuccess) )-import Distribution.Compat.Exception-import Distribution.System ( Platform )--import qualified Data.ByteString.Lazy.Char8 as BS.Char8---- -------------------------------------------------------------------------------- Configuring--configure :: Verbosity -> Maybe FilePath -> Maybe FilePath- -> ProgramConfiguration -> IO (Compiler, Maybe Platform, ProgramConfiguration)-configure verbosity hcPath _hcPkgPath conf = do-- (_ffihugsProg, conf') <- requireProgram verbosity ffihugsProgram- (userMaybeSpecifyPath "ffihugs" hcPath conf)- (_hugsProg, version, conf'')- <- requireProgramVersion verbosity hugsProgram'- (orLaterVersion (Version [2006] [])) conf'-- let comp = Compiler {- compilerId = CompilerId Hugs version,- compilerLanguages = hugsLanguages,- compilerExtensions = hugsLanguageExtensions,- compilerProperties = M.empty- }- compPlatform = Nothing- return (comp, compPlatform, conf'')-- where- hugsProgram' = hugsProgram { programFindVersion = getVersion }--getVersion :: Verbosity -> FilePath -> IO (Maybe Version)-getVersion verbosity hugsPath = do- (output, _err, exit) <- rawSystemStdInOut verbosity hugsPath []- Nothing Nothing- (Just (":quit", False)) False- if exit == ExitSuccess- then return $! findVersion output- else return Nothing-- where- findVersion output = do- (monthStr, yearStr) <- selectWords output- year <- convertYear yearStr- month <- convertMonth monthStr- return (Version [year, month] [])-- selectWords output =- case [ (month, year)- | [_,_,"Version:", month, year,_] <- map words (lines output) ] of- [(month, year)] -> Just (month, year)- _ -> Nothing- convertYear year = case reads year of- [(y, [])] | y >= 1999 && y < 2020 -> Just y- _ -> Nothing- convertMonth month = lookup month (zip months [1..])- months = [ "January", "February", "March", "April", "May", "June", "July"- , "August", "September", "October", "November", "December" ]--hugsLanguages :: [(Language, Flag)]-hugsLanguages = [(Haskell98, "")] --default is 98 mode---- | The flags for the supported extensions-hugsLanguageExtensions :: [(Extension, Flag)]-hugsLanguageExtensions =- let doFlag (f, (enable, disable)) = [(EnableExtension f, enable),- (DisableExtension f, disable)]- alwaysOn = ("", ""{- wrong -})- ext98 = ("-98", ""{- wrong -})- in concatMap doFlag- [(OverlappingInstances , ("+o", "-o"))- ,(IncoherentInstances , ("+oO", "-O"))- ,(HereDocuments , ("+H", "-H"))- ,(TypeSynonymInstances , ext98)- ,(RecursiveDo , ext98)- ,(ParallelListComp , ext98)- ,(MultiParamTypeClasses , ext98)- ,(FunctionalDependencies , ext98)- ,(Rank2Types , ext98)- ,(PolymorphicComponents , ext98)- ,(ExistentialQuantification , ext98)- ,(ScopedTypeVariables , ext98)- ,(ImplicitParams , ext98)- ,(ExtensibleRecords , ext98)- ,(RestrictedTypeSynonyms , ext98)- ,(FlexibleContexts , ext98)- ,(FlexibleInstances , ext98)- ,(ForeignFunctionInterface , alwaysOn)- ,(EmptyDataDecls , alwaysOn)- ,(CPP , alwaysOn)- ]--getInstalledPackages :: Verbosity -> PackageDBStack -> ProgramConfiguration- -> IO PackageIndex-getInstalledPackages verbosity packagedbs conf = do- homedir <- getHomeDirectory- (hugsProg, _) <- requireProgram verbosity hugsProgram conf- let hugsbindir = takeDirectory (programPath hugsProg)- hugslibdir = takeDirectory hugsbindir </> "lib" </> "hugs"- dbdirs = nub (concatMap (packageDbPaths homedir hugslibdir) packagedbs)- indexes <- mapM getIndividualDBPackages dbdirs- return $! mconcat indexes-- where- getIndividualDBPackages :: FilePath -> IO PackageIndex- getIndividualDBPackages dbdir = do- pkgdirs <- getPackageDbDirs dbdir- pkgs <- sequence [ getInstalledPackage pkgname pkgdir- | (pkgname, pkgdir) <- pkgdirs ]- let pkgs' = map setInstalledPackageId (catMaybes pkgs)- return (PackageIndex.fromList pkgs')--packageDbPaths :: FilePath -> FilePath -> PackageDB -> [FilePath]-packageDbPaths home hugslibdir db = case db of- GlobalPackageDB -> [ hugslibdir </> "packages"- , "/usr/local/lib/hugs/packages" ]- UserPackageDB -> [ home </> "lib/hugs/packages" ]- SpecificPackageDB path -> [ path ]--getPackageDbDirs :: FilePath -> IO [(PackageName, FilePath)]-getPackageDbDirs dbdir = do- dbexists <- doesDirectoryExist dbdir- if not dbexists- then return []- else do- entries <- getDirectoryContents dbdir- pkgdirs <- sequence- [ do pkgdirExists <- doesDirectoryExist pkgdir- return (pkgname, pkgdir, pkgdirExists)- | (entry, Just pkgname) <- [ (entry, simpleParse entry)- | entry <- entries ]- , let pkgdir = dbdir </> entry ]- return [ (pkgname, pkgdir) | (pkgname, pkgdir, True) <- pkgdirs ]--getInstalledPackage :: PackageName -> FilePath -> IO (Maybe InstalledPackageInfo)-getInstalledPackage pkgname pkgdir = do- let pkgconfFile = pkgdir </> "package.conf"- pkgconfExists <- doesFileExist pkgconfFile-- let pathsModule = pkgdir </> ("Paths_" ++ display pkgname) <.> "hs"- pathsModuleExists <- doesFileExist pathsModule-- case () of- _ | pkgconfExists -> getFullInstalledPackageInfo pkgname pkgconfFile- | pathsModuleExists -> getPhonyInstalledPackageInfo pkgname pathsModule- | otherwise -> return Nothing--getFullInstalledPackageInfo :: PackageName -> FilePath- -> IO (Maybe InstalledPackageInfo)-getFullInstalledPackageInfo pkgname pkgconfFile =- withUTF8FileContents pkgconfFile $ \contents ->- case parseInstalledPackageInfo contents of- ParseOk _ pkginfo | packageName pkginfo == pkgname- -> return (Just pkginfo)- _ -> return Nothing---- | This is a backup option for existing versions of Hugs which do not supply--- proper installed package info files for the bundled libs. Instead we look--- for the Paths_pkgname.hs file and extract the package version from that.--- We don't know any other details for such packages, in particular we pretend--- that they have no dependencies.----getPhonyInstalledPackageInfo :: PackageName -> FilePath- -> IO (Maybe InstalledPackageInfo)-getPhonyInstalledPackageInfo pkgname pathsModule = do- content <- readFile pathsModule- case extractVersion content of- Nothing -> return Nothing- Just version -> return (Just pkginfo)- where- pkgid = PackageIdentifier pkgname version- pkginfo = emptyInstalledPackageInfo { sourcePackageId = pkgid }- where- -- search through the Paths_pkgname.hs file, looking for a line like:- --- -- > version = Version {versionBranch = [2,0], versionTags = []}- --- -- and parse it using 'Read'. Yes we are that evil.- --- extractVersion content =- case [ version- | ("version":"=":rest) <- map words (lines content)- , (version, []) <- reads (concat rest) ] of- [version] -> Just version- _ -> Nothing---- Older installed package info files did not have the installedPackageId--- field, so if it is missing then we fill it as the source package ID.-setInstalledPackageId :: InstalledPackageInfo -> InstalledPackageInfo-setInstalledPackageId pkginfo@InstalledPackageInfo {- installedPackageId = InstalledPackageId "",- sourcePackageId = pkgid- }- = pkginfo {- --TODO use a proper named function for the conversion- -- from source package id to installed package id- installedPackageId = InstalledPackageId (display pkgid)- }-setInstalledPackageId pkginfo = pkginfo---- -------------------------------------------------------------------------------- Building---- |Building a package for Hugs.-buildLib :: Verbosity -> PackageDescription -> LocalBuildInfo- -> Library -> ComponentLocalBuildInfo -> IO ()-buildLib verbosity pkg_descr lbi lib _clbi = do- let pref = scratchDir lbi- createDirectoryIfMissingVerbose verbosity True pref- copyFileVerbose verbosity (autogenModulesDir lbi </> paths_modulename)- (pref </> paths_modulename)- compileBuildInfo verbosity pref [] (libModules lib) (libBuildInfo lib) lbi- where- paths_modulename = ModuleName.toFilePath (autogenModuleName pkg_descr)- <.> ".hs"- --TODO: switch to using autogenModulesDir as a search dir, rather than- -- always copying the file over.---- |Building an executable for Hugs.-buildExe :: Verbosity -> PackageDescription -> LocalBuildInfo- -> Executable -> ComponentLocalBuildInfo -> IO ()-buildExe verbosity pkg_descr lbi- exe@Executable {modulePath=mainPath, buildInfo=bi} _clbi = do- let pref = scratchDir lbi- createDirectoryIfMissingVerbose verbosity True pref- - let destDir = pref </> "programs"- let exeMods = otherModules bi- srcMainFile <- findFile (hsSourceDirs bi) mainPath- let exeDir = destDir </> exeName exe- let destMainFile = exeDir </> hugsMainFilename exe- copyModule verbosity (EnableExtension CPP `elem` allExtensions bi) bi lbi srcMainFile destMainFile- let destPathsFile = exeDir </> paths_modulename- copyFileVerbose verbosity (autogenModulesDir lbi </> paths_modulename)- destPathsFile- compileBuildInfo verbosity exeDir - (maybe [] (hsSourceDirs . libBuildInfo) (library pkg_descr)) exeMods bi lbi- compileFiles verbosity bi lbi exeDir [destMainFile, destPathsFile]-- where- paths_modulename = ModuleName.toFilePath (autogenModuleName pkg_descr)- <.> ".hs"--compileBuildInfo :: Verbosity- -> FilePath -- ^output directory- -> [FilePath] -- ^library source dirs, if building exes- -> [ModuleName] -- ^Modules- -> BuildInfo- -> LocalBuildInfo- -> IO ()---TODO: should not be using mLibSrcDirs at all-compileBuildInfo verbosity destDir mLibSrcDirs mods bi lbi = do- -- Pass 1: copy or cpp files from build directory to scratch directory- let useCpp = EnableExtension CPP `elem` allExtensions bi- let srcDir = buildDir lbi- srcDirs = nub $ srcDir : hsSourceDirs bi ++ mLibSrcDirs- info verbosity $ "Source directories: " ++ show srcDirs- flip mapM_ mods $ \ m -> do- fs <- findFileWithExtension suffixes srcDirs (ModuleName.toFilePath m)- case fs of- Nothing ->- die ("can't find source for module " ++ display m)- Just srcFile -> do- let ext = takeExtension srcFile- copyModule verbosity useCpp bi lbi srcFile- (destDir </> ModuleName.toFilePath m <.> ext)- -- Pass 2: compile foreign stubs in scratch directory- stubsFileLists <- fmap catMaybes $ sequence- [ findFileWithExtension suffixes [destDir] (ModuleName.toFilePath modu)- | modu <- mods]- compileFiles verbosity bi lbi destDir stubsFileLists--suffixes :: [String]-suffixes = ["hs", "lhs"]---- Copy or cpp a file from the source directory to the build directory.-copyModule :: Verbosity -> Bool -> BuildInfo -> LocalBuildInfo -> FilePath -> FilePath -> IO ()-copyModule verbosity cppAll bi lbi srcFile destFile = do- createDirectoryIfMissingVerbose verbosity True (takeDirectory destFile)- (exts, opts, _) <- getOptionsFromSource srcFile- let ghcOpts = [ op | (GHC, ops) <- opts, op <- ops ]- if cppAll || EnableExtension CPP `elem` exts || "-cpp" `elem` ghcOpts then do- runSimplePreProcessor (ppCpp bi lbi) srcFile destFile verbosity- return ()- else- copyFileVerbose verbosity srcFile destFile--compileFiles :: Verbosity -> BuildInfo -> LocalBuildInfo -> FilePath -> [FilePath] -> IO ()-compileFiles verbosity bi lbi modDir fileList = do- ffiFileList <- filterM testFFI fileList- unless (null ffiFileList) $ do- notice verbosity "Compiling FFI stubs"- mapM_ (compileFFI verbosity bi lbi modDir) ffiFileList---- Only compile FFI stubs for a file if it contains some FFI stuff-testFFI :: FilePath -> IO Bool-testFFI file =- withHaskellFile file $ \inp ->- return $! "foreign" `elem` symbols (stripComments False inp)--compileFFI :: Verbosity -> BuildInfo -> LocalBuildInfo -> FilePath -> FilePath -> IO ()-compileFFI verbosity bi lbi modDir file = do- (_, opts, file_incs) <- getOptionsFromSource file- let ghcOpts = [ op | (GHC, ops) <- opts, op <- ops ]- let pkg_incs = ["\"" ++ inc ++ "\"" | inc <- includes bi]- let incs = nub (sort (file_incs ++ includeOpts ghcOpts ++ pkg_incs))- let pathFlag = "-P" ++ modDir ++ [searchPathSeparator]- let hugsArgs = "-98" : pathFlag : map ("-i" ++) incs- cfiles <- getCFiles file- let cArgs =- ["-I" ++ dir | dir <- includeDirs bi] ++- ccOptions bi ++- cfiles ++- ["-L" ++ dir | dir <- extraLibDirs bi] ++- ldOptions bi ++- ["-l" ++ lib | lib <- extraLibs bi] ++- concat [["-framework", f] | f <- frameworks bi]- rawSystemProgramConf verbosity ffihugsProgram (withPrograms lbi)- (hugsArgs ++ file : cArgs)--includeOpts :: [String] -> [String]-includeOpts [] = []-includeOpts ("-#include" : arg : opts) = arg : includeOpts opts-includeOpts (_ : opts) = includeOpts opts---- get C file names from CFILES pragmas throughout the source file-getCFiles :: FilePath -> IO [String]-getCFiles file =- withHaskellFile file $ \inp ->- let cfiles =- [ normalise cfile- | "{-#" : "CFILES" : rest <- map words- $ lines- $ stripComments True inp- , last rest == "#-}"- , cfile <- init rest]- in seq (length cfiles) (return cfiles)---- List of terminal symbols in a source file.-symbols :: String -> [String]-symbols cs = case lex cs of- (sym, cs'):_ | not (null sym) -> sym : symbols cs'- _ -> []---- Get the non-literate source of a Haskell module.-withHaskellFile :: FilePath -> (String -> IO a) -> IO a-withHaskellFile file action =- withUTF8FileContents file $ \text ->- if ".lhs" `isSuffixOf` file- then either action die (unlit file text)- else action text---- --------------------------------------------------------------- * options in source files--- ---------------------------------------------------------------- |Read the initial part of a source file, before any Haskell code,--- and return the contents of any LANGUAGE, OPTIONS and INCLUDE pragmas.-getOptionsFromSource- :: FilePath- -> IO ([Extension], -- LANGUAGE pragma, if any- [(CompilerFlavor,[String])], -- OPTIONS_FOO pragmas- [String] -- INCLUDE pragmas- )-getOptionsFromSource file =- withHaskellFile file $- (return $!)- . foldr appendOptions ([],[],[]) . map getOptions- . takeWhileJust . map getPragma- . filter textLine . map (dropWhile isSpace) . lines- . stripComments True-- where textLine [] = False- textLine ('#':_) = False- textLine _ = True-- getPragma :: String -> Maybe [String]- getPragma line = case words line of- ("{-#" : rest) | last rest == "#-}" -> Just (init rest)- _ -> Nothing-- getOptions ("OPTIONS":opts) = ([], [(GHC, opts)], [])- getOptions ("OPTIONS_GHC":opts) = ([], [(GHC, opts)], [])- getOptions ("OPTIONS_NHC98":opts) = ([], [(NHC, opts)], [])- getOptions ("OPTIONS_HUGS":opts) = ([], [(Hugs, opts)], [])- getOptions ("LANGUAGE":ws) = (mapMaybe readExtension ws, [], [])- where readExtension :: String -> Maybe Extension- readExtension w = case reads w of- [(ext, "")] -> Just ext- [(ext, ",")] -> Just ext- _ -> Nothing- getOptions ("INCLUDE":ws) = ([], [], ws)- getOptions _ = ([], [], [])-- appendOptions (exts, opts, incs) (exts', opts', incs')- = (exts++exts', opts++opts', incs++incs')---- takeWhileJust f = map fromJust . takeWhile isJust-takeWhileJust :: [Maybe a] -> [a]-takeWhileJust (Just x:xs) = x : takeWhileJust xs-takeWhileJust _ = []---- |Strip comments from Haskell source.-stripComments- :: Bool -- ^ preserve pragmas?- -> String -- ^ input source text- -> String-stripComments keepPragmas = stripCommentsLevel 0- where stripCommentsLevel :: Int -> String -> String- stripCommentsLevel 0 ('"':cs) = '"':copyString cs- stripCommentsLevel 0 ('-':'-':cs) = -- FIX: symbols like -->- stripCommentsLevel 0 (dropWhile (/= '\n') cs)- stripCommentsLevel 0 ('{':'-':'#':cs)- | keepPragmas = '{' : '-' : '#' : copyPragma cs- stripCommentsLevel n ('{':'-':cs) = stripCommentsLevel (n+1) cs- stripCommentsLevel 0 (c:cs) = c : stripCommentsLevel 0 cs- stripCommentsLevel n ('-':'}':cs) = stripCommentsLevel (n-1) cs- stripCommentsLevel n (_:cs) = stripCommentsLevel n cs- stripCommentsLevel _ [] = []-- copyString ('\\':c:cs) = '\\' : c : copyString cs- copyString ('"':cs) = '"' : stripCommentsLevel 0 cs- copyString (c:cs) = c : copyString cs- copyString [] = []-- copyPragma ('#':'-':'}':cs) = '#' : '-' : '}' : stripCommentsLevel 0 cs- copyPragma (c:cs) = c : copyPragma cs- copyPragma [] = []---- -------------------------------------------------------------------------------- |Install for Hugs.--- For install, copy-prefix = prefix, but for copy they're different.--- The library goes in \<copy-prefix>\/lib\/hugs\/packages\/\<pkgname>--- (i.e. \<prefix>\/lib\/hugs\/packages\/\<pkgname> on the target system).--- Each executable goes in \<copy-prefix>\/lib\/hugs\/programs\/\<exename>--- (i.e. \<prefix>\/lib\/hugs\/programs\/\<exename> on the target system)--- with a script \<copy-prefix>\/bin\/\<exename> pointing at--- \<prefix>\/lib\/hugs\/programs\/\<exename>.-install- :: Verbosity -- ^verbosity- -> LocalBuildInfo- -> FilePath -- ^Library install location- -> FilePath -- ^Program install location- -> FilePath -- ^Executable install location- -> FilePath -- ^Program location on target system- -> FilePath -- ^Build location- -> (FilePath,FilePath) -- ^Executable (prefix,suffix)- -> PackageDescription- -> IO ()---FIXME: this script should be generated at build time, just installed at this stage-install verbosity lbi libDir installProgDir binDir targetProgDir buildPref (progprefix,progsuffix) pkg_descr = do- removeDirectoryRecursive libDir `catchIO` \_ -> return ()- withLib pkg_descr $ \ lib ->- findModuleFiles [buildPref] hugsInstallSuffixes (libModules lib)- >>= installOrdinaryFiles verbosity libDir- let buildProgDir = buildPref </> "programs"- when (any (buildable . buildInfo) (executables pkg_descr)) $- createDirectoryIfMissingVerbose verbosity True binDir- withExe pkg_descr $ \ exe -> do- let bi = buildInfo exe- let theBuildDir = buildProgDir </> exeName exe- let installDir = installProgDir </> exeName exe- let targetDir = targetProgDir </> exeName exe- removeDirectoryRecursive installDir `catchIO` \_ -> return ()- findModuleFiles [theBuildDir] hugsInstallSuffixes- (ModuleName.main : autogenModuleName pkg_descr- : otherModules (buildInfo exe))- >>= installOrdinaryFiles verbosity installDir- let targetName = "\"" ++ (targetDir </> hugsMainFilename exe) ++ "\""- let hugsOptions = hcOptions Hugs (buildInfo exe)- ++ languageToFlags (compiler lbi) (defaultLanguage bi)- ++ extensionsToFlags (compiler lbi) (allExtensions bi)- --TODO: also need to consider options, extensions etc of deps- -- see ticket #43- let baseExeFile = progprefix ++ (exeName exe) ++ progsuffix- let exeFile = case buildOS of- Windows -> binDir </> baseExeFile <.> ".bat"- _ -> binDir </> baseExeFile- let script = case buildOS of- Windows ->- let args = hugsOptions ++ [targetName, "%*"]- in unlines ["@echo off",- unwords ("runhugs" : args)]- _ ->- let args = hugsOptions ++ [targetName, "\"$@\""]- in unlines ["#! /bin/sh",- unwords ("runhugs" : args)]- writeFileAtomic exeFile (BS.Char8.pack script)- setFileExecutable exeFile--hugsInstallSuffixes :: [String]-hugsInstallSuffixes = [".hs", ".lhs", dllExtension]---- |Filename used by Hugs for the main module of an executable.--- This is a simple filename, so that Hugs will look for any auxiliary--- modules it uses relative to the directory it's in.-hugsMainFilename :: Executable -> FilePath-hugsMainFilename exe = "Main" <.> ext- where ext = takeExtension (modulePath exe)---- -------------------------------------------------------------------------------- Registering--registerPackage- :: Verbosity- -> InstalledPackageInfo- -> PackageDescription- -> LocalBuildInfo- -> Bool- -> PackageDBStack- -> IO ()-registerPackage verbosity installedPkgInfo pkg lbi inplace _packageDbs = do- --TODO: prefer to have it based on the packageDbs, but how do we know- -- the package subdir based on the name? the user can set crazy libsubdir- let installDirs = absoluteInstallDirs pkg lbi NoCopyDest- pkgdir | inplace = buildDir lbi- | otherwise = libdir installDirs- createDirectoryIfMissingVerbose verbosity True pkgdir- writeUTF8File (pkgdir </> "package.conf")- (showInstalledPackageInfo installedPkgInfo)
Distribution/Simple/Install.hs view
@@ -30,14 +30,13 @@ , die, info, notice, warn, matchDirFileGlob ) import Distribution.Simple.Compiler ( CompilerFlavor(..), compilerFlavor )-import Distribution.Simple.Setup (CopyFlags(..), CopyDest(..), fromFlag)+import Distribution.Simple.Setup (CopyFlags(..), fromFlag) -import qualified Distribution.Simple.GHC as GHC-import qualified Distribution.Simple.NHC as NHC-import qualified Distribution.Simple.JHC as JHC-import qualified Distribution.Simple.LHC as LHC-import qualified Distribution.Simple.Hugs as Hugs-import qualified Distribution.Simple.UHC as UHC+import qualified Distribution.Simple.GHC as GHC+import qualified Distribution.Simple.GHCJS as GHCJS+import qualified Distribution.Simple.JHC as JHC+import qualified Distribution.Simple.LHC as LHC+import qualified Distribution.Simple.UHC as UHC import qualified Distribution.Simple.HaskellSuite as HaskellSuite import Control.Monad (when, unless)@@ -51,8 +50,7 @@ ( display ) -- |Perform the \"@.\/setup install@\" and \"@.\/setup copy@\"--- actions. Move files into place based on the prefix argument. FIX:--- nhc isn't implemented yet.+-- actions. Move files into place based on the prefix argument. install :: PackageDescription -- ^information from the .cabal file -> LocalBuildInfo -- ^information from the configure step@@ -67,7 +65,6 @@ libdir = libPref, -- dynlibdir = dynlibPref, --see TODO below datadir = dataPref,- progdir = progPref, docdir = docPref, htmldir = htmlPref, haddockdir = interfacePref,@@ -134,6 +131,10 @@ GHC.installLib verbosity lbi libPref dynlibPref buildPref pkg_descr withExe pkg_descr $ GHC.installExe verbosity lbi installDirs buildPref (progPrefixPref, progSuffixPref) pkg_descr+ GHCJS-> do withLibLBI pkg_descr lbi $+ GHCJS.installLib verbosity lbi libPref dynlibPref buildPref pkg_descr+ withExe pkg_descr $+ GHCJS.installExe verbosity lbi installDirs buildPref (progPrefixPref, progSuffixPref) pkg_descr LHC -> do withLibLBI pkg_descr lbi $ LHC.installLib verbosity lbi libPref dynlibPref buildPref pkg_descr withExe pkg_descr $@@ -142,12 +143,6 @@ JHC.installLib verbosity libPref buildPref pkg_descr withExe pkg_descr $ JHC.installExe verbosity binPref buildPref (progPrefixPref, progSuffixPref) pkg_descr- Hugs -> do- let targetProgPref = progdir (absoluteInstallDirs pkg_descr lbi NoCopyDest)- let scratchPref = scratchDir lbi- Hugs.install verbosity lbi libPref progPref binPref targetProgPref scratchPref (progPrefixPref, progSuffixPref) pkg_descr- NHC -> do withLibLBI pkg_descr lbi $ NHC.installLib verbosity libPref buildPref (packageId pkg_descr)- withExe pkg_descr $ NHC.installExe verbosity binPref buildPref (progPrefixPref, progSuffixPref) UHC -> do withLib pkg_descr $ UHC.installLib verbosity lbi libPref dynlibPref buildPref pkg_descr HaskellSuite {} -> withLib pkg_descr $
Distribution/Simple/InstallDirs.hs view
@@ -1,4 +1,6 @@ {-# LANGUAGE CPP, ForeignFunctionInterface #-}+{-# LANGUAGE DeriveGeneric #-}+ ----------------------------------------------------------------------------- -- | -- Module : Distribution.Simple.InstallDirs@@ -37,23 +39,26 @@ platformTemplateEnv, compilerTemplateEnv, packageTemplateEnv,+ abiTemplateEnv, installDirsTemplateEnv, ) where +import Data.Binary (Binary) import Data.List (isPrefixOf) import Data.Maybe (fromMaybe) import Data.Monoid (Monoid(..))+import GHC.Generics (Generic) import System.Directory (getAppUserDataDirectory) import System.FilePath ((</>), isPathSeparator, pathSeparator) import System.FilePath (dropDrive) import Distribution.Package- ( PackageIdentifier, packageName, packageVersion )+ ( PackageIdentifier, PackageKey, packageName, packageVersion ) import Distribution.System ( OS(..), buildOS, Platform(..) ) import Distribution.Compiler- ( CompilerId, CompilerFlavor(..) )+ ( AbiTag(..), abiTagString, CompilerInfo(..), CompilerFlavor(..) ) import Distribution.Text ( display ) @@ -80,7 +85,6 @@ libsubdir :: dir, dynlibdir :: dir, libexecdir :: dir,- progdir :: dir, includedir :: dir, datadir :: dir, datasubdir :: dir,@@ -89,8 +93,10 @@ htmldir :: dir, haddockdir :: dir, sysconfdir :: dir- } deriving (Read, Show)+ } deriving (Generic, Read, Show) +instance Binary dir => Binary (InstallDirs dir)+ instance Functor InstallDirs where fmap f dirs = InstallDirs { prefix = f (prefix dirs),@@ -99,7 +105,6 @@ libsubdir = f (libsubdir dirs), dynlibdir = f (dynlibdir dirs), libexecdir = f (libexecdir dirs),- progdir = f (progdir dirs), includedir = f (includedir dirs), datadir = f (datadir dirs), datasubdir = f (datasubdir dirs),@@ -118,7 +123,6 @@ libsubdir = mempty, dynlibdir = mempty, libexecdir = mempty,- progdir = mempty, includedir = mempty, datadir = mempty, datasubdir = mempty,@@ -141,7 +145,6 @@ libsubdir = libsubdir a `combine` libsubdir b, dynlibdir = dynlibdir a `combine` dynlibdir b, libexecdir = libexecdir a `combine` libexecdir b,- progdir = progdir a `combine` progdir b, includedir = includedir a `combine` includedir b, datadir = datadir a `combine` datadir b, datasubdir = datasubdir a `combine` datasubdir b,@@ -177,7 +180,7 @@ -- users to be able to configure @--libdir=\/usr\/lib64@ for example but -- because by default we want to support installing multiple versions of -- packages and building the same package for multiple compilers we append the--- libsubdir to get: @\/usr\/lib64\/$pkgid\/$compiler@.+-- libsubdir to get: @\/usr\/lib64\/$pkgkey\/$compiler@. -- -- An additional complication is the need to support relocatable packages on -- systems which support such things, like Windows.@@ -207,22 +210,20 @@ bindir = "$prefix" </> "bin", libdir = installLibDir, libsubdir = case comp of- Hugs -> "hugs" </> "packages" </> "$pkg" JHC -> "$compiler" LHC -> "$compiler" UHC -> "$pkgid"- _other -> "$arch-$os-$compiler" </> "$pkgid",+ _other -> "$abi" </> "$pkgkey", dynlibdir = "$libdir", libexecdir = case buildOS of- Windows -> "$prefix" </> "$pkgid"+ Windows -> "$prefix" </> "$pkgkey" _other -> "$prefix" </> "libexec",- progdir = "$libdir" </> "hugs" </> "programs", includedir = "$libdir" </> "$libsubdir" </> "include", datadir = case buildOS of Windows -> "$prefix" _other -> "$prefix" </> "share",- datasubdir = "$arch-$os-$compiler" </> "$pkgid",- docdir = "$datadir" </> "doc" </> "$arch-$os-$compiler" </> "$pkgid",+ datasubdir = "$abi" </> "$pkgid",+ docdir = "$datadir" </> "doc" </> "$abi" </> "$pkgid", mandir = "$datadir" </> "man", htmldir = "$docdir" </> "html", haddockdir = "$htmldir",@@ -256,7 +257,6 @@ libsubdir = subst libsubdir [], dynlibdir = subst dynlibdir [prefixVar, bindirVar, libdirVar], libexecdir = subst libexecdir prefixBinLibVars,- progdir = subst progdir prefixBinLibVars, includedir = subst includedir prefixBinLibVars, datadir = subst datadir prefixBinLibVars, datasubdir = subst datasubdir [],@@ -283,10 +283,14 @@ -- | Convert from abstract install directories to actual absolute ones by -- substituting for all the variables in the abstract paths, to get real -- absolute path.-absoluteInstallDirs :: PackageIdentifier -> CompilerId -> CopyDest -> Platform+absoluteInstallDirs :: PackageIdentifier+ -> PackageKey+ -> CompilerInfo+ -> CopyDest+ -> Platform -> InstallDirs PathTemplate -> InstallDirs FilePath-absoluteInstallDirs pkgId compilerId copydest platform dirs =+absoluteInstallDirs pkgId pkg_key compilerId copydest platform dirs = (case copydest of CopyTo destdir -> fmap ((destdir </>) . dropDrive) _ -> id)@@ -294,7 +298,7 @@ . fmap fromPathTemplate $ substituteInstallDirTemplates env dirs where- env = initialPathTemplateEnv pkgId compilerId platform+ env = initialPathTemplateEnv pkgId pkg_key compilerId platform -- |The location prefix for the /copy/ command.@@ -309,10 +313,13 @@ -- prevents us from making a relocatable package (also known as a \"prefix -- independent\" package). ---prefixRelativeInstallDirs :: PackageIdentifier -> CompilerId -> Platform+prefixRelativeInstallDirs :: PackageIdentifier+ -> PackageKey+ -> CompilerInfo+ -> Platform -> InstallDirTemplates -> InstallDirs (Maybe FilePath)-prefixRelativeInstallDirs pkgId compilerId platform dirs =+prefixRelativeInstallDirs pkgId pkg_key compilerId platform dirs = fmap relative . appendSubdirs combinePathTemplate $ -- substitute the path template into each other, except that we map@@ -322,7 +329,7 @@ prefix = PathTemplate [Variable PrefixVar] } where- env = initialPathTemplateEnv pkgId compilerId platform+ env = initialPathTemplateEnv pkgId pkg_key compilerId platform -- If it starts with $prefix then it's relative and produce the relative -- path by stripping off $prefix/ or $prefix@@ -339,13 +346,17 @@ -- | An abstract path, possibly containing variables that need to be -- substituted for to get a real 'FilePath'. ---newtype PathTemplate = PathTemplate [PathComponent]+newtype PathTemplate = PathTemplate [PathComponent] deriving (Eq, Generic, Ord) +instance Binary PathTemplate+ data PathComponent = Ordinary FilePath | Variable PathTemplateVariable- deriving Eq+ deriving (Eq, Ord, Generic) +instance Binary PathComponent+ data PathTemplateVariable = PrefixVar -- ^ The @$prefix@ path variable | BindirVar -- ^ The @$bindir@ path variable@@ -358,16 +369,21 @@ | PkgNameVar -- ^ The @$pkg@ package name path variable | PkgVerVar -- ^ The @$version@ package version path variable | PkgIdVar -- ^ The @$pkgid@ package Id path variable, eg @foo-1.0@+ | PkgKeyVar -- ^ The @$pkgkey@ package key path variable | CompilerVar -- ^ The compiler name and version, eg @ghc-6.6.1@ | OSVar -- ^ The operating system name, eg @windows@ or @linux@ | ArchVar -- ^ The CPU architecture name, eg @i386@ or @x86_64@+ | AbiVar -- ^ The Compiler's ABI identifier, $arch-$os-$compiler-$abitag+ | AbiTagVar -- ^ The optional ABI tag for the compiler | ExecutableNameVar -- ^ The executable name; used in shell wrappers | TestSuiteNameVar -- ^ The name of the test suite being run | TestSuiteResultVar -- ^ The result of the test suite being run, eg -- @pass@, @fail@, or @error@. | BenchmarkNameVar -- ^ The name of the benchmark being run- deriving Eq+ deriving (Eq, Ord, Generic) +instance Binary PathTemplateVariable+ type PathTemplateEnv = [(PathTemplateVariable, PathTemplate)] -- | Convert a 'FilePath' to a 'PathTemplate' including any template vars.@@ -395,23 +411,28 @@ Nothing -> [component] -- | The initial environment has all the static stuff but no paths-initialPathTemplateEnv :: PackageIdentifier -> CompilerId -> Platform+initialPathTemplateEnv :: PackageIdentifier+ -> PackageKey+ -> CompilerInfo+ -> Platform -> PathTemplateEnv-initialPathTemplateEnv pkgId compilerId platform =- packageTemplateEnv pkgId- ++ compilerTemplateEnv compilerId+initialPathTemplateEnv pkgId pkg_key compiler platform =+ packageTemplateEnv pkgId pkg_key+ ++ compilerTemplateEnv compiler ++ platformTemplateEnv platform+ ++ abiTemplateEnv compiler platform -packageTemplateEnv :: PackageIdentifier -> PathTemplateEnv-packageTemplateEnv pkgId =+packageTemplateEnv :: PackageIdentifier -> PackageKey -> PathTemplateEnv+packageTemplateEnv pkgId pkg_key = [(PkgNameVar, PathTemplate [Ordinary $ display (packageName pkgId)]) ,(PkgVerVar, PathTemplate [Ordinary $ display (packageVersion pkgId)])+ ,(PkgKeyVar, PathTemplate [Ordinary $ display pkg_key]) ,(PkgIdVar, PathTemplate [Ordinary $ display pkgId]) ] -compilerTemplateEnv :: CompilerId -> PathTemplateEnv-compilerTemplateEnv compilerId =- [(CompilerVar, PathTemplate [Ordinary $ display compilerId])+compilerTemplateEnv :: CompilerInfo -> PathTemplateEnv+compilerTemplateEnv compiler =+ [(CompilerVar, PathTemplate [Ordinary $ display (compilerInfoId compiler)]) ] platformTemplateEnv :: Platform -> PathTemplateEnv@@ -420,6 +441,16 @@ ,(ArchVar, PathTemplate [Ordinary $ display arch]) ] +abiTemplateEnv :: CompilerInfo -> Platform -> PathTemplateEnv+abiTemplateEnv compiler (Platform arch os) =+ [(AbiVar, PathTemplate [Ordinary $ display arch ++ '-':display os +++ '-':display (compilerInfoId compiler) +++ case compilerInfoAbiTag compiler of+ NoAbiTag -> ""+ AbiTag tag -> '-':tag])+ ,(AbiTagVar, PathTemplate [Ordinary $ abiTagString (compilerInfoAbiTag compiler)])+ ]+ installDirsTemplateEnv :: InstallDirs PathTemplate -> PathTemplateEnv installDirsTemplateEnv dirs = [(PrefixVar, prefix dirs)@@ -444,6 +475,7 @@ instance Show PathTemplateVariable where show PrefixVar = "prefix"+ show PkgKeyVar = "pkgkey" show BindirVar = "bindir" show LibdirVar = "libdir" show LibsubdirVar = "libsubdir"@@ -457,6 +489,8 @@ show CompilerVar = "compiler" show OSVar = "os" show ArchVar = "arch"+ show AbiTagVar = "abitag"+ show AbiVar = "abi" show ExecutableNameVar = "executablename" show TestSuiteNameVar = "test-suite" show TestSuiteResultVar = "result"@@ -468,6 +502,7 @@ [ (var, drop (length varStr) s) | (varStr, var) <- vars , varStr `isPrefixOf` s ]+ -- NB: order matters! Longer strings first where vars = [("prefix", PrefixVar) ,("bindir", BindirVar) ,("libdir", LibdirVar)@@ -477,11 +512,14 @@ ,("docdir", DocdirVar) ,("htmldir", HtmldirVar) ,("pkgid", PkgIdVar)+ ,("pkgkey", PkgKeyVar) ,("pkg", PkgNameVar) ,("version", PkgVerVar) ,("compiler", CompilerVar) ,("os", OSVar) ,("arch", ArchVar)+ ,("abitag", AbiTagVar)+ ,("abi", AbiVar) ,("executablename", ExecutableNameVar) ,("test-suite", TestSuiteNameVar) ,("result", TestSuiteResultVar)@@ -548,7 +586,13 @@ -- csidl_PROGRAM_FILES_COMMON :: CInt -- csidl_PROGRAM_FILES_COMMON = 0x002b -foreign import stdcall unsafe "shlobj.h SHGetFolderPathW"+#ifdef x86_64_HOST_ARCH+#define CALLCONV ccall+#else+#define CALLCONV stdcall+#endif++foreign import CALLCONV unsafe "shlobj.h SHGetFolderPathW" c_SHGetFolderPath :: Ptr () -> CInt -> Ptr ()
Distribution/Simple/JHC.hs view
@@ -22,14 +22,14 @@ import Distribution.InstalledPackageInfo ( emptyInstalledPackageInfo, ) import qualified Distribution.InstalledPackageInfo as InstalledPackageInfo-import Distribution.Simple.PackageIndex (PackageIndex)+import Distribution.Simple.PackageIndex (InstalledPackageIndex) import qualified Distribution.Simple.PackageIndex as PackageIndex import Distribution.Simple.LocalBuildInfo ( LocalBuildInfo(..), ComponentLocalBuildInfo(..) ) import Distribution.Simple.BuildPaths ( autogenModulesDir, exeExtension ) import Distribution.Simple.Compiler- ( CompilerFlavor(..), CompilerId(..), Compiler(..)+ ( CompilerFlavor(..), CompilerId(..), Compiler(..), AbiTag(..) , PackageDBStack, Flag, languageToFlags, extensionsToFlags ) import Language.Haskell.Extension ( Language(Haskell98), Extension(..), KnownExtension(..))@@ -76,6 +76,8 @@ let Just version = programVersion jhcProg comp = Compiler { compilerId = CompilerId JHC version,+ compilerAbiTag = NoAbiTag,+ compilerCompat = [], compilerLanguages = jhcLanguages, compilerExtensions = jhcLanguageExtensions, compilerProperties = M.empty@@ -100,7 +102,7 @@ ] getInstalledPackages :: Verbosity -> PackageDBStack -> ProgramConfiguration- -> IO PackageIndex+ -> IO InstalledPackageIndex getInstalledPackages verbosity _packageDBs conf = do -- jhc --list-libraries lists all available libraries. -- How shall I find out, whether they are global or local
Distribution/Simple/LHC.hs view
@@ -35,13 +35,15 @@ buildLib, buildExe, installLib, installExe, registerPackage,+ hcPkgInfo, ghcOptions, ghcVerbosityOptions ) where import Distribution.PackageDescription as PD ( PackageDescription(..), BuildInfo(..), Executable(..)- , Library(..), libModules, hcOptions, usedExtensions, allExtensions )+ , Library(..), libModules, hcOptions, hcProfOptions, hcSharedOptions+ , usedExtensions, allExtensions ) import Distribution.InstalledPackageInfo ( InstalledPackageInfo , parseInstalledPackageInfo )@@ -72,7 +74,7 @@ import qualified Distribution.Simple.Program.HcPkg as HcPkg import Distribution.Simple.Compiler ( CompilerFlavor(..), CompilerId(..), Compiler(..), compilerVersion- , OptimisationLevel(..), PackageDB(..), PackageDBStack+ , OptimisationLevel(..), PackageDB(..), PackageDBStack, AbiTag(..) , Flag, languageToFlags, extensionsToFlags ) import Distribution.Version ( Version(..), orLaterVersion )@@ -125,6 +127,8 @@ let comp = Compiler { compilerId = CompilerId LHC lhcVersion,+ compilerAbiTag = NoAbiTag,+ compilerCompat = [], compilerLanguages = languages, compilerExtensions = extensions, compilerProperties = M.empty@@ -218,7 +222,7 @@ | Just ext <- map readExtension (lines exts) ] getInstalledPackages :: Verbosity -> PackageDBStack -> ProgramConfiguration- -> IO PackageIndex+ -> IO InstalledPackageIndex getInstalledPackages verbosity packagedbs conf = do checkPackageDbStack packagedbs pkgss <- getInstalledPackages' lhcPkg verbosity packagedbs conf@@ -344,13 +348,13 @@ "-hisuf", "p_hi", "-osuf", "p_o" ]- ++ ghcProfOptions libBi+ ++ hcProfOptions GHC libBi ghcArgsShared = ghcArgs ++ ["-dynamic", "-hisuf", "dyn_hi", "-osuf", "dyn_o", "-fPIC" ]- ++ ghcSharedOptions libBi+ ++ hcSharedOptions GHC libBi unless (null (libModules lib)) $ do ifVanillaLib forceVanillaLib (runGhcProg $ lhcWrap ghcArgs) ifProfLib (runGhcProg $ lhcWrap ghcArgsProf)@@ -529,7 +533,7 @@ then ["-prof", "-hisuf", "p_hi", "-osuf", "p_o"- ] ++ ghcProfOptions exeBi+ ] ++ hcProfOptions GHC exeBi else [] -- For building exe's for profiling that use TH we actually@@ -781,6 +785,15 @@ -> Bool -> PackageDBStack -> IO ()-registerPackage verbosity installedPkgInfo _pkg lbi _inplace packageDbs = do- let Just lhcPkg = lookupProgram lhcPkgProgram (withPrograms lbi)- HcPkg.reregister verbosity lhcPkg packageDbs (Right installedPkgInfo)+registerPackage verbosity installedPkgInfo _pkg lbi _inplace packageDbs =+ HcPkg.reregister (hcPkgInfo $ withPrograms lbi) verbosity packageDbs+ (Right installedPkgInfo)++hcPkgInfo :: ProgramConfiguration -> HcPkg.HcPkgInfo+hcPkgInfo conf = HcPkg.HcPkgInfo { HcPkg.hcPkgProgram = lhcPkgProg+ , HcPkg.noPkgDbStack = False+ , HcPkg.noVerboseFlag = False+ , HcPkg.flagPackageConf = False+ }+ where+ Just lhcPkgProg = lookupProgram lhcPkgProgram conf
Distribution/Simple/LocalBuildInfo.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE DeriveGeneric #-}+ ----------------------------------------------------------------------------- -- | -- Module : Distribution.Simple.LocalBuildInfo@@ -40,6 +42,7 @@ allComponentsInBuildOrder, componentsInBuildOrder, checkComponentsCyclic,+ depLibraryPaths, withAllComponentsInBuildOrder, withComponentsInBuildOrder,@@ -60,28 +63,41 @@ substPathTemplate, ) import qualified Distribution.Simple.InstallDirs as InstallDirs import Distribution.Simple.Program (ProgramConfiguration)+import Distribution.InstalledPackageInfo (InstalledPackageInfo) import Distribution.PackageDescription ( PackageDescription(..), withLib, Library(libBuildInfo), withExe , Executable(exeName, buildInfo), withTest, TestSuite(..)- , BuildInfo(buildable), Benchmark(..) )+ , BuildInfo(buildable), Benchmark(..), ModuleRenaming(..) )+import qualified Distribution.InstalledPackageInfo as Installed import Distribution.Package- ( PackageId, Package(..), InstalledPackageId(..) )+ ( PackageId, Package(..), InstalledPackageId(..), PackageKey+ , PackageName ) import Distribution.Simple.Compiler- ( Compiler(..), PackageDBStack, OptimisationLevel )+ ( Compiler, compilerInfo, PackageDBStack, DebugInfoLevel+ , OptimisationLevel ) import Distribution.Simple.PackageIndex- ( PackageIndex )+ ( InstalledPackageIndex, allPackages )+import Distribution.ModuleName ( ModuleName ) import Distribution.Simple.Setup ( ConfigFlags )+import Distribution.Simple.Utils+ ( shortRelativePath ) import Distribution.Text ( display ) import Distribution.System- ( Platform )-import Data.List (nub, find)-import Data.Graph-import Data.Tree (flatten)+ ( Platform (..) )+ import Data.Array ((!))+import Data.Binary (Binary)+import Data.Graph+import Data.List (nub, find, stripPrefix) import Data.Maybe+import Data.Tree (flatten)+import GHC.Generics (Generic)+import Data.Map (Map) +import System.Directory (doesDirectoryExist, canonicalizePath)+ -- | Data cached after configuration step. See also -- 'Distribution.Simple.Setup.ConfigFlags'. data LocalBuildInfo = LocalBuildInfo {@@ -101,13 +117,10 @@ -- ^ The platform we're building for buildDir :: FilePath, -- ^ Where to build the package.- --TODO: eliminate hugs's scratchDir, use builddir- scratchDir :: FilePath,- -- ^ Where to put the result of the Hugs build. componentsConfigs :: [(ComponentName, ComponentLocalBuildInfo, [ComponentName])], -- ^ All the components to build, ordered by topological sort, and with their dependencies -- over the intrapackage dependency graph- installedPkgs :: PackageIndex,+ installedPkgs :: InstalledPackageIndex, -- ^ All the info about the installed packages that the -- current package depends on (directly or indirectly). pkgDescrFile :: Maybe FilePath,@@ -115,6 +128,10 @@ localPkgDescr :: PackageDescription, -- ^ The resolved package description, that does not contain -- any conditionals.+ pkgKey :: PackageKey,+ -- ^ The package key for the current build, calculated from+ -- the package ID and the dependency graph.+ instantiatedWith :: [(ModuleName, (InstalledPackageInfo, ModuleName))], withPrograms :: ProgramConfiguration, -- ^Location and args for all programs withPackageDB :: PackageDBStack, -- ^What package database to use, global\/user withVanillaLib:: Bool, -- ^Whether to build normal libs.@@ -123,14 +140,18 @@ withDynExe :: Bool, -- ^Whether to link executables dynamically withProfExe :: Bool, -- ^Whether to build executables for profiling. withOptimization :: OptimisationLevel, -- ^Whether to build with optimization (if available).+ withDebugInfo :: DebugInfoLevel, -- ^Whether to emit debug info (if available). withGHCiLib :: Bool, -- ^Whether to build libs suitable for use with GHCi. splitObjs :: Bool, -- ^Use -split-objs with GHC, if available stripExes :: Bool, -- ^Whether to strip executables during install stripLibs :: Bool, -- ^Whether to strip libraries during install progPrefix :: PathTemplate, -- ^Prefix to be prepended to installed executables- progSuffix :: PathTemplate -- ^Suffix to be appended to installed executables- } deriving (Read, Show)+ progSuffix :: PathTemplate, -- ^Suffix to be appended to installed executables+ relocatable :: Bool -- ^Whether to build a relocatable package+ } deriving (Generic, Read, Show) +instance Binary LocalBuildInfo+ -- | External package dependencies for the package as a whole. This is the -- union of the individual 'componentPackageDeps', less any internal deps. externalPackageDeps :: LocalBuildInfo -> [(InstalledPackageId, PackageId)]@@ -164,8 +185,10 @@ | CExeName String | CTestName String | CBenchName String- deriving (Show, Eq, Ord, Read)+ deriving (Eq, Generic, Ord, Read, Show) +instance Binary ComponentName+ showComponentName :: ComponentName -> String showComponentName CLibName = "library" showComponentName (CExeName name) = "executable '" ++ name ++ "'"@@ -179,19 +202,26 @@ -- 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)],+ componentExposedModules :: [Installed.ExposedModule],+ componentPackageRenaming :: Map PackageName ModuleRenaming, componentLibraries :: [LibraryName] } | ExeComponentLocalBuildInfo {- componentPackageDeps :: [(InstalledPackageId, PackageId)]+ componentPackageDeps :: [(InstalledPackageId, PackageId)],+ componentPackageRenaming :: Map PackageName ModuleRenaming } | TestComponentLocalBuildInfo {- componentPackageDeps :: [(InstalledPackageId, PackageId)]+ componentPackageDeps :: [(InstalledPackageId, PackageId)],+ componentPackageRenaming :: Map PackageName ModuleRenaming } | BenchComponentLocalBuildInfo {- componentPackageDeps :: [(InstalledPackageId, PackageId)]+ componentPackageDeps :: [(InstalledPackageId, PackageId)],+ componentPackageRenaming :: Map PackageName ModuleRenaming }- deriving (Read, Show)+ deriving (Generic, Read, Show) +instance Binary ComponentLocalBuildInfo+ foldComponent :: (Library -> a) -> (Executable -> a) -> (TestSuite -> a)@@ -204,8 +234,10 @@ foldComponent _ _ _ f (CBench bch) = f bch data LibraryName = LibraryName String- deriving (Read, Show)+ deriving (Generic, Read, Show) +instance Binary LibraryName+ componentBuildInfo :: Component -> BuildInfo componentBuildInfo = foldComponent libBuildInfo buildInfo testBuildInfo benchmarkBuildInfo@@ -378,7 +410,63 @@ [] -> Nothing (c:_) -> Just (map vertexToNode c) +-- | Determine the directories containing the dynamic libraries of the+-- transitive dependencies of the component we are building.+--+-- When wanted, and possible, returns paths relative to the installDirs 'prefix'+depLibraryPaths :: Bool -- ^ Building for inplace?+ -> Bool -- ^ Generate prefix-relative library paths+ -> LocalBuildInfo+ -> ComponentLocalBuildInfo -- ^ Component that is being built+ -> IO [FilePath]+depLibraryPaths inplace relative lbi clbi = do+ let pkgDescr = localPkgDescr lbi+ installDirs = absoluteInstallDirs pkgDescr lbi NoCopyDest+ executable = case clbi of+ ExeComponentLocalBuildInfo {} -> True+ _ -> False+ relDir | executable = bindir installDirs+ | otherwise = libdir installDirs + let hasInternalDeps = not $ null+ $ [ pkgid+ | (_,pkgid) <- componentPackageDeps clbi+ , internal pkgid+ ]++ let ipkgs = allPackages (installedPkgs lbi)+ allDepLibDirs = concatMap Installed.libraryDirs ipkgs+ internalLib+ | inplace = buildDir lbi+ | otherwise = libdir installDirs+ allDepLibDirs' = if hasInternalDeps+ then internalLib : allDepLibDirs+ else allDepLibDirs+ allDepLibDirsC <- mapM canonicalizePathNoFail allDepLibDirs'++ let p = prefix installDirs+ prefixRelative l = isJust (stripPrefix p l)+ libPaths+ | relative &&+ prefixRelative relDir = map (\l ->+ if prefixRelative l+ then shortRelativePath relDir l+ else l+ ) allDepLibDirsC+ | otherwise = allDepLibDirsC++ return libPaths+ where+ internal pkgid = pkgid == packageId (localPkgDescr lbi)+ -- 'canonicalizePath' fails on UNIX when the directory does not exists.+ -- So just don't canonicalize when it doesn't exist.+ canonicalizePathNoFail p = do+ exists <- doesDirectoryExist p+ if exists+ then canonicalizePath p+ else return p++ -- ----------------------------------------------------------------------------- -- Wrappers for a couple functions from InstallDirs @@ -388,7 +476,8 @@ absoluteInstallDirs pkg lbi copydest = InstallDirs.absoluteInstallDirs (packageId pkg)- (compilerId (compiler lbi))+ (pkgKey lbi)+ (compilerInfo (compiler lbi)) copydest (hostPlatform lbi) (installDirTemplates lbi)@@ -399,7 +488,8 @@ prefixRelativeInstallDirs pkg_descr lbi = InstallDirs.prefixRelativeInstallDirs (packageId pkg_descr)- (compilerId (compiler lbi))+ (pkgKey lbi)+ (compilerInfo (compiler lbi)) (hostPlatform lbi) (installDirTemplates lbi) @@ -409,5 +499,6 @@ . ( InstallDirs.substPathTemplate env ) where env = initialPathTemplateEnv pkgid- (compilerId (compiler lbi))+ (pkgKey lbi)+ (compilerInfo (compiler lbi)) (hostPlatform lbi)
− Distribution/Simple/NHC.hs
@@ -1,406 +0,0 @@--------------------------------------------------------------------------------- |--- Module : Distribution.Simple.NHC--- Copyright : Isaac Jones 2003-2006--- Duncan Coutts 2009--- License : BSD3------ Maintainer : cabal-devel@haskell.org--- Portability : portable------ This module contains most of the NHC-specific code for configuring, building--- and installing packages.--module Distribution.Simple.NHC (- configure,- getInstalledPackages,- buildLib,- buildExe,- installLib,- installExe,- ) where--import Distribution.Package- ( PackageName, PackageIdentifier(..), InstalledPackageId(..)- , packageName )-import Distribution.InstalledPackageInfo- ( InstalledPackageInfo- , InstalledPackageInfo_( InstalledPackageInfo, installedPackageId- , sourcePackageId )- , emptyInstalledPackageInfo, parseInstalledPackageInfo )-import Distribution.PackageDescription- ( PackageDescription(..), BuildInfo(..), Library(..), Executable(..)- , hcOptions, usedExtensions )-import Distribution.ModuleName (ModuleName)-import qualified Distribution.ModuleName as ModuleName-import Distribution.Simple.LocalBuildInfo- ( LocalBuildInfo(..), ComponentLocalBuildInfo(..) )-import Distribution.Simple.BuildPaths- ( mkLibName, objExtension, exeExtension )-import Distribution.Simple.Compiler- ( CompilerFlavor(..), CompilerId(..), Compiler(..)- , Flag, languageToFlags, extensionsToFlags- , PackageDB(..), PackageDBStack )-import qualified Distribution.Simple.PackageIndex as PackageIndex-import Distribution.Simple.PackageIndex (PackageIndex)-import Language.Haskell.Extension- ( Language(Haskell98), Extension(..), KnownExtension(..) )-import Distribution.Simple.Program- ( ProgramConfiguration, userMaybeSpecifyPath, programPath- , requireProgram, requireProgramVersion, lookupProgram- , nhcProgram, hmakeProgram, ldProgram, arProgram- , rawSystemProgramConf )-import Distribution.Simple.Utils- ( die, info, findFileWithExtension, findModuleFiles- , installOrdinaryFile, installExecutableFile, installOrdinaryFiles- , createDirectoryIfMissingVerbose, withUTF8FileContents )-import Distribution.Version- ( Version(..), orLaterVersion )-import Distribution.Verbosity-import Distribution.Text- ( display, simpleParse )-import Distribution.ParseUtils- ( ParseResult(..) )--import System.FilePath- ( (</>), (<.>), normalise, takeDirectory, dropExtension )-import System.Directory- ( doesFileExist, doesDirectoryExist, getDirectoryContents- , removeFile, getHomeDirectory )--import Data.Char ( toLower )-import Data.List ( nub )-import Data.Maybe ( catMaybes )-import qualified Data.Map as M ( empty )-import Data.Monoid ( Monoid(..) )-import Control.Monad ( when, unless )-import Distribution.Compat.Exception-import Distribution.System ( Platform )---- -------------------------------------------------------------------------------- Configuring--configure :: Verbosity -> Maybe FilePath -> Maybe FilePath- -> ProgramConfiguration -> IO (Compiler, Maybe Platform, ProgramConfiguration)-configure verbosity hcPath _hcPkgPath conf = do-- (_nhcProg, nhcVersion, conf') <-- requireProgramVersion verbosity nhcProgram- (orLaterVersion (Version [1,20] []))- (userMaybeSpecifyPath "nhc98" hcPath conf)-- (_hmakeProg, _hmakeVersion, conf'') <-- requireProgramVersion verbosity hmakeProgram- (orLaterVersion (Version [3,13] [])) conf'- (_ldProg, conf''') <- requireProgram verbosity ldProgram conf''- (_arProg, conf'''') <- requireProgram verbosity arProgram conf'''-- --TODO: put this stuff in a monad so we can say just:- -- requireProgram hmakeProgram (orLaterVersion (Version [3,13] []))- -- requireProgram ldProgram anyVersion- -- requireProgram ldPrograrProgramam anyVersion- -- unless (null (cSources bi)) $ requireProgram ccProgram anyVersion-- let comp = Compiler {- compilerId = CompilerId NHC nhcVersion,- compilerLanguages = nhcLanguages,- compilerExtensions = nhcLanguageExtensions,- compilerProperties = M.empty- }- compPlatform = Nothing- return (comp, compPlatform, conf'''')--nhcLanguages :: [(Language, Flag)]-nhcLanguages = [(Haskell98, "-98")]---- | The flags for the supported extensions-nhcLanguageExtensions :: [(Extension, Flag)]-nhcLanguageExtensions =- -- TODO: pattern guards in 1.20- -- NHC doesn't enforce the monomorphism restriction at all.- -- Technically it therefore doesn't support MonomorphismRestriction,- -- but that would mean it doesn't support Haskell98, so we pretend- -- that it does.- [(EnableExtension MonomorphismRestriction, "")- ,(DisableExtension MonomorphismRestriction, "")- -- Similarly, I assume the FFI is always on- ,(EnableExtension ForeignFunctionInterface, "")- ,(DisableExtension ForeignFunctionInterface, "")- -- Similarly, I assume existential quantification is always on- ,(EnableExtension ExistentialQuantification, "")- ,(DisableExtension ExistentialQuantification, "")- -- Similarly, I assume empty data decls is always on- ,(EnableExtension EmptyDataDecls, "")- ,(DisableExtension EmptyDataDecls, "")- ,(EnableExtension NamedFieldPuns, "-puns")- ,(DisableExtension NamedFieldPuns, "-nopuns")- -- CPP can't actually be turned off, but we pretend that it can- ,(EnableExtension CPP, "-cpp")- ,(DisableExtension CPP, "")- ]--getInstalledPackages :: Verbosity -> PackageDBStack -> ProgramConfiguration- -> IO PackageIndex-getInstalledPackages verbosity packagedbs conf = do- homedir <- getHomeDirectory- (nhcProg, _) <- requireProgram verbosity nhcProgram conf- let bindir = takeDirectory (programPath nhcProg)- incdir = takeDirectory bindir </> "include" </> "nhc98"- dbdirs = nub (concatMap (packageDbPaths homedir incdir) packagedbs)- indexes <- mapM getIndividualDBPackages dbdirs- return $! mconcat indexes-- where- getIndividualDBPackages :: FilePath -> IO PackageIndex- getIndividualDBPackages dbdir = do- pkgdirs <- getPackageDbDirs dbdir- pkgs <- sequence [ getInstalledPackage pkgname pkgdir- | (pkgname, pkgdir) <- pkgdirs ]- let pkgs' = map setInstalledPackageId (catMaybes pkgs)- return (PackageIndex.fromList pkgs')--packageDbPaths :: FilePath -> FilePath -> PackageDB -> [FilePath]-packageDbPaths _home incdir db = case db of- GlobalPackageDB -> [ incdir </> "packages" ]- UserPackageDB -> [] --TODO any standard per-user db?- SpecificPackageDB path -> [ path ]--getPackageDbDirs :: FilePath -> IO [(PackageName, FilePath)]-getPackageDbDirs dbdir = do- dbexists <- doesDirectoryExist dbdir- if not dbexists- then return []- else do- entries <- getDirectoryContents dbdir- pkgdirs <- sequence- [ do pkgdirExists <- doesDirectoryExist pkgdir- return (pkgname, pkgdir, pkgdirExists)- | (entry, Just pkgname) <- [ (entry, simpleParse entry)- | entry <- entries ]- , let pkgdir = dbdir </> entry ]- return [ (pkgname, pkgdir) | (pkgname, pkgdir, True) <- pkgdirs ]--getInstalledPackage :: PackageName -> FilePath -> IO (Maybe InstalledPackageInfo)-getInstalledPackage pkgname pkgdir = do- let pkgconfFile = pkgdir </> "package.conf"- pkgconfExists <- doesFileExist pkgconfFile-- let cabalFile = pkgdir <.> "cabal"- cabalExists <- doesFileExist cabalFile-- case () of- _ | pkgconfExists -> getFullInstalledPackageInfo pkgname pkgconfFile- | cabalExists -> getPhonyInstalledPackageInfo pkgname cabalFile- | otherwise -> return Nothing--getFullInstalledPackageInfo :: PackageName -> FilePath- -> IO (Maybe InstalledPackageInfo)-getFullInstalledPackageInfo pkgname pkgconfFile =- withUTF8FileContents pkgconfFile $ \contents ->- case parseInstalledPackageInfo contents of- ParseOk _ pkginfo | packageName pkginfo == pkgname- -> return (Just pkginfo)- _ -> return Nothing---- | This is a backup option for existing versions of nhc98 which do not supply--- proper installed package info files for the bundled libs. Instead we look--- for the .cabal file and extract the package version from that.--- We don't know any other details for such packages, in particular we pretend--- that they have no dependencies.----getPhonyInstalledPackageInfo :: PackageName -> FilePath- -> IO (Maybe InstalledPackageInfo)-getPhonyInstalledPackageInfo pkgname pathsModule = do- content <- readFile pathsModule- case extractVersion content of- Nothing -> return Nothing- Just version -> return (Just pkginfo)- where- pkgid = PackageIdentifier pkgname version- pkginfo = emptyInstalledPackageInfo { sourcePackageId = pkgid }- where- -- search through the .cabal file, looking for a line like:- --- -- > version: 2.0- --- extractVersion :: String -> Maybe Version- extractVersion content =- case catMaybes (map extractVersionLine (lines content)) of- [version] -> Just version- _ -> Nothing- extractVersionLine :: String -> Maybe Version- extractVersionLine line =- case words line of- [versionTag, ":", versionStr]- | map toLower versionTag == "version" -> simpleParse versionStr- [versionTag, versionStr]- | map toLower versionTag == "version:" -> simpleParse versionStr- _ -> Nothing---- Older installed package info files did not have the installedPackageId--- field, so if it is missing then we fill it as the source package ID.-setInstalledPackageId :: InstalledPackageInfo -> InstalledPackageInfo-setInstalledPackageId pkginfo@InstalledPackageInfo {- installedPackageId = InstalledPackageId "",- sourcePackageId = pkgid- }- = pkginfo {- --TODO use a proper named function for the conversion- -- from source package id to installed package id- installedPackageId = InstalledPackageId (display pkgid)- }-setInstalledPackageId pkginfo = pkginfo---- -------------------------------------------------------------------------------- Building---- |FIX: For now, the target must contain a main module. Not used--- ATM. Re-add later.-buildLib :: Verbosity -> PackageDescription -> LocalBuildInfo- -> Library -> ComponentLocalBuildInfo -> IO ()-buildLib verbosity pkg_descr lbi lib clbi = do- libName <- case componentLibraries clbi of- [libName] -> return libName- [] -> die "No library name found when building library"- _ -> die "Multiple library names found when building library"- let conf = withPrograms lbi- Just nhcProg = lookupProgram nhcProgram conf- let bi = libBuildInfo lib- modules = exposedModules lib ++ otherModules bi- -- Unsupported extensions have already been checked by configure- languageFlags = languageToFlags (compiler lbi) (defaultLanguage bi)- ++ extensionsToFlags (compiler lbi) (usedExtensions bi)- inFiles <- getModulePaths lbi bi modules- let targetDir = buildDir lbi- srcDirs = nub (map takeDirectory inFiles)- destDirs = map (targetDir </>) srcDirs- mapM_ (createDirectoryIfMissingVerbose verbosity True) destDirs- rawSystemProgramConf verbosity hmakeProgram conf $- ["-hc=" ++ programPath nhcProg]- ++ nhcVerbosityOptions verbosity- ++ ["-d", targetDir, "-hidir", targetDir]- ++ maybe [] (hcOptions NHC . libBuildInfo)- (library pkg_descr)- ++ languageFlags- ++ concat [ ["-package", display (packageName pkgid) ]- | (_, pkgid) <- componentPackageDeps clbi ]- ++ inFiles-{-- -- build any C sources- unless (null (cSources bi)) $ do- info verbosity "Building C Sources..."- let commonCcArgs = (if verbosity >= deafening then ["-v"] else [])- ++ ["-I" ++ dir | dir <- includeDirs bi]- ++ [opt | opt <- ccOptions bi]- ++ (if withOptimization lbi then ["-O2"] else [])- flip mapM_ (cSources bi) $ \cfile -> do- let ofile = targetDir </> cfile `replaceExtension` objExtension- createDirectoryIfMissingVerbose verbosity True (takeDirectory ofile)- rawSystemProgramConf verbosity hmakeProgram conf- (commonCcArgs ++ ["-c", cfile, "-o", ofile])--}- -- link:- info verbosity "Linking..."- let --cObjs = [ targetDir </> cFile `replaceExtension` objExtension- -- | cFile <- cSources bi ]- libFilePath = targetDir </> mkLibName libName- hObjs = [ targetDir </> ModuleName.toFilePath m <.> objExtension- | m <- modules ]-- unless (null hObjs {-&& null cObjs-}) $ do- -- first remove library if it exists- removeFile libFilePath `catchIO` \_ -> return ()-- let arVerbosity | verbosity >= deafening = "v"- | verbosity >= normal = ""- | otherwise = "c"-- rawSystemProgramConf verbosity arProgram (withPrograms lbi) $- ["q"++ arVerbosity, libFilePath]- ++ hObjs--- ++ cObjs---- | Building an executable for NHC.-buildExe :: Verbosity -> PackageDescription -> LocalBuildInfo- -> Executable -> ComponentLocalBuildInfo -> IO ()-buildExe verbosity pkg_descr lbi exe clbi = do- let conf = withPrograms lbi- Just nhcProg = lookupProgram nhcProgram conf- when (dropExtension (modulePath exe) /= exeName exe) $- die $ "hmake does not support exe names that do not match the name of "- ++ "the 'main-is' file. You will have to rename your executable to "- ++ show (dropExtension (modulePath exe))- let bi = buildInfo exe- modules = otherModules bi- -- Unsupported extensions have already been checked by configure- languageFlags = languageToFlags (compiler lbi) (defaultLanguage bi)- ++ extensionsToFlags (compiler lbi) (usedExtensions bi)- inFiles <- getModulePaths lbi bi modules- let targetDir = buildDir lbi </> exeName exe- exeDir = targetDir </> (exeName exe ++ "-tmp")- srcDirs = nub (map takeDirectory (modulePath exe : inFiles))- destDirs = map (exeDir </>) srcDirs- mapM_ (createDirectoryIfMissingVerbose verbosity True) destDirs- rawSystemProgramConf verbosity hmakeProgram conf $- ["-hc=" ++ programPath nhcProg]- ++ nhcVerbosityOptions verbosity- ++ ["-d", targetDir, "-hidir", targetDir]- ++ maybe [] (hcOptions NHC . libBuildInfo)- (library pkg_descr)- ++ languageFlags- ++ concat [ ["-package", display (packageName pkgid) ]- | (_, pkgid) <- componentPackageDeps clbi ]- ++ inFiles- ++ [exeName exe]--nhcVerbosityOptions :: Verbosity -> [String]-nhcVerbosityOptions verbosity- | verbosity >= deafening = ["-v"]- | verbosity >= normal = []- | otherwise = ["-q"]----TODO: where to put this? it's duplicated in .Simple too-getModulePaths :: LocalBuildInfo -> BuildInfo -> [ModuleName] -> IO [FilePath]-getModulePaths lbi bi modules = sequence- [ findFileWithExtension ["hs", "lhs"] (buildDir lbi : hsSourceDirs bi)- (ModuleName.toFilePath module_) >>= maybe (notFound module_) (return . normalise)- | module_ <- modules ]- where notFound module_ = die $ "can't find source for module " ++ display module_---- -------------------------------------------------------------------------------- Installing---- |Install executables for NHC.-installExe :: Verbosity -- ^verbosity- -> FilePath -- ^install location- -> FilePath -- ^Build location- -> (FilePath, FilePath) -- ^Executable (prefix,suffix)- -> Executable- -> IO ()-installExe verbosity pref buildPref (progprefix,progsuffix) exe- = do createDirectoryIfMissingVerbose verbosity True pref- let exeBaseName = exeName exe- exeFileName = exeBaseName <.> exeExtension- fixedExeFileName = (progprefix ++ exeBaseName ++ progsuffix) <.> exeExtension- installExecutableFile verbosity- (buildPref </> exeBaseName </> exeFileName)- (pref </> fixedExeFileName)---- |Install for nhc98: .hi and .a files-installLib :: Verbosity -- ^verbosity- -> FilePath -- ^install location- -> FilePath -- ^Build location- -> PackageIdentifier- -> Library- -> ComponentLocalBuildInfo- -> IO ()-installLib verbosity pref buildPref _pkgid lib clbi- = do let bi = libBuildInfo lib- modules = exposedModules lib ++ otherModules bi- findModuleFiles [buildPref] ["hi"] modules- >>= installOrdinaryFiles verbosity pref- let libNames = map mkLibName (componentLibraries clbi)- installLib' libName = installOrdinaryFile verbosity- (buildPref </> libName)- (pref </> libName)- mapM_ installLib' libNames
Distribution/Simple/PackageIndex.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE DeriveGeneric #-}+ ----------------------------------------------------------------------------- -- | -- Module : Distribution.Simple.PackageIndex@@ -12,7 +14,9 @@ -- module Distribution.Simple.PackageIndex ( -- * Package index data type+ InstalledPackageIndex, PackageIndex,+ FakeMap, -- * Creating an index fromList,@@ -32,6 +36,7 @@ -- ** Precise lookups lookupInstalledPackageId, lookupSourcePackageId,+ lookupPackageId, lookupPackageName, lookupDependency, @@ -55,47 +60,92 @@ dependencyCycles, dependencyGraph, moduleNameIndex,++ -- ** Variants of special queries supporting fake map+ fakeLookupInstalledPackageId,+ brokenPackages',+ dependencyClosure',+ reverseDependencyClosure',+ dependencyInconsistencies',+ dependencyCycles',+ dependencyGraph', ) where -import Prelude hiding (lookup) import Control.Exception (assert)-import qualified Data.Map as Map-import Data.Map (Map)-import qualified Data.Tree as Tree-import qualified Data.Graph as Graph-import qualified Data.Array as Array import Data.Array ((!))+import qualified Data.Array as Array+import Data.Binary (Binary)+import qualified Data.Graph as Graph import Data.List as List ( null, foldl', sort , groupBy, sortBy, find, isInfixOf, nubBy, deleteBy, deleteFirstsBy ) import Data.Monoid (Monoid(..))+import Data.Map (Map)+import qualified Data.Map as Map import Data.Maybe (isNothing, fromMaybe)+import qualified Data.Tree as Tree+import GHC.Generics (Generic)+import Prelude hiding (lookup) import Distribution.Package ( PackageName(..), PackageId , Package(..), packageName, packageVersion , Dependency(Dependency)--, --PackageFixedDeps(..)- , InstalledPackageId(..) )+ , InstalledPackageId(..), PackageInstalled(..) ) import Distribution.ModuleName ( ModuleName ) import Distribution.InstalledPackageInfo- ( InstalledPackageInfo, installedPackageId )+ ( InstalledPackageInfo ) import qualified Distribution.InstalledPackageInfo as IPI import Distribution.Version ( Version, withinRange ) import Distribution.Simple.Utils (lowercase, comparing, equating) +-- Note [FakeMap]+-----------------+-- We'd like to use the PackageIndex defined in this module for+-- cabal-install's InstallPlan. However, at the moment, this+-- data structure is indexed by InstalledPackageId, which we don't+-- know until after we've compiled a package (whereas InstallPlan+-- needs to store not-compiled packages in the index.) Eventually,+-- an InstalledPackageId will be calculatable prior to actually+-- building the package (making it something of a misnomer), but+-- at the moment, the "fake installed package ID map" is a workaround+-- to solve this problem while reusing PackageIndex. The basic idea+-- is that, since we don't know what an InstalledPackageId is+-- beforehand, we just fake up one based on the package ID (it only+-- needs to be unique for the particular install plan), and fill+-- it out with the actual generated InstalledPackageId after the+-- package is successfully compiled.+--+-- However, there is a problem: in the index there may be+-- references using the old package ID, which are now dangling if+-- we update the InstalledPackageId. We could map over the entire+-- index to update these pointers as well (a costly operation), but+-- instead, we've chosen to parametrize a variety of important functions+-- by a FakeMap, which records what a fake installed package ID was+-- actually resolved to post-compilation. If we do a lookup, we first+-- check and see if it's a fake ID in the FakeMap.+--+-- It's a bit grungy, but we expect this to only be temporary anyway.+-- (Another possible workaround would have been to *not* update+-- the installed package ID, but I decided this would be hard to+-- understand.) +-- | Map from fake installed package IDs to real ones. See Note [FakeMap]+type FakeMap = Map InstalledPackageId InstalledPackageId+ -- | The collection of information about packages from one or more 'PackageDB's.+-- These packages generally should have an instance of 'PackageInstalled' -- -- Packages are uniquely identified in by their 'InstalledPackageId', they can -- also be efficiently looked up by package name or by name and version. ---data PackageIndex = PackageIndex+data PackageIndex a = PackageIndex -- The primary index. Each InstalledPackageInfo record is uniquely identified -- by its InstalledPackageId. --- !(Map InstalledPackageId InstalledPackageInfo)+ !(Map InstalledPackageId a) -- This auxiliary index maps package names (case-sensitively) to all the -- versions and instances of that package. This allows us to find all@@ -108,18 +158,24 @@ -- -- FIXME: Clarify what "preference order" means. Check that this invariant is -- preserved. See #1463 for discussion.- !(Map PackageName (Map Version [InstalledPackageInfo]))+ !(Map PackageName (Map Version [a])) - deriving (Show, Read)+ deriving (Generic, Show, Read) -instance Monoid PackageIndex where+instance Binary a => Binary (PackageIndex a)++-- | The default package index which contains 'InstalledPackageInfo'. Normally+-- use this.+type InstalledPackageIndex = PackageIndex InstalledPackageInfo++instance PackageInstalled a => Monoid (PackageIndex a) where mempty = PackageIndex Map.empty Map.empty mappend = merge --save one mappend with empty in the common case: mconcat [] = mempty mconcat xs = foldr1 mappend xs -invariant :: PackageIndex -> Bool+invariant :: PackageInstalled a => PackageIndex a -> Bool invariant (PackageIndex pids pnames) = map installedPackageId (Map.elems pids) == sort@@ -140,9 +196,10 @@ -- * Internal helpers -- -mkPackageIndex :: Map InstalledPackageId InstalledPackageInfo- -> Map PackageName (Map Version [InstalledPackageInfo])- -> PackageIndex+mkPackageIndex :: PackageInstalled a+ => Map InstalledPackageId a+ -> Map PackageName (Map Version [a])+ -> PackageIndex a mkPackageIndex pids pnames = assert (invariant index) index where index = PackageIndex pids pnames @@ -156,7 +213,7 @@ -- If there are duplicates by 'InstalledPackageId' then later ones mask earlier -- ones. ---fromList :: [InstalledPackageInfo] -> PackageIndex+fromList :: PackageInstalled a => [a] -> PackageIndex a fromList pkgs = mkPackageIndex pids pnames where pids = Map.fromList [ (installedPackageId pkg, pkg) | pkg <- pkgs ]@@ -188,9 +245,9 @@ -- result when we do a lookup by source 'PackageId'. This is the mechanism we -- use to prefer user packages over global packages. ---merge :: PackageIndex -> PackageIndex -> PackageIndex+merge :: PackageInstalled a => PackageIndex a -> PackageIndex a -> PackageIndex a merge (PackageIndex pids1 pnames1) (PackageIndex pids2 pnames2) =- mkPackageIndex (Map.union pids1 pids2)+ mkPackageIndex (Map.unionWith (\_ y -> y) pids1 pids2) (Map.unionWith (Map.unionWith mergeBuckets) pnames1 pnames2) where -- Packages in the second list mask those in the first, however preferred@@ -204,7 +261,7 @@ -- This is equivalent to (but slightly quicker than) using 'mappend' or -- 'merge' with a singleton index. ---insert :: InstalledPackageInfo -> PackageIndex -> PackageIndex+insert :: PackageInstalled a => a -> PackageIndex a -> PackageIndex a insert pkg (PackageIndex pids pnames) = mkPackageIndex pids' pnames' @@ -226,7 +283,7 @@ -- | Removes a single installed package from the index. ---deleteInstalledPackageId :: InstalledPackageId -> PackageIndex -> PackageIndex+deleteInstalledPackageId :: PackageInstalled a => InstalledPackageId -> PackageIndex a -> PackageIndex a deleteInstalledPackageId ipkgid original@(PackageIndex pids pnames) = case Map.updateLookupWithKey (\_ _ -> Nothing) ipkgid pids of (Nothing, _) -> original@@ -248,7 +305,7 @@ -- | Removes all packages with this source 'PackageId' from the index. ---deleteSourcePackageId :: PackageId -> PackageIndex -> PackageIndex+deleteSourcePackageId :: PackageInstalled a => PackageId -> PackageIndex a -> PackageIndex a deleteSourcePackageId pkgid original@(PackageIndex pids pnames) = case Map.lookup (packageName pkgid) pnames of Nothing -> original@@ -268,7 +325,7 @@ -- | Removes all packages with this (case-sensitive) name from the index. ---deletePackageName :: PackageName -> PackageIndex -> PackageIndex+deletePackageName :: PackageInstalled a => PackageName -> PackageIndex a -> PackageIndex a deletePackageName name original@(PackageIndex pids pnames) = case Map.lookup name pnames of Nothing -> original@@ -291,14 +348,14 @@ -- | Get all the packages from the index. ---allPackages :: PackageIndex -> [InstalledPackageInfo]+allPackages :: PackageIndex a -> [a] allPackages (PackageIndex pids _) = Map.elems pids -- | Get all the packages from the index. -- -- They are grouped by package name (case-sensitively). ---allPackagesByName :: PackageIndex -> [(PackageName, [InstalledPackageInfo])]+allPackagesByName :: PackageIndex a -> [(PackageName, [a])] allPackagesByName (PackageIndex _ pnames) = [ (pkgname, concat (Map.elems pvers)) | (pkgname, pvers) <- Map.toList pnames ]@@ -307,7 +364,7 @@ -- -- They are grouped by source package id (package name and version). ---allPackagesBySourcePackageId :: PackageIndex -> [(PackageId, [InstalledPackageInfo])]+allPackagesBySourcePackageId :: PackageInstalled a => PackageIndex a -> [(PackageId, [a])] allPackagesBySourcePackageId (PackageIndex _ pnames) = [ (packageId ipkg, ipkgs) | pvers <- Map.elems pnames@@ -322,8 +379,8 @@ -- Since multiple package DBs mask each other by 'InstalledPackageId', -- then we get back at most one package. ---lookupInstalledPackageId :: PackageIndex -> InstalledPackageId- -> Maybe InstalledPackageInfo+lookupInstalledPackageId :: PackageInstalled a => PackageIndex a -> InstalledPackageId+ -> Maybe a lookupInstalledPackageId (PackageIndex pids _) pid = Map.lookup pid pids @@ -333,7 +390,7 @@ -- but different 'InstalledPackageId'. They are returned in order of -- preference, with the most preferred first. ---lookupSourcePackageId :: PackageIndex -> PackageId -> [InstalledPackageInfo]+lookupSourcePackageId :: PackageInstalled a => PackageIndex a -> PackageId -> [a] lookupSourcePackageId (PackageIndex _ pnames) pkgid = case Map.lookup (packageName pkgid) pnames of Nothing -> []@@ -341,11 +398,18 @@ Nothing -> [] Just pkgs -> pkgs -- in preference order +-- | Convenient alias of 'lookupSourcePackageId', but assuming only+-- one package per package ID.+lookupPackageId :: PackageInstalled a => PackageIndex a -> PackageId -> Maybe a+lookupPackageId index pkgid = case lookupSourcePackageId index pkgid of+ [] -> Nothing+ [pkg] -> Just pkg+ _ -> error "Distribution.Simple.PackageIndex: multiple matches found" -- | Does a lookup by source package name. ---lookupPackageName :: PackageIndex -> PackageName- -> [(Version, [InstalledPackageInfo])]+lookupPackageName :: PackageInstalled a => PackageIndex a -> PackageName+ -> [(Version, [a])] lookupPackageName (PackageIndex _ pnames) name = case Map.lookup name pnames of Nothing -> []@@ -357,8 +421,8 @@ -- We get back any number of versions of the specified package name, all -- satisfying the version range constraint. ---lookupDependency :: PackageIndex -> Dependency- -> [(Version, [InstalledPackageInfo])]+lookupDependency :: PackageInstalled a => PackageIndex a -> Dependency+ -> [(Version, [a])] lookupDependency (PackageIndex _ pnames) (Dependency name versionRange) = case Map.lookup name pnames of Nothing -> []@@ -382,7 +446,7 @@ -- packages. The list of ambiguous results is split by exact package name. So -- it is a non-empty list of non-empty lists. ---searchByName :: PackageIndex -> String -> SearchResult [InstalledPackageInfo]+searchByName :: PackageInstalled a => PackageIndex a -> String -> SearchResult [a] searchByName (PackageIndex _ pnames) name = case [ pkgs | pkgs@(PackageName name',_) <- Map.toList pnames , lowercase name' == lname ] of@@ -399,7 +463,7 @@ -- -- That is, all packages that contain the given string in their name. ---searchByNameSubstring :: PackageIndex -> String -> [InstalledPackageInfo]+searchByNameSubstring :: PackageInstalled a => PackageIndex a -> String -> [a] searchByNameSubstring (PackageIndex _ pnames) searchterm = [ pkg | (PackageName name, pvers) <- Map.toList pnames@@ -423,11 +487,15 @@ -- list of groups of packages where within each group they all depend on each -- other, directly or indirectly. ---dependencyCycles :: PackageIndex -> [[InstalledPackageInfo]]-dependencyCycles index =+dependencyCycles :: PackageInstalled a => PackageIndex a -> [[a]]+dependencyCycles = dependencyCycles' Map.empty++-- | Variant of 'dependencyCycles' which accepts a 'FakeMap'. See Note [FakeMap].+dependencyCycles' :: PackageInstalled a => FakeMap -> PackageIndex a -> [[a]]+dependencyCycles' fakeMap index = [ vs | Graph.CyclicSCC vs <- Graph.stronglyConnComp adjacencyList ] where- adjacencyList = [ (pkg, installedPackageId pkg, IPI.depends pkg)+ adjacencyList = [ (pkg, installedPackageId pkg, fakeInstalledDepends fakeMap pkg) | pkg <- allPackages index ] @@ -435,14 +503,21 @@ -- -- Returns such packages along with the dependencies that they're missing. ---brokenPackages :: PackageIndex -> [(InstalledPackageInfo, [InstalledPackageId])]-brokenPackages index =+brokenPackages :: PackageInstalled a => PackageIndex a -> [(a, [InstalledPackageId])]+brokenPackages = brokenPackages' Map.empty++-- | Variant of 'brokenPackages' which accepts a 'FakeMap'. See Note [FakeMap].+brokenPackages' :: PackageInstalled a => FakeMap -> PackageIndex a -> [(a, [InstalledPackageId])]+brokenPackages' fakeMap index = [ (pkg, missing) | pkg <- allPackages index- , let missing = [ pkg' | pkg' <- IPI.depends pkg- , isNothing (lookupInstalledPackageId index pkg') ]+ , let missing = [ pkg' | pkg' <- installedDepends pkg+ , isNothing (fakeLookupInstalledPackageId fakeMap index pkg') ] , not (null missing) ] +-- | Variant of 'lookupInstalledPackageId' which accepts a 'FakeMap'. See Note [FakeMap].+fakeLookupInstalledPackageId :: PackageInstalled a => FakeMap -> PackageIndex a -> InstalledPackageId -> Maybe a+fakeLookupInstalledPackageId fakeMap index pkg = lookupInstalledPackageId index (Map.findWithDefault pkg pkg fakeMap) -- | Tries to take the transitive closure of the package dependencies. --@@ -452,48 +527,63 @@ -- * Note that if the result is @Right []@ it is because at least one of -- the original given 'PackageId's do not occur in the index. ---dependencyClosure :: PackageIndex+dependencyClosure :: PackageInstalled a => PackageIndex a -> [InstalledPackageId]- -> Either PackageIndex- [(InstalledPackageInfo, [InstalledPackageId])]-dependencyClosure index pkgids0 = case closure mempty [] pkgids0 of+ -> Either (PackageIndex a)+ [(a, [InstalledPackageId])]+dependencyClosure = dependencyClosure' Map.empty++-- | Variant of 'dependencyClosure' which accepts a 'FakeMap'. See Note [FakeMap].+dependencyClosure' :: PackageInstalled a => FakeMap+ -> PackageIndex a+ -> [InstalledPackageId]+ -> Either (PackageIndex a)+ [(a, [InstalledPackageId])]+dependencyClosure' fakeMap index pkgids0 = case closure mempty [] pkgids0 of (completed, []) -> Left completed (completed, _) -> Right (brokenPackages completed) where closure completed failed [] = (completed, failed)- closure completed failed (pkgid:pkgids) = case lookupInstalledPackageId index pkgid of+ closure completed failed (pkgid:pkgids) = case fakeLookupInstalledPackageId fakeMap index pkgid of Nothing -> closure completed (pkgid:failed) pkgids- Just pkg -> case lookupInstalledPackageId completed (installedPackageId pkg) of+ Just pkg -> case fakeLookupInstalledPackageId fakeMap completed (installedPackageId pkg) of Just _ -> closure completed failed pkgids Nothing -> closure completed' failed pkgids' where completed' = insert pkg completed- pkgids' = IPI.depends pkg ++ pkgids+ pkgids' = installedDepends pkg ++ pkgids -- | Takes the transitive closure of the packages reverse dependencies. -- -- * The given 'PackageId's must be in the index. ---reverseDependencyClosure :: PackageIndex+reverseDependencyClosure :: PackageInstalled a => PackageIndex a -> [InstalledPackageId]- -> [InstalledPackageInfo]-reverseDependencyClosure index =+ -> [a]+reverseDependencyClosure = reverseDependencyClosure' Map.empty++-- | Variant of 'reverseDependencyClosure' which accepts a 'FakeMap'. See Note [FakeMap].+reverseDependencyClosure' :: PackageInstalled a => FakeMap+ -> PackageIndex a+ -> [InstalledPackageId]+ -> [a]+reverseDependencyClosure' fakeMap index = map vertexToPkg . concatMap Tree.flatten . Graph.dfs reverseDepGraph . map (fromMaybe noSuchPkgId . pkgIdToVertex) where- (depGraph, vertexToPkg, pkgIdToVertex) = dependencyGraph index+ (depGraph, vertexToPkg, pkgIdToVertex) = dependencyGraph' fakeMap index reverseDepGraph = Graph.transposeG depGraph noSuchPkgId = error "reverseDependencyClosure: package is not in the graph" -topologicalOrder :: PackageIndex -> [InstalledPackageInfo]+topologicalOrder :: PackageInstalled a => PackageIndex a -> [a] topologicalOrder index = map toPkgId . Graph.topSort $ graph where (graph, toPkgId, _) = dependencyGraph index -reverseTopologicalOrder :: PackageIndex -> [InstalledPackageInfo]+reverseTopologicalOrder :: PackageInstalled a => PackageIndex a -> [a] reverseTopologicalOrder index = map toPkgId . Graph.topSort . Graph.transposeG@@ -505,20 +595,28 @@ -- Dependencies on other packages that are not in the index are discarded. -- You can check if there are any such dependencies with 'brokenPackages'. ---dependencyGraph :: PackageIndex+dependencyGraph :: PackageInstalled a => PackageIndex a -> (Graph.Graph,- Graph.Vertex -> InstalledPackageInfo,+ Graph.Vertex -> a, InstalledPackageId -> Maybe Graph.Vertex)-dependencyGraph index = (graph, vertex_to_pkg, id_to_vertex)+dependencyGraph = dependencyGraph' Map.empty++-- | Variant of 'dependencyGraph' which accepts a 'FakeMap'. See Note [FakeMap].+dependencyGraph' :: PackageInstalled a => FakeMap+ -> PackageIndex a+ -> (Graph.Graph,+ Graph.Vertex -> a,+ InstalledPackageId -> Maybe Graph.Vertex)+dependencyGraph' fakeMap index = (graph, vertex_to_pkg, id_to_vertex) where graph = Array.listArray bounds- [ [ v | Just v <- map id_to_vertex (IPI.depends pkg) ]+ [ [ v | Just v <- map id_to_vertex (installedDepends pkg) ] | pkg <- pkgs ] pkgs = sortBy (comparing packageId) (allPackages index) vertices = zip (map installedPackageId pkgs) [0..] vertex_map = Map.fromList vertices- id_to_vertex pid = Map.lookup pid vertex_map+ id_to_vertex pid = Map.lookup (Map.findWithDefault pid pid fakeMap) vertex_map vertex_to_pkg vertex = pkgTable ! vertex @@ -536,9 +634,14 @@ -- depend on it and the versions they require. These are guaranteed to be -- distinct. ---dependencyInconsistencies :: PackageIndex+dependencyInconsistencies :: PackageInstalled a => PackageIndex a -> [(PackageName, [(PackageId, Version)])]-dependencyInconsistencies index =+dependencyInconsistencies = dependencyInconsistencies' Map.empty++-- | Variant of 'dependencyInconsistencies' which accepts a 'FakeMap'. See Note [FakeMap].+dependencyInconsistencies' :: PackageInstalled a => FakeMap -> PackageIndex a+ -> [(PackageName, [(PackageId, Version)])]+dependencyInconsistencies' fakeMap index = [ (name, [ (pid,packageVersion dep) | (dep,pids) <- uses, pid <- pids]) | (name, ipid_map) <- Map.toList inverseIndex , let uses = Map.elems ipid_map@@ -548,29 +651,42 @@ -- for each package with that name, -- the InstalledPackageInfo and the package Ids of packages -- that depend on it.- inverseIndex :: Map PackageName- (Map InstalledPackageId- (InstalledPackageInfo, [PackageId])) inverseIndex = Map.fromListWith (Map.unionWith (\(a,b) (_,b') -> (a,b++b'))) [ (packageName dep, Map.fromList [(ipid,(dep,[packageId pkg]))]) | pkg <- allPackages index- , ipid <- IPI.depends pkg- , Just dep <- [lookupInstalledPackageId index ipid]+ , ipid <- fakeInstalledDepends fakeMap pkg+ , Just dep <- [fakeLookupInstalledPackageId fakeMap index ipid] ] - reallyIsInconsistent :: [InstalledPackageInfo] -> Bool+ reallyIsInconsistent :: PackageInstalled a => [a] -> Bool reallyIsInconsistent [] = False reallyIsInconsistent [_p] = False reallyIsInconsistent [p1, p2] =- installedPackageId p1 `notElem` IPI.depends p2- && installedPackageId p2 `notElem` IPI.depends p1+ let pid1 = installedPackageId p1+ pid2 = installedPackageId p2+ in Map.findWithDefault pid1 pid1 fakeMap `notElem` fakeInstalledDepends fakeMap p2+ && Map.findWithDefault pid2 pid2 fakeMap `notElem` fakeInstalledDepends fakeMap p1 reallyIsInconsistent _ = True +-- | Variant of 'installedDepends' which accepts a 'FakeMap'. See Note [FakeMap].+fakeInstalledDepends :: PackageInstalled a => FakeMap -> a -> [InstalledPackageId]+fakeInstalledDepends fakeMap = map (\pid -> Map.findWithDefault pid pid fakeMap) . installedDepends -moduleNameIndex :: PackageIndex -> Map ModuleName [InstalledPackageInfo]+-- | A rough approximation of GHC's module finder, takes a 'InstalledPackageIndex' and+-- turns it into a map from module names to their source packages. It's used to+-- initialize the @build-deps@ field in @cabal init@.+moduleNameIndex :: InstalledPackageIndex -> Map ModuleName [InstalledPackageInfo] moduleNameIndex index =- Map.fromListWith (++)- [ (moduleName, [pkg])- | pkg <- allPackages index- , moduleName <- IPI.exposedModules pkg ]+ Map.fromListWith (++) $ do+ pkg <- allPackages index+ IPI.ExposedModule m reexport _ <- IPI.exposedModules pkg+ case reexport of+ Nothing -> return (m, [pkg])+ Just (IPI.OriginalModule _ m') | m == m' -> []+ | otherwise -> return (m', [pkg])+ -- The heuristic is this: we want to prefer the original package+ -- which originally exported a module. However, if a reexport+ -- also *renamed* the module (m /= m'), then we have to use the+ -- downstream package, since the upstream package has the wrong+ -- module name!
Distribution/Simple/PreProcess.hs view
@@ -44,7 +44,8 @@ import Distribution.Simple.CCompiler ( cSourceExtensions ) import Distribution.Simple.Compiler- ( CompilerFlavor(..), compilerFlavor, compilerVersion )+ ( CompilerFlavor(..)+ , compilerFlavor, compilerCompatVersion, compilerVersion ) import Distribution.Simple.LocalBuildInfo ( LocalBuildInfo(..), Component(..) ) import Distribution.Simple.BuildPaths (autogenModulesDir,cppHeaderName)@@ -57,7 +58,7 @@ , requireProgram, requireProgramVersion , rawSystemProgramConf, rawSystemProgram , greencardProgram, cpphsProgram, hsc2hsProgram, c2hsProgram- , happyProgram, alexProgram, ghcProgram, gccProgram )+ , happyProgram, alexProgram, ghcProgram, ghcjsProgram, gccProgram ) import Distribution.Simple.Test.LibV09 ( writeSimpleTestStub, stubFilePath, stubName ) import Distribution.System@@ -97,12 +98,12 @@ -- -- The reason for splitting it up this way is that some pre-processors don't -- simply generate one output .hs file from one input file but have--- dependencies on other genereated files (notably c2hs, where building one+-- dependencies on other generated files (notably c2hs, where building one -- .hs file may require reading other .chi files, and then compiling the .hs -- file may require reading a generated .h file). In these cases the generated -- files need to embed relative path names to each other (eg the generated .hs -- file mentions the .h file in the FFI imports). This path must be relative to--- the base directory where the genereated files are located, it cannot be+-- the base directory where the generated files are located, it cannot be -- relative to the top level of the build tree because the compilers do not -- look for .h files relative to there, ie we do not use \"-I .\", instead we -- use \"-I dist\/build\" (or whatever dist dir has been set by the user)@@ -192,11 +193,9 @@ BenchmarkUnsupported tt -> die $ "No support for preprocessing benchmark " ++ "type " ++ display tt where- builtinHaskellSuffixes- | NHC == compilerFlavor (compiler lbi) = ["hs", "lhs", "gc"]- | otherwise = ["hs", "lhs"]- builtinCSuffixes = cSourceExtensions- builtinSuffixes = builtinHaskellSuffixes ++ builtinCSuffixes+ builtinHaskellSuffixes = ["hs", "lhs", "hsig", "lhsig"]+ builtinCSuffixes = cSourceExtensions+ builtinSuffixes = builtinHaskellSuffixes ++ builtinCSuffixes localHandlers bi = [(ext, h bi lbi) | (ext, h) <- handlers] pre dirs dir lhndlrs fp = preprocessFile dirs dir isSrcDist fp verbosity builtinSuffixes lhndlrs@@ -335,26 +334,28 @@ ppCpp' :: [String] -> BuildInfo -> LocalBuildInfo -> PreProcessor ppCpp' extraArgs bi lbi = case compilerFlavor (compiler lbi) of- GHC -> ppGhcCpp (cppArgs ++ extraArgs) bi lbi- _ -> ppCpphs (cppArgs ++ extraArgs) bi lbi-+ GHC -> ppGhcCpp ghcProgram (>= Version [6,6] []) args bi lbi+ GHCJS -> ppGhcCpp ghcjsProgram (const True) args bi lbi+ _ -> ppCpphs args bi lbi where cppArgs = getCppOptions bi lbi+ args = cppArgs ++ extraArgs -ppGhcCpp :: [String] -> BuildInfo -> LocalBuildInfo -> PreProcessor-ppGhcCpp extraArgs _bi lbi =+ppGhcCpp :: Program -> (Version -> Bool)+ -> [String] -> BuildInfo -> LocalBuildInfo -> PreProcessor+ppGhcCpp program xHs extraArgs _bi lbi = PreProcessor { platformIndependent = False, runPreProcessor = mkSimplePreProcessor $ \inFile outFile verbosity -> do- (ghcProg, ghcVersion, _) <- requireProgramVersion verbosity- ghcProgram anyVersion (withPrograms lbi)- rawSystemProgram verbosity ghcProg $+ (prog, version, _) <- requireProgramVersion verbosity+ program anyVersion (withPrograms lbi)+ rawSystemProgram verbosity prog $ ["-E", "-cpp"] -- This is a bit of an ugly hack. We're going to -- unlit the file ourselves later on if appropriate, -- so we need GHC not to unlit it now or it'll get -- double-unlitted. In the future we might switch to -- using cpphs --unlit instead.- ++ (if ghcVersion >= Version [6,6] [] then ["-x", "hs"] else [])+ ++ (if xHs version then ["-x", "hs"] else []) ++ [ "-optP-include", "-optP"++ (autogenModulesDir lbi </> cppHeaderName) ] ++ ["-o", outFile, inFile] ++ extraArgs@@ -441,8 +442,9 @@ isOSX = case buildOS of OSX -> True; _ -> False isELF = case buildOS of OSX -> False; Windows -> False; _ -> True; packageHacks = case compilerFlavor (compiler lbi) of- GHC -> hackRtsPackage- _ -> id+ GHC -> hackRtsPackage+ GHCJS -> 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@@ -506,9 +508,14 @@ ["-D" ++ arch ++ "_BUILD_ARCH=1"] ++ map (\os' -> "-D" ++ os' ++ "_HOST_OS=1") osStr ++ map (\arch' -> "-D" ++ arch' ++ "_HOST_ARCH=1") archStr+ GHCJS ->+ compatGlasgowHaskell +++ ["-D__GHCJS__=" ++ versionInt version] +++ ["-D" ++ os ++ "_BUILD_OS=1"] +++ ["-D" ++ arch ++ "_BUILD_ARCH=1"] +++ map (\os' -> "-D" ++ os' ++ "_HOST_OS=1") osStr +++ map (\arch' -> "-D" ++ arch' ++ "_HOST_ARCH=1") archStr JHC -> ["-D__JHC__=" ++ versionInt version]- NHC -> ["-D__NHC__=" ++ versionInt version]- Hugs -> ["-D__HUGS__"] HaskellSuite {} -> ["-D__HASKELL_SUITE__"] ++ map (\os' -> "-D" ++ os' ++ "_HOST_OS=1") osStr ++@@ -518,6 +525,9 @@ comp = compiler lbi Platform hostArch hostOS = hostPlatform lbi version = compilerVersion comp+ compatGlasgowHaskell =+ maybe [] (\v -> ["-D__GLASGOW_HASKELL__=" ++ versionInt v])+ (compilerCompatVersion GHC comp) -- TODO: move this into the compiler abstraction -- FIXME: this forces GHC's crazy 4.8.2 -> 408 convention on all -- the other compilers. Check if that's really what they want.@@ -547,6 +557,7 @@ IRIX -> ["irix"] HaLVM -> [] IOS -> ["ios"]+ Ghcjs -> ["ghcjs"] OtherOS _ -> [] archStr = case hostArch of I386 -> ["i386"]@@ -564,6 +575,7 @@ Rs6000 -> ["rs6000"] M68k -> ["m68k"] Vax -> ["vax"]+ JavaScript -> ["javascript"] OtherArch _ -> [] ppHappy :: BuildInfo -> LocalBuildInfo -> PreProcessor@@ -571,6 +583,7 @@ where pp = standardPP lbi happyProgram (hcFlags hc) hc = compilerFlavor (compiler lbi) hcFlags GHC = ["-agc"]+ hcFlags GHCJS = ["-agc"] hcFlags _ = [] ppAlex :: BuildInfo -> LocalBuildInfo -> PreProcessor@@ -578,6 +591,7 @@ where pp = standardPP lbi alexProgram (hcFlags hc) hc = compilerFlavor (compiler lbi) hcFlags GHC = ["-g"]+ hcFlags GHCJS = ["-g"] hcFlags _ = [] standardPP :: LocalBuildInfo -> Program -> [String] -> PreProcessor
Distribution/Simple/Program.hs view
@@ -79,6 +79,7 @@ , userSpecifyArgss , userSpecifiedArgs , lookupProgram+ , lookupProgramVersion , updateProgram , configureProgram , configureAllKnownPrograms@@ -91,13 +92,12 @@ -- * Programs that Cabal knows about , ghcProgram , ghcPkgProgram+ , ghcjsProgram+ , ghcjsPkgProgram , lhcProgram , lhcPkgProgram- , nhcProgram , hmakeProgram , jhcProgram- , hugsProgram- , ffihugsProgram , uhcProgram , gccProgram , arProgram
Distribution/Simple/Program/Ar.hs view
@@ -124,6 +124,7 @@ , "0 " -- GID, 6 bytes , "0644 " -- mode, 8 bytes ]+ headerSize :: Int headerSize = 60 -- http://en.wikipedia.org/wiki/Ar_(Unix)#File_format_details
Distribution/Simple/Program/Builtin.hs view
@@ -18,13 +18,12 @@ -- * Programs that Cabal knows about ghcProgram, ghcPkgProgram,+ ghcjsProgram,+ ghcjsPkgProgram, lhcProgram, lhcPkgProgram,- nhcProgram, hmakeProgram, jhcProgram,- hugsProgram,- ffihugsProgram, haskellSuiteProgram, haskellSuitePkgProgram, uhcProgram,@@ -46,13 +45,26 @@ hpcProgram, ) where -import Distribution.Simple.Program.Types- ( Program(..), simpleProgram ) import Distribution.Simple.Program.Find ( findProgramOnSearchPath )+import Distribution.Simple.Program.Run+ ( getProgramInvocationOutput, programInvocation )+import Distribution.Simple.Program.Types+ ( Program(..), ConfiguredProgram(..), simpleProgram ) import Distribution.Simple.Utils ( findProgramVersion )+import Distribution.Compat.Exception+ ( catchIO )+import Distribution.Version+ ( Version(..), withinRange, earlierVersion, laterVersion+ , intersectVersionRanges )+import Data.Char+ ( isDigit ) +import Data.List+ ( isInfixOf )+import qualified Data.Map as Map+ -- ------------------------------------------------------------ -- * Known programs -- ------------------------------------------------------------@@ -65,11 +77,10 @@ -- compilers and related progs ghcProgram , ghcPkgProgram- , hugsProgram- , ffihugsProgram+ , ghcjsProgram+ , ghcjsPkgProgram , haskellSuiteProgram , haskellSuitePkgProgram- , nhcProgram , hmakeProgram , jhcProgram , lhcProgram@@ -97,7 +108,23 @@ ghcProgram :: Program ghcProgram = (simpleProgram "ghc") {- programFindVersion = findProgramVersion "--numeric-version" id+ programFindVersion = findProgramVersion "--numeric-version" id,++ -- Workaround for https://ghc.haskell.org/trac/ghc/ticket/8825+ -- (spurious warning on non-english locales)+ programPostConf = \_verbosity ghcProg ->+ do let ghcProg' = ghcProg {+ programOverrideEnv = ("LANGUAGE", Just "en")+ : programOverrideEnv ghcProg+ }+ -- Only the 7.8 branch seems to be affected. Fixed in 7.8.4.+ affectedVersionRange = intersectVersionRanges+ (laterVersion $ Version [7,8,0] [])+ (earlierVersion $ Version [7,8,4] [])+ return $ maybe ghcProg+ (\v -> if withinRange v affectedVersionRange+ then ghcProg' else ghcProg)+ (programVersion ghcProg) } ghcPkgProgram :: Program@@ -110,6 +137,21 @@ _ -> "" } +ghcjsProgram :: Program+ghcjsProgram = (simpleProgram "ghcjs") {+ programFindVersion = findProgramVersion "--numeric-ghcjs-version" id+ }++ghcjsPkgProgram :: Program+ghcjsPkgProgram = (simpleProgram "ghcjs-pkg") {+ programFindVersion = findProgramVersion "--ghcjs-version" $ \str ->+ -- Invoking "ghcjs-pkg --version" gives a string like+ -- "GHCJS package manager version 6.4.1"+ case words str of+ (_:_:_:_:ver:_) -> ver+ _ -> ""+ }+ lhcProgram :: Program lhcProgram = (simpleProgram "lhc") { programFindVersion = findProgramVersion "--numeric-version" id@@ -125,16 +167,6 @@ _ -> "" } -nhcProgram :: Program-nhcProgram = (simpleProgram "nhc98") {- programFindVersion = findProgramVersion "--version" $ \str ->- -- Invoking "nhc98 --version" gives a string like- -- "/usr/local/bin/nhc98: v1.20 (2007-11-22)"- case words str of- (_:('v':ver):_) -> ver- _ -> ""- }- hmakeProgram :: Program hmakeProgram = (simpleProgram "hmake") { programFindVersion = findProgramVersion "--version" $ \str ->@@ -170,13 +202,6 @@ _ -> "" } --- AArgh! Finding the version of hugs or ffihugs is almost impossible.-hugsProgram :: Program-hugsProgram = simpleProgram "hugs"--ffihugsProgram :: Program-ffihugsProgram = simpleProgram "ffihugs"- -- This represents a haskell-suite compiler. Of course, the compiler -- itself probably is not called "haskell-suite", so this is not a real -- program. (But we don't know statically the name of the actual compiler,@@ -226,7 +251,7 @@ -- Invoking "alex --version" gives a string like -- "Alex version 2.1.0, (c) 2003 Chris Dornan and Simon Marlow" case words str of- (_:_:ver:_) -> takeWhile (`elem` ('.':['0'..'9'])) ver+ (_:_:ver:_) -> takeWhile (\x -> isDigit x || x == '.') ver _ -> "" } @@ -292,7 +317,19 @@ ldProgram = simpleProgram "ld" tarProgram :: Program-tarProgram = simpleProgram "tar"+tarProgram = (simpleProgram "tar") {+ -- See #1901. Some versions of 'tar' (OpenBSD, NetBSD, ...) don't support the+ -- '--format' option.+ programPostConf = \verbosity tarProg -> do+ tarHelpOutput <- getProgramInvocationOutput+ verbosity (programInvocation tarProg ["--help"])+ -- Some versions of tar don't support '--help'.+ `catchIO` (\_ -> return "")+ let k = "Supports --format"+ v = if ("--format" `isInfixOf` tarHelpOutput) then "YES" else "NO"+ m = Map.insert k v (programProperties tarProg)+ return $ tarProg { programProperties = m }+ } cppProgram :: Program cppProgram = simpleProgram "cpp"
Distribution/Simple/Program/Db.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE DeriveGeneric #-}+ ----------------------------------------------------------------------------- -- | -- Module : Distribution.Simple.Program.Db@@ -34,6 +36,7 @@ knownPrograms, getProgramSearchPath, setProgramSearchPath,+ modifyProgramSearchPath, userSpecifyPath, userSpecifyPaths, userMaybeSpecifyPath,@@ -47,6 +50,7 @@ -- ** Query and manipulate the program db configureProgram, configureAllKnownPrograms,+ lookupProgramVersion, reconfigurePrograms, requireProgram, requireProgramVersion,@@ -69,6 +73,8 @@ import Distribution.Verbosity ( Verbosity ) +import Data.Binary (Binary(..))+import Data.Functor ((<$>)) import Data.List ( foldl' ) import Data.Maybe@@ -131,7 +137,13 @@ [ (emptyProgramDb { configuredProgs = Map.fromList s' }, r) | (s', r) <- readsPrec p s ] +instance Binary ProgramDb where+ put = put . configuredProgs+ get = do+ progs <- get+ return $! emptyProgramDb { configuredProgs = progs } + -- | The Read\/Show instance does not preserve all the unconfigured 'Programs' -- because 'Program' is not in Read\/Show because it contains functions. So to -- fully restore a deserialised 'ProgramDb' use this function to add@@ -185,6 +197,16 @@ setProgramSearchPath :: ProgramSearchPath -> ProgramDb -> ProgramDb setProgramSearchPath searchpath db = db { progSearchPath = searchpath } +-- | Modify the current 'ProgramSearchPath' used by the 'ProgramDb'.+-- This will affect programs that are configured from here on, so you+-- should usually modify it before configuring any programs.+--+modifyProgramSearchPath :: (ProgramSearchPath -> ProgramSearchPath)+ -> ProgramDb+ -> ProgramDb+modifyProgramSearchPath f db =+ setProgramSearchPath (f $ getProgramSearchPath db) db+ -- |User-specify this path. Basically override any path information -- for this program in the configuration. If it's not a known -- program ignore it.@@ -284,7 +306,7 @@ -- -- The reason for it not being a failure at this stage is that we don't know up -- front all the programs we will need, so we try to configure them all.--- To verify that a program was actually sucessfully configured use+-- To verify that a program was actually successfully configured use -- 'requireProgram'. -- configureProgram :: Verbosity@@ -317,6 +339,7 @@ programDefaultArgs = [], programOverrideArgs = userSpecifiedArgs prog conf, programOverrideEnv = [("PATH", Just newPath)],+ programProperties = Map.empty, programLocation = location } configuredProg' <- programPostConf prog verbosity configuredProg@@ -389,32 +412,35 @@ -- | Check that a program is configured and available to be run. ----- Additionally check that the version of the program number is suitable and--- return it. For example you could require 'AnyVersion' or--- @'orLaterVersion' ('Version' [1,0] [])@+-- Additionally check that the program version number is suitable and return+-- it. For example you could require 'AnyVersion' or @'orLaterVersion'+-- ('Version' [1,0] [])@ ----- It raises an exception if the program could not be configured or the version--- is unsuitable, otherwise it returns the configured program and its version--- number.+-- It returns the configured program, its version number and a possibly updated+-- 'ProgramDb'. If the program could not be configured or the version is+-- unsuitable, it returns an error value. ---requireProgramVersion :: Verbosity -> Program -> VersionRange- -> ProgramDb- -> IO (ConfiguredProgram, Version, ProgramDb)-requireProgramVersion verbosity prog range conf = do+lookupProgramVersion+ :: Verbosity -> Program -> VersionRange -> ProgramDb+ -> IO (Either String (ConfiguredProgram, Version, ProgramDb))+lookupProgramVersion verbosity prog range programDb = do -- If it's not already been configured, try to configure it now- conf' <- case lookupProgram prog conf of- Nothing -> configureProgram verbosity prog conf- Just _ -> return conf+ programDb' <- case lookupProgram prog programDb of+ Nothing -> configureProgram verbosity prog programDb+ Just _ -> return programDb - case lookupProgram prog conf' of- Nothing -> die notFound+ case lookupProgram prog programDb' of+ Nothing -> return $! Left notFound Just configuredProg@ConfiguredProgram { programLocation = location } -> case programVersion configuredProg of Just version- | withinRange version range -> return (configuredProg, version, conf')- | otherwise -> die (badVersion version location)- Nothing -> die (noVersion location)+ | withinRange version range ->+ return $! Right (configuredProg, version ,programDb')+ | otherwise ->+ return $! Left (badVersion version location)+ Nothing ->+ return $! Left (noVersion location) where notFound = "The program '" ++ programName prog ++ "'" ++ versionRequirement@@ -430,3 +456,13 @@ versionRequirement | isAnyVersion range = "" | otherwise = " version " ++ display range++-- | Like 'lookupProgramVersion', but raises an exception in case of error+-- instead of returning 'Left errMsg'.+--+requireProgramVersion :: Verbosity -> Program -> VersionRange+ -> ProgramDb+ -> IO (ConfiguredProgram, Version, ProgramDb)+requireProgramVersion verbosity prog range programDb =+ join $ either die return <$>+ lookupProgramVersion verbosity prog range programDb
Distribution/Simple/Program/Find.hs view
@@ -89,6 +89,7 @@ -- .bat; .cmd". extensions = case buildOS of Windows -> ["", "exe"]+ Ghcjs -> ["", "exe"] _ -> [""] tryPathElem ProgramSearchPathDefault = do
Distribution/Simple/Program/GHC.hs view
@@ -11,20 +11,23 @@ ) where +import Distribution.Simple.GHC.ImplInfo ( getImplInfo, GhcImplInfo(..) ) import Distribution.Package+import Distribution.PackageDescription hiding (Flag) import Distribution.ModuleName import Distribution.Simple.Compiler hiding (Flag) import Distribution.Simple.Setup ( Flag(..), flagToMaybe, fromFlagOrDefault, flagToList )---import Distribution.Simple.LocalBuildInfo import Distribution.Simple.Program.Types import Distribution.Simple.Program.Run import Distribution.Text import Distribution.Verbosity-import Distribution.Version+import Distribution.Utils.NubList ( NubListR, fromNubListR ) import Language.Haskell.Extension ( Language(..), Extension(..) ) +import qualified Data.Map as M import Data.Monoid+import Data.List ( intercalate ) -- | A structured set of GHC options/flags --@@ -35,20 +38,20 @@ -- | Any extra options to pass directly to ghc. These go at the end and hence -- override other stuff.- ghcOptExtra :: [String],+ ghcOptExtra :: NubListR String, -- | Extra default flags to pass directly to ghc. These go at the beginning -- and so can be overridden by other stuff.- ghcOptExtraDefault :: [String],+ ghcOptExtraDefault :: NubListR String, ----------------------- -- Inputs and outputs -- | The main input files; could be .hs, .hi, .c, .o, depending on mode.- ghcOptInputFiles :: [FilePath],+ ghcOptInputFiles :: NubListR FilePath, -- | The names of input Haskell modules, mainly for @--make@ mode.- ghcOptInputModules :: [ModuleName],+ ghcOptInputModules :: NubListR ModuleName, -- | Location for output file; the @ghc -o@ flag. ghcOptOutputFile :: Flag FilePath,@@ -62,66 +65,73 @@ ghcOptSourcePathClear :: Flag Bool, -- | Search path for Haskell source files; the @ghc -i@ flag.- ghcOptSourcePath :: [FilePath],+ ghcOptSourcePath :: NubListR FilePath, ------------- -- Packages - -- | The package name the modules will belong to; the @ghc -package-name@ flag- ghcOptPackageName :: Flag PackageId,+ -- | The package key the modules will belong to; the @ghc -this-package-key@+ -- flag.+ ghcOptPackageKey :: Flag PackageKey, - -- | GHC package databases to use, the @ghc -package-conf@ flag+ -- | GHC package databases to use, the @ghc -package-conf@ flag. ghcOptPackageDBs :: PackageDBStack, -- | The GHC packages to use. For compatability with old and new ghc, this -- requires both the short and long form of the package id; -- the @ghc -package@ or @ghc -package-id@ flags.- ghcOptPackages :: [(InstalledPackageId, PackageId)],+ ghcOptPackages ::+ NubListR (InstalledPackageId, PackageId, ModuleRenaming), -- | Start with a clean package set; the @ghc -hide-all-packages@ flag ghcOptHideAllPackages :: Flag Bool, - -- | Don't automatically link in Haskell98 etc; the @ghc -no-auto-link-packages@ flag.+ -- | Don't automatically link in Haskell98 etc; the @ghc+ -- -no-auto-link-packages@ flag. ghcOptNoAutoLinkPackages :: Flag Bool, + -- | What packages are implementing the signatures+ ghcOptSigOf :: [(ModuleName, (PackageKey, ModuleName))],+ ----------------- -- Linker stuff -- | Names of libraries to link in; the @ghc -l@ flag.- ghcOptLinkLibs :: [FilePath],+ ghcOptLinkLibs :: NubListR FilePath, -- | Search path for libraries to link in; the @ghc -L@ flag.- ghcOptLinkLibPath :: [FilePath],+ ghcOptLinkLibPath :: NubListR FilePath, -- | Options to pass through to the linker; the @ghc -optl@ flag.- ghcOptLinkOptions :: [String],+ ghcOptLinkOptions :: NubListR String, -- | OSX only: frameworks to link in; the @ghc -framework@ flag.- ghcOptLinkFrameworks :: [String],+ ghcOptLinkFrameworks :: NubListR String, -- | Don't do the link step, useful in make mode; the @ghc -no-link@ flag. ghcOptNoLink :: Flag Bool, - -- | Don't link in the normal RTS @main@ entry point; the @ghc -no-hs-main@ flag.+ -- | Don't link in the normal RTS @main@ entry point; the @ghc -no-hs-main@+ -- flag. ghcOptLinkNoHsMain :: Flag Bool, -------------------- -- C and CPP stuff -- | Options to pass through to the C compiler; the @ghc -optc@ flag.- ghcOptCcOptions :: [String],+ ghcOptCcOptions :: NubListR String, -- | Options to pass through to CPP; the @ghc -optP@ flag.- ghcOptCppOptions :: [String],+ ghcOptCppOptions :: NubListR String, -- | Search path for CPP includes like header files; the @ghc -I@ flag.- ghcOptCppIncludePath :: [FilePath],+ ghcOptCppIncludePath :: NubListR FilePath, -- | Extra header files to include at CPP stage; the @ghc -optP-include@ flag.- ghcOptCppIncludes :: [FilePath],+ ghcOptCppIncludes :: NubListR FilePath, -- | Extra header files to include for old-style FFI; the @ghc -#include@ flag.- ghcOptFfiIncludes :: [FilePath],+ ghcOptFfiIncludes :: NubListR FilePath, ---------------------------- -- Language and extensions@@ -130,11 +140,11 @@ ghcOptLanguage :: Flag Language, -- | The language extensions; the @ghc -X@ flag.- ghcOptExtensions :: [Extension],+ ghcOptExtensions :: NubListR Extension, -- | A GHC version-dependent mapping of extensions to flags. This must be -- set to be able to make use of the 'ghcOptExtensions'.- ghcOptExtensionMap :: [(Extension, String)],+ ghcOptExtensionMap :: M.Map Extension String, ---------------- -- Compilation@@ -142,6 +152,9 @@ -- | What optimisation level to use; the @ghc -O@ flag. ghcOptOptimisation :: Flag GhcOptimisation, + -- | Emit debug info; the @ghc -g@ flag.+ ghcOptDebugInfo :: Flag Bool,+ -- | Compile in profiling mode; the @ghc -prof@ flag. ghcOptProfilingMode :: Flag Bool, @@ -149,13 +162,16 @@ ghcOptSplitObjs :: Flag Bool, -- | Run N jobs simultaneously (if possible).- ghcOptNumJobs :: Flag Int,+ ghcOptNumJobs :: Flag (Maybe Int), + -- | Enable coverage analysis; the @ghc -fhpc -hpcdir@ flags.+ ghcOptHPCDir :: Flag FilePath,+ ---------------- -- GHCi -- | Extra GHCi startup scripts; the @-ghci-script@ flag- ghcOptGHCiScripts :: [FilePath],+ ghcOptGHCiScripts :: NubListR FilePath, ------------------------ -- Redirecting outputs@@ -176,6 +192,7 @@ ghcOptShared :: Flag Bool, ghcOptFPic :: Flag Bool, ghcOptDylibName :: Flag String,+ ghcOptRPaths :: NubListR FilePath, --------------- -- Misc flags@@ -220,12 +237,11 @@ ghcInvocation prog comp opts = programInvocation prog (renderGhcOptions comp opts) - renderGhcOptions :: Compiler -> GhcOptions -> [String] renderGhcOptions comp opts- | compilerFlavor comp /= GHC =+ | compilerFlavor comp `notElem` [GHC, GHCJS] = error $ "Distribution.Simple.Program.GHC.renderGhcOptions: "- ++ "compiler flavor must be 'GHC'!"+ ++ "compiler flavor must be 'GHC' or 'GHCJS'!" | otherwise = concat [ case flagToMaybe (ghcOptMode opts) of@@ -247,7 +263,8 @@ , maybe [] verbosityOpts (flagToMaybe (ghcOptVerbosity opts)) - , [ "-fbuilding-cabal-package" | flagBool ghcOptCabal, ver >= [6,11] ]+ , [ "-fbuilding-cabal-package" | flagBool ghcOptCabal+ , flagBuildingCabalPkg implInfo ] ---------------- -- Compilation@@ -259,15 +276,20 @@ Just GhcMaximumOptimisation -> ["-O2"] Just (GhcSpecialOptimisation s) -> ["-O" ++ s] -- eg -Odph + , [ "-g" | flagDebugInfo implInfo && flagBool ghcOptDebugInfo ]+ , [ "-prof" | flagBool ghcOptProfilingMode ] , [ "-split-objs" | flagBool ghcOptSplitObjs ] + , case flagToMaybe (ghcOptHPCDir opts) of+ Nothing -> []+ Just hpcdir -> ["-fhpc", "-hpcdir", hpcdir] , if parmakeSupported comp- then- let numJobs = fromFlagOrDefault 1 (ghcOptNumJobs opts)- in if numJobs > 1 then ["-j" ++ show numJobs] else []+ then case ghcOptNumJobs opts of+ NoFlag -> []+ Flag n -> ["-j" ++ maybe "" show n] else [] --------------------@@ -290,10 +312,12 @@ , concat [ ["-hisuf", suf] | suf <- flag ghcOptHiSuffix ] , concat [ ["-dynosuf", suf] | suf <- flag ghcOptDynObjSuffix ] , concat [ ["-dynhisuf",suf] | suf <- flag ghcOptDynHiSuffix ]- , concat [ ["-outputdir", dir] | dir <- flag ghcOptOutputDir, ver >= [6,10] ]+ , concat [ ["-outputdir", dir] | dir <- flag ghcOptOutputDir+ , flagOutputDir implInfo ] , concat [ ["-odir", dir] | dir <- flag ghcOptObjDir ] , concat [ ["-hidir", dir] | dir <- flag ghcOptHiDir ]- , concat [ ["-stubdir", dir] | dir <- flag ghcOptStubDir, ver >= [6,8] ]+ , concat [ ["-stubdir", dir] | dir <- flag ghcOptStubDir+ , flagStubdir implInfo ] ----------------------- -- Source search path@@ -306,8 +330,10 @@ , [ "-I" ++ dir | dir <- flags ghcOptCppIncludePath ] , [ "-optP" ++ opt | opt <- flags ghcOptCppOptions ]- , concat [ [ "-optP-include", "-optP" ++ inc] | inc <- flags ghcOptCppIncludes ]- , [ "-#include \"" ++ inc ++ "\"" | inc <- flags ghcOptFfiIncludes, ver < [6,11] ]+ , concat [ [ "-optP-include", "-optP" ++ inc]+ | inc <- flags ghcOptCppIncludes ]+ , [ "-#include \"" ++ inc ++ "\""+ | inc <- flags ghcOptFfiIncludes, flagFfiIncludes implInfo ] , [ "-optc" ++ opt | opt <- flags ghcOptCcOptions ] -----------------@@ -318,45 +344,64 @@ , ["-L" ++ dir | dir <- flags ghcOptLinkLibPath ] , concat [ ["-framework", fmwk] | fmwk <- flags ghcOptLinkFrameworks ] , [ "-no-hs-main" | flagBool ghcOptLinkNoHsMain ]+ , [ "-dynload deploy" | not (null (flags ghcOptRPaths)) ]+ , concat [ [ "-optl-Wl,-rpath," ++ dir]+ | dir <- flags ghcOptRPaths ] ------------- -- Packages - , concat [ ["-package-name", display pkgid] | pkgid <- flag ghcOptPackageName ]+ , concat [ [if packageKeySupported comp+ then "-this-package-key"+ else "-package-name", display pkgid]+ | pkgid <- flag ghcOptPackageKey ] , [ "-hide-all-packages" | flagBool ghcOptHideAllPackages ] , [ "-no-auto-link-packages" | flagBool ghcOptNoAutoLinkPackages ] - , packageDbArgs version (flags ghcOptPackageDBs)+ , packageDbArgs implInfo (ghcOptPackageDBs opts) - , concat $ if ver >= [6,11]- then [ ["-package-id", display ipkgid] | (ipkgid,_) <- flags ghcOptPackages ]- else [ ["-package", display pkgid] | (_,pkgid) <- flags ghcOptPackages ]+ , if null (ghcOptSigOf opts)+ then []+ else "-sig-of"+ : intercalate "," (map (\(n,(p,m)) -> display n ++ " is "+ ++ display p ++ ":"+ ++ display m)+ (ghcOptSigOf opts))+ : [] + , concat $ if flagPackageId implInfo+ then let space "" = ""+ space xs = ' ' : xs+ in [ ["-package-id", display ipkgid ++ space (display rns)]+ | (ipkgid,_,rns) <- flags ghcOptPackages ]+ else [ ["-package", display pkgid]+ | (_,pkgid,_) <- flags ghcOptPackages ]+ ---------------------------- -- Language and extensions - , if ver >= [7]+ , if supportsHaskell2010 implInfo then [ "-X" ++ display lang | lang <- flag ghcOptLanguage ] else [] - , [ case lookup ext (ghcOptExtensionMap opts) of+ , [ case M.lookup ext (ghcOptExtensionMap opts) of Just arg -> arg Nothing -> error $ "Distribution.Simple.Program.GHC.renderGhcOptions: " ++ display ext ++ " not present in ghcOptExtensionMap."- | ext <- ghcOptExtensions opts ]+ | ext <- flags ghcOptExtensions ] ---------------- -- GHCi , concat [ [ "-ghci-script", script ] | script <- flags ghcOptGHCiScripts- , ver >= [7,2] ]+ , flagGhciScript implInfo ] --------------- -- Inputs , [ display modu | modu <- flags ghcOptInputModules ]- , ghcOptInputFiles opts+ , flags ghcOptInputFiles , concat [ [ "-o", out] | out <- flag ghcOptOutputFile ] , concat [ [ "-dyno", out] | out <- flag ghcOptOutputDynFile ]@@ -364,18 +409,17 @@ --------------- -- Extra - , ghcOptExtra opts+ , flags ghcOptExtra ] where+ implInfo = getImplInfo comp flag flg = flagToList (flg opts)- flags flg = flg opts+ flags flg = fromNubListR . flg $ opts flagBool flg = fromFlagOrDefault False (flg opts) - version@(Version ver _) = compilerVersion comp- verbosityOpts :: Verbosity -> [String] verbosityOpts verbosity | verbosity >= deafening = ["-v"]@@ -383,8 +427,8 @@ | otherwise = ["-w", "-v0"] -packageDbArgs :: Version -> PackageDBStack -> [String]-packageDbArgs (Version ver _) dbstack = case dbstack of+packageDbArgs :: GhcImplInfo -> PackageDBStack -> [String]+packageDbArgs implInfo dbstack = case dbstack of (GlobalPackageDB:UserPackageDB:dbs) -> concatMap specific dbs (GlobalPackageDB:dbs) -> ("-no-user-" ++ packageDbFlag) : concatMap specific dbs@@ -394,9 +438,8 @@ specific _ = ierror ierror = error $ "internal error: unexpected package db stack: " ++ show dbstack- packageDbFlag- | ver < [7,5]+ | flagPackageConf implInfo = "package-conf" | otherwise = "package-db"@@ -416,11 +459,12 @@ ghcOptOutputDynFile = mempty, ghcOptSourcePathClear = mempty, ghcOptSourcePath = mempty,- ghcOptPackageName = mempty,+ ghcOptPackageKey = mempty, ghcOptPackageDBs = mempty, ghcOptPackages = mempty, ghcOptHideAllPackages = mempty, ghcOptNoAutoLinkPackages = mempty,+ ghcOptSigOf = mempty, ghcOptLinkLibs = mempty, ghcOptLinkLibPath = mempty, ghcOptLinkOptions = mempty,@@ -436,9 +480,11 @@ ghcOptExtensions = mempty, ghcOptExtensionMap = mempty, ghcOptOptimisation = mempty,+ ghcOptDebugInfo = mempty, ghcOptProfilingMode = mempty, ghcOptSplitObjs = mempty, ghcOptNumJobs = mempty,+ ghcOptHPCDir = mempty, ghcOptGHCiScripts = mempty, ghcOptHiSuffix = mempty, ghcOptObjSuffix = mempty,@@ -452,6 +498,7 @@ ghcOptShared = mempty, ghcOptFPic = mempty, ghcOptDylibName = mempty,+ ghcOptRPaths = mempty, ghcOptVerbosity = mempty, ghcOptCabal = mempty }@@ -465,11 +512,12 @@ ghcOptOutputDynFile = combine ghcOptOutputDynFile, ghcOptSourcePathClear = combine ghcOptSourcePathClear, ghcOptSourcePath = combine ghcOptSourcePath,- ghcOptPackageName = combine ghcOptPackageName,+ ghcOptPackageKey = combine ghcOptPackageKey, ghcOptPackageDBs = combine ghcOptPackageDBs, ghcOptPackages = combine ghcOptPackages, ghcOptHideAllPackages = combine ghcOptHideAllPackages, ghcOptNoAutoLinkPackages = combine ghcOptNoAutoLinkPackages,+ ghcOptSigOf = combine ghcOptSigOf, ghcOptLinkLibs = combine ghcOptLinkLibs, ghcOptLinkLibPath = combine ghcOptLinkLibPath, ghcOptLinkOptions = combine ghcOptLinkOptions,@@ -485,9 +533,11 @@ ghcOptExtensions = combine ghcOptExtensions, ghcOptExtensionMap = combine ghcOptExtensionMap, ghcOptOptimisation = combine ghcOptOptimisation,+ ghcOptDebugInfo = combine ghcOptDebugInfo, ghcOptProfilingMode = combine ghcOptProfilingMode, ghcOptSplitObjs = combine ghcOptSplitObjs, ghcOptNumJobs = combine ghcOptNumJobs,+ ghcOptHPCDir = combine ghcOptHPCDir, ghcOptGHCiScripts = combine ghcOptGHCiScripts, ghcOptHiSuffix = combine ghcOptHiSuffix, ghcOptObjSuffix = combine ghcOptObjSuffix,@@ -501,6 +551,7 @@ ghcOptShared = combine ghcOptShared, ghcOptFPic = combine ghcOptFPic, ghcOptDylibName = combine ghcOptDylibName,+ ghcOptRPaths = combine ghcOptRPaths, ghcOptVerbosity = combine ghcOptVerbosity, ghcOptCabal = combine ghcOptCabal }
Distribution/Simple/Program/HcPkg.hs view
@@ -7,9 +7,11 @@ -- Portability : portable -- -- This module provides an library interface to the @hc-pkg@ program.--- Currently only GHC and LHC have hc-pkg programs.+-- Currently only GHC, GHCJS and LHC have hc-pkg programs. module Distribution.Simple.Program.HcPkg (+ HcPkgInfo(..),+ init, invoke, register,@@ -42,12 +44,10 @@ import Distribution.Simple.Compiler ( PackageDB(..), PackageDBStack ) import Distribution.Simple.Program.Types- ( ConfiguredProgram(programId, programVersion) )+ ( ConfiguredProgram(programId) ) import Distribution.Simple.Program.Run ( ProgramInvocation(..), IOEncoding(..), programInvocation , runProgramInvocation, getProgramInvocationOutput )-import Distribution.Version- ( Version(..) ) import Distribution.Text ( display, simpleParse ) import Distribution.Simple.Utils@@ -59,127 +59,122 @@ import Data.Char ( isSpace )-import Data.Maybe- ( fromMaybe ) import Data.List ( stripPrefix ) import System.FilePath as FilePath ( (</>), splitPath, splitDirectories, joinPath, isPathSeparator ) import qualified System.FilePath.Posix as FilePath.Posix +-- | Information about the features and capabilities of an @hc-pkg@+-- program.+--+data HcPkgInfo = HcPkgInfo+ { hcPkgProgram :: ConfiguredProgram+ , noPkgDbStack :: Bool -- ^ no package DB stack supported+ , noVerboseFlag :: Bool -- ^ hc-pkg does not support verbosity flags+ , flagPackageConf :: Bool -- ^ use package-conf option instead of package-db+ } -- | Call @hc-pkg@ to initialise a package database at the location {path}. -- -- > hc-pkg init {path} ---init :: Verbosity -> ConfiguredProgram -> FilePath -> IO ()-init verbosity hcPkg path =- runProgramInvocation verbosity- (initInvocation hcPkg verbosity path)+init :: HcPkgInfo -> Verbosity -> FilePath -> IO ()+init hpi verbosity path =+ runProgramInvocation verbosity (initInvocation hpi verbosity path) -- | Run @hc-pkg@ using a given package DB stack, directly forwarding the -- provided command-line arguments to it.-invoke :: Verbosity -> ConfiguredProgram -> PackageDBStack -> [String] -> IO ()-invoke verbosity hcPkg dbStack extraArgs =+invoke :: HcPkgInfo -> Verbosity -> PackageDBStack -> [String] -> IO ()+invoke hpi verbosity dbStack extraArgs = runProgramInvocation verbosity invocation where- args = packageDbStackOpts hcPkg dbStack ++ extraArgs- invocation = programInvocation hcPkg args+ args = packageDbStackOpts hpi dbStack ++ extraArgs+ invocation = programInvocation (hcPkgProgram hpi) args -- | Call @hc-pkg@ to register a package. -- -- > hc-pkg register {filename | -} [--user | --global | --package-db] ---register :: Verbosity -> ConfiguredProgram -> PackageDBStack+register :: HcPkgInfo -> Verbosity -> PackageDBStack -> Either FilePath InstalledPackageInfo -> IO ()-register verbosity hcPkg packagedb pkgFile =+register hpi verbosity packagedb pkgFile = runProgramInvocation verbosity- (registerInvocation hcPkg verbosity packagedb pkgFile)+ (registerInvocation hpi verbosity packagedb pkgFile) -- | Call @hc-pkg@ to re-register a package. -- -- > hc-pkg register {filename | -} [--user | --global | --package-db] ---reregister :: Verbosity -> ConfiguredProgram -> PackageDBStack+reregister :: HcPkgInfo -> Verbosity -> PackageDBStack -> Either FilePath InstalledPackageInfo -> IO ()-reregister verbosity hcPkg packagedb pkgFile =+reregister hpi verbosity packagedb pkgFile = runProgramInvocation verbosity- (reregisterInvocation hcPkg verbosity packagedb pkgFile)+ (reregisterInvocation hpi verbosity packagedb pkgFile) -- | Call @hc-pkg@ to unregister a package -- -- > hc-pkg unregister [pkgid] [--user | --global | --package-db] ---unregister :: Verbosity -> ConfiguredProgram -> PackageDB -> PackageId -> IO ()-unregister verbosity hcPkg packagedb pkgid =+unregister :: HcPkgInfo -> Verbosity -> PackageDB -> PackageId -> IO ()+unregister hpi verbosity packagedb pkgid = runProgramInvocation verbosity- (unregisterInvocation hcPkg verbosity packagedb pkgid)+ (unregisterInvocation hpi verbosity packagedb pkgid) -- | Call @hc-pkg@ to expose a package. -- -- > hc-pkg expose [pkgid] [--user | --global | --package-db] ---expose :: Verbosity -> ConfiguredProgram -> PackageDB -> PackageId -> IO ()-expose verbosity hcPkg packagedb pkgid =+expose :: HcPkgInfo -> Verbosity -> PackageDB -> PackageId -> IO ()+expose hpi verbosity packagedb pkgid = runProgramInvocation verbosity- (exposeInvocation hcPkg verbosity packagedb pkgid)+ (exposeInvocation hpi verbosity packagedb pkgid) --- | Call @hc-pkg@ to expose a package.+-- | Call @hc-pkg@ to hide a package. ----- > hc-pkg expose [pkgid] [--user | --global | --package-db]+-- > hc-pkg hide [pkgid] [--user | --global | --package-db] ---hide :: Verbosity -> ConfiguredProgram -> PackageDB -> PackageId -> IO ()-hide verbosity hcPkg packagedb pkgid =+hide :: HcPkgInfo -> Verbosity -> PackageDB -> PackageId -> IO ()+hide hpi verbosity packagedb pkgid = runProgramInvocation verbosity- (hideInvocation hcPkg verbosity packagedb pkgid)+ (hideInvocation hpi verbosity packagedb pkgid) -- | Call @hc-pkg@ to get all the details of all the packages in the given -- package database. ---dump :: Verbosity -> ConfiguredProgram -> PackageDB -> IO [InstalledPackageInfo]-dump verbosity hcPkg packagedb = do+dump :: HcPkgInfo -> Verbosity -> PackageDB -> IO [InstalledPackageInfo]+dump hpi verbosity packagedb = do output <- getProgramInvocationOutput verbosity- (dumpInvocation hcPkg verbosity packagedb)- `catchExit` \_ -> die $ programId hcPkg ++ " dump failed"+ (dumpInvocation hpi verbosity packagedb)+ `catchExit` \_ -> die $ programId (hcPkgProgram hpi) ++ " dump failed" case parsePackages output of Left ok -> return ok _ -> die $ "failed to parse output of '"- ++ programId hcPkg ++ " dump'"+ ++ programId (hcPkgProgram hpi) ++ " dump'" where parsePackages str = let parsed = map parseInstalledPackageInfo' (splitPkgs str) in case [ msg | ParseFailed msg <- parsed ] of [] -> Left [ setInstalledPackageId- . maybe id mungePackagePaths pkgroot+ . maybe id mungePackagePaths (pkgRoot pkg) $ pkg- | ParseOk _ (pkgroot, pkg) <- parsed ]+ | ParseOk _ pkg <- parsed ] msgs -> Right msgs parseInstalledPackageInfo' =- parseFieldsFlat fields (Nothing, emptyInstalledPackageInfo)- where- fields = liftFieldFst pkgrootField- : map liftFieldSnd fieldsInstalledPackageInfo-- pkgrootField =- simpleField "pkgroot"- showFilePath parseFilePathQ- (fromMaybe "") (\x _ -> Just x)-- liftFieldFst = liftField fst (\x (_x,y) -> (x,y))- liftFieldSnd = liftField snd (\y (x,_y) -> (x,y))+ parseFieldsFlat fieldsInstalledPackageInfo emptyInstalledPackageInfo --TODO: this could be a lot faster. We're doing normaliseLineEndings twice -- and converting back and forth with lines/unlines.@@ -256,162 +251,145 @@ -- Note in particular that it does not include the 'InstalledPackageId', just -- the source 'PackageId' which is not necessarily unique in any package db. ---list :: Verbosity -> ConfiguredProgram -> PackageDB -> IO [PackageId]-list verbosity hcPkg packagedb = do+list :: HcPkgInfo -> Verbosity -> PackageDB+ -> IO [PackageId]+list hpi verbosity packagedb = do output <- getProgramInvocationOutput verbosity- (listInvocation hcPkg verbosity packagedb)- `catchExit` \_ -> die $ programId hcPkg ++ " list failed"+ (listInvocation hpi verbosity packagedb)+ `catchExit` \_ -> die $ programId (hcPkgProgram hpi) ++ " list failed" case parsePackageIds output of Just ok -> return ok _ -> die $ "failed to parse output of '"- ++ programId hcPkg ++ " list'"+ ++ programId (hcPkgProgram hpi) ++ " list'" where- parsePackageIds str =- let parsed = map simpleParse (words str)- in case [ () | Nothing <- parsed ] of- [] -> Just [ pkgid | Just pkgid <- parsed ]- _ -> Nothing-+ parsePackageIds = sequence . map simpleParse . words -------------------------- -- The program invocations -- -initInvocation :: ConfiguredProgram- -> Verbosity -> FilePath -> ProgramInvocation-initInvocation hcPkg verbosity path =- programInvocation hcPkg args+initInvocation :: HcPkgInfo -> Verbosity -> FilePath -> ProgramInvocation+initInvocation hpi verbosity path =+ programInvocation (hcPkgProgram hpi) args where args = ["init", path]- ++ verbosityOpts hcPkg verbosity+ ++ verbosityOpts hpi verbosity registerInvocation, reregisterInvocation- :: ConfiguredProgram -> Verbosity -> PackageDBStack+ :: HcPkgInfo -> Verbosity -> PackageDBStack -> Either FilePath InstalledPackageInfo -> ProgramInvocation registerInvocation = registerInvocation' "register" reregisterInvocation = registerInvocation' "update" -registerInvocation' :: String- -> ConfiguredProgram -> Verbosity -> PackageDBStack+registerInvocation' :: String -> HcPkgInfo -> Verbosity -> PackageDBStack -> Either FilePath InstalledPackageInfo -> ProgramInvocation-registerInvocation' cmdname hcPkg verbosity packagedbs (Left pkgFile) =- programInvocation hcPkg args+registerInvocation' cmdname hpi verbosity packagedbs (Left pkgFile) =+ programInvocation (hcPkgProgram hpi) args where args = [cmdname, pkgFile]- ++ (if legacyVersion hcPkg- then [packageDbOpts hcPkg (last packagedbs)]- else packageDbStackOpts hcPkg packagedbs)- ++ verbosityOpts hcPkg verbosity+ ++ (if noPkgDbStack hpi+ then [packageDbOpts hpi (last packagedbs)]+ else packageDbStackOpts hpi packagedbs)+ ++ verbosityOpts hpi verbosity -registerInvocation' cmdname hcPkg verbosity packagedbs (Right pkgInfo) =- (programInvocation hcPkg args) {+registerInvocation' cmdname hpi verbosity packagedbs (Right pkgInfo) =+ (programInvocation (hcPkgProgram hpi) args) { progInvokeInput = Just (showInstalledPackageInfo pkgInfo), progInvokeInputEncoding = IOEncodingUTF8 } where args = [cmdname, "-"]- ++ (if legacyVersion hcPkg- then [packageDbOpts hcPkg (last packagedbs)]- else packageDbStackOpts hcPkg packagedbs)- ++ verbosityOpts hcPkg verbosity+ ++ (if noPkgDbStack hpi+ then [packageDbOpts hpi (last packagedbs)]+ else packageDbStackOpts hpi packagedbs)+ ++ verbosityOpts hpi verbosity -unregisterInvocation :: ConfiguredProgram- -> Verbosity -> PackageDB -> PackageId+unregisterInvocation :: HcPkgInfo -> Verbosity -> PackageDB -> PackageId -> ProgramInvocation-unregisterInvocation hcPkg verbosity packagedb pkgid =- programInvocation hcPkg $- ["unregister", packageDbOpts hcPkg packagedb, display pkgid]- ++ verbosityOpts hcPkg verbosity+unregisterInvocation hpi verbosity packagedb pkgid =+ programInvocation (hcPkgProgram hpi) $+ ["unregister", packageDbOpts hpi packagedb, display pkgid]+ ++ verbosityOpts hpi verbosity -exposeInvocation :: ConfiguredProgram- -> Verbosity -> PackageDB -> PackageId -> ProgramInvocation-exposeInvocation hcPkg verbosity packagedb pkgid =- programInvocation hcPkg $- ["expose", packageDbOpts hcPkg packagedb, display pkgid]- ++ verbosityOpts hcPkg verbosity+exposeInvocation :: HcPkgInfo -> Verbosity -> PackageDB -> PackageId+ -> ProgramInvocation+exposeInvocation hpi verbosity packagedb pkgid =+ programInvocation (hcPkgProgram hpi) $+ ["expose", packageDbOpts hpi packagedb, display pkgid]+ ++ verbosityOpts hpi verbosity -hideInvocation :: ConfiguredProgram- -> Verbosity -> PackageDB -> PackageId -> ProgramInvocation-hideInvocation hcPkg verbosity packagedb pkgid =- programInvocation hcPkg $- ["hide", packageDbOpts hcPkg packagedb, display pkgid]- ++ verbosityOpts hcPkg verbosity+hideInvocation :: HcPkgInfo -> Verbosity -> PackageDB -> PackageId+ -> ProgramInvocation+hideInvocation hpi verbosity packagedb pkgid =+ programInvocation (hcPkgProgram hpi) $+ ["hide", packageDbOpts hpi packagedb, display pkgid]+ ++ verbosityOpts hpi verbosity -dumpInvocation :: ConfiguredProgram- -> Verbosity -> PackageDB -> ProgramInvocation-dumpInvocation hcPkg _verbosity packagedb =- (programInvocation hcPkg args) {+dumpInvocation :: HcPkgInfo -> Verbosity -> PackageDB -> ProgramInvocation+dumpInvocation hpi _verbosity packagedb =+ (programInvocation (hcPkgProgram hpi) args) { progInvokeOutputEncoding = IOEncodingUTF8 } where- args = ["dump", packageDbOpts hcPkg packagedb]- ++ verbosityOpts hcPkg silent+ args = ["dump", packageDbOpts hpi packagedb]+ ++ verbosityOpts hpi silent -- We use verbosity level 'silent' because it is important that we -- do not contaminate the output with info/debug messages. -listInvocation :: ConfiguredProgram- -> Verbosity -> PackageDB -> ProgramInvocation-listInvocation hcPkg _verbosity packagedb =- (programInvocation hcPkg args) {+listInvocation :: HcPkgInfo -> Verbosity -> PackageDB -> ProgramInvocation+listInvocation hpi _verbosity packagedb =+ (programInvocation (hcPkgProgram hpi) args) { progInvokeOutputEncoding = IOEncodingUTF8 } where- args = ["list", "--simple-output", packageDbOpts hcPkg packagedb]- ++ verbosityOpts hcPkg silent+ args = ["list", "--simple-output", packageDbOpts hpi packagedb]+ ++ verbosityOpts hpi silent -- We use verbosity level 'silent' because it is important that we -- do not contaminate the output with info/debug messages. -packageDbStackOpts :: ConfiguredProgram -> PackageDBStack -> [String]-packageDbStackOpts hcPkg dbstack = case dbstack of+packageDbStackOpts :: HcPkgInfo -> PackageDBStack -> [String]+packageDbStackOpts hpi dbstack = case dbstack of (GlobalPackageDB:UserPackageDB:dbs) -> "--global" : "--user" : map specific dbs (GlobalPackageDB:dbs) -> "--global"- : ("--no-user-" ++ packageDbFlag hcPkg)+ : ("--no-user-" ++ packageDbFlag hpi) : map specific dbs _ -> ierror where- specific (SpecificPackageDB db) = "--" ++ packageDbFlag hcPkg ++ "=" ++ db+ specific (SpecificPackageDB db) = "--" ++ packageDbFlag hpi ++ "=" ++ db specific _ = ierror ierror :: a ierror = error ("internal error: unexpected package db stack: " ++ show dbstack) -packageDbFlag :: ConfiguredProgram -> String-packageDbFlag hcPkg- | programVersion hcPkg < Just (Version [7,5] [])+packageDbFlag :: HcPkgInfo -> String+packageDbFlag hpi+ | flagPackageConf hpi = "package-conf" | otherwise = "package-db" -packageDbOpts :: ConfiguredProgram -> PackageDB -> String+packageDbOpts :: HcPkgInfo -> PackageDB -> String packageDbOpts _ GlobalPackageDB = "--global" packageDbOpts _ UserPackageDB = "--user"-packageDbOpts hcPkg (SpecificPackageDB db) = "--" ++ packageDbFlag hcPkg ++ "=" ++ db--verbosityOpts :: ConfiguredProgram -> Verbosity -> [String]-verbosityOpts hcPkg v+packageDbOpts hpi (SpecificPackageDB db) = "--" ++ packageDbFlag hpi ++ "=" ++ db - -- ghc-pkg < 6.11 does not support -v- | programId hcPkg == "ghc-pkg"- && programVersion hcPkg < Just (Version [6,11] [])+verbosityOpts :: HcPkgInfo -> Verbosity -> [String]+verbosityOpts hpi v+ | noVerboseFlag hpi = []- | v >= deafening = ["-v2"] | v == silent = ["-v0"] | otherwise = [] --- Handle quirks in ghc-pkg 6.8 and older-legacyVersion :: ConfiguredProgram -> Bool-legacyVersion hcPkg = programId hcPkg == "ghc-pkg"- && programVersion hcPkg < Just (Version [6,9] [])
Distribution/Simple/Program/Hpc.hs view
@@ -55,7 +55,7 @@ runProgramInvocation verbosity (markupInvocation hpc tixFile hpcDirs' destDir excluded) where- version07 = Version { versionBranch = [0, 7], versionTags = [] }+ version07 = Version [0, 7] [] (passedDirs, droppedDirs) = splitAt 1 hpcDirs markupInvocation :: ConfiguredProgram
Distribution/Simple/Program/Run.hs view
@@ -133,7 +133,7 @@ mcwd menv (Just input) True when (exitCode /= ExitSuccess) $- die errors+ die $ "'" ++ path ++ "' exited with an error:\n" ++ errors where input = case encoding of IOEncodingText -> (inputStr, False)@@ -160,7 +160,7 @@ mcwd menv input utf8 when (exitCode /= ExitSuccess) $- die errors+ die $ "'" ++ path ++ "' exited with an error:\n" ++ errors return (decode output) where input =
Distribution/Simple/Program/Types.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE DeriveGeneric #-}+ ----------------------------------------------------------------------------- -- | -- Module : Distribution.Simple.Program.Types@@ -38,6 +40,10 @@ import Distribution.Verbosity ( Verbosity ) +import Data.Binary (Binary)+import qualified Data.Map as Map+import GHC.Generics (Generic)+ -- | Represents a program which can be configured. -- -- Note: rather than constructing this directly, start with 'simpleProgram' and@@ -96,10 +102,17 @@ -- the current to form the environment for the new process. programOverrideEnv :: [(String, Maybe String)], + -- | A key-value map listing various properties of the program, useful+ -- for feature detection. Populated during the configuration step, key+ -- names depend on the specific program.+ programProperties :: Map.Map String String,+ -- | Location of the program. eg. @\/usr\/bin\/ghc-6.4@ programLocation :: ProgramLocation- } deriving (Read, Show, Eq)+ } deriving (Eq, Generic, Read, Show) +instance Binary ConfiguredProgram+ -- | Where a program was found. Also tells us whether it's specified by user or -- not. This includes not just the path, but the program as well. data ProgramLocation@@ -108,8 +121,10 @@ -- eg. --ghc-path=\/usr\/bin\/ghc-6.6 | FoundOnSystem { locationPath :: FilePath } -- ^The program was found automatically.- deriving (Read, Show, Eq)+ deriving (Eq, Generic, Read, Show) +instance Binary ProgramLocation+ -- | The full path of a configured program. programPath :: ConfiguredProgram -> FilePath programPath = locationPath . programLocation@@ -144,5 +159,6 @@ programDefaultArgs = [], programOverrideArgs = [], programOverrideEnv = [],+ programProperties = Map.empty, programLocation = loc }
Distribution/Simple/Register.hs view
@@ -42,26 +42,28 @@ , LibraryName(..) , InstallDirs(..), absoluteInstallDirs ) import Distribution.Simple.BuildPaths (haddockName)-import qualified Distribution.Simple.GHC as GHC-import qualified Distribution.Simple.LHC as LHC-import qualified Distribution.Simple.Hugs as Hugs-import qualified Distribution.Simple.UHC as UHC++import qualified Distribution.Simple.GHC as GHC+import qualified Distribution.Simple.GHCJS as GHCJS+import qualified Distribution.Simple.LHC as LHC+import qualified Distribution.Simple.UHC as UHC import qualified Distribution.Simple.HaskellSuite as HaskellSuite+ import Distribution.Simple.Compiler ( compilerVersion, Compiler, CompilerFlavor(..), compilerFlavor- , PackageDBStack, registrationPackageDB )+ , PackageDB, PackageDBStack, absolutePackageDBPaths+ , registrationPackageDB ) import Distribution.Simple.Program- ( ProgramConfiguration, ConfiguredProgram- , runProgramInvocation, requireProgram, lookupProgram- , ghcPkgProgram, lhcPkgProgram )+ ( ProgramConfiguration, runProgramInvocation ) import Distribution.Simple.Program.Script ( invocationAsSystemScript )+import Distribution.Simple.Program.HcPkg (HcPkgInfo) import qualified Distribution.Simple.Program.HcPkg as HcPkg import Distribution.Simple.Setup ( RegisterFlags(..), CopyDest(..) , fromFlag, fromFlagOrDefault, flagToMaybe ) import Distribution.PackageDescription- ( PackageDescription(..), Library(..), BuildInfo(..), hcOptions )+ ( PackageDescription(..), Library(..), BuildInfo(..), libModules ) import Distribution.Package ( Package(..), packageName, InstalledPackageId(..) ) import Distribution.InstalledPackageInfo@@ -70,7 +72,7 @@ import qualified Distribution.InstalledPackageInfo as IPI import Distribution.Simple.Utils ( writeUTF8File, writeFileAtomic, setFileExecutable- , die, notice, setupMessage )+ , die, notice, setupMessage, shortRelativePath ) import Distribution.System ( OS(..), buildOS ) import Distribution.Text@@ -78,13 +80,12 @@ import Distribution.Version ( Version(..) ) import Distribution.Verbosity as Verbosity ( Verbosity, normal )-import Distribution.Compat.Exception- ( tryIO ) import System.FilePath ((</>), (<.>), isAbsolute) import System.Directory- ( getCurrentDirectory, removeDirectoryRecursive )+ ( getCurrentDirectory ) +import Control.Monad (when) import Data.Maybe ( isJust, fromMaybe, maybeToList ) import Data.List@@ -100,9 +101,15 @@ register pkg@PackageDescription { library = Just lib } lbi regFlags = do let clbi = getComponentLocalBuildInfo lbi CLibName++ absPackageDBs <- absolutePackageDBPaths packageDbs installedPkgInfo <- generateRegistrationInfo- verbosity pkg lib lbi clbi inplace distPref+ verbosity pkg lib lbi clbi inplace reloc distPref+ (registrationPackageDB absPackageDBs) + when (fromFlag (regPrintId regFlags)) $ do+ putStrLn (display (IPI.installedPackageId installedPkgInfo))+ -- Three different modes: case () of _ | modeGenerateRegFile -> writeRegistrationFile installedPkgInfo@@ -118,6 +125,7 @@ modeGenerateRegScript = fromFlag (regGenScript regFlags) inplace = fromFlag (regInPlace regFlags)+ reloc = relocatable lbi -- FIXME: there's really no guarantee this will work. -- registering into a totally different db stack can -- fail if dependencies cannot be satisfied.@@ -132,15 +140,12 @@ writeRegisterScript installedPkgInfo = case compilerFlavor (compiler lbi) of- GHC -> do (ghcPkg, _) <- requireProgram verbosity ghcPkgProgram (withPrograms lbi)- writeHcPkgRegisterScript verbosity installedPkgInfo ghcPkg packageDbs- LHC -> do (lhcPkg, _) <- requireProgram verbosity lhcPkgProgram (withPrograms lbi)- writeHcPkgRegisterScript verbosity installedPkgInfo lhcPkg packageDbs- Hugs -> notice verbosity "Registration scripts not needed for hugs"- JHC -> notice verbosity "Registration scripts not needed for jhc"- NHC -> notice verbosity "Registration scripts not needed for nhc98"- UHC -> notice verbosity "Registration scripts not needed for uhc"- _ -> die "Registration scripts are not implemented for this compiler"+ JHC -> notice verbosity "Registration scripts not needed for jhc"+ UHC -> notice verbosity "Registration scripts not needed for uhc"+ _ -> withHcPkg+ "Registration scripts are not implemented for this compiler"+ (compiler lbi) (withPrograms lbi)+ (writeHcPkgRegisterScript verbosity installedPkgInfo packageDbs) register _ _ regFlags = notice verbosity "No package to register" where@@ -153,9 +158,11 @@ -> LocalBuildInfo -> ComponentLocalBuildInfo -> Bool+ -> Bool -> FilePath+ -> PackageDB -> IO InstalledPackageInfo-generateRegistrationInfo verbosity pkg lib lbi clbi inplace distPref = do+generateRegistrationInfo verbosity pkg lib lbi clbi inplace reloc distPref packageDb = do --TODO: eliminate pwd! pwd <- getCurrentDirectory @@ -167,38 +174,69 @@ GHC | compilerVersion comp >= Version [6,11] [] -> do s <- GHC.libAbiHash verbosity pkg lbi lib clbi return (InstalledPackageId (display (packageId pkg) ++ '-':s))+ GHCJS -> do+ s <- GHCJS.libAbiHash verbosity pkg lbi lib clbi+ return (InstalledPackageId (display (packageId pkg) ++ '-':s)) _other -> do return (InstalledPackageId (display (packageId pkg))) - let installedPkgInfo- | inplace = inplaceInstalledPackageInfo pwd distPref- pkg lib lbi clbi- | otherwise = absoluteInstalledPackageInfo- pkg lib lbi clbi+ installedPkgInfo <-+ if inplace+ then return (inplaceInstalledPackageInfo pwd distPref+ pkg ipid lib lbi clbi)+ else if reloc+ then relocRegistrationInfo verbosity+ pkg lib lbi clbi ipid packageDb+ else return (absoluteInstalledPackageInfo+ pkg ipid lib lbi clbi) + return installedPkgInfo{ IPI.installedPackageId = ipid } +relocRegistrationInfo :: Verbosity+ -> PackageDescription+ -> Library+ -> LocalBuildInfo+ -> ComponentLocalBuildInfo+ -> InstalledPackageId+ -> PackageDB+ -> IO InstalledPackageInfo+relocRegistrationInfo verbosity pkg lib lbi clbi ipid packageDb =+ case (compilerFlavor (compiler lbi)) of+ GHC -> do fs <- GHC.pkgRoot verbosity lbi packageDb+ return (relocatableInstalledPackageInfo+ pkg ipid lib lbi clbi fs)+ _ -> die "Distribution.Simple.Register.relocRegistrationInfo: \+ \not implemented for this compiler" -- | Create an empty package DB at the specified location. initPackageDB :: Verbosity -> Compiler -> ProgramConfiguration -> FilePath -> IO () initPackageDB verbosity comp conf dbPath =- case (compilerFlavor comp) of- GHC -> GHC.initPackageDB verbosity conf dbPath+ case compilerFlavor comp of HaskellSuite {} -> HaskellSuite.initPackageDB verbosity conf dbPath- _ -> die "Distribution.Simple.Register.initPackageDB: \- \not implemented for this compiler"+ _ -> withHcPkg "Distribution.Simple.Register.initPackageDB: \+ \not implemented for this compiler" comp conf+ (\hpi -> HcPkg.init hpi verbosity dbPath) -- | Run @hc-pkg@ using a given package DB stack, directly forwarding the -- provided command-line arguments to it. invokeHcPkg :: Verbosity -> Compiler -> ProgramConfiguration -> PackageDBStack -> [String] -> IO () invokeHcPkg verbosity comp conf dbStack extraArgs =- case (compilerFlavor comp) of- GHC -> GHC.invokeHcPkg verbosity conf dbStack extraArgs- _ -> die "Distribution.Simple.Register.invokeHcPkg: \- \not implemented for this compiler"+ withHcPkg "invokeHcPkg" comp conf+ (\hpi -> HcPkg.invoke hpi verbosity dbStack extraArgs) +withHcPkg :: String -> Compiler -> ProgramConfiguration+ -> (HcPkgInfo -> IO a) -> IO a+withHcPkg name comp conf f =+ case compilerFlavor comp of+ GHC -> f (GHC.hcPkgInfo conf)+ GHCJS -> f (GHCJS.hcPkgInfo conf)+ LHC -> f (LHC.hcPkgInfo conf)+ _ -> die ("Distribution.Simple.Register." ++ name ++ ":\+ \not implemented for this compiler")+ registerPackage :: Verbosity -> InstalledPackageInfo -> PackageDescription@@ -212,26 +250,24 @@ else "Registering" setupMessage verbosity msg (packageId pkg) case compilerFlavor (compiler lbi) of- GHC -> GHC.registerPackage verbosity installedPkgInfo pkg lbi inplace packageDbs- LHC -> LHC.registerPackage verbosity installedPkgInfo pkg lbi inplace packageDbs- Hugs -> Hugs.registerPackage verbosity installedPkgInfo pkg lbi inplace packageDbs- UHC -> UHC.registerPackage verbosity installedPkgInfo pkg lbi inplace packageDbs- JHC -> notice verbosity "Registering for jhc (nothing to do)"- NHC -> notice verbosity "Registering for nhc98 (nothing to do)"+ GHC -> GHC.registerPackage verbosity installedPkgInfo pkg lbi inplace packageDbs+ GHCJS -> GHCJS.registerPackage verbosity installedPkgInfo pkg lbi inplace packageDbs+ LHC -> LHC.registerPackage verbosity installedPkgInfo pkg lbi inplace packageDbs+ UHC -> UHC.registerPackage verbosity installedPkgInfo pkg lbi inplace packageDbs+ JHC -> notice verbosity "Registering for jhc (nothing to do)" HaskellSuite {} -> HaskellSuite.registerPackage verbosity installedPkgInfo pkg lbi inplace packageDbs _ -> die "Registering is not implemented for this compiler" - writeHcPkgRegisterScript :: Verbosity -> InstalledPackageInfo- -> ConfiguredProgram -> PackageDBStack+ -> HcPkgInfo -> IO ()-writeHcPkgRegisterScript verbosity installedPkgInfo hcPkg packageDbs = do- let invocation = HcPkg.reregisterInvocation hcPkg Verbosity.normal+writeHcPkgRegisterScript verbosity installedPkgInfo packageDbs hpi = do+ let invocation = HcPkg.reregisterInvocation hpi Verbosity.normal packageDbs (Right installedPkgInfo)- regScript = invocationAsSystemScript buildOS invocation+ regScript = invocationAsSystemScript buildOS invocation notice verbosity ("Creating package registration script: " ++ regScriptFileName) writeUTF8File regScriptFileName regScript@@ -253,15 +289,17 @@ :: ([FilePath] -> [FilePath]) -- ^ Translate relative include dir paths to -- absolute paths. -> PackageDescription+ -> InstalledPackageId -> Library+ -> LocalBuildInfo -> ComponentLocalBuildInfo -> InstallDirs FilePath -> InstalledPackageInfo-generalInstalledPackageInfo adjustRelIncDirs pkg lib clbi installDirs =+generalInstalledPackageInfo adjustRelIncDirs pkg ipid lib lbi clbi installDirs = InstalledPackageInfo {- --TODO: do not open-code this conversion from PackageId to InstalledPackageId- IPI.installedPackageId = InstalledPackageId (display (packageId pkg)),+ IPI.installedPackageId = ipid, IPI.sourcePackageId = packageId pkg,+ IPI.packageKey = pkgKey lbi, IPI.license = license pkg, IPI.copyright = copyright pkg, IPI.maintainer = maintainer pkg,@@ -273,22 +311,27 @@ IPI.description = description pkg, IPI.category = category pkg, IPI.exposed = libExposed lib,- IPI.exposedModules = exposedModules lib,+ IPI.exposedModules = map fixupSelf (componentExposedModules clbi), IPI.hiddenModules = otherModules bi,+ IPI.instantiatedWith = map (\(k,(p,n)) ->+ (k,IPI.OriginalModule (IPI.installedPackageId p) n))+ (instantiatedWith lbi), IPI.trusted = IPI.trusted IPI.emptyInstalledPackageInfo, IPI.importDirs = [ libdir installDirs | hasModules ],+ -- Note. the libsubdir and datasubdir templates have already been expanded+ -- into libdir and datadir. IPI.libraryDirs = if hasLibrary then libdir installDirs : extraLibDirs bi else extraLibDirs bi,+ IPI.dataDir = datadir installDirs, IPI.hsLibraries = [ libname | LibraryName libname <- componentLibraries clbi , hasLibrary ], IPI.extraLibraries = extraLibs bi,- IPI.extraGHCiLibraries = [],+ IPI.extraGHCiLibraries = extraGHCiLibs bi, IPI.includeDirs = absinc ++ adjustRelIncDirs relinc, IPI.includes = includes bi, IPI.depends = map fst (componentPackageDeps clbi),- IPI.hugsOptions = hcOptions Hugs bi, IPI.ccOptions = [], -- Note. NOT ccOptions bi! -- We don't want cc-options to be propagated -- to C compilations in other packages.@@ -296,15 +339,28 @@ IPI.frameworkDirs = [], IPI.frameworks = frameworks bi, IPI.haddockInterfaces = [haddockdir installDirs </> haddockName pkg],- IPI.haddockHTMLs = [htmldir installDirs]+ IPI.haddockHTMLs = [htmldir installDirs],+ IPI.pkgRoot = Nothing } where bi = libBuildInfo lib (absinc, relinc) = partition isAbsolute (includeDirs bi)- hasModules = not $ null (exposedModules lib)- && null (otherModules bi)+ hasModules = not $ null (libModules lib) hasLibrary = hasModules || not (null (cSources bi))+ || (not (null (jsSources bi)) &&+ compilerFlavor (compiler lbi) == GHCJS) + -- Since we currently don't decide the InstalledPackageId of our package+ -- until just before we register, we didn't have one for the re-exports+ -- of modules defined within this package, so we used an empty one that+ -- we fill in here now that we know what it is. It's a bit of a hack,+ -- we ought really to decide the InstalledPackageId ahead of time.+ fixupSelf (IPI.ExposedModule n o o') =+ IPI.ExposedModule n (fmap fixupOriginalModule o)+ (fmap fixupOriginalModule o')+ fixupOriginalModule (IPI.OriginalModule i m) = IPI.OriginalModule (fixupIpid i) m+ fixupIpid (InstalledPackageId []) = ipid+ fixupIpid x = x -- | Construct 'InstalledPackageInfo' for a library that is in place in the -- build tree.@@ -314,20 +370,20 @@ inplaceInstalledPackageInfo :: FilePath -- ^ top of the build tree -> FilePath -- ^ location of the dist tree -> PackageDescription+ -> InstalledPackageId -> Library -> LocalBuildInfo -> ComponentLocalBuildInfo -> InstalledPackageInfo-inplaceInstalledPackageInfo inplaceDir distPref pkg lib lbi clbi =- generalInstalledPackageInfo adjustRelativeIncludeDirs pkg lib clbi- installDirs+inplaceInstalledPackageInfo inplaceDir distPref pkg ipid lib lbi clbi =+ generalInstalledPackageInfo adjustRelativeIncludeDirs+ pkg ipid lib lbi clbi installDirs where adjustRelativeIncludeDirs = map (inplaceDir </>) installDirs = (absoluteInstallDirs pkg lbi NoCopyDest) { libdir = inplaceDir </> buildDir lbi,- datadir = inplaceDir,- datasubdir = distPref,+ datadir = inplaceDir </> dataDir pkg, docdir = inplaceDocdir, htmldir = inplaceHtmldir, haddockdir = inplaceHtmldir@@ -342,12 +398,14 @@ -- This function knows about the layout of installed packages. -- absoluteInstalledPackageInfo :: PackageDescription+ -> InstalledPackageId -> Library -> LocalBuildInfo -> ComponentLocalBuildInfo -> InstalledPackageInfo-absoluteInstalledPackageInfo pkg lib lbi clbi =- generalInstalledPackageInfo adjustReativeIncludeDirs pkg lib clbi installDirs+absoluteInstalledPackageInfo pkg ipid lib lbi clbi =+ generalInstalledPackageInfo adjustReativeIncludeDirs+ pkg ipid lib lbi clbi installDirs where -- For installed packages we install all include files into one dir, -- whereas in the build tree they may live in multiple local dirs.@@ -357,6 +415,28 @@ bi = libBuildInfo lib installDirs = absoluteInstallDirs pkg lbi NoCopyDest ++relocatableInstalledPackageInfo :: PackageDescription+ -> InstalledPackageId+ -> Library+ -> LocalBuildInfo+ -> ComponentLocalBuildInfo+ -> FilePath+ -> InstalledPackageInfo+relocatableInstalledPackageInfo pkg ipid lib lbi clbi pkgroot =+ generalInstalledPackageInfo adjustReativeIncludeDirs+ pkg ipid lib lbi clbi installDirs+ where+ -- For installed packages we install all include files into one dir,+ -- whereas in the build tree they may live in multiple local dirs.+ adjustReativeIncludeDirs _+ | null (installIncludes bi) = []+ | otherwise = [includedir installDirs]+ bi = libBuildInfo lib++ installDirs = fmap (("${pkgroot}" </>) . shortRelativePath pkgroot)+ $ absoluteInstallDirs pkg lbi NoCopyDest+ -- ----------------------------------------------------------------------------- -- Unregistration @@ -367,25 +447,16 @@ verbosity = fromFlag (regVerbosity regFlags) packageDb = fromFlagOrDefault (registrationPackageDB (withPackageDB lbi)) (regPackageDB regFlags)- installDirs = absoluteInstallDirs pkg lbi NoCopyDest+ unreg hpi =+ let invocation = HcPkg.unregisterInvocation+ hpi Verbosity.normal packageDb pkgid+ in if genScript+ then writeFileAtomic unregScriptFileName+ (BS.Char8.pack $ invocationAsSystemScript buildOS invocation)+ else runProgramInvocation verbosity invocation setupMessage verbosity "Unregistering" pkgid- case compilerFlavor (compiler lbi) of- GHC ->- let Just ghcPkg = lookupProgram ghcPkgProgram (withPrograms lbi)- invocation = HcPkg.unregisterInvocation ghcPkg Verbosity.normal- packageDb pkgid- in if genScript- then writeFileAtomic unregScriptFileName- (BS.Char8.pack $ invocationAsSystemScript buildOS invocation)- else runProgramInvocation verbosity invocation- Hugs -> do- _ <- tryIO $ removeDirectoryRecursive (libdir installDirs)- return ()- NHC -> do- _ <- tryIO $ removeDirectoryRecursive (libdir installDirs)- return ()- _ ->- die ("only unregistering with GHC and Hugs is implemented")+ withHcPkg "unregistering is only implemented for GHC and GHCJS"+ (compiler lbi) (withPrograms lbi) unreg unregScriptFileName :: FilePath unregScriptFileName = case buildOS of
Distribution/Simple/Setup.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE DeriveGeneric #-}+ ----------------------------------------------------------------------------- -- | -- Module : Distribution.Simple.Setup@@ -70,6 +72,7 @@ ( Text(..), display ) import qualified Distribution.Compat.ReadP as Parse import qualified Text.PrettyPrint as Disp+import Distribution.ModuleName import Distribution.Package ( Dependency(..) , PackageName , InstalledPackageId )@@ -79,10 +82,11 @@ import qualified Distribution.Simple.Command as Command import Distribution.Simple.Compiler ( CompilerFlavor(..), defaultCompilerFlavor, PackageDB(..)+ , DebugInfoLevel(..), flagToDebugInfoLevel , OptimisationLevel(..), flagToOptimisationLevel , absolutePackageDBPath ) import Distribution.Simple.Utils- ( wrapLine, lowercase, intercalate )+ ( wrapText, wrapLine, lowercase, intercalate ) import Distribution.Simple.Program (Program(..), ProgramConfiguration, requireProgram, programInvocation, progInvokePath, progInvokeArgs,@@ -93,11 +97,14 @@ ( InstallDirs(..), CopyDest(..), PathTemplate, toPathTemplate, fromPathTemplate ) import Distribution.Verbosity+import Distribution.Utils.NubList import Control.Monad (liftM)+import Data.Binary (Binary) import Data.List ( sort ) import Data.Char ( isSpace, isAlpha ) import Data.Monoid ( Monoid(..) )+import GHC.Generics (Generic) -- FIXME Not sure where this should live defaultDistPref :: FilePath@@ -124,8 +131,10 @@ -- Its monoid instance gives us the behaviour where it starts out as -- 'NoFlag' and later flags override earlier ones. ---data Flag a = Flag a | NoFlag deriving (Show, Read, Eq)+data Flag a = Flag a | NoFlag deriving (Eq, Generic, Show, Read) +instance Binary a => Binary (Flag a)+ instance Functor Flag where fmap f (Flag x) = Flag (f x) fmap _ NoFlag = NoFlag@@ -197,21 +206,34 @@ globalNumericVersion = Flag False } -globalCommand :: CommandUI GlobalFlags-globalCommand = CommandUI {- commandName = "",- commandSynopsis = "",- commandUsage = \_ ->+globalCommand :: [Command action] -> CommandUI GlobalFlags+globalCommand commands = CommandUI+ { commandName = ""+ , commandSynopsis = ""+ , commandUsage = \pname -> "This Setup program uses the Haskell Cabal Infrastructure.\n"- ++ "See http://www.haskell.org/cabal/ for more information.\n",- commandDescription = Just $ \pname ->- "For more information about a command use\n"+ ++ "See http://www.haskell.org/cabal/ for more information.\n"+ ++ "\n"+ ++ "Usage: " ++ pname ++ " [GLOBAL FLAGS] [COMMAND [FLAGS]]\n"+ , commandDescription = Just $ \pname ->+ let+ commands' = commands ++ [commandAddAction helpCommandUI undefined]+ cmdDescs = getNormalCommandDescriptions commands'+ maxlen = maximum $ [length name | (name, _) <- cmdDescs]+ align str = str ++ replicate (maxlen - length str) ' '+ in+ "Commands:\n"+ ++ unlines [ " " ++ align name ++ " " ++ description+ | (name, description) <- cmdDescs ]+ ++ "\n"+ ++ "For more information about a command use\n" ++ " " ++ pname ++ " COMMAND --help\n\n" ++ "Typical steps for installing Cabal packages:\n" ++ concat [ " " ++ pname ++ " " ++ x ++ "\n"- | x <- ["configure", "build", "install"]],- commandDefaultFlags = defaultGlobalFlags,- commandOptions = \_ ->+ | x <- ["configure", "build", "install"]]+ , commandNotes = Nothing+ , commandDefaultFlags = defaultGlobalFlags+ , commandOptions = \_ -> [option ['V'] ["version"] "Print version information" globalVersion (\v flags -> flags { globalVersion = v })@@ -252,10 +274,10 @@ configProgramPaths :: [(String, FilePath)], -- ^user specified programs paths configProgramArgs :: [(String, [String])], -- ^user specified programs args- configProgramPathExtra :: [FilePath], -- ^Extend the $PATH+ configProgramPathExtra :: NubList FilePath, -- ^Extend the $PATH configHcFlavor :: Flag CompilerFlavor, -- ^The \"flavor\" of the -- compiler, such as GHC or- -- Hugs.+ -- JHC. configHcPath :: Flag FilePath, -- ^given compiler location configHcPkg :: Flag FilePath, -- ^given hc-pkg location configVanillaLib :: Flag Bool, -- ^Enable vanilla library@@ -286,18 +308,25 @@ configConstraints :: [Dependency], -- ^Additional constraints for -- dependencies. configDependencies :: [(PackageName, InstalledPackageId)],+ configInstantiateWith :: [(ModuleName, (InstalledPackageId, ModuleName))], -- ^The packages depended on. configConfigurationsFlags :: FlagAssignment, configTests :: Flag Bool, -- ^Enable test suite compilation configBenchmarks :: Flag Bool, -- ^Enable benchmark compilation- configLibCoverage :: Flag Bool,- -- ^Enable test suite program coverage.- configExactConfiguration :: Flag Bool+ configCoverage :: Flag Bool, -- ^Enable program coverage+ configLibCoverage :: Flag Bool, -- ^OBSOLETE. Just used to signal error.+ configExactConfiguration :: Flag Bool, -- ^All direct dependencies and flags are provided on the command line by -- the user via the '--dependency' and '--flags' options.+ configFlagError :: Flag String,+ -- ^Halt and show an error message indicating an error in flag assignment+ configRelocatable :: Flag Bool, -- ^ Enable relocatable package built+ configDebugInfo :: Flag DebugInfoLevel -- ^ Emit debug info. }- deriving (Read,Show)+ deriving (Generic, Read, Show) +instance Binary ConfigFlags+ configAbsolutePaths :: ConfigFlags -> IO ConfigFlags configAbsolutePaths f = (\v -> f { configPackageDBs = v })@@ -309,10 +338,10 @@ configPrograms = progConf, configHcFlavor = maybe NoFlag Flag defaultCompilerFlavor, configVanillaLib = Flag True,- configProfLib = Flag False,+ configProfLib = NoFlag, configSharedLib = NoFlag, configDynExe = Flag False,- configProfExe = Flag False,+ configProfExe = NoFlag, configOptimization = Flag NormalOptimisation, configProgPrefix = Flag (toPathTemplate ""), configProgSuffix = Flag (toPathTemplate ""),@@ -323,26 +352,36 @@ -- See #1589. configGHCiLib = Flag True, #else- configGHCiLib = Flag False,+ configGHCiLib = NoFlag, #endif configSplitObjs = Flag False, -- takes longer, so turn off by default configStripExes = Flag True, configStripLibs = Flag True, configTests = Flag False, configBenchmarks = Flag False,- configLibCoverage = Flag False,- configExactConfiguration = Flag False+ configCoverage = Flag False,+ configLibCoverage = NoFlag,+ configExactConfiguration = Flag False,+ configFlagError = NoFlag,+ configRelocatable = Flag False,+ configDebugInfo = Flag NoDebugInfo } configureCommand :: ProgramConfiguration -> CommandUI ConfigFlags-configureCommand progConf = makeCommand name shortDesc- longDesc defaultFlags options- where- name = "configure"- shortDesc = "Prepare to build the package."- longDesc = Just (\_ -> programFlagsDescription progConf)- defaultFlags = defaultConfigFlags progConf- options showOrParseArgs =+configureCommand progConf = CommandUI+ { commandName = "configure"+ , commandSynopsis = "Prepare to build the package."+ , commandDescription = Just $ \_ -> wrapText $+ "Configure how the package is built by setting "+ ++ "package (and other) flags.\n"+ ++ "\n"+ ++ "The configuration affects several other commands, "+ ++ "including build, test, bench, run, repl.\n"+ , commandNotes = Just (\_ -> programFlagsDescription progConf)+ , commandUsage = \pname ->+ "Usage: " ++ pname ++ " configure [FLAGS]\n"+ , commandDefaultFlags = defaultConfigFlags progConf+ , commandOptions = \showOrParseArgs -> configureOptions showOrParseArgs ++ programConfigurationPaths progConf showOrParseArgs configProgramPaths (\v fs -> fs { configProgramPaths = v })@@ -350,6 +389,7 @@ configProgramArgs (\v fs -> fs { configProgramArgs = v }) ++ programConfigurationOptions progConf showOrParseArgs configProgramArgs (\v fs -> fs { configProgramArgs = v })+ } configureOptions :: ShowOrParseArgs -> [OptionField ConfigFlags] configureOptions showOrParseArgs =@@ -361,13 +401,11 @@ ,option [] ["compiler"] "compiler" configHcFlavor (\v flags -> flags { configHcFlavor = v })- (choiceOpt [ (Flag GHC, ("g", ["ghc"]), "compile with GHC")- , (Flag NHC, ([] , ["nhc98"]), "compile with NHC")- , (Flag JHC, ([] , ["jhc"]), "compile with JHC")- , (Flag LHC, ([] , ["lhc"]), "compile with LHC")- , (Flag Hugs,([] , ["hugs"]), "compile with Hugs")- , (Flag UHC, ([] , ["uhc"]), "compile with UHC")-+ (choiceOpt [ (Flag GHC, ("g", ["ghc"]), "compile with GHC")+ , (Flag GHCJS, ([] , ["ghcjs"]), "compile with GHCJS")+ , (Flag JHC, ([] , ["jhc"]), "compile with JHC")+ , (Flag LHC, ([] , ["lhc"]), "compile with LHC")+ , (Flag UHC, ([] , ["uhc"]), "compile with UHC") -- "haskell-suite" compiler id string will be replaced -- by a more specific one during the configure stage , (Flag (HaskellSuite "haskell-suite"), ([] , ["haskell-suite"]),@@ -384,13 +422,7 @@ (reqArgFlag "PATH") ] ++ map liftInstallDirs installDirsOptions- ++ [option "b" ["scratchdir"]- "directory to receive the built package (hugs-only)"- configScratchDir (\v flags -> flags { configScratchDir = v })- (reqArgFlag "DIR")- --TODO: eliminate scratchdir flag-- ,option "" ["program-prefix"]+ ++ [option "" ["program-prefix"] "prefix to be applied to installed executables" configProgPrefix (\v flags -> flags { configProgPrefix = v })@@ -421,8 +453,8 @@ configDynExe (\v flags -> flags { configDynExe = v }) (boolOpt [] []) - ,option "" ["executable-profiling"]- "Executable profiling"+ ,option "" ["profiling", "executable-profiling"]+ "Executable profiling (requires library profiling)" configProfExe (\v flags -> flags { configProfExe = v }) (boolOpt [] []) @@ -441,6 +473,22 @@ "Build without optimization" ] + ,multiOption "debug-info"+ configDebugInfo (\v flags -> flags { configDebugInfo = v })+ [optArg' "n" (Flag . flagToDebugInfoLevel)+ (\f -> case f of+ Flag NoDebugInfo -> []+ Flag MinimalDebugInfo -> [Just "1"]+ Flag NormalDebugInfo -> [Nothing]+ Flag MaximalDebugInfo -> [Just "3"]+ _ -> [])+ "" ["enable-debug-info"]+ "Emit debug info (n is 0--3, default is 0)",+ noArg (Flag NoDebugInfo) []+ ["disable-debug-info"]+ "Don't emit debug info"+ ]+ ,option "" ["library-for-ghci"] "compile library for use with GHCi" configGHCiLib (\v flags -> flags { configGHCiLib = v })@@ -494,7 +542,7 @@ ,option "" ["extra-prog-path"] "A list of directories to search for required programs (in addition to the normal search locations)" configProgramPathExtra (\v flags -> flags {configProgramPathExtra = v})- (reqArg' "PATH" (\x -> [x]) id)+ (reqArg' "PATH" (\x -> toNubList [x]) fromNubList) ,option "" ["constraint"] "A list of additional constraints on the dependencies."@@ -510,16 +558,28 @@ (readP_to_E (const "dependency expected") ((\x -> [x]) `fmap` parseDependency)) (map (\x -> display (fst x) ++ "=" ++ display (snd x)))) + ,option "" ["instantiate-with"]+ "A mapping of signature names to concrete module instantiations. E.g., --instantiate-with=\"Map=Data.Map.Strict@containers-0.5.5.1-inplace\""+ configInstantiateWith (\v flags -> flags { configInstantiateWith = v })+ (reqArg "NAME=PKG:MOD"+ (readP_to_E (const "signature mapping expected") ((\x -> [x]) `fmap` parseHoleMapEntry))+ (map (\(n,(p,m)) -> display n ++ "=" ++ display m ++ "@" ++ display p)))+ ,option "" ["tests"] "dependency checking and compilation for test suites listed in the package description file." configTests (\v flags -> flags { configTests = v }) (boolOpt [] []) ,option "" ["library-coverage"]- "build library and test suites with Haskell Program Coverage enabled. (GHC only)"+ "OBSOLETE. Please use --enable-coverage instead." configLibCoverage (\v flags -> flags { configLibCoverage = v }) (boolOpt [] []) + ,option "" ["coverage"]+ "build package with Haskell Program Coverage enabled. (GHC only)"+ configCoverage (\v flags -> flags { configCoverage = v })+ (boolOpt [] [])+ ,option "" ["exact-configuration"] "All direct dependencies and flags are provided on the command line." configExactConfiguration@@ -530,6 +590,11 @@ "dependency checking and compilation for benchmarks listed in the package description file." configBenchmarks (\v flags -> flags { configBenchmarks = v }) (boolOpt [] [])++ ,option "" ["relocatable"]+ "building a package that is relocatable. (GHC only)"+ configRelocatable (\v flags -> flags { configRelocatable = v})+ (boolOpt [] []) ] where readFlagList :: String -> FlagAssignment@@ -570,6 +635,15 @@ y <- parse return (x, y) +parseHoleMapEntry :: Parse.ReadP r (ModuleName, (InstalledPackageId, ModuleName))+parseHoleMapEntry = do+ x <- parse+ _ <- Parse.char '='+ y <- parse+ _ <- Parse.char '@'+ z <- parse+ return (x, (z, y))+ installDirsOptions :: [OptionField (InstallDirs (Flag PathTemplate))] installDirsOptions = [ option "" ["prefix"]@@ -666,12 +740,17 @@ configExtraLibDirs = mempty, configConstraints = mempty, configDependencies = mempty,+ configInstantiateWith = mempty, configExtraIncludeDirs = mempty, configConfigurationsFlags = mempty, configTests = mempty,- configLibCoverage = mempty,+ configCoverage = mempty,+ configLibCoverage = mempty, configExactConfiguration = mempty,- configBenchmarks = mempty+ configBenchmarks = mempty,+ configFlagError = mempty,+ configRelocatable = mempty,+ configDebugInfo = mempty } mappend a b = ConfigFlags { configPrograms = configPrograms b,@@ -703,12 +782,17 @@ configExtraLibDirs = combine configExtraLibDirs, configConstraints = combine configConstraints, configDependencies = combine configDependencies,+ configInstantiateWith = combine configInstantiateWith, configExtraIncludeDirs = combine configExtraIncludeDirs, configConfigurationsFlags = combine configConfigurationsFlags, configTests = combine configTests,+ configCoverage = combine configCoverage, configLibCoverage = combine configLibCoverage, configExactConfiguration = combine configExactConfiguration,- configBenchmarks = combine configBenchmarks+ configBenchmarks = combine configBenchmarks,+ configFlagError = combine configFlagError,+ configRelocatable = combine configRelocatable,+ configDebugInfo = combine configDebugInfo } where combine field = field a `mappend` field b @@ -732,14 +816,17 @@ } copyCommand :: CommandUI CopyFlags-copyCommand = makeCommand name shortDesc longDesc defaultCopyFlags options- where- name = "copy"- shortDesc = "Copy the files into the install locations."- longDesc = Just $ \_ ->- "Does not call register, and allows a prefix at install time\n"+copyCommand = CommandUI+ { commandName = "copy"+ , commandSynopsis = "Copy the files into the install locations."+ , commandDescription = Just $ \_ -> wrapText $+ "Does not call register, and allows a prefix at install time. " ++ "Without the --destdir flag, configure determines location.\n"- options showOrParseArgs =+ , commandNotes = Nothing+ , commandUsage = \pname ->+ "Usage: " ++ pname ++ " copy [FLAGS]\n"+ , commandDefaultFlags = defaultCopyFlags+ , commandOptions = \showOrParseArgs -> [optionVerbosity copyVerbosity (\v flags -> flags { copyVerbosity = v }) ,optionDistPref@@ -752,6 +839,7 @@ (reqArg "DIR" (succeedReadE (Flag . CopyTo)) (\f -> case f of Flag (CopyTo p) -> [p]; _ -> [])) ]+ } emptyCopyFlags :: CopyFlags emptyCopyFlags = mempty@@ -793,15 +881,19 @@ } installCommand :: CommandUI InstallFlags-installCommand = makeCommand name shortDesc longDesc defaultInstallFlags options- where- name = "install"- shortDesc = "Copy the files into the install locations. Run register."- longDesc = Just $ \_ ->- "Unlike the copy command, install calls the register command.\n"- ++ "If you want to install into a location that is not what was\n"+installCommand = CommandUI+ { commandName = "install"+ , commandSynopsis =+ "Copy the files into the install locations. Run register."+ , commandDescription = Just $ \_ -> wrapText $+ "Unlike the copy command, install calls the register command."+ ++ "If you want to install into a location that is not what was" ++ "specified in the configure step, use the copy command.\n"- options showOrParseArgs =+ , commandNotes = Nothing+ , commandUsage = \pname ->+ "Usage: " ++ pname ++ " install [FLAGS]\n"+ , commandDefaultFlags = defaultInstallFlags+ , commandOptions = \showOrParseArgs -> [optionVerbosity installVerbosity (\v flags -> flags { installVerbosity = v }) ,optionDistPref installDistPref (\d flags -> flags { installDistPref = d })@@ -824,6 +916,7 @@ , (Flag GlobalPackageDB, ([],["global"]), "(default) upon configuration register this package in the system-wide package database")]) ]+ } emptyInstallFlags :: InstallFlags emptyInstallFlags = mempty@@ -869,18 +962,22 @@ } sdistCommand :: CommandUI SDistFlags-sdistCommand = makeCommand name shortDesc longDesc defaultSDistFlags options- where- name = "sdist"- shortDesc = "Generate a source distribution file (.tar.gz)."- longDesc = Nothing- options showOrParseArgs =+sdistCommand = CommandUI+ { commandName = "sdist"+ , commandSynopsis =+ "Generate a source distribution file (.tar.gz)."+ , commandDescription = Nothing+ , commandNotes = Nothing+ , commandUsage = \pname ->+ "Usage: " ++ pname ++ " sdist [FLAGS]\n"+ , commandDefaultFlags = defaultSDistFlags+ , commandOptions = \showOrParseArgs -> [optionVerbosity sDistVerbosity (\v flags -> flags { sDistVerbosity = v }) ,optionDistPref sDistDistPref (\d flags -> flags { sDistDistPref = d }) showOrParseArgs - ,option "" ["list-sources"]+ ,option "" ["list-sources"] "Just write a list of the package's sources to a file" sDistListSources (\v flags -> flags { sDistListSources = v }) (reqArgFlag "FILE")@@ -896,6 +993,7 @@ sDistDirectory (\v flags -> flags { sDistDirectory = v }) (reqArgFlag "DIR") ]+ } emptySDistFlags :: SDistFlags emptySDistFlags = mempty@@ -929,6 +1027,7 @@ regGenPkgConf :: Flag (Maybe FilePath), regInPlace :: Flag Bool, regDistPref :: Flag FilePath,+ regPrintId :: Flag Bool, regVerbosity :: Flag Verbosity } deriving Show@@ -940,17 +1039,21 @@ regGenPkgConf = NoFlag, regInPlace = Flag False, regDistPref = Flag defaultDistPref,+ regPrintId = Flag False, regVerbosity = Flag normal } registerCommand :: CommandUI RegisterFlags-registerCommand = makeCommand name shortDesc longDesc- defaultRegisterFlags options- where- name = "register"- shortDesc = "Register this package with the compiler."- longDesc = Nothing- options showOrParseArgs =+registerCommand = CommandUI+ { commandName = "register"+ , commandSynopsis =+ "Register this package with the compiler."+ , commandDescription = Nothing+ , commandNotes = Nothing+ , commandUsage = \pname ->+ "Usage: " ++ pname ++ " register [FLAGS]\n"+ , commandDefaultFlags = defaultRegisterFlags+ , commandOptions = \showOrParseArgs -> [optionVerbosity regVerbosity (\v flags -> flags { regVerbosity = v }) ,optionDistPref regDistPref (\d flags -> flags { regDistPref = d })@@ -977,16 +1080,25 @@ "instead of registering, generate a package registration file" regGenPkgConf (\v flags -> flags { regGenPkgConf = v }) (optArg' "PKG" Flag flagToList)++ ,option "" ["print-ipid"]+ "print the installed package ID calculated for this package"+ regPrintId (\v flags -> flags { regPrintId = v })+ trueArg ]+ } unregisterCommand :: CommandUI RegisterFlags-unregisterCommand = makeCommand name shortDesc- longDesc defaultRegisterFlags options- where- name = "unregister"- shortDesc = "Unregister this package with the compiler."- longDesc = Nothing- options showOrParseArgs =+unregisterCommand = CommandUI+ { commandName = "unregister"+ , commandSynopsis =+ "Unregister this package with the compiler."+ , commandDescription = Nothing+ , commandNotes = Nothing+ , commandUsage = \pname ->+ "Usage: " ++ pname ++ " unregister [FLAGS]\n"+ , commandDefaultFlags = defaultRegisterFlags+ , commandOptions = \showOrParseArgs -> [optionVerbosity regVerbosity (\v flags -> flags { regVerbosity = v }) ,optionDistPref regDistPref (\d flags -> flags { regDistPref = d })@@ -1004,6 +1116,7 @@ regGenScript (\v flags -> flags { regGenScript = v }) trueArg ]+ } emptyRegisterFlags :: RegisterFlags emptyRegisterFlags = mempty@@ -1014,6 +1127,7 @@ regGenScript = mempty, regGenPkgConf = mempty, regInPlace = mempty,+ regPrintId = mempty, regDistPref = mempty, regVerbosity = mempty }@@ -1022,6 +1136,7 @@ regGenScript = combine regGenScript, regGenPkgConf = combine regGenPkgConf, regInPlace = combine regInPlace,+ regPrintId = combine regPrintId, regDistPref = combine regDistPref, regVerbosity = combine regVerbosity }@@ -1074,13 +1189,16 @@ where combine field = field a `mappend` field b hscolourCommand :: CommandUI HscolourFlags-hscolourCommand = makeCommand name shortDesc longDesc- defaultHscolourFlags options- where- name = "hscolour"- shortDesc = "Generate HsColour colourised code, in HTML format."- longDesc = Just (\_ -> "Requires hscolour.\n")- options showOrParseArgs =+hscolourCommand = CommandUI+ { commandName = "hscolour"+ , commandSynopsis =+ "Generate HsColour colourised code, in HTML format."+ , commandDescription = Just (\_ -> "Requires the hscolour program.\n")+ , commandNotes = Nothing+ , commandUsage = \pname ->+ "Usage: " ++ pname ++ " hscolour [FLAGS]\n"+ , commandDefaultFlags = defaultHscolourFlags+ , commandOptions = \showOrParseArgs -> [optionVerbosity hscolourVerbosity (\v flags -> flags { hscolourVerbosity = v }) ,optionDistPref@@ -1117,6 +1235,7 @@ hscolourCSS (\v flags -> flags { hscolourCSS = v }) (reqArgFlag "PATH") ]+ } -- ------------------------------------------------------------ -- * Haddock flags@@ -1163,18 +1282,25 @@ } haddockCommand :: CommandUI HaddockFlags-haddockCommand = makeCommand name shortDesc longDesc defaultHaddockFlags options- where- name = "haddock"- shortDesc = "Generate Haddock HTML documentation."- longDesc = Just $ \_ -> "Requires the program haddock, version 2.x.\n"- options showOrParseArgs = haddockOptions showOrParseArgs+haddockCommand = CommandUI+ { commandName = "haddock"+ , commandSynopsis = "Generate Haddock HTML documentation."+ , commandDescription = Just $ \_ ->+ "Requires the program haddock, version 2.x.\n"+ , commandNotes = Nothing+ , commandUsage = \pname ->+ "Usage: " ++ pname ++ " haddock [FLAGS]\n"+ , commandDefaultFlags = defaultHaddockFlags+ , commandOptions = \showOrParseArgs ->+ haddockOptions showOrParseArgs ++ programConfigurationPaths progConf ParseArgs haddockProgramPaths (\v flags -> flags { haddockProgramPaths = v}) ++ programConfigurationOption progConf showOrParseArgs haddockProgramArgs (\v fs -> fs { haddockProgramArgs = v }) ++ programConfigurationOptions progConf ParseArgs haddockProgramArgs (\v flags -> flags { haddockProgramArgs = v})+ }+ where progConf = addKnownProgram haddockProgram $ addKnownProgram ghcProgram $ emptyProgramConfiguration@@ -1321,12 +1447,16 @@ } cleanCommand :: CommandUI CleanFlags-cleanCommand = makeCommand name shortDesc longDesc defaultCleanFlags options- where- name = "clean"- shortDesc = "Clean up after a build."- longDesc = Just (\_ -> "Removes .hi, .o, preprocessed sources, etc.\n")- options showOrParseArgs =+cleanCommand = CommandUI+ { commandName = "clean"+ , commandSynopsis = "Clean up after a build."+ , commandDescription = Just $ \_ ->+ "Removes .hi, .o, preprocessed sources, etc.\n"+ , commandNotes = Nothing+ , commandUsage = \pname ->+ "Usage: " ++ pname ++ " clean [FLAGS]\n"+ , commandDefaultFlags = defaultCleanFlags+ , commandOptions = \showOrParseArgs -> [optionVerbosity cleanVerbosity (\v flags -> flags { cleanVerbosity = v }) ,optionDistPref cleanDistPref (\d flags -> flags { cleanDistPref = d })@@ -1337,6 +1467,7 @@ cleanSaveConf (\v flags -> flags { cleanSaveConf = v }) trueArg ]+ } emptyCleanFlags :: CleanFlags emptyCleanFlags = mempty@@ -1385,21 +1516,14 @@ } buildCommand :: ProgramConfiguration -> CommandUI BuildFlags-buildCommand progConf =- makeCommand name shortDesc longDesc- defaultBuildFlags- (\showOrParseArgs ->- [ optionVerbosity- buildVerbosity (\v flags -> flags { buildVerbosity = v })-- , optionDistPref- buildDistPref (\d flags -> flags { buildDistPref = d }) showOrParseArgs- ]- ++ buildOptions progConf showOrParseArgs)- where- name = "build"- shortDesc = "Compile all targets or specific targets."- longDesc = Just $ \pname ->+buildCommand progConf = CommandUI+ { commandName = "build"+ , commandSynopsis = "Compile all/specific components."+ , commandDescription = Just $ \_ -> wrapText $+ "Components encompass executables, tests, and benchmarks.\n"+ ++ "\n"+ ++ "Affected by configuration options, see `configure`.\n"+ , commandNotes = Just $ \pname -> "Examples:\n" ++ " " ++ pname ++ " build " ++ " All the components in the package\n"@@ -1415,7 +1539,21 @@ -- ++ "name, e.g.\n" -- ++ " " ++ pname ++ " build foo:Foo.Bar\n" -- ++ " " ++ pname ++ " build testsuite1:Foo/Bar.hs\n"+ , commandUsage = usageAlternatives "build" $+ [ "[FLAGS]"+ , "COMPONENTS [FLAGS]"+ ]+ , commandDefaultFlags = defaultBuildFlags+ , commandOptions = \showOrParseArgs ->+ [ optionVerbosity+ buildVerbosity (\v flags -> flags { buildVerbosity = v }) + , optionDistPref+ buildDistPref (\d flags -> flags { buildDistPref = d }) showOrParseArgs+ ]+ ++ buildOptions progConf showOrParseArgs+ }+ buildOptions :: ProgramConfiguration -> ShowOrParseArgs -> [OptionField BuildFlags] buildOptions progConf showOrParseArgs =@@ -1494,15 +1632,37 @@ where combine field = field a `mappend` field b replCommand :: ProgramConfiguration -> CommandUI ReplFlags-replCommand progConf = CommandUI {- commandName = "repl",- commandSynopsis = "Open an interpreter session for the given target.",- commandDescription = Just $ \pname ->- "Examples:\n"- ++ " " ++ pname ++ " repl "- ++ " The first component in the package\n"- ++ " " ++ pname ++ " repl foo "- ++ " A named component (i.e. lib, exe, test suite)\n",+replCommand progConf = CommandUI+ { commandName = "repl"+ , commandSynopsis = + "Open an interpreter session for the given component."+ , commandDescription = Just $ \pname -> wrapText $+ "If the current directory contains no package, ignores COMPONENT "+ ++ "parameters and opens an interactive interpreter session; if a "+ ++ "sandbox is present, its package database will be used.\n"+ ++ "\n"+ ++ "Otherwise, (re)configures with the given or default flags, and "+ ++ "loads the interpreter with the relevant modules. For executables, "+ ++ "tests and benchmarks, loads the main module (and its "+ ++ "dependencies); for libraries all exposed/other modules.\n"+ ++ "\n"+ ++ "The default component is the library itself, or the executable "+ ++ "if that is the only component.\n"+ ++ "\n"+ ++ "Support for loading specific modules is planned but not "+ ++ "implemented yet. For certain scenarios, `" ++ pname+ ++ " exec -- ghci :l Foo` may be used instead. Note that `exec` will "+ ++ "not (re)configure and you will have to specify the location of "+ ++ "other modules, if required.\n"++ , commandNotes = Just $ \pname ->+ "Examples:\n"+ ++ " " ++ pname ++ " repl "+ ++ " The first component in the package\n"+ ++ " " ++ pname ++ " repl foo "+ ++ " A named component (i.e. lib, exe, test suite)\n"+ ++ " " ++ pname ++ " repl --ghc-options=\"-lstdc++\""+ ++ " Specifying flags for interpreter\n" --TODO: re-enable once we have support for module/file targets -- ++ " " ++ pname ++ " repl Foo.Bar " -- ++ " A module\n"@@ -1512,10 +1672,9 @@ -- ++ "name, e.g.\n" -- ++ " " ++ pname ++ " repl foo:Foo.Bar\n" -- ++ " " ++ pname ++ " repl testsuite1:Foo/Bar.hs\n"-- commandUsage = \pname -> "Usage: " ++ pname ++ " repl [FILENAME] [FLAGS]\n",- commandDefaultFlags = defaultReplFlags,- commandOptions = \showOrParseArgs ->+ , commandUsage = \pname -> "Usage: " ++ pname ++ " repl [COMPONENT] [FLAGS]\n"+ , commandDefaultFlags = defaultReplFlags+ , commandOptions = \showOrParseArgs -> optionVerbosity replVerbosity (\v flags -> flags { replVerbosity = v }) : optionDistPref replDistPref (\d flags -> flags { replDistPref = d })@@ -1538,7 +1697,7 @@ trueArg ] _ -> []- }+ } -- ------------------------------------------------------------ -- * Test flags@@ -1573,9 +1732,6 @@ testMachineLog :: Flag PathTemplate, testShowDetails :: Flag TestShowDetails, testKeepTix :: Flag Bool,- --TODO: eliminate the test list and pass it directly as positional args to- --the testHook- testList :: Flag [String], -- TODO: think about if/how options are passed to test exes testOptions :: [PathTemplate] }@@ -1588,17 +1744,31 @@ testMachineLog = toFlag $ toPathTemplate $ "$pkgid.log", testShowDetails = toFlag Failures, testKeepTix = toFlag False,- testList = Flag [], testOptions = [] } testCommand :: CommandUI TestFlags-testCommand = makeCommand name shortDesc longDesc defaultTestFlags options- where- name = "test"- shortDesc = "Run the test suite, if any (configure with UserHooks)."- longDesc = Nothing- options showOrParseArgs =+testCommand = CommandUI+ { commandName = "test"+ , commandSynopsis =+ "Run all/specific tests in the test suite."+ , commandDescription = Just $ \pname -> wrapText $+ "If necessary (re)configures with `--enable-tests` flag and builds"+ ++ " the test suite.\n"+ ++ "\n"+ ++ "Remember that the tests' dependencies must be installed if there"+ ++ " are additional ones; e.g. with `" ++ pname+ ++ " install --only-dependencies --enable-tests`.\n"+ ++ "\n"+ ++ "By defining UserHooks in a custom Setup.hs, the package can"+ ++ " define actions to be executed before and after running tests.\n"+ , commandNotes = Nothing+ , commandUsage = usageAlternatives "test"+ [ "[FLAGS]"+ , "TESTCOMPONENTS [FLAGS]"+ ]+ , commandDefaultFlags = defaultTestFlags+ , commandOptions = \showOrParseArgs -> [ optionVerbosity testVerbosity (\v flags -> flags { testVerbosity = v }) , optionDistPref testDistPref (\d flags -> flags { testDistPref = d })@@ -1620,7 +1790,8 @@ , option [] ["show-details"] ("'always': always show results of individual test cases. " ++ "'never': never show results of individual test cases. "- ++ "'failures': show results of failing test cases.")+ ++ "'failures': show results of failing test cases. "+ ++ "'streaming': show results of test cases in real time.") testShowDetails (\v flags -> flags { testShowDetails = v }) (reqArg "FILTER" (readP_to_E (\_ -> "--show-details flag expects one of "@@ -1648,6 +1819,7 @@ (reqArg' "TEMPLATE" (\x -> [toPathTemplate x]) (map fromPathTemplate)) ]+ } emptyTestFlags :: TestFlags emptyTestFlags = mempty@@ -1660,7 +1832,6 @@ testMachineLog = mempty, testShowDetails = mempty, testKeepTix = mempty,- testList = mempty, testOptions = mempty } mappend a b = TestFlags {@@ -1670,7 +1841,6 @@ testMachineLog = combine testMachineLog, testShowDetails = combine testShowDetails, testKeepTix = combine testKeepTix,- testList = combine testList, testOptions = combine testOptions } where combine field = field a `mappend` field b@@ -1693,13 +1863,28 @@ } benchmarkCommand :: CommandUI BenchmarkFlags-benchmarkCommand = makeCommand name shortDesc- longDesc defaultBenchmarkFlags options- where- name = "bench"- shortDesc = "Run the benchmark, if any (configure with UserHooks)."- longDesc = Nothing- options showOrParseArgs =+benchmarkCommand = CommandUI+ { commandName = "bench"+ , commandSynopsis =+ "Run all/specific benchmarks."+ , commandDescription = Just $ \pname -> wrapText $+ "If necessary (re)configures with `--enable-benchmarks` flag and"+ ++ " builds the benchmarks.\n"+ ++ "\n"+ ++ "Remember that the benchmarks' dependencies must be installed if"+ ++ " there are additional ones; e.g. with `" ++ pname+ ++ " install --only-dependencies --enable-benchmarks`.\n"+ ++ "\n"+ ++ "By defining UserHooks in a custom Setup.hs, the package can"+ ++ " define actions to be executed before and after running"+ ++ " benchmarks.\n"+ , commandNotes = Nothing+ , commandUsage = usageAlternatives "bench"+ [ "[FLAGS]"+ , "BENCHCOMPONENTS [FLAGS]"+ ]+ , commandDefaultFlags = defaultBenchmarkFlags+ , commandOptions = \showOrParseArgs -> [ optionVerbosity benchmarkVerbosity (\v flags -> flags { benchmarkVerbosity = v }) , optionDistPref@@ -1721,6 +1906,7 @@ (reqArg' "TEMPLATE" (\x -> [toPathTemplate x]) (map fromPathTemplate)) ]+ } emptyBenchmarkFlags :: BenchmarkFlags emptyBenchmarkFlags = mempty
Distribution/Simple/SrcDist.hs view
@@ -66,13 +66,14 @@ ( LocalBuildInfo(..), withAllComponentsInBuildOrder ) import Distribution.Simple.BuildPaths ( autogenModuleName ) import Distribution.Simple.Program ( defaultProgramConfiguration, requireProgram,- rawSystemProgram, tarProgram )+ runProgram, programProperties, tarProgram ) import Distribution.Text ( display ) import Control.Monad(when, unless, forM) import Data.Char (toLower) import Data.List (partition, isPrefixOf)+import qualified Data.Map as Map import Data.Maybe (isNothing, catMaybes) import Data.Time (UTCTime, getCurrentTime, toGregorian, utctDay) import System.Directory ( doesFileExist )@@ -411,13 +412,17 @@ (tarProg, _) <- requireProgram verbosity tarProgram (maybe defaultProgramConfiguration withPrograms mb_lbi)-- -- Hmm: I could well be skating on thinner ice here by using the -C option- -- (=> GNU tar-specific?) [The prev. solution used pipes and sub-command- -- sequences to set up the paths correctly, which is problematic in a Windows- -- setting.]- rawSystemProgram verbosity tarProg- ["-C", tmpDir, "-czf", tarBallFilePath, tarBallName pkg_descr]+ let formatOptSupported = maybe False (== "YES") $+ Map.lookup "Supports --format"+ (programProperties tarProg)+ runProgram verbosity tarProg $+ -- Hmm: I could well be skating on thinner ice here by using the -C option+ -- (=> seems to be supported at least by GNU and *BSD tar) [The+ -- prev. solution used pipes and sub-command sequences to set up the paths+ -- correctly, which is problematic in a Windows setting.]+ ["-czf", tarBallFilePath, "-C", tmpDir]+ ++ (if formatOptSupported then ["--format", "ustar"] else [])+ ++ [tarBallName pkg_descr] return tarBallFilePath -- | Given a buildinfo, return the names of all source files.@@ -438,7 +443,7 @@ in findFileWithExtension fileExts (hsSourceDirs bi) file | module_ <- modules ++ otherModules bi ] - return $ sources ++ catMaybes bootFiles ++ cSources bi+ return $ sources ++ catMaybes bootFiles ++ cSources bi ++ jsSources bi where suffixes = ppSuffixes pps ++ ["hs", "lhs"]
Distribution/Simple/Test.hs view
@@ -19,14 +19,15 @@ ( PackageDescription(..), BuildInfo(buildable) , TestSuite(..) , TestSuiteInterface(..), testType, hasTests )-import Distribution.Simple.Compiler ( Compiler(..) )+import Distribution.Simple.Compiler ( compilerInfo ) import Distribution.Simple.Hpc ( markupPackage ) import Distribution.Simple.InstallDirs ( fromPathTemplate, initialPathTemplateEnv, substPathTemplate , PathTemplate ) import qualified Distribution.Simple.LocalBuildInfo as LBI ( LocalBuildInfo(..) )-import Distribution.Simple.Setup ( TestFlags(..), fromFlag )+import Distribution.Simple.Setup ( TestFlags(..), fromFlag, configCoverage )+import Distribution.Simple.UserHooks ( Args ) import qualified Distribution.Simple.Test.ExeV10 as ExeV10 import qualified Distribution.Simple.Test.LibV09 as LibV09 import Distribution.Simple.Test.Log@@ -42,16 +43,17 @@ import System.FilePath ( (</>) ) -- |Perform the \"@.\/setup test@\" action.-test :: PD.PackageDescription -- ^information from the .cabal file+test :: Args -- ^positional command-line arguments+ -> PD.PackageDescription -- ^information from the .cabal file -> LBI.LocalBuildInfo -- ^information from the configure step -> TestFlags -- ^flags sent to test -> IO ()-test pkg_descr lbi flags = do+test args pkg_descr lbi flags = do let verbosity = fromFlag $ testVerbosity flags machineTemplate = fromFlag $ testMachineLog flags distPref = fromFlag $ testDistPref flags testLogDir = distPref </> "test"- testNames = fromFlag $ testList flags+ testNames = args pkgTests = PD.testSuites pkg_descr enabledTests = [ t | t <- pkgTests , PD.testEnabled t@@ -115,8 +117,10 @@ allOk <- summarizePackage verbosity packageLog writeFile packageLogFile $ show packageLog - markupPackage verbosity lbi distPref (display $ PD.package pkg_descr)- $ map fst testsToRun+ let isCoverageEnabled = fromFlag $ configCoverage $ LBI.configFlags lbi+ when isCoverageEnabled $+ markupPackage verbosity lbi distPref (display $ PD.package pkg_descr) $+ map fst testsToRun unless allOk exitFailure @@ -128,5 +132,5 @@ fromPathTemplate $ substPathTemplate env template where env = initialPathTemplateEnv- (PD.package pkg_descr) (compilerId $ LBI.compiler lbi)- (LBI.hostPlatform lbi)+ (PD.package pkg_descr) (LBI.pkgKey lbi)+ (compilerInfo $ LBI.compiler lbi) (LBI.hostPlatform lbi)
Distribution/Simple/Test/ExeV10.hs view
@@ -7,15 +7,18 @@ import qualified Distribution.PackageDescription as PD import Distribution.Simple.Build.PathsModule ( pkgPathEnvVar ) import Distribution.Simple.BuildPaths ( exeExtension )-import Distribution.Simple.Compiler ( Compiler(..) )-import Distribution.Simple.Hpc ( markupTest, tixDir, tixFilePath )+import Distribution.Simple.Compiler ( compilerInfo )+import Distribution.Simple.Hpc ( guessWay, markupTest, tixDir, tixFilePath ) import Distribution.Simple.InstallDirs ( fromPathTemplate, initialPathTemplateEnv, PathTemplateVariable(..) , substPathTemplate , toPathTemplate, PathTemplate ) import qualified Distribution.Simple.LocalBuildInfo as LBI-import Distribution.Simple.Setup ( TestFlags(..), TestShowDetails(..), fromFlag )+import Distribution.Simple.Setup+ ( TestFlags(..), TestShowDetails(..), fromFlag, configCoverage ) import Distribution.Simple.Test.Log-import Distribution.Simple.Utils ( die, notice, rawSystemIOWithEnv )+import Distribution.Simple.Utils+ ( die, notice, rawSystemIOWithEnv, addLibraryPath )+import Distribution.System ( Platform (..) ) import Distribution.TestSuite import Distribution.Text import Distribution.Verbosity ( normal )@@ -35,6 +38,10 @@ -> PD.TestSuite -> IO TestSuiteLog runTest pkg_descr lbi flags suite = do+ let isCoverageEnabled = fromFlag $ configCoverage $ LBI.configFlags lbi+ way = guessWay lbi+ tixDir_ = tixDir distPref way $ PD.testName suite+ pwd <- getCurrentDirectory existingEnv <- getEnvironment @@ -47,12 +54,11 @@ -- Remove old .tix files if appropriate. unless (fromFlag $ testKeepTix flags) $ do- let tDir = tixDir distPref $ PD.testName suite- exists' <- doesDirectoryExist tDir- when exists' $ removeDirectoryRecursive tDir+ exists' <- doesDirectoryExist tixDir_+ when exists' $ removeDirectoryRecursive tixDir_ -- Create directory for HPC files.- createDirectoryIfMissing True $ tixDir distPref $ PD.testName suite+ createDirectoryIfMissing True tixDir_ -- Write summary notices indicating start of test suite notice verbosity $ summarizeSuiteStart $ PD.testName suite@@ -71,11 +77,21 @@ let opts = map (testOption pkg_descr lbi suite) (testOptions flags) dataDirPath = pwd </> PD.dataDir pkg_descr- tixFile = pwd </> (tixFilePath distPref $ PD.testName suite)- shellEnv = (pkgPathEnvVar pkg_descr "datadir", dataDirPath)- : ("HPCTIXFILE", tixFile)+ tixFile = pwd </> tixFilePath distPref way (PD.testName suite)+ pkgPathEnv = (pkgPathEnvVar pkg_descr "datadir", dataDirPath) : existingEnv- exit <- rawSystemIOWithEnv verbosity cmd opts Nothing (Just shellEnv)+ shellEnv = [("HPCTIXFILE", tixFile) | isCoverageEnabled] ++ pkgPathEnv++ -- Add (DY)LD_LIBRARY_PATH if needed+ shellEnv' <- if LBI.withDynExe lbi+ then do let (Platform _ os) = LBI.hostPlatform lbi+ clbi = LBI.getComponentLocalBuildInfo lbi+ (LBI.CTestName (PD.testName suite))+ paths <- LBI.depLibraryPaths True False lbi clbi+ return (addLibraryPath os paths shellEnv)+ else return shellEnv++ exit <- rawSystemIOWithEnv verbosity cmd opts Nothing (Just shellEnv') -- these handles are automatically closed Nothing (Just wOut) (Just wOut) @@ -107,8 +123,8 @@ -- Write summary notice to terminal indicating end of test suite notice verbosity $ summarizeSuiteFinish suiteLog - markupTest verbosity lbi distPref- (display $ PD.package pkg_descr) suite+ when isCoverageEnabled $+ markupTest verbosity lbi distPref (display $ PD.package pkg_descr) suite return suiteLog where@@ -136,8 +152,8 @@ pkg_descr lbi n l } --- TODO: This is abusing the notion of a 'PathTemplate'. The result--- isn't neccesarily a path.+-- TODO: This is abusing the notion of a 'PathTemplate'. The result isn't+-- necessarily a path. testOption :: PD.PackageDescription -> LBI.LocalBuildInfo -> PD.TestSuite@@ -147,6 +163,6 @@ fromPathTemplate $ substPathTemplate env template where env = initialPathTemplateEnv- (PD.package pkg_descr) (compilerId $ LBI.compiler lbi)- (LBI.hostPlatform lbi) +++ (PD.package pkg_descr) (LBI.pkgKey lbi)+ (compilerInfo $ LBI.compiler lbi) (LBI.hostPlatform lbi) ++ [(TestSuiteNameVar, toPathTemplate $ PD.testName suite)]
Distribution/Simple/Test/LibV09.hs view
@@ -13,15 +13,18 @@ import qualified Distribution.PackageDescription as PD import Distribution.Simple.Build.PathsModule ( pkgPathEnvVar ) import Distribution.Simple.BuildPaths ( exeExtension )-import Distribution.Simple.Compiler ( Compiler(..) )-import Distribution.Simple.Hpc ( markupTest, tixDir, tixFilePath )+import Distribution.Simple.Compiler ( compilerInfo )+import Distribution.Simple.Hpc ( guessWay, markupTest, tixDir, tixFilePath ) import Distribution.Simple.InstallDirs ( fromPathTemplate, initialPathTemplateEnv, PathTemplateVariable(..) , substPathTemplate , toPathTemplate, PathTemplate ) import qualified Distribution.Simple.LocalBuildInfo as LBI-import Distribution.Simple.Setup ( TestFlags(..), TestShowDetails(..), fromFlag )+import Distribution.Simple.Setup+ ( TestFlags(..), TestShowDetails(..), fromFlag, configCoverage ) import Distribution.Simple.Test.Log-import Distribution.Simple.Utils ( die, notice, rawSystemIOWithEnv )+import Distribution.Simple.Utils+ ( die, notice, rawSystemIOWithEnv, addLibraryPath )+import Distribution.System ( Platform (..) ) import Distribution.TestSuite import Distribution.Text import Distribution.Verbosity ( normal )@@ -43,6 +46,9 @@ -> PD.TestSuite -> IO TestSuiteLog runTest pkg_descr lbi flags suite = do+ let isCoverageEnabled = fromFlag $ configCoverage $ LBI.configFlags lbi+ way = guessWay lbi+ pwd <- getCurrentDirectory existingEnv <- getEnvironment @@ -55,12 +61,12 @@ -- Remove old .tix files if appropriate. unless (fromFlag $ testKeepTix flags) $ do- let tDir = tixDir distPref $ PD.testName suite+ let tDir = tixDir distPref way $ PD.testName suite exists' <- doesDirectoryExist tDir when exists' $ removeDirectoryRecursive tDir -- Create directory for HPC files.- createDirectoryIfMissing True $ tixDir distPref $ PD.testName suite+ createDirectoryIfMissing True $ tixDir distPref way $ PD.testName suite -- Write summary notices indicating start of test suite notice verbosity $ summarizeSuiteStart $ PD.testName suite@@ -78,11 +84,24 @@ -- Run test executable _ <- do let opts = map (testOption pkg_descr lbi suite) $ testOptions flags dataDirPath = pwd </> PD.dataDir pkg_descr- shellEnv = (pkgPathEnvVar pkg_descr "datadir", dataDirPath)- : ("HPCTIXFILE", (</>) pwd- $ tixFilePath distPref $ PD.testName suite)+ tixFile = pwd </> tixFilePath distPref way (PD.testName suite)+ pkgPathEnv = (pkgPathEnvVar pkg_descr "datadir", dataDirPath) : existingEnv- rawSystemIOWithEnv verbosity cmd opts Nothing (Just shellEnv)+ shellEnv = [("HPCTIXFILE", tixFile) | isCoverageEnabled]+ ++ pkgPathEnv+ -- Add (DY)LD_LIBRARY_PATH if needed+ shellEnv' <- if LBI.withDynExe lbi+ then do+ let (Platform _ os) = LBI.hostPlatform lbi+ clbi = LBI.getComponentLocalBuildInfo+ lbi+ (LBI.CTestName+ (PD.testName suite))+ paths <- LBI.depLibraryPaths+ True False lbi clbi+ return (addLibraryPath os paths shellEnv)+ else return shellEnv+ rawSystemIOWithEnv verbosity cmd opts Nothing (Just shellEnv') -- these handles are closed automatically (Just rIn) (Just wOut) (Just wOut) @@ -120,8 +139,8 @@ -- Write summary notice to terminal indicating end of test suite notice verbosity $ summarizeSuiteFinish suiteLog - markupTest verbosity lbi distPref- (display $ PD.package pkg_descr) suite+ when isCoverageEnabled $+ markupTest verbosity lbi distPref (display $ PD.package pkg_descr) suite return suiteLog where@@ -137,8 +156,8 @@ distPref = fromFlag $ testDistPref flags verbosity = fromFlag $ testVerbosity flags --- TODO: This is abusing the notion of a 'PathTemplate'. The result--- isn't neccesarily a path.+-- TODO: This is abusing the notion of a 'PathTemplate'. The result isn't+-- necessarily a path. testOption :: PD.PackageDescription -> LBI.LocalBuildInfo -> PD.TestSuite@@ -148,8 +167,8 @@ fromPathTemplate $ substPathTemplate env template where env = initialPathTemplateEnv- (PD.package pkg_descr) (compilerId $ LBI.compiler lbi)- (LBI.hostPlatform lbi) +++ (PD.package pkg_descr) (LBI.pkgKey lbi)+ (compilerInfo $ LBI.compiler lbi) (LBI.hostPlatform lbi) ++ [(TestSuiteNameVar, toPathTemplate $ PD.testName suite)] -- Test stub ----------
Distribution/Simple/Test/Log.hs view
@@ -13,7 +13,7 @@ import Distribution.Package ( PackageId ) import qualified Distribution.PackageDescription as PD-import Distribution.Simple.Compiler ( Compiler(..), CompilerId )+import Distribution.Simple.Compiler ( Compiler(..), compilerInfo, CompilerId ) import Distribution.Simple.InstallDirs ( fromPathTemplate, initialPathTemplateEnv, PathTemplateVariable(..) , substPathTemplate , toPathTemplate, PathTemplate )@@ -113,8 +113,8 @@ fromPathTemplate $ substPathTemplate env template where env = initialPathTemplateEnv- (PD.package pkg_descr) (compilerId $ LBI.compiler lbi)- (LBI.hostPlatform lbi)+ (PD.package pkg_descr) (LBI.pkgKey lbi)+ (compilerInfo $ LBI.compiler lbi) (LBI.hostPlatform lbi) ++ [ (TestSuiteNameVar, toPathTemplate name) , (TestSuiteResultVar, toPathTemplate $ resultString result) ]
Distribution/Simple/UHC.hs view
@@ -24,7 +24,7 @@ import qualified Data.Map as M ( empty ) import Distribution.Compat.ReadP import Distribution.InstalledPackageInfo-import Distribution.Package+import Distribution.Package hiding (installedPackageId) import Distribution.PackageDescription import Distribution.Simple.BuildPaths import Distribution.Simple.Compiler as C@@ -54,6 +54,8 @@ let comp = Compiler { compilerId = CompilerId UHC uhcVersion,+ compilerAbiTag = C.NoAbiTag,+ compilerCompat = [], compilerLanguages = uhcLanguages, compilerExtensions = uhcLanguageExtensions, compilerProperties = M.empty@@ -86,7 +88,7 @@ (FlexibleInstances, alwaysOn)] getInstalledPackages :: Verbosity -> Compiler -> PackageDBStack -> ProgramConfiguration- -> IO PackageIndex+ -> IO InstalledPackageIndex getInstalledPackages verbosity comp packagedbs conf = do let compilerid = compilerId comp systemPkgDir <- rawSystemProgramStdoutConf verbosity uhcProgram conf ["--meta-pkgdir-system"]
Distribution/Simple/UserHooks.hs view
@@ -144,7 +144,7 @@ -- |Hook to run before test command. preTest :: Args -> TestFlags -> IO HookedBuildInfo, -- |Over-ride this hook to get different behavior during test.- testHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> TestFlags -> IO (),+ testHook :: Args -> PackageDescription -> LocalBuildInfo -> UserHooks -> TestFlags -> IO (), -- |Hook to run after test command. postTest :: Args -> TestFlags -> PackageDescription -> LocalBuildInfo -> IO (), @@ -200,7 +200,7 @@ haddockHook = ru, postHaddock = ru, preTest = rn',- testHook = ru,+ testHook = \_ -> ru, postTest = ru, preBench = rn', benchHook = \_ -> ru,
Distribution/Simple/Utils.hs view
@@ -24,6 +24,7 @@ topHandler, topHandlerWith, warn, notice, setupMessage, info, debug, debugNoWrap, chattyTry,+ printRawCommandAndArgs, printRawCommandAndArgsAndEnv, -- * running programs rawSystemExit,@@ -53,6 +54,7 @@ installExecutableFiles, installMaybeExecutableFiles, installDirectoryContents,+ copyDirectoryRecursive, -- * File permissions doesExecutableExist,@@ -61,6 +63,7 @@ -- * file names currentDir,+ shortRelativePath, -- * finding files findFile,@@ -73,6 +76,7 @@ -- * environment variables isInSearchPath,+ addLibraryPath, -- * simple file globbing matchFileGlob,@@ -110,11 +114,17 @@ normaliseLineEndings, -- * generic utils+ dropWhileEndLE,+ takeWhileEndLE, equating, comparing, isInfixOf, intercalate, lowercase,+ listUnion,+ listUnionRight,+ ordNub,+ ordNubRight, wrapText, wrapLine, ) where@@ -126,11 +136,12 @@ import Data.List ( nub, unfoldr, isPrefixOf, tails, intercalate ) import Data.Char as Char- ( toLower, chr, ord )+ ( isDigit, toLower, chr, ord ) import Data.Bits ( Bits((.|.), (.&.), shiftL, shiftR) ) import qualified Data.ByteString.Lazy as BS import qualified Data.ByteString.Lazy.Char8 as BS.Char8+import qualified Data.Set as Set import System.Directory ( Permissions(executable), getDirectoryContents, getPermissions@@ -142,14 +153,15 @@ ( exitWith, ExitCode(..) ) import System.FilePath ( normalise, (</>), (<.>)- , getSearchPath, takeDirectory, splitFileName- , splitExtension, splitExtensions, splitDirectories )+ , getSearchPath, joinPath, takeDirectory, splitFileName+ , splitExtension, splitExtensions, splitDirectories+ , searchPathSeparator ) import System.Directory ( createDirectory, renameFile, removeDirectoryRecursive ) import System.IO- ( Handle, openFile, openBinaryFile, openBinaryTempFile+ ( Handle, openFile, openBinaryFile, openBinaryTempFileWithDefaultPermissions , IOMode(ReadMode), hSetBinaryMode- , hGetContents, stdin, stderr, stdout, hPutStr, hFlush, hClose )+ , hGetContents, stderr, stdout, hPutStr, hFlush, hClose ) import System.IO.Error as IO.Error ( isDoesNotExistError, isAlreadyExistsError , ioeSetFileName, ioeGetFileName, ioeGetErrorString )@@ -165,27 +177,18 @@ ( PackageIdentifier ) import Distribution.ModuleName (ModuleName) import qualified Distribution.ModuleName as ModuleName+import Distribution.System+ ( OS (..) ) import Distribution.Version (Version(..)) import Control.Exception (IOException, evaluate, throwIO)-import System.Process (rawSystem)-import qualified System.Process as Process (CreateProcess(..))- import Control.Concurrent (forkIO)-import System.Process (runInteractiveProcess, waitForProcess, proc,- StdStream(..))-#if __GLASGOW_HASKELL__ >= 702-import System.Process (showCommandForUser)-#endif--#ifndef mingw32_HOST_OS-import System.Posix.Signals (installHandler, sigINT, sigQUIT, Handler(..))-import System.Process.Internals (defaultSignal, runGenProcess_)-#else-import System.Process (createProcess)-#endif-+import qualified System.Process as Process+ ( CreateProcess(..), StdStream(..), proc)+import System.Process+ ( createProcess, rawSystem, runInteractiveProcess+ , showCommandForUser, waitForProcess) import Distribution.Compat.CopyFile ( copyFile, copyOrdinaryFile, copyExecutableFile , setFileOrdinary, setFileExecutable, setDirOrdinary )@@ -238,8 +241,8 @@ Nothing -> "" Just path -> path ++ location ++ ": " location = case ioeGetLocation ioe of- l@(n:_) | n >= '0' && n <= '9' -> ':' : l- _ -> ""+ l@(n:_) | Char.isDigit n -> ':' : l+ _ -> "" detail = ioeGetErrorString ioe topHandler :: IO a -> IO a@@ -343,61 +346,22 @@ unless (res == ExitSuccess) $ exitWith res printRawCommandAndArgs :: Verbosity -> FilePath -> [String] -> IO ()-printRawCommandAndArgs verbosity path args- | verbosity >= deafening = print (path, args)- | verbosity >= verbose =-#if __GLASGOW_HASKELL__ >= 702- putStrLn $ showCommandForUser path args-#else- putStrLn $ unwords (path : args)-#endif- | otherwise = return ()+printRawCommandAndArgs verbosity path args =+ printRawCommandAndArgsAndEnv verbosity path args Nothing printRawCommandAndArgsAndEnv :: Verbosity -> FilePath -> [String]- -> [(String, String)]+ -> Maybe [(String, String)] -> IO ()-printRawCommandAndArgsAndEnv verbosity path args env- | verbosity >= deafening = do putStrLn ("Environment: " ++ show env)- print (path, args)- | verbosity >= verbose = putStrLn $ unwords (path : args)+printRawCommandAndArgsAndEnv verbosity path args menv+ | verbosity >= deafening = do+ maybe (return ()) (putStrLn . ("Environment: " ++) . show) menv+ print (path, args)+ | verbosity >= verbose = putStrLn $ showCommandForUser path args | otherwise = return () --- This is taken directly from the process package.--- The reason we need it is that runProcess doesn't handle ^C in the same--- way that rawSystem handles it, but rawSystem doesn't allow us to pass--- an environment.-syncProcess :: String -> Process.CreateProcess -> IO ExitCode-#if mingw32_HOST_OS-syncProcess _fun c = do- (_,_,_,p) <- createProcess c- waitForProcess p-#else-syncProcess fun c = do- -- The POSIX version of system needs to do some manipulation of signal- -- handlers. Since we're going to be synchronously waiting for the child,- -- we want to ignore ^C in the parent, but handle it the default way- -- in the child (using SIG_DFL isn't really correct, it should be the- -- original signal handler, but the GHC RTS will have already set up- -- its own handler and we don't want to use that).- r <- Exception.bracket (installHandlers) (restoreHandlers) $- (\_ -> do (_,_,_,p) <- runGenProcess_ fun c- (Just defaultSignal) (Just defaultSignal)- waitForProcess p)- return r- where- installHandlers = do- old_int <- installHandler sigINT Ignore Nothing- old_quit <- installHandler sigQUIT Ignore Nothing- return (old_int, old_quit)- restoreHandlers (old_int, old_quit) = do- _ <- installHandler sigINT old_int Nothing- _ <- installHandler sigQUIT old_quit Nothing- return ()-#endif /* mingw32_HOST_OS */- -- Exit with the same exit code if the subcommand fails rawSystemExit :: Verbosity -> FilePath -> [String] -> IO () rawSystemExit verbosity path args = do@@ -423,10 +387,19 @@ -> [(String, String)] -> IO () rawSystemExitWithEnv verbosity path args env = do- printRawCommandAndArgsAndEnv verbosity path args env+ printRawCommandAndArgsAndEnv verbosity path args (Just env) hFlush stdout- exitcode <- syncProcess "rawSystemExitWithEnv" (proc path args)- { Process.env = Just env }+ (_,_,_,ph) <- createProcess $+ (Process.proc path args) { Process.env = (Just env)+#ifdef MIN_VERSION_process+#if MIN_VERSION_process(1,2,0)+-- delegate_ctlc has been added in process 1.2, and we still want to be able to+-- bootstrap GHC on systems not having that version+ , Process.delegate_ctlc = True+#endif+#endif+ }+ exitcode <- waitForProcess ph unless (exitcode == ExitSuccess) $ do debug verbosity $ path ++ " returned " ++ show exitcode exitWith exitcode@@ -442,29 +415,29 @@ -> Maybe Handle -- ^ stderr -> IO ExitCode rawSystemIOWithEnv verbosity path args mcwd menv inp out err = do- maybe (printRawCommandAndArgs verbosity path args)- (printRawCommandAndArgsAndEnv verbosity path args) menv+ printRawCommandAndArgsAndEnv verbosity path args menv hFlush stdout- exitcode <- syncProcess "rawSystemIOWithEnv" (proc path args)- { Process.cwd = mcwd- , Process.env = menv- , Process.std_in = mbToStd inp- , Process.std_out = mbToStd out- , Process.std_err = mbToStd err }- `Exception.finally` (mapM_ maybeClose [inp, out, err])+ (_,_,_,ph) <- createProcess $+ (Process.proc path args) { Process.cwd = mcwd+ , Process.env = menv+ , Process.std_in = mbToStd inp+ , Process.std_out = mbToStd out+ , Process.std_err = mbToStd err+#ifdef MIN_VERSION_process+#if MIN_VERSION_process(1,2,0)+-- delegate_ctlc has been added in process 1.2, and we still want to be able to+-- bootstrap GHC on systems not having that version+ , Process.delegate_ctlc = True+#endif+#endif+ }+ exitcode <- waitForProcess ph unless (exitcode == ExitSuccess) $ do debug verbosity $ path ++ " returned " ++ show exitcode return exitcode where- -- Also taken from System.Process- maybeClose :: Maybe Handle -> IO ()- maybeClose (Just hdl)- | hdl /= stdin && hdl /= stdout && hdl /= stderr = hClose hdl- maybeClose _ = return ()-- mbToStd :: Maybe Handle -> StdStream- mbToStd Nothing = Inherit- mbToStd (Just hdl) = UseHandle hdl+ mbToStd :: Maybe Handle -> Process.StdStream+ mbToStd = maybe Process.Inherit Process.UseHandle -- | Run a command and return its output. --@@ -726,6 +699,25 @@ isInSearchPath :: FilePath -> IO Bool isInSearchPath path = fmap (elem path) getSearchPath +addLibraryPath :: OS+ -> [FilePath]+ -> [(String,String)]+ -> [(String,String)]+addLibraryPath os paths = addEnv+ where+ pathsString = intercalate [searchPathSeparator] paths+ ldPath = case os of+ OSX -> "DYLD_LIBRARY_PATH"+ _ -> "LD_LIBRARY_PATH"++ addEnv [] = [(ldPath,pathsString)]+ addEnv ((key,value):xs)+ | key == ldPath =+ if null value+ then (key,pathsString):xs+ else (key,value ++ (searchPathSeparator:pathsString)):xs+ | otherwise = (key,value):addEnv xs+ ---------------- -- File globbing @@ -953,6 +945,13 @@ srcFiles <- getDirectoryContentsRecursive srcDir installOrdinaryFiles verbosity destDir [ (srcDir, f) | f <- srcFiles ] +-- | Recursively copy the contents of one directory to another path.+copyDirectoryRecursive :: Verbosity -> FilePath -> FilePath -> IO ()+copyDirectoryRecursive verbosity srcDir destDir = do+ info verbosity ("copy directory '" ++ srcDir ++ "' to '" ++ destDir ++ "'.")+ srcFiles <- getDirectoryContentsRecursive srcDir+ copyFilesWith (const copyFile) verbosity destDir [ (srcDir, f) | f <- srcFiles ]+ ------------------- -- File permissions @@ -1056,7 +1055,7 @@ -- | Writes a file atomically. ----- The file is either written sucessfully or an IO exception is raised and+-- The file is either written successfully or an IO exception is raised and -- the original file is left unchanged. -- -- On windows it is not possible to delete a file that is open by a process.@@ -1066,7 +1065,7 @@ writeFileAtomic targetPath content = do let (targetDir, targetFile) = splitFileName targetPath Exception.bracketOnError- (openBinaryTempFile targetDir $ targetFile <.> "tmp")+ (openBinaryTempFileWithDefaultPermissions targetDir $ targetFile <.> "tmp") (\(tmpPath, handle) -> hClose handle >> removeFile tmpPath) (\(tmpPath, handle) -> do BS.hPut handle content@@ -1096,6 +1095,16 @@ currentDir :: FilePath currentDir = "." +shortRelativePath :: FilePath -> FilePath -> FilePath+shortRelativePath from to =+ case dropCommonPrefix (splitDirectories from) (splitDirectories to) of+ (stuff, path) -> joinPath (map (const "..") stuff ++ path)+ where+ dropCommonPrefix :: Eq a => [a] -> [a] -> ([a],[a])+ dropCommonPrefix (x:xs) (y:ys)+ | x == y = dropCommonPrefix xs ys+ dropCommonPrefix xs ys = (xs,ys)+ -- ------------------------------------------------------------ -- * Finding the description file -- ------------------------------------------------------------@@ -1269,6 +1278,84 @@ -- ------------------------------------------------------------ -- * Common utils -- ------------------------------------------------------------++-- | @dropWhileEndLE p@ is equivalent to @reverse . dropWhile p . reverse@, but+-- quite a bit faster. The difference between "Data.List.dropWhileEnd" and this+-- version is that the one in "Data.List" is strict in elements, but spine-lazy,+-- while this one is spine-strict but lazy in elements. That's what @LE@ stands+-- for - "lazy in elements".+--+-- Example:+--+-- @+-- > tail $ Data.List.dropWhileEnd (<3) [undefined, 5, 4, 3, 2, 1]+-- *** Exception: Prelude.undefined+-- > tail $ dropWhileEndLE (<3) [undefined, 5, 4, 3, 2, 1]+-- [5,4,3]+-- > take 3 $ Data.List.dropWhileEnd (<3) [5, 4, 3, 2, 1, undefined]+-- [5,4,3]+-- > take 3 $ dropWhileEndLE (<3) [5, 4, 3, 2, 1, undefined]+-- *** Exception: Prelude.undefined+-- @+dropWhileEndLE :: (a -> Bool) -> [a] -> [a]+dropWhileEndLE p = foldr (\x r -> if null r && p x then [] else x:r) []++-- | @takeWhileEndLE p@ is equivalent to @reverse . takeWhile p . reverse@, but+-- is usually faster (as well as being easier to read).+takeWhileEndLE :: (a -> Bool) -> [a] -> [a]+takeWhileEndLE p = fst . foldr go ([], False)+ where+ go x (rest, done)+ | not done && p x = (x:rest, False)+ | otherwise = (rest, True)++-- | Like "Data.List.nub", but has @O(n log n)@ complexity instead of+-- @O(n^2)@. Code for 'ordNub' and 'listUnion' taken from Niklas Hambüchen's+-- <http://github.com/nh2/haskell-ordnub ordnub> package.+ordNub :: (Ord a) => [a] -> [a]+ordNub l = go Set.empty l+ where+ go _ [] = []+ go s (x:xs) = if x `Set.member` s then go s xs+ else x : go (Set.insert x s) xs++-- | Like "Data.List.union", but has @O(n log n)@ complexity instead of+-- @O(n^2)@.+listUnion :: (Ord a) => [a] -> [a] -> [a]+listUnion a b = a ++ ordNub (filter (`Set.notMember` aSet) b)+ where+ aSet = Set.fromList a++-- | A right-biased version of 'ordNub'.+--+-- Example:+--+-- @+-- > ordNub [1,2,1]+-- [1,2]+-- > ordNubRight [1,2,1]+-- [2,1]+-- @+ordNubRight :: (Ord a) => [a] -> [a]+ordNubRight = fst . foldr go ([], Set.empty)+ where+ go x p@(l, s) = if x `Set.member` s then p+ else (x:l, Set.insert x s)++-- | A right-biased version of 'listUnion'.+--+-- Example:+--+-- @+-- > listUnion [1,2,3,4,3] [2,1,1]+-- [1,2,3,4,3]+-- > listUnionRight [1,2,3,4,3] [2,1,1]+-- [4,3,2,1,1]+-- @+listUnionRight :: (Ord a) => [a] -> [a] -> [a]+listUnionRight a b = ordNubRight (filter (`Set.notMember` bSet) a) ++ b+ where+ bSet = Set.fromList b equating :: Eq a => (b -> a) -> b -> b -> Bool equating p x y = p x == p y
Distribution/System.hs view
@@ -1,4 +1,6 @@ {-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+ ----------------------------------------------------------------------------- -- | -- Module : Distribution.System@@ -32,11 +34,13 @@ import qualified System.Info (os, arch) import qualified Data.Char as Char (toLower, isAlphaNum) +import Data.Binary (Binary) import Data.Data (Data) import Data.Typeable (Typeable) import Data.Maybe (fromMaybe, listToMaybe) import Distribution.Text (Text(..), display) import qualified Distribution.Compat.ReadP as Parse+import GHC.Generics (Generic) import qualified Text.PrettyPrint as Disp import Text.PrettyPrint ((<>)) @@ -69,9 +73,12 @@ | Solaris | AIX | HPUX | IRIX -- ageing Unix OSs | HaLVM -- bare metal / VMs / hypervisors | IOS -- iOS+ | Ghcjs | OtherOS String- deriving (Eq, Ord, Show, Read, Typeable, Data)+ deriving (Eq, Generic, Ord, Show, Read, Typeable, Data) +instance Binary OS+ --TODO: decide how to handle Android and iOS. -- They are like Linux and OSX but with some differences. -- Should they be separate from Linux/OS X, or a subtype?@@ -82,7 +89,8 @@ ,FreeBSD, OpenBSD, NetBSD, DragonFly ,Solaris, AIX, HPUX, IRIX ,HaLVM- ,IOS]+ ,IOS+ ,Ghcjs] osAliases :: ClassificationStrictness -> OS -> [String] osAliases Permissive Windows = ["mingw32", "win32", "cygwin32"]@@ -120,15 +128,19 @@ | IA64 | S390 | Alpha | Hppa | Rs6000 | M68k | Vax+ | JavaScript | OtherArch String- deriving (Eq, Ord, Show, Read, Typeable, Data)+ deriving (Eq, Generic, Ord, Show, Read, Typeable, Data) +instance Binary Arch+ knownArches :: [Arch] knownArches = [I386, X86_64, PPC, PPC64, Sparc ,Arm, Mips, SH ,IA64, S390 ,Alpha, Hppa, Rs6000- ,M68k, Vax]+ ,M68k, Vax+ ,JavaScript] archAliases :: ClassificationStrictness -> Arch -> [String] archAliases Strict _ = []@@ -162,7 +174,9 @@ -- ------------------------------------------------------------ data Platform = Platform Arch OS- deriving (Eq, Ord, Show, Read, Typeable, Data)+ deriving (Eq, Generic, Ord, Show, Read, Typeable, Data)++instance Binary Platform instance Text Platform where disp (Platform arch os) = disp arch <> Disp.char '-' <> disp os
+ Distribution/Utils/NubList.hs view
@@ -0,0 +1,97 @@+module Distribution.Utils.NubList+ ( NubList -- opaque+ , toNubList -- smart construtor+ , fromNubList+ , overNubList++ , NubListR+ , toNubListR+ , fromNubListR+ , overNubListR+ ) where++import Data.Binary+import Data.Monoid++import Distribution.Simple.Utils (ordNub, listUnion, ordNubRight, listUnionRight)++import qualified Text.Read as R++-- | NubList : A de-duplicated list that maintains the original order.+newtype NubList a =+ NubList { fromNubList :: [a] }+ deriving Eq++-- NubList assumes that nub retains the list order while removing duplicate+-- elements (keeping the first occurence). Documentation for "Data.List.nub"+-- does not specifically state that ordering is maintained so we will add a test+-- for that to the test suite.++-- | Smart constructor for the NubList type.+toNubList :: Ord a => [a] -> NubList a+toNubList list = NubList $ ordNub list++-- | Lift a function over lists to a function over NubLists.+overNubList :: Ord a => ([a] -> [a]) -> NubList a -> NubList a+overNubList f (NubList list) = toNubList . f $ list++-- | Monoid operations on NubLists.+-- For a valid Monoid instance we need to satistfy the required monoid laws;+-- identity, associativity and closure.+--+-- Identity : by inspection:+-- mempty `mappend` NubList xs == NubList xs `mappend` mempty+--+-- Associativity : by inspection:+-- (NubList xs `mappend` NubList ys) `mappend` NubList zs+-- == NubList xs `mappend` (NubList ys `mappend` NubList zs)+--+-- Closure : appending two lists of type a and removing duplicates obviously+-- does not change the type.++instance Ord a => Monoid (NubList a) where+ mempty = NubList []+ mappend (NubList xs) (NubList ys) = NubList $ xs `listUnion` ys++instance Show a => Show (NubList a) where+ show (NubList list) = show list++instance (Ord a, Read a) => Read (NubList a) where+ readPrec = readNubList toNubList++-- | Helper used by NubList/NubListR's Read instances.+readNubList :: (Ord a, Read a) => ([a] -> l a) -> R.ReadPrec (l a)+readNubList toList = R.parens . R.prec 10 $ fmap toList R.readPrec++-- | Binary instance for 'NubList a' is the same as for '[a]'. For 'put', we+-- just pull off constructor and put the list. For 'get', we get the list and+-- make a 'NubList' out of it using 'toNubList'.+instance (Ord a, Binary a) => Binary (NubList a) where+ put (NubList l) = put l+ get = fmap toNubList get++-- | NubListR : A right-biased version of 'NubList'. That is @toNubListR+-- ["-XNoFoo", "-XFoo", "-XNoFoo"]@ will result in @["-XFoo", "-XNoFoo"]@,+-- unlike the normal 'NubList', which is left-biased. Built on top of+-- 'ordNubRight' and 'listUnionRight'.+newtype NubListR a =+ NubListR { fromNubListR :: [a] }+ deriving Eq++-- | Smart constructor for the NubListR type.+toNubListR :: Ord a => [a] -> NubListR a+toNubListR list = NubListR $ ordNubRight list++-- | Lift a function over lists to a function over NubListRs.+overNubListR :: Ord a => ([a] -> [a]) -> NubListR a -> NubListR a+overNubListR f (NubListR list) = toNubListR . f $ list++instance Ord a => Monoid (NubListR a) where+ mempty = NubListR []+ mappend (NubListR xs) (NubListR ys) = NubListR $ xs `listUnionRight` ys++instance Show a => Show (NubListR a) where+ show (NubListR list) = show list++instance (Ord a, Read a) => Read (NubListR a) where+ readPrec = readNubList toNubListR
Distribution/Verbosity.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE DeriveGeneric #-}+ ----------------------------------------------------------------------------- -- | -- Module : Distribution.Verbosity@@ -22,11 +24,15 @@ showForCabal, showForGHC ) where +import Data.Binary import Data.List (elemIndex) import Distribution.ReadE+import GHC.Generics data Verbosity = Silent | Normal | Verbose | Deafening- deriving (Show, Read, Eq, Ord, Enum, Bounded)+ deriving (Generic, Show, Read, Eq, Ord, Enum, Bounded)++instance Binary Verbosity -- We shouldn't print /anything/ unless an error occurs in silent mode silent :: Verbosity
Distribution/Version.hs view
@@ -1,4 +1,10 @@-{-# LANGUAGE CPP, DeriveDataTypeable, StandaloneDeriving #-}+{-# LANGUAGE CPP, DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+#if __GLASGOW_HASKELL__ < 707+{-# LANGUAGE StandaloneDeriving #-}+#endif+{-# OPTIONS_GHC -fno-warn-orphans #-}+ ----------------------------------------------------------------------------- -- | -- Module : Distribution.Version@@ -65,9 +71,11 @@ ) where +import Data.Binary ( Binary(..) ) import Data.Data ( Data ) import Data.Typeable ( Typeable ) import Data.Version ( Version(..) )+import GHC.Generics ( Generic ) import Distribution.Text ( Text(..) ) import qualified Distribution.Compat.ReadP as Parse@@ -92,13 +100,26 @@ | UnionVersionRanges VersionRange VersionRange | IntersectVersionRanges VersionRange VersionRange | VersionRangeParens VersionRange -- just '(exp)' parentheses syntax- deriving (Show,Read,Eq,Typeable,Data)+ deriving (Data, Eq, Generic, Read, Show, Typeable) +instance Binary VersionRange+ #if __GLASGOW_HASKELL__ < 707 -- starting with ghc-7.7/base-4.7 this instance is provided in "Data.Data" deriving instance Data Version #endif +-- Deriving this instance from Generic gives trouble on GHC 7.2 because the+-- Generic instance has to be standalone-derived. So, we hand-roll our own.+-- We can't use a generic Binary instance on later versions because we must+-- maintain compatibility between compiler versions.+instance Binary Version where+ get = do+ br <- get+ tags <- get+ return $ Version br tags+ put (Version br tags) = put br >> put tags+ {-# DEPRECATED AnyVersion "Use 'anyVersion', 'foldVersionRange' or 'asVersionIntervals'" #-} {-# DEPRECATED ThisVersion "use 'thisVersion', 'foldVersionRange' or 'asVersionIntervals'" #-} {-# DEPRECATED LaterVersion "use 'laterVersion', 'foldVersionRange' or 'asVersionIntervals'" #-}@@ -701,9 +722,11 @@ return f) factor = Parse.choice $ parens expr : parseAnyVersion+ : parseNoVersion : parseWildcardRange : map parseRangeOp rangeOps parseAnyVersion = Parse.string "-any" >> return AnyVersion+ parseNoVersion = Parse.string "-none" >> return noVersion parseWildcardRange = do _ <- Parse.string "=="
Language/Haskell/Extension.hs view
@@ -1,4 +1,6 @@ {-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+ ----------------------------------------------------------------------------- -- | -- Module : Language.Haskell.Extension@@ -25,8 +27,10 @@ import qualified Text.PrettyPrint as Disp import qualified Data.Char as Char (isAlphaNum) import Data.Array (Array, accumArray, bounds, Ix(inRange), (!))+import Data.Binary (Binary) import Data.Data (Data) import Data.Typeable (Typeable)+import GHC.Generics (Generic) -- ------------------------------------------------------------ -- * Language@@ -49,8 +53,10 @@ -- | An unknown language, identified by its name. | UnknownLanguage String- deriving (Show, Read, Eq, Typeable, Data)+ deriving (Generic, Show, Read, Eq, Typeable, Data) +instance Binary Language+ knownLanguages :: [Language] knownLanguages = [Haskell98, Haskell2010] @@ -77,7 +83,7 @@ -- Note: if you add a new 'KnownExtension': -- -- * also add it to the Distribution.Simple.X.languageExtensions lists--- (where X is each compiler: GHC, JHC, Hugs, NHC)+-- (where X is each compiler: GHC, JHC, LHC, UHC, HaskellSuite) -- -- | This represents language extensions beyond a base 'Language' definition -- (such as 'Haskell98') that are supported by some implementations, usually@@ -97,8 +103,10 @@ -- pragma. | UnknownExtension String - deriving (Show, Read, Eq, Typeable, Data)+ deriving (Generic, Show, Read, Eq, Ord, Typeable, Data) +instance Binary Extension+ data KnownExtension = -- | Allow overlapping class instances, provided there is a unique@@ -123,11 +131,11 @@ -- * <http://www.haskell.org/ghc/docs/latest/html/users_guide/type-class-extensions.html#instance-overlap> | IncoherentInstances - -- | /(deprecated)/ Allows recursive bindings in @do@ blocks, using the @rec@+ -- | /(deprecated)/ Allow recursive bindings in @do@ blocks, using the @rec@ -- keyword. See also 'RecursiveDo'. | DoRec - -- | Allows recursive bindings using @mdo@, a variant of @do@.+ -- | Allow recursive bindings using @mdo@, a variant of @do@. -- @DoRec@ provides a different, preferred syntax. -- -- * <http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#recursive-do-notation>@@ -504,13 +512,13 @@ -- and Josef Svenningsson, from ICFP '04. | RegularPatterns - -- | Enables the use of tuple sections, e.g. @(, True)@ desugars into+ -- | Enable the use of tuple sections, e.g. @(, True)@ desugars into -- @\x -> (x, True)@. -- -- * <http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#tuple-sections> | TupleSections - -- | Allows GHC primops, written in C--, to be imported into a Haskell+ -- | Allow GHC primops, written in C--, to be imported into a Haskell -- file. | GHCForeignImportPrim @@ -628,7 +636,7 @@ -- * <http://www.haskell.org/haskellwiki/GHC/Data_Parallel_Haskell> | ParallelArrays - -- | Enable explicit role annotations, like in (@data T a\@R@).+ -- | Enable explicit role annotations, like in (@type role Foo representational representational@). -- -- * <http://www.haskell.org/ghc/docs/latest/html/users_guide/roles.html> | RoleAnnotations@@ -639,7 +647,7 @@ -- * <http://www.haskell.org/ghc/docs/latest/html/users_guide/type-class-extensions.html#overloaded-lists> | OverloadedLists - -- | Enables case expressions that have no alternatives. Also applies to lambda-case expressions if they are enabled.+ -- | Enable case expressions that have no alternatives. Also applies to lambda-case expressions if they are enabled. -- -- * <http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#empty-case> | EmptyCase@@ -655,17 +663,17 @@ -- * <http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#negative-literals> | NegativeLiterals - -- | Allows the use of binary integer literal syntax (e.g. @0b11001001@ to denote @201@).+ -- | Allow the use of binary integer literal syntax (e.g. @0b11001001@ to denote @201@). -- -- * <http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#binary-literals> | BinaryLiterals - -- | Allows the use of floating literal syntax for all instances of 'Num', including 'Int' and 'Integer'.+ -- | Allow the use of floating literal syntax for all instances of 'Num', including 'Int' and 'Integer'. -- -- * <http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#num-decimals> | NumDecimals - -- | Enables support for type classes with no type parameter.+ -- | Enable support for type classes with no type parameter. -- -- * <http://www.haskell.org/ghc/docs/latest/html/users_guide/type-class-extensions.html#nullary-type-classes> | NullaryTypeClasses@@ -680,7 +688,35 @@ -- * <http://www.haskell.org/ghc/docs/latest/html/users_guide/other-type-extensions.html#ambiguity> | AllowAmbiguousTypes - deriving (Show, Read, Eq, Enum, Bounded, Typeable, Data)+ -- | Enable @foreign import javascript@.+ | JavaScriptFFI++ -- | Allow giving names to and abstracting over patterns.+ --+ -- * <http://www.haskell.org/ghc/docs/latest/html/users_guide/other-type-extensions.html#pattern-synonyms>+ | PatternSynonyms++ -- | Allow anonymous placeholders (underscore) inside type signatures. The+ -- type inference engine will generate a message describing the type inferred+ -- at the hole's location.+ --+ -- * <http://www.haskell.org/ghc/docs/latest/html/users_guide/other-type-extensions.html#partial-type-signatures>+ | PartialTypeSignatures++ -- | Allow named placeholders written with a leading underscore inside type+ -- signatures. Wildcards with the same name unify to the same type.+ --+ -- * <http://www.haskell.org/ghc/docs/latest/html/users_guide/other-type-extensions.html#named-wildcards>+ | NamedWildCards++ -- | Enable @deriving@ for any class.+ --+ -- * <http://www.haskell.org/ghc/docs/latest/html/users_guide/other-type-extensions.html#derive-any-class>+ | DeriveAnyClass++ deriving (Generic, Show, Read, Eq, Ord, Enum, Bounded, Typeable, Data)++instance Binary KnownExtension {-# DEPRECATED knownExtensions "KnownExtension is an instance of Enum and Bounded, use those instead." #-}
− README
@@ -1,179 +0,0 @@-The Cabal library package-=========================--[Cabal home page](http://www.haskell.org/cabal/)--If you also want the `cabal` command line program then you need-the `cabal-install` package in addition to this library.---Installation instructions for the Cabal library-===============================================--If you have the `cabal` program already------------------------------------------In this case it's simple, just-- cabal install--Of course, if you don't have an existing version of the `cabal` program-then to get one you'd first need to install the Cabal library! To avoid-this bootstrapping problem, you can install the Cabal library directly:--Installing as a user (no root or administrator access)--------------------------------------------------------- ghc -threaded --make Setup- ./Setup configure --user- ./Setup build- ./Setup install--Note the use of the `--user` flag at the configure step.--Compiling Setup rather than using `runghc Setup` is much faster and works on-Windows. For all packages other than Cabal itself it is fine to use `runghc`.--This will install into `$HOME/.cabal/` on unix and into-`$Documents and Settings\$User\Application Data\cabal\` on Windows-If you want to install elsewhere use the `--prefix=` flag at the-configure step.---Installing as root / Administrator------------------------------------- ghc -threaded --make Setup- ./Setup configure- ./Setup build- sudo ./Setup install--Compiling Setup rather than using `runghc Setup` is much faster and works on-Windows. For all packages other than Cabal itself it is fine to use `runghc`.--This will install into `/usr/local` on unix and on Windows it will-install into `$ProgramFiles/Haskell`. If you want to install-elsewhere use the `--prefix=` flag at the configure step.---Working with older versions of GHC and Cabal-============================================--It is recommended just to leave any pre-existing version of Cabal-installed. In particular it is *essential* to keep the version that-came with GHC itself since other installed packages need it (eg the-"ghc" api package).--Prior to GHC 6.4.2 however, GHC didn't deal particularly well with-having multiple versions of packages installed at once. So if you-are using GHC 6.4.1 or older and you have an older version of Cabal-installed, you probably just want to remove it:-- ghc-pkg unregister Cabal--or if you had Cabal installed just for your user account then:-- ghc-pkg unregister Cabal --user---The `filepath` dependency-=========================--Cabal now uses the `filepath` package so that must be installed first.-GHC-6.6.1 and later come with `filepath` however earlier versions do not by-default. If you do not already have `filepath` then you need to install it. You-can use any existing version of Cabal to do that. If you have neither Cabal or-filepath then it is slightly harder but still possible.--Unpack Cabal and filepath into separate directories. For example:-- tar -xzf filepath-1.1.0.0.tar.gz- tar -xzf Cabal-1.6.0.0.tar.gz-- # rename to make the following instructions simpler:- mv filepath-1.1.0.0/ filepath/- mv Cabal-1.6.0.0/ Cabal/-- cd Cabal- ghc -i../filepath -cpp --make Setup.hs -o ../filepath/setup- cd ../filepath/- ./setup configure --user- ./setup build- ./setup install--This installs filepath so you are then in a position to install Cabal by the-normal method.---More Information-================--Please see the web site for the [user guide] and API documentation.-There is some more information available on the [development wiki].--[user guide]: http://www.haskell.org/cabal/-[development wiki]: http://hackage.haskell.org/trac/hackage/---Bugs-=======--Please report bugs and wish-list items in our [bug tracker].--[bug tracker]: https://github.com/haskell/cabal/issues---Your Help------------To help us in the next round of development work it would be-enormously helpful to know from our users what their most pressing-problems are with Cabal and Hackage. You probably have a favourite-Cabal bug or limitation. Take a look at our [bug tracker]. Make sure-the problem is reported there and properly described. Comment on the-ticket to tell us how much of a problem the bug is for you. Add-yourself to the ticket's cc list so we can discuss requirements and-keep you informed on progress. For feature requests it is very-helpful if there is a description of how you would expect to-interact with the new feature.---Code-=======--You can get the code from the web page; the version control system we-use is very open and welcoming to new developers.--You can get the main development branch:--> darcs get --partial http://darcs.haskell.org/cabal--and you can get the stable 1.6 branch:--> darcs get --partial http://darcs.haskell.org/cabal-branches/cabal-1.6---Credits-=======--Cabal Coders (in alphabetical order):--- Krasimir Angelov-- Bjorn Bringert-- Duncan Coutts-- Isaac Jones-- David Himmelstrup (Lemmih)-- Simon Marlow-- Ross Patterson-- Thomas Schilling-- Martin Sjögren-- Malcolm Wallace-- and nearly 30 other people have contributed occasional patches--Cabal spec:--- Isaac Jones-- Simon Marlow-- Ross Patterson-- Simon Peyton Jones-- Malcolm Wallace
+ README.md view
@@ -0,0 +1,182 @@+The Cabal library package+=========================++See the [Cabal web site] for more information.++If you also want the `cabal` command-line program, you need the+[cabal-install] package in addition to this library.++[cabal-install]: ../cabal-install/README.md++Installing the Cabal library+============================++If you already have the `cabal` program+---------------------------------------++In this case run:++ $ cabal install++However, if you do not have an existing version of the `cabal` program,+you first must install the Cabal library. To avoid this bootstrapping+problem, you can install the Cabal library directly as described below.+++Installing as a user (no root or administrator access)+------------------------------------------------------++ ghc -threaded --make Setup+ ./Setup configure --user+ ./Setup build+ ./Setup install++Note the use of the `--user` flag at the configure step.++Compiling 'Setup' rather than using `runghc Setup` is much faster and+works on Windows. For all packages other than Cabal itself, it is fine+to use `runghc`.++This will install into `$HOME/.cabal/` on Unix and into+`Documents and Settings\$User\Application Data\cabal\` on Windows.+If you want to install elsewhere, use the `--prefix=` flag at the+configure step.+++Installing as root or Administrator+-----------------------------------++ ghc -threaded --make Setup+ ./Setup configure+ ./Setup build+ sudo ./Setup install++Compiling Setup rather than using `runghc Setup` is much faster and+works on Windows. For all packages other than Cabal itself, it is fine+to use `runghc`.++This will install into `/usr/local` on Unix, and on Windows it will+install into `$ProgramFiles/Haskell`. If you want to install elsewhere,+use the `--prefix=` flag at the configure step.+++Using older versions of GHC and Cabal+======================================++It is recommended that you leave any pre-existing version of Cabal+installed. In particular, it is *essential* you keep the version that+came with GHC itself, since other installed packages require it (for+instance, the "ghc" API package).++Prior to GHC 6.4.2, however, GHC did not deal particularly well with+having multiple versions of packages installed at once. So if you are+using GHC 6.4.1 or older and you have an older version of Cabal+installed, you should probably remove it by running:++ $ ghc-pkg unregister Cabal++or, if you had Cabal installed only for your user account, run:++ $ ghc-pkg unregister Cabal --user++The `filepath` dependency+=========================++Cabal uses the [filepath] package, so it must be installed first.+GHC version 6.6.1 and later come with `filepath`, however, earlier+versions do not by default. If you do not already have `filepath`,+you need to install it. You can use any existing version of Cabal to do+that. If you have neither Cabal nor `filepath`, it is slightly+harder but still possible.++Unpack Cabal and `filepath` into separate directories. For example:++ tar -xzf filepath-1.1.0.0.tar.gz+ tar -xzf Cabal-1.6.0.0.tar.gz++ # rename to make the following instructions simpler:+ mv filepath-1.1.0.0/ filepath/+ mv Cabal-1.6.0.0/ Cabal/++ cd Cabal+ ghc -i../filepath -cpp --make Setup.hs -o ../filepath/setup+ cd ../filepath/+ ./setup configure --user+ ./setup build+ ./setup install++This installs `filepath` so that you can install Cabal with the normal+method.++[filepath]: http://hackage.haskell.org/package/filepath++More information+================++Please see the [Cabal web site] for the [user guide] and [API+documentation]. There is additional information available on the+[development wiki].++[user guide]: http://www.haskell.org/cabal/users-guide+[API documentation]: http://www.haskell.org/cabal/release/cabal-latest/doc/API/Cabal/Distribution-Simple.html+[development wiki]: https://github.com/haskell/cabal/wiki+++Bugs+====++Please report bugs and feature requests to Cabal's [bug tracker].+++Your help+---------++To help Cabal's development, it is enormously helpful to know from+Cabal's users what their most pressing problems are with Cabal and+[Hackage]. You may have a favourite Cabal bug or limitation. Look at+Cabal's [bug tracker]. Ensure that the problem is reported there and+adequately described. Comment on the issue to report how much of a+problem the bug is for you. Subscribe to the issues's notifications to+discussed requirements and keep informed on progress. For feature+requests, it is helpful if there is a description of how you would+expect to interact with the new feature.++[Hackage]: http://hackage.haskell.org+++Source code+===========++You can get the master development branch using:++ $ git clone https://github.com/haskell/cabal.git+++Credits+=======++Cabal developers (in alphabetical order):++- Krasimir Angelov+- Bjorn Bringert+- Duncan Coutts+- Isaac Jones+- David Himmelstrup ("Lemmih")+- Simon Marlow+- Ross Patterson+- Thomas Schilling+- Martin Sjögren+- Malcolm Wallace+- and nearly 30 other people have contributed occasional patches++Cabal specification authors:++- Isaac Jones+- Simon Marlow+- Ross Patterson+- Simon Peyton Jones+- Malcolm Wallace+++[bug tracker]: https://github.com/haskell/cabal/issues+[Cabal web site]: http://www.haskell.org/cabal/
changelog view
@@ -1,7 +1,37 @@ -*-change-log-*- -1.20.0.4 Ryan Thomas <ryan@ryant.org> January 2016- * Cabal.cabal: change build-type to Simple.+1.22.0.0 Johan Tibell <johan.tibell@gmail.com> January 2015+ * Support GHC 7.10.+ * Experimental support for emitting DWARF debug info.+ * Preliminary support for relocatable packages.+ * Allow cabal to be used inside cabal exec enviroments.+ * hpc: support mutliple "ways" (e.g. profiling and vanilla).+ * Support GHCJS.+ * Improved command line documentation.+ * Add '-none' constraint syntax for version ranges (#2093).+ * Make the default doc index file path compiler/arch/os-dependent+ (#2136).+ * Warn instead of dying when generating documentation and hscolour+ isn't installed (455f51622fa38347db62197a04bb0fa5b928ff17).+ * Support the new BinaryLiterals extension+ (1f25ab3c5eff311ada73c6c987061b80e9bbebd9).+ * Warn about 'ghc-prof-options: -auto-all' in 'cabal check' (#2162).+ * Add preliminary support for multiple instances of the same package+ version installed side-by-side (#2002).+ * New binary build config format - faster build times (#2076).+ * Support module thinning and renaming (#2038).+ * Add a new license type: UnspecifiedLicense (#2141).+ * Remove support for Hugs and nhc98 (#2168).+ * Invoke 'tar' with '--formar ustar' if possible in 'sdist' (#1903).+ * Replace --enable-library-coverage with --enable-coverage, which+ enables program coverage for all components (#1945).+ * Suggest that `ExitFailure 9` is probably due to memory+ exhaustion (#1522).+ * Drop support for Haddock < 2.0 (#1808, #1718).+ * Make 'cabal test'/'cabal bench' build only what's needed for+ running tests/benchmarks (#1821).+ * Build shared libraries by default when linking executables dynamically.+ * Build profiled libraries by default when profiling executables. 1.20.0.1 Johan Tibell <johan.tibell@gmail.com> May 2014 * Fix streaming test output.@@ -17,7 +47,7 @@ * Don't call ranlib on OS X * Avoid re-linking executables, test suites, and benchmarks unnecessarily, shortening build times- * Add --allow-never which allows upper version bounds to be+ * Add --allow-newer which allows upper version bounds to be ignored * Add --enable-library-stripping * Add command for freezing dependencies@@ -31,10 +61,6 @@ * Improve pretty-printing of Cabal files * Add test flag --show-details=streaming for real-time test output * Add exec command--1.11.x (current development version)--1.10.0.x (next stable release version) 1.10.2.0 Duncan Coutts <duncan@community.haskell.org> June 2011 * Include test suites in cabal sdist
+ doc/developing-packages.markdown view
@@ -0,0 +1,2146 @@+% Cabal User Guide: Developing Cabal packages+++# Quickstart #+++Lets assume we have created a project directory and already have a+Haskell module or two.++Every project needs a name, we'll call this example "proglet".++~~~~~~~~~~~+$ cd proglet/+$ ls+Proglet.hs+~~~~~~~~~~~++It is assumed that (apart from external dependencies) all the files that+make up a package live under a common project root directory. This+simple example has all the project files in one directory, but most+packages will use one or more subdirectories.++To turn this into a Cabal package we need two extra files in the+project's root directory:++ * `proglet.cabal`: containing package metadata and build information.++ * `Setup.hs`: usually containing a few standardized lines of code, but+ can be customized if necessary.++We can create both files manually or we can use `cabal init` to create+them for us.++### Using "cabal init" ###++The `cabal init` command is interactive. It asks us a number of+questions starting with the package name and version.++~~~~~~~~~~+$ cabal init+Package name [default "proglet"]?+Package version [default "0.1"]?+...+~~~~~~~~~~++It also asks questions about various other bits of package metadata. For+a package that you never intend to distribute to others, these fields can+be left blank.++One of the important questions is whether the package contains a library+or an executable. Libraries are collections of Haskell modules that can+be re-used by other Haskell libraries and programs, while executables+are standalone programs.++~~~~~~~~~~+What does the package build:+ 1) Library+ 2) Executable+Your choice?+~~~~~~~~~~++For the moment these are the only choices. For more complex packages+(e.g. a library and multiple executables or test suites) the `.cabal`+file can be edited afterwards.++Finally, `cabal init` creates the initial `proglet.cabal` and `Setup.hs`+files, and depending on your choice of license, a `LICENSE` file as well.++~~~~~~~~~~+Generating LICENSE...+Generating Setup.hs...+Generating proglet.cabal...++You may want to edit the .cabal file and add a Description field.+~~~~~~~~~~++As this stage the `proglet.cabal` is not quite complete and before you+are able to build the package you will need to edit the file and add+some build information about the library or executable.++### Editing the .cabal file ###++Load up the `.cabal` file in a text editor. The first part of the+`.cabal` file has the package metadata and towards the end of the file+you will find the `executable` or `library` section.++You will see that the fields that have yet to be filled in are commented+out. Cabal files use "`--`" Haskell-style comment syntax. (Note that+comments are only allowed on lines on their own. Trailing comments on+other lines are not allowed because they could be confused with program+options.)++If you selected earlier to create a library package then your `.cabal`+file will have a section that looks like this:++~~~~~~~~~~~~~~~~~+library+ exposed-modules: Proglet+ -- other-modules:+ -- build-depends:+~~~~~~~~~~~~~~~~~++Alternatively, if you selected an executable then there will be a+section like:++~~~~~~~~~~~~~~~~~+executable proglet+ -- main-is:+ -- other-modules:+ -- build-depends:+~~~~~~~~~~~~~~~~~++The build information fields listed (but commented out) are just the few+most important and common fields. There are many others that are covered+later in this chapter.++Most of the build information fields are the same between libraries and+executables. The difference is that libraries have a number of "exposed"+modules that make up the public interface of the library, while+executables have a file containing a `Main` module.++The name of a library always matches the name of the package, so it is+not specified in the library section. Executables often follow the name+of the package too, but this is not required and the name is given+explicitly.++### Modules included in the package ###++For a library, `cabal init` looks in the project directory for files+that look like Haskell modules and adds all the modules to the+`exposed-modules` field. For modules that do not form part of your+package's public interface, you can move those modules to the+`other-modules` field. Either way, all modules in the library need to be+listed.++For an executable, `cabal init` does not try to guess which file+contains your program's `Main` module. You will need to fill in the+`main-is` field with the file name of your program's `Main` module+(including `.hs` or `.lhs` extension). Other modules included in the+executable should be listed in the `other-modules` field.++### Modules imported from other packages ###++While your library or executable may include a number of modules, it+almost certainly also imports a number of external modules from the+standard libraries or other pre-packaged libraries. (These other+libraries are of course just Cabal packages that contain a library.)++You have to list all of the library packages that your library or+executable imports modules from. Or to put it another way: you have to+list all the other packages that your package depends on.++For example, suppose the example `Proglet` module imports the module+`Data.Map`. The `Data.Map` module comes from the `containers` package,+so we must list it:++~~~~~~~~~~~~~~~~~+library+ exposed-modules: Proglet+ other-modules:+ build-depends: containers, base == 4.*+~~~~~~~~~~~~~~~~~++In addition, almost every package also depends on the `base` library+package because it exports the standard `Prelude` module plus other+basic modules like `Data.List`.++You will notice that we have listed `base == 4.*`. This gives a+constraint on the version of the base package that our package will work+with. The most common kinds of constraints are:++ * `pkgname >= n`+ * `pkgname >= n && < m`+ * `pkgname == n.*`++The last is just shorthand, for example `base == 4.*` means exactly the+same thing as `base >= 4 && < 5`.++### Building the package ###++For simple packages that's it! We can now try configuring and building+the package:++~~~~~~~~~~~~~~~~+cabal configure+cabal build+~~~~~~~~~~~~~~~~++Assuming those two steps worked then you can also install the package:++~~~~~~~~~~~~~~~~+cabal install+~~~~~~~~~~~~~~~~++For libraries this makes them available for use in GHCi or to be used by+other packages. For executables it installs the program so that you can+run it (though you may first need to adjust your system's `$PATH`).++### Next steps ###++What we have covered so far should be enough for very simple packages+that you use on your own system.++The next few sections cover more details needed for more complex+packages and details needed for distributing packages to other people.++The previous chapter covers building and installing packages -- your own+packages or ones developed by other people.+++# Package concepts #++Before diving into the details of writing packages it helps to+understand a bit about packages in the Haskell world and the particular+approach that Cabal takes.++### The point of packages ###++Packages are a mechanism for organising and distributing code. Packages+are particularly suited for "programming in the large", that is building+big systems by using and re-using code written by different people at+different times.++People organise code into packages based on functionality and+dependencies. Social factors are also important: most packages have a+single author, or a relatively small team of authors.++Packages are also used for distribution: the idea is that a package can+be created in one place and be moved to a different computer and be+usable in that different environment. There are a surprising number of+details that have to be got right for this to work, and a good package+system helps to simply this process and make it reliable.++Packages come in two main flavours: libraries of reusable code, and+complete programs. Libraries present a code interface, an API, while+programs can be run directly. In the Haskell world, library packages+expose a set of Haskell modules as their public interface. Cabal+packages can contain a library or executables or both.++Some programming languages have packages as a builtin language concept.+For example in Java, a package provides a local namespace for types and+other definitions. In the Haskell world, packages are not a part of the+language itself. Haskell programs consist of a number of modules, and+packages just provide a way to partition the modules into sets of+related functionality. Thus the choice of module names in Haskell is+still important, even when using packages.++### Package names and versions ###++All packages have a name, e.g. "HUnit". Package names are assumed to be+unique. Cabal package names can use letters, numbers and hyphens, but+not spaces. The namespace for Cabal packages is flat, not hierarchical.++Packages also have a version, e.g "1.1". This matches the typical way in+which packages are developed. Strictly speaking, each version of a+package is independent, but usually they are very similar. Cabal package+versions follow the conventional numeric style, consisting of a sequence+of digits such as "1.0.1" or "2.0". There are a range of common+conventions for "versioning" packages, that is giving some meaning to+the version number in terms of changes in the package. Section [TODO]+has some tips on package versioning.++The combination of package name and version is called the _package ID_+and is written with a hyphen to separate the name and version, e.g.+"HUnit-1.1".++For Cabal packages, the combination of the package name and version+_uniquely_ identifies each package. Or to put it another way: two+packages with the same name and version are considered to _be_ the same.++Strictly speaking, the package ID only identifies each Cabal _source_+package; the same Cabal source package can be configured and built in+different ways. There is a separate installed package ID that uniquely+identifies each installed package instance. Most of the time however,+users need not be aware of this detail.++### Kinds of package: Cabal vs GHC vs system ###++It can be slightly confusing at first because there are various+different notions of package floating around. Fortunately the details+are not very complicated.++Cabal packages+: Cabal packages are really source packages. That is they contain+ Haskell (and sometimes C) source code.++ Cabal packages can be compiled to produce GHC packages. They can+ also be translated into operating system packages.++GHC packages+: This is GHC's view on packages. GHC only cares about library+ packages, not executables. Library packages have to be registered+ with GHC for them to be available in GHCi or to be used when+ compiling other programs or packages.++ The low-level tool `ghc-pkg` is used to register GHC packages and to+ get information on what packages are currently registered.++ You never need to make GHC packages manually. When you build and+ install a Cabal package containing a library then it gets registered+ with GHC automatically.++ Haskell implementations other than GHC have essentially the same+ concept of registered packages. For the most part, Cabal hides the+ slight differences.++Operating system packages+: On operating systems like Linux and Mac OS X, the system has a+ specific notion of a package and there are tools for installing and+ managing packages.++ The Cabal package format is designed to allow Cabal packages to be+ translated, mostly-automatically, into operating system packages.+ They are usually translated 1:1, that is a single Cabal package+ becomes a single system package.++ It is also possible to make Windows installers from Cabal packages,+ though this is typically done for a program together with all of its+ library dependencies, rather than packaging each library separately.+++### Unit of distribution ###++The Cabal package is the unit of distribution. What this means is that+each Cabal package can be distributed on its own in source or binary+form. Of course there may dependencies between packages, but there is+usually a degree of flexibility in which versions of packages can work+together so distributing them independently makes sense.++It is perhaps easiest to see what being ``the unit of distribution''+means by contrast to an alternative approach. Many projects are made up+of several interdependent packages and during development these might+all be kept under one common directory tree and be built and tested+together. When it comes to distribution however, rather than+distributing them all together in a single tarball, it is required that+they each be distributed independently in their own tarballs.++Cabal's approach is to say that if you can specify a dependency on a+package then that package should be able to be distributed+independently. Or to put it the other way round, if you want to+distribute it as a single unit, then it should be a single package.+++### Explicit dependencies and automatic package management ###++Cabal takes the approach that all packages dependencies are specified+explicitly and specified in a declarative way. The point is to enable+automatic package management. This means tools like `cabal` can resolve+dependencies and install a package plus all of its dependencies+automatically. Alternatively, it is possible to mechanically (or mostly+mechanically) translate Cabal packages into system packages and let the+system package manager install dependencies automatically.++It is important to track dependencies accurately so that packages can+reliably be moved from one system to another system and still be able to+build it there. Cabal is therefore relatively strict about specifying+dependencies. For example Cabal's default build system will not even let+code build if it tries to import a module from a package that isn't+listed in the `.cabal` file, even if that package is actually installed.+This helps to ensure that there are no "untracked dependencies" that+could cause the code to fail to build on some other system.++The explicit dependency approach is in contrast to the traditional+"./configure" approach where instead of specifying dependencies+declaratively, the `./configure` script checks if the dependencies are+present on the system. Some manual work is required to transform a+`./configure` based package into a Linux distribution package (or+similar). This conversion work is usually done by people other than the+package author(s). The practical effect of this is that only the most+popular packages will benefit from automatic package management. Instead,+Cabal forces the original author to specify the dependencies but the+advantage is that every package can benefit from automatic package+management.++The "./configure" approach tends to encourage packages that adapt+themselves to the environment in which they are built, for example by+disabling optional features so that they can continue to work when a+particular dependency is not available. This approach makes sense in a+world where installing additional dependencies is a tiresome manual+process and so minimising dependencies is important. The automatic+package management view is that packages should just declare what they+need and the package manager will take responsibility for ensuring that+all the dependencies are installed.++Sometimes of course optional features and optional dependencies do make+sense. Cabal packages can have optional features and varying+dependencies. These conditional dependencies are still specified in a+declarative way however and remain compatible with automatic package+management. The need to remain compatible with automatic package+management means that Cabal's conditional dependencies system is a bit+less flexible than with the "./configure" approach.++### Portability ###++One of the purposes of Cabal is to make it easier to build packages on+different platforms (operating systems and CPU architectures), with+different compiler versions and indeed even with different Haskell+implementations. (Yes, there are Haskell implementations other than+GHC!)++Cabal provides abstractions of features present in different Haskell+implementations and wherever possible it is best to take advantage of+these to increase portability. Where necessary however it is possible to+use specific features of specific implementations.++For example a package author can list in the package's `.cabal` what+language extensions the code uses. This allows Cabal to figure out if+the language extension is supported by the Haskell implementation that+the user picks. Additionally, certain language extensions such as+Template Haskell require special handling from the build system and by+listing the extension it provides the build system with enough+information to do the right thing.++Another similar example is linking with foreign libraries. Rather than+specifying GHC flags directly, the package author can list the libraries+that are needed and the build system will take care of using the right+flags for the compiler. Additionally this makes it easier for tools to+discover what system C libraries a package needs, which is useful for+tracking dependencies on system libraries (e.g. when translating into+Linux distribution packages).++In fact both of these examples fall into the category of explicitly+specifying dependencies. Not all dependencies are other Cabal packages.+Foreign libraries are clearly another kind of dependency. It's also+possible to think of language extensions as dependencies: the package+depends on a Haskell implementation that supports all those extensions.++Where compiler-specific options are needed however, there is an "escape+hatch" available. The developer can specify implementation-specific+options and more generally there is a configuration mechanism to+customise many aspects of how a package is built depending on the+Haskell implementation, the operating system, computer architecture and+user-specified configuration flags.+++# Developing packages #++The Cabal package is the unit of distribution. When installed, its+purpose is to make available:++ * One or more Haskell programs.++ * At most one library, exposing a number of Haskell modules.++However having both a library and executables in a package does not work+very well; if the executables depend on the library, they must+explicitly list all the modules they directly or indirectly import from+that library. Fortunately, starting with Cabal 1.8.0.4, executables can+also declare the package that they are in as a dependency, and Cabal+will treat them as if they were in another package that depended on+the library.++Internally, the package may consist of much more than a bunch of Haskell+modules: it may also have C source code and header files, source code+meant for preprocessing, documentation, test cases, auxiliary tools etc.++A package is identified by a globally-unique _package name_, which+consists of one or more alphanumeric words separated by hyphens. To+avoid ambiguity, each of these words should contain at least one letter.+Chaos will result if two distinct packages with the same name are+installed on the same system. A particular version of the package is+distinguished by a _version number_, consisting of a sequence of one or+more integers separated by dots. These can be combined to form a single+text string called the _package ID_, using a hyphen to separate the name+from the version, e.g. "`HUnit-1.1`".++Note: Packages are not part of the Haskell language; they simply+populate the hierarchical space of module names. In GHC 6.6 and later a+program may contain multiple modules with the same name if they come+from separate packages; in all other current Haskell systems packages+may not overlap in the modules they provide, including hidden modules.+++## Creating a package ##++Suppose you have a directory hierarchy containing the source files that+make up your package. You will need to add two more files to the root+directory of the package:++_package_`.cabal`++: a Unicode UTF-8 text file containing a package description.+ For details of the syntax of this file, see the [section on package+ descriptions](#package-descriptions).++`Setup.hs`++: a single-module Haskell program to perform various setup tasks (with+ the interface described in the section on [building and installing+ packages](installing-packages.html). This module should+ import only modules that will be present in all Haskell+ implementations, including modules of the Cabal library. The+ content of this file is determined by the `build-type` setting in+ the `.cabal` file. In most cases it will be trivial, calling on+ the Cabal library to do most of the work.++Once you have these, you can create a source bundle of this directory+for distribution. Building of the package is discussed in the section on+[building and installing packages](installing-packages.html).++One of the purposes of Cabal is to make it easier to build a package+with different Haskell implementations. So it provides abstractions of+features present in different Haskell implementations and wherever+possible it is best to take advantage of these to increase portability.+Where necessary however it is possible to use specific features of+specific implementations. For example one of the pieces of information a+package author can put in the package's `.cabal` file is what language+extensions the code uses. This is far preferable to specifying flags for+a specific compiler as it allows Cabal to pick the right flags for the+Haskell implementation that the user picks. It also allows Cabal to+figure out if the language extension is even supported by the Haskell+implementation that the user picks. Where compiler-specific options are+needed however, there is an "escape hatch" available. The developer can+specify implementation-specific options and more generally there is a+configuration mechanism to customise many aspects of how a package is+built depending on the Haskell implementation, the Operating system,+computer architecture and user-specified configuration flags.++~~~~~~~~~~~~~~~~+name: Foo+version: 1.0++library+ build-depends: base+ exposed-modules: Foo+ extensions: ForeignFunctionInterface+ ghc-options: -Wall+ if os(windows)+ build-depends: Win32+~~~~~~~~~~~~~~~~++#### Example: A package containing a simple library ####++The HUnit package contains a file `HUnit.cabal` containing:++~~~~~~~~~~~~~~~~+name: HUnit+version: 1.1.1+synopsis: A unit testing framework for Haskell+homepage: http://hunit.sourceforge.net/+category: Testing+author: Dean Herington+license: BSD3+license-file: LICENSE+cabal-version: >= 1.10+build-type: Simple++library+ build-depends: base >= 2 && < 4+ exposed-modules: Test.HUnit.Base, Test.HUnit.Lang,+ Test.HUnit.Terminal, Test.HUnit.Text, Test.HUnit+ default-extensions: CPP+~~~~~~~~~~~~~~~~++and the following `Setup.hs`:++~~~~~~~~~~~~~~~~+import Distribution.Simple+main = defaultMain+~~~~~~~~~~~~~~~~++#### Example: A package containing executable programs ####++~~~~~~~~~~~~~~~~+name: TestPackage+version: 0.0+synopsis: Small package with two programs+author: Angela Author+license: BSD3+build-type: Simple+cabal-version: >= 1.2++executable program1+ build-depends: HUnit+ main-is: Main.hs+ hs-source-dirs: prog1++executable program2+ main-is: Main.hs+ build-depends: HUnit+ hs-source-dirs: prog2+ other-modules: Utils+~~~~~~~~~~~~~~~~++with `Setup.hs` the same as above.++#### Example: A package containing a library and executable programs ####++~~~~~~~~~~~~~~~~+name: TestPackage+version: 0.0+synopsis: Package with library and two programs+license: BSD3+author: Angela Author+build-type: Simple+cabal-version: >= 1.2++library+ build-depends: HUnit+ exposed-modules: A, B, C++executable program1+ main-is: Main.hs+ hs-source-dirs: prog1+ other-modules: A, B++executable program2+ main-is: Main.hs+ hs-source-dirs: prog2+ other-modules: A, C, Utils+~~~~~~~~~~~~~~~~++with `Setup.hs` the same as above. Note that any library modules+required (directly or indirectly) by an executable must be listed again.++The trivial setup script used in these examples uses the _simple build+infrastructure_ provided by the Cabal library (see+[Distribution.Simple][dist-simple]). The simplicity lies in its+interface rather that its implementation. It automatically handles+preprocessing with standard preprocessors, and builds packages for all+the Haskell implementations.++The simple build infrastructure can also handle packages where building+is governed by system-dependent parameters, if you specify a little more+(see the section on [system-dependent+parameters](#system-dependent-parameters)). A few packages require [more+elaborate solutions](#more-complex-packages).++## Package descriptions ##++The package description file must have a name ending in "`.cabal`". It+must be a Unicode text file encoded using valid UTF-8. There must be+exactly one such file in the directory. The first part of the name is+usually the package name, and some of the tools that operate on Cabal+packages require this.++In the package description file, lines whose first non-whitespace characters+are "`--`" are treated as comments and ignored.++This file should contain of a number global property descriptions and+several sections.++* The [global properties](#package-properties) describe the package as a+ whole, such as name, license, author, etc.++* Optionally, a number of _configuration flags_ can be declared. These+ can be used to enable or disable certain features of a package. (see+ the section on [configurations](#configurations)).++* The (optional) library section specifies the [library+ properties](#library) and relevant [build+ information](#build-information).++* Following is an arbitrary number of executable sections+ which describe an executable program and relevant [build+ information](#build-information).++Each section consists of a number of property descriptions+in the form of field/value pairs, with a syntax roughly like mail+message headers.++* Case is not significant in field names, but is significant in field+ values.++* To continue a field value, indent the next line relative to the field+ name.++* Field names may be indented, but all field values in the same section+ must use the same indentation.++* Tabs are *not* allowed as indentation characters due to a missing+ standard interpretation of tab width.++* To get a blank line in a field value, use an indented "`.`"++The syntax of the value depends on the field. Field types include:++_token_, _filename_, _directory_+: Either a sequence of one or more non-space non-comma characters, or+ a quoted string in Haskell 98 lexical syntax. Unless otherwise+ stated, relative filenames and directories are interpreted from the+ package root directory.++_freeform_, _URL_, _address_+: An arbitrary, uninterpreted string.++_identifier_+: A letter followed by zero or more alphanumerics or underscores.++_compiler_+: A compiler flavor (one of: `GHC`, `JHC`, `UHC` or `LHC`) followed by a+ version range. For example, `GHC ==6.10.3`, or `LHC >=0.6 && <0.8`.++### Modules and preprocessors ###++Haskell module names listed in the `exposed-modules` and `other-modules`+fields may correspond to Haskell source files, i.e. with names ending in+"`.hs`" or "`.lhs`", or to inputs for various Haskell preprocessors. The+simple build infrastructure understands the extensions:++* `.gc` ([greencard][])+* `.chs` ([c2hs][])+* `.hsc` (`hsc2hs`)+* `.y` and `.ly` ([happy][])+* `.x` ([alex][])+* `.cpphs` ([cpphs][])++When building, Cabal will automatically run the appropriate preprocessor+and compile the Haskell module it produces.++Some fields take lists of values, which are optionally separated by commas,+except for the `build-depends` field, where the commas are mandatory.++Some fields are marked as required. All others are optional, and unless+otherwise specified have empty default values.++### Package properties ###++These fields may occur in the first top-level properties section and+describe the package as a whole:++`name:` _package-name_ (required)+: The unique name of the package, without the version number.++`version:` _numbers_ (required)+: The package version number, usually consisting of a sequence of+ natural numbers separated by dots.++`cabal-version:` _>= x.y_+: The version of the Cabal specification that this package description uses.+ The Cabal specification does slowly evolve, introducing new features and+ occasionally changing the meaning of existing features. By specifying+ which version of the spec you are using it enables programs which process+ the package description to know what syntax to expect and what each part+ means.++ For historical reasons this is always expressed using _>=_ version range+ syntax. No other kinds of version range make sense, in particular upper+ bounds do not make sense. In future this field will specify just a version+ number, rather than a version range.++ The version number you specify will affect both compatibility and+ behaviour. Most tools (including the Cabal library and cabal program)+ understand a range of versions of the Cabal specification. Older tools+ will of course only work with older versions of the Cabal specification.+ Most of the time, tools that are too old will recognise this fact and+ produce a suitable error message.++ As for behaviour, new versions of the Cabal spec can change the meaning+ of existing syntax. This means if you want to take advantage of the new+ meaning or behaviour then you must specify the newer Cabal version.+ Tools are expected to use the meaning and behaviour appropriate to the+ version given in the package description.++ In particular, the syntax of package descriptions changed significantly+ with Cabal version 1.2 and the `cabal-version` field is now required.+ Files written in the old syntax are still recognized, so if you require+ compatibility with very old Cabal versions then you may write your package+ description file using the old syntax. Please consult the user's guide of+ an older Cabal version for a description of that syntax.++`build-type:` _identifier_+: The type of build used by this package. Build types are the+ constructors of the [BuildType][] type, defaulting to `Custom`.++ If the build type is anything other than `Custom`, then the+ `Setup.hs` file *must* be exactly the standardized content+ discussed below. This is because in these cases, `cabal` will+ ignore the `Setup.hs` file completely, whereas other methods of+ package management, such as `runhaskell Setup.hs [CMD]`, still+ rely on the `Setup.hs` file.++ For build type `Simple`, the contents of `Setup.hs` must be:++ ~~~~~~~~~~~~~~~~+ import Distribution.Simple+ main = defaultMain+ ~~~~~~~~~~~~~~~~++ For build type `Configure` (see the section on [system-dependent+ parameters](#system-dependent-parameters) below), the contents of+ `Setup.hs` must be:++ ~~~~~~~~~~~~~~~~+ import Distribution.Simple+ main = defaultMainWithHooks autoconfUserHooks+ ~~~~~~~~~~~~~~~~++ For build type `Make` (see the section on [more complex+ packages](installing-packages.html#more-complex-packages) below),+ the contents of `Setup.hs` must be:++ ~~~~~~~~~~~~~~~~+ import Distribution.Make+ main = defaultMain+ ~~~~~~~~~~~~~~~~++ For build type `Custom`, the file `Setup.hs` can be customized,+ and will be used both by `cabal` and other tools.++ For most packages, the build type `Simple` is sufficient.++`license:` _identifier_ (default: `AllRightsReserved`)+: The type of license under which this package is distributed.+ License names are the constants of the [License][dist-license] type.++`license-file:` _filename_ or `license-files:` _filename list_+: The name of a file(s) containing the precise copyright license for+ this package. The license file(s) will be installed with the package.++ If you have multiple license files then use the `license-files`+ field instead of (or in addition to) the `license-file` field.++`copyright:` _freeform_+: The content of a copyright notice, typically the name of the holder+ of the copyright on the package and the year(s) from which copyright+ is claimed. For example: `Copyright: (c) 2006-2007 Joe Bloggs`++`author:` _freeform_+: The original author of the package.++ Remember that `.cabal` files are Unicode, using the UTF-8 encoding.++`maintainer:` _address_+: The current maintainer or maintainers of the package. This is an e-mail address to which users should send bug+ reports, feature requests and patches.++`stability:` _freeform_+: The stability level of the package, e.g. `alpha`, `experimental`, `provisional`,+ `stable`.++`homepage:` _URL_+: The package homepage.++`bug-reports:` _URL_+: The URL where users should direct bug reports. This would normally be either:++ * A `mailto:` URL, e.g. for a person or a mailing list.++ * An `http:` (or `https:`) URL for an online bug tracking system.++ For example Cabal itself uses a web-based bug tracking system++ ~~~~~~~~~~~~~~~~+ bug-reports: http://hackage.haskell.org/trac/hackage/+ ~~~~~~~~~~~~~~~~++`package-url:` _URL_+: The location of a source bundle for the package. The distribution+ should be a Cabal package.++`synopsis:` _freeform_+: A very short description of the package, for use in a table of+ packages. This is your headline, so keep it short (one line) but as+ informative as possible. Save space by not including the package+ name or saying it's written in Haskell.++`description:` _freeform_+: Description of the package. This may be several paragraphs, and+ should be aimed at a Haskell programmer who has never heard of your+ package before.++ For library packages, this field is used as prologue text by [`setup+ haddock`](installing-packages.html#setup-haddock), and thus may+ contain the same markup as [haddock][] documentation comments.++`category:` _freeform_+: A classification category for future use by the package catalogue [Hackage]. These+ categories have not yet been specified, but the upper levels of the+ module hierarchy make a good start.++`tested-with:` _compiler list_+: A list of compilers and versions against which the package has been+ tested (or at least built).++`data-files:` _filename list_+: A list of files to be installed for run-time use by the package.+ This is useful for packages that use a large amount of static data,+ such as tables of values or code templates. Cabal provides a way to+ [find these files at+ run-time](#accessing-data-files-from-package-code).++ A limited form of `*` wildcards in file names, for example+ `data-files: images/*.png` matches all the `.png` files in the+ `images` directory.++ The limitation is that `*` wildcards are only allowed in place of+ the file name, not in the directory name or file extension. In+ particular, wildcards do not include directories contents+ recursively. Furthermore, if a wildcard is used it must be used with+ an extension, so `data-files: data/*` is not allowed. When matching+ a wildcard plus extension, a file's full extension must match+ exactly, so `*.gz` matches `foo.gz` but not `foo.tar.gz`. A wildcard+ that does not match any files is an error.++ The reason for providing only a very limited form of wildcard is to+ concisely express the common case of a large number of related files+ of the same file type without making it too easy to accidentally+ include unwanted files.++`data-dir:` _directory_+: The directory where Cabal looks for data files to install, relative+ to the source directory. By default, Cabal will look in the source+ directory itself.++`extra-source-files:` _filename list_+: A list of additional files to be included in source distributions+ built with [`setup sdist`](installing-packages.html#setup-sdist). As+ with `data-files` it can use a limited form of `*` wildcards in file+ names.++`extra-doc-files:` _filename list_+: A list of additional files to be included in source distributions,+ and also copied to the html directory when Haddock documentation is+ generated. As with `data-files` it can use a limited form of `*`+ wildcards in file names.++`extra-tmp-files:` _filename list_+: A list of additional files or directories to be removed by [`setup+ clean`](installing-packages.html#setup-clean). These would typically+ be additional files created by additional hooks, such as the scheme+ described in the section on [system-dependent+ parameters](#system-dependent-parameters).++### Library ###++The library section should contain the following fields:++`exposed-modules:` _identifier list_ (required if this package contains a library)+: A list of modules added by this package.++`exposed:` _boolean_ (default: `True`)+: Some Haskell compilers (notably GHC) support the notion of packages+ being "exposed" or "hidden" which means the modules they provide can+ be easily imported without always having to specify which package+ they come from. However this only works effectively if the modules+ provided by all exposed packages do not overlap (otherwise a module+ import would be ambiguous).++ Almost all new libraries use hierarchical module names that do not+ clash, so it is very uncommon to have to use this field. However it+ may be necessary to set `exposed: False` for some old libraries that+ use a flat module namespace or where it is known that the exposed+ modules would clash with other common modules.++`reexported-modules:` _exportlist _+: Supported only in GHC 7.10 and later. A list of modules to _reexport_ from+ this package. The syntax of this field is `orig-pkg:Name as NewName` to+ reexport module `Name` from `orig-pkg` with the new name `NewName`. We also+ support abbreviated versions of the syntax: if you omit `as NewName`,+ we'll reexport without renaming; if you omit `orig-pkg`, then we will+ automatically figure out which package to reexport from, if it's+ unambiguous.++ Reexported modules are useful for compatibility shims when a package has+ been split into multiple packages, and they have the useful property that+ if a package provides a module, and another package reexports it under+ the same name, these are not considered a conflict (as would be the case+ with a stub module.) They can also be used to resolve name conflicts.++The library section may also contain build information fields (see the+section on [build information](#build-information)).++#### Opening an interpreter session ####++While developing a package, it is often useful to make its code available inside+an interpreter session. This can be done with the `repl` command:++~~~~~~~~~~~~~~~~+cabal repl+~~~~~~~~~~~~~~~~++The name comes from the acronym [REPL], which stands for+"read-eval-print-loop". By default `cabal repl` loads the first component in a+package. If the package contains several named components, the name can be given+as an argument to `repl`. The name can be also optionally prefixed with the+component's type for disambiguation purposes. Example:++~~~~~~~~~~~~~~~~+cabal repl foo+cabal repl exe:foo+cabal repl test:bar+cabal repl bench:baz+~~~~~~~~~~~~~~~~++#### Freezing dependency versions ####++If a package is built in several different environments, such as a development+environment, a staging environment and a production environment, it may be+necessary or desirable to ensure that the same dependency versions are+selected in each environment. This can be done with the `freeze` command:++~~~~~~~~~~~~~~~~+cabal freeze+~~~~~~~~~~~~~~~~++The command writes the selected version for all dependencies to the+`cabal.config` file. All environments which share this file will use the+dependency versions specified in it.++### Executables ###++Executable sections (if present) describe executable programs contained+in the package and must have an argument after the section label, which+defines the name of the executable. This is a freeform argument but may+not contain spaces.++The executable may be described using the following fields, as well as+build information fields (see the section on [build+information](#build-information)).++`main-is:` _filename_ (required)+: The name of the `.hs` or `.lhs` file containing the `Main` module. Note that it is the+ `.hs` filename that must be listed, even if that file is generated+ using a preprocessor. The source file must be relative to one of the+ directories listed in `hs-source-dirs`.++#### Running executables ####++You can have Cabal build and run your executables by using the `run` command:++~~~~~~~~~~~~~~~~+$ cabal run EXECUTABLE [-- EXECUTABLE_FLAGS]+~~~~~~~~~~~~~~~~++This command will configure, build and run the executable `EXECUTABLE`. The+double dash separator is required to distinguish executable flags from `run`'s+own flags. If there is only one executable defined in the whole package, the+executable's name can be omitted. See the output of `cabal help run` for a list+of options you can pass to `cabal run`.+++### Test suites ###++Test suite sections (if present) describe package test suites and must have an+argument after the section label, which defines the name of the test suite.+This is a freeform argument, but may not contain spaces. It should be unique+among the names of the package's other test suites, the package's executables,+and the package itself. Using test suite sections requires at least Cabal+version 1.9.2.++The test suite may be described using the following fields, as well as build+information fields (see the section on [build+information](#build-information)).++`type:` _interface_ (required)+: The interface type and version of the test suite. Cabal supports two test+ suite interfaces, called `exitcode-stdio-1.0` and `detailed-0.9`. Each of+ these types may require or disallow other fields as described below.++Test suites using the `exitcode-stdio-1.0` interface are executables+that indicate test failure with a non-zero exit code when run; they may provide+human-readable log information through the standard output and error channels.+This interface is provided primarily for compatibility with existing test+suites; it is preferred that new test suites be written for the `detailed-0.9`+interface. The `exitcode-stdio-1.0` type requires the `main-is` field.++`main-is:` _filename_ (required: `exitcode-stdio-1.0`, disallowed: `detailed-0.9`)+: The name of the `.hs` or `.lhs` file containing the `Main` module. Note that it is the+ `.hs` filename that must be listed, even if that file is generated+ using a preprocessor. The source file must be relative to one of the+ directories listed in `hs-source-dirs`. This field is analogous to the+ `main-is` field of an executable section.++Test suites using the `detailed-0.9` interface are modules exporting the symbol+`tests :: IO [Test]`. The `Test` type is exported by the module+`Distribution.TestSuite` provided by Cabal. For more details, see the example below.++The `detailed-0.9` interface allows Cabal and other test agents to inspect a+test suite's results case by case, producing detailed human- and+machine-readable log files. The `detailed-0.9` interface requires the+`test-module` field.++`test-module:` _identifier_ (required: `detailed-0.9`, disallowed: `exitcode-stdio-1.0`)+: The module exporting the `tests` symbol.++#### Example: Package using `exitcode-stdio-1.0` interface ####++The example package description and executable source file below demonstrate+the use of the `exitcode-stdio-1.0` interface. For brevity, the example package+does not include a library or any normal executables, but a real package would+be required to have at least one library or executable.++foo.cabal:++~~~~~~~~~~~~~~~~+Name: foo+Version: 1.0+License: BSD3+Cabal-Version: >= 1.9.2+Build-Type: Simple++Test-Suite test-foo+ type: exitcode-stdio-1.0+ main-is: test-foo.hs+ build-depends: base+~~~~~~~~~~~~~~~~++test-foo.hs:++~~~~~~~~~~~~~~~~+module Main where++import System.Exit (exitFailure)++main = do+ putStrLn "This test always fails!"+ exitFailure+~~~~~~~~~~~~~~~~++#### Example: Package using `detailed-0.9` interface ####++The example package description and test module source file below demonstrate+the use of the `detailed-0.9` interface. For brevity, the example package does+note include a library or any normal executables, but a real package would be+required to have at least one library or executable. The test module below+also develops a simple implementation of the interface set by+`Distribution.TestSuite`, but in actual usage the implementation would be+provided by the library that provides the testing facility.++bar.cabal:++~~~~~~~~~~~~~~~~+Name: bar+Version: 1.0+License: BSD3+Cabal-Version: >= 1.9.2+Build-Type: Simple++Test-Suite test-bar+ type: detailed-0.9+ test-module: Bar+ build-depends: base, Cabal >= 1.9.2+~~~~~~~~~~~~~~~~++Bar.hs:++~~~~~~~~~~~~~~~~+module Bar ( tests ) where++import Distribution.TestSuite++tests :: IO [Test]+tests = return [ Test succeeds, Test fails ]+ where+ succeeds = TestInstance+ { run = return $ Finished Pass+ , name = "succeeds"+ , tags = []+ , options = []+ , setOption = \_ _ -> Right succeeds+ }+ fails = TestInstance+ { run = return $ Finished $ Fail "Always fails!"+ , name = "fails"+ , tags = []+ , options = []+ , setOption = \_ _ -> Right fails+ }+~~~~~~~~~~~~~~~~++#### Running test suites ####++You can have Cabal run your test suites using its built-in test+runner:++~~~~~~~~~~~~~~~~+$ cabal configure --enable-tests+$ cabal build+$ cabal test+~~~~~~~~~~~~~~~~++See the output of `cabal help test` for a list of options you can pass+to `cabal test`.++### Benchmarks ###++Benchmark sections (if present) describe benchmarks contained in the package and+must have an argument after the section label, which defines the name of the+benchmark. This is a freeform argument, but may not contain spaces. It should+be unique among the names of the package's other benchmarks, the package's test+suites, the package's executables, and the package itself. Using benchmark+sections requires at least Cabal version 1.9.2.++The benchmark may be described using the following fields, as well as build+information fields (see the section on [build information](#build-information)).++`type:` _interface_ (required)+: The interface type and version of the benchmark. At the moment Cabal only+ support one benchmark interface, called `exitcode-stdio-1.0`.++Benchmarks using the `exitcode-stdio-1.0` interface are executables that+indicate failure to run the benchmark with a non-zero exit code when run; they+may provide human-readable information through the standard output and error+channels.++`main-is:` _filename_ (required: `exitcode-stdio-1.0`)+: The name of the `.hs` or `.lhs` file containing the `Main` module. Note that+ it is the `.hs` filename that must be listed, even if that file is generated+ using a preprocessor. The source file must be relative to one of the+ directories listed in `hs-source-dirs`. This field is analogous to the+ `main-is` field of an executable section.++#### Example: Package using `exitcode-stdio-1.0` interface ####++The example package description and executable source file below demonstrate+the use of the `exitcode-stdio-1.0` interface. For brevity, the example package+does not include a library or any normal executables, but a real package would+be required to have at least one library or executable.++foo.cabal:++~~~~~~~~~~~~~~~~+Name: foo+Version: 1.0+License: BSD3+Cabal-Version: >= 1.9.2+Build-Type: Simple++Benchmark bench-foo+ type: exitcode-stdio-1.0+ main-is: bench-foo.hs+ build-depends: base, time+~~~~~~~~~~~~~~~~++bench-foo.hs:++~~~~~~~~~~~~~~~~+{-# LANGUAGE BangPatterns #-}+module Main where++import Data.Time.Clock++fib 0 = 1+fib 1 = 1+fib n = fib (n-1) + fib (n-2)++main = do+ start <- getCurrentTime+ let !r = fib 20+ end <- getCurrentTime+ putStrLn $ "fib 20 took " ++ show (diffUTCTime end start)+~~~~~~~~~~~~~~~~++#### Running benchmarks ####++You can have Cabal run your benchmark using its built-in benchmark runner:++~~~~~~~~~~~~~~~~+$ cabal configure --enable-benchmarks+$ cabal build+$ cabal bench+~~~~~~~~~~~~~~~~++See the output of `cabal help bench` for a list of options you can+pass to `cabal bench`.++### Build information ###++The following fields may be optionally present in a library or+executable section, and give information for the building of the+corresponding library or executable. See also the sections on+[system-dependent parameters](#system-dependent-parameters) and+[configurations](#configurations) for a way to supply system-dependent+values for these fields.++`build-depends:` _package list_+: A list of packages needed to build this one. Each package can be+ annotated with a version constraint.++ Version constraints use the operators `==, >=, >, <, <=` and a+ version number. Multiple constraints can be combined using `&&` or+ `||`. If no version constraint is specified, any version is assumed+ to be acceptable. For example:++ ~~~~~~~~~~~~~~~~+ library+ build-depends:+ base >= 2,+ foo >= 1.2 && < 1.3,+ bar+ ~~~~~~~~~~~~~~~~++ Dependencies like `foo >= 1.2 && < 1.3` turn out to be very common+ because it is recommended practise for package versions to+ correspond to API versions. As of Cabal 1.6, there is a special+ syntax to support this use:++ ~~~~~~~~~~~~~~~~+ build-depends: foo ==1.2.*+ ~~~~~~~~~~~~~~~~++ It is only syntactic sugar. It is exactly equivalent to `foo >= 1.2 && < 1.3`.++ With Cabal 1.20 and GHC 7.10, `build-depends` also supports module+ thinning and renaming, which allows you to selectively decide what+ modules become visible from a package dependency. For example:++ ~~~~~~~~~~~~~~~~+ build-depends: containers (Data.Set, Data.IntMap as Map)+ ~~~~~~~~~~~~~~~~++ This results in only the modules `Data.Set` and `Map` being visible to+ the user from containers, hiding all other modules. To add additional+ names for modules without hiding the others, you can use the `with`+ keyword:++ ~~~~~~~~~~~~~~~~+ build-depends: containers with (Data.IntMap as Map)+ ~~~~~~~~~~~~~~~~++ Note: Prior to Cabal 1.8, build-depends specified in each section+ were global to all sections. This was unintentional, but some packages+ were written to depend on it, so if you need your build-depends to+ be local to each section, you must specify at least+ `Cabal-Version: >= 1.8` in your `.cabal` file.++`other-modules:` _identifier list_+: A list of modules used by the component but not exposed to users.+ For a library component, these would be hidden modules of the+ library. For an executable, these would be auxiliary modules to be+ linked with the file named in the `main-is` field.++ Note: Every module in the package *must* be listed in one of+ `other-modules`, `exposed-modules` or `main-is` fields.++`hs-source-dirs:` _directory list_ (default: "`.`")+: Root directories for the module hierarchy.++ For backwards compatibility, the old variant `hs-source-dir` is also+ recognized.++`extensions:` _identifier list_+: A list of Haskell extensions used by every module. Extension names+ are the constructors of the [Extension][extension] type. These+ determine corresponding compiler options. In particular, `CPP` specifies that+ Haskell source files are to be preprocessed with a C preprocessor.++ Extensions used only by one module may be specified by placing a+ `LANGUAGE` pragma in the source file affected, e.g.:++ ~~~~~~~~~~~~~~~~+ {-# LANGUAGE CPP, MultiParamTypeClasses #-}+ ~~~~~~~~~~~~~~~~++ Note: GHC versions prior to 6.6 do not support the `LANGUAGE` pragma.++`build-tools:` _program list_+: A list of programs, possibly annotated with versions, needed to+ build this package, e.g. `c2hs >= 0.15, cpphs`.If no version+ constraint is specified, any version is assumed to be acceptable.++`buildable:` _boolean_ (default: `True`)+: Is the component buildable? Like some of the other fields below,+ this field is more useful with the slightly more elaborate form of+ the simple build infrastructure described in the section on+ [system-dependent parameters](#system-dependent-parameters).++`ghc-options:` _token list_+: Additional options for GHC. You can often achieve the same effect+ using the `extensions` field, which is preferred.++ Options required only by one module may be specified by placing an+ `OPTIONS_GHC` pragma in the source file affected.++`ghc-prof-options:` _token list_+: Additional options for GHC when the package is built with profiling+ enabled.++`ghc-shared-options:` _token list_+: Additional options for GHC when the package is built as shared library.++`includes:` _filename list_+: A list of header files to be included in any compilations via C.+ This field applies to both header files that are already installed+ on the system and to those coming with the package to be installed.+ These files typically contain function prototypes for foreign+ imports used by the package.++`install-includes:` _filename list_+: A list of header files from this package to be installed into+ `$libdir/includes` when the package is installed. Files listed in+ `install-includes:` should be found in relative to the top of the+ source tree or relative to one of the directories listed in+ `include-dirs`.++ `install-includes` is typically used to name header files that+ contain prototypes for foreign imports used in Haskell code in this+ package, for which the C implementations are also provided with the+ package. Note that to include them when compiling the package+ itself, they need to be listed in the `includes:` field as well.++`include-dirs:` _directory list_+: A list of directories to search for header files, when preprocessing+ with `c2hs`, `hsc2hs`, `cpphs` or the C preprocessor, and+ also when compiling via C.++`c-sources:` _filename list_+: A list of C source files to be compiled and linked with the Haskell files.++`js-sources:` _filename list_+: A list of JavaScript source files to be linked with the Haskell files+ (only for JavaScript targets).++`extra-libraries:` _token list_+: A list of extra libraries to link with.++`extra-ghci-libraries:` _token list_+: A list of extra libraries to be used instead of 'extra-libraries' when+ the package is loaded with GHCi.++`extra-lib-dirs:` _directory list_+: A list of directories to search for libraries.++`cc-options:` _token list_+: Command-line arguments to be passed to the C compiler. Since the+ arguments are compiler-dependent, this field is more useful with the+ setup described in the section on [system-dependent+ parameters](#system-dependent-parameters).++`cpp-options:` _token list_+: Command-line arguments for pre-processing Haskell code. Applies to+ haskell source and other pre-processed Haskell source like .hsc .chs.+ Does not apply to C code, that's what cc-options is for.++`ld-options:` _token list_+: Command-line arguments to be passed to the linker. Since the+ arguments are compiler-dependent, this field is more useful with the+ setup described in the section on [system-dependent+ parameters](#system-dependent-parameters)>.++`pkgconfig-depends:` _package list_+: A list of [pkg-config][] packages, needed to build this package.+ They can be annotated with versions, e.g. `gtk+-2.0 >= 2.10, cairo+ >= 1.0`. If no version constraint is specified, any version is+ assumed to be acceptable. Cabal uses `pkg-config` to find if the+ packages are available on the system and to find the extra+ compilation and linker options needed to use the packages.++ If you need to bind to a C library that supports `pkg-config` (use+ `pkg-config --list-all` to find out if it is supported) then it is+ much preferable to use this field rather than hard code options into+ the other fields.++`frameworks:` _token list_+: On Darwin/MacOS X, a list of frameworks to link to. See Apple's+ developer documentation for more details on frameworks. This entry+ is ignored on all other platforms.++### Configurations ###++Library and executable sections may include conditional+blocks, which test for various system parameters and+configuration flags. The flags mechanism is rather generic,+but most of the time a flag represents certain feature, that+can be switched on or off by the package user.+Here is an example package description file using+configurations:++#### Example: A package containing a library and executable programs ####++~~~~~~~~~~~~~~~~+Name: Test1+Version: 0.0.1+Cabal-Version: >= 1.2+License: BSD3+Author: Jane Doe+Synopsis: Test package to test configurations+Category: Example++Flag Debug+ Description: Enable debug support+ Default: False++Flag WebFrontend+ Description: Include API for web frontend.+ -- Cabal checks if the configuration is possible, first+ -- with this flag set to True and if not it tries with False++Library+ Build-Depends: base+ Exposed-Modules: Testing.Test1+ Extensions: CPP++ if flag(debug)+ GHC-Options: -DDEBUG+ if !os(windows)+ CC-Options: "-DDEBUG"+ else+ CC-Options: "-DNDEBUG"++ if flag(webfrontend)+ Build-Depends: cgi > 0.42+ Other-Modules: Testing.WebStuff++Executable test1+ Main-is: T1.hs+ Other-Modules: Testing.Test1+ Build-Depends: base++ if flag(debug)+ CC-Options: "-DDEBUG"+ GHC-Options: -DDEBUG+~~~~~~~~~~~~~~~~++#### Layout ####++Flags, conditionals, library and executable sections use layout to+indicate structure. This is very similar to the Haskell layout rule.+Entries in a section have to all be indented to the same level which+must be more than the section header. Tabs are not allowed to be used+for indentation.++As an alternative to using layout you can also use explicit braces `{}`.+In this case the indentation of entries in a section does not matter,+though different fields within a block must be on different lines. Here+is a bit of the above example again, using braces:++#### Example: Using explicit braces rather than indentation for layout ####++~~~~~~~~~~~~~~~~+Name: Test1+Version: 0.0.1+Cabal-Version: >= 1.2+License: BSD3+Author: Jane Doe+Synopsis: Test package to test configurations+Category: Example++Flag Debug {+ Description: Enable debug support+ Default: False+}++Library {+ Build-Depends: base+ Exposed-Modules: Testing.Test1+ Extensions: CPP+ if flag(debug) {+ GHC-Options: -DDEBUG+ if !os(windows) {+ CC-Options: "-DDEBUG"+ } else {+ CC-Options: "-DNDEBUG"+ }+ }+}+~~~~~~~~~~~~~~~~++#### Configuration Flags ####++A flag section takes the flag name as an argument and may contain the+following fields.++`description:` _freeform_+: The description of this flag.++`default:` _boolean_ (default: `True`)+: The default value of this flag.++ Note that this value may be [overridden in several+ ways](installing-packages.html#controlling-flag-assignments"). The+ rationale for having flags default to True is that users usually+ want new features as soon as they are available. Flags representing+ features that are not (yet) recommended for most users (such as+ experimental features or debugging support) should therefore+ explicitly override the default to False.++`manual:` _boolean_ (default: `False`)+: By default, Cabal will first try to satisfy dependencies with the+ default flag value and then, if that is not possible, with the+ negated value. However, if the flag is manual, then the default+ value (which can be overridden by commandline flags) will be used.++#### Conditional Blocks ####++Conditional blocks may appear anywhere inside a library or executable+section. They have to follow rather strict formatting rules.+Conditional blocks must always be of the shape++~~~~~~~~~~~~~~~~+ `if `_condition_+ _property-descriptions-or-conditionals*_+~~~~~~~~~~~~~~~~++or++~~~~~~~~~~~~~~~~+ `if `_condition_+ _property-descriptions-or-conditionals*_+ `else`+ _property-descriptions-or-conditionals*_+~~~~~~~~~~~~~~~~++Note that the `if` and the condition have to be all on the same line.++#### Conditions ####++Conditions can be formed using boolean tests and the boolean operators+`||` (disjunction / logical "or"), `&&` (conjunction / logical "and"),+or `!` (negation / logical "not"). The unary `!` takes highest+precedence, `||` takes lowest. Precedence levels may be overridden+through the use of parentheses. For example, `os(darwin) && !arch(i386)+|| os(freebsd)` is equivalent to `(os(darwin) && !(arch(i386))) ||+os(freebsd)`.++The following tests are currently supported.++`os(`_name_`)`+: Tests if the current operating system is _name_. The argument is+ tested against `System.Info.os` on the target system. There is+ unfortunately some disagreement between Haskell implementations+ about the standard values of `System.Info.os`. Cabal canonicalises+ it so that in particular `os(windows)` works on all implementations.+ If the canonicalised os names match, this test evaluates to true,+ otherwise false. The match is case-insensitive.++`arch(`_name_`)`+: Tests if the current architecture is _name_. The argument is+ matched against `System.Info.arch` on the target system. If the arch+ names match, this test evaluates to true, otherwise false. The match+ is case-insensitive.++`impl(`_compiler_`)`+: Tests for the configured Haskell implementation. An optional version+ constraint may be specified (for example `impl(ghc >= 6.6.1)`). If+ the configured implementation is of the right type and matches the+ version constraint, then this evaluates to true, otherwise false.+ The match is case-insensitive.++`flag(`_name_`)`+: Evaluates to the current assignment of the flag of the given name.+ Flag names are case insensitive. Testing for flags that have not+ been introduced with a flag section is an error.++`true`+: Constant value true.++`false`+: Constant value false.++#### Resolution of Conditions and Flags ####++If a package descriptions specifies configuration flags the package user can+[control these in several ways](installing-packages.html#controlling-flag-assignments).+If the user does not fix the value of a flag, Cabal will try to find a flag+assignment in the following way.++ * For each flag specified, it will assign its default value, evaluate+ all conditions with this flag assignment, and check if all+ dependencies can be satisfied. If this check succeeded, the package+ will be configured with those flag assignments.++ * If dependencies were missing, the last flag (as by the order in+ which the flags were introduced in the package description) is tried+ with its alternative value and so on. This continues until either+ an assignment is found where all dependencies can be satisfied, or+ all possible flag assignments have been tried.++To put it another way, Cabal does a complete backtracking search to find+a satisfiable package configuration. It is only the dependencies+specified in the `build-depends` field in conditional blocks that+determine if a particular flag assignment is satisfiable (`build-tools`+are not considered). The order of the declaration and the default value+of the flags determines the search order. Flags overridden on the+command line fix the assignment of that flag, so no backtracking will be+tried for that flag.++If no suitable flag assignment could be found, the configuration phase+will fail and a list of missing dependencies will be printed. Note that+this resolution process is exponential in the worst case (i.e., in the+case where dependencies cannot be satisfied). There are some+optimizations applied internally, but the overall complexity remains+unchanged.++### Meaning of field values when using conditionals ###++During the configuration phase, a flag assignment is chosen, all+conditionals are evaluated, and the package description is combined into+a flat package descriptions. If the same field both inside a conditional+and outside then they are combined using the following rules.+++ * Boolean fields are combined using conjunction (logical "and").++ * List fields are combined by appending the inner items to the outer+ items, for example++ ~~~~~~~~~~~~~~~~+ Extensions: CPP+ if impl(ghc)+ Extensions: MultiParamTypeClasses+ ~~~~~~~~~~~~~~~~++ when compiled using GHC will be combined to++ ~~~~~~~~~~~~~~~~+ Extensions: CPP, MultiParamTypeClasses+ ~~~~~~~~~~~~~~~~++ Similarly, if two conditional sections appear at the same nesting+ level, properties specified in the latter will come after properties+ specified in the former.++ * All other fields must not be specified in ambiguous ways. For+ example++ ~~~~~~~~~~~~~~~~+ Main-is: Main.hs+ if flag(useothermain)+ Main-is: OtherMain.hs+ ~~~~~~~~~~~~~~~~++ will lead to an error. Instead use++ ~~~~~~~~~~~~~~~~+ if flag(useothermain)+ Main-is: OtherMain.hs+ else+ Main-is: Main.hs+ ~~~~~~~~~~~~~~~~++### Source Repositories ###++It is often useful to be able to specify a source revision control+repository for a package. Cabal lets you specifying this information in+a relatively structured form which enables other tools to interpret and+make effective use of the information. For example the information+should be sufficient for an automatic tool to checkout the sources.++Cabal supports specifying different information for various common+source control systems. Obviously not all automated tools will support+all source control systems.++Cabal supports specifying repositories for different use cases. By+declaring which case we mean automated tools can be more useful. There+are currently two kinds defined:++ * The `head` kind refers to the latest development branch of the+ package. This may be used for example to track activity of a project+ or as an indication to outside developers what sources to get for+ making new contributions.++ * The `this` kind refers to the branch and tag of a repository that+ contains the sources for this version or release of a package. For most+ source control systems this involves specifying a tag, id or hash of+ some form and perhaps a branch. The purpose is to be able to+ reconstruct the sources corresponding to a particular package+ version. This might be used to indicate what sources to get if+ someone needs to fix a bug in an older branch that is no longer an+ active head branch.++You can specify one kind or the other or both. As an example here are+the repositories for the Cabal library. Note that the `this` kind of+repository specifies a tag.++~~~~~~~~~~~~~~~~+source-repository head+ type: darcs+ location: http://darcs.haskell.org/cabal/++source-repository this+ type: darcs+ location: http://darcs.haskell.org/cabal-branches/cabal-1.6/+ tag: 1.6.1+~~~~~~~~~~~~~~~~++The exact fields are as follows:++`type:` _token_+: The name of the source control system used for this repository. The+ currently recognised types are:++ * `darcs`+ * `git`+ * `svn`+ * `cvs`+ * `mercurial` (or alias `hg`)+ * `bazaar` (or alias `bzr`)+ * `arch`+ * `monotone`++ This field is required.++`location:` _URL_+: The location of the repository. The exact form of this field depends+ on the repository type. For example:++ * for darcs: `http://code.haskell.org/foo/`+ * for git: `git://github.com/foo/bar.git`+ * for CVS: `anoncvs@cvs.foo.org:/cvs`++ This field is required.++`module:` _token_+: CVS requires a named module, as each CVS server can host multiple+ named repositories.++ This field is required for the CVS repository type and should not+ be used otherwise.++`branch:` _token_+: Many source control systems support the notion of a branch, as a+ distinct concept from having repositories in separate locations. For+ example CVS, SVN and git use branches while for darcs uses different+ locations for different branches. If you need to specify a branch to+ identify a your repository then specify it in this field.++ This field is optional.++`tag:` _token_+: A tag identifies a particular state of a source repository. The tag+ can be used with a `this` repository kind to identify the state of+ a repository corresponding to a particular package version or+ release. The exact form of the tag depends on the repository type.++ This field is required for the `this` repository kind.++`subdir:` _directory_+: Some projects put the sources for multiple packages under a single+ source repository. This field lets you specify the relative path+ from the root of the repository to the top directory for the+ package, i.e. the directory containing the package's `.cabal` file.++ This field is optional. It default to empty which corresponds to the+ root directory of the repository.++### Downloading a package's source ###++The `cabal get` command allows to access a package's source code - either by+unpacking a tarball downloaded from Hackage (the default) or by checking out a+working copy from the package's source repository.++~~~~~~~~~~~~~~~~+$ cabal get [FLAGS] PACKAGES+~~~~~~~~~~~~~~~~++The `get` command supports the following options:++`-d --destdir` _PATH_+: Where to place the package source, defaults to (a subdirectory of) the+ current directory.++`-s --source-repository` _[head|this|...]_+: Fork the package's source repository using the appropriate version control+ system. The optional argument allows to choose a specific repository kind.+++## Accessing data files from package code ##++The placement on the target system of files listed in the `data-files`+field varies between systems, and in some cases one can even move+packages around after installation (see [prefix+independence](installing-packages.html#prefix-independence)). To enable+packages to find these files in a portable way, Cabal generates a module+called `Paths_`_pkgname_ (with any hyphens in _pkgname_ replaced by+underscores) during building, so that it may be imported by modules of+the package. This module defines a function++~~~~~~~~~~~~~~~+getDataFileName :: FilePath -> IO FilePath+~~~~~~~~~~~~~~~++If the argument is a filename listed in the `data-files` field, the+result is the name of the corresponding file on the system on which the+program is running.++Note: If you decide to import the `Paths_`_pkgname_ module then it+*must* be listed in the `other-modules` field just like any other module+in your package.++The `Paths_`_pkgname_ module is not platform independent so it does not+get included in the source tarballs generated by `sdist`.++### Accessing the package version ###++The aforementioned auto generated `Paths_`_pkgname_ module also+exports the constant `version ::` [Version][data-version] which is+defined as the version of your package as specified in the `version`+field.++## System-dependent parameters ##++For some packages, especially those interfacing with C libraries,+implementation details and the build procedure depend on the build+environment. The `build-type` `Configure` can be used to handle many+such situations. In this case, `Setup.hs` should be:++~~~~~~~~~~~~~~~~+import Distribution.Simple+main = defaultMainWithHooks autoconfUserHooks+~~~~~~~~~~~~~~~~++Most packages, however, would probably do better using the `Simple`+build type and [configurations](#configurations).++The `build-type` `Configure` differs from `Simple` in two ways:++* The package root directory must contain a shell script called+ `configure`. The configure step will run the script. This `configure`+ script may be produced by [autoconf][] or may be hand-written. The+ `configure` script typically discovers information about the system+ and records it for later steps, e.g. by generating system-dependent+ header files for inclusion in C source files and preprocessed Haskell+ source files. (Clearly this won't work for Windows without MSYS or+ Cygwin: other ideas are needed.)++* If the package root directory contains a file called+ _package_`.buildinfo` after the configuration step, subsequent steps+ will read it to obtain additional settings for [build+ information](#build-information) fields,to be merged with the ones+ given in the `.cabal` file. In particular, this file may be generated+ by the `configure` script mentioned above, allowing these settings to+ vary depending on the build environment.++ The build information file should have the following structure:++ > _buildinfo_+ >+ > `executable:` _name_+ > _buildinfo_+ >+ > `executable:` _name_+ > _buildinfo_+ > ...++ where each _buildinfo_ consists of settings of fields listed in the+ section on [build information](#build-information). The first one (if+ present) relates to the library, while each of the others relate to+ the named executable. (The names must match the package description,+ but you don't have to have entries for all of them.)++Neither of these files is required. If they are absent, this setup+script is equivalent to `defaultMain`.++#### Example: Using autoconf ####++This example is for people familiar with the [autoconf][] tools.++In the X11 package, the file `configure.ac` contains:++~~~~~~~~~~~~~~~~+AC_INIT([Haskell X11 package], [1.1], [libraries@haskell.org], [X11])++# Safety check: Ensure that we are in the correct source directory.+AC_CONFIG_SRCDIR([X11.cabal])++# Header file to place defines in+AC_CONFIG_HEADERS([include/HsX11Config.h])++# Check for X11 include paths and libraries+AC_PATH_XTRA+AC_TRY_CPP([#include <X11/Xlib.h>],,[no_x=yes])++# Build the package if we found X11 stuff+if test "$no_x" = yes+then BUILD_PACKAGE_BOOL=False+else BUILD_PACKAGE_BOOL=True+fi+AC_SUBST([BUILD_PACKAGE_BOOL])++AC_CONFIG_FILES([X11.buildinfo])+AC_OUTPUT+~~~~~~~~~~~~~~~~++Then the setup script will run the `configure` script, which checks for+the presence of the X11 libraries and substitutes for variables in the+file `X11.buildinfo.in`:++~~~~~~~~~~~~~~~~+buildable: @BUILD_PACKAGE_BOOL@+cc-options: @X_CFLAGS@+ld-options: @X_LIBS@+~~~~~~~~~~~~~~~~++This generates a file `X11.buildinfo` supplying the parameters needed by+later stages:++~~~~~~~~~~~~~~~~+buildable: True+cc-options: -I/usr/X11R6/include+ld-options: -L/usr/X11R6/lib+~~~~~~~~~~~~~~~~++The `configure` script also generates a header file `include/HsX11Config.h`+containing C preprocessor defines recording the results of various tests. This+file may be included by C source files and preprocessed Haskell source files in+the package.++Note: Packages using these features will also need to list additional files such+as `configure`, templates for `.buildinfo` files, files named only in+`.buildinfo` files, header files and so on in the `extra-source-files` field to+ensure that they are included in source distributions. They should also list+files and directories generated by `configure` in the `extra-tmp-files` field to+ensure that they are removed by `setup clean`.++Quite often the files generated by `configure` need to be listed somewhere in+the package description (for example, in the `install-includes` field). However,+we usually don't want generated files to be included in the source tarball. The+solution is again provided by the `.buildinfo` file. In the above example, the+following line should be added to `X11.buildinfo`:++~~~~~~~~~~~~~~~~+install-includes: HsX11Config.h+~~~~~~~~~~~~~~~~++In this way, the generated `HsX11Config.h` file won't be included in the source+tarball in addition to `HsX11Config.h.in`, but it will be copied to the right+location during the install process. Packages that use custom `Setup.hs` scripts+can update the necessary fields programmatically instead of using the+`.buildinfo` file.+++## Conditional compilation ##++Sometimes you want to write code that works with more than one version+of a dependency. You can specify a range of versions for the dependency+in the `build-depends`, but how do you then write the code that can use+different versions of the API?++Haskell lets you preprocess your code using the C preprocessor (either+the real C preprocessor, or `cpphs`). To enable this, add `extensions:+CPP` to your package description. When using CPP, Cabal provides some+pre-defined macros to let you test the version of dependent packages;+for example, suppose your package works with either version 3 or version+4 of the `base` package, you could select the available version in your+Haskell modules like this:++~~~~~~~~~~~~~~~~+#if MIN_VERSION_base(4,0,0)+... code that works with base-4 ...+#else+... code that works with base-3 ...+#endif+~~~~~~~~~~~~~~~~++In general, Cabal supplies a macro `MIN_VERSION_`_`package`_`_(A,B,C)`+for each package depended on via `build-depends`. This macro is true if+the actual version of the package in use is greater than or equal to+`A.B.C` (using the conventional ordering on version numbers, which is+lexicographic on the sequence, but numeric on each component, so for+example 1.2.0 is greater than 1.0.3).++Since version 1.20, there is also the `MIN_TOOL_VERSION_`_`tool`_ family of+macros for conditioning on the version of build tools used to build the program+(e.g. `hsc2hs`).++Cabal places the definitions of these macros into an+automatically-generated header file, which is included when+preprocessing Haskell source code by passing options to the C+preprocessor.++Cabal also allows to detect when the source code is being used for generating+documentation. The `__HADDOCK_VERSION__` macro is defined only when compiling+via [haddock][] instead of a normal Haskell compiler. The value of the+`__HADDOCK_VERSION__` macro is defined as `A*1000 + B*10 + C`, where `A.B.C` is+the Haddock version. This can be useful for working around bugs in Haddock or+generating prettier documentation in some special cases.++## More complex packages ##++For packages that don't fit the simple schemes described above, you have+a few options:++ * By using the `build-type` `Custom`, you can supply your own+ `Setup.hs` file, and customize the simple build infrastructure+ using _hooks_. These allow you to perform additional actions+ before and after each command is run, and also to specify+ additional preprocessors. A typical `Setup.hs` may look like this:++ ~~~~~~~~~~~~~~~~+ import Distribution.Simple+ main = defaultMainWithHooks simpleUserHooks { postHaddock = posthaddock }++ posthaddock args flags desc info = ....+ ~~~~~~~~~~~~~~~~++ See `UserHooks` in [Distribution.Simple][dist-simple] for the+ details, but note that this interface is experimental, and likely+ to change in future releases.++ * You could delegate all the work to `make`, though this is unlikely+ to be very portable. Cabal supports this with the `build-type`+ `Make` and a trivial setup library [Distribution.Make][dist-make],+ which simply parses the command line arguments and invokes `make`.+ Here `Setup.hs` should look like this:++ ~~~~~~~~~~~~~~~~+ import Distribution.Make+ main = defaultMain+ ~~~~~~~~~~~~~~~~++ The root directory of the package should contain a `configure`+ script, and, after that has run, a `Makefile` with a default target+ that builds the package, plus targets `install`, `register`,+ `unregister`, `clean`, `dist` and `docs`. Some options to commands+ are passed through as follows:++ * The `--with-hc-pkg`, `--prefix`, `--bindir`, `--libdir`, `--datadir`,+ `--libexecdir` and `--sysconfdir` options to the `configure` command are+ passed on to the `configure` script. In addition the value of the+ `--with-compiler` option is passed in a `--with-hc` option and all+ options specified with `--configure-option=` are passed on.++ * The `--destdir` option to the `copy` command becomes a setting+ of a `destdir` variable on the invocation of `make copy`. The+ supplied `Makefile` should provide a `copy` target, which will+ probably look like this:++ ~~~~~~~~~~~~~~~~+ copy :+ $(MAKE) install prefix=$(destdir)/$(prefix) \+ bindir=$(destdir)/$(bindir) \+ libdir=$(destdir)/$(libdir) \+ datadir=$(destdir)/$(datadir) \+ libexecdir=$(destdir)/$(libexecdir) \+ sysconfdir=$(destdir)/$(sysconfdir) \+ ~~~~~~~~~~~~~~~~++ * Finally, with the `build-type` `Custom`, you can also write your+ own setup script from scratch. It must conform to the interface+ described in the section on [building and installing+ packages](installing-packages.html), and you may use the Cabal+ library for all or part of the work. One option is to copy the+ source of `Distribution.Simple`, and alter it for your needs. Good+ luck.++++[dist-simple]: ../release/cabal-latest/doc/API/Cabal/Distribution-Simple.html+[dist-make]: ../release/cabal-latest/doc/API/Cabal/Distribution-Make.html+[dist-license]: ../release/cabal-latest/doc/API/Cabal/Distribution-License.html#t:License+[extension]: ../release/cabal-latest/doc/API/Cabal/Language-Haskell-Extension.html#t:Extension+[BuildType]: ../release/cabal-latest/doc/API/Cabal/Distribution-PackageDescription.html#t:BuildType+[data-version]: http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Version.html+[alex]: http://www.haskell.org/alex/+[autoconf]: http://www.gnu.org/software/autoconf/+[c2hs]: http://www.cse.unsw.edu.au/~chak/haskell/c2hs/+[cpphs]: http://projects.haskell.org/cpphs/+[greencard]: http://hackage.haskell.org/package/greencard+[haddock]: http://www.haskell.org/haddock/+[HsColour]: http://www.cs.york.ac.uk/fp/darcs/hscolour/+[happy]: http://www.haskell.org/happy/+[Hackage]: http://hackage.haskell.org/+[pkg-config]: http://www.freedesktop.org/wiki/Software/pkg-config/+[REPL]: http://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop
+ doc/index.markdown view
@@ -0,0 +1,200 @@+% Cabal User Guide++Cabal is the standard package system for [Haskell] software. It helps+people to configure, build and install Haskell software and to+distribute it easily to other users and developers.++There is a command line tool called `cabal` for working with Cabal+packages. It helps with installing existing packages and also helps+people developing their own packages. It can be used to work with local+packages or to install packages from online package archives, including+automatically installing dependencies. By default it is configured to+use [Hackage] which is Haskell's central package archive that contains+thousands of libraries and applications in the Cabal package format.++# Contents #++ * [Introduction](#introduction)+ - [What's in a package](#whats-in-a-package)+ - [A tool for working with packages](#a-tool-for-working-with-packages)+ * [Building, installing and managing packages](installing-packages.html)+ * [Creating packages](developing-packages.html)+ * [Reporting bugs and deficiencies](misc.html#reporting-bugs-and-deficiencies)+ * [Stability of Cabal interfaces](misc.html#stability-of-cabal-interfaces)++# Introduction #++Cabal is a package system for Haskell software. The point of a package+system is to enable software developers and users to easily distribute,+use and reuse software. A package system makes it easier for developers+to get their software into the hands of users. Equally importantly, it+makes it easier for software developers to be able to reuse software+components written by other developers.++Packaging systems deal with packages and with Cabal we call them _Cabal+packages_. The Cabal package is the unit of distribution. Every Cabal+package has a name and a version number which are used to identify the+package, e.g. `filepath-1.0`.++Cabal packages can depend on other Cabal packages. There are tools+to enable automated package management. This means it is possible for+developers and users to install a package plus all of the other Cabal+packages that it depends on. It also means that it is practical to make+very modular systems using lots of packages that reuse code written by+many developers.++Cabal packages are source based and are typically (but not necessarily)+portable to many platforms and Haskell implementations. The Cabal+package format is designed to make it possible to translate into other+formats, including binary packages for various systems.++When distributed, Cabal packages use the standard compressed tarball+format, with the file extension `.tar.gz`, e.g. `filepath-1.0.tar.gz`.++Note that packages are not part of the Haskell language, rather they+are a feature provided by the combination of Cabal and GHC (and several+other Haskell implementations).+++## A tool for working with packages ##++There is a command line tool, called "`cabal`", that users and developers+can use to build and install Cabal packages. It can be used for both+local packages and for packages available remotely over the network. It+can automatically install Cabal packages plus any other Cabal packages+they depend on.++Developers can use the tool with packages in local directories, e.g.++~~~~~~~~~~~~~~~~+cd foo/+cabal install+~~~~~~~~~~~~~~~~++While working on a package in a local directory, developers can run the+individual steps to configure and build, and also generate documentation+and run test suites and benchmarks.++It is also possible to install several local packages at once, e.g.++~~~~~~~~~~~~~~~~+cabal install foo/ bar/+~~~~~~~~~~~~~~~~++Developers and users can use the tool to install packages from remote+Cabal package archives. By default, the `cabal` tool is configured to+use the central Haskell package archive called [Hackage] but it+is possible to use it with any other suitable archive.++~~~~~~~~~~~~~~~~+cabal install xmonad+~~~~~~~~~~~~~~~~++This will install the `xmonad` package plus all of its dependencies.++In addition to packages that have been published in an archive,+developers can install packages from local or remote tarball files,+for example++~~~~~~~~~~~~~~~~+cabal install foo-1.0.tar.gz+cabal install http://example.com/foo-1.0.tar.gz+~~~~~~~~~~~~~~~~++Cabal provides a number of ways for a user to customise how and where a+package is installed. They can decide where a package will be installed,+which Haskell implementation to use and whether to build optimised code+or build with the ability to profile code. It is not expected that users+will have to modify any of the information in the `.cabal` file.++For full details, see the section on [building and installing+packages](installing-packages.html).++Note that `cabal` is not the only tool for working with Cabal packages.+Due to the standardised format and a library for reading `.cabal` files,+there are several other special-purpose tools.++## What's in a package ##++A Cabal package consists of:++ * Haskell software, including libraries, executables and tests+ * metadata about the package in a standard human and machine+ readable format (the "`.cabal`" file)+ * a standard interface to build the package (the "`Setup.hs`" file)++The `.cabal` file contains information about the package, supplied by+the package author. In particular it lists the other Cabal packages+that the package depends on.++For full details on what goes in the `.cabal` and `Setup.hs` files, and+for all the other features provided by the build system, see the section+on [developing packages](developing-packages.html).+++## Cabal featureset ##++Cabal and its associated tools and websites covers:++ * a software build system+ * software configuration+ * packaging for distribution+ * automated package management+ * natively using the `cabal` command line tool; or+ * by translation into native package formats such as RPM or deb+ * web and local Cabal package archives+ * central Hackage website with 1000's of Cabal packages++Some parts of the system can be used without others. In particular the+built-in build system for simple packages is optional: it is possible+to use custom build systems.++## Similar systems ##++The Cabal system is roughly comparable with the system of Python Eggs,+Ruby Gems or Perl distributions. Each system has a notion of+distributable packages, and has tools to manage the process of+distributing and installing packages.++Hackage is an online archive of Cabal packages. It is roughly comparable+to CPAN but with rather fewer packages (around 5,000 vs 28,000).++Cabal is often compared with autoconf and automake and there is some+overlap in functionality. The most obvious similarity is that the+command line interface for actually configuring and building packages+follows the same steps and has many of the same configuration+parameters.++~~~~~~~~~~+./configure --prefix=...+make+make install+~~~~~~~~~~++compared to++~~~~~~~~~~+cabal configure --prefix=...+cabal build+cabal install+~~~~~~~~~~++Cabal's build system for simple packages is considerably less flexible+than make/automake, but has builtin knowledge of how to build Haskell+code and requires very little manual configuration. Cabal's simple build+system is also portable to Windows, without needing a Unix-like+environment such as cygwin/mingwin.++Compared to autoconf, Cabal takes a somewhat different approach to+package configuration. Cabal's approach is designed for automated+package management. Instead of having a configure script that tests for+whether dependencies are available, Cabal packages specify their+dependencies. There is some scope for optional and conditional+dependencies. By having package authors specify dependencies it makes it+possible for tools to install a package and all of its dependencies+automatically. It also makes it possible to translate (in a+mostly-automatically way) into another package format like RPM or deb+which also have automatic dependency resolution.++[Haskell]: http://www.haskell.org/+[Hackage]: http://hackage.haskell.org/
+ doc/installing-packages.markdown view
@@ -0,0 +1,1067 @@+% Cabal User Guide++# Building and installing packages #++After you've unpacked a Cabal package, you can build it by moving into+the root directory of the package and running the `cabal` tool there:++> `cabal [command] [option...]`++The _command_ argument selects a particular step in the build/install process.++You can also get a summary of the command syntax with++> `cabal help`++Alternatively, you can also use the `Setup.hs` or `Setup.lhs` script:++> `runhaskell Setup.hs [command] [option...]`++For the summary of the command syntax, run:++> `cabal help`++or++> `runhaskell Setup.hs --help`++## Building and installing a system package ##++~~~~~~~~~~~~~~~~+runhaskell Setup.hs configure --ghc+runhaskell Setup.hs build+runhaskell Setup.hs install+~~~~~~~~~~~~~~~~++The first line readies the system to build the tool using GHC; for+example, it checks that GHC exists on the system. The second line+performs the actual building, while the last both copies the build+results to some permanent place and registers the package with GHC.++## Building and installing a user package ##++~~~~~~~~~~~~~~~~+runhaskell Setup.hs configure --user+runhaskell Setup.hs build+runhaskell Setup.hs install+~~~~~~~~~~~~~~~~++The package is installed under the user's home directory and is+registered in the user's package database (`--user`).++## Installing packages from Hackage ##++The `cabal` tool also can download, configure, build and install a [Hackage]+package and all of its dependencies in a single step. To do this, run:++~~~~~~~~~~~~~~~~+cabal install [PACKAGE...]+~~~~~~~~~~~~~~~~++To browse the list of available packages, visit the [Hackage] web site.++## Developing with sandboxes ##++By default, any dependencies of the package are installed into the global or+user package databases (e.g. using `cabal install --only-dependencies`). If+you're building several different packages that have incompatible dependencies,+this can cause the build to fail. One way to avoid this problem is to build each+package in an isolated environment ("sandbox"), with a sandbox-local package+database. Because sandboxes are per-project, inconsistent dependencies can be+simply disallowed.++For more on sandboxes, see also+[this article](http://coldwa.st/e/blog/2013-08-20-Cabal-sandbox.html).++### Sandboxes: basic usage ###++To initialise a fresh sandbox in the current directory, run `cabal sandbox+init`. All subsequent commands (such as `build` and `install`) from this point+will use the sandbox.++~~~~~~~~~~~~~~~+$ cd /path/to/my/haskell/library+$ cabal sandbox init # Initialise the sandbox+$ cabal install --only-dependencies # Install dependencies into the sandbox+$ cabal build # Build your package inside the sandbox+~~~~~~~~~~~~~~~++It can be useful to make a source package available for installation in the+sandbox - for example, if your package depends on a patched or an unreleased+version of a library. This can be done with the `cabal sandbox add-source`+command - think of it as "local [Hackage]". If an add-source dependency is later+modified, it is reinstalled automatically.++~~~~~~~~~~~~~~~+$ cabal sandbox add-source /my/patched/library # Add a new add-source dependency+$ cabal install --dependencies-only # Install it into the sandbox+$ cabal build # Build the local package+$ $EDITOR /my/patched/library/Source.hs # Modify the add-source dependency+$ cabal build # Modified dependency is automatically reinstalled+~~~~~~~~~~~~~~~++Normally, the sandbox settings (such as optimisation level) are inherited from+the main Cabal config file (`$HOME/cabal/config`). Sometimes, though, you need+to change some settings specifically for a single sandbox. You can do this by+creating a `cabal.config` file in the same directory with your+`cabal.sandbox.config` (which was created by `sandbox init`). This file has the+same syntax as the main Cabal config file.++~~~~~~~~~~~~~~~+$ cat cabal.config+documentation: True+constraints: foo == 1.0, bar >= 2.0, baz+$ cabal build # Uses settings from the cabal.config file+~~~~~~~~~~~~~~~++When you have decided that you no longer want to build your package inside a+sandbox, just delete it:++~~~~~~~~~~~~~~~+$ cabal sandbox delete # Built-in command+$ rm -rf .cabal-sandbox cabal.sandbox.config # Alternative manual method+~~~~~~~~~~~~~~~++### Sandboxes: advanced usage ###++The default behaviour of the `add-source` command is to track modifications done+to the added dependency and reinstall the sandbox copy of the package when+needed. Sometimes this is not desirable: in these cases you can use `add-source+--snapshot`, which disables the change tracking. In addition to `add-source`,+there are also `list-sources` and `delete-source` commands.++Sometimes one wants to share a single sandbox between multiple packages. This+can be easily done with the `--sandbox` option:++~~~~~~~~~~~~~~~+$ mkdir -p /path/to/shared-sandbox+$ cd /path/to/shared-sandbox+$ cabal sandbox init --sandbox .+$ cd /path/to/package-a+$ cabal sandbox init --sandbox /path/to/shared-sandbox+$ cd /path/to/package-b+$ cabal sandbox init --sandbox /path/to/shared-sandbox+~~~~~~~~~~~~~~~++Note that `cabal sandbox init --sandbox .` puts all sandbox files into the+current directory. By default, `cabal sandbox init` initialises a new sandbox in+a newly-created subdirectory of the current working directory+(`./.cabal-sandbox`).++Using multiple different compiler versions simultaneously is also supported, via+the `-w` option:++~~~~~~~~~~~~~~~+$ cabal sandbox init+$ cabal install --only-dependencies -w /path/to/ghc-1 # Install dependencies for both compilers+$ cabal install --only-dependencies -w /path/to/ghc-2+$ cabal configure -w /path/to/ghc-1 # Build with the first compiler+$ cabal build+$ cabal configure -w /path/to/ghc-2 # Build with the second compiler+$ cabal build+~~~~~~~~~~~~~~~++It can be occasionally useful to run the compiler-specific package manager tool+(e.g. `ghc-pkg`) tool on the sandbox package DB directly (for example, you may+need to unregister some packages). The `cabal sandbox hc-pkg` command is a+convenient wrapper that runs the compiler-specific package manager tool with the+arguments:++~~~~~~~~~~~~~~~+$ cabal -v sandbox hc-pkg list+Using a sandbox located at /path/to/.cabal-sandbox+'ghc-pkg' '--global' '--no-user-package-conf'+ '--package-conf=/path/to/.cabal-sandbox/i386-linux-ghc-7.4.2-packages.conf.d'+ 'list'+[...]+~~~~~~~~~~~~~~~++The `--require-sandbox` option makes all sandbox-aware commands+(`install`/`build`/etc.) exit with error if there is no sandbox present. This+makes it harder to accidentally modify the user package database. The option can+be also turned on via the per-user configuration file (`~/.cabal/config`) or the+per-project one (`$PROJECT_DIR/cabal.config`). The error can be squelched with+`--no-require-sandbox`.++The option `--sandbox-config-file` allows to specify the location of the+`cabal.sandbox.config` file (by default, `cabal` searches for it in the current+directory). This provides the same functionality as shared sandboxes, but+sometimes can be more convenient. Example:++~~~~~~~~~~~~~~~+$ mkdir my/sandbox+$ cd my/sandbox+$ cabal sandbox init+$ cd /path/to/my/project+$ cabal --sandbox-config-file=/path/to/my/sandbox/cabal.sandbox.config install+# Uses the sandbox located at /path/to/my/sandbox/.cabal-sandbox+$ cd ~+$ cabal --sandbox-config-file=/path/to/my/sandbox/cabal.sandbox.config install+# Still uses the same sandbox+~~~~~~~~~~~~~~~++The sandbox config file can be also specified via the `CABAL_SANDBOX_CONFIG`+environment variable.++Finally, the flag `--ignore-sandbox` lets you temporarily ignore an existing+sandbox:++~~~~~~~~~~~~~~~+$ mkdir my/sandbox+$ cd my/sandbox+$ cabal sandbox init+$ cabal --ignore-sandbox install text+# Installs 'text' in the user package database ('~/.cabal').+~~~~~~~~~~~~~~~++## Creating a binary package ##++When creating binary packages (e.g. for Red Hat or Debian) one needs to+create a tarball that can be sent to another system for unpacking in the+root directory:++~~~~~~~~~~~~~~~~+runhaskell Setup.hs configure --prefix=/usr+runhaskell Setup.hs build+runhaskell Setup.hs copy --destdir=/tmp/mypkg+tar -czf mypkg.tar.gz /tmp/mypkg/+~~~~~~~~~~~~~~~~++If the package contains a library, you need two additional steps:++~~~~~~~~~~~~~~~~+runhaskell Setup.hs register --gen-script+runhaskell Setup.hs unregister --gen-script+~~~~~~~~~~~~~~~~++This creates shell scripts `register.sh` and `unregister.sh`, which must+also be sent to the target system. After unpacking there, the package+must be registered by running the `register.sh` script. The+`unregister.sh` script would be used in the uninstall procedure of the+package. Similar steps may be used for creating binary packages for+Windows.+++The following options are understood by all commands:++`--help`, `-h` or `-?`+: List the available options for the command.++`--verbose=`_n_ or `-v`_n_+: Set the verbosity level (0-3). The normal level is 1; a missing _n_+ defaults to 2.++The various commands and the additional options they support are+described below. In the simple build infrastructure, any other options+will be reported as errors.++## setup configure ##++Prepare to build the package. Typically, this step checks that the+target platform is capable of building the package, and discovers+platform-specific features that are needed during the build.++The user may also adjust the behaviour of later stages using the options+listed in the following subsections. In the simple build+infrastructure, the values supplied via these options are recorded in a+private file read by later stages.++If a user-supplied `configure` script is run (see the section on+[system-dependent+parameters](developing-packages.html#system-dependent-parameters) or on+[complex packages](developing-packages.html#more-complex-packages)), it+is passed the `--with-hc-pkg`, `--prefix`, `--bindir`, `--libdir`,+`--datadir`, `--libexecdir` and `--sysconfdir` options. In addition the+value of the `--with-compiler` option is passed in a `--with-hc` option+and all options specified with `--configure-option=` are passed on.++### Programs used for building ###++The following options govern the programs used to process the source+files of a package:++`--ghc` or `-g`, `--jhc`, `--lhc`, `--uhc`+: Specify which Haskell implementation to use to build the package.+ At most one of these flags may be given. If none is given, the+ implementation under which the setup script was compiled or+ interpreted is used.++`--with-compiler=`_path_ or `-w`_path_+: Specify the path to a particular compiler. If given, this must match+ the implementation selected above. The default is to search for the+ usual name of the selected implementation.++ This flag also sets the default value of the `--with-hc-pkg` option+ to the package tool for this compiler. Check the output of `setup+ configure -v` to ensure that it finds the right package tool (or use+ `--with-hc-pkg` explicitly).+++`--with-hc-pkg=`_path_+: Specify the path to the package tool, e.g. `ghc-pkg`. The package+ tool must be compatible with the compiler specified by+ `--with-compiler`. If this option is omitted, the default value is+ determined from the compiler selected.++`--with-`_`prog`_`=`_path_+: Specify the path to the program _prog_. Any program known to Cabal+ can be used in place of _prog_. It can either be a fully path or the+ name of a program that can be found on the program search path. For+ example: `--with-ghc=ghc-6.6.1` or+ `--with-cpphs=/usr/local/bin/cpphs`.+ The full list of accepted programs is not enumerated in this user guide.+ Rather, run `cabal install --help` to view the list.++`--`_`prog`_`-options=`_options_+: Specify additional options to the program _prog_. Any program known+ to Cabal can be used in place of _prog_. For example:+ `--alex-options="--template=mytemplatedir/"`. The _options_ is split+ into program options based on spaces. Any options containing embedded+ spaced need to be quoted, for example+ `--foo-options='--bar="C:\Program File\Bar"'`. As an alternative+ that takes only one option at a time but avoids the need to quote,+ use `--`_`prog`_`-option` instead.++`--`_`prog`_`-option=`_option_+: Specify a single additional option to the program _prog_. For+ passing an option that contain embedded spaces, such as a file name+ with embedded spaces, using this rather than `--`_`prog`_`-options`+ means you do not need an additional level of quoting. Of course if+ you are using a command shell you may still need to quote, for+ example `--foo-options="--bar=C:\Program File\Bar"`.++All of the options passed with either `--`_`prog`_`-options` or+`--`_`prog`_`-option` are passed in the order they were specified on the+configure command line.++### Installation paths ###++The following options govern the location of installed files from a+package:++`--prefix=`_dir_+: The root of the installation. For example for a global install you+ might use `/usr/local` on a Unix system, or `C:\Program Files` on a+ Windows system. The other installation paths are usually+ subdirectories of _prefix_, but they don't have to be.++ In the simple build system, _dir_ may contain the following path+ variables: `$pkgid`, `$pkg`, `$version`, `$compiler`, `$os`,+ `$arch`, `$abi`, `$abitag`++`--bindir=`_dir_+: Executables that the user might invoke are installed here.++ In the simple build system, _dir_ may contain the following path+ variables: `$prefix`, `$pkgid`, `$pkg`, `$version`, `$compiler`,+ `$os`, `$arch`, `$abi`, `$abitag++`--libdir=`_dir_+: Object-code libraries are installed here.++ In the simple build system, _dir_ may contain the following path+ variables: `$prefix`, `$bindir`, `$pkgid`, `$pkg`, `$version`,+ `$compiler`, `$os`, `$arch`, `$abi`, `$abitag`++`--libexecdir=`_dir_+: Executables that are not expected to be invoked directly by the user+ are installed here.++ In the simple build system, _dir_ may contain the following path+ variables: `$prefix`, `$bindir`, `$libdir`, `$libsubdir`, `$pkgid`,+ `$pkg`, `$version`, `$compiler`, `$os`, `$arch`, `$abi`, `$abitag`++`--datadir`=_dir_+: Architecture-independent data files are installed here.++ In the simple build system, _dir_ may contain the following path+ variables: `$prefix`, `$bindir`, `$libdir`, `$libsubdir`, `$pkgid`, `$pkg`,+ `$version`, `$compiler`, `$os`, `$arch`, `$abi`, `$abitag`++`--sysconfdir=`_dir_+: Installation directory for the configuration files.++ In the simple build system, _dir_ may contain the following path variables:+ `$prefix`, `$bindir`, `$libdir`, `$libsubdir`, `$pkgid`, `$pkg`, `$version`,+ `$compiler`, `$os`, `$arch`, `$abi`, `$abitag`++In addition the simple build system supports the following installation path options:++`--libsubdir=`_dir_+: A subdirectory of _libdir_ in which libraries are actually+ installed. For example, in the simple build system on Unix, the+ default _libdir_ is `/usr/local/lib`, and _libsubdir_ contains the+ package identifier and compiler, e.g. `mypkg-0.2/ghc-6.4`, so+ libraries would be installed in `/usr/local/lib/mypkg-0.2/ghc-6.4`.++ _dir_ may contain the following path variables: `$pkgid`, `$pkg`,+ `$version`, `$compiler`, `$os`, `$arch`, `$abi`, `$abitag`++`--datasubdir=`_dir_+: A subdirectory of _datadir_ in which data files are actually+ installed.++ _dir_ may contain the following path variables: `$pkgid`, `$pkg`,+ `$version`, `$compiler`, `$os`, `$arch`, `$abi`, `$abitag`++`--docdir=`_dir_+: Documentation files are installed relative to this directory.++ _dir_ may contain the following path variables: `$prefix`, `$bindir`,+ `$libdir`, `$libsubdir`, `$datadir`, `$datasubdir`, `$pkgid`, `$pkg`,+ `$version`, `$compiler`, `$os`, `$arch`, `$abi`, `$abitag`++`--htmldir=`_dir_+: HTML documentation files are installed relative to this directory.++ _dir_ may contain the following path variables: `$prefix`, `$bindir`,+ `$libdir`, `$libsubdir`, `$datadir`, `$datasubdir`, `$docdir`, `$pkgid`,+ `$pkg`, `$version`, `$compiler`, `$os`, `$arch`, `$abi`, `$abitag`++`--program-prefix=`_prefix_+: Prepend _prefix_ to installed program names.++ _prefix_ may contain the following path variables: `$pkgid`, `$pkg`,+ `$version`, `$compiler`, `$os`, `$arch`, `$abi`, `$abitag`++`--program-suffix=`_suffix_+: Append _suffix_ to installed program names. The most obvious use for+ this is to append the program's version number to make it possible+ to install several versions of a program at once:+ `--program-suffix='$version'`.++ _suffix_ may contain the following path variables: `$pkgid`, `$pkg`,+ `$version`, `$compiler`, `$os`, `$arch`, `$abi`, `$abitag`++#### Path variables in the simple build system ####++For the simple build system, there are a number of variables that can be+used when specifying installation paths. The defaults are also specified+in terms of these variables. A number of the variables are actually for+other paths, like `$prefix`. This allows paths to be specified relative+to each other rather than as absolute paths, which is important for+building relocatable packages (see [prefix+independence](#prefix-independence)).++`$prefix`+: The path variable that stands for the root of the installation. For+ an installation to be relocatable, all other installation paths must+ be relative to the `$prefix` variable.++`$bindir`+: The path variable that expands to the path given by the `--bindir`+ configure option (or the default).++`$libdir`+: As above but for `--libdir`++`$libsubdir`+: As above but for `--libsubdir`++`$datadir`+: As above but for `--datadir`++`$datasubdir`+: As above but for `--datasubdir`++`$docdir`+: As above but for `--docdir`++`$pkgid`+: The name and version of the package, e.g. `mypkg-0.2`++`$pkg`+: The name of the package, e.g. `mypkg`++`$version`+: The version of the package, e.g. `0.2`++`$compiler`+: The compiler being used to build the package, e.g. `ghc-6.6.1`++`$os`+: The operating system of the computer being used to build the+ package, e.g. `linux`, `windows`, `osx`, `freebsd` or `solaris`++`$arch`+: The architecture of the computer being used to build the package, e.g.+ `i386`, `x86_64`, `ppc` or `sparc`++`$abitag`+: An optional tag that a compiler can use for telling incompatible ABI's+ on the same architecture apart. GHCJS encodes the underlying GHC version+ in the ABI tag.++`$abi`+: A shortcut for getting a path that completely identifies the platform in terms+ of binary compatibility. Expands to the same value as `$arch-$os-compiler-$abitag`+ if the compiler uses an abi tag, `$arch-$os-$compiler` if it doesn't.++#### Paths in the simple build system ####++For the simple build system, the following defaults apply:++Option Windows Default Unix Default+------- ---------------- -------------+`--prefix` (global) `C:\Program Files\Haskell` `/usr/local`+`--prefix` (per-user) `C:\Documents And Settings\user\Application Data\cabal` `$HOME/.cabal`+`--bindir` `$prefix\bin` `$prefix/bin`+`--libdir` `$prefix` `$prefix/lib`+`--libsubdir` (others) `$pkgid\$compiler` `$pkgid/$compiler`+`--libexecdir` `$prefix\$pkgid` `$prefix/libexec`+`--datadir` (executable) `$prefix` `$prefix/share`+`--datadir` (library) `C:\Program Files\Haskell` `$prefix/share`+`--datasubdir` `$pkgid` `$pkgid`+`--docdir` `$prefix\doc\$pkgid` `$datadir/doc/$pkgid`+`--sysconfdir` `$prefix\etc` `$prefix/etc`+`--htmldir` `$docdir\html` `$docdir/html`+`--program-prefix` (empty) (empty)+`--program-suffix` (empty) (empty)+++#### Prefix-independence ####++On Windows it is possible to obtain the pathname of the running program. This+means that we can construct an installable executable package that is+independent of its absolute install location. The executable can find its+auxiliary files by finding its own path and knowing the location of the other+files relative to `$bindir`. Prefix-independence is particularly useful: it+means the user can choose the install location (i.e. the value of `$prefix`) at+install-time, rather than having to bake the path into the binary when it is+built.++In order to achieve this, we require that for an executable on Windows,+all of `$bindir`, `$libdir`, `$datadir` and `$libexecdir` begin with+`$prefix`. If this is not the case then the compiled executable will+have baked-in all absolute paths.++The application need do nothing special to achieve prefix-independence.+If it finds any files using `getDataFileName` and the [other functions+provided for the+purpose](developing-packages.html#accessing-data-files-from-package-code),+the files will be accessed relative to the location of the current+executable.++A library cannot (currently) be prefix-independent, because it will be+linked into an executable whose file system location bears no relation+to the library package.++### Controlling Flag Assignments ###++Flag assignments (see the [resolution of conditions and+flags](developing-packages.html#resolution-of-conditions-and-flags)) can+be controlled with the following command line options.++`-f` _flagname_ or `-f` `-`_flagname_+: Force the specified flag to `true` or `false` (if preceded with a `-`). Later+ specifications for the same flags will override earlier, i.e.,+ specifying `-fdebug -f-debug` is equivalent to `-f-debug`++`--flags=`_flagspecs_+: Same as `-f`, but allows specifying multiple flag assignments at+ once. The parameter is a space-separated list of flag names (to+ force a flag to `true`), optionally preceded by a `-` (to force a+ flag to `false`). For example, `--flags="debug -feature1 feature2"` is+ equivalent to `-fdebug -f-feature1 -ffeature2`.++### Building Test Suites ###++`--enable-tests`+: Build the test suites defined in the package description file during the+ `build` stage. Check for dependencies required by the test suites. If the+ package is configured with this option, it will be possible to run the test+ suites with the `test` command after the package is built.++`--disable-tests`+: (default) Do not build any test suites during the `build` stage.+ Do not check for dependencies required only by the test suites. It will not+ be possible to invoke the `test` command without reconfiguring the package.++`--enable-coverage`+: Build libraries and executables (including test suites) with Haskell+ Program Coverage enabled. Running the test suites will automatically+ generate coverage reports with HPC.++`--disable-coverage`+: (default) Do not enable Haskell Program Coverage.++### Miscellaneous options ##++`--user`+: Does a per-user installation. This changes the [default installation+ prefix](#paths-in-the-simple-build-system). It also allow+ dependencies to be satisfied by the user's package database, in+ addition to the global database. This also implies a default of+ `--user` for any subsequent `install` command, as packages+ registered in the global database should not depend on packages+ registered in a user's database.++`--global`+: (default) Does a global installation. In this case package+ dependencies must be satisfied by the global package database. All+ packages in the user's package database will be ignored. Typically+ the final installation step will require administrative privileges.++`--package-db=`_db_+: Allows package dependencies to be satisfied from this additional+ package database _db_ in addition to the global package database.+ All packages in the user's package database will be ignored. The+ interpretation of _db_ is implementation-specific. Typically it will+ be a file or directory. Not all implementations support arbitrary+ package databases.++`--enable-optimization`[=_n_] or `-O`[_n_]+: (default) Build with optimization flags (if available). This is+ appropriate for production use, taking more time to build faster+ libraries and programs.++ The optional _n_ value is the optimisation level. Some compilers+ support multiple optimisation levels. The range is 0 to 2. Level 0+ is equivalent to `--disable-optimization`, level 1 is the default if+ no _n_ parameter is given. Level 2 is higher optimisation if the+ compiler supports it. Level 2 is likely to lead to longer compile+ times and bigger generated code.++`--disable-optimization`+: Build without optimization. This is suited for development: building+ will be quicker, but the resulting library or programs will be slower.++`--enable-library-profiling` or `-p`+: Request that an additional version of the library with profiling+ features enabled be built and installed (only for implementations+ that support profiling).++`--disable-library-profiling`+: (default) Do not generate an additional profiling version of the+ library.++`--enable-profiling`+: Any executables generated should have profiling enabled (only for+ implementations that support profiling). For this to work, all+ libraries used by these executables must also have been built with+ profiling support. The library will be built with profiling enabled (if+ supported) unless `--disable-library-profiling` is specified.++`--disable-profiling`+: (default) Do not enable profiling in generated executables.++`--enable-library-vanilla`+: (default) Build ordinary libraries (as opposed to profiling+ libraries). This is independent of the `--enable-library-profiling`+ option. If you enable both, you get both.++`--disable-library-vanilla`+: Do not build ordinary libraries. This is useful in conjunction with+ `--enable-library-profiling` to build only profiling libraries,+ rather than profiling and ordinary libraries.++`--enable-library-for-ghci`+: (default) Build libraries suitable for use with GHCi.++`--disable-library-for-ghci`+: Not all platforms support GHCi and indeed on some platforms, trying+ to build GHCi libs fails. In such cases this flag can be used as a+ workaround.++`--enable-split-objs`+: Use the GHC `-split-objs` feature when building the library. This+ reduces the final size of the executables that use the library by+ allowing them to link with only the bits that they use rather than+ the entire library. The downside is that building the library takes+ longer and uses considerably more memory.++`--disable-split-objs`+: (default) Do not use the GHC `-split-objs` feature. This makes+ building the library quicker but the final executables that use the+ library will be larger.++`--enable-executable-stripping`+: (default) When installing binary executable programs, run the+ `strip` program on the binary. This can considerably reduce the size+ of the executable binary file. It does this by removing debugging+ information and symbols. While such extra information is useful for+ debugging C programs with traditional debuggers it is rarely helpful+ for debugging binaries produced by Haskell compilers.++ Not all Haskell implementations generate native binaries. For such+ implementations this option has no effect.++`--disable-executable-stripping`+: Do not strip binary executables during installation. You might want+ to use this option if you need to debug a program using gdb, for+ example if you want to debug the C parts of a program containing+ both Haskell and C code. Another reason is if your are building a+ package for a system which has a policy of managing the stripping+ itself (such as some Linux distributions).++`--enable-shared`+: Build shared library. This implies a separate compiler run to+ generate position independent code as required on most platforms.++`--disable-shared`+: (default) Do not build shared library.++`--enable-executable-dynamic`+: Link executables dynamically. The executable's library dependencies should+ be built as shared objects. This implies `--enable-shared` unless+ `--disable-shared` is explicitly specified.++`--disable-executable-dynamic`+: (default) Link executables statically.++`--configure-option=`_str_+: An extra option to an external `configure` script, if one is used+ (see the section on [system-dependent+ parameters](developing-packages.html#system-dependent-parameters)).+ There can be several of these options.++`--extra-include-dirs`[=_dir_]+: An extra directory to search for C header files. You can use this+ flag multiple times to get a list of directories.++ You might need to use this flag if you have standard system header+ files in a non-standard location that is not mentioned in the+ package's `.cabal` file. Using this option has the same affect as+ appending the directory _dir_ to the `include-dirs` field in each+ library and executable in the package's `.cabal` file. The advantage+ of course is that you do not have to modify the package at all.+ These extra directories will be used while building the package and+ for libraries it is also saved in the package registration+ information and used when compiling modules that use the library.++`--extra-lib-dirs`[=_dir_]+: An extra directory to search for system libraries files. You can use+ this flag multiple times to get a list of directories.++ You might need to use this flag if you have standard system+ libraries in a non-standard location that is not mentioned in the+ package's `.cabal` file. Using this option has the same affect as+ appending the directory _dir_ to the `extra-lib-dirs` field in each+ library and executable in the package's `.cabal` file. The advantage+ of course is that you do not have to modify the package at all.+ These extra directories will be used while building the package and+ for libraries it is also saved in the package registration+ information and used when compiling modules that use the library.++`--allow-newer`[=_pkgs_]+: Selectively relax upper bounds in dependencies without editing the+ package description.++ If you want to install a package A that depends on B >= 1.0 && < 2.0, but+ you have the version 2.0 of B installed, you can compile A against B 2.0 by+ using `cabal install --allow-newer=B A`. This works for the whole package+ index: if A also depends on C that in turn depends on B < 2.0, C's+ dependency on B will be also relaxed.++ Example:++ ~~~~~~~~~~~~~~~~+ $ cd foo+ $ cabal configure+ Resolving dependencies...+ cabal: Could not resolve dependencies:+ [...]+ $ cabal configure --allow-newer+ Resolving dependencies...+ Configuring foo...+ ~~~~~~~~~~~~~~~~++ Additional examples:++ ~~~~~~~~~~~~~~~~+ # Relax upper bounds in all dependencies.+ $ cabal install --allow-newer foo++ # Relax upper bounds only in dependencies on bar, baz and quux.+ $ cabal install --allow-newer=bar,baz,quux foo++ # Relax the upper bound on bar and force bar==2.1.+ $ cabal install --allow-newer=bar --constraint="bar==2.1" foo+ ~~~~~~~~~~~~~~~~++ It's also possible to enable `--allow-newer` permanently by setting+ `allow-newer: True` in the `~/.cabal/config` file.++`--constraint=`_constraint_+: Restrict solutions involving a package to a given version range.+ For example, `cabal install --constraint="bar==2.1"` will only consider+ install plans that do not use `bar` at all, or `bar` of version 2.1.++ As a special case, `cabal install --constraint="bar -none"` prevents `bar`+ from being used at all (`-none` abbreviates `> 1 && < 1`); `cabal install+ --constraint="bar installed"` prevents reinstallation of the `bar` package;+ `cabal install --constraint="bar +foo -baz"` specifies that the flag `foo`+ should be turned on and the `baz` flag should be turned off.++## setup build ##++Perform any preprocessing or compilation needed to make this package ready for installation.++This command takes the following options:++--_prog_-options=_options_, --_prog_-option=_option_+: These are mostly the same as the [options configure+ step](#setup-configure). Unlike the options specified at the+ configure step, any program options specified at the build step are+ not persistent but are used for that invocation only. They options+ specified at the build step are in addition not in replacement of+ any options specified at the configure step.++## setup haddock ##++Build the documentation for the package using [haddock][]. By default,+only the documentation for the exposed modules is generated (but see the+`--executables` and `--internal` flags below).++This command takes the following options:++`--hoogle`+: Generate a file `dist/doc/html/`_pkgid_`.txt`, which can be+ converted by [Hoogle](http://www.haskell.org/hoogle/) into a+ database for searching. This is equivalent to running [haddock][]+ with the `--hoogle` flag.++`--html-location=`_url_+: Specify a template for the location of HTML documentation for+ prerequisite packages. The substitutions ([see+ listing](#paths-in-the-simple-build-system)) are applied to the+ template to obtain a location for each package, which will be used+ by hyperlinks in the generated documentation. For example, the+ following command generates links pointing at [Hackage] pages:++ > setup haddock --html-location='http://hackage.haskell.org/packages/archive/$pkg/latest/doc/html'++ Here the argument is quoted to prevent substitution by the shell. If+ this option is omitted, the location for each package is obtained+ using the package tool (e.g. `ghc-pkg`).++`--executables`+: Also run [haddock][] for the modules of all the executable programs.+ By default [haddock][] is run only on the exported modules.++`--internal`+: Run [haddock][] for the all modules, including unexposed ones, and+ make [haddock][] generate documentation for unexported symbols as+ well.++`--css=`_path_+: The argument _path_ denotes a CSS file, which is passed to+ [haddock][] and used to set the style of the generated+ documentation. This is only needed to override the default style+ that [haddock][] uses.++`--hyperlink-source`+: Generate [haddock][] documentation integrated with [HsColour][].+ First, [HsColour][] is run to generate colourised code. Then+ [haddock][] is run to generate HTML documentation. Each entity+ shown in the documentation is linked to its definition in the+ colourised code.++`--hscolour-css=`_path_+: The argument _path_ denotes a CSS file, which is passed to [HsColour][] as in++ > runhaskell Setup.hs hscolour --css=_path_++## setup hscolour ##++Produce colourised code in HTML format using [HsColour][]. Colourised+code for exported modules is put in `dist/doc/html/`_pkgid_`/src`.++This command takes the following options:++`--executables`+: Also run [HsColour][] on the sources of all executable programs.+ Colourised code is put in `dist/doc/html/`_pkgid_/_executable_`/src`.++`--css=`_path_+: Use the given CSS file for the generated HTML files. The CSS file+ defines the colours used to colourise code. Note that this copies+ the given CSS file to the directory with the generated HTML files+ (renamed to `hscolour.css`) rather than linking to it.++## setup install ##++Copy the files into the install locations and (for library packages)+register the package with the compiler, i.e. make the modules it+contains available to programs.++The [install locations](#installation-paths) are determined by options+to `setup configure`.++This command takes the following options:++`--global`+: Register this package in the system-wide database. (This is the+ default, unless the `--user` option was supplied to the `configure`+ command.)++`--user`+: Register this package in the user's local package database. (This is+ the default if the `--user` option was supplied to the `configure`+ command.)++## setup copy ##++Copy the files without registering them. This command is mainly of use+to those creating binary packages.++This command takes the following option:++`--destdir=`_path_++Specify the directory under which to place installed files. If this is+not given, then the root directory is assumed.++## setup register ##++Register this package with the compiler, i.e. make the modules it+contains available to programs. This only makes sense for library+packages. Note that the `install` command incorporates this action. The+main use of this separate command is in the post-installation step for a+binary package.++This command takes the following options:++`--global`+: Register this package in the system-wide database. (This is the default.)+++`--user`+: Register this package in the user's local package database.+++`--gen-script`+: Instead of registering the package, generate a script containing+ commands to perform the registration. On Unix, this file is called+ `register.sh`, on Windows, `register.bat`. This script might be+ included in a binary bundle, to be run after the bundle is unpacked+ on the target system.++`--gen-pkg-config`[=_path_]+: Instead of registering the package, generate a package registration+ file. This only applies to compilers that support package+ registration files which at the moment is only GHC. The file should+ be used with the compiler's mechanism for registering packages. This+ option is mainly intended for packaging systems. If possible use the+ `--gen-script` option instead since it is more portable across+ Haskell implementations. The _path_ is+ optional and can be used to specify a particular output file to+ generate. Otherwise, by default the file is the package name and+ version with a `.conf` extension.++`--inplace`+: Registers the package for use directly from the build tree, without+ needing to install it. This can be useful for testing: there's no+ need to install the package after modifying it, just recompile and+ test.++ This flag does not create a build-tree-local package database. It+ still registers the package in one of the user or global databases.++ However, there are some caveats. It only works with GHC+ (currently). It only works if your package doesn't depend on having+ any supplemental files installed --- plain Haskell libraries should+ be fine.++## setup unregister ##++Deregister this package with the compiler.++This command takes the following options:++`--global`+: Deregister this package in the system-wide database. (This is the default.)++`--user`+: Deregister this package in the user's local package database.++`--gen-script`+: Instead of deregistering the package, generate a script containing+ commands to perform the deregistration. On Unix, this file is+ called `unregister.sh`, on Windows, `unregister.bat`. This script+ might be included in a binary bundle, to be run on the target+ system.++## setup clean ##++Remove any local files created during the `configure`, `build`,+`haddock`, `register` or `unregister` steps, and also any files and+directories listed in the `extra-tmp-files` field.++This command takes the following options:++`--save-configure` or `-s`+: Keeps the configuration information so it is not necessary to run+ the configure step again before building.++## setup test ##++Run the test suites specified in the package description file. Aside from+the following flags, Cabal accepts the name of one or more test suites on the+command line after `test`. When supplied, Cabal will run only the named test+suites, otherwise, Cabal will run all test suites in the package.++`--builddir=`_dir_+: The directory where Cabal puts generated build files (default: `dist`).+ Test logs will be located in the `test` subdirectory.++`--human-log=`_path_+: The template used to name human-readable test logs; the path is relative+ to `dist/test`. By default, logs are named according to the template+ `$pkgid-$test-suite.log`, so that each test suite will be logged to its own+ human-readable log file. Template variables allowed are: `$pkgid`,+ `$compiler`, `$os`, `$arch`, `$abi`, `$abitag`, `$test-suite`, and `$result`.++`--machine-log=`_path_+: The path to the machine-readable log, relative to `dist/test`. The default+ template is `$pkgid.log`. Template variables allowed are: `$pkgid`,+ `$compiler`, `$os`, `$arch`, `$abi`, `$abitag` and `$result`.++`--show-details=`_filter_+: Determines if the results of individual test cases are shown on the+ terminal. May be `always` (always show), `never` (never show), `failures`+ (show only failed results), or `streaming` (show all results in real time).++`--test-options=`_options_+: Give extra options to the test executables.++`--test-option=`_option_+: give an extra option to the test executables. There is no need to quote+ options containing spaces because a single option is assumed, so options+ will not be split on spaces.++## setup sdist ##++Create a system- and compiler-independent source distribution in a file+_package_-_version_`.tar.gz` in the `dist` subdirectory, for+distribution to package builders. When unpacked, the commands listed in+this section will be available.++The files placed in this distribution are the package description file,+the setup script, the sources of the modules named in the package+description file, and files named in the `license-file`, `main-is`,+`c-sources`, `js-sources`, `data-files`, `extra-source-files` and+`extra-doc-files` fields.++This command takes the following option:++`--snapshot`+: Append today's date (in "YYYYMMDD" format) to the version number for+ the generated source package. The original package is unaffected.+++[dist-simple]: ../release/cabal-latest/doc/API/Cabal/Distribution-Simple.html+[dist-make]: ../release/cabal-latest/doc/API/Cabal/Distribution-Make.html+[dist-license]: ../release/cabal-latest/doc/API/Cabal/Distribution-License.html#t:License+[extension]: ../release/cabal-latest/doc/API/Cabal/Language-Haskell-Extension.html#t:Extension+[BuildType]: ../release/cabal-latest/doc/API/Cabal/Distribution-PackageDescription.html#t:BuildType+[alex]: http://www.haskell.org/alex/+[autoconf]: http://www.gnu.org/software/autoconf/+[c2hs]: http://www.cse.unsw.edu.au/~chak/haskell/c2hs/+[cpphs]: http://projects.haskell.org/cpphs/+[greencard]: http://hackage.haskell.org/package/greencard+[haddock]: http://www.haskell.org/haddock/+[HsColour]: http://www.cs.york.ac.uk/fp/darcs/hscolour/+[happy]: http://www.haskell.org/happy/+[Hackage]: http://hackage.haskell.org/+[pkg-config]: http://www.freedesktop.org/wiki/Software/pkg-config/
+ doc/misc.markdown view
@@ -0,0 +1,109 @@+% Cabal User Guide++# Reporting bugs and deficiencies #++Please report any flaws or feature requests in the [bug tracker][].++For general discussion or queries email the libraries mailing list+<libraries@haskell.org>. There is also a development mailing list+<cabal-devel@haskell.org>.++[bug tracker]: https://github.com/haskell/cabal/issues++# Stability of Cabal interfaces #++The Cabal library and related infrastructure is still under active+development. New features are being added and limitations and bugs are+being fixed. This requires internal changes and often user visible+changes as well. We therefore cannot promise complete future-proof+stability, at least not without halting all development work.++This section documents the aspects of the Cabal interface that we can+promise to keep stable and which bits are subject to change.++## Cabal file format ##++This is backwards compatible and mostly forwards compatible. New fields+can be added without breaking older versions of Cabal. Fields can be+deprecated without breaking older packages.++## Command-line interface ##++### Very Stable Command-line interfaces ###++* `./setup configure`+ * `--prefix`+ * `--user`+ * `--ghc`, `--uhc`+ * `--verbose`+ * `--prefix`++* `./setup build`+* `./setup install`+* `./setup register`+* `./setup copy`++### Stable Command-line interfaces ###++### Unstable command-line ###++## Functions and Types ##++The Cabal library follows the [Package Versioning Policy][PVP]. This+means that within a stable major release, for example 1.2.x, there will+be no incompatible API changes. But minor versions increments, for+example 1.2.3, indicate compatible API additions.++The Package Versioning Policy does not require any API guarantees+between major releases, for example between 1.2.x and 1.4.x. In practise+of course not everything changes between major releases. Some parts of+the API are more prone to change than others. The rest of this section+gives some informal advice on what level of API stability you can expect+between major releases.++[PVP]: http://www.haskell.org/haskellwiki/Package_versioning_policy++### Very Stable API ###++* `defaultMain`++* `defaultMainWithHooks defaultUserHooks`++ But regular `defaultMainWithHooks` isn't stable since `UserHooks`+ changes.++### Semi-stable API ###++* `UserHooks` The hooks API will change in the future++* `Distribution.*` is mostly declarative information about packages and+ is somewhat stable.++### Unstable API ###++Everything under `Distribution.Simple.*` has no stability guarantee.++## Hackage ##++The index format is a partly stable interface. It consists of a tar.gz+file that contains directories with `.cabal` files in. In future it may+contain more kinds of files so do not assume every file is a `.cabal`+file. Incompatible revisions to the format would involve bumping the+name of the index file, i.e., `00-index.tar.gz`, `01-index.tar.gz` etc.+++[dist-simple]: ../release/cabal-latest/doc/API/Cabal/Distribution-Simple.html+[dist-make]: ../release/cabal-latest/doc/API/Cabal/Distribution-Make.html+[dist-license]: ../release/cabal-latest/doc/API/Cabal/Distribution-License.html#t:License+[extension]: ../release/cabal-latest/doc/API/Cabal/Language-Haskell-Extension.html#t:Extension+[BuildType]: ../release/cabal-latest/doc/API/Cabal/Distribution-PackageDescription.html#t:BuildType+[alex]: http://www.haskell.org/alex/+[autoconf]: http://www.gnu.org/software/autoconf/+[c2hs]: http://www.cse.unsw.edu.au/~chak/haskell/c2hs/+[cpphs]: http://projects.haskell.org/cpphs/+[greencard]: http://hackage.haskell.org/package/greencard+[haddock]: http://www.haskell.org/haddock/+[HsColour]: http://www.cs.york.ac.uk/fp/darcs/hscolour/+[happy]: http://www.haskell.org/happy/+[Hackage]: http://hackage.haskell.org/+[pkg-config]: http://www.freedesktop.org/wiki/Software/pkg-config/
tests/PackageTests.hs view
@@ -34,22 +34,23 @@ import PackageTests.TestStanza.Check import PackageTests.TestSuiteExeV10.Check import PackageTests.OrderFlags.Check+import PackageTests.ReexportedModules.Check -import Distribution.Compat.Exception (catchIO)+import Distribution.Simple.Configure+ ( ConfigStateFileError(..), getConfigStateFile ) import Distribution.Simple.LocalBuildInfo (LocalBuildInfo(..)) import Distribution.Simple.Program.Types (programPath)-import Distribution.Simple.Program.Builtin (ghcProgram, ghcPkgProgram,- haddockProgram)+import Distribution.Simple.Program.Builtin+ ( ghcProgram, ghcPkgProgram, haddockProgram ) import Distribution.Simple.Program.Db (requireProgram)-import Distribution.Simple.Utils (cabalVersion, die, withFileContents)+import Distribution.Simple.Utils (cabalVersion) import Distribution.Text (display) import Distribution.Verbosity (normal) import Distribution.Version (Version(Version)) -import Data.Maybe (isJust)-import System.Directory (doesFileExist, getCurrentDirectory,- setCurrentDirectory)-import System.Environment (getEnv)+import Control.Exception (try, throw)+import System.Directory+ ( getCurrentDirectory, setCurrentDirectory ) import System.FilePath ((</>)) import System.IO (BufferMode(NoBuffering), hSetBuffering, stdout) import Test.Framework (Test, TestName, defaultMain, testGroup)@@ -76,9 +77,7 @@ , hunit "TestStanza" (PackageTests.TestStanza.Check.suite ghcPath) -- ^ The Test stanza test will eventually be required -- only for higher versions.- , hunit "TestSuiteExeV10/Test" (PackageTests.TestSuiteExeV10.Check.checkTest ghcPath)- , hunit "TestSuiteExeV10/TestWithHpc"- (PackageTests.TestSuiteExeV10.Check.checkTestWithHpc ghcPath)+ , testGroup "TestSuiteExeV10" (PackageTests.TestSuiteExeV10.Check.checks ghcPath) , hunit "TestOptions" (PackageTests.TestOptions.Check.suite ghcPath) , hunit "BenchmarkStanza" (PackageTests.BenchmarkStanza.Check.suite ghcPath) -- ^ The benchmark stanza test will eventually be required@@ -104,6 +103,8 @@ (PackageTests.OrderFlags.Check.suite ghcPath) , hunit "TemplateHaskell/dynamic" (PackageTests.TemplateHaskell.Check.dynamic ghcPath)+ , hunit "ReexportedModules"+ (PackageTests.ReexportedModules.Check.suite ghcPath) ] ++ -- These tests are only required to pass on cabal version >= 1.7 (if version >= Version [1, 7] []@@ -139,6 +140,7 @@ , configOpts = [ "--package-db=" ++ dbFile , "--constraint=Cabal == " ++ display cabalVersion ]+ , distPref = Nothing } putStrLn $ "Cabal test suite - testing cabal version " ++ display cabalVersion@@ -162,16 +164,9 @@ -- we run Cabal's own test suite, due to bootstrapping issues. getPersistBuildConfig_ :: FilePath -> IO LocalBuildInfo getPersistBuildConfig_ filename = do- exists <- doesFileExist filename- if not exists- then die missing- else withFileContents filename $ \str ->- case lines str of- [_header, rest] -> case reads rest of- [(bi,_)] -> return bi- _ -> die cantParse- _ -> die cantParse- where- missing = "Run the 'configure' command first."- cantParse = "Saved package config file seems to be corrupt. "- ++ "Try re-running the 'configure' command."+ eLBI <- try $ getConfigStateFile filename+ case eLBI of+ Left (ConfigStateFileBadVersion _ _ (Right lbi)) -> return lbi+ Left (ConfigStateFileBadVersion _ _ (Left err)) -> throw err+ Left err -> throw err+ Right lbi -> return lbi
tests/PackageTests/BenchmarkExeV10/Check.hs view
@@ -11,6 +11,6 @@ checkBenchmark :: FilePath -> Test checkBenchmark ghcPath = TestCase $ do- let spec = PackageSpec dir ["--enable-benchmarks"]+ let spec = PackageSpec dir Nothing ["--enable-benchmarks"] buildResult <- cabal_build spec ghcPath assertBuildSucceeded buildResult
tests/PackageTests/BenchmarkOptions/Check.hs view
@@ -6,8 +6,11 @@ suite :: FilePath -> Test suite ghcPath = TestCase $ do- let spec = PackageSpec ("PackageTests" </> "BenchmarkOptions")- ["--enable-benchmarks"]+ let spec = PackageSpec+ { directory = "PackageTests" </> "BenchmarkOptions"+ , configOpts = ["--enable-benchmarks"]+ , distPref = Nothing+ } _ <- cabal_build spec ghcPath result <- cabal_bench spec ["--benchmark-options=1 2 3"] ghcPath let message = "\"cabal bench\" did not pass the correct options to the "
tests/PackageTests/BenchmarkStanza/Check.hs view
@@ -2,6 +2,7 @@ import Test.HUnit import System.FilePath+import qualified Data.Map as Map import PackageTests.PackageTester import Distribution.Version import Distribution.PackageDescription.Parse@@ -14,28 +15,30 @@ ( PackageDescription(..), BuildInfo(..), Benchmark(..) , BenchmarkInterface(..) , emptyBuildInfo- , emptyBenchmark )+ , emptyBenchmark, defaultRenaming ) import Distribution.Verbosity (silent) import Distribution.System (buildPlatform) import Distribution.Compiler- ( CompilerId(..), CompilerFlavor(..) )+ ( CompilerId(..), CompilerFlavor(..), unknownCompilerInfo, AbiTag(..) ) import Distribution.Text suite :: FilePath -> Test suite ghcPath = TestCase $ do let dir = "PackageTests" </> "BenchmarkStanza" pdFile = dir </> "my" <.> "cabal"- spec = PackageSpec dir []+ spec = PackageSpec { directory = dir, configOpts = [], distPref = Nothing } result <- cabal_configure spec ghcPath assertOutputDoesNotContain "unknown section type" result genPD <- readPackageDescription silent pdFile- let compiler = CompilerId GHC $ Version [6, 12, 2] []+ let compiler = unknownCompilerInfo (CompilerId GHC $ Version [6, 12, 2] []) NoAbiTag anticipatedBenchmark = emptyBenchmark { benchmarkName = "dummy" , benchmarkInterface = BenchmarkExeV10 (Version [1,0] []) "dummy.hs" , benchmarkBuildInfo = emptyBuildInfo { targetBuildDepends = [ Dependency (PackageName "base") anyVersion ]+ , targetBuildRenaming =+ Map.singleton (PackageName "base") defaultRenaming , hsSourceDirs = ["."] } , benchmarkEnabled = False
tests/PackageTests/BuildDeps/InternalLibrary0/Check.hs view
@@ -9,7 +9,11 @@ suite :: Version -> FilePath -> Test suite cabalVersion ghcPath = TestCase $ do- let spec = PackageSpec ("PackageTests" </> "BuildDeps" </> "InternalLibrary0") []+ let spec = PackageSpec+ { directory = "PackageTests" </> "BuildDeps" </> "InternalLibrary0"+ , configOpts = []+ , distPref = Nothing+ } result <- cabal_build spec ghcPath assertBuildFailed result when (cabalVersion >= Version [1, 7] []) $ do
tests/PackageTests/BuildDeps/InternalLibrary1/Check.hs view
@@ -7,6 +7,10 @@ suite :: FilePath -> Test suite ghcPath = TestCase $ do- let spec = PackageSpec ("PackageTests" </> "BuildDeps" </> "InternalLibrary1") []+ let spec = PackageSpec+ { directory = "PackageTests" </> "BuildDeps" </> "InternalLibrary1"+ , configOpts = []+ , distPref = Nothing+ } result <- cabal_build spec ghcPath assertBuildSucceeded result
tests/PackageTests/BuildDeps/InternalLibrary2/Check.hs view
@@ -8,8 +8,16 @@ suite :: FilePath -> FilePath -> Test suite ghcPath ghcPkgPath = TestCase $ do- let spec = PackageSpec ("PackageTests" </> "BuildDeps" </> "InternalLibrary2") []- let specTI = PackageSpec (directory spec </> "to-install") []+ let spec = PackageSpec+ { directory = "PackageTests" </> "BuildDeps" </> "InternalLibrary2"+ , configOpts = []+ , distPref = Nothing+ }+ let specTI = PackageSpec+ { directory = directory spec </> "to-install"+ , configOpts = []+ , distPref = Nothing+ } unregister "InternalLibrary2" ghcPkgPath iResult <- cabal_install specTI ghcPath@@ -18,7 +26,7 @@ assertBuildSucceeded bResult unregister "InternalLibrary2" ghcPkgPath - (_, _, output) <- run (Just $ directory spec) (directory spec </> "dist" </> "build" </> "lemon" </> "lemon") []+ (_, _, output) <- run (Just $ directory spec) (directory spec </> "dist" </> "build" </> "lemon" </> "lemon") [] [] C.appendFile (directory spec </> "test-log.txt") (C.pack $ "\ndist/build/lemon/lemon\n"++output) assertEqual "executable should have linked with the internal library" "myLibFunc internal" (concat $ lines output)
tests/PackageTests/BuildDeps/InternalLibrary3/Check.hs view
@@ -8,8 +8,16 @@ suite :: FilePath -> FilePath -> Test suite ghcPath ghcPkgPath = TestCase $ do- let spec = PackageSpec ("PackageTests" </> "BuildDeps" </> "InternalLibrary3") []- let specTI = PackageSpec (directory spec </> "to-install") []+ let spec = PackageSpec+ { directory = "PackageTests" </> "BuildDeps" </> "InternalLibrary3"+ , configOpts = []+ , distPref = Nothing+ }+ let specTI = PackageSpec+ { directory = directory spec </> "to-install"+ , configOpts = []+ , distPref = Nothing+ } unregister "InternalLibrary3" ghcPkgPath iResult <- cabal_install specTI ghcPath@@ -18,7 +26,7 @@ assertBuildSucceeded bResult unregister "InternalLibrary3"ghcPkgPath - (_, _, output) <- run (Just $ directory spec) (directory spec </> "dist" </> "build" </> "lemon" </> "lemon") []+ (_, _, output) <- run (Just $ directory spec) (directory spec </> "dist" </> "build" </> "lemon" </> "lemon") [] [] C.appendFile (directory spec </> "test-log.txt") (C.pack $ "\ndist/build/lemon/lemon\n"++output) assertEqual "executable should have linked with the internal library" "myLibFunc internal" (concat $ lines output)
tests/PackageTests/BuildDeps/InternalLibrary4/Check.hs view
@@ -8,8 +8,16 @@ suite :: FilePath -> FilePath -> Test suite ghcPath ghcPkgPath = TestCase $ do- let spec = PackageSpec ("PackageTests" </> "BuildDeps" </> "InternalLibrary4") []- let specTI = PackageSpec (directory spec </> "to-install") []+ let spec = PackageSpec+ { directory = "PackageTests" </> "BuildDeps" </> "InternalLibrary4"+ , configOpts = []+ , distPref = Nothing+ }+ let specTI = PackageSpec+ { directory = directory spec </> "to-install"+ , configOpts = []+ , distPref = Nothing+ } unregister "InternalLibrary4" ghcPkgPath iResult <- cabal_install specTI ghcPath@@ -18,7 +26,7 @@ assertBuildSucceeded bResult unregister "InternalLibrary4" ghcPkgPath - (_, _, output) <- run (Just $ directory spec) (directory spec </> "dist" </> "build" </> "lemon" </> "lemon") []+ (_, _, output) <- run (Just $ directory spec) (directory spec </> "dist" </> "build" </> "lemon" </> "lemon") [] [] C.appendFile (directory spec </> "test-log.txt") (C.pack $ "\ndist/build/lemon/lemon\n"++output) assertEqual "executable should have linked with the installed library" "myLibFunc installed" (concat $ lines output)
tests/PackageTests/BuildDeps/SameDepsAllRound/Check.hs view
@@ -8,7 +8,11 @@ suite :: FilePath -> Test suite ghcPath = TestCase $ do- let spec = PackageSpec ("PackageTests" </> "BuildDeps" </> "SameDepsAllRound") []+ let spec = PackageSpec+ { directory = "PackageTests" </> "BuildDeps" </> "SameDepsAllRound"+ , configOpts = []+ , distPref = Nothing+ } result <- cabal_build spec ghcPath do assertEqual "cabal build should succeed - see test-log.txt" True (successful result)
tests/PackageTests/BuildDeps/TargetSpecificDeps1/Check.hs view
@@ -10,7 +10,11 @@ suite :: FilePath -> Test suite ghcPath = TestCase $ do- let spec = PackageSpec ("PackageTests" </> "BuildDeps" </> "TargetSpecificDeps1") []+ let spec = PackageSpec+ { directory = "PackageTests" </> "BuildDeps" </> "TargetSpecificDeps1"+ , configOpts = []+ , distPref = Nothing+ } result <- cabal_build spec ghcPath do assertEqual "cabal build should fail - see test-log.txt" False (successful result)
tests/PackageTests/BuildDeps/TargetSpecificDeps2/Check.hs view
@@ -8,7 +8,11 @@ suite :: FilePath -> Test suite ghcPath = TestCase $ do- let spec = PackageSpec ("PackageTests" </> "BuildDeps" </> "TargetSpecificDeps2") []+ let spec = PackageSpec+ { directory = "PackageTests" </> "BuildDeps" </> "TargetSpecificDeps2"+ , configOpts = []+ , distPref = Nothing+ } result <- cabal_build spec ghcPath do assertEqual "cabal build should succeed - see test-log.txt" True (successful result)
tests/PackageTests/BuildDeps/TargetSpecificDeps3/Check.hs view
@@ -10,7 +10,11 @@ suite :: FilePath -> Test suite ghcPath = TestCase $ do- let spec = PackageSpec ("PackageTests" </> "BuildDeps" </> "TargetSpecificDeps3") []+ let spec = PackageSpec+ { directory = "PackageTests" </> "BuildDeps" </> "TargetSpecificDeps3"+ , configOpts = []+ , distPref = Nothing+ } result <- cabal_build spec ghcPath do assertEqual "cabal build should fail - see test-log.txt" False (successful result)
tests/PackageTests/CMain/Check.hs view
@@ -11,6 +11,10 @@ checkBuild :: FilePath -> Test checkBuild ghcPath = TestCase $ do- let spec = PackageSpec dir []+ let spec = PackageSpec+ { directory = dir+ , distPref = Nothing+ , configOpts = []+ } buildResult <- cabal_build spec ghcPath assertBuildSucceeded buildResult
tests/PackageTests/DeterministicAr/Check.hs view
@@ -22,7 +22,7 @@ ghcPkg_field :: String -> String -> FilePath -> IO [FilePath] ghcPkg_field libraryName fieldName ghcPkgPath = do- (cmd, exitCode, raw) <- run Nothing ghcPkgPath+ (cmd, exitCode, raw) <- run Nothing ghcPkgPath [] ["--user", "field", libraryName, fieldName] let output = filter ('\r' /=) raw -- Windows -- copypasta of PackageTester.requireSuccess@@ -51,7 +51,11 @@ suite :: FilePath -> FilePath -> Test suite ghcPath ghcPkgPath = TestCase $ do let dir = "PackageTests" </> this- let spec = PackageSpec dir []+ let spec = PackageSpec+ { directory = dir+ , configOpts = []+ , distPref = Nothing+ } unregister this ghcPkgPath iResult <- cabal_install spec ghcPath
tests/PackageTests/EmptyLib/Check.hs view
@@ -7,7 +7,10 @@ -- See https://github.com/haskell/cabal/issues/1241 emptyLib :: FilePath -> Test emptyLib ghcPath = TestCase $ do- let spec = PackageSpec ("PackageTests" </> "EmptyLib"- </> "empty") []+ let spec = PackageSpec+ { directory = "PackageTests" </> "EmptyLib" </> "empty"+ , configOpts = []+ , distPref = Nothing+ } result <- cabal_build spec ghcPath assertBuildSucceeded result
tests/PackageTests/Haddock/Check.hs view
@@ -18,7 +18,11 @@ suite ghcPath = TestCase $ do let dir = "PackageTests" </> this haddocksDir = dir </> "dist" </> "doc" </> "html" </> "Haddock"- spec = PackageSpec dir []+ spec = PackageSpec+ { directory = dir+ , configOpts = []+ , distPref = Nothing+ } haddocksDirExists <- doesDirectoryExist haddocksDir when haddocksDirExists (removeDirectoryRecursive haddocksDir)
tests/PackageTests/OrderFlags/Check.hs view
@@ -11,7 +11,11 @@ suite :: FilePath -> Test suite ghcPath = TestCase $ do- let spec = PackageSpec ("PackageTests" </> "OrderFlags") []+ let spec = PackageSpec+ { directory = "PackageTests" </> "OrderFlags"+ , configOpts = []+ , distPref = Nothing+ } result <- cabal_build spec ghcPath do assertEqual "cabal build should succeed - see test-log.txt" True (successful result)
tests/PackageTests/PackageTester.hs view
@@ -37,19 +37,21 @@ import System.Environment (getEnv) import System.Exit (ExitCode(ExitSuccess)) import System.FilePath-import System.IO+import System.IO (hIsEOF, hGetChar, hClose) import System.IO.Error (isDoesNotExistError) import System.Process (runProcess, waitForProcess) import Test.HUnit (Assertion, assertFailure) -import Distribution.Simple.BuildPaths (exeExtension) import Distribution.Compat.CreatePipe (createPipe)+import Distribution.Simple.BuildPaths (exeExtension)+import Distribution.Simple.Program.Run (getEffectiveEnvironment)+import Distribution.Simple.Utils (printRawCommandAndArgsAndEnv) import Distribution.ReadE (readEOrFail)-import Distribution.Verbosity (Verbosity, deafening, flagToVerbosity, normal,- verbose)+import Distribution.Verbosity (Verbosity, flagToVerbosity, normal) data PackageSpec = PackageSpec { directory :: FilePath+ , distPref :: Maybe FilePath , configOpts :: [String] } @@ -92,9 +94,9 @@ doCabalConfigure :: PackageSpec -> FilePath -> IO Result doCabalConfigure spec ghcPath = do- cleanResult@(_, _, _) <- cabal spec ["clean"] ghcPath+ cleanResult@(_, _, _) <- cabal spec [] ["clean"] ghcPath requireSuccess cleanResult- res <- cabal spec+ res <- cabal spec [] (["configure", "--user", "-w", ghcPath] ++ configOpts spec) ghcPath return $ recordRun res ConfigureSuccess nullResult@@ -104,7 +106,7 @@ configResult <- doCabalConfigure spec ghcPath if successful configResult then do- res <- cabal spec ["build", "-v"] ghcPath+ res <- cabal spec [] ["build", "-v"] ghcPath return $ recordRun res BuildSuccess configResult else return configResult@@ -126,14 +128,14 @@ configResult <- doCabalConfigure spec ghcPath if successful configResult then do- res <- cabal spec ("haddock" : extraArgs) ghcPath+ res <- cabal spec [] ("haddock" : extraArgs) ghcPath return $ recordRun res HaddockSuccess configResult else return configResult unregister :: String -> FilePath -> IO () unregister libraryName ghcPkgPath = do- res@(_, _, output) <- run Nothing ghcPkgPath ["unregister", "--user", libraryName]+ res@(_, _, output) <- run Nothing ghcPkgPath [] ["unregister", "--user", libraryName] if "cannot find package" `isInfixOf` output then return () else requireSuccess res@@ -144,23 +146,23 @@ buildResult <- doCabalBuild spec ghcPath res <- if successful buildResult then do- res <- cabal spec ["install"] ghcPath+ res <- cabal spec [] ["install"] ghcPath return $ recordRun res InstallSuccess buildResult else return buildResult record spec res return res -cabal_test :: PackageSpec -> [String] -> FilePath -> IO Result-cabal_test spec extraArgs ghcPath = do- res <- cabal spec ("test" : extraArgs) ghcPath+cabal_test :: PackageSpec -> [(String, Maybe String)] -> [String] -> FilePath -> IO Result+cabal_test spec envOverrides extraArgs ghcPath = do+ res <- cabal spec envOverrides ("test" : extraArgs) ghcPath let r = recordRun res TestSuccess nullResult record spec r return r cabal_bench :: PackageSpec -> [String] -> FilePath -> IO Result cabal_bench spec extraArgs ghcPath = do- res <- cabal spec ("bench" : extraArgs) ghcPath+ res <- cabal spec [] ("bench" : extraArgs) ghcPath let r = recordRun res BenchSuccess nullResult record spec r return r@@ -168,7 +170,7 @@ compileSetup :: FilePath -> FilePath -> IO () compileSetup packageDir ghcPath = do wd <- getCurrentDirectory- r <- run (Just $ packageDir) ghcPath+ r <- run (Just $ packageDir) ghcPath [] [ "--make" -- HPC causes trouble -- see #1012 -- , "-fhpc"@@ -178,30 +180,35 @@ requireSuccess r -- | Returns the command that was issued, the return code, and the output text.-cabal :: PackageSpec -> [String] -> FilePath -> IO (String, ExitCode, String)-cabal spec cabalArgs ghcPath = do+cabal :: PackageSpec -> [(String, Maybe String)] -> [String] -> FilePath -> IO (String, ExitCode, String)+cabal spec envOverrides cabalArgs_ ghcPath = do+ let cabalArgs = case distPref spec of+ Nothing -> cabalArgs_+ Just dist -> ("--builddir=" ++ dist) : cabalArgs_ customSetup <- doesFileExist (directory spec </> "Setup.hs") if customSetup then do compileSetup (directory spec) ghcPath path <- canonicalizePath $ directory spec </> "Setup"- run (Just $ directory spec) path cabalArgs+ run (Just $ directory spec) path envOverrides cabalArgs else do -- Use shared Setup executable (only for Simple build types). path <- canonicalizePath "Setup"- run (Just $ directory spec) path cabalArgs+ run (Just $ directory spec) path envOverrides cabalArgs --- | Returns the command that was issued, the return code, and hte output text-run :: Maybe FilePath -> String -> [String] -> IO (String, ExitCode, String)-run cwd path args = do+-- | Returns the command that was issued, the return code, and the output text+run :: Maybe FilePath -> String -> [(String, Maybe String)] -> [String] -> IO (String, ExitCode, String)+run cwd path envOverrides args = do verbosity <- getVerbosity -- path is relative to the current directory; canonicalizePath makes it -- absolute, so that runProcess will find it even when changing directory. path' <- do pathExists <- doesFileExist path canonicalizePath (if pathExists then path else path <.> exeExtension)- printRawCommandAndArgs verbosity path' args+ menv <- getEffectiveEnvironment envOverrides++ printRawCommandAndArgsAndEnv verbosity path' args menv (readh, writeh) <- createPipe- pid <- runProcess path' args cwd Nothing Nothing (Just writeh) (Just writeh)+ pid <- runProcess path' args cwd menv Nothing (Just writeh) (Just writeh) -- fork off a thread to start consuming the output out <- suckH [] readh@@ -220,12 +227,6 @@ c <- hGetChar h suckH (c:output) h --- Copied from Distribution/Simple/Utils.hs-printRawCommandAndArgs :: Verbosity -> FilePath -> [String] -> IO ()-printRawCommandAndArgs verbosity path args- | verbosity >= deafening = print (path, args)- | verbosity >= verbose = putStrLn $ unwords (path : args)- | otherwise = return () requireSuccess :: (String, ExitCode, String) -> IO () requireSuccess (cmd, exitCode, output) =
tests/PackageTests/PathsModule/Executable/Check.hs view
@@ -7,7 +7,10 @@ suite :: FilePath -> Test suite ghcPath = TestCase $ do- let spec = PackageSpec ("PackageTests" </> "PathsModule" </> "Executable")- []+ let spec = PackageSpec+ { directory = "PackageTests" </> "PathsModule" </> "Executable"+ , distPref = Nothing+ , configOpts = []+ } result <- cabal_build spec ghcPath assertBuildSucceeded result
tests/PackageTests/PathsModule/Library/Check.hs view
@@ -7,6 +7,10 @@ suite :: FilePath -> Test suite ghcPath = TestCase $ do- let spec = PackageSpec ("PackageTests" </> "PathsModule" </> "Library") []+ let spec = PackageSpec+ { directory = "PackageTests" </> "PathsModule" </> "Library"+ , distPref = Nothing+ , configOpts = []+ } result <- cabal_build spec ghcPath assertBuildSucceeded result
tests/PackageTests/PreProcess/Check.hs view
@@ -7,7 +7,10 @@ suite :: FilePath -> Test suite ghcPath = TestCase $ do- let spec = PackageSpec ("PackageTests" </> "PreProcess")- ["--enable-tests", "--enable-benchmarks"]+ let spec = PackageSpec+ { directory = "PackageTests" </> "PreProcess"+ , distPref = Nothing+ , configOpts = ["--enable-tests", "--enable-benchmarks"]+ } result <- cabal_build spec ghcPath assertBuildSucceeded result
tests/PackageTests/TemplateHaskell/Check.hs view
@@ -6,8 +6,11 @@ vanilla :: FilePath -> Test vanilla ghcPath = TestCase $ do- let spec = PackageSpec ("PackageTests" </>- "TemplateHaskell" </> "vanilla") []+ let spec = PackageSpec+ { directory = "PackageTests" </> "TemplateHaskell" </> "vanilla"+ , configOpts = []+ , distPref = Nothing+ } result <- cabal_build spec ghcPath assertBuildSucceeded result @@ -15,9 +18,12 @@ profiling ghcPath = TestCase $ do let flags = ["--enable-library-profiling" -- ,"--disable-library-vanilla"- ,"--enable-executable-profiling"]- spec = PackageSpec ("PackageTests" </>- "TemplateHaskell" </> "profiling") flags+ ,"--enable-profiling"]+ spec = PackageSpec+ { directory = "PackageTests" </> "TemplateHaskell" </> "profiling"+ , configOpts = flags+ , distPref = Nothing+ } result <- cabal_build spec ghcPath assertBuildSucceeded result @@ -26,7 +32,10 @@ let flags = ["--enable-shared" -- ,"--disable-library-vanilla" ,"--enable-executable-dynamic"]- spec = PackageSpec ("PackageTests" </>- "TemplateHaskell" </> "dynamic") flags+ spec = PackageSpec+ { directory = "PackageTests" </> "TemplateHaskell" </> "dynamic"+ , configOpts = flags+ , distPref = Nothing+ } result <- cabal_build spec ghcPath assertBuildSucceeded result
tests/PackageTests/TestOptions/Check.hs view
@@ -6,17 +6,20 @@ suite :: FilePath -> Test suite ghcPath = TestCase $ do- let spec = PackageSpec ("PackageTests" </> "TestOptions")- ["--enable-tests"]+ let spec = PackageSpec+ { directory = "PackageTests" </> "TestOptions"+ , configOpts = ["--enable-tests"]+ , distPref = Nothing+ } _ <- cabal_build spec ghcPath- result <- cabal_test spec ["--test-options=1 2 3"] ghcPath+ result <- cabal_test spec [] ["--test-options=1 2 3"] ghcPath let message = "\"cabal test\" did not pass the correct options to the " ++ "test executable with \"--test-options\"" assertEqual message True $ successful result- result' <- cabal_test spec [ "--test-option=1"- , "--test-option=2"- , "--test-option=3"- ]+ result' <- cabal_test spec [] [ "--test-option=1"+ , "--test-option=2"+ , "--test-option=3"+ ] ghcPath let message' = "\"cabal test\" did not pass the correct options to the " ++ "test executable with \"--test-option\""
tests/PackageTests/TestStanza/Check.hs view
@@ -2,6 +2,7 @@ import Test.HUnit import System.FilePath+import qualified Data.Map as Map import PackageTests.PackageTester import Distribution.Version import Distribution.PackageDescription.Parse (readPackageDescription)@@ -10,27 +11,35 @@ import Distribution.Package (PackageName(..), Dependency(..)) import Distribution.PackageDescription ( PackageDescription(..), BuildInfo(..), TestSuite(..)- , TestSuiteInterface(..), emptyBuildInfo, emptyTestSuite)+ , TestSuiteInterface(..), emptyBuildInfo, emptyTestSuite+ , defaultRenaming) import Distribution.Verbosity (silent) import Distribution.System (buildPlatform)-import Distribution.Compiler (CompilerId(..), CompilerFlavor(..))+import Distribution.Compiler+ ( CompilerId(..), CompilerFlavor(..), unknownCompilerInfo, AbiTag(..) ) import Distribution.Text suite :: FilePath -> Test suite ghcPath = TestCase $ do let dir = "PackageTests" </> "TestStanza" pdFile = dir </> "my" <.> "cabal"- spec = PackageSpec dir []+ spec = PackageSpec+ { directory = dir+ , configOpts = []+ , distPref = Nothing+ } result <- cabal_configure spec ghcPath assertOutputDoesNotContain "unknown section type" result genPD <- readPackageDescription silent pdFile- let compiler = CompilerId GHC $ Version [6, 12, 2] []+ let compiler = unknownCompilerInfo (CompilerId GHC $ Version [6, 12, 2] []) NoAbiTag anticipatedTestSuite = emptyTestSuite { testName = "dummy" , testInterface = TestSuiteExeV10 (Version [1,0] []) "dummy.hs" , testBuildInfo = emptyBuildInfo { targetBuildDepends = [ Dependency (PackageName "base") anyVersion ]+ , targetBuildRenaming =+ Map.singleton (PackageName "base") defaultRenaming , hsSourceDirs = ["."] } , testEnabled = False
tests/PackageTests/TestSuiteExeV10/Check.hs view
@@ -1,65 +1,138 @@-module PackageTests.TestSuiteExeV10.Check- ( checkTest- , checkTestWithHpc- ) where+module PackageTests.TestSuiteExeV10.Check (checks) where -import Distribution.PackageDescription ( TestSuite(..), emptyTestSuite )-import Distribution.Version ( Version(..), orLaterVersion )-import Distribution.Simple.Hpc-import Distribution.Simple.Program.Builtin ( hpcProgram )-import Distribution.Simple.Program.Db ( emptyProgramDb, configureProgram,- requireProgramVersion )-import PackageTests.PackageTester-import qualified Control.Exception as E ( IOException, catch )-import Control.Monad ( when )-import System.Directory+import qualified Control.Exception as E (IOException, catch)+import Control.Monad (when)+import Data.Maybe (catMaybes)+import System.Directory ( doesFileExist ) import System.FilePath-import Test.HUnit+import qualified Test.Framework as TF+import Test.Framework (testGroup)+import Test.Framework.Providers.HUnit (hUnitTestToTests)+import Test.HUnit hiding ( path ) +import Distribution.Simple.Configure (getPersistBuildConfig)+import Distribution.Simple.Hpc+import Distribution.Simple.Program.Builtin (hpcProgram)+import Distribution.Simple.Program.Db+ ( emptyProgramDb, configureProgram, requireProgramVersion ) import qualified Distribution.Verbosity as Verbosity+import Distribution.Version (Version(..), orLaterVersion) +import PackageTests.PackageTester++checks :: FilePath -> [TF.Test]+checks ghcPath =+ [ hunit "Test" $ checkTest ghcPath ]+ ++ hpcTestMatrix ghcPath +++ [ hunit "TestNoHpc/NoTix" $ checkTestNoHpcNoTix ghcPath+ , hunit "TestNoHpc/NoMarkup" $ checkTestNoHpcNoMarkup ghcPath+ ]++hpcTestMatrix :: FilePath -> [TF.Test]+hpcTestMatrix ghcPath = do+ libProf <- [True, False]+ exeProf <- [True, False]+ exeDyn <- [True, False]+ shared <- [True, False]+ let name = concat+ [ "WithHpc-"+ , if libProf then "LibProf" else ""+ , if exeProf then "ExeProf" else ""+ , if exeDyn then "ExeDyn" else ""+ , if shared then "Shared" else ""+ ]+ enable cond flag+ | cond = Just $ "--enable-" ++ flag+ | otherwise = Nothing+ opts = catMaybes+ [ enable libProf "library-profiling"+ , enable exeProf "profiling"+ , enable exeDyn "executable-dynamic"+ , enable shared "shared"+ ]+ return $ hunit name $ checkTestWithHpc ghcPath name opts+ dir :: FilePath dir = "PackageTests" </> "TestSuiteExeV10" checkTest :: FilePath -> Test-checkTest ghcPath = TestCase $ do- let spec = PackageSpec dir ["--enable-tests"]+checkTest ghcPath = TestCase $ buildAndTest ghcPath "Default" [] []++shouldExist :: FilePath -> Assertion+shouldExist path = doesFileExist path >>= assertBool (path ++ " should exist")++shouldNotExist :: FilePath -> Assertion+shouldNotExist path =+ doesFileExist path >>= assertBool (path ++ " should exist") . not++-- | Ensure that both .tix file and markup are generated if coverage is enabled.+checkTestWithHpc :: FilePath -> String -> [String] -> Test+checkTestWithHpc ghcPath name extraOpts = TestCase $ do+ isCorrectVersion <- correctHpcVersion+ when isCorrectVersion $ do+ buildAndTest ghcPath name [] ("--enable-coverage" : extraOpts)+ lbi <- getPersistBuildConfig (dir </> "dist-" ++ name)+ let way = guessWay lbi+ mapM_ shouldExist+ [ mixDir (dir </> "dist-" ++ name) way "my-0.1"+ </> "my-0.1" </> "Foo.mix"+ , mixDir (dir </> "dist-" ++ name) way "test-Foo" </> "Main.mix"+ , tixFilePath (dir </> "dist-" ++ name) way "test-Foo"+ , htmlDir (dir </> "dist-" ++ name) way "test-Foo"+ </> "hpc_index.html"+ ]++-- | Ensures that even if -fhpc is manually provided no .tix file is output.+checkTestNoHpcNoTix :: FilePath -> Test+checkTestNoHpcNoTix ghcPath = TestCase $ do+ buildAndTest ghcPath "NoHpcNoTix" []+ [ "--ghc-option=-fhpc"+ , "--ghc-option=-hpcdir"+ , "--ghc-option=dist-NoHpcNoTix/hpc/vanilla" ]+ lbi <- getPersistBuildConfig (dir </> "dist-NoHpcNoTix")+ let way = guessWay lbi+ shouldNotExist $ tixFilePath (dir </> "dist-NoHpcNoTix") way "test-Foo"++-- | Ensures that even if a .tix file happens to be left around+-- markup isn't generated.+checkTestNoHpcNoMarkup :: FilePath -> Test+checkTestNoHpcNoMarkup ghcPath = TestCase $ do+ let tixFile = tixFilePath "dist-NoHpcNoMarkup" Vanilla "test-Foo"+ buildAndTest ghcPath "NoHpcNoMarkup"+ [("HPCTIXFILE", Just tixFile)]+ [ "--ghc-option=-fhpc"+ , "--ghc-option=-hpcdir"+ , "--ghc-option=dist-NoHpcNoMarkup/hpc/vanilla" ]+ shouldNotExist $ htmlDir (dir </> "dist-NoHpcNoMarkup") Vanilla "test-Foo" </> "hpc_index.html"++-- | Build and test a package and ensure that both were successful.+--+-- The flag "--enable-tests" is provided in addition to the given flags.+buildAndTest :: FilePath -> String -> [(String, Maybe String)] -> [String] -> IO ()+buildAndTest ghcPath name envOverrides flags = do+ let spec = PackageSpec+ { directory = dir+ , distPref = Just $ "dist-" ++ name+ , configOpts = "--enable-tests" : flags+ } buildResult <- cabal_build spec ghcPath assertBuildSucceeded buildResult- testResult <- cabal_test spec [] ghcPath+ testResult <- cabal_test spec envOverrides [] ghcPath assertTestSucceeded testResult -checkTestWithHpc :: FilePath -> Test-checkTestWithHpc ghcPath = TestCase $ do- isCorrectVersion <- checkHpcVersion- when isCorrectVersion $ do- let spec = PackageSpec dir [ "--enable-tests"- , "--enable-library-coverage"- ]- buildResult <- cabal_build spec ghcPath- assertBuildSucceeded buildResult- testResult <- cabal_test spec [] ghcPath- assertTestSucceeded testResult- let dummy = emptyTestSuite { testName = "test-Foo" }- tixFile = tixFilePath (dir </> "dist") $ testName dummy- tixFileMessage = ".tix file should exist"- markupDir = htmlDir (dir </> "dist") $ testName dummy- markupFile = markupDir </> "hpc_index" <.> "html"- markupFileMessage = "HPC markup file should exist"- tixFileExists <- doesFileExist tixFile- assertEqual tixFileMessage True tixFileExists- markupFileExists <- doesFileExist markupFile- assertEqual markupFileMessage True markupFileExists- where- checkHpcVersion :: IO Bool- checkHpcVersion = do- let programDb' = emptyProgramDb- let verbosity = Verbosity.normal- let verRange = orLaterVersion (Version [0,7] [])- programDb <- configureProgram verbosity hpcProgram programDb'- (requireProgramVersion verbosity hpcProgram verRange programDb- >> return True) `catchIO` (\_ -> return False)+hunit :: TF.TestName -> Test -> TF.Test+hunit name = testGroup name . hUnitTestToTests - -- Distirubution.Compat.Exception is hidden.+-- | Checks for a suitable HPC version for testing.+correctHpcVersion :: IO Bool+correctHpcVersion = do+ let programDb' = emptyProgramDb+ let verbosity = Verbosity.normal+ let verRange = orLaterVersion (Version [0,7] [])+ programDb <- configureProgram verbosity hpcProgram programDb'+ (requireProgramVersion verbosity hpcProgram verRange programDb+ >> return True) `catchIO` (\_ -> return False)+ where+ -- Distribution.Compat.Exception is hidden. catchIO :: IO a -> (E.IOException -> IO a) -> IO a catchIO = E.catch
− tests/README
@@ -1,22 +0,0 @@-Writing Package Tests-=====================--The tests under the `PackageTests` directory define and build packages which-exercise various components of Cabal. Each test case is an `HUnit` test. The-entry point for the test suite, where all the test cases are listed, is-`PackageTests.hs`. There are utilities for calling the stages of Cabal's build-process in `PackageTests/PackageTester.hs`; have a look at an existing test case-to see how they're used.--It is very important that package tests use the in-place version of Cabal,-rather than the system version. Several long-standing bugs in the test suite-were caused by testing the system (rather than the newly-compiled) version of-Cabal. There are two places where the system Cabal can accidentally be invoked:-1. Compiling `Setup.hs`. `runghc` needs to be told about the in-place package-database. This issue should be solved for all future package tests; see-`compileSetup` in `PackageTests/PackageTester.hs`.-2. Compiling a package which depends on Cabal. In particular, packages with-`detailed` type test suites depend on the Cabal library directly, so it is-important that they are configured to use the in-place package database. The-test suite already creates a stub `PackageSpec` for this case; see-`PackageTests/BuildTestSuiteDetailedV09/Check.hs` to see how it is used.
+ tests/README.md view
@@ -0,0 +1,34 @@+Writing package tests+=====================++The tests under the [PackageTests] directory define and build packages+that exercise various components of Cabal. Each test case is an [HUnit]+test. The entry point for the test suite, where all the test cases are+listed, is [PackageTests.hs]. There are utilities for calling the stages+of Cabal's build process in [PackageTests/PackageTester.hs]; have a look+at an existing test case to see how they are used.++It is important that package tests use the in-place version of Cabal+rather than the system version. Several long-standing bugs in the test+suite were caused by testing the system (rather than the newly compiled)+version of Cabal. There are two places where the system Cabal can+accidentally be invoked:++1. Compiling `Setup.hs`. `runghc` needs to be told about the in-place+ package database. This issue should be solved for all future package+ tests; see `compileSetup` in [PackageTests/PackageTester.hs].++2. Compiling a package which depends on Cabal. In particular, packages+ with the [detailed]-type test suites depend on the Cabal library+ directly, so it is important that they are configured to use the+ in-place package database. The test suite already creates a stub+ `PackageSpec` for this case; see+ [PackageTests/BuildTestSuiteDetailedV09/Check.hs] to see how it is+ used.++[PackageTests]: PackageTests+[HUnit]: http://hackage.haskell.org/package/HUnit+[PackageTests.hs]: PackageTests.hs+[PackageTests/PackageTester.hs]: PackageTests/PackageTester.hs+[detailed]: ../Distribution/TestSuite.hs+[PackageTests/BuildTestSuiteDetailedV09/Check.hs]: PackageTests/BuildTestSuiteDetailedV09/Check.hs
tests/UnitTests.hs view
@@ -5,12 +5,18 @@ import System.IO (BufferMode(NoBuffering), hSetBuffering, stdout) import Test.Framework +import qualified UnitTests.Distribution.Compat.CreatePipe import qualified UnitTests.Distribution.Compat.ReadP+import qualified UnitTests.Distribution.Utils.NubList tests :: [Test]-tests = [- testGroup "Distribution.Compat.ReadP"+tests =+ [ testGroup "Distribution.Compat.ReadP" UnitTests.Distribution.Compat.ReadP.tests+ , testGroup "Distribution.Compat.CreatePipe"+ UnitTests.Distribution.Compat.CreatePipe.tests+ , testGroup "Distribution.Utils.NubList"+ UnitTests.Distribution.Utils.NubList.tests ] main :: IO ()
+ tests/UnitTests/Distribution/Compat/CreatePipe.hs view
@@ -0,0 +1,20 @@+module UnitTests.Distribution.Compat.CreatePipe (tests) where++import Distribution.Compat.CreatePipe+import System.IO (hClose, hGetContents, hPutStr, hSetEncoding, localeEncoding)+import Test.Framework+import Test.Framework.Providers.HUnit+import Test.HUnit hiding (Test)++tests :: [Test]+tests = [testCase "Locale Encoding" case_Locale_Encoding]++case_Locale_Encoding :: Assertion+case_Locale_Encoding = assert $ do+ let str = "\0252"+ (r, w) <- createPipe+ hSetEncoding w localeEncoding+ out <- hGetContents r+ hPutStr w str+ hClose w+ return $! out == str
+ tests/UnitTests/Distribution/Utils/NubList.hs view
@@ -0,0 +1,44 @@+module UnitTests.Distribution.Utils.NubList+ ( tests+ ) where++import Data.Monoid+import Distribution.Utils.NubList+import Test.Framework+import Test.Framework.Providers.HUnit (testCase)+import Test.Framework.Providers.QuickCheck2+import Test.HUnit (Assertion, assertBool)++tests :: [Test]+tests =+ [ testCase "Numlist retains ordering" testOrdering+ , testCase "Numlist removes duplicates" testDeDupe+ , testProperty "Monoid Numlist Identity" prop_Identity+ , testProperty "Monoid Numlist Associativity" prop_Associativity+ ]++someIntList :: [Int]+-- This list must not have duplicate entries.+someIntList = [ 1, 3, 4, 2, 0, 7, 6, 5, 9, -1 ]++testOrdering :: Assertion+testOrdering =+ assertBool "Maintains element ordering:" $+ fromNubList (toNubList someIntList) == someIntList++testDeDupe :: Assertion+testDeDupe =+ assertBool "De-duplicates a list:" $+ fromNubList (toNubList (someIntList ++ someIntList)) == someIntList++-- ---------------------------------------------------------------------------+-- QuickCheck properties for NubList++prop_Identity :: [Int] -> Bool+prop_Identity xs =+ mempty `mappend` toNubList xs == toNubList xs `mappend` mempty++prop_Associativity :: [Int] -> [Int] -> [Int] -> Bool+prop_Associativity xs ys zs =+ (toNubList xs `mappend` toNubList ys) `mappend` toNubList zs+ == toNubList xs `mappend` (toNubList ys `mappend` toNubList zs)