Cabal 3.12.1.0 → 3.14.0.0
raw patch · 88 files changed
+10708/−5173 lines, 88 filesdep ~Cabal-syntaxdep ~basedep ~containersPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: Cabal-syntax, base, containers
API changes (from Hackage documentation)
- Distribution.Simple.BuildPaths: haddockName :: PackageDescription -> FilePath
- Distribution.Simple.Compiler: data PackageDB
- Distribution.Simple.Compiler: instance Data.Binary.Class.Binary Distribution.Simple.Compiler.PackageDB
- Distribution.Simple.Compiler: instance Distribution.Utils.Structured.Structured Distribution.Simple.Compiler.PackageDB
- Distribution.Simple.Compiler: instance GHC.Classes.Eq Distribution.Simple.Compiler.PackageDB
- Distribution.Simple.Compiler: instance GHC.Classes.Ord Distribution.Simple.Compiler.PackageDB
- Distribution.Simple.Compiler: instance GHC.Generics.Generic Distribution.Simple.Compiler.PackageDB
- Distribution.Simple.Compiler: instance GHC.Read.Read Distribution.Simple.Compiler.PackageDB
- Distribution.Simple.Compiler: instance GHC.Show.Show Distribution.Simple.Compiler.PackageDB
- Distribution.Simple.Errors: FindFileCwd :: FilePath -> CabalException
- Distribution.Simple.Errors: FindFileEx :: FilePath -> CabalException
- Distribution.Simple.GHC: isDynamic :: Compiler -> Bool
- Distribution.Simple.Glob.Internal: EmptyGlob :: GlobSyntaxError
- Distribution.Simple.Glob.Internal: GlobMatch :: a -> GlobResult a
- Distribution.Simple.Glob.Internal: GlobMatchesDirectory :: a -> GlobResult a
- Distribution.Simple.Glob.Internal: GlobMissingDirectory :: a -> GlobResult a
- Distribution.Simple.Glob.Internal: GlobWarnMultiDot :: a -> GlobResult a
- Distribution.Simple.Glob.Internal: LiteralFileNameGlobStar :: GlobSyntaxError
- Distribution.Simple.Glob.Internal: NoExtensionOnStar :: GlobSyntaxError
- Distribution.Simple.Glob.Internal: StarInDirectory :: GlobSyntaxError
- Distribution.Simple.Glob.Internal: StarInExtension :: GlobSyntaxError
- Distribution.Simple.Glob.Internal: StarInFileName :: GlobSyntaxError
- Distribution.Simple.Glob.Internal: VersionDoesNotSupportGlob :: GlobSyntaxError
- Distribution.Simple.Glob.Internal: VersionDoesNotSupportGlobStar :: GlobSyntaxError
- Distribution.Simple.Glob.Internal: checkNameMatches :: CabalSpecVersion -> GlobPieces -> String -> Maybe (GlobResult ())
- Distribution.Simple.Glob.Internal: data GlobResult a
- Distribution.Simple.Glob.Internal: data GlobSyntaxError
- Distribution.Simple.Glob.Internal: enableMultidot :: CabalSpecVersion -> Bool
- Distribution.Simple.Glob.Internal: explainGlobSyntaxError :: FilePath -> GlobSyntaxError -> String
- Distribution.Simple.Glob.Internal: fileGlobMatches :: CabalSpecVersion -> Glob -> FilePath -> Maybe (GlobResult ())
- Distribution.Simple.Glob.Internal: instance GHC.Base.Functor Distribution.Simple.Glob.Internal.GlobResult
- Distribution.Simple.Glob.Internal: instance GHC.Classes.Eq Distribution.Simple.Glob.Internal.GlobSyntaxError
- Distribution.Simple.Glob.Internal: instance GHC.Classes.Eq a => GHC.Classes.Eq (Distribution.Simple.Glob.Internal.GlobResult a)
- Distribution.Simple.Glob.Internal: instance GHC.Classes.Ord a => GHC.Classes.Ord (Distribution.Simple.Glob.Internal.GlobResult a)
- Distribution.Simple.Glob.Internal: instance GHC.Show.Show Distribution.Simple.Glob.Internal.GlobSyntaxError
- Distribution.Simple.Glob.Internal: instance GHC.Show.Show a => GHC.Show.Show (Distribution.Simple.Glob.Internal.GlobResult a)
- Distribution.Simple.Glob.Internal: isRecursiveInRoot :: Glob -> Bool
- Distribution.Simple.Glob.Internal: matchGlob :: FilePath -> Glob -> IO [FilePath]
- Distribution.Simple.Glob.Internal: matchGlobPieces :: GlobPieces -> String -> Bool
- Distribution.Simple.Glob.Internal: parseFileGlob :: CabalSpecVersion -> FilePath -> Either GlobSyntaxError Glob
- Distribution.Simple.Glob.Internal: runDirFileGlob :: Verbosity -> Maybe CabalSpecVersion -> FilePath -> Glob -> IO [GlobResult FilePath]
- Distribution.Simple.LocalBuildInfo: cabalFilePath :: LocalBuildInfo -> Maybe FilePath
- Distribution.Simple.Setup: [benchmarkDistPref] :: BenchmarkFlags -> Flag FilePath
- Distribution.Simple.Setup: [benchmarkVerbosity] :: BenchmarkFlags -> Flag Verbosity
- Distribution.Simple.Setup: [buildArgs] :: BuildFlags -> [String]
- Distribution.Simple.Setup: [buildCabalFilePath] :: BuildFlags -> Flag FilePath
- Distribution.Simple.Setup: [buildDistPref] :: BuildFlags -> Flag FilePath
- Distribution.Simple.Setup: [buildVerbosity] :: BuildFlags -> Flag Verbosity
- Distribution.Simple.Setup: [cleanCabalFilePath] :: CleanFlags -> Flag FilePath
- Distribution.Simple.Setup: [cleanDistPref] :: CleanFlags -> Flag FilePath
- Distribution.Simple.Setup: [cleanVerbosity] :: CleanFlags -> Flag Verbosity
- Distribution.Simple.Setup: [configArgs] :: ConfigFlags -> [String]
- Distribution.Simple.Setup: [configCabalFilePath] :: ConfigFlags -> Flag FilePath
- Distribution.Simple.Setup: [configDistPref] :: ConfigFlags -> Flag FilePath
- Distribution.Simple.Setup: [configVerbosity] :: ConfigFlags -> Flag Verbosity
- Distribution.Simple.Setup: [copyArgs] :: CopyFlags -> [String]
- Distribution.Simple.Setup: [copyCabalFilePath] :: CopyFlags -> Flag FilePath
- Distribution.Simple.Setup: [copyDistPref] :: CopyFlags -> Flag FilePath
- Distribution.Simple.Setup: [copyVerbosity] :: CopyFlags -> Flag Verbosity
- Distribution.Simple.Setup: [haddockArgs] :: HaddockFlags -> [String]
- Distribution.Simple.Setup: [haddockCabalFilePath] :: HaddockFlags -> Flag FilePath
- Distribution.Simple.Setup: [haddockDistPref] :: HaddockFlags -> Flag FilePath
- Distribution.Simple.Setup: [haddockLib] :: HaddockFlags -> Flag String
- Distribution.Simple.Setup: [haddockProjectLib] :: HaddockProjectFlags -> Flag String
- Distribution.Simple.Setup: [haddockProjectOutputDir] :: HaddockProjectFlags -> Flag FilePath
- Distribution.Simple.Setup: [haddockVerbosity] :: HaddockFlags -> Flag Verbosity
- Distribution.Simple.Setup: [hscolourCabalFilePath] :: HscolourFlags -> Flag FilePath
- Distribution.Simple.Setup: [hscolourDistPref] :: HscolourFlags -> Flag FilePath
- Distribution.Simple.Setup: [hscolourVerbosity] :: HscolourFlags -> Flag Verbosity
- Distribution.Simple.Setup: [installCabalFilePath] :: InstallFlags -> Flag FilePath
- Distribution.Simple.Setup: [installDistPref] :: InstallFlags -> Flag FilePath
- Distribution.Simple.Setup: [installVerbosity] :: InstallFlags -> Flag Verbosity
- Distribution.Simple.Setup: [regArgs] :: RegisterFlags -> [String]
- Distribution.Simple.Setup: [regCabalFilePath] :: RegisterFlags -> Flag FilePath
- Distribution.Simple.Setup: [regDistPref] :: RegisterFlags -> Flag FilePath
- Distribution.Simple.Setup: [regVerbosity] :: RegisterFlags -> Flag Verbosity
- Distribution.Simple.Setup: [replDistPref] :: ReplFlags -> Flag FilePath
- Distribution.Simple.Setup: [replVerbosity] :: ReplFlags -> Flag Verbosity
- Distribution.Simple.Setup: [sDistDistPref] :: SDistFlags -> Flag FilePath
- Distribution.Simple.Setup: [sDistVerbosity] :: SDistFlags -> Flag Verbosity
- Distribution.Simple.Setup: [testDistPref] :: TestFlags -> Flag FilePath
- Distribution.Simple.Setup: [testVerbosity] :: TestFlags -> Flag Verbosity
- Distribution.Simple.Setup: configAbsolutePaths :: ConfigFlags -> IO ConfigFlags
- Distribution.Simple.Utils: currentDir :: FilePath
- Distribution.Simple.Utils: defaultPackageDesc :: Verbosity -> IO FilePath
- Distribution.Simple.Utils: findPackageDescCwd :: FilePath -> FilePath -> IO (Either CabalException FilePath)
- Distribution.Simple.Utils: tryFindPackageDescCwd :: Verbosity -> FilePath -> FilePath -> IO FilePath
- Distribution.Types.LocalBuildInfo: cabalFilePath :: LocalBuildInfo -> Maybe FilePath
- Distribution.Types.LocalBuildInfo: configFlagsBuildDir :: ConfigFlags -> FilePath
+ Distribution.PackageDescription.Check: GitProtocol :: CheckExplanation
+ Distribution.Simple: autoconfSetupHooks :: SetupHooks
+ Distribution.Simple: defaultMainWithSetupHooks :: SetupHooks -> IO ()
+ Distribution.Simple: defaultMainWithSetupHooksArgs :: SetupHooks -> [String] -> IO ()
+ Distribution.Simple.Build: addInternalBuildTools :: PackageDescription -> LocalBuildInfo -> BuildInfo -> ProgramDb -> ProgramDb
+ Distribution.Simple.Build: build_setupHooks :: BuildHooks -> PackageDescription -> LocalBuildInfo -> BuildFlags -> [PPSuffixHandler] -> IO ()
+ Distribution.Simple.Build: repl_setupHooks :: BuildHooks -> PackageDescription -> LocalBuildInfo -> ReplFlags -> [PPSuffixHandler] -> [String] -> IO ()
+ Distribution.Simple.Build.Inputs: buildingWhatCommonFlags :: BuildingWhat -> CommonSetupFlags
+ Distribution.Simple.Build.Inputs: buildingWhatWorkingDir :: BuildingWhat -> Maybe (SymbolicPath CWD (Dir Pkg))
+ Distribution.Simple.BuildPaths: benchmarkBuildDir :: LocalBuildInfo -> Benchmark -> SymbolicPath Pkg (Dir Build)
+ Distribution.Simple.BuildPaths: getBenchmarkSourceFiles :: Verbosity -> LocalBuildInfo -> Benchmark -> ComponentLocalBuildInfo -> IO [(ModuleName, SymbolicPath Pkg 'File)]
+ Distribution.Simple.BuildPaths: getTestSourceFiles :: Verbosity -> LocalBuildInfo -> TestSuite -> ComponentLocalBuildInfo -> IO [(ModuleName, SymbolicPath Pkg 'File)]
+ Distribution.Simple.BuildPaths: haddockBenchmarkDirPath :: HaddockTarget -> PackageDescription -> Benchmark -> FilePath
+ Distribution.Simple.BuildPaths: haddockLibraryDirPath :: HaddockTarget -> PackageDescription -> Library -> FilePath
+ Distribution.Simple.BuildPaths: haddockLibraryName :: PackageDescription -> Library -> String
+ Distribution.Simple.BuildPaths: haddockLibraryPath :: PackageDescription -> Library -> FilePath
+ Distribution.Simple.BuildPaths: haddockPackageLibraryName :: PackageDescription -> Library -> String
+ Distribution.Simple.BuildPaths: haddockPackageLibraryName' :: PackageName -> LibraryName -> String
+ Distribution.Simple.BuildPaths: haddockPath :: PackageDescription -> FilePath
+ Distribution.Simple.BuildPaths: haddockTestDirPath :: HaddockTarget -> PackageDescription -> TestSuite -> FilePath
+ Distribution.Simple.BuildPaths: mkProfSharedLibName :: Platform -> CompilerId -> UnitId -> String
+ Distribution.Simple.BuildPaths: stubName :: TestSuite -> FilePath
+ Distribution.Simple.BuildPaths: testBuildDir :: LocalBuildInfo -> TestSuite -> SymbolicPath Pkg (Dir Build)
+ Distribution.Simple.BuildWay: DynWay :: BuildWay
+ Distribution.Simple.BuildWay: ProfDynWay :: BuildWay
+ Distribution.Simple.BuildWay: ProfWay :: BuildWay
+ Distribution.Simple.BuildWay: StaticWay :: BuildWay
+ Distribution.Simple.BuildWay: buildWayPrefix :: BuildWay -> String
+ Distribution.Simple.BuildWay: data BuildWay
+ Distribution.Simple.BuildWay: instance GHC.Classes.Eq Distribution.Simple.BuildWay.BuildWay
+ Distribution.Simple.BuildWay: instance GHC.Classes.Ord Distribution.Simple.BuildWay.BuildWay
+ Distribution.Simple.BuildWay: instance GHC.Enum.Enum Distribution.Simple.BuildWay.BuildWay
+ Distribution.Simple.BuildWay: instance GHC.Read.Read Distribution.Simple.BuildWay.BuildWay
+ Distribution.Simple.BuildWay: instance GHC.Show.Show Distribution.Simple.BuildWay.BuildWay
+ Distribution.Simple.Command: fmapOptDescr :: forall a b. (b -> a) -> (a -> b -> b) -> OptDescr a -> OptDescr b
+ Distribution.Simple.Compiler: coercePackageDB :: PackageDBCWD -> PackageDBX (SymbolicPath CWD (Dir PkgDB))
+ Distribution.Simple.Compiler: coercePackageDBStack :: [PackageDBCWD] -> [PackageDBX (SymbolicPath CWD (Dir PkgDB))]
+ Distribution.Simple.Compiler: data PackageDBX fp
+ Distribution.Simple.Compiler: dynamicSupported :: Compiler -> Maybe Bool
+ Distribution.Simple.Compiler: instance Data.Binary.Class.Binary fp => Data.Binary.Class.Binary (Distribution.Simple.Compiler.PackageDBX fp)
+ Distribution.Simple.Compiler: instance Data.Foldable.Foldable Distribution.Simple.Compiler.PackageDBX
+ Distribution.Simple.Compiler: instance Data.Traversable.Traversable Distribution.Simple.Compiler.PackageDBX
+ Distribution.Simple.Compiler: instance Distribution.Utils.Structured.Structured fp => Distribution.Utils.Structured.Structured (Distribution.Simple.Compiler.PackageDBX fp)
+ Distribution.Simple.Compiler: instance GHC.Base.Functor Distribution.Simple.Compiler.PackageDBX
+ Distribution.Simple.Compiler: instance GHC.Classes.Eq fp => GHC.Classes.Eq (Distribution.Simple.Compiler.PackageDBX fp)
+ Distribution.Simple.Compiler: instance GHC.Classes.Ord fp => GHC.Classes.Ord (Distribution.Simple.Compiler.PackageDBX fp)
+ Distribution.Simple.Compiler: instance GHC.Generics.Generic (Distribution.Simple.Compiler.PackageDBX fp)
+ Distribution.Simple.Compiler: instance GHC.Read.Read fp => GHC.Read.Read (Distribution.Simple.Compiler.PackageDBX fp)
+ Distribution.Simple.Compiler: instance GHC.Show.Show fp => GHC.Show.Show (Distribution.Simple.Compiler.PackageDBX fp)
+ Distribution.Simple.Compiler: interpretPackageDB :: Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDB -> PackageDBCWD
+ Distribution.Simple.Compiler: interpretPackageDBStack :: Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDBStack -> PackageDBStackCWD
+ Distribution.Simple.Compiler: profilingDynamicSupported :: Compiler -> Maybe Bool
+ Distribution.Simple.Compiler: profilingDynamicSupportedOrUnknown :: Compiler -> Bool
+ Distribution.Simple.Compiler: profilingVanillaSupported :: Compiler -> Maybe Bool
+ Distribution.Simple.Compiler: profilingVanillaSupportedOrUnknown :: Compiler -> Bool
+ Distribution.Simple.Compiler: type PackageDB = PackageDBX (SymbolicPath Pkg (Dir PkgDB))
+ Distribution.Simple.Compiler: type PackageDBCWD = PackageDBX FilePath
+ Distribution.Simple.Compiler: type PackageDBS from = PackageDBX (SymbolicPath from (Dir PkgDB))
+ Distribution.Simple.Compiler: type PackageDBStackCWD = PackageDBStackX FilePath
+ Distribution.Simple.Compiler: type PackageDBStackS from = PackageDBStackX (SymbolicPath from (Dir PkgDB))
+ Distribution.Simple.Compiler: type PackageDBStackX from = [PackageDBX from]
+ Distribution.Simple.Configure: [cfgStateFileErrorCwd] :: ConfigStateFileError -> Maybe (SymbolicPath CWD (Dir Pkg))
+ Distribution.Simple.Configure: [cfgStateFileErrorFile] :: ConfigStateFileError -> SymbolicPath Pkg File
+ Distribution.Simple.Configure: configure_setupHooks :: ConfigureHooks -> (GenericPackageDescription, HookedBuildInfo) -> ConfigFlags -> IO LocalBuildInfo
+ Distribution.Simple.Errors: FindFile :: FilePath -> CabalException
+ Distribution.Simple.Errors: SetupHooksException :: SetupHooksException -> CabalException
+ Distribution.Simple.FileMonitor.Types: DirExists :: MonitorKindDir
+ Distribution.Simple.FileMonitor.Types: DirModTime :: MonitorKindDir
+ Distribution.Simple.FileMonitor.Types: DirNotExists :: MonitorKindDir
+ Distribution.Simple.FileMonitor.Types: FileExists :: MonitorKindFile
+ Distribution.Simple.FileMonitor.Types: FileHashed :: MonitorKindFile
+ Distribution.Simple.FileMonitor.Types: FileModTime :: MonitorKindFile
+ Distribution.Simple.FileMonitor.Types: FileNotExists :: MonitorKindFile
+ Distribution.Simple.FileMonitor.Types: FilePathHomeDir :: FilePathRoot
+ Distribution.Simple.FileMonitor.Types: FilePathRelative :: FilePathRoot
+ Distribution.Simple.FileMonitor.Types: FilePathRoot :: FilePath -> FilePathRoot
+ Distribution.Simple.FileMonitor.Types: MonitorFile :: !MonitorKindFile -> !MonitorKindDir -> !FilePath -> MonitorFilePath
+ Distribution.Simple.FileMonitor.Types: MonitorFileGlob :: !MonitorKindFile -> !MonitorKindDir -> !RootedGlob -> MonitorFilePath
+ Distribution.Simple.FileMonitor.Types: RootedGlob :: FilePathRoot -> Glob -> RootedGlob
+ Distribution.Simple.FileMonitor.Types: [monitorKindDir] :: MonitorFilePath -> !MonitorKindDir
+ Distribution.Simple.FileMonitor.Types: [monitorKindFile] :: MonitorFilePath -> !MonitorKindFile
+ Distribution.Simple.FileMonitor.Types: [monitorPathGlob] :: MonitorFilePath -> !RootedGlob
+ Distribution.Simple.FileMonitor.Types: [monitorPath] :: MonitorFilePath -> !FilePath
+ Distribution.Simple.FileMonitor.Types: data FilePathRoot
+ Distribution.Simple.FileMonitor.Types: data Glob
+ Distribution.Simple.FileMonitor.Types: data MonitorFilePath
+ Distribution.Simple.FileMonitor.Types: data MonitorKindDir
+ Distribution.Simple.FileMonitor.Types: data MonitorKindFile
+ Distribution.Simple.FileMonitor.Types: data RootedGlob
+ Distribution.Simple.FileMonitor.Types: instance Data.Binary.Class.Binary Distribution.Simple.FileMonitor.Types.FilePathRoot
+ Distribution.Simple.FileMonitor.Types: instance Data.Binary.Class.Binary Distribution.Simple.FileMonitor.Types.MonitorFilePath
+ Distribution.Simple.FileMonitor.Types: instance Data.Binary.Class.Binary Distribution.Simple.FileMonitor.Types.MonitorKindDir
+ Distribution.Simple.FileMonitor.Types: instance Data.Binary.Class.Binary Distribution.Simple.FileMonitor.Types.MonitorKindFile
+ Distribution.Simple.FileMonitor.Types: instance Data.Binary.Class.Binary Distribution.Simple.FileMonitor.Types.RootedGlob
+ Distribution.Simple.FileMonitor.Types: instance Distribution.Parsec.Parsec Distribution.Simple.FileMonitor.Types.FilePathRoot
+ Distribution.Simple.FileMonitor.Types: instance Distribution.Parsec.Parsec Distribution.Simple.FileMonitor.Types.RootedGlob
+ Distribution.Simple.FileMonitor.Types: instance Distribution.Pretty.Pretty Distribution.Simple.FileMonitor.Types.FilePathRoot
+ Distribution.Simple.FileMonitor.Types: instance Distribution.Pretty.Pretty Distribution.Simple.FileMonitor.Types.RootedGlob
+ Distribution.Simple.FileMonitor.Types: instance Distribution.Utils.Structured.Structured Distribution.Simple.FileMonitor.Types.FilePathRoot
+ Distribution.Simple.FileMonitor.Types: instance Distribution.Utils.Structured.Structured Distribution.Simple.FileMonitor.Types.MonitorFilePath
+ Distribution.Simple.FileMonitor.Types: instance Distribution.Utils.Structured.Structured Distribution.Simple.FileMonitor.Types.MonitorKindDir
+ Distribution.Simple.FileMonitor.Types: instance Distribution.Utils.Structured.Structured Distribution.Simple.FileMonitor.Types.MonitorKindFile
+ Distribution.Simple.FileMonitor.Types: instance Distribution.Utils.Structured.Structured Distribution.Simple.FileMonitor.Types.RootedGlob
+ Distribution.Simple.FileMonitor.Types: instance GHC.Classes.Eq Distribution.Simple.FileMonitor.Types.FilePathRoot
+ Distribution.Simple.FileMonitor.Types: instance GHC.Classes.Eq Distribution.Simple.FileMonitor.Types.MonitorFilePath
+ Distribution.Simple.FileMonitor.Types: instance GHC.Classes.Eq Distribution.Simple.FileMonitor.Types.MonitorKindDir
+ Distribution.Simple.FileMonitor.Types: instance GHC.Classes.Eq Distribution.Simple.FileMonitor.Types.MonitorKindFile
+ Distribution.Simple.FileMonitor.Types: instance GHC.Classes.Eq Distribution.Simple.FileMonitor.Types.RootedGlob
+ Distribution.Simple.FileMonitor.Types: instance GHC.Generics.Generic Distribution.Simple.FileMonitor.Types.FilePathRoot
+ Distribution.Simple.FileMonitor.Types: instance GHC.Generics.Generic Distribution.Simple.FileMonitor.Types.MonitorFilePath
+ Distribution.Simple.FileMonitor.Types: instance GHC.Generics.Generic Distribution.Simple.FileMonitor.Types.MonitorKindDir
+ Distribution.Simple.FileMonitor.Types: instance GHC.Generics.Generic Distribution.Simple.FileMonitor.Types.MonitorKindFile
+ Distribution.Simple.FileMonitor.Types: instance GHC.Generics.Generic Distribution.Simple.FileMonitor.Types.RootedGlob
+ Distribution.Simple.FileMonitor.Types: instance GHC.Show.Show Distribution.Simple.FileMonitor.Types.FilePathRoot
+ Distribution.Simple.FileMonitor.Types: instance GHC.Show.Show Distribution.Simple.FileMonitor.Types.MonitorFilePath
+ Distribution.Simple.FileMonitor.Types: instance GHC.Show.Show Distribution.Simple.FileMonitor.Types.MonitorKindDir
+ Distribution.Simple.FileMonitor.Types: instance GHC.Show.Show Distribution.Simple.FileMonitor.Types.MonitorKindFile
+ Distribution.Simple.FileMonitor.Types: instance GHC.Show.Show Distribution.Simple.FileMonitor.Types.RootedGlob
+ Distribution.Simple.FileMonitor.Types: monitorDirectory :: FilePath -> MonitorFilePath
+ Distribution.Simple.FileMonitor.Types: monitorDirectoryExistence :: FilePath -> MonitorFilePath
+ Distribution.Simple.FileMonitor.Types: monitorFile :: FilePath -> MonitorFilePath
+ Distribution.Simple.FileMonitor.Types: monitorFileExistence :: FilePath -> MonitorFilePath
+ Distribution.Simple.FileMonitor.Types: monitorFileGlob :: RootedGlob -> MonitorFilePath
+ Distribution.Simple.FileMonitor.Types: monitorFileGlobExistence :: RootedGlob -> MonitorFilePath
+ Distribution.Simple.FileMonitor.Types: monitorFileHashed :: FilePath -> MonitorFilePath
+ Distribution.Simple.FileMonitor.Types: monitorFileHashedSearchPath :: [FilePath] -> FilePath -> [MonitorFilePath]
+ Distribution.Simple.FileMonitor.Types: monitorFileOrDirectory :: FilePath -> MonitorFilePath
+ Distribution.Simple.FileMonitor.Types: monitorFileSearchPath :: [FilePath] -> FilePath -> [MonitorFilePath]
+ Distribution.Simple.FileMonitor.Types: monitorNonExistentDirectory :: FilePath -> MonitorFilePath
+ Distribution.Simple.FileMonitor.Types: monitorNonExistentFile :: FilePath -> MonitorFilePath
+ Distribution.Simple.GHC: compilerBuildWay :: Compiler -> BuildWay
+ Distribution.Simple.Glob: instance GHC.Base.Functor Distribution.Simple.Glob.GlobResult
+ Distribution.Simple.Glob: instance GHC.Classes.Eq Distribution.Simple.Glob.GlobSyntaxError
+ Distribution.Simple.Glob: instance GHC.Classes.Eq a => GHC.Classes.Eq (Distribution.Simple.Glob.GlobResult a)
+ Distribution.Simple.Glob: instance GHC.Classes.Ord a => GHC.Classes.Ord (Distribution.Simple.Glob.GlobResult a)
+ Distribution.Simple.Glob: instance GHC.Show.Show Distribution.Simple.Glob.GlobSyntaxError
+ Distribution.Simple.Glob: instance GHC.Show.Show a => GHC.Show.Show (Distribution.Simple.Glob.GlobResult a)
+ Distribution.Simple.Glob: matchGlob :: FilePath -> Glob -> IO [FilePath]
+ Distribution.Simple.Glob: matchGlobPieces :: GlobPieces -> String -> Bool
+ Distribution.Simple.Haddock: haddock_setupHooks :: BuildHooks -> PackageDescription -> LocalBuildInfo -> [PPSuffixHandler] -> HaddockFlags -> IO ()
+ Distribution.Simple.Haddock: hscolour_setupHooks :: BuildHooks -> PackageDescription -> LocalBuildInfo -> [PPSuffixHandler] -> HscolourFlags -> IO ()
+ Distribution.Simple.Hpc: ProfDyn :: Way
+ Distribution.Simple.Install: installFileGlob :: Verbosity -> CabalSpecVersion -> Maybe (SymbolicPath CWD (Dir Pkg)) -> (Maybe (SymbolicPath CWD (Dir DataDir)), SymbolicPath Pkg (Dir DataDir)) -> RelativePath DataDir File -> IO ()
+ Distribution.Simple.Install: install_setupHooks :: InstallHooks -> PackageDescription -> LocalBuildInfo -> CopyFlags -> IO ()
+ Distribution.Simple.LocalBuildInfo: absoluteWorkingDirLBI :: LocalBuildInfo -> IO (AbsolutePath (Dir Pkg))
+ Distribution.Simple.LocalBuildInfo: buildWays :: LocalBuildInfo -> (Bool -> [BuildWay], Bool -> BuildWay, BuildWay)
+ Distribution.Simple.LocalBuildInfo: interpretSymbolicPathLBI :: LocalBuildInfo -> SymbolicPathX allowAbsolute Pkg to -> FilePath
+ Distribution.Simple.LocalBuildInfo: mbWorkDirLBI :: LocalBuildInfo -> Maybe (SymbolicPath CWD (Dir Pkg))
+ Distribution.Simple.LocalBuildInfo: packageRoot :: CommonSetupFlags -> FilePath
+ Distribution.Simple.PreProcess: preprocessFile :: Maybe (SymbolicPath CWD (Dir Pkg)) -> [SymbolicPath Pkg (Dir Source)] -> SymbolicPath Pkg (Dir Build) -> Bool -> RelativePath Source File -> Verbosity -> [Suffix] -> [(Suffix, PreProcessor)] -> Bool -> IO ()
+ Distribution.Simple.PreProcess.Types: type PreProcessCommand = -- | Location of the source file relative to a base dir (FilePath, FilePath) -> -- | Output file name, relative to an output base dir (FilePath, FilePath) -> Verbosity -> IO ()
+ Distribution.Simple.Program: getDbProgramOutputCwd :: Verbosity -> Maybe (SymbolicPath CWD (Dir to)) -> Program -> ProgramDb -> [ProgArg] -> IO String
+ Distribution.Simple.Program: runDbProgramCwd :: Verbosity -> Maybe (SymbolicPath CWD (Dir to)) -> Program -> ProgramDb -> [ProgArg] -> IO ()
+ Distribution.Simple.Program: runProgramCwd :: Verbosity -> Maybe (SymbolicPath CWD (Dir to)) -> ConfiguredProgram -> [ProgArg] -> IO ()
+ Distribution.Simple.Program.Db: ProgramDb :: UnconfiguredProgs -> ProgramSearchPath -> [(String, Maybe String)] -> ConfiguredProgs -> ProgramDb
+ Distribution.Simple.Program.Db: [configuredProgs] :: ProgramDb -> ConfiguredProgs
+ Distribution.Simple.Program.Db: [progOverrideEnv] :: ProgramDb -> [(String, Maybe String)]
+ Distribution.Simple.Program.Db: [progSearchPath] :: ProgramDb -> ProgramSearchPath
+ Distribution.Simple.Program.Db: [unconfiguredProgs] :: ProgramDb -> UnconfiguredProgs
+ Distribution.Simple.Program.Db: configureUnconfiguredProgram :: Verbosity -> Program -> ProgramDb -> IO (Maybe ConfiguredProgram)
+ Distribution.Simple.Program.Db: prependProgramSearchPathNoLogging :: [FilePath] -> [(String, Maybe String)] -> ProgramDb -> ProgramDb
+ Distribution.Simple.Program.Db: type ConfiguredProgs = Map String ConfiguredProgram
+ Distribution.Simple.Program.Db: type UnconfiguredProgs = Map String UnconfiguredProgram
+ Distribution.Simple.Program.Db: updateConfiguredProgs :: (ConfiguredProgs -> ConfiguredProgs) -> ProgramDb -> ProgramDb
+ Distribution.Simple.Program.Db: updateUnconfiguredProgs :: (UnconfiguredProgs -> UnconfiguredProgs) -> ProgramDb -> ProgramDb
+ Distribution.Simple.Program.Find: logExtraProgramOverrideEnv :: Verbosity -> [(String, Maybe String)] -> IO ()
+ Distribution.Simple.Program.Run: programInvocationCwd :: forall to. Maybe (SymbolicPath CWD (Dir to)) -> ConfiguredProgram -> [String] -> ProgramInvocation
+ Distribution.Simple.Program.Types: instance GHC.Show.Show Distribution.Simple.Program.Types.ProgramSearchPathEntry
+ Distribution.Simple.Setup: CommonSetupFlags :: !Flag Verbosity -> !Flag (SymbolicPath CWD (Dir Pkg)) -> !Flag (SymbolicPath Pkg (Dir Dist)) -> !Flag (SymbolicPath Pkg File) -> [String] -> CommonSetupFlags
+ Distribution.Simple.Setup: [benchmarkCommonFlags] :: BenchmarkFlags -> !CommonSetupFlags
+ Distribution.Simple.Setup: [buildCommonFlags] :: BuildFlags -> !CommonSetupFlags
+ Distribution.Simple.Setup: [cleanCommonFlags] :: CleanFlags -> !CommonSetupFlags
+ Distribution.Simple.Setup: [configCommonFlags] :: ConfigFlags -> !CommonSetupFlags
+ Distribution.Simple.Setup: [configIgnoreBuildTools] :: ConfigFlags -> Flag Bool
+ Distribution.Simple.Setup: [configProfShared] :: ConfigFlags -> Flag Bool
+ Distribution.Simple.Setup: [copyCommonFlags] :: CopyFlags -> !CommonSetupFlags
+ Distribution.Simple.Setup: [globalWorkingDir] :: GlobalFlags -> Flag (SymbolicPath CWD (Dir Pkg))
+ Distribution.Simple.Setup: [haddockCommonFlags] :: HaddockFlags -> !CommonSetupFlags
+ Distribution.Simple.Setup: [haddockProjectResourcesDir] :: HaddockProjectFlags -> Flag String
+ Distribution.Simple.Setup: [haddockProjectUseUnicode] :: HaddockProjectFlags -> Flag Bool
+ Distribution.Simple.Setup: [haddockResourcesDir] :: HaddockFlags -> Flag String
+ Distribution.Simple.Setup: [haddockUseUnicode] :: HaddockFlags -> Flag Bool
+ Distribution.Simple.Setup: [hscolourCommonFlags] :: HscolourFlags -> !CommonSetupFlags
+ Distribution.Simple.Setup: [installCommonFlags] :: InstallFlags -> !CommonSetupFlags
+ Distribution.Simple.Setup: [registerCommonFlags] :: RegisterFlags -> !CommonSetupFlags
+ Distribution.Simple.Setup: [replCommonFlags] :: ReplFlags -> !CommonSetupFlags
+ Distribution.Simple.Setup: [sDistCommonFlags] :: SDistFlags -> !CommonSetupFlags
+ Distribution.Simple.Setup: [setupCabalFilePath] :: CommonSetupFlags -> !Flag (SymbolicPath Pkg File)
+ Distribution.Simple.Setup: [setupDistPref] :: CommonSetupFlags -> !Flag (SymbolicPath Pkg (Dir Dist))
+ Distribution.Simple.Setup: [setupTargets] :: CommonSetupFlags -> [String]
+ Distribution.Simple.Setup: [setupVerbosity] :: CommonSetupFlags -> !Flag Verbosity
+ Distribution.Simple.Setup: [setupWorkingDir] :: CommonSetupFlags -> !Flag (SymbolicPath CWD (Dir Pkg))
+ Distribution.Simple.Setup: [testCommonFlags] :: TestFlags -> !CommonSetupFlags
+ Distribution.Simple.Setup: buildingWhatCommonFlags :: BuildingWhat -> CommonSetupFlags
+ Distribution.Simple.Setup: buildingWhatWorkingDir :: BuildingWhat -> Maybe (SymbolicPath CWD (Dir Pkg))
+ Distribution.Simple.Setup: data CommonSetupFlags
+ Distribution.Simple.Setup: defaultCommonSetupFlags :: CommonSetupFlags
+ Distribution.Simple.Setup: instance Data.Binary.Class.Binary Distribution.Simple.Setup.BuildingWhat
+ Distribution.Simple.Setup: instance Distribution.Utils.Structured.Structured Distribution.Simple.Setup.BuildingWhat
+ Distribution.Simple.Setup: pattern BenchmarkCommonFlags :: Flag Verbosity -> Flag (SymbolicPath Pkg (Dir Dist)) -> Flag (SymbolicPath CWD (Dir Pkg)) -> Flag (SymbolicPath Pkg File) -> [String] -> BenchmarkFlags
+ Distribution.Simple.Setup: pattern BuildCommonFlags :: Flag Verbosity -> Flag (SymbolicPath Pkg (Dir Dist)) -> Flag (SymbolicPath CWD (Dir Pkg)) -> Flag (SymbolicPath Pkg File) -> [String] -> BuildFlags
+ Distribution.Simple.Setup: pattern CleanCommonFlags :: Flag Verbosity -> Flag (SymbolicPath Pkg (Dir Dist)) -> Flag (SymbolicPath CWD (Dir Pkg)) -> Flag (SymbolicPath Pkg File) -> [String] -> CleanFlags
+ Distribution.Simple.Setup: pattern ConfigCommonFlags :: Flag Verbosity -> Flag (SymbolicPath Pkg (Dir Dist)) -> Flag (SymbolicPath CWD (Dir Pkg)) -> Flag (SymbolicPath Pkg File) -> [String] -> ConfigFlags
+ Distribution.Simple.Setup: pattern CopyCommonFlags :: Flag Verbosity -> Flag (SymbolicPath Pkg (Dir Dist)) -> Flag (SymbolicPath CWD (Dir Pkg)) -> Flag (SymbolicPath Pkg File) -> [String] -> CopyFlags
+ Distribution.Simple.Setup: pattern HaddockCommonFlags :: Flag Verbosity -> Flag (SymbolicPath Pkg (Dir Dist)) -> Flag (SymbolicPath CWD (Dir Pkg)) -> Flag (SymbolicPath Pkg File) -> [String] -> HaddockFlags
+ Distribution.Simple.Setup: pattern HscolourCommonFlags :: Flag Verbosity -> Flag (SymbolicPath Pkg (Dir Dist)) -> Flag (SymbolicPath CWD (Dir Pkg)) -> Flag (SymbolicPath Pkg File) -> [String] -> HscolourFlags
+ Distribution.Simple.Setup: pattern InstallCommonFlags :: Flag Verbosity -> Flag (SymbolicPath Pkg (Dir Dist)) -> Flag (SymbolicPath CWD (Dir Pkg)) -> Flag (SymbolicPath Pkg File) -> [String] -> InstallFlags
+ Distribution.Simple.Setup: pattern RegisterCommonFlags :: Flag Verbosity -> Flag (SymbolicPath Pkg (Dir Dist)) -> Flag (SymbolicPath CWD (Dir Pkg)) -> Flag (SymbolicPath Pkg File) -> [String] -> RegisterFlags
+ Distribution.Simple.Setup: pattern ReplCommonFlags :: Flag Verbosity -> Flag (SymbolicPath Pkg (Dir Dist)) -> Flag (SymbolicPath CWD (Dir Pkg)) -> Flag (SymbolicPath Pkg File) -> [String] -> ReplFlags
+ Distribution.Simple.Setup: pattern SDistCommonFlags :: Flag Verbosity -> Flag (SymbolicPath Pkg (Dir Dist)) -> Flag (SymbolicPath CWD (Dir Pkg)) -> Flag (SymbolicPath Pkg File) -> [String] -> SDistFlags
+ Distribution.Simple.Setup: pattern TestCommonFlags :: Flag Verbosity -> Flag (SymbolicPath Pkg (Dir Dist)) -> Flag (SymbolicPath CWD (Dir Pkg)) -> Flag (SymbolicPath Pkg File) -> [String] -> TestFlags
+ Distribution.Simple.SetupHooks.Errors: CannotApplyComponentDiff :: CannotApplyComponentDiffReason -> SetupHooksException
+ Distribution.Simple.SetupHooks.Errors: CannotChangeBuildInfoField :: String -> IllegalComponentDiffReason
+ Distribution.Simple.SetupHooks.Errors: CannotChangeComponentField :: String -> IllegalComponentDiffReason
+ Distribution.Simple.SetupHooks.Errors: CannotChangeName :: IllegalComponentDiffReason
+ Distribution.Simple.SetupHooks.Errors: CantFindSourceForRuleDependencies :: RuleBinary -> NonEmpty Location -> RulesException
+ Distribution.Simple.SetupHooks.Errors: CyclicRuleDependencies :: NonEmpty (RuleBinary, [Tree RuleBinary]) -> RulesException
+ Distribution.Simple.SetupHooks.Errors: DuplicateRuleId :: !RuleId -> !Rule -> !Rule -> RulesException
+ Distribution.Simple.SetupHooks.Errors: IllegalComponentDiff :: Component -> NonEmpty IllegalComponentDiffReason -> CannotApplyComponentDiffReason
+ Distribution.Simple.SetupHooks.Errors: InvalidRuleOutputIndex :: RuleId -> RuleId -> NonEmpty Location -> Word -> RulesException
+ Distribution.Simple.SetupHooks.Errors: MismatchedComponentTypes :: Component -> Component -> CannotApplyComponentDiffReason
+ Distribution.Simple.SetupHooks.Errors: MissingRuleOutputs :: RuleBinary -> NonEmpty Location -> RulesException
+ Distribution.Simple.SetupHooks.Errors: RulesException :: RulesException -> SetupHooksException
+ Distribution.Simple.SetupHooks.Errors: data CannotApplyComponentDiffReason
+ Distribution.Simple.SetupHooks.Errors: data IllegalComponentDiffReason
+ Distribution.Simple.SetupHooks.Errors: data RulesException
+ Distribution.Simple.SetupHooks.Errors: data SetupHooksException
+ Distribution.Simple.SetupHooks.Errors: instance GHC.Show.Show Distribution.Simple.SetupHooks.Errors.CannotApplyComponentDiffReason
+ Distribution.Simple.SetupHooks.Errors: instance GHC.Show.Show Distribution.Simple.SetupHooks.Errors.IllegalComponentDiffReason
+ Distribution.Simple.SetupHooks.Errors: instance GHC.Show.Show Distribution.Simple.SetupHooks.Errors.RulesException
+ Distribution.Simple.SetupHooks.Errors: instance GHC.Show.Show Distribution.Simple.SetupHooks.Errors.SetupHooksException
+ Distribution.Simple.SetupHooks.Errors: setupHooksExceptionCode :: SetupHooksException -> Int
+ Distribution.Simple.SetupHooks.Errors: setupHooksExceptionMessage :: SetupHooksException -> String
+ Distribution.Simple.SetupHooks.Internal: BuildHaddock :: HaddockFlags -> BuildingWhat
+ Distribution.Simple.SetupHooks.Internal: BuildHooks :: Maybe PreBuildComponentRules -> Maybe PostBuildComponentHook -> BuildHooks
+ Distribution.Simple.SetupHooks.Internal: BuildHscolour :: HscolourFlags -> BuildingWhat
+ Distribution.Simple.SetupHooks.Internal: BuildNormal :: BuildFlags -> BuildingWhat
+ Distribution.Simple.SetupHooks.Internal: BuildRepl :: ReplFlags -> BuildingWhat
+ Distribution.Simple.SetupHooks.Internal: ComponentDiff :: Component -> ComponentDiff
+ Distribution.Simple.SetupHooks.Internal: ConfigureHooks :: Maybe PreConfPackageHook -> Maybe PostConfPackageHook -> Maybe PreConfComponentHook -> ConfigureHooks
+ Distribution.Simple.SetupHooks.Internal: InstallComponentInputs :: CopyFlags -> LocalBuildInfo -> TargetInfo -> InstallComponentInputs
+ Distribution.Simple.SetupHooks.Internal: InstallHooks :: Maybe InstallComponentHook -> InstallHooks
+ Distribution.Simple.SetupHooks.Internal: PostBuildComponentInputs :: BuildFlags -> LocalBuildInfo -> TargetInfo -> PostBuildComponentInputs
+ Distribution.Simple.SetupHooks.Internal: PostConfPackageInputs :: LocalBuildConfig -> PackageBuildDescr -> PostConfPackageInputs
+ Distribution.Simple.SetupHooks.Internal: PreBuildComponentInputs :: BuildingWhat -> LocalBuildInfo -> TargetInfo -> PreBuildComponentInputs
+ Distribution.Simple.SetupHooks.Internal: PreConfComponentInputs :: LocalBuildConfig -> PackageBuildDescr -> Component -> PreConfComponentInputs
+ Distribution.Simple.SetupHooks.Internal: PreConfComponentOutputs :: ComponentDiff -> PreConfComponentOutputs
+ Distribution.Simple.SetupHooks.Internal: PreConfPackageInputs :: ConfigFlags -> LocalBuildConfig -> Compiler -> Platform -> PreConfPackageInputs
+ Distribution.Simple.SetupHooks.Internal: PreConfPackageOutputs :: BuildOptions -> ConfiguredProgs -> PreConfPackageOutputs
+ Distribution.Simple.SetupHooks.Internal: SetupHooks :: ConfigureHooks -> BuildHooks -> InstallHooks -> SetupHooks
+ Distribution.Simple.SetupHooks.Internal: [$sel:buildFlags:PostBuildComponentInputs] :: PostBuildComponentInputs -> BuildFlags
+ Distribution.Simple.SetupHooks.Internal: [$sel:buildHooks:SetupHooks] :: SetupHooks -> BuildHooks
+ Distribution.Simple.SetupHooks.Internal: [$sel:buildOptions:PreConfPackageOutputs] :: PreConfPackageOutputs -> BuildOptions
+ Distribution.Simple.SetupHooks.Internal: [$sel:buildingWhat:PreBuildComponentInputs] :: PreBuildComponentInputs -> BuildingWhat
+ Distribution.Simple.SetupHooks.Internal: [$sel:compiler:PreConfPackageInputs] :: PreConfPackageInputs -> Compiler
+ Distribution.Simple.SetupHooks.Internal: [$sel:component:PreConfComponentInputs] :: PreConfComponentInputs -> Component
+ Distribution.Simple.SetupHooks.Internal: [$sel:componentDiff:ComponentDiff] :: ComponentDiff -> Component
+ Distribution.Simple.SetupHooks.Internal: [$sel:componentDiff:PreConfComponentOutputs] :: PreConfComponentOutputs -> ComponentDiff
+ Distribution.Simple.SetupHooks.Internal: [$sel:configFlags:PreConfPackageInputs] :: PreConfPackageInputs -> ConfigFlags
+ Distribution.Simple.SetupHooks.Internal: [$sel:configureHooks:SetupHooks] :: SetupHooks -> ConfigureHooks
+ Distribution.Simple.SetupHooks.Internal: [$sel:copyFlags:InstallComponentInputs] :: InstallComponentInputs -> CopyFlags
+ Distribution.Simple.SetupHooks.Internal: [$sel:extraConfiguredProgs:PreConfPackageOutputs] :: PreConfPackageOutputs -> ConfiguredProgs
+ Distribution.Simple.SetupHooks.Internal: [$sel:installComponentHook:InstallHooks] :: InstallHooks -> Maybe InstallComponentHook
+ Distribution.Simple.SetupHooks.Internal: [$sel:installHooks:SetupHooks] :: SetupHooks -> InstallHooks
+ Distribution.Simple.SetupHooks.Internal: [$sel:localBuildConfig:PostConfPackageInputs] :: PostConfPackageInputs -> LocalBuildConfig
+ Distribution.Simple.SetupHooks.Internal: [$sel:localBuildConfig:PreConfComponentInputs] :: PreConfComponentInputs -> LocalBuildConfig
+ Distribution.Simple.SetupHooks.Internal: [$sel:localBuildConfig:PreConfPackageInputs] :: PreConfPackageInputs -> LocalBuildConfig
+ Distribution.Simple.SetupHooks.Internal: [$sel:localBuildInfo:InstallComponentInputs] :: InstallComponentInputs -> LocalBuildInfo
+ Distribution.Simple.SetupHooks.Internal: [$sel:localBuildInfo:PostBuildComponentInputs] :: PostBuildComponentInputs -> LocalBuildInfo
+ Distribution.Simple.SetupHooks.Internal: [$sel:localBuildInfo:PreBuildComponentInputs] :: PreBuildComponentInputs -> LocalBuildInfo
+ Distribution.Simple.SetupHooks.Internal: [$sel:packageBuildDescr:PostConfPackageInputs] :: PostConfPackageInputs -> PackageBuildDescr
+ Distribution.Simple.SetupHooks.Internal: [$sel:packageBuildDescr:PreConfComponentInputs] :: PreConfComponentInputs -> PackageBuildDescr
+ Distribution.Simple.SetupHooks.Internal: [$sel:platform:PreConfPackageInputs] :: PreConfPackageInputs -> Platform
+ Distribution.Simple.SetupHooks.Internal: [$sel:postBuildComponentHook:BuildHooks] :: BuildHooks -> Maybe PostBuildComponentHook
+ Distribution.Simple.SetupHooks.Internal: [$sel:postConfPackageHook:ConfigureHooks] :: ConfigureHooks -> Maybe PostConfPackageHook
+ Distribution.Simple.SetupHooks.Internal: [$sel:preBuildComponentRules:BuildHooks] :: BuildHooks -> Maybe PreBuildComponentRules
+ Distribution.Simple.SetupHooks.Internal: [$sel:preConfComponentHook:ConfigureHooks] :: ConfigureHooks -> Maybe PreConfComponentHook
+ Distribution.Simple.SetupHooks.Internal: [$sel:preConfPackageHook:ConfigureHooks] :: ConfigureHooks -> Maybe PreConfPackageHook
+ Distribution.Simple.SetupHooks.Internal: [$sel:targetInfo:InstallComponentInputs] :: InstallComponentInputs -> TargetInfo
+ Distribution.Simple.SetupHooks.Internal: [$sel:targetInfo:PostBuildComponentInputs] :: PostBuildComponentInputs -> TargetInfo
+ Distribution.Simple.SetupHooks.Internal: [$sel:targetInfo:PreBuildComponentInputs] :: PreBuildComponentInputs -> TargetInfo
+ Distribution.Simple.SetupHooks.Internal: applyComponentDiffs :: Verbosity -> (Component -> IO (Maybe ComponentDiff)) -> PackageDescription -> IO PackageDescription
+ Distribution.Simple.SetupHooks.Internal: buildInfoComponentDiff :: ComponentName -> BuildInfo -> ComponentDiff
+ Distribution.Simple.SetupHooks.Internal: buildingWhatDistPref :: BuildingWhat -> SymbolicPath Pkg (Dir Dist)
+ Distribution.Simple.SetupHooks.Internal: buildingWhatVerbosity :: BuildingWhat -> Verbosity
+ Distribution.Simple.SetupHooks.Internal: buildingWhatWorkingDir :: BuildingWhat -> Maybe (SymbolicPath CWD (Dir Pkg))
+ Distribution.Simple.SetupHooks.Internal: data BuildHooks
+ Distribution.Simple.SetupHooks.Internal: data BuildingWhat
+ Distribution.Simple.SetupHooks.Internal: data ConfigureHooks
+ Distribution.Simple.SetupHooks.Internal: data InstallComponentInputs
+ Distribution.Simple.SetupHooks.Internal: data InstallHooks
+ Distribution.Simple.SetupHooks.Internal: data PostBuildComponentInputs
+ Distribution.Simple.SetupHooks.Internal: data PostConfPackageInputs
+ Distribution.Simple.SetupHooks.Internal: data PreBuildComponentInputs
+ Distribution.Simple.SetupHooks.Internal: data PreConfComponentInputs
+ Distribution.Simple.SetupHooks.Internal: data PreConfComponentOutputs
+ Distribution.Simple.SetupHooks.Internal: data PreConfPackageInputs
+ Distribution.Simple.SetupHooks.Internal: data PreConfPackageOutputs
+ Distribution.Simple.SetupHooks.Internal: data SetupHooks
+ Distribution.Simple.SetupHooks.Internal: emptyComponentDiff :: ComponentName -> ComponentDiff
+ Distribution.Simple.SetupHooks.Internal: executeRules :: Verbosity -> LocalBuildInfo -> TargetInfo -> Map RuleId Rule -> IO ()
+ Distribution.Simple.SetupHooks.Internal: forComponents_ :: PackageDescription -> (Component -> IO ()) -> IO ()
+ Distribution.Simple.SetupHooks.Internal: hookedBuildInfoComponentDiff_maybe :: HookedBuildInfo -> ComponentName -> Maybe (IO ComponentDiff)
+ Distribution.Simple.SetupHooks.Internal: hookedBuildInfoComponents :: HookedBuildInfo -> Set ComponentName
+ Distribution.Simple.SetupHooks.Internal: instance Data.Binary.Class.Binary Distribution.Simple.SetupHooks.Internal.ComponentDiff
+ Distribution.Simple.SetupHooks.Internal: instance Data.Binary.Class.Binary Distribution.Simple.SetupHooks.Internal.InstallComponentInputs
+ Distribution.Simple.SetupHooks.Internal: instance Data.Binary.Class.Binary Distribution.Simple.SetupHooks.Internal.PostBuildComponentInputs
+ Distribution.Simple.SetupHooks.Internal: instance Data.Binary.Class.Binary Distribution.Simple.SetupHooks.Internal.PostConfPackageInputs
+ Distribution.Simple.SetupHooks.Internal: instance Data.Binary.Class.Binary Distribution.Simple.SetupHooks.Internal.PreBuildComponentInputs
+ Distribution.Simple.SetupHooks.Internal: instance Data.Binary.Class.Binary Distribution.Simple.SetupHooks.Internal.PreConfComponentInputs
+ Distribution.Simple.SetupHooks.Internal: instance Data.Binary.Class.Binary Distribution.Simple.SetupHooks.Internal.PreConfComponentOutputs
+ Distribution.Simple.SetupHooks.Internal: instance Data.Binary.Class.Binary Distribution.Simple.SetupHooks.Internal.PreConfPackageInputs
+ Distribution.Simple.SetupHooks.Internal: instance Data.Binary.Class.Binary Distribution.Simple.SetupHooks.Internal.PreConfPackageOutputs
+ Distribution.Simple.SetupHooks.Internal: instance Distribution.Utils.Structured.Structured Distribution.Simple.SetupHooks.Internal.ComponentDiff
+ Distribution.Simple.SetupHooks.Internal: instance Distribution.Utils.Structured.Structured Distribution.Simple.SetupHooks.Internal.InstallComponentInputs
+ Distribution.Simple.SetupHooks.Internal: instance Distribution.Utils.Structured.Structured Distribution.Simple.SetupHooks.Internal.PostBuildComponentInputs
+ Distribution.Simple.SetupHooks.Internal: instance Distribution.Utils.Structured.Structured Distribution.Simple.SetupHooks.Internal.PostConfPackageInputs
+ Distribution.Simple.SetupHooks.Internal: instance Distribution.Utils.Structured.Structured Distribution.Simple.SetupHooks.Internal.PreBuildComponentInputs
+ Distribution.Simple.SetupHooks.Internal: instance Distribution.Utils.Structured.Structured Distribution.Simple.SetupHooks.Internal.PreConfComponentInputs
+ Distribution.Simple.SetupHooks.Internal: instance Distribution.Utils.Structured.Structured Distribution.Simple.SetupHooks.Internal.PreConfComponentOutputs
+ Distribution.Simple.SetupHooks.Internal: instance Distribution.Utils.Structured.Structured Distribution.Simple.SetupHooks.Internal.PreConfPackageInputs
+ Distribution.Simple.SetupHooks.Internal: instance Distribution.Utils.Structured.Structured Distribution.Simple.SetupHooks.Internal.PreConfPackageOutputs
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Base.Monoid Distribution.Simple.SetupHooks.Internal.BuildHooks
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Base.Monoid Distribution.Simple.SetupHooks.Internal.ConfigureHooks
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Base.Monoid Distribution.Simple.SetupHooks.Internal.InstallHooks
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Base.Monoid Distribution.Simple.SetupHooks.Internal.SetupHooks
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Base.Semigroup Distribution.Simple.SetupHooks.Internal.BuildHooks
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Base.Semigroup Distribution.Simple.SetupHooks.Internal.ComponentDiff
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Base.Semigroup Distribution.Simple.SetupHooks.Internal.ConfigureHooks
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Base.Semigroup Distribution.Simple.SetupHooks.Internal.InstallHooks
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Base.Semigroup Distribution.Simple.SetupHooks.Internal.PreConfComponentSemigroup
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Base.Semigroup Distribution.Simple.SetupHooks.Internal.PreConfPkgSemigroup
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Base.Semigroup Distribution.Simple.SetupHooks.Internal.SetupHooks
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Generics.Generic Distribution.Simple.SetupHooks.Internal.InstallComponentInputs
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Generics.Generic Distribution.Simple.SetupHooks.Internal.PostBuildComponentInputs
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Generics.Generic Distribution.Simple.SetupHooks.Internal.PostConfPackageInputs
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Generics.Generic Distribution.Simple.SetupHooks.Internal.PreBuildComponentInputs
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Generics.Generic Distribution.Simple.SetupHooks.Internal.PreConfComponentInputs
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Generics.Generic Distribution.Simple.SetupHooks.Internal.PreConfComponentOutputs
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Generics.Generic Distribution.Simple.SetupHooks.Internal.PreConfPackageInputs
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Generics.Generic Distribution.Simple.SetupHooks.Internal.PreConfPackageOutputs
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Show.Show Distribution.Simple.SetupHooks.Internal.ComponentDiff
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Show.Show Distribution.Simple.SetupHooks.Internal.InstallComponentInputs
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Show.Show Distribution.Simple.SetupHooks.Internal.PostBuildComponentInputs
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Show.Show Distribution.Simple.SetupHooks.Internal.PostConfPackageInputs
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Show.Show Distribution.Simple.SetupHooks.Internal.PreBuildComponentInputs
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Show.Show Distribution.Simple.SetupHooks.Internal.PreConfComponentInputs
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Show.Show Distribution.Simple.SetupHooks.Internal.PreConfComponentOutputs
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Show.Show Distribution.Simple.SetupHooks.Internal.PreConfPackageInputs
+ Distribution.Simple.SetupHooks.Internal: instance GHC.Show.Show Distribution.Simple.SetupHooks.Internal.PreConfPackageOutputs
+ Distribution.Simple.SetupHooks.Internal: newtype ComponentDiff
+ Distribution.Simple.SetupHooks.Internal: noBuildHooks :: BuildHooks
+ Distribution.Simple.SetupHooks.Internal: noConfigureHooks :: ConfigureHooks
+ Distribution.Simple.SetupHooks.Internal: noInstallHooks :: InstallHooks
+ Distribution.Simple.SetupHooks.Internal: noPreConfComponentOutputs :: PreConfComponentInputs -> PreConfComponentOutputs
+ Distribution.Simple.SetupHooks.Internal: noPreConfPackageOutputs :: PreConfPackageInputs -> PreConfPackageOutputs
+ Distribution.Simple.SetupHooks.Internal: noSetupHooks :: SetupHooks
+ Distribution.Simple.SetupHooks.Internal: type BenchmarkDiff = Benchmark
+ Distribution.Simple.SetupHooks.Internal: type BuildInfoDiff = BuildInfo
+ Distribution.Simple.SetupHooks.Internal: type ExecutableDiff = Executable
+ Distribution.Simple.SetupHooks.Internal: type ForeignLibDiff = ForeignLib
+ Distribution.Simple.SetupHooks.Internal: type InstallComponentHook = InstallComponentInputs -> IO ()
+ Distribution.Simple.SetupHooks.Internal: type LibraryDiff = Library
+ Distribution.Simple.SetupHooks.Internal: type PostBuildComponentHook = PostBuildComponentInputs -> IO ()
+ Distribution.Simple.SetupHooks.Internal: type PostConfPackageHook = PostConfPackageInputs -> IO ()
+ Distribution.Simple.SetupHooks.Internal: type PreBuildComponentRules = Rules PreBuildComponentInputs
+ Distribution.Simple.SetupHooks.Internal: type PreConfComponentHook = PreConfComponentInputs -> IO PreConfComponentOutputs
+ Distribution.Simple.SetupHooks.Internal: type PreConfPackageHook = PreConfPackageInputs -> IO PreConfPackageOutputs
+ Distribution.Simple.SetupHooks.Internal: type TestSuiteDiff = TestSuite
+ Distribution.Simple.SetupHooks.Rule: Command :: !Static scope (arg -> res) -> !ScopedArgument scope arg -> !Static scope (Dict (Binary arg, Show arg)) -> CommandData (scope :: Scope) (arg :: Type) (res :: Type)
+ Distribution.Simple.SetupHooks.Rule: DepsRes :: ScopedArgument scope depsRes -> DepsRes (scope :: Scope) depsArg depsRes
+ Distribution.Simple.SetupHooks.Rule: DirExists :: MonitorKindDir
+ Distribution.Simple.SetupHooks.Rule: DirModTime :: MonitorKindDir
+ Distribution.Simple.SetupHooks.Rule: DirNotExists :: MonitorKindDir
+ Distribution.Simple.SetupHooks.Rule: DynDepsCmd :: CommandData scope depsArg (IO ([Dependency], depsRes)) -> DynDepsCmd scope depsArg depsRes
+ Distribution.Simple.SetupHooks.Rule: FileDependency :: !Location -> Dependency
+ Distribution.Simple.SetupHooks.Rule: FileExists :: MonitorKindFile
+ Distribution.Simple.SetupHooks.Rule: FileHashed :: MonitorKindFile
+ Distribution.Simple.SetupHooks.Rule: FileModTime :: MonitorKindFile
+ Distribution.Simple.SetupHooks.Rule: FileNotExists :: MonitorKindFile
+ Distribution.Simple.SetupHooks.Rule: MonitorFile :: !MonitorKindFile -> !MonitorKindDir -> !FilePath -> MonitorFilePath
+ Distribution.Simple.SetupHooks.Rule: MonitorFileGlob :: !MonitorKindFile -> !MonitorKindDir -> !RootedGlob -> MonitorFilePath
+ Distribution.Simple.SetupHooks.Rule: Rule :: !RuleCmds scope -> ![Dependency] -> !NonEmpty Location -> RuleData (scope :: Scope)
+ Distribution.Simple.SetupHooks.Rule: RuleDependency :: !RuleOutput -> Dependency
+ Distribution.Simple.SetupHooks.Rule: RuleId :: !RulesNameSpace -> !ShortText -> RuleId
+ Distribution.Simple.SetupHooks.Rule: RuleOutput :: !RuleId -> !Word -> RuleOutput
+ Distribution.Simple.SetupHooks.Rule: Rules :: (env -> RulesM ()) -> Rules env
+ Distribution.Simple.SetupHooks.Rule: RulesEnv :: !Verbosity -> !RulesNameSpace -> RulesEnv
+ Distribution.Simple.SetupHooks.Rule: RulesT :: ReaderT RulesEnv (StateT (Map RuleId Rule) (WriterT [MonitorFilePath] m)) a -> RulesT m a
+ Distribution.Simple.SetupHooks.Rule: System :: Scope
+ Distribution.Simple.SetupHooks.Rule: User :: Scope
+ Distribution.Simple.SetupHooks.Rule: [Dict] :: c => Dict c
+ Distribution.Simple.SetupHooks.Rule: [DynamicRuleCommands] :: forall depsArg depsRes arg deps ruleCmd scope. If (scope == System) (depsArg ~ ByteString, depsRes ~ ByteString, arg ~ ByteString) (() :: Constraint) => !Static scope (Dict (Binary depsRes, Show depsRes, Eq depsRes)) -> !deps scope depsArg depsRes -> !ruleCmd scope arg (depsRes -> IO ()) -> !If (scope == System) SomeTypeRep (TypeRep (depsArg, depsRes, arg)) -> RuleCommands scope deps ruleCmd
+ Distribution.Simple.SetupHooks.Rule: [Location] :: !SymbolicPath Pkg (Dir baseDir) -> !RelativePath baseDir File -> Location
+ Distribution.Simple.SetupHooks.Rule: [SSystem] :: SScope System
+ Distribution.Simple.SetupHooks.Rule: [SUser] :: SScope User
+ Distribution.Simple.SetupHooks.Rule: [StaticRuleCommand] :: forall arg deps ruleCmd scope. If (scope == System) (arg ~ ByteString) (() :: Constraint) => !ruleCmd scope arg (IO ()) -> !If (scope == System) SomeTypeRep (TypeRep arg) -> RuleCommands scope deps ruleCmd
+ Distribution.Simple.SetupHooks.Rule: [actionArg] :: CommandData (scope :: Scope) (arg :: Type) (res :: Type) -> !ScopedArgument scope arg
+ Distribution.Simple.SetupHooks.Rule: [actionPtr] :: CommandData (scope :: Scope) (arg :: Type) (res :: Type) -> !Static scope (arg -> res)
+ Distribution.Simple.SetupHooks.Rule: [cmdInstances] :: CommandData (scope :: Scope) (arg :: Type) (res :: Type) -> !Static scope (Dict (Binary arg, Show arg))
+ Distribution.Simple.SetupHooks.Rule: [depsRes] :: DepsRes (scope :: Scope) depsArg depsRes -> ScopedArgument scope depsRes
+ Distribution.Simple.SetupHooks.Rule: [dynDepsCmd] :: DynDepsCmd scope depsArg depsRes -> CommandData scope depsArg (IO ([Dependency], depsRes))
+ Distribution.Simple.SetupHooks.Rule: [monitorKindDir] :: MonitorFilePath -> !MonitorKindDir
+ Distribution.Simple.SetupHooks.Rule: [monitorKindFile] :: MonitorFilePath -> !MonitorKindFile
+ Distribution.Simple.SetupHooks.Rule: [monitorPathGlob] :: MonitorFilePath -> !RootedGlob
+ Distribution.Simple.SetupHooks.Rule: [monitorPath] :: MonitorFilePath -> !FilePath
+ Distribution.Simple.SetupHooks.Rule: [outputIndex] :: RuleOutput -> !Word
+ Distribution.Simple.SetupHooks.Rule: [outputOfRule] :: RuleOutput -> !RuleId
+ Distribution.Simple.SetupHooks.Rule: [results] :: RuleData (scope :: Scope) -> !NonEmpty Location
+ Distribution.Simple.SetupHooks.Rule: [ruleCommands] :: RuleData (scope :: Scope) -> !RuleCmds scope
+ Distribution.Simple.SetupHooks.Rule: [ruleNameSpace] :: RuleId -> !RulesNameSpace
+ Distribution.Simple.SetupHooks.Rule: [ruleName] :: RuleId -> !ShortText
+ Distribution.Simple.SetupHooks.Rule: [rulesEnvNameSpace] :: RulesEnv -> !RulesNameSpace
+ Distribution.Simple.SetupHooks.Rule: [rulesEnvVerbosity] :: RulesEnv -> !Verbosity
+ Distribution.Simple.SetupHooks.Rule: [runRulesT] :: RulesT m a -> ReaderT RulesEnv (StateT (Map RuleId Rule) (WriterT [MonitorFilePath] m)) a
+ Distribution.Simple.SetupHooks.Rule: [runRules] :: Rules env -> env -> RulesM ()
+ Distribution.Simple.SetupHooks.Rule: [staticDependencies] :: RuleData (scope :: Scope) -> ![Dependency]
+ Distribution.Simple.SetupHooks.Rule: computeRules :: Verbosity -> env -> Rules env -> IO (Map RuleId Rule, [MonitorFilePath])
+ Distribution.Simple.SetupHooks.Rule: data CommandData (scope :: Scope) (arg :: Type) (res :: Type)
+ Distribution.Simple.SetupHooks.Rule: data Dependency
+ Distribution.Simple.SetupHooks.Rule: data Dict c
+ Distribution.Simple.SetupHooks.Rule: data Location
+ Distribution.Simple.SetupHooks.Rule: data MonitorFilePath
+ Distribution.Simple.SetupHooks.Rule: data MonitorKindDir
+ Distribution.Simple.SetupHooks.Rule: data MonitorKindFile
+ Distribution.Simple.SetupHooks.Rule: data RuleCommands (scope :: Scope) (deps :: Scope -> Type -> Type -> Type) (ruleCmd :: Scope -> Type -> Type -> Type)
+ Distribution.Simple.SetupHooks.Rule: data RuleData (scope :: Scope)
+ Distribution.Simple.SetupHooks.Rule: data RuleId
+ Distribution.Simple.SetupHooks.Rule: data RuleOutput
+ Distribution.Simple.SetupHooks.Rule: data RulesEnv
+ Distribution.Simple.SetupHooks.Rule: data SScope (scope :: Scope)
+ Distribution.Simple.SetupHooks.Rule: data Scope
+ Distribution.Simple.SetupHooks.Rule: data family Static (scope :: Scope) :: Type -> Type
+ Distribution.Simple.SetupHooks.Rule: dynamicRule :: forall depsArg depsRes arg. (Typeable depsArg, Typeable depsRes, Typeable arg) => StaticPtr (Dict (Binary depsRes, Show depsRes, Eq depsRes)) -> Command depsArg (IO ([Dependency], depsRes)) -> Command arg (depsRes -> IO ()) -> [Dependency] -> NonEmpty Location -> Rule
+ Distribution.Simple.SetupHooks.Rule: instance (arg GHC.Types.~ Data.ByteString.Lazy.Internal.ByteString) => Data.Binary.Class.Binary (Distribution.Simple.SetupHooks.Rule.CommandData 'Distribution.Simple.SetupHooks.Rule.System arg res)
+ Distribution.Simple.SetupHooks.Rule: instance (arg GHC.Types.~ Data.ByteString.Lazy.Internal.ByteString) => Data.Binary.Class.Binary (Distribution.Simple.SetupHooks.Rule.ScopedArgument 'Distribution.Simple.SetupHooks.Rule.System arg)
+ Distribution.Simple.SetupHooks.Rule: instance (arg GHC.Types.~ Data.ByteString.Lazy.Internal.ByteString) => GHC.Classes.Eq (Distribution.Simple.SetupHooks.Rule.CommandData 'Distribution.Simple.SetupHooks.Rule.System arg res)
+ Distribution.Simple.SetupHooks.Rule: instance (arg GHC.Types.~ Data.ByteString.Lazy.Internal.ByteString, depsRes GHC.Types.~ Data.ByteString.Lazy.Internal.ByteString) => Data.Binary.Class.Binary (Distribution.Simple.SetupHooks.Rule.DynDepsCmd 'Distribution.Simple.SetupHooks.Rule.System arg depsRes)
+ Distribution.Simple.SetupHooks.Rule: instance (arg GHC.Types.~ Data.ByteString.Lazy.Internal.ByteString, depsRes GHC.Types.~ Data.ByteString.Lazy.Internal.ByteString) => GHC.Classes.Eq (Distribution.Simple.SetupHooks.Rule.DynDepsCmd 'Distribution.Simple.SetupHooks.Rule.System arg depsRes)
+ Distribution.Simple.SetupHooks.Rule: instance (forall arg res. Data.Binary.Class.Binary (ruleCmd 'Distribution.Simple.SetupHooks.Rule.User arg res), forall depsArg depsRes. Data.Binary.Class.Binary depsRes => Data.Binary.Class.Binary (deps 'Distribution.Simple.SetupHooks.Rule.User depsArg depsRes)) => Data.Binary.Class.Binary (Distribution.Simple.SetupHooks.Rule.RuleCommands 'Distribution.Simple.SetupHooks.Rule.User deps ruleCmd)
+ Distribution.Simple.SetupHooks.Rule: instance (forall arg res. GHC.Classes.Eq (ruleCmd 'Distribution.Simple.SetupHooks.Rule.User arg res), forall depsArg depsRes. GHC.Classes.Eq depsRes => GHC.Classes.Eq (deps 'Distribution.Simple.SetupHooks.Rule.User depsArg depsRes)) => GHC.Classes.Eq (Distribution.Simple.SetupHooks.Rule.RuleCommands 'Distribution.Simple.SetupHooks.Rule.User deps ruleCmd)
+ Distribution.Simple.SetupHooks.Rule: instance (forall arg res. GHC.Show.Show (ruleCmd 'Distribution.Simple.SetupHooks.Rule.User arg res), forall depsArg depsRes. GHC.Show.Show depsRes => GHC.Show.Show (deps 'Distribution.Simple.SetupHooks.Rule.User depsArg depsRes)) => GHC.Show.Show (Distribution.Simple.SetupHooks.Rule.RuleCommands 'Distribution.Simple.SetupHooks.Rule.User deps ruleCmd)
+ Distribution.Simple.SetupHooks.Rule: instance (forall res. Data.Binary.Class.Binary (ruleCmd 'Distribution.Simple.SetupHooks.Rule.System Data.ByteString.Lazy.Internal.ByteString res), Data.Binary.Class.Binary (deps 'Distribution.Simple.SetupHooks.Rule.System Data.ByteString.Lazy.Internal.ByteString Data.ByteString.Lazy.Internal.ByteString)) => Data.Binary.Class.Binary (Distribution.Simple.SetupHooks.Rule.RuleCommands 'Distribution.Simple.SetupHooks.Rule.System deps ruleCmd)
+ Distribution.Simple.SetupHooks.Rule: instance (forall res. GHC.Classes.Eq (ruleCmd 'Distribution.Simple.SetupHooks.Rule.System Data.ByteString.Lazy.Internal.ByteString res), GHC.Classes.Eq (deps 'Distribution.Simple.SetupHooks.Rule.System Data.ByteString.Lazy.Internal.ByteString Data.ByteString.Lazy.Internal.ByteString)) => GHC.Classes.Eq (Distribution.Simple.SetupHooks.Rule.RuleCommands 'Distribution.Simple.SetupHooks.Rule.System deps ruleCmd)
+ Distribution.Simple.SetupHooks.Rule: instance Control.Monad.Fix.MonadFix m => Control.Monad.Fix.MonadFix (Distribution.Simple.SetupHooks.Rule.RulesT m)
+ Distribution.Simple.SetupHooks.Rule: instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Distribution.Simple.SetupHooks.Rule.RulesT m)
+ Distribution.Simple.SetupHooks.Rule: instance Control.Monad.Trans.Class.MonadTrans Distribution.Simple.SetupHooks.Rule.RulesT
+ Distribution.Simple.SetupHooks.Rule: instance Data.Binary.Class.Binary (Distribution.Simple.SetupHooks.Rule.CommandData 'Distribution.Simple.SetupHooks.Rule.User arg res)
+ Distribution.Simple.SetupHooks.Rule: instance Data.Binary.Class.Binary (Distribution.Simple.SetupHooks.Rule.DynDepsCmd 'Distribution.Simple.SetupHooks.Rule.User depsArg depsRes)
+ Distribution.Simple.SetupHooks.Rule: instance Data.Binary.Class.Binary (Distribution.Simple.SetupHooks.Rule.RuleData 'Distribution.Simple.SetupHooks.Rule.System)
+ Distribution.Simple.SetupHooks.Rule: instance Data.Binary.Class.Binary (Distribution.Simple.SetupHooks.Rule.RuleData 'Distribution.Simple.SetupHooks.Rule.User)
+ Distribution.Simple.SetupHooks.Rule: instance Data.Binary.Class.Binary (Distribution.Simple.SetupHooks.Rule.Static 'Distribution.Simple.SetupHooks.Rule.System fnTy)
+ Distribution.Simple.SetupHooks.Rule: instance Data.Binary.Class.Binary (Distribution.Simple.SetupHooks.Rule.Static 'Distribution.Simple.SetupHooks.Rule.User fnTy)
+ Distribution.Simple.SetupHooks.Rule: instance Data.Binary.Class.Binary Distribution.Simple.SetupHooks.Rule.Dependency
+ Distribution.Simple.SetupHooks.Rule: instance Data.Binary.Class.Binary Distribution.Simple.SetupHooks.Rule.Location
+ Distribution.Simple.SetupHooks.Rule: instance Data.Binary.Class.Binary Distribution.Simple.SetupHooks.Rule.RuleId
+ Distribution.Simple.SetupHooks.Rule: instance Data.Binary.Class.Binary Distribution.Simple.SetupHooks.Rule.RuleOutput
+ Distribution.Simple.SetupHooks.Rule: instance Data.Binary.Class.Binary Distribution.Simple.SetupHooks.Rule.RulesNameSpace
+ Distribution.Simple.SetupHooks.Rule: instance Data.Binary.Class.Binary arg => Data.Binary.Class.Binary (Distribution.Simple.SetupHooks.Rule.ScopedArgument 'Distribution.Simple.SetupHooks.Rule.User arg)
+ Distribution.Simple.SetupHooks.Rule: instance Distribution.Utils.Structured.Structured Distribution.Simple.SetupHooks.Rule.Dependency
+ Distribution.Simple.SetupHooks.Rule: instance Distribution.Utils.Structured.Structured Distribution.Simple.SetupHooks.Rule.Location
+ Distribution.Simple.SetupHooks.Rule: instance Distribution.Utils.Structured.Structured Distribution.Simple.SetupHooks.Rule.RuleId
+ Distribution.Simple.SetupHooks.Rule: instance Distribution.Utils.Structured.Structured Distribution.Simple.SetupHooks.Rule.RuleOutput
+ Distribution.Simple.SetupHooks.Rule: instance Distribution.Utils.Structured.Structured Distribution.Simple.SetupHooks.Rule.RulesNameSpace
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Base.Functor m => GHC.Base.Functor (Distribution.Simple.SetupHooks.Rule.RulesT m)
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Base.Monad m => GHC.Base.Applicative (Distribution.Simple.SetupHooks.Rule.RulesT m)
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Base.Monad m => GHC.Base.Monad (Distribution.Simple.SetupHooks.Rule.RulesT m)
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Base.Monoid (Distribution.Simple.SetupHooks.Rule.Rules env)
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Base.Semigroup (Distribution.Simple.SetupHooks.Rule.Rules env)
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Classes.Eq (Distribution.Simple.SetupHooks.Rule.CommandData 'Distribution.Simple.SetupHooks.Rule.User arg res)
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Classes.Eq (Distribution.Simple.SetupHooks.Rule.DynDepsCmd 'Distribution.Simple.SetupHooks.Rule.User depsArg depsRes)
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Classes.Eq (Distribution.Simple.SetupHooks.Rule.RuleData 'Distribution.Simple.SetupHooks.Rule.System)
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Classes.Eq (Distribution.Simple.SetupHooks.Rule.RuleData 'Distribution.Simple.SetupHooks.Rule.User)
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Classes.Eq (Distribution.Simple.SetupHooks.Rule.Static 'Distribution.Simple.SetupHooks.Rule.System fnTy)
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Classes.Eq (Distribution.Simple.SetupHooks.Rule.Static 'Distribution.Simple.SetupHooks.Rule.User fnTy)
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Classes.Eq Distribution.Simple.SetupHooks.Rule.Dependency
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Classes.Eq Distribution.Simple.SetupHooks.Rule.Location
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Classes.Eq Distribution.Simple.SetupHooks.Rule.RuleId
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Classes.Eq Distribution.Simple.SetupHooks.Rule.RuleOutput
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Classes.Eq Distribution.Simple.SetupHooks.Rule.RulesNameSpace
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Classes.Eq arg => GHC.Classes.Eq (Distribution.Simple.SetupHooks.Rule.ScopedArgument scope arg)
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Classes.Ord (Distribution.Simple.SetupHooks.Rule.Static 'Distribution.Simple.SetupHooks.Rule.System fnTy)
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Classes.Ord (Distribution.Simple.SetupHooks.Rule.Static 'Distribution.Simple.SetupHooks.Rule.User fnTy)
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Classes.Ord Distribution.Simple.SetupHooks.Rule.Dependency
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Classes.Ord Distribution.Simple.SetupHooks.Rule.Location
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Classes.Ord Distribution.Simple.SetupHooks.Rule.RuleId
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Classes.Ord Distribution.Simple.SetupHooks.Rule.RuleOutput
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Classes.Ord Distribution.Simple.SetupHooks.Rule.RulesNameSpace
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Classes.Ord arg => GHC.Classes.Ord (Distribution.Simple.SetupHooks.Rule.ScopedArgument scope arg)
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Generics.Generic (Distribution.Simple.SetupHooks.Rule.RuleData scope)
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Generics.Generic Distribution.Simple.SetupHooks.Rule.Dependency
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Generics.Generic Distribution.Simple.SetupHooks.Rule.RuleId
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Generics.Generic Distribution.Simple.SetupHooks.Rule.RuleOutput
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Generics.Generic Distribution.Simple.SetupHooks.Rule.RulesNameSpace
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Show.Show (Distribution.Simple.SetupHooks.Rule.CommandData 'Distribution.Simple.SetupHooks.Rule.User arg res)
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Show.Show (Distribution.Simple.SetupHooks.Rule.DynDepsCmd 'Distribution.Simple.SetupHooks.Rule.User depsArg depsRes)
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Show.Show (Distribution.Simple.SetupHooks.Rule.RuleData 'Distribution.Simple.SetupHooks.Rule.User)
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Show.Show (Distribution.Simple.SetupHooks.Rule.Static 'Distribution.Simple.SetupHooks.Rule.System fnTy)
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Show.Show (Distribution.Simple.SetupHooks.Rule.Static 'Distribution.Simple.SetupHooks.Rule.User fnTy)
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Show.Show Distribution.Simple.SetupHooks.Rule.Dependency
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Show.Show Distribution.Simple.SetupHooks.Rule.Location
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Show.Show Distribution.Simple.SetupHooks.Rule.RuleBinary
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Show.Show Distribution.Simple.SetupHooks.Rule.RuleId
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Show.Show Distribution.Simple.SetupHooks.Rule.RuleOutput
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Show.Show Distribution.Simple.SetupHooks.Rule.RulesNameSpace
+ Distribution.Simple.SetupHooks.Rule: instance GHC.Show.Show arg => GHC.Show.Show (Distribution.Simple.SetupHooks.Rule.ScopedArgument scope arg)
+ Distribution.Simple.SetupHooks.Rule: instance forall (scope :: Distribution.Simple.SetupHooks.Rule.Scope) k (depsArg :: k) depsRes. GHC.Classes.Eq depsRes => GHC.Classes.Eq (Distribution.Simple.SetupHooks.Rule.DepsRes scope depsArg depsRes)
+ Distribution.Simple.SetupHooks.Rule: instance forall (scope :: Distribution.Simple.SetupHooks.Rule.Scope) k (depsArg :: k) depsRes. GHC.Classes.Ord depsRes => GHC.Classes.Ord (Distribution.Simple.SetupHooks.Rule.DepsRes scope depsArg depsRes)
+ Distribution.Simple.SetupHooks.Rule: instance forall (scope :: Distribution.Simple.SetupHooks.Rule.Scope) k (depsArg :: k) depsRes. GHC.Show.Show depsRes => GHC.Show.Show (Distribution.Simple.SetupHooks.Rule.DepsRes scope depsArg depsRes)
+ Distribution.Simple.SetupHooks.Rule: instance forall (scope :: Distribution.Simple.SetupHooks.Rule.Scope) k1 (arg :: k1) k2 (res :: k2). Data.Binary.Class.Binary (Distribution.Simple.SetupHooks.Rule.NoCmd scope arg res)
+ Distribution.Simple.SetupHooks.Rule: instance forall (scope :: Distribution.Simple.SetupHooks.Rule.Scope) k1 (arg :: k1) k2 (res :: k2). GHC.Classes.Eq (Distribution.Simple.SetupHooks.Rule.NoCmd scope arg res)
+ Distribution.Simple.SetupHooks.Rule: instance forall (scope :: Distribution.Simple.SetupHooks.Rule.Scope) k1 (arg :: k1) k2 (res :: k2). GHC.Classes.Ord (Distribution.Simple.SetupHooks.Rule.NoCmd scope arg res)
+ Distribution.Simple.SetupHooks.Rule: instance forall (scope :: Distribution.Simple.SetupHooks.Rule.Scope) k1 (arg :: k1) k2 (res :: k2). GHC.Generics.Generic (Distribution.Simple.SetupHooks.Rule.NoCmd scope arg res)
+ Distribution.Simple.SetupHooks.Rule: instance forall (scope :: Distribution.Simple.SetupHooks.Rule.Scope) k1 (arg :: k1) k2 (res :: k2). GHC.Show.Show (Distribution.Simple.SetupHooks.Rule.NoCmd scope arg res)
+ Distribution.Simple.SetupHooks.Rule: instance forall k (scope :: Distribution.Simple.SetupHooks.Rule.Scope) depsRes (depsArg :: k). Data.Binary.Class.Binary (Distribution.Simple.SetupHooks.Rule.ScopedArgument scope depsRes) => Data.Binary.Class.Binary (Distribution.Simple.SetupHooks.Rule.DepsRes scope depsArg depsRes)
+ Distribution.Simple.SetupHooks.Rule: location :: Location -> SymbolicPath Pkg File
+ Distribution.Simple.SetupHooks.Rule: mkCommand :: forall arg res. StaticPtr (Dict (Binary arg, Show arg)) -> StaticPtr (arg -> res) -> arg -> Command arg res
+ Distribution.Simple.SetupHooks.Rule: newtype DepsRes (scope :: Scope) depsArg depsRes
+ Distribution.Simple.SetupHooks.Rule: newtype DynDepsCmd scope depsArg depsRes
+ Distribution.Simple.SetupHooks.Rule: newtype Rules env
+ Distribution.Simple.SetupHooks.Rule: newtype RulesT m a
+ Distribution.Simple.SetupHooks.Rule: noRules :: RulesM ()
+ Distribution.Simple.SetupHooks.Rule: ruleBinary :: Rule -> RuleBinary
+ Distribution.Simple.SetupHooks.Rule: ruleDepsCmd :: RuleCmds scope -> RuleDynDepsCmd scope
+ Distribution.Simple.SetupHooks.Rule: ruleExecCmd :: SScope scope -> RuleCmds scope -> Maybe ByteString -> RuleExecCmd scope
+ Distribution.Simple.SetupHooks.Rule: rules :: StaticPtr label -> (env -> RulesM ()) -> Rules env
+ Distribution.Simple.SetupHooks.Rule: runCommand :: Command args res -> res
+ Distribution.Simple.SetupHooks.Rule: runRuleDynDepsCmd :: RuleDynDepsCmd User -> Maybe (IO ([Dependency], ByteString))
+ Distribution.Simple.SetupHooks.Rule: runRuleExecCmd :: RuleExecCmd User -> IO ()
+ Distribution.Simple.SetupHooks.Rule: staticRule :: forall arg. Typeable arg => Command arg (IO ()) -> [Dependency] -> NonEmpty Location -> Rule
+ Distribution.Simple.SetupHooks.Rule: type Command = CommandData User
+ Distribution.Simple.SetupHooks.Rule: type Rule = RuleData User
+ Distribution.Simple.SetupHooks.Rule: type RuleBinary = RuleData System
+ Distribution.Simple.SetupHooks.Rule: type RuleCmds scope = RuleCommands scope DynDepsCmd CommandData
+ Distribution.Simple.SetupHooks.Rule: type RuleDynDepsCmd scope = RuleCommands scope DynDepsCmd NoCmd
+ Distribution.Simple.SetupHooks.Rule: type RuleExecCmd scope = RuleCommands scope DepsRes CommandData
+ Distribution.Simple.SetupHooks.Rule: type RulesM a = RulesT IO a
+ Distribution.Simple.Utils: Suffix :: String -> Suffix
+ Distribution.Simple.Utils: copyFileToCwd :: Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> SymbolicPath Pkg (Dir target) -> RelativePath Pkg File -> IO ()
+ Distribution.Simple.Utils: defaultPackageDescCwd :: Verbosity -> IO (RelativePath Pkg File)
+ Distribution.Simple.Utils: findFileCwdWithExtension' :: forall searchDir allowAbsolute. Maybe (SymbolicPath CWD (Dir Pkg)) -> [Suffix] -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)] -> RelativePath searchDir File -> IO (Maybe (SymbolicPathX allowAbsolute Pkg (Dir searchDir), RelativePath searchDir File))
+ Distribution.Simple.Utils: findModuleFileCwd :: forall searchDir allowAbsolute. Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)] -> [Suffix] -> ModuleName -> IO (SymbolicPathX allowAbsolute Pkg (Dir searchDir), RelativePath searchDir File)
+ Distribution.Simple.Utils: findModuleFilesCwd :: forall searchDir allowAbsolute. Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)] -> [Suffix] -> [ModuleName] -> IO [(SymbolicPathX allowAbsolute Pkg (Dir searchDir), RelativePath searchDir File)]
+ Distribution.Simple.Utils: newtype Suffix
+ Distribution.Simple.Utils: rawSystemExitWithEnvCwd :: Verbosity -> Maybe (SymbolicPath CWD to) -> FilePath -> [String] -> [(String, String)] -> IO ()
+ Distribution.Simple.Utils: withTempDirectoryCwd :: Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> SymbolicPath Pkg (Dir tmpDir1) -> String -> (SymbolicPath Pkg (Dir tmpDir2) -> IO a) -> IO a
+ Distribution.Simple.Utils: withTempDirectoryCwdEx :: forall a tmpDir1 tmpDir2. Verbosity -> TempFileOptions -> Maybe (SymbolicPath CWD (Dir Pkg)) -> SymbolicPath Pkg (Dir tmpDir1) -> String -> (SymbolicPath Pkg (Dir tmpDir2) -> IO a) -> IO a
+ Distribution.Simple.Utils: withTempFileCwd :: Maybe (SymbolicPath CWD (Dir Pkg)) -> SymbolicPath Pkg (Dir tmpDir) -> String -> (SymbolicPath Pkg File -> Handle -> IO a) -> IO a
+ Distribution.Types.GivenComponent: PromisedComponent :: PackageId -> LibraryName -> ComponentId -> PromisedComponent
+ Distribution.Types.GivenComponent: [promisedComponentId] :: PromisedComponent -> ComponentId
+ Distribution.Types.GivenComponent: [promisedComponentName] :: PromisedComponent -> LibraryName
+ Distribution.Types.GivenComponent: [promisedComponentPackage] :: PromisedComponent -> PackageId
+ Distribution.Types.GivenComponent: data PromisedComponent
+ Distribution.Types.GivenComponent: instance Data.Binary.Class.Binary Distribution.Types.GivenComponent.PromisedComponent
+ Distribution.Types.GivenComponent: instance Distribution.Utils.Structured.Structured Distribution.Types.GivenComponent.PromisedComponent
+ Distribution.Types.GivenComponent: instance GHC.Classes.Eq Distribution.Types.GivenComponent.PromisedComponent
+ Distribution.Types.GivenComponent: instance GHC.Generics.Generic Distribution.Types.GivenComponent.PromisedComponent
+ Distribution.Types.GivenComponent: instance GHC.Read.Read Distribution.Types.GivenComponent.PromisedComponent
+ Distribution.Types.GivenComponent: instance GHC.Show.Show Distribution.Types.GivenComponent.PromisedComponent
+ Distribution.Types.LocalBuildConfig: [$sel:withProfLibShared:BuildOptions] :: BuildOptions -> Bool
+ Distribution.Types.LocalBuildInfo: buildWays :: LocalBuildInfo -> (Bool -> [BuildWay], Bool -> BuildWay, BuildWay)
+ Distribution.Types.LocalBuildInfo: distPrefLBI :: LocalBuildInfo -> SymbolicPath Pkg (Dir Dist)
+ Distribution.Types.LocalBuildInfo: packageRoot :: CommonSetupFlags -> FilePath
+ Distribution.Types.LocalBuildInfo: setupFlagsBuildDir :: CommonSetupFlags -> SymbolicPath Pkg (Dir Build)
- Distribution.Backpack.Configure: configureComponentLocalBuildInfos :: Verbosity -> Bool -> ComponentRequestedSpec -> Bool -> Flag String -> Flag ComponentId -> PackageDescription -> ([PreExistingComponent], [PromisedComponent]) -> FlagAssignment -> [(ModuleName, Module)] -> InstalledPackageIndex -> Compiler -> LogProgress ([ComponentLocalBuildInfo], InstalledPackageIndex)
+ Distribution.Backpack.Configure: configureComponentLocalBuildInfos :: Verbosity -> Bool -> ComponentRequestedSpec -> Bool -> Flag String -> Flag ComponentId -> PackageDescription -> ([PreExistingComponent], [ConfiguredPromisedComponent]) -> FlagAssignment -> [(ModuleName, Module)] -> InstalledPackageIndex -> Compiler -> LogProgress ([ComponentLocalBuildInfo], InstalledPackageIndex)
- Distribution.PackageDescription.Check: UnknownFile :: String -> SymbolicPath PackageDir LicenseFile -> CheckExplanation
+ Distribution.PackageDescription.Check: UnknownFile :: String -> RelativePath Pkg File -> CheckExplanation
- Distribution.Simple.Build: createInternalPackageDB :: Verbosity -> LocalBuildInfo -> FilePath -> IO PackageDB
+ Distribution.Simple.Build: createInternalPackageDB :: Verbosity -> LocalBuildInfo -> SymbolicPath Pkg (Dir Dist) -> IO PackageDB
- Distribution.Simple.Build: preBuildComponent :: Verbosity -> LocalBuildInfo -> TargetInfo -> IO ()
+ Distribution.Simple.Build: preBuildComponent :: (LocalBuildInfo -> TargetInfo -> IO ()) -> Verbosity -> LocalBuildInfo -> TargetInfo -> IO ()
- Distribution.Simple.Build.Inputs: buildingWhatDistPref :: BuildingWhat -> FilePath
+ Distribution.Simple.Build.Inputs: buildingWhatDistPref :: BuildingWhat -> SymbolicPath Pkg (Dir Dist)
- Distribution.Simple.Build.Inputs: pattern LocalBuildInfo :: ConfigFlags -> FlagAssignment -> ComponentRequestedSpec -> [String] -> InstallDirTemplates -> Compiler -> Platform -> Maybe FilePath -> Graph ComponentLocalBuildInfo -> Map ComponentName [ComponentLocalBuildInfo] -> Map (PackageName, ComponentName) ComponentId -> InstalledPackageIndex -> PackageDescription -> ProgramDb -> PackageDBStack -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> ProfDetailLevel -> ProfDetailLevel -> OptimisationLevel -> DebugInfoLevel -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> [UnitId] -> Bool -> LocalBuildInfo
+ Distribution.Simple.Build.Inputs: pattern LocalBuildInfo :: ConfigFlags -> FlagAssignment -> ComponentRequestedSpec -> [String] -> InstallDirTemplates -> Compiler -> Platform -> Maybe (SymbolicPath Pkg File) -> Graph ComponentLocalBuildInfo -> Map ComponentName [ComponentLocalBuildInfo] -> Map (PackageName, ComponentName) PromisedComponent -> InstalledPackageIndex -> PackageDescription -> ProgramDb -> PackageDBStack -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> ProfDetailLevel -> ProfDetailLevel -> OptimisationLevel -> DebugInfoLevel -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> [UnitId] -> Bool -> LocalBuildInfo
- Distribution.Simple.BuildPaths: autogenComponentModulesDir :: LocalBuildInfo -> ComponentLocalBuildInfo -> String
+ Distribution.Simple.BuildPaths: autogenComponentModulesDir :: LocalBuildInfo -> ComponentLocalBuildInfo -> SymbolicPath Pkg (Dir Source)
- Distribution.Simple.BuildPaths: autogenPackageModulesDir :: LocalBuildInfo -> String
+ Distribution.Simple.BuildPaths: autogenPackageModulesDir :: LocalBuildInfo -> SymbolicPath Pkg (Dir Source)
- Distribution.Simple.BuildPaths: buildInfoPref :: FilePath -> FilePath
+ Distribution.Simple.BuildPaths: buildInfoPref :: SymbolicPath root (Dir Dist) -> SymbolicPath root File
- Distribution.Simple.BuildPaths: defaultDistPref :: FilePath
+ Distribution.Simple.BuildPaths: defaultDistPref :: SymbolicPath Pkg (Dir Dist)
- Distribution.Simple.BuildPaths: exeBuildDir :: LocalBuildInfo -> Executable -> FilePath
+ Distribution.Simple.BuildPaths: exeBuildDir :: LocalBuildInfo -> Executable -> SymbolicPath Pkg (Dir Build)
- Distribution.Simple.BuildPaths: flibBuildDir :: LocalBuildInfo -> ForeignLib -> FilePath
+ Distribution.Simple.BuildPaths: flibBuildDir :: LocalBuildInfo -> ForeignLib -> SymbolicPath Pkg (Dir Build)
- Distribution.Simple.BuildPaths: getExeSourceFiles :: Verbosity -> LocalBuildInfo -> Executable -> ComponentLocalBuildInfo -> IO [(ModuleName, FilePath)]
+ Distribution.Simple.BuildPaths: getExeSourceFiles :: Verbosity -> LocalBuildInfo -> Executable -> ComponentLocalBuildInfo -> IO [(ModuleName, SymbolicPath Pkg 'File)]
- Distribution.Simple.BuildPaths: getFLibSourceFiles :: Verbosity -> LocalBuildInfo -> ForeignLib -> ComponentLocalBuildInfo -> IO [(ModuleName, FilePath)]
+ Distribution.Simple.BuildPaths: getFLibSourceFiles :: Verbosity -> LocalBuildInfo -> ForeignLib -> ComponentLocalBuildInfo -> IO [(ModuleName, SymbolicPath Pkg File)]
- Distribution.Simple.BuildPaths: getLibSourceFiles :: Verbosity -> LocalBuildInfo -> Library -> ComponentLocalBuildInfo -> IO [(ModuleName, FilePath)]
+ Distribution.Simple.BuildPaths: getLibSourceFiles :: Verbosity -> LocalBuildInfo -> Library -> ComponentLocalBuildInfo -> IO [(ModuleName, SymbolicPath Pkg File)]
- Distribution.Simple.BuildPaths: getSourceFiles :: Verbosity -> [FilePath] -> [ModuleName] -> IO [(ModuleName, FilePath)]
+ Distribution.Simple.BuildPaths: getSourceFiles :: Verbosity -> Maybe (SymbolicPath CWD ('Dir Pkg)) -> [SymbolicPathX allowAbsolute Pkg (Dir Source)] -> [ModuleName] -> IO [(ModuleName, SymbolicPathX allowAbsolute Pkg File)]
- Distribution.Simple.BuildPaths: haddockPref :: HaddockTarget -> FilePath -> PackageDescription -> FilePath
+ Distribution.Simple.BuildPaths: haddockPref :: HaddockTarget -> SymbolicPath root (Dir Dist) -> PackageDescription -> SymbolicPath root (Dir Artifacts)
- Distribution.Simple.BuildPaths: hscolourPref :: HaddockTarget -> FilePath -> PackageDescription -> FilePath
+ Distribution.Simple.BuildPaths: hscolourPref :: HaddockTarget -> SymbolicPath root (Dir Dist) -> PackageDescription -> SymbolicPath root (Dir Artifacts)
- Distribution.Simple.Compiler: GlobalPackageDB :: PackageDB
+ Distribution.Simple.Compiler: GlobalPackageDB :: PackageDBX fp
- Distribution.Simple.Compiler: SpecificPackageDB :: FilePath -> PackageDB
+ Distribution.Simple.Compiler: SpecificPackageDB :: fp -> PackageDBX fp
- Distribution.Simple.Compiler: UserPackageDB :: PackageDB
+ Distribution.Simple.Compiler: UserPackageDB :: PackageDBX fp
- Distribution.Simple.Compiler: absolutePackageDBPath :: PackageDB -> IO PackageDB
+ Distribution.Simple.Compiler: absolutePackageDBPath :: Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDB -> IO PackageDB
- Distribution.Simple.Compiler: absolutePackageDBPaths :: PackageDBStack -> IO PackageDBStack
+ Distribution.Simple.Compiler: absolutePackageDBPaths :: Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDBStack -> IO PackageDBStack
- Distribution.Simple.Compiler: registrationPackageDB :: PackageDBStack -> PackageDB
+ Distribution.Simple.Compiler: registrationPackageDB :: PackageDBStackX from -> PackageDBX from
- Distribution.Simple.Compiler: type PackageDBStack = [PackageDB]
+ Distribution.Simple.Compiler: type PackageDBStack = PackageDBStackX (SymbolicPath Pkg (Dir PkgDB))
- Distribution.Simple.Configure: ConfigStateFileMissing :: ConfigStateFileError
+ Distribution.Simple.Configure: ConfigStateFileMissing :: Maybe (SymbolicPath CWD (Dir Pkg)) -> SymbolicPath Pkg File -> ConfigStateFileError
- Distribution.Simple.Configure: checkPersistBuildConfigOutdated :: FilePath -> FilePath -> IO Bool
+ Distribution.Simple.Configure: checkPersistBuildConfigOutdated :: Maybe (SymbolicPath CWD (Dir Pkg)) -> SymbolicPath Pkg (Dir Dist) -> SymbolicPath Pkg File -> IO Bool
- Distribution.Simple.Configure: computeEffectiveProfiling :: ConfigFlags -> (Bool, Bool)
+ Distribution.Simple.Configure: computeEffectiveProfiling :: ConfigFlags -> (Bool, Bool, Bool)
- Distribution.Simple.Configure: findDistPref :: FilePath -> Flag FilePath -> IO FilePath
+ Distribution.Simple.Configure: findDistPref :: SymbolicPath Pkg (Dir Dist) -> Flag (SymbolicPath Pkg (Dir Dist)) -> IO (SymbolicPath Pkg (Dir Dist))
- Distribution.Simple.Configure: findDistPrefOrDefault :: Flag FilePath -> IO FilePath
+ Distribution.Simple.Configure: findDistPrefOrDefault :: Flag (SymbolicPath Pkg (Dir Dist)) -> IO (SymbolicPath Pkg (Dir Dist))
- Distribution.Simple.Configure: getConfigStateFile :: FilePath -> IO LocalBuildInfo
+ Distribution.Simple.Configure: getConfigStateFile :: Maybe (SymbolicPath CWD (Dir Pkg)) -> SymbolicPath Pkg File -> IO LocalBuildInfo
- Distribution.Simple.Configure: getInstalledPackages :: Verbosity -> Compiler -> PackageDBStack -> ProgramDb -> IO InstalledPackageIndex
+ Distribution.Simple.Configure: getInstalledPackages :: Verbosity -> Compiler -> Maybe (SymbolicPath CWD (Dir from)) -> PackageDBStackX (SymbolicPath from (Dir PkgDB)) -> ProgramDb -> IO InstalledPackageIndex
- Distribution.Simple.Configure: getInstalledPackagesMonitorFiles :: Verbosity -> Compiler -> PackageDBStack -> ProgramDb -> Platform -> IO [FilePath]
+ Distribution.Simple.Configure: getInstalledPackagesMonitorFiles :: Verbosity -> Compiler -> Maybe (SymbolicPath CWD ('Dir from)) -> PackageDBStackS from -> ProgramDb -> Platform -> IO [FilePath]
- Distribution.Simple.Configure: getPackageDBContents :: Verbosity -> Compiler -> PackageDB -> ProgramDb -> IO InstalledPackageIndex
+ Distribution.Simple.Configure: getPackageDBContents :: Verbosity -> Compiler -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDB -> ProgramDb -> IO InstalledPackageIndex
- Distribution.Simple.Configure: getPersistBuildConfig :: FilePath -> IO LocalBuildInfo
+ Distribution.Simple.Configure: getPersistBuildConfig :: Maybe (SymbolicPath CWD (Dir Pkg)) -> SymbolicPath Pkg (Dir Dist) -> IO LocalBuildInfo
- Distribution.Simple.Configure: interpretPackageDbFlags :: Bool -> [Maybe PackageDB] -> PackageDBStack
+ Distribution.Simple.Configure: interpretPackageDbFlags :: Bool -> [Maybe (PackageDBX fp)] -> PackageDBStackX fp
- Distribution.Simple.Configure: localBuildInfoFile :: FilePath -> FilePath
+ Distribution.Simple.Configure: localBuildInfoFile :: SymbolicPath Pkg (Dir Dist) -> SymbolicPath Pkg File
- Distribution.Simple.Configure: maybeGetPersistBuildConfig :: FilePath -> IO (Maybe LocalBuildInfo)
+ Distribution.Simple.Configure: maybeGetPersistBuildConfig :: Maybe (SymbolicPath CWD (Dir Pkg)) -> SymbolicPath Pkg (Dir Dist) -> IO (Maybe LocalBuildInfo)
- Distribution.Simple.Configure: tryGetConfigStateFile :: FilePath -> IO (Either ConfigStateFileError LocalBuildInfo)
+ Distribution.Simple.Configure: tryGetConfigStateFile :: Maybe (SymbolicPath CWD (Dir Pkg)) -> SymbolicPath Pkg File -> IO (Either ConfigStateFileError LocalBuildInfo)
- Distribution.Simple.Configure: tryGetPersistBuildConfig :: FilePath -> IO (Either ConfigStateFileError LocalBuildInfo)
+ Distribution.Simple.Configure: tryGetPersistBuildConfig :: Maybe (SymbolicPath CWD (Dir Pkg)) -> SymbolicPath Pkg (Dir Dist) -> IO (Either ConfigStateFileError LocalBuildInfo)
- Distribution.Simple.Configure: writePersistBuildConfig :: FilePath -> LocalBuildInfo -> IO ()
+ Distribution.Simple.Configure: writePersistBuildConfig :: Maybe (SymbolicPath CWD (Dir Pkg)) -> SymbolicPath Pkg (Dir Dist) -> LocalBuildInfo -> IO ()
- Distribution.Simple.Errors: ConfigureScriptNotFound :: CabalException
+ Distribution.Simple.Errors: ConfigureScriptNotFound :: FilePath -> CabalException
- Distribution.Simple.Errors: NoOSSupport :: OS -> CabalException
+ Distribution.Simple.Errors: NoOSSupport :: OS -> String -> CabalException
- Distribution.Simple.GHC: GhcEnvFileClearPackageDbStack :: GhcEnvironmentFileEntry
+ Distribution.Simple.GHC: GhcEnvFileClearPackageDbStack :: GhcEnvironmentFileEntry fp
- Distribution.Simple.GHC: GhcEnvFileComment :: String -> GhcEnvironmentFileEntry
+ Distribution.Simple.GHC: GhcEnvFileComment :: String -> GhcEnvironmentFileEntry fp
- Distribution.Simple.GHC: GhcEnvFilePackageDb :: PackageDB -> GhcEnvironmentFileEntry
+ Distribution.Simple.GHC: GhcEnvFilePackageDb :: PackageDBX fp -> GhcEnvironmentFileEntry fp
- Distribution.Simple.GHC: GhcEnvFilePackageId :: UnitId -> GhcEnvironmentFileEntry
+ Distribution.Simple.GHC: GhcEnvFilePackageId :: UnitId -> GhcEnvironmentFileEntry fp
- Distribution.Simple.GHC: componentCcGhcOptions :: Verbosity -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo -> FilePath -> FilePath -> GhcOptions
+ Distribution.Simple.GHC: componentCcGhcOptions :: Verbosity -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo -> SymbolicPath Pkg (Dir Artifacts) -> SymbolicPath Pkg File -> GhcOptions
- Distribution.Simple.GHC: componentGhcOptions :: Verbosity -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo -> FilePath -> GhcOptions
+ Distribution.Simple.GHC: componentGhcOptions :: Verbosity -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo -> SymbolicPath Pkg (Dir build) -> GhcOptions
- Distribution.Simple.GHC: data GhcEnvironmentFileEntry
+ Distribution.Simple.GHC: data GhcEnvironmentFileEntry fp
- Distribution.Simple.GHC: getInstalledPackages :: Verbosity -> Compiler -> PackageDBStack -> ProgramDb -> IO InstalledPackageIndex
+ Distribution.Simple.GHC: getInstalledPackages :: Verbosity -> Compiler -> Maybe (SymbolicPath CWD (Dir from)) -> PackageDBStackX (SymbolicPath from (Dir PkgDB)) -> ProgramDb -> IO InstalledPackageIndex
- Distribution.Simple.GHC: getInstalledPackagesMonitorFiles :: Verbosity -> Platform -> ProgramDb -> [PackageDB] -> IO [FilePath]
+ Distribution.Simple.GHC: getInstalledPackagesMonitorFiles :: forall from. Verbosity -> Maybe (SymbolicPath CWD (Dir from)) -> Platform -> ProgramDb -> [PackageDBS from] -> IO [FilePath]
- Distribution.Simple.GHC: getPackageDBContents :: Verbosity -> PackageDB -> ProgramDb -> IO InstalledPackageIndex
+ Distribution.Simple.GHC: getPackageDBContents :: Verbosity -> Maybe (SymbolicPath CWD (Dir from)) -> PackageDBX (SymbolicPath from (Dir PkgDB)) -> ProgramDb -> IO InstalledPackageIndex
- Distribution.Simple.GHC: parseGhcEnvironmentFile :: Parser [GhcEnvironmentFileEntry]
+ Distribution.Simple.GHC: parseGhcEnvironmentFile :: Parser [GhcEnvironmentFileEntry FilePath]
- Distribution.Simple.GHC: pkgRoot :: Verbosity -> LocalBuildInfo -> PackageDB -> IO FilePath
+ Distribution.Simple.GHC: pkgRoot :: Verbosity -> LocalBuildInfo -> PackageDB -> IO (SymbolicPath CWD (Dir Pkg))
- Distribution.Simple.GHC: readGhcEnvironmentFile :: FilePath -> IO [GhcEnvironmentFileEntry]
+ Distribution.Simple.GHC: readGhcEnvironmentFile :: FilePath -> IO [GhcEnvironmentFileEntry FilePath]
- Distribution.Simple.GHC: registerPackage :: Verbosity -> ProgramDb -> PackageDBStack -> InstalledPackageInfo -> RegisterOptions -> IO ()
+ Distribution.Simple.GHC: registerPackage :: Verbosity -> ProgramDb -> Maybe (SymbolicPath CWD (Dir from)) -> PackageDBStackS from -> InstalledPackageInfo -> RegisterOptions -> IO ()
- Distribution.Simple.GHC: renderGhcEnvironmentFile :: [GhcEnvironmentFileEntry] -> String
+ Distribution.Simple.GHC: renderGhcEnvironmentFile :: [GhcEnvironmentFileEntry FilePath] -> String
- Distribution.Simple.GHC: simpleGhcEnvironmentFile :: PackageDBStack -> [UnitId] -> [GhcEnvironmentFileEntry]
+ Distribution.Simple.GHC: simpleGhcEnvironmentFile :: PackageDBStackX fp -> [UnitId] -> [GhcEnvironmentFileEntry fp]
- Distribution.Simple.GHC: writeGhcEnvironmentFile :: FilePath -> Platform -> Version -> [GhcEnvironmentFileEntry] -> IO FilePath
+ Distribution.Simple.GHC: writeGhcEnvironmentFile :: FilePath -> Platform -> Version -> [GhcEnvironmentFileEntry FilePath] -> IO FilePath
- Distribution.Simple.GHCJS: GhcEnvFileClearPackageDbStack :: GhcEnvironmentFileEntry
+ Distribution.Simple.GHCJS: GhcEnvFileClearPackageDbStack :: GhcEnvironmentFileEntry fp
- Distribution.Simple.GHCJS: GhcEnvFileComment :: String -> GhcEnvironmentFileEntry
+ Distribution.Simple.GHCJS: GhcEnvFileComment :: String -> GhcEnvironmentFileEntry fp
- Distribution.Simple.GHCJS: GhcEnvFilePackageDb :: PackageDB -> GhcEnvironmentFileEntry
+ Distribution.Simple.GHCJS: GhcEnvFilePackageDb :: PackageDBX fp -> GhcEnvironmentFileEntry fp
- Distribution.Simple.GHCJS: GhcEnvFilePackageId :: UnitId -> GhcEnvironmentFileEntry
+ Distribution.Simple.GHCJS: GhcEnvFilePackageId :: UnitId -> GhcEnvironmentFileEntry fp
- Distribution.Simple.GHCJS: componentCcGhcOptions :: Verbosity -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo -> FilePath -> FilePath -> GhcOptions
+ Distribution.Simple.GHCJS: componentCcGhcOptions :: Verbosity -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo -> SymbolicPath Pkg (Dir Artifacts) -> SymbolicPath Pkg File -> GhcOptions
- Distribution.Simple.GHCJS: componentGhcOptions :: Verbosity -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo -> FilePath -> GhcOptions
+ Distribution.Simple.GHCJS: componentGhcOptions :: Verbosity -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo -> SymbolicPath Pkg (Dir build) -> GhcOptions
- Distribution.Simple.GHCJS: data GhcEnvironmentFileEntry
+ Distribution.Simple.GHCJS: data GhcEnvironmentFileEntry fp
- Distribution.Simple.GHCJS: getInstalledPackages :: Verbosity -> PackageDBStack -> ProgramDb -> IO InstalledPackageIndex
+ Distribution.Simple.GHCJS: getInstalledPackages :: Verbosity -> Maybe (SymbolicPath CWD (Dir from)) -> PackageDBStackX (SymbolicPath from (Dir PkgDB)) -> ProgramDb -> IO InstalledPackageIndex
- Distribution.Simple.GHCJS: getInstalledPackagesMonitorFiles :: Verbosity -> Platform -> ProgramDb -> [PackageDB] -> IO [FilePath]
+ Distribution.Simple.GHCJS: getInstalledPackagesMonitorFiles :: Verbosity -> Platform -> Maybe (SymbolicPath CWD (Dir Pkg)) -> ProgramDb -> [PackageDB] -> IO [FilePath]
- Distribution.Simple.GHCJS: getPackageDBContents :: Verbosity -> PackageDB -> ProgramDb -> IO InstalledPackageIndex
+ Distribution.Simple.GHCJS: getPackageDBContents :: Verbosity -> Maybe (SymbolicPath CWD (Dir from)) -> PackageDBX (SymbolicPath from (Dir PkgDB)) -> ProgramDb -> IO InstalledPackageIndex
- Distribution.Simple.GHCJS: parseGhcEnvironmentFile :: Parser [GhcEnvironmentFileEntry]
+ Distribution.Simple.GHCJS: parseGhcEnvironmentFile :: Parser [GhcEnvironmentFileEntry FilePath]
- Distribution.Simple.GHCJS: readGhcEnvironmentFile :: FilePath -> IO [GhcEnvironmentFileEntry]
+ Distribution.Simple.GHCJS: readGhcEnvironmentFile :: FilePath -> IO [GhcEnvironmentFileEntry FilePath]
- Distribution.Simple.GHCJS: registerPackage :: Verbosity -> ProgramDb -> PackageDBStack -> InstalledPackageInfo -> RegisterOptions -> IO ()
+ Distribution.Simple.GHCJS: registerPackage :: Verbosity -> ProgramDb -> Maybe (SymbolicPath CWD (Dir from)) -> PackageDBStackS from -> InstalledPackageInfo -> RegisterOptions -> IO ()
- Distribution.Simple.GHCJS: renderGhcEnvironmentFile :: [GhcEnvironmentFileEntry] -> String
+ Distribution.Simple.GHCJS: renderGhcEnvironmentFile :: [GhcEnvironmentFileEntry FilePath] -> String
- Distribution.Simple.GHCJS: simpleGhcEnvironmentFile :: PackageDBStack -> [UnitId] -> [GhcEnvironmentFileEntry]
+ Distribution.Simple.GHCJS: simpleGhcEnvironmentFile :: PackageDBStackX fp -> [UnitId] -> [GhcEnvironmentFileEntry fp]
- Distribution.Simple.GHCJS: writeGhcEnvironmentFile :: FilePath -> Platform -> Version -> [GhcEnvironmentFileEntry] -> IO FilePath
+ Distribution.Simple.GHCJS: writeGhcEnvironmentFile :: FilePath -> Platform -> Version -> [GhcEnvironmentFileEntry FilePath] -> IO FilePath
- Distribution.Simple.Glob: matchDirFileGlob :: Verbosity -> CabalSpecVersion -> FilePath -> FilePath -> IO [FilePath]
+ Distribution.Simple.Glob: matchDirFileGlob :: Verbosity -> CabalSpecVersion -> Maybe (SymbolicPath CWD (Dir dir)) -> SymbolicPathX allowAbs dir file -> IO [SymbolicPathX allowAbs dir file]
- Distribution.Simple.Glob: matchDirFileGlobWithDie :: Verbosity -> (Verbosity -> CabalException -> IO [FilePath]) -> CabalSpecVersion -> FilePath -> FilePath -> IO [FilePath]
+ Distribution.Simple.Glob: matchDirFileGlobWithDie :: Verbosity -> (forall res. Verbosity -> CabalException -> IO [res]) -> CabalSpecVersion -> Maybe (SymbolicPath CWD (Dir dir)) -> SymbolicPathX allowAbs dir file -> IO [SymbolicPathX allowAbs dir file]
- Distribution.Simple.Haddock: createHaddockIndex :: Verbosity -> ProgramDb -> Compiler -> Platform -> HaddockProjectFlags -> IO ()
+ Distribution.Simple.Haddock: createHaddockIndex :: Verbosity -> ProgramDb -> Compiler -> Platform -> Maybe (SymbolicPath CWD (Dir Pkg)) -> HaddockProjectFlags -> IO ()
- Distribution.Simple.HaskellSuite: getInstalledPackages :: Verbosity -> PackageDBStack -> ProgramDb -> IO InstalledPackageIndex
+ Distribution.Simple.HaskellSuite: getInstalledPackages :: Verbosity -> PackageDBStackX (SymbolicPath from (Dir PkgDB)) -> ProgramDb -> IO InstalledPackageIndex
- Distribution.Simple.HaskellSuite: packageDbOpt :: PackageDB -> String
+ Distribution.Simple.HaskellSuite: packageDbOpt :: PackageDBX (SymbolicPath from (Dir PkgDB)) -> String
- Distribution.Simple.HaskellSuite: registerPackage :: Verbosity -> ProgramDb -> PackageDBStack -> InstalledPackageInfo -> IO ()
+ Distribution.Simple.HaskellSuite: registerPackage :: Verbosity -> ProgramDb -> PackageDBStackS from -> InstalledPackageInfo -> IO ()
- Distribution.Simple.Hpc: HPCMarkupInfo :: [FilePath] -> [ModuleName] -> HPCMarkupInfo
+ Distribution.Simple.Hpc: HPCMarkupInfo :: [SymbolicPath Pkg (Dir Artifacts)] -> [ModuleName] -> HPCMarkupInfo
- Distribution.Simple.Hpc: [pathsToLibsArtifacts] :: HPCMarkupInfo -> [FilePath]
+ Distribution.Simple.Hpc: [pathsToLibsArtifacts] :: HPCMarkupInfo -> [SymbolicPath Pkg (Dir Artifacts)]
- Distribution.Simple.Hpc: htmlDir :: FilePath -> Way -> FilePath
+ Distribution.Simple.Hpc: htmlDir :: SymbolicPath Pkg (Dir Dist) -> Way -> SymbolicPath Pkg (Dir Artifacts)
- Distribution.Simple.Hpc: markupPackage :: Verbosity -> HPCMarkupInfo -> LocalBuildInfo -> FilePath -> PackageDescription -> [TestSuite] -> IO ()
+ Distribution.Simple.Hpc: markupPackage :: Verbosity -> HPCMarkupInfo -> LocalBuildInfo -> SymbolicPath Pkg (Dir Dist) -> PackageDescription -> [TestSuite] -> IO ()
- Distribution.Simple.Hpc: mixDir :: FilePath -> Way -> FilePath
+ Distribution.Simple.Hpc: mixDir :: SymbolicPath Pkg (Dir Dist) -> Way -> SymbolicPath Pkg (Dir Mix)
- Distribution.Simple.Hpc: tixDir :: FilePath -> Way -> FilePath
+ Distribution.Simple.Hpc: tixDir :: SymbolicPath Pkg (Dir Dist) -> Way -> SymbolicPath Pkg (Dir Tix)
- Distribution.Simple.Hpc: tixFilePath :: FilePath -> Way -> FilePath -> FilePath
+ Distribution.Simple.Hpc: tixFilePath :: SymbolicPath Pkg (Dir Dist) -> Way -> FilePath -> SymbolicPath Pkg File
- Distribution.Simple.LocalBuildInfo: buildDir :: LocalBuildInfo -> FilePath
+ Distribution.Simple.LocalBuildInfo: buildDir :: LocalBuildInfo -> SymbolicPath Pkg (Dir Build)
- Distribution.Simple.LocalBuildInfo: componentBuildDir :: LocalBuildInfo -> ComponentLocalBuildInfo -> FilePath
+ Distribution.Simple.LocalBuildInfo: componentBuildDir :: LocalBuildInfo -> ComponentLocalBuildInfo -> SymbolicPath Pkg (Dir Build)
- Distribution.Simple.LocalBuildInfo: pattern LocalBuildInfo :: ConfigFlags -> FlagAssignment -> ComponentRequestedSpec -> [String] -> InstallDirTemplates -> Compiler -> Platform -> Maybe FilePath -> Graph ComponentLocalBuildInfo -> Map ComponentName [ComponentLocalBuildInfo] -> Map (PackageName, ComponentName) ComponentId -> InstalledPackageIndex -> PackageDescription -> ProgramDb -> PackageDBStack -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> ProfDetailLevel -> ProfDetailLevel -> OptimisationLevel -> DebugInfoLevel -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> [UnitId] -> Bool -> LocalBuildInfo
+ Distribution.Simple.LocalBuildInfo: pattern LocalBuildInfo :: ConfigFlags -> FlagAssignment -> ComponentRequestedSpec -> [String] -> InstallDirTemplates -> Compiler -> Platform -> Maybe (SymbolicPath Pkg File) -> Graph ComponentLocalBuildInfo -> Map ComponentName [ComponentLocalBuildInfo] -> Map (PackageName, ComponentName) PromisedComponent -> InstalledPackageIndex -> PackageDescription -> ProgramDb -> PackageDBStack -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> ProfDetailLevel -> ProfDetailLevel -> OptimisationLevel -> DebugInfoLevel -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> [UnitId] -> Bool -> LocalBuildInfo
- Distribution.Simple.PackageDescription: readGenericPackageDescription :: Verbosity -> FilePath -> IO GenericPackageDescription
+ Distribution.Simple.PackageDescription: readGenericPackageDescription :: HasCallStack => Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> SymbolicPath Pkg File -> IO GenericPackageDescription
- Distribution.Simple.PackageDescription: readHookedBuildInfo :: Verbosity -> FilePath -> IO HookedBuildInfo
+ Distribution.Simple.PackageDescription: readHookedBuildInfo :: Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> SymbolicPath Pkg File -> IO HookedBuildInfo
- Distribution.Simple.PreProcess: PreProcessor :: Bool -> (Verbosity -> [FilePath] -> [ModuleName] -> IO [ModuleName]) -> ((FilePath, FilePath) -> (FilePath, FilePath) -> Verbosity -> IO ()) -> PreProcessor
+ Distribution.Simple.PreProcess: PreProcessor :: Bool -> (Verbosity -> [SymbolicPath Pkg (Dir Source)] -> [ModuleName] -> IO [ModuleName]) -> PreProcessCommand -> PreProcessor
- Distribution.Simple.PreProcess: [ppOrdering] :: PreProcessor -> Verbosity -> [FilePath] -> [ModuleName] -> IO [ModuleName]
+ Distribution.Simple.PreProcess: [ppOrdering] :: PreProcessor -> Verbosity -> [SymbolicPath Pkg (Dir Source)] -> [ModuleName] -> IO [ModuleName]
- Distribution.Simple.PreProcess: [runPreProcessor] :: PreProcessor -> (FilePath, FilePath) -> (FilePath, FilePath) -> Verbosity -> IO ()
+ Distribution.Simple.PreProcess: [runPreProcessor] :: PreProcessor -> PreProcessCommand
- Distribution.Simple.PreProcess: preprocessExtras :: Verbosity -> Component -> LocalBuildInfo -> IO [FilePath]
+ Distribution.Simple.PreProcess: preprocessExtras :: Verbosity -> Component -> LocalBuildInfo -> IO [SymbolicPath Pkg File]
- Distribution.Simple.PreProcess: unsorted :: Verbosity -> [FilePath] -> [ModuleName] -> IO [ModuleName]
+ Distribution.Simple.PreProcess: unsorted :: Verbosity -> [path] -> [ModuleName] -> IO [ModuleName]
- Distribution.Simple.PreProcess.Types: PreProcessor :: Bool -> (Verbosity -> [FilePath] -> [ModuleName] -> IO [ModuleName]) -> ((FilePath, FilePath) -> (FilePath, FilePath) -> Verbosity -> IO ()) -> PreProcessor
+ Distribution.Simple.PreProcess.Types: PreProcessor :: Bool -> (Verbosity -> [SymbolicPath Pkg (Dir Source)] -> [ModuleName] -> IO [ModuleName]) -> PreProcessCommand -> PreProcessor
- Distribution.Simple.PreProcess.Types: [ppOrdering] :: PreProcessor -> Verbosity -> [FilePath] -> [ModuleName] -> IO [ModuleName]
+ Distribution.Simple.PreProcess.Types: [ppOrdering] :: PreProcessor -> Verbosity -> [SymbolicPath Pkg (Dir Source)] -> [ModuleName] -> IO [ModuleName]
- Distribution.Simple.PreProcess.Types: [runPreProcessor] :: PreProcessor -> (FilePath, FilePath) -> (FilePath, FilePath) -> Verbosity -> IO ()
+ Distribution.Simple.PreProcess.Types: [runPreProcessor] :: PreProcessor -> PreProcessCommand
- Distribution.Simple.Program.Ar: createArLibArchive :: Verbosity -> LocalBuildInfo -> FilePath -> [FilePath] -> IO ()
+ Distribution.Simple.Program.Ar: createArLibArchive :: Verbosity -> LocalBuildInfo -> SymbolicPath Pkg File -> [SymbolicPath Pkg File] -> IO ()
- Distribution.Simple.Program.Db: prependProgramSearchPath :: Verbosity -> [FilePath] -> ProgramDb -> IO ProgramDb
+ Distribution.Simple.Program.Db: prependProgramSearchPath :: Verbosity -> [FilePath] -> [(String, Maybe FilePath)] -> ProgramDb -> IO ProgramDb
- Distribution.Simple.Program.GHC: GhcOptions :: Flag GhcMode -> [String] -> [String] -> NubListR FilePath -> NubListR FilePath -> NubListR ModuleName -> Flag FilePath -> Flag FilePath -> Flag Bool -> NubListR FilePath -> Flag String -> Flag ComponentId -> [(ModuleName, OpenModule)] -> Flag Bool -> PackageDBStack -> NubListR (OpenUnitId, ModuleRenaming) -> Flag Bool -> Flag Bool -> Flag Bool -> [FilePath] -> NubListR FilePath -> [String] -> NubListR String -> NubListR String -> Flag Bool -> Flag Bool -> Flag Bool -> NubListR FilePath -> [String] -> [String] -> [String] -> [String] -> NubListR FilePath -> NubListR FilePath -> NubListR FilePath -> Flag FilePath -> Flag Language -> NubListR Extension -> Map Extension (Maybe CompilerFlag) -> Flag GhcOptimisation -> Flag DebugInfoLevel -> Flag Bool -> Flag GhcProfAuto -> Flag Bool -> Flag Bool -> Flag ParStrat -> Flag FilePath -> [FilePath] -> Flag String -> Flag String -> Flag String -> Flag String -> Flag FilePath -> Flag FilePath -> Flag FilePath -> Flag FilePath -> Flag FilePath -> Flag GhcDynLinkMode -> Flag Bool -> Flag Bool -> Flag Bool -> Flag String -> NubListR FilePath -> Flag Verbosity -> NubListR FilePath -> Flag Bool -> GhcOptions
+ Distribution.Simple.Program.GHC: GhcOptions :: Flag GhcMode -> [String] -> [String] -> NubListR (SymbolicPath Pkg File) -> NubListR (SymbolicPath Pkg File) -> NubListR ModuleName -> Flag (SymbolicPath Pkg File) -> Flag FilePath -> Flag Bool -> NubListR (SymbolicPath Pkg (Dir Source)) -> Flag String -> Flag ComponentId -> [(ModuleName, OpenModule)] -> Flag Bool -> PackageDBStack -> NubListR (OpenUnitId, ModuleRenaming) -> Flag Bool -> Flag Bool -> Flag Bool -> [FilePath] -> NubListR (SymbolicPath Pkg (Dir Lib)) -> [String] -> NubListR String -> NubListR (SymbolicPath Pkg (Dir Framework)) -> Flag Bool -> Flag Bool -> Flag Bool -> NubListR FilePath -> [String] -> [String] -> [String] -> [String] -> NubListR (SymbolicPath Pkg (Dir Include)) -> NubListR (SymbolicPath Pkg File) -> NubListR FilePath -> Flag FilePath -> Flag Language -> NubListR Extension -> Map Extension (Maybe CompilerFlag) -> Flag GhcOptimisation -> Flag DebugInfoLevel -> Flag Bool -> Flag GhcProfAuto -> Flag Bool -> Flag Bool -> Flag ParStrat -> Flag (SymbolicPath Pkg (Dir Mix)) -> [FilePath] -> Flag String -> Flag String -> Flag String -> Flag String -> Flag (SymbolicPath Pkg (Dir Artifacts)) -> Flag (SymbolicPath Pkg (Dir Artifacts)) -> Flag (SymbolicPath Pkg (Dir Artifacts)) -> Flag (SymbolicPath Pkg (Dir Artifacts)) -> Flag (SymbolicPath Pkg (Dir Artifacts)) -> Flag GhcDynLinkMode -> Flag Bool -> Flag Bool -> Flag Bool -> Flag String -> NubListR FilePath -> Flag Verbosity -> NubListR (SymbolicPath Pkg (Dir Build)) -> Flag Bool -> GhcOptions
- Distribution.Simple.Program.GHC: [ghcOptCppIncludePath] :: GhcOptions -> NubListR FilePath
+ Distribution.Simple.Program.GHC: [ghcOptCppIncludePath] :: GhcOptions -> NubListR (SymbolicPath Pkg (Dir Include))
- Distribution.Simple.Program.GHC: [ghcOptCppIncludes] :: GhcOptions -> NubListR FilePath
+ Distribution.Simple.Program.GHC: [ghcOptCppIncludes] :: GhcOptions -> NubListR (SymbolicPath Pkg File)
- Distribution.Simple.Program.GHC: [ghcOptExtraPath] :: GhcOptions -> NubListR FilePath
+ Distribution.Simple.Program.GHC: [ghcOptExtraPath] :: GhcOptions -> NubListR (SymbolicPath Pkg (Dir Build))
- Distribution.Simple.Program.GHC: [ghcOptHPCDir] :: GhcOptions -> Flag FilePath
+ Distribution.Simple.Program.GHC: [ghcOptHPCDir] :: GhcOptions -> Flag (SymbolicPath Pkg (Dir Mix))
- Distribution.Simple.Program.GHC: [ghcOptHiDir] :: GhcOptions -> Flag FilePath
+ Distribution.Simple.Program.GHC: [ghcOptHiDir] :: GhcOptions -> Flag (SymbolicPath Pkg (Dir Artifacts))
- Distribution.Simple.Program.GHC: [ghcOptHieDir] :: GhcOptions -> Flag FilePath
+ Distribution.Simple.Program.GHC: [ghcOptHieDir] :: GhcOptions -> Flag (SymbolicPath Pkg (Dir Artifacts))
- Distribution.Simple.Program.GHC: [ghcOptInputFiles] :: GhcOptions -> NubListR FilePath
+ Distribution.Simple.Program.GHC: [ghcOptInputFiles] :: GhcOptions -> NubListR (SymbolicPath Pkg File)
- Distribution.Simple.Program.GHC: [ghcOptInputScripts] :: GhcOptions -> NubListR FilePath
+ Distribution.Simple.Program.GHC: [ghcOptInputScripts] :: GhcOptions -> NubListR (SymbolicPath Pkg File)
- Distribution.Simple.Program.GHC: [ghcOptLinkFrameworkDirs] :: GhcOptions -> NubListR String
+ Distribution.Simple.Program.GHC: [ghcOptLinkFrameworkDirs] :: GhcOptions -> NubListR (SymbolicPath Pkg (Dir Framework))
- Distribution.Simple.Program.GHC: [ghcOptLinkLibPath] :: GhcOptions -> NubListR FilePath
+ Distribution.Simple.Program.GHC: [ghcOptLinkLibPath] :: GhcOptions -> NubListR (SymbolicPath Pkg (Dir Lib))
- Distribution.Simple.Program.GHC: [ghcOptObjDir] :: GhcOptions -> Flag FilePath
+ Distribution.Simple.Program.GHC: [ghcOptObjDir] :: GhcOptions -> Flag (SymbolicPath Pkg (Dir Artifacts))
- Distribution.Simple.Program.GHC: [ghcOptOutputDir] :: GhcOptions -> Flag FilePath
+ Distribution.Simple.Program.GHC: [ghcOptOutputDir] :: GhcOptions -> Flag (SymbolicPath Pkg (Dir Artifacts))
- Distribution.Simple.Program.GHC: [ghcOptOutputFile] :: GhcOptions -> Flag FilePath
+ Distribution.Simple.Program.GHC: [ghcOptOutputFile] :: GhcOptions -> Flag (SymbolicPath Pkg File)
- Distribution.Simple.Program.GHC: [ghcOptSourcePath] :: GhcOptions -> NubListR FilePath
+ Distribution.Simple.Program.GHC: [ghcOptSourcePath] :: GhcOptions -> NubListR (SymbolicPath Pkg (Dir Source))
- Distribution.Simple.Program.GHC: [ghcOptStubDir] :: GhcOptions -> Flag FilePath
+ Distribution.Simple.Program.GHC: [ghcOptStubDir] :: GhcOptions -> Flag (SymbolicPath Pkg (Dir Artifacts))
- Distribution.Simple.Program.GHC: ghcInvocation :: Verbosity -> ConfiguredProgram -> Compiler -> Platform -> GhcOptions -> IO ProgramInvocation
+ Distribution.Simple.Program.GHC: ghcInvocation :: Verbosity -> ConfiguredProgram -> Compiler -> Platform -> Maybe (SymbolicPath CWD (Dir Pkg)) -> GhcOptions -> IO ProgramInvocation
- Distribution.Simple.Program.GHC: packageDbArgsDb :: PackageDBStack -> [String]
+ Distribution.Simple.Program.GHC: packageDbArgsDb :: PackageDBStackCWD -> [String]
- Distribution.Simple.Program.GHC: runGHC :: Verbosity -> ConfiguredProgram -> Compiler -> Platform -> GhcOptions -> IO ()
+ Distribution.Simple.Program.GHC: runGHC :: Verbosity -> ConfiguredProgram -> Compiler -> Platform -> Maybe (SymbolicPath CWD (Dir Pkg)) -> GhcOptions -> IO ()
- Distribution.Simple.Program.HcPkg: describe :: HcPkgInfo -> Verbosity -> PackageDBStack -> PackageId -> IO [InstalledPackageInfo]
+ Distribution.Simple.Program.HcPkg: describe :: HcPkgInfo -> Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDBStack -> PackageId -> IO [InstalledPackageInfo]
- Distribution.Simple.Program.HcPkg: describeInvocation :: HcPkgInfo -> Verbosity -> PackageDBStack -> PackageId -> ProgramInvocation
+ Distribution.Simple.Program.HcPkg: describeInvocation :: HcPkgInfo -> Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDBStack -> PackageId -> ProgramInvocation
- Distribution.Simple.Program.HcPkg: dump :: HcPkgInfo -> Verbosity -> PackageDB -> IO [InstalledPackageInfo]
+ Distribution.Simple.Program.HcPkg: dump :: HcPkgInfo -> Verbosity -> Maybe (SymbolicPath CWD (Dir from)) -> PackageDBX (SymbolicPath from (Dir PkgDB)) -> IO [InstalledPackageInfo]
- Distribution.Simple.Program.HcPkg: dumpInvocation :: HcPkgInfo -> Verbosity -> PackageDB -> ProgramInvocation
+ Distribution.Simple.Program.HcPkg: dumpInvocation :: HcPkgInfo -> Verbosity -> Maybe (SymbolicPath CWD (Dir from)) -> PackageDBX (SymbolicPath from (Dir PkgDB)) -> ProgramInvocation
- Distribution.Simple.Program.HcPkg: expose :: HcPkgInfo -> Verbosity -> PackageDB -> PackageId -> IO ()
+ Distribution.Simple.Program.HcPkg: expose :: HcPkgInfo -> Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDB -> PackageId -> IO ()
- Distribution.Simple.Program.HcPkg: exposeInvocation :: HcPkgInfo -> Verbosity -> PackageDB -> PackageId -> ProgramInvocation
+ Distribution.Simple.Program.HcPkg: exposeInvocation :: HcPkgInfo -> Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDB -> PackageId -> ProgramInvocation
- Distribution.Simple.Program.HcPkg: hide :: HcPkgInfo -> Verbosity -> PackageDB -> PackageId -> IO ()
+ Distribution.Simple.Program.HcPkg: hide :: HcPkgInfo -> Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDB -> PackageId -> IO ()
- Distribution.Simple.Program.HcPkg: hideInvocation :: HcPkgInfo -> Verbosity -> PackageDB -> PackageId -> ProgramInvocation
+ Distribution.Simple.Program.HcPkg: hideInvocation :: HcPkgInfo -> Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDB -> PackageId -> ProgramInvocation
- Distribution.Simple.Program.HcPkg: invoke :: HcPkgInfo -> Verbosity -> PackageDBStack -> [String] -> IO ()
+ Distribution.Simple.Program.HcPkg: invoke :: HcPkgInfo -> Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDBStack -> [String] -> IO ()
- Distribution.Simple.Program.HcPkg: list :: HcPkgInfo -> Verbosity -> PackageDB -> IO [PackageId]
+ Distribution.Simple.Program.HcPkg: list :: HcPkgInfo -> Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDB -> IO [PackageId]
- Distribution.Simple.Program.HcPkg: listInvocation :: HcPkgInfo -> Verbosity -> PackageDB -> ProgramInvocation
+ Distribution.Simple.Program.HcPkg: listInvocation :: HcPkgInfo -> Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDB -> ProgramInvocation
- Distribution.Simple.Program.HcPkg: recache :: HcPkgInfo -> Verbosity -> PackageDB -> IO ()
+ Distribution.Simple.Program.HcPkg: recache :: HcPkgInfo -> Verbosity -> Maybe (SymbolicPath CWD (Dir from)) -> PackageDBS from -> IO ()
- Distribution.Simple.Program.HcPkg: recacheInvocation :: HcPkgInfo -> Verbosity -> PackageDB -> ProgramInvocation
+ Distribution.Simple.Program.HcPkg: recacheInvocation :: HcPkgInfo -> Verbosity -> Maybe (SymbolicPath CWD (Dir from)) -> PackageDBS from -> ProgramInvocation
- Distribution.Simple.Program.HcPkg: register :: HcPkgInfo -> Verbosity -> PackageDBStack -> InstalledPackageInfo -> RegisterOptions -> IO ()
+ Distribution.Simple.Program.HcPkg: register :: HcPkgInfo -> Verbosity -> Maybe (SymbolicPath CWD (Dir from)) -> PackageDBStackS from -> InstalledPackageInfo -> RegisterOptions -> IO ()
- Distribution.Simple.Program.HcPkg: registerInvocation :: HcPkgInfo -> Verbosity -> PackageDBStack -> InstalledPackageInfo -> RegisterOptions -> ProgramInvocation
+ Distribution.Simple.Program.HcPkg: registerInvocation :: HcPkgInfo -> Verbosity -> Maybe (SymbolicPath CWD (Dir from)) -> PackageDBStackS from -> InstalledPackageInfo -> RegisterOptions -> ProgramInvocation
- Distribution.Simple.Program.HcPkg: unregister :: HcPkgInfo -> Verbosity -> PackageDB -> PackageId -> IO ()
+ Distribution.Simple.Program.HcPkg: unregister :: HcPkgInfo -> Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDB -> PackageId -> IO ()
- Distribution.Simple.Program.HcPkg: unregisterInvocation :: HcPkgInfo -> Verbosity -> PackageDB -> PackageId -> ProgramInvocation
+ Distribution.Simple.Program.HcPkg: unregisterInvocation :: HcPkgInfo -> Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDB -> PackageId -> ProgramInvocation
- Distribution.Simple.Program.Hpc: markup :: ConfiguredProgram -> Version -> Verbosity -> FilePath -> [FilePath] -> FilePath -> [ModuleName] -> IO ()
+ Distribution.Simple.Program.Hpc: markup :: Maybe (SymbolicPath CWD (Dir Pkg)) -> ConfiguredProgram -> Version -> Verbosity -> SymbolicPath Pkg File -> [SymbolicPath Pkg (Dir Mix)] -> SymbolicPath Pkg (Dir Artifacts) -> [ModuleName] -> IO ()
- Distribution.Simple.Program.Hpc: union :: ConfiguredProgram -> Verbosity -> [FilePath] -> FilePath -> [ModuleName] -> IO ()
+ Distribution.Simple.Program.Hpc: union :: Maybe (SymbolicPath CWD (Dir Pkg)) -> ConfiguredProgram -> Verbosity -> [SymbolicPath Pkg File] -> SymbolicPath Pkg File -> [ModuleName] -> IO ()
- Distribution.Simple.Program.Ld: combineObjectFiles :: Verbosity -> LocalBuildInfo -> ConfiguredProgram -> FilePath -> [FilePath] -> IO ()
+ Distribution.Simple.Program.Ld: combineObjectFiles :: Verbosity -> LocalBuildInfo -> ConfiguredProgram -> SymbolicPath Pkg File -> [SymbolicPath Pkg File] -> IO ()
- Distribution.Simple.Program.ResponseFile: withResponseFile :: Verbosity -> TempFileOptions -> FilePath -> FilePath -> Maybe TextEncoding -> [String] -> (FilePath -> IO a) -> IO a
+ Distribution.Simple.Program.ResponseFile: withResponseFile :: Verbosity -> TempFileOptions -> Maybe (SymbolicPath CWD (Dir Pkg)) -> SymbolicPath Pkg (Dir Response) -> String -> Maybe TextEncoding -> [String] -> (FilePath -> IO a) -> IO a
- Distribution.Simple.Register: abiHash :: Verbosity -> PackageDescription -> FilePath -> LocalBuildInfo -> Library -> ComponentLocalBuildInfo -> IO AbiHash
+ Distribution.Simple.Register: abiHash :: Verbosity -> PackageDescription -> SymbolicPath Pkg (Dir Dist) -> LocalBuildInfo -> Library -> ComponentLocalBuildInfo -> IO AbiHash
- Distribution.Simple.Register: generateRegistrationInfo :: Verbosity -> PackageDescription -> Library -> LocalBuildInfo -> ComponentLocalBuildInfo -> Bool -> Bool -> FilePath -> PackageDB -> IO InstalledPackageInfo
+ Distribution.Simple.Register: generateRegistrationInfo :: Verbosity -> PackageDescription -> Library -> LocalBuildInfo -> ComponentLocalBuildInfo -> Bool -> Bool -> SymbolicPath Pkg (Dir Dist) -> PackageDB -> IO InstalledPackageInfo
- Distribution.Simple.Register: inplaceInstalledPackageInfo :: FilePath -> FilePath -> PackageDescription -> AbiHash -> Library -> LocalBuildInfo -> ComponentLocalBuildInfo -> InstalledPackageInfo
+ Distribution.Simple.Register: inplaceInstalledPackageInfo :: AbsolutePath (Dir Pkg) -> SymbolicPath Pkg (Dir Dist) -> PackageDescription -> AbiHash -> Library -> LocalBuildInfo -> ComponentLocalBuildInfo -> InstalledPackageInfo
- Distribution.Simple.Register: internalPackageDBPath :: LocalBuildInfo -> FilePath -> FilePath
+ Distribution.Simple.Register: internalPackageDBPath :: LocalBuildInfo -> SymbolicPath Pkg (Dir Dist) -> SymbolicPath Pkg (Dir PkgDB)
- Distribution.Simple.Register: invokeHcPkg :: Verbosity -> Compiler -> ProgramDb -> PackageDBStack -> [String] -> IO ()
+ Distribution.Simple.Register: invokeHcPkg :: Verbosity -> Compiler -> ProgramDb -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDBStack -> [String] -> IO ()
- Distribution.Simple.Register: registerPackage :: Verbosity -> Compiler -> ProgramDb -> PackageDBStack -> InstalledPackageInfo -> RegisterOptions -> IO ()
+ Distribution.Simple.Register: registerPackage :: Verbosity -> Compiler -> ProgramDb -> Maybe (SymbolicPath CWD (Dir from)) -> PackageDBStackS from -> InstalledPackageInfo -> RegisterOptions -> IO ()
- Distribution.Simple.Setup: BenchmarkFlags :: Flag FilePath -> Flag Verbosity -> [PathTemplate] -> BenchmarkFlags
+ Distribution.Simple.Setup: BenchmarkFlags :: !CommonSetupFlags -> [PathTemplate] -> BenchmarkFlags
- Distribution.Simple.Setup: BuildFlags :: [(String, FilePath)] -> [(String, [String])] -> Flag FilePath -> Flag Verbosity -> Flag (Maybe Int) -> Flag String -> [String] -> Flag FilePath -> BuildFlags
+ Distribution.Simple.Setup: BuildFlags :: !CommonSetupFlags -> [(String, FilePath)] -> [(String, [String])] -> Flag (Maybe Int) -> Flag String -> BuildFlags
- Distribution.Simple.Setup: CleanFlags :: Flag Bool -> Flag FilePath -> Flag Verbosity -> Flag FilePath -> CleanFlags
+ Distribution.Simple.Setup: CleanFlags :: !CommonSetupFlags -> Flag Bool -> CleanFlags
- Distribution.Simple.Setup: ConfigFlags :: [String] -> Option' (Last' ProgramDb) -> [(String, FilePath)] -> [(String, [String])] -> NubList FilePath -> Flag CompilerFlavor -> Flag FilePath -> Flag FilePath -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag ProfDetailLevel -> Flag ProfDetailLevel -> [String] -> Flag OptimisationLevel -> Flag PathTemplate -> Flag PathTemplate -> InstallDirs (Flag PathTemplate) -> Flag FilePath -> [FilePath] -> [FilePath] -> [FilePath] -> [FilePath] -> Flag String -> Flag ComponentId -> Flag Bool -> Flag FilePath -> Flag FilePath -> Flag Verbosity -> Flag Bool -> [Maybe PackageDB] -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> [PackageVersionConstraint] -> [GivenComponent] -> [GivenComponent] -> [(ModuleName, Module)] -> FlagAssignment -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag String -> Flag Bool -> Flag DebugInfoLevel -> Flag DumpBuildInfo -> Flag Bool -> Flag Bool -> Flag [UnitId] -> ConfigFlags
+ Distribution.Simple.Setup: ConfigFlags :: !CommonSetupFlags -> Option' (Last' ProgramDb) -> [(String, FilePath)] -> [(String, [String])] -> NubList FilePath -> Flag CompilerFlavor -> Flag FilePath -> Flag FilePath -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag ProfDetailLevel -> Flag ProfDetailLevel -> [String] -> Flag OptimisationLevel -> Flag PathTemplate -> Flag PathTemplate -> InstallDirs (Flag PathTemplate) -> Flag FilePath -> [SymbolicPath Pkg (Dir Lib)] -> [SymbolicPath Pkg (Dir Lib)] -> [SymbolicPath Pkg (Dir Framework)] -> [SymbolicPath Pkg (Dir Include)] -> Flag String -> Flag ComponentId -> Flag Bool -> Flag Bool -> [Maybe PackageDB] -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> [PackageVersionConstraint] -> [GivenComponent] -> [PromisedComponent] -> [(ModuleName, Module)] -> FlagAssignment -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag String -> Flag Bool -> Flag DebugInfoLevel -> Flag DumpBuildInfo -> Flag Bool -> Flag Bool -> Flag [UnitId] -> Flag Bool -> ConfigFlags
- Distribution.Simple.Setup: CopyFlags :: Flag CopyDest -> Flag FilePath -> Flag Verbosity -> [String] -> Flag FilePath -> CopyFlags
+ Distribution.Simple.Setup: CopyFlags :: !CommonSetupFlags -> Flag CopyDest -> CopyFlags
- Distribution.Simple.Setup: GlobalFlags :: Flag Bool -> Flag Bool -> GlobalFlags
+ Distribution.Simple.Setup: GlobalFlags :: Flag Bool -> Flag Bool -> Flag (SymbolicPath CWD (Dir Pkg)) -> GlobalFlags
- Distribution.Simple.Setup: HaddockFlags :: [(String, FilePath)] -> [(String, [String])] -> Flag Bool -> Flag Bool -> Flag String -> Flag HaddockTarget -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag FilePath -> Flag Bool -> Flag Bool -> Flag FilePath -> Flag PathTemplate -> Flag PathTemplate -> Flag FilePath -> Flag Bool -> Flag Verbosity -> Flag FilePath -> Flag String -> Flag String -> Flag FilePath -> [String] -> HaddockFlags
+ Distribution.Simple.Setup: HaddockFlags :: !CommonSetupFlags -> [(String, FilePath)] -> [(String, [String])] -> Flag Bool -> Flag Bool -> Flag String -> Flag HaddockTarget -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag FilePath -> Flag Bool -> Flag Bool -> Flag FilePath -> Flag PathTemplate -> Flag PathTemplate -> Flag Bool -> Flag String -> Flag String -> Flag FilePath -> Flag Bool -> HaddockFlags
- Distribution.Simple.Setup: HaddockProjectFlags :: Flag Bool -> Flag String -> Flag String -> Flag [(FilePath, Maybe FilePath, Maybe FilePath, Visibility)] -> [(String, FilePath)] -> [(String, [String])] -> Flag Bool -> Flag String -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag FilePath -> Flag FilePath -> Flag Bool -> Flag Verbosity -> Flag String -> Flag FilePath -> HaddockProjectFlags
+ Distribution.Simple.Setup: HaddockProjectFlags :: Flag Bool -> Flag String -> Flag String -> Flag [(FilePath, Maybe FilePath, Maybe FilePath, Visibility)] -> [(String, FilePath)] -> [(String, [String])] -> Flag Bool -> Flag String -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag FilePath -> Flag FilePath -> Flag Bool -> Flag Verbosity -> Flag String -> Flag Bool -> HaddockProjectFlags
- Distribution.Simple.Setup: HscolourFlags :: Flag FilePath -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> Flag FilePath -> Flag Verbosity -> Flag FilePath -> HscolourFlags
+ Distribution.Simple.Setup: HscolourFlags :: !CommonSetupFlags -> Flag FilePath -> Flag Bool -> Flag Bool -> Flag Bool -> Flag Bool -> HscolourFlags
- Distribution.Simple.Setup: InstallFlags :: Flag PackageDB -> Flag CopyDest -> Flag FilePath -> Flag Bool -> Flag Bool -> Flag Verbosity -> Flag FilePath -> InstallFlags
+ Distribution.Simple.Setup: InstallFlags :: !CommonSetupFlags -> Flag PackageDB -> Flag CopyDest -> Flag Bool -> Flag Bool -> InstallFlags
- Distribution.Simple.Setup: RegisterFlags :: Flag PackageDB -> Flag Bool -> Flag (Maybe FilePath) -> Flag Bool -> Flag FilePath -> Flag Bool -> Flag Verbosity -> [String] -> Flag FilePath -> RegisterFlags
+ Distribution.Simple.Setup: RegisterFlags :: !CommonSetupFlags -> Flag PackageDB -> Flag Bool -> Flag (Maybe (SymbolicPath Pkg (Dir PkgConf))) -> Flag Bool -> Flag Bool -> RegisterFlags
- Distribution.Simple.Setup: ReplFlags :: [(String, FilePath)] -> [(String, [String])] -> Flag FilePath -> Flag Verbosity -> Flag Bool -> ReplOptions -> ReplFlags
+ Distribution.Simple.Setup: ReplFlags :: !CommonSetupFlags -> [(String, FilePath)] -> [(String, [String])] -> Flag Bool -> ReplOptions -> ReplFlags
- Distribution.Simple.Setup: SDistFlags :: Flag Bool -> Flag FilePath -> Flag FilePath -> Flag FilePath -> Flag Verbosity -> SDistFlags
+ Distribution.Simple.Setup: SDistFlags :: !CommonSetupFlags -> Flag Bool -> Flag FilePath -> Flag FilePath -> SDistFlags
- Distribution.Simple.Setup: TestFlags :: Flag FilePath -> Flag Verbosity -> Flag PathTemplate -> Flag PathTemplate -> Flag TestShowDetails -> Flag Bool -> Flag FilePath -> Flag Bool -> [PathTemplate] -> TestFlags
+ Distribution.Simple.Setup: TestFlags :: !CommonSetupFlags -> Flag PathTemplate -> Flag PathTemplate -> Flag TestShowDetails -> Flag Bool -> Flag FilePath -> Flag Bool -> [PathTemplate] -> TestFlags
- Distribution.Simple.Setup: [configExtraFrameworkDirs] :: ConfigFlags -> [FilePath]
+ Distribution.Simple.Setup: [configExtraFrameworkDirs] :: ConfigFlags -> [SymbolicPath Pkg (Dir Framework)]
- Distribution.Simple.Setup: [configExtraIncludeDirs] :: ConfigFlags -> [FilePath]
+ Distribution.Simple.Setup: [configExtraIncludeDirs] :: ConfigFlags -> [SymbolicPath Pkg (Dir Include)]
- Distribution.Simple.Setup: [configExtraLibDirsStatic] :: ConfigFlags -> [FilePath]
+ Distribution.Simple.Setup: [configExtraLibDirsStatic] :: ConfigFlags -> [SymbolicPath Pkg (Dir Lib)]
- Distribution.Simple.Setup: [configExtraLibDirs] :: ConfigFlags -> [FilePath]
+ Distribution.Simple.Setup: [configExtraLibDirs] :: ConfigFlags -> [SymbolicPath Pkg (Dir Lib)]
- Distribution.Simple.Setup: [configPromisedDependencies] :: ConfigFlags -> [GivenComponent]
+ Distribution.Simple.Setup: [configPromisedDependencies] :: ConfigFlags -> [PromisedComponent]
- Distribution.Simple.Setup: [regGenPkgConf] :: RegisterFlags -> Flag (Maybe FilePath)
+ Distribution.Simple.Setup: [regGenPkgConf] :: RegisterFlags -> Flag (Maybe (SymbolicPath Pkg (Dir PkgConf)))
- Distribution.Simple.Setup: buildingWhatDistPref :: BuildingWhat -> FilePath
+ Distribution.Simple.Setup: buildingWhatDistPref :: BuildingWhat -> SymbolicPath Pkg (Dir Dist)
- Distribution.Simple.Setup: defaultDistPref :: FilePath
+ Distribution.Simple.Setup: defaultDistPref :: SymbolicPath Pkg (Dir Dist)
- Distribution.Simple.Setup: optionDistPref :: (flags -> Flag FilePath) -> (Flag FilePath -> flags -> flags) -> ShowOrParseArgs -> OptionField flags
+ Distribution.Simple.Setup: optionDistPref :: (flags -> Flag (SymbolicPath Pkg (Dir Dist))) -> (Flag (SymbolicPath Pkg (Dir Dist)) -> flags -> flags) -> ShowOrParseArgs -> OptionField flags
- Distribution.Simple.ShowBuildInfo: mkBuildInfo :: FilePath -> PackageDescription -> LocalBuildInfo -> BuildFlags -> (ConfiguredProgram, Compiler) -> [TargetInfo] -> ([String], Json)
+ Distribution.Simple.ShowBuildInfo: mkBuildInfo :: AbsolutePath (Dir Pkg) -> PackageDescription -> LocalBuildInfo -> BuildFlags -> (ConfiguredProgram, Compiler) -> [TargetInfo] -> ([String], Json)
- Distribution.Simple.ShowBuildInfo: mkComponentInfo :: FilePath -> PackageDescription -> LocalBuildInfo -> ComponentLocalBuildInfo -> ([String], Json)
+ Distribution.Simple.ShowBuildInfo: mkComponentInfo :: AbsolutePath (Dir Pkg) -> PackageDescription -> LocalBuildInfo -> ComponentLocalBuildInfo -> ([String], Json)
- Distribution.Simple.SrcDist: listPackageSources :: Verbosity -> FilePath -> PackageDescription -> [PPSuffixHandler] -> IO [FilePath]
+ Distribution.Simple.SrcDist: listPackageSources :: Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDescription -> [PPSuffixHandler] -> IO [SymbolicPath Pkg File]
- Distribution.Simple.SrcDist: listPackageSourcesWithDie :: Verbosity -> (Verbosity -> CabalException -> IO [FilePath]) -> FilePath -> PackageDescription -> [PPSuffixHandler] -> IO [FilePath]
+ Distribution.Simple.SrcDist: listPackageSourcesWithDie :: Verbosity -> (forall res. Verbosity -> CabalException -> IO [res]) -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDescription -> [PPSuffixHandler] -> IO [SymbolicPath Pkg File]
- Distribution.Simple.SrcDist: prepareSnapshotTree :: Verbosity -> PackageDescription -> FilePath -> [PPSuffixHandler] -> IO ()
+ Distribution.Simple.SrcDist: prepareSnapshotTree :: Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDescription -> FilePath -> [PPSuffixHandler] -> IO ()
- Distribution.Simple.SrcDist: prepareTree :: Verbosity -> PackageDescription -> FilePath -> [PPSuffixHandler] -> IO ()
+ Distribution.Simple.SrcDist: prepareTree :: Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDescription -> FilePath -> [PPSuffixHandler] -> IO ()
- Distribution.Simple.UHC: getInstalledPackages :: Verbosity -> Compiler -> PackageDBStack -> ProgramDb -> IO InstalledPackageIndex
+ Distribution.Simple.UHC: getInstalledPackages :: Verbosity -> Compiler -> Maybe (SymbolicPath CWD (Dir from)) -> PackageDBStackX (SymbolicPath from (Dir PkgDB)) -> ProgramDb -> IO InstalledPackageIndex
- Distribution.Simple.UHC: inplacePackageDbPath :: LocalBuildInfo -> FilePath
+ Distribution.Simple.UHC: inplacePackageDbPath :: LocalBuildInfo -> SymbolicPath Pkg (Dir PkgDB)
- Distribution.Simple.UHC: registerPackage :: Verbosity -> Compiler -> ProgramDb -> PackageDBStack -> InstalledPackageInfo -> IO ()
+ Distribution.Simple.UHC: registerPackage :: Verbosity -> Maybe (SymbolicPath CWD (Dir from)) -> Compiler -> ProgramDb -> PackageDBStackS from -> InstalledPackageInfo -> IO ()
- Distribution.Simple.Utils: findAllFilesCwdWithExtension :: FilePath -> [Suffix] -> [FilePath] -> FilePath -> IO [FilePath]
+ Distribution.Simple.Utils: findAllFilesCwdWithExtension :: forall searchDir allowAbsolute. Maybe (SymbolicPath CWD (Dir Pkg)) -> [Suffix] -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)] -> RelativePath searchDir File -> IO [SymbolicPathX allowAbsolute Pkg File]
- Distribution.Simple.Utils: findAllFilesWithExtension :: [Suffix] -> [FilePath] -> FilePath -> IO [FilePath]
+ Distribution.Simple.Utils: findAllFilesWithExtension :: [Suffix] -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)] -> RelativePath searchDir File -> IO [SymbolicPathX allowAbsolute Pkg File]
- Distribution.Simple.Utils: findFileCwd :: Verbosity -> FilePath -> [FilePath] -> FilePath -> IO FilePath
+ Distribution.Simple.Utils: findFileCwd :: forall searchDir allowAbsolute. Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)] -> RelativePath searchDir File -> IO (SymbolicPathX allowAbsolute Pkg File)
- Distribution.Simple.Utils: findFileCwdWithExtension :: FilePath -> [Suffix] -> [FilePath] -> FilePath -> IO (Maybe FilePath)
+ Distribution.Simple.Utils: findFileCwdWithExtension :: forall searchDir allowAbsolute. Maybe (SymbolicPath CWD (Dir Pkg)) -> [Suffix] -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)] -> RelativePath searchDir File -> IO (Maybe (SymbolicPathX allowAbsolute Pkg File))
- Distribution.Simple.Utils: findFileEx :: Verbosity -> [FilePath] -> FilePath -> IO FilePath
+ Distribution.Simple.Utils: findFileEx :: forall searchDir allowAbsolute. Verbosity -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)] -> RelativePath searchDir File -> IO (SymbolicPathX allowAbsolute Pkg File)
- Distribution.Simple.Utils: findFileWithExtension :: [Suffix] -> [FilePath] -> FilePath -> IO (Maybe FilePath)
+ Distribution.Simple.Utils: findFileWithExtension :: [Suffix] -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)] -> RelativePath searchDir File -> IO (Maybe (SymbolicPathX allowAbsolute Pkg File))
- Distribution.Simple.Utils: findFileWithExtension' :: [Suffix] -> [FilePath] -> FilePath -> IO (Maybe (FilePath, FilePath))
+ Distribution.Simple.Utils: findFileWithExtension' :: [Suffix] -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)] -> RelativePath searchDir File -> IO (Maybe (SymbolicPathX allowAbsolute Pkg (Dir searchDir), RelativePath searchDir File))
- Distribution.Simple.Utils: findHookedPackageDesc :: Verbosity -> FilePath -> IO (Maybe FilePath)
+ Distribution.Simple.Utils: findHookedPackageDesc :: Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> SymbolicPath Pkg (Dir Build) -> IO (Maybe (SymbolicPath Pkg File))
- Distribution.Simple.Utils: findModuleFileEx :: Verbosity -> [FilePath] -> [Suffix] -> ModuleName -> IO (FilePath, FilePath)
+ Distribution.Simple.Utils: findModuleFileEx :: forall searchDir allowAbsolute. Verbosity -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)] -> [Suffix] -> ModuleName -> IO (SymbolicPathX allowAbsolute Pkg (Dir searchDir), RelativePath searchDir File)
- Distribution.Simple.Utils: findModuleFilesEx :: Verbosity -> [FilePath] -> [Suffix] -> [ModuleName] -> IO [(FilePath, FilePath)]
+ Distribution.Simple.Utils: findModuleFilesEx :: forall searchDir allowAbsolute. Verbosity -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)] -> [Suffix] -> [ModuleName] -> IO [(SymbolicPathX allowAbsolute Pkg (Dir searchDir), RelativePath searchDir File)]
- Distribution.Simple.Utils: findPackageDesc :: FilePath -> IO (Either CabalException FilePath)
+ Distribution.Simple.Utils: findPackageDesc :: Maybe (SymbolicPath CWD (Dir Pkg)) -> IO (Either CabalException (RelativePath Pkg File))
- Distribution.Simple.Utils: rawSystemExit :: Verbosity -> FilePath -> [String] -> IO ()
+ Distribution.Simple.Utils: rawSystemExit :: Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> FilePath -> [String] -> IO ()
- Distribution.Simple.Utils: rawSystemExitCode :: Verbosity -> FilePath -> [String] -> IO ExitCode
+ Distribution.Simple.Utils: rawSystemExitCode :: Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> FilePath -> [String] -> Maybe [(String, String)] -> IO ExitCode
- Distribution.Simple.Utils: tryFindPackageDesc :: Verbosity -> FilePath -> IO FilePath
+ Distribution.Simple.Utils: tryFindPackageDesc :: Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> IO (RelativePath Pkg File)
- Distribution.Simple.Utils: withTempFileEx :: TempFileOptions -> FilePath -> String -> (FilePath -> Handle -> IO a) -> IO a
+ Distribution.Simple.Utils: withTempFileEx :: forall a tmpDir. TempFileOptions -> Maybe (SymbolicPath CWD (Dir Pkg)) -> SymbolicPath Pkg (Dir tmpDir) -> String -> (SymbolicPath Pkg File -> Handle -> IO a) -> IO a
- Distribution.Types.LocalBuildConfig: BuildOptions :: Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> ProfDetailLevel -> ProfDetailLevel -> OptimisationLevel -> DebugInfoLevel -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> BuildOptions
+ Distribution.Types.LocalBuildConfig: BuildOptions :: Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> ProfDetailLevel -> ProfDetailLevel -> OptimisationLevel -> DebugInfoLevel -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> BuildOptions
- Distribution.Types.LocalBuildConfig: ComponentBuildDescr :: Graph ComponentLocalBuildInfo -> Map ComponentName [ComponentLocalBuildInfo] -> Map (PackageName, ComponentName) ComponentId -> InstalledPackageIndex -> ComponentBuildDescr
+ Distribution.Types.LocalBuildConfig: ComponentBuildDescr :: Graph ComponentLocalBuildInfo -> Map ComponentName [ComponentLocalBuildInfo] -> Map (PackageName, ComponentName) PromisedComponent -> InstalledPackageIndex -> ComponentBuildDescr
- Distribution.Types.LocalBuildConfig: PackageBuildDescr :: ConfigFlags -> FlagAssignment -> ComponentRequestedSpec -> Compiler -> Platform -> Maybe FilePath -> PackageDescription -> InstallDirTemplates -> PackageDBStack -> [UnitId] -> PackageBuildDescr
+ Distribution.Types.LocalBuildConfig: PackageBuildDescr :: ConfigFlags -> FlagAssignment -> ComponentRequestedSpec -> Compiler -> Platform -> Maybe (SymbolicPath Pkg File) -> PackageDescription -> InstallDirTemplates -> PackageDBStack -> [UnitId] -> PackageBuildDescr
- Distribution.Types.LocalBuildConfig: [$sel:pkgDescrFile:PackageBuildDescr] :: PackageBuildDescr -> Maybe FilePath
+ Distribution.Types.LocalBuildConfig: [$sel:pkgDescrFile:PackageBuildDescr] :: PackageBuildDescr -> Maybe (SymbolicPath Pkg File)
- Distribution.Types.LocalBuildConfig: [$sel:promisedPkgs:ComponentBuildDescr] :: ComponentBuildDescr -> Map (PackageName, ComponentName) ComponentId
+ Distribution.Types.LocalBuildConfig: [$sel:promisedPkgs:ComponentBuildDescr] :: ComponentBuildDescr -> Map (PackageName, ComponentName) PromisedComponent
- Distribution.Types.LocalBuildInfo: buildDir :: LocalBuildInfo -> FilePath
+ Distribution.Types.LocalBuildInfo: buildDir :: LocalBuildInfo -> SymbolicPath Pkg (Dir Build)
- Distribution.Types.LocalBuildInfo: buildDirPBD :: PackageBuildDescr -> FilePath
+ Distribution.Types.LocalBuildInfo: buildDirPBD :: PackageBuildDescr -> SymbolicPath Pkg (Dir Build)
- Distribution.Types.LocalBuildInfo: pattern LocalBuildInfo :: ConfigFlags -> FlagAssignment -> ComponentRequestedSpec -> [String] -> InstallDirTemplates -> Compiler -> Platform -> Maybe FilePath -> Graph ComponentLocalBuildInfo -> Map ComponentName [ComponentLocalBuildInfo] -> Map (PackageName, ComponentName) ComponentId -> InstalledPackageIndex -> PackageDescription -> ProgramDb -> PackageDBStack -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> ProfDetailLevel -> ProfDetailLevel -> OptimisationLevel -> DebugInfoLevel -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> [UnitId] -> Bool -> LocalBuildInfo
+ Distribution.Types.LocalBuildInfo: pattern LocalBuildInfo :: ConfigFlags -> FlagAssignment -> ComponentRequestedSpec -> [String] -> InstallDirTemplates -> Compiler -> Platform -> Maybe (SymbolicPath Pkg File) -> Graph ComponentLocalBuildInfo -> Map ComponentName [ComponentLocalBuildInfo] -> Map (PackageName, ComponentName) PromisedComponent -> InstalledPackageIndex -> PackageDescription -> ProgramDb -> PackageDBStack -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> ProfDetailLevel -> ProfDetailLevel -> OptimisationLevel -> DebugInfoLevel -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> Bool -> [UnitId] -> Bool -> LocalBuildInfo
Files
- Cabal.cabal +15/−8
- ChangeLog.md +4/−0
- src/Distribution/Backpack/Configure.hs +4/−4
- src/Distribution/Backpack/PreExistingComponent.hs +3/−3
- src/Distribution/Compat/Async.hs +2/−8
- src/Distribution/Compat/Internal/TempFile.hs +3/−2
- src/Distribution/Compat/ResponseFile.hs +3/−51
- src/Distribution/Compat/Stack.hs +7/−67
- src/Distribution/Compat/Time.hs +4/−13
- src/Distribution/Make.hs +32/−18
- src/Distribution/PackageDescription/Check.hs +39/−22
- src/Distribution/PackageDescription/Check/Target.hs +30/−28
- src/Distribution/PackageDescription/Check/Warning.hs +14/−10
- src/Distribution/Simple.hs +466/−238
- src/Distribution/Simple/Bench.hs +51/−11
- src/Distribution/Simple/Build.hs +310/−178
- src/Distribution/Simple/Build/Inputs.hs +5/−1
- src/Distribution/Simple/BuildPaths.hs +198/−36
- src/Distribution/Simple/BuildTarget.hs +8/−7
- src/Distribution/Simple/BuildWay.hs +14/−0
- src/Distribution/Simple/Command.hs +13/−0
- src/Distribution/Simple/Compiler.hs +121/−15
- src/Distribution/Simple/Configure.hs +448/−223
- src/Distribution/Simple/ConfigureScript.hs +38/−30
- src/Distribution/Simple/Errors.hs +44/−43
- src/Distribution/Simple/FileMonitor/Types.hs +217/−0
- src/Distribution/Simple/GHC.hs +206/−119
- src/Distribution/Simple/GHC/Build.hs +56/−58
- src/Distribution/Simple/GHC/Build/ExtraSources.hs +143/−125
- src/Distribution/Simple/GHC/Build/Link.hs +262/−159
- src/Distribution/Simple/GHC/Build/Modules.hs +135/−76
- src/Distribution/Simple/GHC/Build/Utils.hs +45/−16
- src/Distribution/Simple/GHC/EnvironmentParser.hs +3/−5
- src/Distribution/Simple/GHC/Internal.hs +69/−107
- src/Distribution/Simple/GHCJS.hs +133/−87
- src/Distribution/Simple/Glob.hs +418/−41
- src/Distribution/Simple/Glob/Internal.hs +2/−366
- src/Distribution/Simple/Haddock.hs +1614/−1224
- src/Distribution/Simple/HaskellSuite.hs +16/−13
- src/Distribution/Simple/Hpc.hs +35/−26
- src/Distribution/Simple/Install.hs +123/−59
- src/Distribution/Simple/InstallDirs.hs +2/−0
- src/Distribution/Simple/LocalBuildInfo.hs +59/−22
- src/Distribution/Simple/PackageDescription.hs +30/−10
- src/Distribution/Simple/PreProcess.hs +142/−114
- src/Distribution/Simple/PreProcess/Types.hs +18/−5
- src/Distribution/Simple/Program.hs +64/−4
- src/Distribution/Simple/Program/Ar.hs +36/−27
- src/Distribution/Simple/Program/Builtin.hs +2/−10
- src/Distribution/Simple/Program/Db.hs +64/−17
- src/Distribution/Simple/Program/Find.hs +14/−0
- src/Distribution/Simple/Program/GHC.hs +59/−39
- src/Distribution/Simple/Program/HcPkg.hs +112/−57
- src/Distribution/Simple/Program/Hpc.hs +34/−30
- src/Distribution/Simple/Program/Ld.hs +40/−34
- src/Distribution/Simple/Program/ResponseFile.hs +15/−6
- src/Distribution/Simple/Program/Run.hs +25/−3
- src/Distribution/Simple/Program/Types.hs +1/−1
- src/Distribution/Simple/Register.hs +93/−77
- src/Distribution/Simple/Setup.hs +31/−15
- src/Distribution/Simple/Setup/Benchmark.hs +74/−45
- src/Distribution/Simple/Setup/Build.hs +59/−36
- src/Distribution/Simple/Setup/Clean.hs +54/−24
- src/Distribution/Simple/Setup/Common.hs +108/−9
- src/Distribution/Simple/Setup/Config.hs +145/−92
- src/Distribution/Simple/Setup/Copy.hs +76/−51
- src/Distribution/Simple/Setup/Global.hs +11/−0
- src/Distribution/Simple/Setup/Haddock.hs +254/−197
- src/Distribution/Simple/Setup/Hscolour.hs +103/−75
- src/Distribution/Simple/Setup/Install.hs +58/−29
- src/Distribution/Simple/Setup/Register.hs +126/−100
- src/Distribution/Simple/Setup/Repl.hs +69/−37
- src/Distribution/Simple/Setup/SDist.hs +70/−38
- src/Distribution/Simple/Setup/Test.hs +150/−117
- src/Distribution/Simple/SetupHooks/Errors.hs +231/−0
- src/Distribution/Simple/SetupHooks/Internal.hs +1096/−0
- src/Distribution/Simple/SetupHooks/Rule.hs +1142/−0
- src/Distribution/Simple/ShowBuildInfo.hs +16/−13
- src/Distribution/Simple/SrcDist.hs +107/−71
- src/Distribution/Simple/Test.hs +32/−19
- src/Distribution/Simple/Test/ExeV10.hs +26/−20
- src/Distribution/Simple/Test/LibV09.hs +30/−25
- src/Distribution/Simple/UHC.hs +37/−24
- src/Distribution/Simple/UserHooks.hs +1/−1
- src/Distribution/Simple/Utils.hs +329/−163
- src/Distribution/Types/GivenComponent.hs +19/−0
- src/Distribution/Types/LocalBuildConfig.hs +9/−4
- src/Distribution/Types/LocalBuildInfo.hs +82/−15
Cabal.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: Cabal-version: 3.12.1.0+version: 3.14.0.0 copyright: 2003-2024, Cabal Development Team (see AUTHORS file) license: BSD-3-Clause license-file: LICENSE@@ -34,9 +34,9 @@ hs-source-dirs: src build-depends:- Cabal-syntax ^>= 3.12.1.0,+ Cabal-syntax ^>= 3.14, array >= 0.4.0.1 && < 0.6,- base >= 4.11 && < 5,+ base >= 4.13 && < 5, bytestring >= 0.10.0.0 && < 0.13, containers >= 0.5.0.0 && < 0.8, deepseq >= 1.3.0.1 && < 1.6,@@ -51,7 +51,13 @@ else build-depends: unix >= 2.6.0.0 && < 2.9 - ghc-options: -Wall -fno-ignore-asserts -fwarn-tabs -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates+ ghc-options:+ -Wall+ -fno-ignore-asserts+ -fwarn-tabs+ -fwarn-incomplete-uni-patterns+ -fwarn-incomplete-record-updates+ -fno-warn-unticked-promoted-constructors if impl(ghc >= 8.0) ghc-options: -Wcompat -Wnoncanonical-monad-instances@@ -59,9 +65,6 @@ if impl(ghc >= 8.0) && impl(ghc < 8.8) ghc-options: -Wnoncanonical-monadfail-instances - if impl(ghc >= 8.10)- ghc-options: -Wunused-packages- exposed-modules: Distribution.Backpack.Configure Distribution.Backpack.ComponentsGraph@@ -98,11 +101,13 @@ Distribution.Simple.BuildPaths Distribution.Simple.BuildTarget Distribution.Simple.BuildToolDepends+ Distribution.Simple.BuildWay Distribution.Simple.CCompiler Distribution.Simple.Command Distribution.Simple.Compiler Distribution.Simple.Configure Distribution.Simple.Errors+ Distribution.Simple.FileMonitor.Types Distribution.Simple.Flag Distribution.Simple.GHC Distribution.Simple.GHCJS@@ -145,6 +150,9 @@ Distribution.Simple.Test.Log Distribution.Simple.UHC Distribution.Simple.UserHooks+ Distribution.Simple.SetupHooks.Errors+ Distribution.Simple.SetupHooks.Internal+ Distribution.Simple.SetupHooks.Rule Distribution.Simple.Utils Distribution.TestSuite Distribution.Types.AnnotatedId@@ -181,7 +189,6 @@ Distribution.Compat.Parsing, Distribution.Compat.Prelude, Distribution.Compat.Semigroup,- Distribution.Compat.Typeable, Distribution.Compiler, Distribution.FieldGrammar, Distribution.FieldGrammar.Class,
ChangeLog.md view
@@ -1,7 +1,11 @@+# 3.14.0.0 [Hécate](mailto:hecate+github@glitchbra.in) September 2024+* See https://github.com/haskell/cabal/blob/master/release-notes/Cabal-3.14.0.0.md+ # 3.12.1.0 [Artem Pelenitsyn](mailto:a.pelenitsyn@gmail.com) June 2024 * See https://github.com/haskell/cabal/blob/master/release-notes/Cabal-3.12.1.0.md # 3.12.0.0 [Francesco Ariis](mailto:fa-ml@ariis.it) May 2024+# 3.12.0.0 [Francesco Ariis](mailto:fa-ml@ariis.it) March 2024 * See https://github.com/haskell/cabal/blob/master/release-notes/Cabal-3.12.0.0.md # 3.10.3.0 [Hécate](mailto:hecate+github@glitchbra.in) January 2024
src/Distribution/Backpack/Configure.hs view
@@ -70,7 +70,7 @@ -> Flag String -- configIPID -> Flag ComponentId -- configCID -> PackageDescription- -> ([PreExistingComponent], [PromisedComponent])+ -> ([PreExistingComponent], [ConfiguredPromisedComponent]) -> FlagAssignment -- configConfigurationsFlags -> [(ModuleName, Module)] -- configInstantiateWith -> InstalledPackageIndex@@ -118,7 +118,7 @@ `Map.union` Map.fromListWith Map.union [ (pkg, Map.singleton (ann_cname aid) aid)- | PromisedComponent pkg aid <- promisedPkgDeps+ | ConfiguredPromisedComponent pkg aid <- promisedPkgDeps ] graph1 <- toConfiguredComponents@@ -151,7 +151,7 @@ , emptyModuleShape ) )- | PromisedComponent _ aid <- promisedPkgDeps+ | ConfiguredPromisedComponent _ aid <- promisedPkgDeps ] uid_lookup def_uid | Just pkg <- PackageIndex.lookupUnitId installedPackageSet uid =@@ -208,7 +208,7 @@ toComponentLocalBuildInfos :: Compiler -> InstalledPackageIndex -- FULL set- -> [PromisedComponent]+ -> [ConfiguredPromisedComponent] -> PackageDescription -> [PreExistingComponent] -- external package deps -> [ReadyComponent]
src/Distribution/Backpack/PreExistingComponent.hs view
@@ -1,7 +1,7 @@ -- | See <https://github.com/ezyang/ghc-proposals/blob/backpack/proposals/0000-backpack.rst> module Distribution.Backpack.PreExistingComponent ( PreExistingComponent (..)- , PromisedComponent (..)+ , ConfiguredPromisedComponent (..) , ipiToPreExistingComponent ) where @@ -24,12 +24,12 @@ -- These components are promised to @configure@ but are not yet built. -- -- In other words this is 'PreExistingComponent' which doesn't yet exist.-data PromisedComponent = PromisedComponent+data ConfiguredPromisedComponent = ConfiguredPromisedComponent { pr_pkgname :: PackageName , pr_cid :: AnnotatedId ComponentId } -instance Package PromisedComponent where+instance Package ConfiguredPromisedComponent where packageId = packageId . pr_cid -- | Stripped down version of 'LinkedComponent' for things
src/Distribution/Compat/Async.hs view
@@ -29,6 +29,8 @@ ( BlockedIndefinitelyOnMVar (..) , Exception (..) , SomeException (..)+ , asyncExceptionFromException+ , asyncExceptionToException , catch , evaluate , mask@@ -41,10 +43,6 @@ import Data.Typeable (Typeable) import GHC.Exts (inline) -#if MIN_VERSION_base(4,7,0)-import Control.Exception (asyncExceptionFromException, asyncExceptionToException)-#endif- -- | Async, but based on 'MVar', as we don't depend on @stm@. data AsyncM a = Async { asyncThreadId :: {-# UNPACK #-} !ThreadId@@ -148,15 +146,11 @@ , Typeable ) -{- FOURMOLU_DISABLE -} instance Exception AsyncCancelled where-#if MIN_VERSION_base(4,7,0) -- wraps in SomeAsyncException -- See https://github.com/ghc/ghc/commit/756a970eacbb6a19230ee3ba57e24999e4157b09 fromException = asyncExceptionFromException toException = asyncExceptionToException-#endif-{- FOURMOLU_ENABLE -} -- | Cancel an asynchronous action --
src/Distribution/Compat/Internal/TempFile.hs view
@@ -126,10 +126,11 @@ findTempName pid where findTempName x = do- let dirpath = dir </> template ++ "-" ++ show x+ let relpath = template ++ "-" ++ show x+ dirpath = dir </> relpath r <- tryIO $ mkPrivateDir dirpath case r of- Right _ -> return dirpath+ Right _ -> return relpath Left e | isAlreadyExistsError e -> findTempName (x + 1) | otherwise -> ioError e
src/Distribution/Compat/ResponseFile.hs view
@@ -8,62 +8,14 @@ module Distribution.Compat.ResponseFile (expandResponse, escapeArgs) where import Distribution.Compat.Prelude++import GHC.ResponseFile (escapeArgs, unescapeArgs)+ import Prelude () import System.FilePath import System.IO (hPutStrLn, stderr) import System.IO.Error--#if MIN_VERSION_base(4,12,0)-import GHC.ResponseFile (unescapeArgs, escapeArgs)-#else--unescapeArgs :: String -> [String]-unescapeArgs = filter (not . null) . unescape--data Quoting = NoneQ | SngQ | DblQ--unescape :: String -> [String]-unescape args = reverse . map reverse $ go args NoneQ False [] []- where- -- n.b., the order of these cases matters; these are cribbed from gcc- -- case 1: end of input- go [] _q _bs a as = a:as- -- case 2: back-slash escape in progress- go (c:cs) q True a as = go cs q False (c:a) as- -- case 3: no back-slash escape in progress, but got a back-slash- go (c:cs) q False a as- | '\\' == c = go cs q True a as- -- case 4: single-quote escaping in progress- go (c:cs) SngQ False a as- | '\'' == c = go cs NoneQ False a as- | otherwise = go cs SngQ False (c:a) as- -- case 5: double-quote escaping in progress- go (c:cs) DblQ False a as- | '"' == c = go cs NoneQ False a as- | otherwise = go cs DblQ False (c:a) as- -- case 6: no escaping is in progress- go (c:cs) NoneQ False a as- | isSpace c = go cs NoneQ False [] (a:as)- | '\'' == c = go cs SngQ False a as- | '"' == c = go cs DblQ False a as- | otherwise = go cs NoneQ False (c:a) as--escapeArgs :: [String] -> String-escapeArgs = unlines . map escapeArg--escapeArg :: String -> String-escapeArg = reverse . foldl' escape []--escape :: String -> Char -> String-escape cs c- | isSpace c- || '\\' == c- || '\'' == c- || '"' == c = c:'\\':cs -- n.b., our caller must reverse the result- | otherwise = c:cs--#endif -- | The arg file / response file parser. --
src/Distribution/Compat/Stack.hs view
@@ -13,91 +13,31 @@ , parentSrcLocPrefix ) where -import System.IO.Error--#ifdef MIN_VERSION_base-#if MIN_VERSION_base(4,8,1)-#define GHC_STACK_SUPPORTED 1-#endif-#endif--#ifdef GHC_STACK_SUPPORTED import GHC.Stack-#endif--#ifdef GHC_STACK_SUPPORTED+import System.IO.Error -#if MIN_VERSION_base(4,9,0) type WithCallStack a = HasCallStack => a-#elif MIN_VERSION_base(4,8,1)-type WithCallStack a = (?callStack :: CallStack) => a-#endif -#if !MIN_VERSION_base(4,9,0)--- NB: Can't say WithCallStack (WithCallStack a -> a);--- Haskell doesn't support this kind of implicit parameter!--- See https://mail.haskell.org/pipermail/ghc-devs/2016-January/011096.html--- Since this function doesn't do anything, it's OK to--- give it a less good type.-withFrozenCallStack :: WithCallStack (a -> a)-withFrozenCallStack x = x--callStack :: (?callStack :: CallStack) => CallStack-callStack = ?callStack--prettyCallStack :: CallStack -> String-prettyCallStack = showCallStack-#endif- -- | Give the *parent* of the person who invoked this; -- so it's most suitable for being called from a utility function. -- You probably want to call this using 'withFrozenCallStack'; otherwise -- it's not very useful. We didn't implement this for base-4.8.1 -- because we cannot rely on freezing to have taken place.--- parentSrcLocPrefix :: WithCallStack String-#if MIN_VERSION_base(4,9,0) parentSrcLocPrefix = case getCallStack callStack of- (_:(_, loc):_) -> showLoc loc+ (_ : (_, loc) : _) -> showLoc loc [(_, loc)] -> showLoc loc [] -> error "parentSrcLocPrefix: empty call stack"- where- showLoc loc =- srcLocFile loc ++ ":" ++ show (srcLocStartLine loc) ++ ": "-#else-parentSrcLocPrefix = "Call sites not available with base < 4.9.0.0 (GHC 8.0): "-#endif+ where+ showLoc loc =+ srcLocFile loc ++ ":" ++ show (srcLocStartLine loc) ++ ": " -- Yeah, this uses skivvy implementation details. withLexicalCallStack :: (a -> WithCallStack (IO b)) -> WithCallStack (a -> IO b) withLexicalCallStack f =- let stk = ?callStack- in \x -> let ?callStack = stk in f x--#else--data CallStack = CallStack- deriving (Eq, Show)--type WithCallStack a = a--withFrozenCallStack :: a -> a-withFrozenCallStack x = x--callStack :: CallStack-callStack = CallStack--prettyCallStack :: CallStack -> String-prettyCallStack _ = "Call stacks not available with base < 4.8.1.0 (GHC 7.10)"--parentSrcLocPrefix :: String-parentSrcLocPrefix = "Call sites not available with base < 4.9.0.0 (GHC 8.0): "--withLexicalCallStack :: (a -> IO b) -> a -> IO b-withLexicalCallStack f = f--#endif+ let stk = ?callStack+ in \x -> let ?callStack = stk in f x -- | This function is for when you *really* want to add a call -- stack to raised IO, but you don't have a
src/Distribution/Compat/Time.hs view
@@ -21,7 +21,8 @@ import System.Directory (getModificationTime) -import Distribution.Simple.Utils (withTempDirectory)+import Distribution.Simple.Utils (withTempDirectoryCwd)+import Distribution.Utils.Path (getSymbolicPath, sameDirectory) import Distribution.Verbosity (silent) import System.FilePath@@ -33,11 +34,7 @@ import qualified Prelude import Data.Bits ((.|.), unsafeShiftL)-#if MIN_VERSION_base(4,7,0) import Data.Bits (finiteBitSize)-#else-import Data.Bits (bitSize)-#endif import Foreign ( allocaBytes, peekByteOff ) import System.IO.Error ( mkIOError, doesNotExistErrorType )@@ -91,15 +88,9 @@ index_WIN32_FILE_ATTRIBUTE_DATA_ftLastWriteTime_dwLowDateTime dwHigh <- peekByteOff info index_WIN32_FILE_ATTRIBUTE_DATA_ftLastWriteTime_dwHighDateTime-#if MIN_VERSION_base(4,7,0) let qwTime = (fromIntegral (dwHigh :: DWORD) `unsafeShiftL` finiteBitSize dwHigh) .|. (fromIntegral (dwLow :: DWORD))-#else- let qwTime =- (fromIntegral (dwHigh :: DWORD) `unsafeShiftL` bitSize dwHigh)- .|. (fromIntegral (dwLow :: DWORD))-#endif return $! ModTime (qwTime :: Word64) {- FOURMOLU_DISABLE -}@@ -177,8 +168,8 @@ -- than 10 ms, but never larger than 1 second. calibrateMtimeChangeDelay :: IO (Int, Int) calibrateMtimeChangeDelay =- withTempDirectory silent "." "calibration-" $ \dir -> do- let fileName = dir </> "probe"+ withTempDirectoryCwd silent Nothing sameDirectory "calibration-" $ \dir -> do+ let fileName = getSymbolicPath dir </> "probe" mtimes <- for [1 .. 25] $ \(i :: Int) -> time $ do writeFile fileName $ show i t0 <- getModTime fileName
src/Distribution/Make.hs view
@@ -68,15 +68,13 @@ import Prelude () -- local+import Distribution.License import Distribution.Package+import Distribution.Pretty import Distribution.Simple.Command import Distribution.Simple.Program import Distribution.Simple.Setup- import Distribution.Simple.Utils--import Distribution.License-import Distribution.Pretty import Distribution.Version import System.Environment (getArgs, getProgName)@@ -114,7 +112,6 @@ putStrLn $ "Cabal library version " ++ prettyShow cabalVersion- progs = defaultProgramDb commands = [ configureCommand progs `commandAddAction` configureAction@@ -131,8 +128,9 @@ configureAction :: ConfigFlags -> [String] -> IO () configureAction flags args = do noExtraFlags args- let verbosity = fromFlag (configVerbosity flags)- rawSystemExit verbosity "sh" $+ let verbosity = fromFlag $ configVerbosity flags+ mbWorkDir = flagToMaybe $ configWorkingDir flags+ rawSystemExit verbosity mbWorkDir "sh" $ "configure" : configureArgs backwardsCompatHack flags where@@ -141,47 +139,63 @@ copyAction :: CopyFlags -> [String] -> IO () copyAction flags args = do noExtraFlags args- let destArgs = case fromFlag $ copyDest flags of+ let verbosity = fromFlag $ copyVerbosity flags+ mbWorkDir = flagToMaybe $ copyWorkingDir flags+ destArgs = case fromFlag $ copyDest flags of NoCopyDest -> ["install"] CopyTo path -> ["copy", "destdir=" ++ path] CopyToDb _ -> error "CopyToDb not supported via Make" - rawSystemExit (fromFlag $ copyVerbosity flags) "make" destArgs+ rawSystemExit verbosity mbWorkDir "make" destArgs installAction :: InstallFlags -> [String] -> IO () installAction flags args = do noExtraFlags args- rawSystemExit (fromFlag $ installVerbosity flags) "make" ["install"]- rawSystemExit (fromFlag $ installVerbosity flags) "make" ["register"]+ let verbosity = fromFlag $ installVerbosity flags+ mbWorkDir = flagToMaybe $ installWorkingDir flags+ rawSystemExit verbosity mbWorkDir "make" ["install"]+ rawSystemExit verbosity mbWorkDir "make" ["register"] haddockAction :: HaddockFlags -> [String] -> IO () haddockAction flags args = do noExtraFlags args- rawSystemExit (fromFlag $ haddockVerbosity flags) "make" ["docs"]+ let verbosity = fromFlag $ haddockVerbosity flags+ mbWorkDir = flagToMaybe $ haddockWorkingDir flags+ rawSystemExit verbosity mbWorkDir "make" ["docs"] `catchIO` \_ ->- rawSystemExit (fromFlag $ haddockVerbosity flags) "make" ["doc"]+ rawSystemExit verbosity mbWorkDir "make" ["doc"] buildAction :: BuildFlags -> [String] -> IO () buildAction flags args = do noExtraFlags args- rawSystemExit (fromFlag $ buildVerbosity flags) "make" []+ let verbosity = fromFlag $ buildVerbosity flags+ mbWorkDir = flagToMaybe $ buildWorkingDir flags+ rawSystemExit verbosity mbWorkDir "make" [] cleanAction :: CleanFlags -> [String] -> IO () cleanAction flags args = do noExtraFlags args- rawSystemExit (fromFlag $ cleanVerbosity flags) "make" ["clean"]+ let verbosity = fromFlag $ cleanVerbosity flags+ mbWorkDir = flagToMaybe $ cleanWorkingDir flags+ rawSystemExit verbosity mbWorkDir "make" ["clean"] sdistAction :: SDistFlags -> [String] -> IO () sdistAction flags args = do noExtraFlags args- rawSystemExit (fromFlag $ sDistVerbosity flags) "make" ["dist"]+ let verbosity = fromFlag $ sDistVerbosity flags+ mbWorkDir = flagToMaybe $ sDistWorkingDir flags+ rawSystemExit verbosity mbWorkDir "make" ["dist"] registerAction :: RegisterFlags -> [String] -> IO () registerAction flags args = do noExtraFlags args- rawSystemExit (fromFlag $ regVerbosity flags) "make" ["register"]+ let verbosity = fromFlag $ registerVerbosity flags+ mbWorkDir = flagToMaybe $ registerWorkingDir flags+ rawSystemExit verbosity mbWorkDir "make" ["register"] unregisterAction :: RegisterFlags -> [String] -> IO () unregisterAction flags args = do noExtraFlags args- rawSystemExit (fromFlag $ regVerbosity flags) "make" ["unregister"]+ let verbosity = fromFlag $ registerVerbosity flags+ mbWorkDir = flagToMaybe $ registerWorkingDir flags+ rawSystemExit verbosity mbWorkDir "make" ["unregister"]
src/Distribution/PackageDescription/Check.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE ScopedTypeVariables #-} -- |@@ -70,14 +71,9 @@ import Distribution.Simple.Utils hiding (findPackageDesc, notice) import Distribution.Utils.Generic (isAscii) import Distribution.Utils.Path- ( LicenseFile- , PackageDir- , SymbolicPath- , getSymbolicPath- ) import Distribution.Verbosity import Distribution.Version-import System.FilePath (splitExtension, takeFileName, (<.>), (</>))+import System.FilePath (splitExtension, takeFileName) import qualified Data.ByteString.Lazy as BS import qualified Distribution.SPDX as SPDX@@ -185,6 +181,7 @@ , getDirectoryContentsM = System.Directory.getDirectoryContents . relative } + relative :: FilePath -> FilePath relative path = root </> path -- | Same as 'checkPackageFilesGPD', but working with 'PackageDescription'.@@ -412,6 +409,7 @@ extraSrcFiles_ extraTmpFiles_ extraDocFiles_+ extraFiles_ ) = do -- § Sanity checks. checkPackageId package_@@ -456,26 +454,30 @@ (PackageDistSuspicious ShortDesc) -- § Paths.- mapM_ (checkPath False "extra-source-files" PathKindGlob) extraSrcFiles_- mapM_ (checkPath False "extra-tmp-files" PathKindFile) extraTmpFiles_- mapM_ (checkPath False "extra-doc-files" PathKindGlob) extraDocFiles_- mapM_ (checkPath False "data-files" PathKindGlob) dataFiles_- checkPath True "data-dir" PathKindDirectory dataDir_+ mapM_ (checkPath False "extra-source-files" PathKindGlob . getSymbolicPath) extraSrcFiles_+ mapM_ (checkPath False "extra-tmp-files" PathKindFile . getSymbolicPath) extraTmpFiles_+ mapM_ (checkPath False "extra-doc-files" PathKindGlob . getSymbolicPath) extraDocFiles_+ mapM_ (checkPath False "extra-files" PathKindGlob . getSymbolicPath) extraFiles_+ mapM_ (checkPath False "data-files" PathKindGlob . getSymbolicPath) dataFiles_+ let rawDataDir = getSymbolicPath dataDir_+ checkPath True "data-dir" PathKindDirectory rawDataDir let licPaths = map getSymbolicPath licenseFiles_ mapM_ (checkPath False "license-file" PathKindFile) licPaths mapM_ checkLicFileExist licenseFiles_ -- § Globs.- dataGlobs <- mapM (checkGlob "data-files") dataFiles_- extraGlobs <- mapM (checkGlob "extra-source-files") extraSrcFiles_- docGlobs <- mapM (checkGlob "extra-doc-files") extraDocFiles_+ dataGlobs <- mapM (checkGlob "data-files" . getSymbolicPath) dataFiles_+ extraSrcGlobs <- mapM (checkGlob "extra-source-files" . getSymbolicPath) extraSrcFiles_+ docGlobs <- mapM (checkGlob "extra-doc-files" . getSymbolicPath) extraDocFiles_+ extraGlobs <- mapM (checkGlob "extra-files" . getSymbolicPath) extraFiles_ -- We collect globs to feed them to checkMissingDocs. -- § Missing documentation. checkMissingDocs (catMaybes dataGlobs)- (catMaybes extraGlobs)+ (catMaybes extraSrcGlobs) (catMaybes docGlobs)+ (catMaybes extraGlobs) -- § Datafield checks. checkSetupBuildInfo setupBuildInfo_@@ -512,16 +514,17 @@ (isNothing buildTypeRaw_ && specVersion_ < CabalSpecV2_2) (PackageBuildWarning NoBuildType) checkP- (isJust setupBuildInfo_ && buildType pkg /= Custom)+ (isJust setupBuildInfo_ && buildType pkg `notElem` [Custom, Hooks]) (PackageBuildWarning NoCustomSetup) -- Contents. checkConfigureExists (buildType pkg) checkSetupExists (buildType pkg) checkCabalFile (packageName pkg)- mapM_ (checkGlobFile specVersion_ "." "extra-source-files") extraSrcFiles_- mapM_ (checkGlobFile specVersion_ "." "extra-doc-files") extraDocFiles_- mapM_ (checkGlobFile specVersion_ dataDir_ "data-files") dataFiles_+ mapM_ (checkGlobFile specVersion_ "." "extra-source-files" . getSymbolicPath) extraSrcFiles_+ mapM_ (checkGlobFile specVersion_ "." "extra-doc-files" . getSymbolicPath) extraDocFiles_+ mapM_ (checkGlobFile specVersion_ "." "extra-files" . getSymbolicPath) extraFiles_+ mapM_ (checkGlobFile specVersion_ rawDataDir "data-files" . getSymbolicPath) dataFiles_ where checkNull :: Monad m@@ -681,6 +684,7 @@ checkP (isNothing repoLocation_) (PackageDistInexcusable MissingLocation)+ checkGitProtocol repoLocation_ checkP ( repoType_ == Just (KnownRepoType CVS) && isNothing repoModule_@@ -719,6 +723,17 @@ repoTypeDirname Monotone = ["_MTN"] repoTypeDirname Pijul = [".pijul"] +-- git:// lacks TLS or other encryption, see+-- https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols#_the_cons_4+checkGitProtocol+ :: Monad m+ => Maybe String -- Repository location+ -> CheckM m ()+checkGitProtocol mloc =+ checkP+ (fmap (isPrefixOf "git://") mloc == Just True)+ (PackageBuildWarning GitProtocol)+ -- ------------------------------------------------------------ -- Package and distribution checks -- ------------------------------------------------------------@@ -786,7 +801,7 @@ checkLicFileExist :: Monad m- => SymbolicPath PackageDir LicenseFile+ => RelativePath Pkg File -> CheckM m () checkLicFileExist sp = do let fp = getSymbolicPath sp@@ -987,8 +1002,9 @@ => [Glob] -- data-files globs. -> [Glob] -- extra-source-files globs. -> [Glob] -- extra-doc-files globs.+ -> [Glob] -- extra-files globs. -> CheckM m ()-checkMissingDocs dgs esgs edgs = do+checkMissingDocs dgs esgs edgs efgs = do extraDocSupport <- (>= CabalSpecV1_18) <$> asksCM ccSpecVersion -- Everything in this block uses CheckPreDistributionOps interface.@@ -1007,9 +1023,10 @@ rgs <- realGlob dgs res <- realGlob esgs red <- realGlob edgs+ ref <- realGlob efgs -- 3. Check if anything in 1. is missing in 2.- let mcs = checkDoc extraDocSupport des (rgs ++ res ++ red)+ let mcs = checkDoc extraDocSupport des (rgs ++ res ++ red ++ ref) -- 4. Check if files are present but in the wrong field. let pcsData = checkDocMove extraDocSupport "data-files" des rgs
src/Distribution/PackageDescription/Check/Target.hs view
@@ -86,7 +86,7 @@ checkP ( not $ all- (flip elem (allExplicitIncludes lib))+ (flip elem (allExplicitIncludes lib) . getSymbolicPath) (view L.autogenIncludes lib) ) $ (PackageBuildImpossible AutogenIncludesNotIncluded)@@ -107,8 +107,8 @@ where allExplicitIncludes :: L.HasBuildInfo a => a -> [FilePath] allExplicitIncludes x =- view L.includes x- ++ view L.installIncludes x+ map getSymbolicPath (view L.includes x)+ ++ map getSymbolicPath (view L.installIncludes x) checkForeignLib :: Monad m => ForeignLib -> CheckM m () checkForeignLib@@ -136,12 +136,13 @@ ads exe@( Executable exeName_- modulePath_+ symbolicModulePath_ _exeScope_ buildInfo_ ) = do -- Target type/name (exe). let cet = CETExecutable exeName_+ modulePath_ = getSymbolicPath symbolicModulePath_ -- § Exe specific checks checkP@@ -172,7 +173,7 @@ checkP ( not $ all- (flip elem (view L.includes exe))+ (flip elem (view L.includes exe) . relativeSymbolicPath) (view L.autogenIncludes exe) ) (PackageBuildImpossible AutogenIncludesNotIncludedExe)@@ -217,7 +218,7 @@ checkP ( not $ all- (flip elem (view L.includes ts))+ (flip elem (view L.includes ts) . relativeSymbolicPath) (view L.autogenIncludes ts) ) (PackageBuildImpossible AutogenIncludesNotIncludedExe)@@ -233,12 +234,12 @@ where mainIsWrongExt = case testInterface_ of- TestSuiteExeV10 _ f -> not (fileExtensionSupportedLanguage f)+ TestSuiteExeV10 _ f -> not (fileExtensionSupportedLanguage $ getSymbolicPath f) _ -> False mainIsNotHsExt = case testInterface_ of- TestSuiteExeV10 _ f -> takeExtension f `notElem` [".hs", ".lhs"]+ TestSuiteExeV10 _ f -> takeExtension (getSymbolicPath f) `notElem` [".hs", ".lhs"] _ -> False checkBenchmark@@ -278,7 +279,7 @@ checkP ( not $ all- (flip elem (view L.includes bm))+ (flip elem (view L.includes bm) . relativeSymbolicPath) (view L.autogenIncludes bm) ) (PackageBuildImpossible AutogenIncludesNotIncludedExe)@@ -290,7 +291,7 @@ -- they are different. mainIsWrongExt = case benchmarkInterface_ of- BenchmarkExeV10 _ f -> takeExtension f `notElem` [".hs", ".lhs"]+ BenchmarkExeV10 _ f -> takeExtension (getSymbolicPath f) `notElem` [".hs", ".lhs"] _ -> False -- ------------------------------------------------------------@@ -346,14 +347,14 @@ mapM_ checkCustomField (customFieldsBI bi) -- Content.- mapM_ (checkLocalPathExist "extra-lib-dirs") (extraLibDirs bi)+ mapM_ (checkLocalPathExist "extra-lib-dirs" . getSymbolicPath) (extraLibDirs bi) mapM_- (checkLocalPathExist "extra-lib-dirs-static")+ (checkLocalPathExist "extra-lib-dirs-static" . getSymbolicPath) (extraLibDirsStatic bi) mapM_- (checkLocalPathExist "extra-framework-dirs")+ (checkLocalPathExist "extra-framework-dirs" . getSymbolicPath) (extraFrameworkDirs bi)- mapM_ (checkLocalPathExist "include-dirs") (includeDirs bi)+ mapM_ (checkLocalPathExist "include-dirs" . getSymbolicPath) (includeDirs bi) mapM_ (checkLocalPathExist "hs-source-dirs" . getSymbolicPath) (hsSourceDirs bi)@@ -431,27 +432,27 @@ -- Paths well-formedness check for BuildInfo. checkBuildInfoPathsWellFormedness :: Monad m => BuildInfo -> CheckM m () checkBuildInfoPathsWellFormedness bi = do- mapM_ (checkPath False "asm-sources" PathKindFile) (asmSources bi)- mapM_ (checkPath False "cmm-sources" PathKindFile) (cmmSources bi)- mapM_ (checkPath False "c-sources" PathKindFile) (cSources bi)- mapM_ (checkPath False "cxx-sources" PathKindFile) (cxxSources bi)- mapM_ (checkPath False "js-sources" PathKindFile) (jsSources bi)+ mapM_ (checkPath False "asm-sources" PathKindFile . getSymbolicPath) (asmSources bi)+ mapM_ (checkPath False "cmm-sources" PathKindFile . getSymbolicPath) (cmmSources bi)+ mapM_ (checkPath False "c-sources" PathKindFile . getSymbolicPath) (cSources bi)+ mapM_ (checkPath False "cxx-sources" PathKindFile . getSymbolicPath) (cxxSources bi)+ mapM_ (checkPath False "js-sources" PathKindFile . getSymbolicPath) (jsSources bi) mapM_- (checkPath False "install-includes" PathKindFile)+ (checkPath False "install-includes" PathKindFile . getSymbolicPath) (installIncludes bi) mapM_ (checkPath False "hs-source-dirs" PathKindDirectory . getSymbolicPath) (hsSourceDirs bi) -- Possibly absolute paths.- mapM_ (checkPath True "includes" PathKindFile) (includes bi)+ mapM_ (checkPath True "includes" PathKindFile . getSymbolicPath) (includes bi) mapM_- (checkPath True "include-dirs" PathKindDirectory)+ (checkPath True "include-dirs" PathKindDirectory . getSymbolicPath) (includeDirs bi) mapM_- (checkPath True "extra-lib-dirs" PathKindDirectory)+ (checkPath True "extra-lib-dirs" PathKindDirectory . getSymbolicPath) (extraLibDirs bi) mapM_- (checkPath True "extra-lib-dirs-static" PathKindDirectory)+ (checkPath True "extra-lib-dirs-static" PathKindDirectory . getSymbolicPath) (extraLibDirsStatic bi) mapM_ checkOptionPath (perCompilerFlavorToList $ options bi) where@@ -501,8 +502,8 @@ (PackageBuildWarning CVExtensionsDeprecated) -- asm-sources, cmm-sources and friends only w/ spec ≥ 1.10- checkCVSources (asmSources bi)- checkCVSources (cmmSources bi)+ checkCVSources (map getSymbolicPath $ asmSources bi)+ checkCVSources (map getSymbolicPath $ cmmSources bi) checkCVSources (extraBundledLibs bi) checkCVSources (extraLibFlavours bi) @@ -824,9 +825,10 @@ checkFlags ["-prof"] (PackageBuildWarning $ OptProf title)- -- Does not apply to scripts.- -- Why do we need this? See #8963. pid <- asksCM (pnPackageId . ccNames)+ -- Scripts add the -o flag in the fake-package.cabal in order to have the+ -- executable name match the script name even when there are characters+ -- in the script name which are illegal to have as a target name. unless (pid == fakePackageId) $ checkFlags ["-o"]
src/Distribution/PackageDescription/Check/Warning.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE ScopedTypeVariables #-}@@ -46,12 +47,7 @@ import Distribution.Types.TestType (TestType, knownTestTypes) import Distribution.Types.UnqualComponentName import Distribution.Types.Version (Version)-import Distribution.Utils.Path- ( LicenseFile- , PackageDir- , SymbolicPath- , getSymbolicPath- )+import Distribution.Utils.Path (FileOrDir (..), Pkg, RelativePath, getSymbolicPath) import Language.Haskell.Extension (Extension) import qualified Data.Either as Either@@ -197,6 +193,7 @@ | UnrecognisedSourceRepo String | MissingType | MissingLocation+ | GitProtocol | MissingModule | MissingTag | SubdirRelPath@@ -276,7 +273,7 @@ | NotPackageName FilePath String | NoDesc | MultiDesc [String]- | UnknownFile String (SymbolicPath PackageDir LicenseFile)+ | UnknownFile String (RelativePath Pkg File) | MissingSetupFile | MissingConfigureScript | UnknownDirectory String FilePath@@ -359,6 +356,7 @@ | CIUnrecognisedSourceRepo | CIMissingType | CIMissingLocation+ | CIGitProtocol | CIMissingModule | CIMissingTag | CISubdirRelPath@@ -500,6 +498,7 @@ checkExplanationId (UnrecognisedSourceRepo{}) = CIUnrecognisedSourceRepo checkExplanationId (MissingType{}) = CIMissingType checkExplanationId (MissingLocation{}) = CIMissingLocation+checkExplanationId (GitProtocol{}) = CIGitProtocol checkExplanationId (MissingModule{}) = CIMissingModule checkExplanationId (MissingTag{}) = CIMissingTag checkExplanationId (SubdirRelPath{}) = CISubdirRelPath@@ -646,6 +645,7 @@ ppCheckExplanationId CIUnrecognisedSourceRepo = "unrecognised-repo-type" ppCheckExplanationId CIMissingType = "repo-no-type" ppCheckExplanationId CIMissingLocation = "repo-no-location"+ppCheckExplanationId CIGitProtocol = "git-protocol" ppCheckExplanationId CIMissingModule = "repo-no-module" ppCheckExplanationId CIMissingTag = "repo-no-tag" ppCheckExplanationId CISubdirRelPath = "repo-relative-dir"@@ -968,6 +968,10 @@ "The source-repository 'type' is a required field." ppExplanation MissingLocation = "The source-repository 'location' is a required field."+ppExplanation GitProtocol =+ "Cloning over git:// might lead to an arbitrary code execution "+ ++ "vulnerability. Furthermore, popular forges like GitHub do "+ ++ "not support it. Use https:// or ssh:// instead." ppExplanation MissingModule = "For a CVS source-repository, the 'module' is a required field." ppExplanation MissingTag =@@ -1117,9 +1121,9 @@ ++ quotes paths ++ " invalid on Windows, which " ++ "would cause portability problems for this package. Windows file "- ++ "names cannot contain any of the characters \":*?<>|\" and there "- ++ "a few reserved names including \"aux\", \"nul\", \"con\", "- ++ "\"prn\", \"com1-9\", \"lpt1-9\" and \"clock$\"."+ ++ "names cannot contain any of the characters \":*?<>|\", and there "+ ++ "are a few reserved names including \"aux\", \"nul\", \"con\", "+ ++ "\"prn\", \"com{1-9}\", \"lpt{1-9}\" and \"clock$\"." where quotes [failed] = "path " ++ quote failed ++ " is" quotes failed =
src/Distribution/Simple.hs view
@@ -1,7 +1,12 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} ----------------------------------------------------------------------------- {- Work around this warning:@@ -53,6 +58,8 @@ , UserHooks (..) , Args , defaultMainWithHooks+ , defaultMainWithSetupHooks+ , defaultMainWithSetupHooksArgs , defaultMainWithHooksArgs , defaultMainWithHooksNoRead , defaultMainWithHooksNoReadArgs@@ -60,12 +67,14 @@ -- ** Standard sets of hooks , simpleUserHooks , autoconfUserHooks+ , autoconfSetupHooks , emptyUserHooks ) where import Control.Exception (try) import Distribution.Compat.Prelude+import Distribution.Compat.ResponseFile (expandResponse) import Prelude () -- local@@ -79,6 +88,7 @@ import Distribution.Simple.PreProcess import Distribution.Simple.Program import Distribution.Simple.Setup+import qualified Distribution.Simple.SetupHooks.Internal as SetupHooks import Distribution.Simple.UserHooks import Distribution.Simple.Build@@ -91,20 +101,24 @@ import Distribution.Pretty import Distribution.Simple.Bench import Distribution.Simple.BuildPaths-import Distribution.Simple.ConfigureScript+import Distribution.Simple.ConfigureScript (runConfigureScript) import Distribution.Simple.Errors import Distribution.Simple.Haddock import Distribution.Simple.Install import Distribution.Simple.LocalBuildInfo+import Distribution.Simple.SetupHooks.Internal+ ( SetupHooks+ ) import Distribution.Simple.Test import Distribution.Simple.Utils+import qualified Distribution.Types.LocalBuildConfig as LBC+import Distribution.Utils.Path import Distribution.Verbosity import Distribution.Version import Language.Haskell.Extension -- Base--import Distribution.Compat.ResponseFile (expandResponse)+import Data.List (unionBy, (\\)) import System.Directory ( doesDirectoryExist , doesFileExist@@ -112,10 +126,7 @@ , removeFile ) import System.Environment (getArgs, getProgName)-import System.FilePath (takeDirectory, (</>)) -import Data.List (unionBy, (\\))- -- | A simple implementation of @main@ for a Cabal setup script. -- It reads the package description file using IO, and performs the -- action specified on the command line.@@ -127,6 +138,112 @@ defaultMainArgs :: [String] -> IO () defaultMainArgs = defaultMainHelper simpleUserHooks +defaultMainWithSetupHooks :: SetupHooks -> IO ()+defaultMainWithSetupHooks setup_hooks =+ getArgs >>= defaultMainWithSetupHooksArgs setup_hooks++defaultMainWithSetupHooksArgs :: SetupHooks -> [String] -> IO ()+defaultMainWithSetupHooksArgs setupHooks =+ defaultMainHelper $+ simpleUserHooks+ { confHook = setup_confHook+ , buildHook = setup_buildHook+ , copyHook = setup_copyHook+ , instHook = setup_installHook+ , replHook = setup_replHook+ , haddockHook = setup_haddockHook+ , hscolourHook = setup_hscolourHook+ }+ where+ setup_confHook+ :: (GenericPackageDescription, HookedBuildInfo)+ -> ConfigFlags+ -> IO LocalBuildInfo+ setup_confHook =+ configure_setupHooks+ (SetupHooks.configureHooks setupHooks)++ setup_buildHook+ :: PackageDescription+ -> LocalBuildInfo+ -> UserHooks+ -> BuildFlags+ -> IO ()+ setup_buildHook pkg_descr lbi hooks flags =+ build_setupHooks+ (SetupHooks.buildHooks setupHooks)+ pkg_descr+ lbi+ flags+ (allSuffixHandlers hooks)++ setup_copyHook+ :: PackageDescription+ -> LocalBuildInfo+ -> UserHooks+ -> CopyFlags+ -> IO ()+ setup_copyHook pkg_descr lbi _hooks flags =+ install_setupHooks+ (SetupHooks.installHooks setupHooks)+ pkg_descr+ lbi+ flags++ setup_installHook+ :: PackageDescription+ -> LocalBuildInfo+ -> UserHooks+ -> InstallFlags+ -> IO ()+ setup_installHook =+ defaultInstallHook_setupHooks+ (SetupHooks.installHooks setupHooks)++ setup_replHook+ :: PackageDescription+ -> LocalBuildInfo+ -> UserHooks+ -> ReplFlags+ -> [String]+ -> IO ()+ setup_replHook pkg_descr lbi hooks flags args =+ repl_setupHooks+ (SetupHooks.buildHooks setupHooks)+ pkg_descr+ lbi+ flags+ (allSuffixHandlers hooks)+ args++ setup_haddockHook+ :: PackageDescription+ -> LocalBuildInfo+ -> UserHooks+ -> HaddockFlags+ -> IO ()+ setup_haddockHook pkg_descr lbi hooks flags =+ haddock_setupHooks+ (SetupHooks.buildHooks setupHooks)+ pkg_descr+ lbi+ (allSuffixHandlers hooks)+ flags++ setup_hscolourHook+ :: PackageDescription+ -> LocalBuildInfo+ -> UserHooks+ -> HscolourFlags+ -> IO ()+ setup_hscolourHook pkg_descr lbi hooks flags =+ hscolour_setupHooks+ (SetupHooks.buildHooks setupHooks)+ pkg_descr+ lbi+ (allSuffixHandlers hooks)+ flags+ -- | A customizable version of 'defaultMain'. defaultMainWithHooks :: UserHooks -> IO () defaultMainWithHooks hooks = getArgs >>= defaultMainHelper hooks@@ -173,15 +290,15 @@ CommandHelp help -> printHelp help CommandList opts -> printOptionsList opts CommandErrors errs -> printErrors errs- CommandReadyToGo (flags, commandParse) ->+ CommandReadyToGo (globalFlags, commandParse) -> case commandParse of _- | fromFlag (globalVersion flags) -> printVersion- | fromFlag (globalNumericVersion flags) -> printNumericVersion+ | fromFlag (globalVersion globalFlags) -> printVersion+ | fromFlag (globalNumericVersion globalFlags) -> printNumericVersion CommandHelp help -> printHelp help CommandList opts -> printOptionsList opts CommandErrors errs -> printErrors errs- CommandReadyToGo action -> action+ CommandReadyToGo action -> action globalFlags where printHelp help = getProgName >>= putStr . help printOptionsList = putStr . unlines@@ -195,21 +312,24 @@ ++ prettyShow cabalVersion progs = addKnownPrograms (hookedPrograms hooks) defaultProgramDb+ addAction :: CommandUI flags -> (GlobalFlags -> UserHooks -> flags -> [String] -> IO res) -> Command (GlobalFlags -> IO ())+ addAction cmd action =+ cmd `commandAddAction` \flags as globalFlags -> void $ action globalFlags hooks flags as+ commands :: [Command (GlobalFlags -> IO ())] commands =- [ configureCommand progs- `commandAddAction` \fs as -> configureAction hooks fs as >> return ()- , buildCommand progs `commandAddAction` buildAction hooks- , replCommand progs `commandAddAction` replAction hooks- , installCommand `commandAddAction` installAction hooks- , copyCommand `commandAddAction` copyAction hooks- , haddockCommand `commandAddAction` haddockAction hooks- , cleanCommand `commandAddAction` cleanAction hooks- , sdistCommand `commandAddAction` sdistAction hooks- , hscolourCommand `commandAddAction` hscolourAction hooks- , registerCommand `commandAddAction` registerAction hooks- , unregisterCommand `commandAddAction` unregisterAction hooks- , testCommand `commandAddAction` testAction hooks- , benchmarkCommand `commandAddAction` benchAction hooks+ [ configureCommand progs `addAction` configureAction+ , buildCommand progs `addAction` buildAction+ , replCommand progs `addAction` replAction+ , installCommand `addAction` installAction+ , copyCommand `addAction` copyAction+ , haddockCommand `addAction` haddockAction+ , cleanCommand `addAction` cleanAction+ , sdistCommand `addAction` sdistAction+ , hscolourCommand `addAction` hscolourAction+ , registerCommand `addAction` registerAction+ , unregisterCommand `addAction` unregisterAction+ , testCommand `addAction` testAction+ , benchmarkCommand `addAction` benchAction ] -- | Combine the preprocessors in the given hooks with the@@ -223,14 +343,22 @@ overridesPP :: [PPSuffixHandler] -> [PPSuffixHandler] -> [PPSuffixHandler] overridesPP = unionBy (\x y -> fst x == fst y) -configureAction :: UserHooks -> ConfigFlags -> Args -> IO LocalBuildInfo-configureAction hooks flags args = do- distPref <- findDistPrefOrDefault (configDistPref flags)- let flags' =+configureAction :: GlobalFlags -> UserHooks -> ConfigFlags -> Args -> IO LocalBuildInfo+configureAction globalFlags hooks flags args = do+ distPref <- findDistPrefOrDefault (setupDistPref $ configCommonFlags flags)+ let commonFlags = configCommonFlags flags+ commonFlags' =+ commonFlags+ { setupDistPref = toFlag distPref+ , setupWorkingDir = globalWorkingDir globalFlags <> setupWorkingDir commonFlags+ , setupTargets = args+ }+ flags' = flags- { configDistPref = toFlag distPref- , configArgs = args+ { configCommonFlags = commonFlags' }+ mbWorkDir = flagToMaybe $ setupWorkingDir commonFlags'+ verbosity = fromFlag $ setupVerbosity commonFlags' -- See docs for 'HookedBuildInfo' pbi <- preConf hooks args flags'@@ -239,55 +367,75 @@ confPkgDescr hooks verbosity- (flagToMaybe (configCabalFilePath flags))+ mbWorkDir+ (flagToMaybe (setupCabalFilePath commonFlags')) let epkg_descr = (pkg_descr0, pbi) - localbuildinfo0 <- confHook hooks epkg_descr flags'+ lbi1 <- confHook hooks epkg_descr flags' -- remember the .cabal filename if we know it -- and all the extra command line args let localbuildinfo =- localbuildinfo0+ lbi1 { pkgDescrFile = mb_pd_file , extraConfigArgs = args }- writePersistBuildConfig distPref localbuildinfo+ writePersistBuildConfig mbWorkDir distPref localbuildinfo let pkg_descr = localPkgDescr localbuildinfo postConf hooks args flags' pkg_descr localbuildinfo return localbuildinfo- where- verbosity = fromFlag (configVerbosity flags) confPkgDescr :: UserHooks -> Verbosity- -> Maybe FilePath- -> IO (Maybe FilePath, GenericPackageDescription)-confPkgDescr hooks verbosity mb_path = do+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -> Maybe (SymbolicPath Pkg File)+ -> IO (Maybe (SymbolicPath Pkg File), GenericPackageDescription)+confPkgDescr hooks verbosity cwd mb_path = do mdescr <- readDesc hooks case mdescr of Just descr -> return (Nothing, descr) Nothing -> do pdfile <- case mb_path of- Nothing -> defaultPackageDesc verbosity+ Nothing -> relativeSymbolicPath <$> tryFindPackageDesc verbosity cwd Just path -> return path info verbosity "Using Parsec parser"- descr <- readGenericPackageDescription verbosity pdfile+ descr <- readGenericPackageDescription verbosity cwd pdfile return (Just pdfile, descr) -buildAction :: UserHooks -> BuildFlags -> Args -> IO ()-buildAction hooks flags args = do- distPref <- findDistPrefOrDefault (buildDistPref flags)- let verbosity = fromFlag $ buildVerbosity flags- lbi <- getBuildConfig hooks verbosity distPref- let flags' =- flags- { buildDistPref = toFlag distPref- , buildCabalFilePath = maybeToFlag (cabalFilePath lbi)- }+getCommonFlags+ :: GlobalFlags+ -> UserHooks+ -> CommonSetupFlags+ -> Args+ -> IO (LocalBuildInfo, CommonSetupFlags)+getCommonFlags globalFlags hooks commonFlags args = do+ distPref <- findDistPrefOrDefault (setupDistPref commonFlags)+ let verbosity = fromFlag $ setupVerbosity commonFlags+ lbi <- getBuildConfig globalFlags hooks verbosity distPref+ let common' = configCommonFlags $ configFlags lbi+ return $+ ( lbi+ , commonFlags+ { setupDistPref = toFlag distPref+ , setupCabalFilePath = setupCabalFilePath common' <> setupCabalFilePath commonFlags+ , setupWorkingDir =+ globalWorkingDir globalFlags+ <> setupWorkingDir common'+ <> setupWorkingDir commonFlags+ , setupTargets = args+ }+ ) +buildAction :: GlobalFlags -> UserHooks -> BuildFlags -> Args -> IO ()+buildAction globalFlags hooks flags args = do+ let common = buildCommonFlags flags+ verbosity = fromFlag $ setupVerbosity common+ (lbi, common') <- getCommonFlags globalFlags hooks common args+ let flags' = flags{buildCommonFlags = common'}+ progs <- reconfigurePrograms verbosity@@ -302,16 +450,15 @@ postBuild (return lbi{withPrograms = progs}) hooks- flags'{buildArgs = args}+ flags' args -replAction :: UserHooks -> ReplFlags -> Args -> IO ()-replAction hooks flags args = do- distPref <- findDistPrefOrDefault (replDistPref flags)- let verbosity = fromFlag $ replVerbosity flags- flags' = flags{replDistPref = toFlag distPref}-- lbi <- getBuildConfig hooks verbosity distPref+replAction :: GlobalFlags -> UserHooks -> ReplFlags -> Args -> IO ()+replAction globalFlags hooks flags args = do+ let common = replCommonFlags flags+ verbosity = fromFlag $ setupVerbosity common+ (lbi, common') <- getCommonFlags globalFlags hooks common args+ let flags' = flags{replCommonFlags = common'} progs <- reconfigurePrograms verbosity@@ -334,37 +481,30 @@ replHook hooks pkg_descr lbi' hooks flags' args postRepl hooks args flags' pkg_descr lbi' -hscolourAction :: UserHooks -> HscolourFlags -> Args -> IO ()-hscolourAction hooks flags args = do- distPref <- findDistPrefOrDefault (hscolourDistPref flags)- let verbosity = fromFlag $ hscolourVerbosity flags- lbi <- getBuildConfig hooks verbosity distPref- let flags' =- flags- { hscolourDistPref = toFlag distPref- , hscolourCabalFilePath = maybeToFlag (cabalFilePath lbi)- }+hscolourAction :: GlobalFlags -> UserHooks -> HscolourFlags -> Args -> IO ()+hscolourAction globalFlags hooks flags args = do+ let common = hscolourCommonFlags flags+ verbosity = fromFlag $ setupVerbosity common+ (_lbi, common') <- getCommonFlags globalFlags hooks common args+ let flags' = flags{hscolourCommonFlags = common'}+ distPref = fromFlag $ setupDistPref common' hookedAction verbosity preHscolour hscolourHook postHscolour- (getBuildConfig hooks verbosity distPref)+ (getBuildConfig globalFlags hooks verbosity distPref) hooks flags' args -haddockAction :: UserHooks -> HaddockFlags -> Args -> IO ()-haddockAction hooks flags args = do- distPref <- findDistPrefOrDefault (haddockDistPref flags)- let verbosity = fromFlag $ haddockVerbosity flags- lbi <- getBuildConfig hooks verbosity distPref- let flags' =- flags- { haddockDistPref = toFlag distPref- , haddockCabalFilePath = maybeToFlag (cabalFilePath lbi)- }+haddockAction :: GlobalFlags -> UserHooks -> HaddockFlags -> Args -> IO ()+haddockAction globalFlags hooks flags args = do+ let common = haddockCommonFlags flags+ verbosity = fromFlag $ setupVerbosity common+ (lbi, common') <- getCommonFlags globalFlags hooks common args+ let flags' = flags{haddockCommonFlags = common'} progs <- reconfigurePrograms@@ -380,25 +520,42 @@ postHaddock (return lbi{withPrograms = progs}) hooks- flags'{haddockArgs = args}+ flags' args -cleanAction :: UserHooks -> CleanFlags -> Args -> IO ()-cleanAction hooks flags args = do- distPref <- findDistPrefOrDefault (cleanDistPref flags)-- elbi <- tryGetBuildConfig hooks verbosity distPref- let flags' =- flags- { cleanDistPref = toFlag distPref- , cleanCabalFilePath = case elbi of- Left _ -> mempty- Right lbi -> maybeToFlag (cabalFilePath lbi)+cleanAction :: GlobalFlags -> UserHooks -> CleanFlags -> Args -> IO ()+cleanAction globalFlags hooks flags args = do+ let common = cleanCommonFlags flags+ verbosity = fromFlag $ setupVerbosity common+ distPref <- findDistPrefOrDefault (setupDistPref common)+ elbi <- tryGetBuildConfig globalFlags hooks verbosity distPref+ let common' =+ common+ { setupDistPref = toFlag distPref+ , setupWorkingDir = case elbi of+ Left _ ->+ globalWorkingDir globalFlags+ <> setupWorkingDir common+ Right lbi ->+ globalWorkingDir globalFlags+ <> setupWorkingDir (configCommonFlags $ configFlags lbi)+ <> setupWorkingDir common+ , setupCabalFilePath = case elbi of+ Left _ -> setupCabalFilePath common+ Right lbi ->+ setupCabalFilePath common+ <> setupCabalFilePath (configCommonFlags $ configFlags lbi)+ , setupTargets = args }+ flags' =+ flags{cleanCommonFlags = common'} + mbWorkDirFlag = cleanWorkingDir flags'+ mbWorkDir = flagToMaybe mbWorkDirFlag+ pbi <- preClean hooks args flags' - (_, ppd) <- confPkgDescr hooks verbosity Nothing+ (_, ppd) <- confPkgDescr hooks verbosity mbWorkDir Nothing -- It might seem like we are doing something clever here -- but we're really not: if you look at the implementation -- of 'clean' in the end all the package description is@@ -413,125 +570,115 @@ cleanHook hooks pkg_descr () hooks flags' postClean hooks args flags' pkg_descr ()- where- verbosity = fromFlag (cleanVerbosity flags) -copyAction :: UserHooks -> CopyFlags -> Args -> IO ()-copyAction hooks flags args = do- distPref <- findDistPrefOrDefault (copyDistPref flags)- let verbosity = fromFlag $ copyVerbosity flags- lbi <- getBuildConfig hooks verbosity distPref- let flags' =- flags- { copyDistPref = toFlag distPref- , copyCabalFilePath = maybeToFlag (cabalFilePath lbi)- }+copyAction :: GlobalFlags -> UserHooks -> CopyFlags -> Args -> IO ()+copyAction globalFlags hooks flags args = do+ let common = copyCommonFlags flags+ verbosity = fromFlag $ setupVerbosity common+ (_lbi, common') <- getCommonFlags globalFlags hooks common args+ let flags' = flags{copyCommonFlags = common'}+ distPref = fromFlag $ setupDistPref common' hookedAction verbosity preCopy copyHook postCopy- (getBuildConfig hooks verbosity distPref)+ (getBuildConfig globalFlags hooks verbosity distPref) hooks- flags'{copyArgs = args}+ flags' args -installAction :: UserHooks -> InstallFlags -> Args -> IO ()-installAction hooks flags args = do- distPref <- findDistPrefOrDefault (installDistPref flags)- let verbosity = fromFlag $ installVerbosity flags- lbi <- getBuildConfig hooks verbosity distPref- let flags' =- flags- { installDistPref = toFlag distPref- , installCabalFilePath = maybeToFlag (cabalFilePath lbi)- }+installAction :: GlobalFlags -> UserHooks -> InstallFlags -> Args -> IO ()+installAction globalFlags hooks flags args = do+ let common = installCommonFlags flags+ verbosity = fromFlag $ setupVerbosity common+ (_lbi, common') <- getCommonFlags globalFlags hooks common args+ let flags' = flags{installCommonFlags = common'}+ distPref = fromFlag $ setupDistPref common' hookedAction verbosity preInst instHook postInst- (getBuildConfig hooks verbosity distPref)+ (getBuildConfig globalFlags hooks verbosity distPref) hooks flags' args -- Since Cabal-3.4 UserHooks are completely ignored-sdistAction :: UserHooks -> SDistFlags -> Args -> IO ()-sdistAction _hooks flags _args = do- (_, ppd) <- confPkgDescr emptyUserHooks verbosity Nothing+sdistAction :: GlobalFlags -> UserHooks -> SDistFlags -> Args -> IO ()+sdistAction _globalFlags _hooks flags _args = do+ let mbWorkDir = flagToMaybe $ sDistWorkingDir flags+ (_, ppd) <- confPkgDescr emptyUserHooks verbosity mbWorkDir Nothing let pkg_descr = flattenPackageDescription ppd sdist pkg_descr flags srcPref knownSuffixHandlers where- verbosity = fromFlag (sDistVerbosity flags)--testAction :: UserHooks -> TestFlags -> Args -> IO ()-testAction hooks flags args = do- distPref <- findDistPrefOrDefault (testDistPref flags)- let verbosity = fromFlag $ testVerbosity flags- flags' = flags{testDistPref = toFlag distPref}+ verbosity = fromFlag (setupVerbosity $ sDistCommonFlags flags) +testAction :: GlobalFlags -> UserHooks -> TestFlags -> Args -> IO ()+testAction globalFlags hooks flags args = do+ let common = testCommonFlags flags+ verbosity = fromFlag $ setupVerbosity common+ (_lbi, common') <- getCommonFlags globalFlags hooks common args+ let flags' = flags{testCommonFlags = common'}+ distPref = fromFlag $ setupDistPref common' hookedActionWithArgs verbosity preTest testHook postTest- (getBuildConfig hooks verbosity distPref)+ (getBuildConfig globalFlags hooks verbosity distPref) hooks flags' args -benchAction :: UserHooks -> BenchmarkFlags -> Args -> IO ()-benchAction hooks flags args = do- distPref <- findDistPrefOrDefault (benchmarkDistPref flags)- let verbosity = fromFlag $ benchmarkVerbosity flags- flags' = flags{benchmarkDistPref = toFlag distPref}+benchAction :: GlobalFlags -> UserHooks -> BenchmarkFlags -> Args -> IO ()+benchAction globalFlags hooks flags args = do+ let common = benchmarkCommonFlags flags+ verbosity = fromFlag $ setupVerbosity common+ (_lbi, common') <- getCommonFlags globalFlags hooks common args+ let flags' = flags{benchmarkCommonFlags = common'}+ distPref = fromFlag $ setupDistPref common' hookedActionWithArgs verbosity preBench benchHook postBench- (getBuildConfig hooks verbosity distPref)+ (getBuildConfig globalFlags hooks verbosity distPref) hooks flags' args -registerAction :: UserHooks -> RegisterFlags -> Args -> IO ()-registerAction hooks flags args = do- distPref <- findDistPrefOrDefault (regDistPref flags)- let verbosity = fromFlag $ regVerbosity flags- lbi <- getBuildConfig hooks verbosity distPref- let flags' =- flags- { regDistPref = toFlag distPref- , regCabalFilePath = maybeToFlag (cabalFilePath lbi)- }+registerAction :: GlobalFlags -> UserHooks -> RegisterFlags -> Args -> IO ()+registerAction globalFlags hooks flags args = do+ let common = registerCommonFlags flags+ verbosity = fromFlag $ setupVerbosity common+ (_lbi, common') <- getCommonFlags globalFlags hooks common args+ let flags' = flags{registerCommonFlags = common'}+ distPref = fromFlag $ setupDistPref common' hookedAction verbosity preReg regHook postReg- (getBuildConfig hooks verbosity distPref)+ (getBuildConfig globalFlags hooks verbosity distPref) hooks- flags'{regArgs = args}+ flags' args -unregisterAction :: UserHooks -> RegisterFlags -> Args -> IO ()-unregisterAction hooks flags args = do- distPref <- findDistPrefOrDefault (regDistPref flags)- let verbosity = fromFlag $ regVerbosity flags- lbi <- getBuildConfig hooks verbosity distPref- let flags' =- flags- { regDistPref = toFlag distPref- , regCabalFilePath = maybeToFlag (cabalFilePath lbi)- }+unregisterAction :: GlobalFlags -> UserHooks -> RegisterFlags -> Args -> IO ()+unregisterAction globalFlags hooks flags args = do+ let common = registerCommonFlags flags+ verbosity = fromFlag $ setupVerbosity common+ (_lbi, common') <- getCommonFlags globalFlags hooks common args+ let flags' = flags{registerCommonFlags = common'}+ distPref = fromFlag $ setupDistPref common' hookedAction verbosity preUnreg unregHook postUnreg- (getBuildConfig hooks verbosity distPref)+ (getBuildConfig globalFlags hooks verbosity distPref) hooks flags' args@@ -625,16 +772,22 @@ -- | Try to read the 'localBuildInfoFile' tryGetBuildConfig- :: UserHooks+ :: GlobalFlags+ -> UserHooks -> Verbosity- -> FilePath+ -> SymbolicPath Pkg (Dir Dist) -> IO (Either ConfigStateFileError LocalBuildInfo)-tryGetBuildConfig u v = try . getBuildConfig u v+tryGetBuildConfig g u v = try . getBuildConfig g u v -- | Read the 'localBuildInfoFile' or throw an exception.-getBuildConfig :: UserHooks -> Verbosity -> FilePath -> IO LocalBuildInfo-getBuildConfig hooks verbosity distPref = do- lbi_wo_programs <- getPersistBuildConfig distPref+getBuildConfig+ :: GlobalFlags+ -> UserHooks+ -> Verbosity+ -> SymbolicPath Pkg (Dir Dist)+ -> IO LocalBuildInfo+getBuildConfig globalFlags hooks verbosity distPref = do+ lbi_wo_programs <- getPersistBuildConfig mbWorkDir distPref -- Restore info about unconfigured programs, since it is not serialized let lbi = lbi_wo_programs@@ -647,15 +800,16 @@ case pkgDescrFile lbi of Nothing -> return lbi Just pkg_descr_file -> do- outdated <- checkPersistBuildConfigOutdated distPref pkg_descr_file+ outdated <- checkPersistBuildConfigOutdated mbWorkDir distPref pkg_descr_file if outdated then reconfigure pkg_descr_file lbi else return lbi where- reconfigure :: FilePath -> LocalBuildInfo -> IO LocalBuildInfo+ mbWorkDir = flagToMaybe $ globalWorkingDir globalFlags+ reconfigure :: SymbolicPath Pkg File -> LocalBuildInfo -> IO LocalBuildInfo reconfigure pkg_descr_file lbi = do notice verbosity $- pkg_descr_file+ getSymbolicPath pkg_descr_file ++ " has been changed. " ++ "Re-configuring with most recently used options. " ++ "If this fails, please run configure manually.\n"@@ -671,35 +825,43 @@ (builtinPrograms ++ hookedPrograms hooks) ) `fmap` configPrograms_ cFlags- , -- Use the current, not saved verbosity level:- configVerbosity = Flag verbosity+ , configCommonFlags =+ (configCommonFlags cFlags)+ { -- Use the current, not saved verbosity level:+ setupVerbosity = Flag verbosity+ } }- configureAction hooks cFlags' (extraConfigArgs lbi)+ configureAction globalFlags hooks cFlags' (extraConfigArgs lbi) -- -------------------------------------------------------------------------- -- Cleaning clean :: PackageDescription -> CleanFlags -> IO () clean pkg_descr flags = do- let distPref = fromFlagOrDefault defaultDistPref $ cleanDistPref flags+ let common = cleanCommonFlags flags+ verbosity = fromFlag (setupVerbosity common)+ distPref = fromFlagOrDefault defaultDistPref $ setupDistPref common+ mbWorkDir = flagToMaybe $ setupWorkingDir common+ i = interpretSymbolicPath mbWorkDir -- See Note [Symbolic paths] in Distribution.Utils.Path+ distPath = i distPref notice verbosity "cleaning..." maybeConfig <- if fromFlag (cleanSaveConf flags)- then maybeGetPersistBuildConfig distPref+ then maybeGetPersistBuildConfig mbWorkDir distPref else return Nothing -- remove the whole dist/ directory rather than tracking exactly what files -- we created in there. chattyTry "removing dist/" $ do- exists <- doesDirectoryExist distPref- when exists (removeDirectoryRecursive distPref)+ exists <- doesDirectoryExist distPath+ when exists (removeDirectoryRecursive distPath) -- Any extra files the user wants to remove- traverse_ removeFileOrDirectory (extraTmpFiles pkg_descr)+ traverse_ (removeFileOrDirectory . i) (extraTmpFiles pkg_descr) -- If the user wanted to save the config, write it back- traverse_ (writePersistBuildConfig distPref) maybeConfig+ traverse_ (writePersistBuildConfig mbWorkDir distPref) maybeConfig where removeFileOrDirectory :: FilePath -> IO () removeFileOrDirectory fname = do@@ -708,7 +870,6 @@ if isDir then removeDirectoryRecursive fname else when isFile $ removeFile fname- verbosity = fromFlag (cleanVerbosity flags) -- -------------------------------------------------------------------------- -- Default hooks@@ -724,9 +885,9 @@ , replHook = defaultReplHook , copyHook = \desc lbi _ f -> install desc lbi f , -- 'install' has correct 'copy' behavior with params- testHook = defaultTestHook+ instHook = defaultInstallHook+ , testHook = defaultTestHook , benchHook = defaultBenchHook- , instHook = defaultInstallHook , cleanHook = \p _ _ f -> clean p f , hscolourHook = \p l h f -> hscolour p l (allSuffixHandlers h) f , haddockHook = \p l h f -> haddock p l (allSuffixHandlers h) f@@ -737,7 +898,7 @@ finalChecks _args flags pkg_descr lbi = checkForeignDeps pkg_descr lbi (lessVerbose verbosity) where- verbosity = fromFlag (configVerbosity flags)+ verbosity = fromFlag (setupVerbosity $ configCommonFlags flags) -- | Basic autoconf 'UserHooks': --@@ -752,17 +913,17 @@ autoconfUserHooks = simpleUserHooks { postConf = defaultPostConf- , preBuild = readHookWithArgs buildVerbosity buildDistPref- , preRepl = readHookWithArgs replVerbosity replDistPref- , preCopy = readHookWithArgs copyVerbosity copyDistPref- , preClean = readHook cleanVerbosity cleanDistPref- , preInst = readHook installVerbosity installDistPref- , preHscolour = readHook hscolourVerbosity hscolourDistPref- , preHaddock = readHookWithArgs haddockVerbosity haddockDistPref- , preReg = readHook regVerbosity regDistPref- , preUnreg = readHook regVerbosity regDistPref- , preTest = readHookWithArgs testVerbosity testDistPref- , preBench = readHookWithArgs benchmarkVerbosity benchmarkDistPref+ , preBuild = readHookWithArgs buildCommonFlags+ , preRepl = readHookWithArgs replCommonFlags+ , preCopy = readHookWithArgs copyCommonFlags+ , preClean = readHook cleanCommonFlags+ , preInst = readHook installCommonFlags+ , preHscolour = readHook hscolourCommonFlags+ , preHaddock = readHookWithArgs haddockCommonFlags+ , preReg = readHook registerCommonFlags+ , preUnreg = readHook registerCommonFlags+ , preTest = readHookWithArgs testCommonFlags+ , preBench = readHookWithArgs benchmarkCommonFlags } where defaultPostConf@@ -773,60 +934,119 @@ -> IO () defaultPostConf args flags pkg_descr lbi = do- let verbosity = fromFlag (configVerbosity flags)- baseDir lbi' =- fromMaybe- ""- (takeDirectory <$> cabalFilePath lbi')- confExists <- doesFileExist $ (baseDir lbi) </> "configure"- if confExists- then- runConfigureScript- verbosity- flags- lbi- else dieWithException verbosity ConfigureScriptNotFound-- pbi <- getHookedBuildInfo verbosity (buildDir lbi)+ let common = configCommonFlags flags+ verbosity = fromFlag $ setupVerbosity common+ mbWorkDir = flagToMaybe $ setupWorkingDir common+ runConfigureScript+ flags+ (flagAssignment lbi)+ (withPrograms lbi)+ (hostPlatform lbi)+ pbi <- getHookedBuildInfo verbosity mbWorkDir (buildDir lbi) sanityCheckHookedBuildInfo verbosity pkg_descr pbi let pkg_descr' = updatePackageDescription pbi pkg_descr lbi' = lbi{localPkgDescr = pkg_descr'} postConf simpleUserHooks args flags pkg_descr' lbi' readHookWithArgs- :: (a -> Flag Verbosity)- -> (a -> Flag FilePath)+ :: (flags -> CommonSetupFlags) -> Args- -> a+ -> flags -> IO HookedBuildInfo- readHookWithArgs get_verbosity get_dist_pref _ flags = do- dist_dir <- findDistPrefOrDefault (get_dist_pref flags)- getHookedBuildInfo verbosity (dist_dir </> "build")- where- verbosity = fromFlag (get_verbosity flags)+ readHookWithArgs get_common_flags _args flags = do+ let common = get_common_flags flags+ verbosity = fromFlag (setupVerbosity common)+ mbWorkDir = flagToMaybe $ setupWorkingDir common+ distPref = setupDistPref common+ dist_dir <- findDistPrefOrDefault distPref+ getHookedBuildInfo verbosity mbWorkDir (dist_dir </> makeRelativePathEx "build") readHook- :: (a -> Flag Verbosity)- -> (a -> Flag FilePath)+ :: (flags -> CommonSetupFlags) -> Args- -> a+ -> flags -> IO HookedBuildInfo- readHook get_verbosity get_dist_pref a flags = do- noExtraFlags a- dist_dir <- findDistPrefOrDefault (get_dist_pref flags)- getHookedBuildInfo verbosity (dist_dir </> "build")- where- verbosity = fromFlag (get_verbosity flags)+ readHook get_common_flags args flags = do+ let common = get_common_flags flags+ verbosity = fromFlag (setupVerbosity common)+ mbWorkDir = flagToMaybe $ setupWorkingDir common+ distPref = setupDistPref common+ noExtraFlags args+ dist_dir <- findDistPrefOrDefault distPref+ getHookedBuildInfo verbosity mbWorkDir (dist_dir </> makeRelativePathEx "build") -getHookedBuildInfo :: Verbosity -> FilePath -> IO HookedBuildInfo-getHookedBuildInfo verbosity build_dir = do- maybe_infoFile <- findHookedPackageDesc verbosity build_dir+getHookedBuildInfo+ :: Verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -> SymbolicPath Pkg (Dir Build)+ -> IO HookedBuildInfo+getHookedBuildInfo verbosity mbWorkDir build_dir = do+ maybe_infoFile <- findHookedPackageDesc verbosity mbWorkDir build_dir case maybe_infoFile of Nothing -> return emptyHookedBuildInfo Just infoFile -> do- info verbosity $ "Reading parameters from " ++ infoFile- readHookedBuildInfo verbosity infoFile+ info verbosity $ "Reading parameters from " ++ getSymbolicPath infoFile+ readHookedBuildInfo verbosity mbWorkDir infoFile +autoconfSetupHooks :: SetupHooks+autoconfSetupHooks =+ SetupHooks.noSetupHooks+ { SetupHooks.configureHooks =+ SetupHooks.noConfigureHooks+ { SetupHooks.postConfPackageHook = Just post_conf_pkg+ , SetupHooks.preConfComponentHook = Just pre_conf_comp+ }+ }+ where+ post_conf_pkg+ :: SetupHooks.PostConfPackageInputs+ -> IO ()+ post_conf_pkg+ ( SetupHooks.PostConfPackageInputs+ { SetupHooks.localBuildConfig =+ LBC.LocalBuildConfig{LBC.withPrograms = progs}+ , SetupHooks.packageBuildDescr =+ LBC.PackageBuildDescr+ { LBC.configFlags = cfg+ , LBC.flagAssignment = flags+ , LBC.hostPlatform = plat+ }+ }+ ) = runConfigureScript cfg flags progs plat++ pre_conf_comp+ :: SetupHooks.PreConfComponentInputs+ -> IO SetupHooks.PreConfComponentOutputs+ pre_conf_comp+ ( SetupHooks.PreConfComponentInputs+ { SetupHooks.packageBuildDescr =+ LBC.PackageBuildDescr+ { LBC.configFlags = cfg+ , localPkgDescr = pkg_descr+ }+ , SetupHooks.component = component+ }+ ) = do+ let verbosity = fromFlag $ configVerbosity cfg+ mbWorkDir = flagToMaybe $ configWorkingDir cfg+ distPref = configDistPref cfg+ dist_dir <- findDistPrefOrDefault distPref+ -- Read the ".buildinfo" file and use that to update+ -- the components (main library + executables only).+ hbi <- getHookedBuildInfo verbosity mbWorkDir (dist_dir </> makeRelativePathEx "build")+ sanityCheckHookedBuildInfo verbosity pkg_descr hbi+ -- SetupHooks TODO: we are reading getHookedBuildInfo once+ -- for each component. I think this is inherent to the SetupHooks+ -- approach.+ let comp_name = componentName component+ diff <- case SetupHooks.hookedBuildInfoComponentDiff_maybe hbi comp_name of+ Nothing -> return $ SetupHooks.emptyComponentDiff comp_name+ Just do_diff -> do_diff+ return $+ SetupHooks.PreConfComponentOutputs+ { SetupHooks.componentDiff = diff+ }+ defaultTestHook :: Args -> PackageDescription@@ -853,22 +1073,30 @@ -> UserHooks -> InstallFlags -> IO ()-defaultInstallHook pkg_descr localbuildinfo _ flags = do+defaultInstallHook =+ defaultInstallHook_setupHooks SetupHooks.noInstallHooks++defaultInstallHook_setupHooks+ :: SetupHooks.InstallHooks+ -> PackageDescription+ -> LocalBuildInfo+ -> UserHooks+ -> InstallFlags+ -> IO ()+defaultInstallHook_setupHooks inst_hooks pkg_descr localbuildinfo _ flags = do let copyFlags = defaultCopyFlags- { copyDistPref = installDistPref flags- , copyDest = installDest flags- , copyVerbosity = installVerbosity flags+ { copyDest = installDest flags+ , copyCommonFlags = installCommonFlags flags }- install pkg_descr localbuildinfo copyFlags+ install_setupHooks inst_hooks pkg_descr localbuildinfo copyFlags let registerFlags = defaultRegisterFlags- { regDistPref = installDistPref flags- , regInPlace = installInPlace flags+ { regInPlace = installInPlace flags , regPackageDB = installPackageDB flags- , regVerbosity = installVerbosity flags }- when (hasLibs pkg_descr) $ register pkg_descr localbuildinfo registerFlags+ when (hasLibs pkg_descr) $+ register pkg_descr localbuildinfo registerFlags defaultBuildHook :: PackageDescription@@ -900,6 +1128,6 @@ then register pkg_descr localbuildinfo flags else setupMessage- (fromFlag (regVerbosity flags))+ (fromFlag (setupVerbosity $ registerCommonFlags flags)) "Package contains no library to register:" (packageId pkg_descr)
src/Distribution/Simple/Bench.hs view
@@ -1,4 +1,6 @@+{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RankNTypes #-} -----------------------------------------------------------------------------@@ -21,22 +23,28 @@ import Distribution.Compat.Prelude import Prelude () +import Distribution.Compat.Environment import qualified Distribution.PackageDescription as PD import Distribution.Pretty+import Distribution.Simple.Build (addInternalBuildTools) import Distribution.Simple.BuildPaths import Distribution.Simple.Compiler-import Distribution.Simple.Flag (fromFlag)+import Distribution.Simple.Errors import Distribution.Simple.InstallDirs import qualified Distribution.Simple.LocalBuildInfo as LBI+import Distribution.Simple.Program.Db+import Distribution.Simple.Program.Find+import Distribution.Simple.Program.Run import Distribution.Simple.Setup.Benchmark+import Distribution.Simple.Setup.Common import Distribution.Simple.UserHooks import Distribution.Simple.Utils-+import Distribution.System (Platform (Platform))+import Distribution.Types.Benchmark (Benchmark (benchmarkBuildInfo)) import Distribution.Types.UnqualComponentName+import Distribution.Utils.Path -import Distribution.Simple.Errors import System.Directory (doesFileExist)-import System.FilePath ((<.>), (</>)) -- | Perform the \"@.\/setup bench@\" action. bench@@ -53,16 +61,28 @@ let verbosity = fromFlag $ benchmarkVerbosity flags benchmarkNames = args pkgBenchmarks = PD.benchmarks pkg_descr- enabledBenchmarks = map fst (LBI.enabledBenchLBIs pkg_descr lbi)+ enabledBenchmarks = LBI.enabledBenchLBIs pkg_descr lbi+ mbWorkDir = flagToMaybe $ benchmarkWorkingDir flags+ i = interpretSymbolicPath mbWorkDir -- See Note [Symbolic paths] in Distribution.Utils.Path -- Run the benchmark- doBench :: PD.Benchmark -> IO ExitCode- doBench bm =+ doBench :: (PD.Benchmark, LBI.ComponentLocalBuildInfo) -> IO ExitCode+ doBench (bm, clbi) = do+ let lbiForBench =+ lbi+ { -- Include any build-tool-depends on build tools internal to the current package.+ LBI.withPrograms =+ addInternalBuildTools+ pkg_descr+ lbi+ (benchmarkBuildInfo bm)+ (LBI.withPrograms lbi)+ } case PD.benchmarkInterface bm of PD.BenchmarkExeV10 _ _ -> do- let cmd = LBI.buildDir lbi </> name </> name <.> exeExtension (LBI.hostPlatform lbi)+ let cmd = i $ LBI.buildDir lbiForBench </> makeRelativePathEx (name </> name <.> exeExtension (LBI.hostPlatform lbi)) options =- map (benchOption pkg_descr lbi bm) $+ map (benchOption pkg_descr lbiForBench bm) $ benchmarkOptions flags -- Check that the benchmark executable exists. exists <- doesFileExist cmd@@ -70,10 +90,29 @@ dieWithException verbosity $ NoBenchMarkProgram cmd + existingEnv <- getEnvironment++ -- Compute the appropriate environment for running the benchmark+ let progDb = LBI.withPrograms lbiForBench+ pathVar = progSearchPath progDb+ envOverrides = progOverrideEnv progDb+ newPath <- programSearchPathAsPATHVar pathVar+ overrideEnv <- fromMaybe [] <$> getEffectiveEnvironment ([("PATH", Just newPath)] ++ envOverrides)+ let shellEnv = overrideEnv ++ existingEnv++ -- Add (DY)LD_LIBRARY_PATH if needed+ shellEnv' <-+ if LBI.withDynExe lbiForBench+ then do+ let (Platform _ os) = LBI.hostPlatform lbiForBench+ paths <- LBI.depLibraryPaths True False lbiForBench clbi+ return (addLibraryPath os paths shellEnv)+ else return shellEnv+ notice verbosity $ startMessage name -- This will redirect the child process -- stdout/stderr to the parent process.- exitcode <- rawSystemExitCode verbosity cmd options+ exitcode <- rawSystemExitCode verbosity mbWorkDir cmd options (Just shellEnv') notice verbosity $ finishMessage name exitcode return exitcode _ -> do@@ -98,7 +137,7 @@ [] -> return enabledBenchmarks names -> for names $ \bmName -> let benchmarkMap = zip enabledNames enabledBenchmarks- enabledNames = map PD.benchmarkName enabledBenchmarks+ enabledNames = map (PD.benchmarkName . fst) enabledBenchmarks allNames = map PD.benchmarkName pkgBenchmarks in case lookup (mkUnqualComponentName bmName) benchmarkMap of Just t -> return t@@ -110,6 +149,7 @@ let totalBenchmarks = length bmsToRun notice verbosity $ "Running " ++ show totalBenchmarks ++ " benchmarks..." exitcodes <- traverse doBench bmsToRun+ let allOk = totalBenchmarks == length (filter (== ExitSuccess) exitcodes) unless allOk exitFailure where
src/Distribution/Simple/Build.hs view
@@ -1,5 +1,8 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TupleSections #-} @@ -22,9 +25,11 @@ module Distribution.Simple.Build ( -- * Build build+ , build_setupHooks -- * Repl , repl+ , repl_setupHooks , startInterpreter -- * Build preparation@@ -40,6 +45,9 @@ -- * Internal package database creation , createInternalPackageDB++ -- * Handling of internal build tools+ , addInternalBuildTools ) where import Distribution.Compat.Prelude@@ -71,7 +79,7 @@ import Distribution.Simple.Build.Macros (generateCabalMacrosHeader) import Distribution.Simple.Build.PackageInfoModule (generatePackageInfoModule)-import Distribution.Simple.Build.PathsModule (generatePathsModule)+import Distribution.Simple.Build.PathsModule (generatePathsModule, pkgPathEnvVar) import qualified Distribution.Simple.Program.HcPkg as HcPkg import Distribution.InstalledPackageInfo (InstalledPackageInfo)@@ -90,12 +98,21 @@ import Distribution.Simple.PreProcess import Distribution.Simple.Program import Distribution.Simple.Program.Builtin (haskellSuiteProgram)+import Distribution.Simple.Program.Db import qualified Distribution.Simple.Program.GHC as GHC import Distribution.Simple.Program.Types import Distribution.Simple.Register import Distribution.Simple.Setup.Build+import Distribution.Simple.Setup.Common import Distribution.Simple.Setup.Config import Distribution.Simple.Setup.Repl+import Distribution.Simple.SetupHooks.Internal+ ( BuildHooks (..)+ , BuildingWhat (..)+ , noBuildHooks+ )+import qualified Distribution.Simple.SetupHooks.Internal as SetupHooks+import qualified Distribution.Simple.SetupHooks.Rule as SetupHooks import Distribution.Simple.ShowBuildInfo import Distribution.Simple.Test.LibV09 import Distribution.Simple.Utils@@ -113,8 +130,8 @@ import qualified Data.ByteString.Lazy as LBS import qualified Data.Map as Map import Distribution.Simple.Errors-import System.Directory (doesFileExist, getCurrentDirectory, removeFile)-import System.FilePath (takeDirectory, (<.>), (</>))+import System.Directory (doesFileExist, removeFile)+import System.FilePath (takeDirectory) -- ----------------------------------------------------------------------------- @@ -129,70 +146,108 @@ -> [PPSuffixHandler] -- ^ preprocessors to run before compiling -> IO ()-build pkg_descr lbi flags suffixes = do- checkSemaphoreSupport verbosity (compiler lbi) flags- targets <- readTargetInfos verbosity pkg_descr lbi (buildArgs flags)- let componentsToBuild = neededTargetsInBuildOrder' pkg_descr lbi (map nodeKey targets)- info verbosity $- "Component build order: "- ++ intercalate- ", "- ( map- (showComponentName . componentLocalName . targetCLBI)- componentsToBuild- )+build = build_setupHooks noBuildHooks - when (null targets) $- -- Only bother with this message if we're building the whole package- setupMessage verbosity "Building" (packageId pkg_descr)+build_setupHooks+ :: BuildHooks+ -> PackageDescription+ -- ^ Mostly information from the .cabal file+ -> LocalBuildInfo+ -- ^ Configuration information+ -> BuildFlags+ -- ^ Flags that the user passed to build+ -> [PPSuffixHandler]+ -- ^ preprocessors to run before compiling+ -> IO ()+build_setupHooks+ (BuildHooks{preBuildComponentRules = mbPbcRules, postBuildComponentHook = mbPostBuild})+ pkg_descr+ lbi+ flags+ suffixHandlers = do+ checkSemaphoreSupport verbosity (compiler lbi) flags+ targets <- readTargetInfos verbosity pkg_descr lbi (buildTargets flags)+ let componentsToBuild = neededTargetsInBuildOrder' pkg_descr lbi (map nodeKey targets)+ info verbosity $+ "Component build order: "+ ++ intercalate+ ", "+ ( map+ (showComponentName . componentLocalName . targetCLBI)+ componentsToBuild+ ) - internalPackageDB <- createInternalPackageDB verbosity lbi distPref+ when (null targets) $+ -- Only bother with this message if we're building the whole package+ setupMessage verbosity "Building" (packageId pkg_descr) - -- Before the actual building, dump out build-information.- -- This way, if the actual compilation failed, the options have still been- -- dumped.- dumpBuildInfo verbosity distPref (configDumpBuildInfo (configFlags lbi)) pkg_descr lbi flags+ internalPackageDB <- createInternalPackageDB verbosity lbi distPref - -- Now do the actual building- (\f -> foldM_ f (installedPkgs lbi) componentsToBuild) $ \index target -> do- preBuildComponent verbosity lbi target- let comp = targetComponent target- clbi = targetCLBI target- bi = componentBuildInfo comp- progs' = addInternalBuildTools pkg_descr lbi bi (withPrograms lbi)- lbi' =- lbi- { withPrograms = progs'- , withPackageDB = withPackageDB lbi ++ [internalPackageDB]- , installedPkgs = index- }- par_strat <-- toFlag <$> case buildUseSemaphore flags of- Flag sem_name -> case buildNumJobs flags of- Flag{} -> do- warn verbosity $ "Ignoring -j due to --semaphore"- return $ UseSem sem_name- NoFlag -> return $ UseSem sem_name- NoFlag -> return $ case buildNumJobs flags of- Flag n -> NumJobs n- NoFlag -> Serial- mb_ipi <-- buildComponent- flags- par_strat- pkg_descr- lbi'- suffixes- comp- clbi- distPref- return (maybe index (Index.insert `flip` index) mb_ipi)+ -- Before the actual building, dump out build-information.+ -- This way, if the actual compilation failed, the options have still been+ -- dumped.+ dumpBuildInfo verbosity distPref (configDumpBuildInfo (configFlags lbi)) pkg_descr lbi flags - return ()- where- distPref = fromFlag (buildDistPref flags)- verbosity = fromFlag (buildVerbosity flags)+ -- Now do the actual building+ (\f -> foldM_ f (installedPkgs lbi) componentsToBuild) $ \index target -> do+ let comp = targetComponent target+ clbi = targetCLBI target+ bi = componentBuildInfo comp+ -- Include any build-tool-depends on build tools internal to the current package.+ progs' = addInternalBuildTools pkg_descr lbi bi (withPrograms lbi)+ lbi' =+ lbi+ { withPrograms = progs'+ , withPackageDB = withPackageDB lbi ++ [internalPackageDB]+ , installedPkgs = index+ }+ runPreBuildHooks :: LocalBuildInfo -> TargetInfo -> IO ()+ runPreBuildHooks lbi2 tgt =+ let inputs =+ SetupHooks.PreBuildComponentInputs+ { SetupHooks.buildingWhat = BuildNormal flags+ , SetupHooks.localBuildInfo = lbi2+ , SetupHooks.targetInfo = tgt+ }+ in for_ mbPbcRules $ \pbcRules -> do+ (ruleFromId, _mons) <- SetupHooks.computeRules verbosity inputs pbcRules+ SetupHooks.executeRules verbosity lbi2 tgt ruleFromId+ preBuildComponent runPreBuildHooks verbosity lbi' target+ let numJobs = buildNumJobs flags+ par_strat <-+ toFlag <$> case buildUseSemaphore flags of+ Flag sem_name -> case numJobs of+ Flag{} -> do+ warn verbosity $ "Ignoring -j due to --semaphore"+ return $ UseSem sem_name+ NoFlag -> return $ UseSem sem_name+ NoFlag -> return $ case numJobs of+ Flag n -> NumJobs n+ NoFlag -> Serial+ mb_ipi <-+ buildComponent+ flags+ par_strat+ pkg_descr+ lbi'+ suffixHandlers+ comp+ clbi+ distPref+ let postBuildInputs =+ SetupHooks.PostBuildComponentInputs+ { SetupHooks.buildFlags = flags+ , SetupHooks.localBuildInfo = lbi'+ , SetupHooks.targetInfo = target+ }+ for_ mbPostBuild ($ postBuildInputs)+ return (maybe index (Index.insert `flip` index) mb_ipi) + return ()+ where+ distPref = fromFlag (buildDistPref flags)+ verbosity = fromFlag (buildVerbosity flags)+ -- | Check for conditions that would prevent the build from succeeding. checkSemaphoreSupport :: Verbosity -> Compiler -> BuildFlags -> IO ()@@ -208,7 +263,7 @@ -- lib:Cabal made sure that dependencies are up-to-date. dumpBuildInfo :: Verbosity- -> FilePath+ -> SymbolicPath Pkg (Dir Dist) -- ^ To which directory should the build-info be dumped? -> Flag DumpBuildInfo -- ^ Should we dump detailed build information for this component?@@ -232,26 +287,27 @@ (showComponentName . componentLocalName . targetCLBI) activeTargets )- pwd <- getCurrentDirectory (compilerProg, _) <- case flavorToProgram (compilerFlavor (compiler lbi)) of Nothing -> dieWithException verbosity $ UnknownCompilerFlavor (compilerFlavor (compiler lbi)) Just program -> requireProgram verbosity program (withPrograms lbi) - let (warns, json) = mkBuildInfo pwd pkg_descr lbi flags (compilerProg, compiler lbi) activeTargets+ wdir <- absoluteWorkingDirLBI lbi+ let (warns, json) = mkBuildInfo wdir pkg_descr lbi flags (compilerProg, compiler lbi) activeTargets buildInfoText = renderJson json unless (null warns) $ warn verbosity $ "Encountered warnings while dumping build-info:\n" ++ unlines warns- LBS.writeFile (buildInfoPref distPref) buildInfoText+ LBS.writeFile buildInfoFile buildInfoText when (not shouldDumpBuildInfo) $ do -- Remove existing build-info.json as it might be outdated now.- exists <- doesFileExist (buildInfoPref distPref)- when exists $ removeFile (buildInfoPref distPref)+ exists <- doesFileExist buildInfoFile+ when exists $ removeFile buildInfoFile where+ buildInfoFile = interpretSymbolicPathLBI lbi $ buildInfoPref distPref shouldDumpBuildInfo = fromFlagOrDefault NoDumpBuildInfo dumpBuildInfoFlag == DumpBuildInfo -- \| Given the flavor of the compiler, try to find out@@ -275,67 +331,100 @@ -- ^ preprocessors to run before compiling -> [String] -> IO ()-repl pkg_descr lbi flags suffixes args = do- let distPref = fromFlag (replDistPref flags)- verbosity = fromFlag (replVerbosity flags)+repl = repl_setupHooks noBuildHooks - target <-- readTargetInfos verbosity pkg_descr lbi args >>= \r -> case r of- -- This seems DEEPLY questionable.- [] -> case allTargetsInBuildOrder' pkg_descr lbi of- (target : _) -> return target- [] -> dieWithException verbosity $ FailedToDetermineTarget- [target] -> return target- _ -> dieWithException verbosity $ NoMultipleTargets- let componentsToBuild = neededTargetsInBuildOrder' pkg_descr lbi [nodeKey target]- debug verbosity $- "Component build order: "- ++ intercalate- ", "- ( map- (showComponentName . componentLocalName . targetCLBI)- componentsToBuild- )+repl_setupHooks+ :: BuildHooks+ -- ^ build hook+ -> PackageDescription+ -- ^ Mostly information from the .cabal file+ -> LocalBuildInfo+ -- ^ Configuration information+ -> ReplFlags+ -- ^ Flags that the user passed to build+ -> [PPSuffixHandler]+ -- ^ preprocessors to run before compiling+ -> [String]+ -> IO ()+repl_setupHooks+ (BuildHooks{preBuildComponentRules = mbPbcRules})+ pkg_descr+ lbi+ flags+ suffixHandlers+ args = do+ let distPref = fromFlag (replDistPref flags)+ verbosity = fromFlag (replVerbosity flags) - internalPackageDB <- createInternalPackageDB verbosity lbi distPref+ target <-+ readTargetInfos verbosity pkg_descr lbi args >>= \r -> case r of+ -- This seems DEEPLY questionable.+ [] -> case allTargetsInBuildOrder' pkg_descr lbi of+ (target : _) -> return target+ [] -> dieWithException verbosity $ FailedToDetermineTarget+ [target] -> return target+ _ -> dieWithException verbosity $ NoMultipleTargets+ let componentsToBuild = neededTargetsInBuildOrder' pkg_descr lbi [nodeKey target]+ debug verbosity $+ "Component build order: "+ ++ intercalate+ ", "+ ( map+ (showComponentName . componentLocalName . targetCLBI)+ componentsToBuild+ ) - let lbiForComponent comp lbi' =- lbi'- { withPackageDB = withPackageDB lbi ++ [internalPackageDB]- , withPrograms =- addInternalBuildTools- pkg_descr- lbi'- (componentBuildInfo comp)- (withPrograms lbi')- }+ internalPackageDB <- createInternalPackageDB verbosity lbi distPref - -- build any dependent components- sequence_- [ do- let clbi = targetCLBI subtarget- comp = targetComponent subtarget- lbi' = lbiForComponent comp lbi- preBuildComponent verbosity lbi subtarget- buildComponent- mempty{buildVerbosity = toFlag verbosity}- NoFlag- pkg_descr- lbi'- suffixes- comp- clbi- distPref- | subtarget <- safeInit componentsToBuild- ]+ let lbiForComponent comp lbi' =+ lbi'+ { withPackageDB = withPackageDB lbi ++ [internalPackageDB]+ , withPrograms =+ -- Include any build-tool-depends on build tools internal to the current package.+ addInternalBuildTools+ pkg_descr+ lbi'+ (componentBuildInfo comp)+ (withPrograms lbi')+ }+ runPreBuildHooks :: LocalBuildInfo -> TargetInfo -> IO ()+ runPreBuildHooks lbi2 tgt =+ let inputs =+ SetupHooks.PreBuildComponentInputs+ { SetupHooks.buildingWhat = BuildRepl flags+ , SetupHooks.localBuildInfo = lbi2+ , SetupHooks.targetInfo = tgt+ }+ in for_ mbPbcRules $ \pbcRules -> do+ (ruleFromId, _mons) <- SetupHooks.computeRules verbosity inputs pbcRules+ SetupHooks.executeRules verbosity lbi2 tgt ruleFromId - -- REPL for target components- let clbi = targetCLBI target- comp = targetComponent target- lbi' = lbiForComponent comp lbi- preBuildComponent verbosity lbi target- replComponent flags verbosity pkg_descr lbi' suffixes comp clbi distPref+ -- build any dependent components+ sequence_+ [ do+ let clbi = targetCLBI subtarget+ comp = targetComponent subtarget+ lbi' = lbiForComponent comp lbi+ preBuildComponent runPreBuildHooks verbosity lbi' subtarget+ buildComponent+ (mempty{buildCommonFlags = mempty{setupVerbosity = toFlag verbosity}})+ NoFlag+ pkg_descr+ lbi'+ suffixHandlers+ comp+ clbi+ distPref+ | subtarget <- safeInit componentsToBuild+ ] + -- REPL for target components+ let clbi = targetCLBI target+ comp = targetComponent target+ lbi' = lbiForComponent comp lbi+ preBuildComponent runPreBuildHooks verbosity lbi' target+ replComponent flags verbosity pkg_descr lbi' suffixHandlers comp clbi distPref+ -- | Start an interpreter without loading any package files. startInterpreter :: Verbosity@@ -358,18 +447,20 @@ -> [PPSuffixHandler] -> Component -> ComponentLocalBuildInfo- -> FilePath+ -> SymbolicPath Pkg (Dir Dist) -> IO (Maybe InstalledPackageInfo) buildComponent flags _ _ _ _ (CTest TestSuite{testInterface = TestSuiteUnsupported tt}) _ _ =- dieWithException (fromFlag $ buildVerbosity flags) $ NoSupportBuildingTestSuite tt+ dieWithException (fromFlag $ buildVerbosity flags) $+ NoSupportBuildingTestSuite tt buildComponent flags _ _ _ _ (CBench Benchmark{benchmarkInterface = BenchmarkUnsupported tt}) _ _ =- dieWithException (fromFlag $ buildVerbosity flags) $ NoSupportBuildingBenchMark tt+ dieWithException (fromFlag $ buildVerbosity flags) $+ NoSupportBuildingBenchMark tt buildComponent flags numJobs pkg_descr lbi0- suffixes+ suffixHandlers comp@( CTest test@TestSuite{testInterface = TestSuiteLibV09{}} )@@ -380,11 +471,11 @@ -- built. distPref = do+ inplaceDir <- absoluteWorkingDirLBI lbi0 let verbosity = fromFlag $ buildVerbosity flags- pwd <- getCurrentDirectory let (pkg, lib, libClbi, lbi, ipi, exe, exeClbi) =- testSuiteLibV09AsLibAndExe pkg_descr test clbi lbi0 distPref pwd- preprocessComponent pkg_descr comp lbi clbi False verbosity suffixes+ testSuiteLibV09AsLibAndExe pkg_descr test clbi lbi0 inplaceDir distPref+ preprocessComponent pkg_descr comp lbi clbi False verbosity suffixHandlers extras <- preprocessExtras verbosity comp lbi -- TODO find cpphs processed files (genDir, generatedExtras) <- generateCode (testCodeGenerators test) (testName test) pkg_descr (testBuildInfo test) lbi clbi verbosity setupMessage'@@ -403,6 +494,7 @@ verbosity (compiler lbi) (withPrograms lbi)+ (mbWorkDirLBI lbi) (withPackageDB lbi) ipi HcPkg.defaultRegisterOptions@@ -420,13 +512,13 @@ numJobs pkg_descr lbi- suffixes+ suffixHandlers comp clbi distPref = do let verbosity = fromFlag $ buildVerbosity flags- preprocessComponent pkg_descr comp lbi clbi False verbosity suffixes+ preprocessComponent pkg_descr comp lbi clbi False verbosity suffixHandlers extras <- preprocessExtras verbosity comp lbi setupMessage' verbosity@@ -459,12 +551,12 @@ then do -- Register the library in-place, so exes can depend -- on internally defined libraries.- pwd <- getCurrentDirectory+ inplaceDir <- absoluteWorkingDirLBI lbi let -- The in place registration uses the "-inplace" suffix, not an ABI hash installedPkgInfo = inplaceInstalledPackageInfo- pwd+ inplaceDir distPref pkg_descr -- NB: Use a fake ABI hash to avoid@@ -478,6 +570,7 @@ verbosity (compiler lbi) (withPrograms lbi)+ (flagToMaybe $ buildWorkingDir flags) (withPackageDB lbi) installedPkgInfo HcPkg.defaultRegisterOptions@@ -519,24 +612,27 @@ -> LocalBuildInfo -> ComponentLocalBuildInfo -> Verbosity- -> IO (FilePath, [ModuleName.ModuleName])+ -> IO (SymbolicPath Pkg (Dir Source), [ModuleName.ModuleName]) generateCode codeGens nm pdesc bi lbi clbi verbosity = do- when (not . null $ codeGens) $ createDirectoryIfMissingVerbose verbosity True tgtDir+ when (not . null $ codeGens) $ createDirectoryIfMissingVerbose verbosity True $ i tgtDir (\x -> (tgtDir, x)) . concat <$> mapM go codeGens where allLibs = (maybe id (:) $ library pdesc) (subLibraries pdesc) dependencyLibs = filter (const True) allLibs -- intersect with componentPackageDeps of clbi srcDirs = concatMap (hsSourceDirs . libBuildInfo) dependencyLibs nm' = unUnqualComponentName nm- tgtDir = buildDir lbi </> nm' </> nm' ++ "-gen"+ mbWorkDir = mbWorkDirLBI lbi+ i = interpretSymbolicPath mbWorkDir -- See Note [Symbolic paths] in Distribution.Utils.Path+ tgtDir = buildDir lbi </> makeRelativePathEx (nm' </> nm' ++ "-gen") go :: String -> IO [ModuleName.ModuleName] go codeGenProg = fmap fromString . lines- <$> getDbProgramOutput+ <$> getDbProgramOutputCwd verbosity+ mbWorkDir (simpleProgram codeGenProg) (withPrograms lbi)- ( (tgtDir : map getSymbolicPath srcDirs)+ ( map interpretSymbolicPathCWD (tgtDir : srcDirs) ++ ( "--" : GHC.renderGhcOptions (compiler lbi) (hostPlatform lbi) (GHC.componentGhcOptions verbosity lbi bi clbi tgtDir) )@@ -544,35 +640,35 @@ -- | Add extra C sources generated by preprocessing to build -- information.-addExtraCSources :: BuildInfo -> [FilePath] -> BuildInfo+addExtraCSources :: BuildInfo -> [SymbolicPath Pkg File] -> BuildInfo addExtraCSources bi extras = bi{cSources = new} where new = ordNub (extras ++ cSources bi) -- | Add extra C++ sources generated by preprocessing to build -- information.-addExtraCxxSources :: BuildInfo -> [FilePath] -> BuildInfo+addExtraCxxSources :: BuildInfo -> [SymbolicPath Pkg File] -> BuildInfo addExtraCxxSources bi extras = bi{cxxSources = new} where new = ordNub (extras ++ cxxSources bi) -- | Add extra C-- sources generated by preprocessing to build -- information.-addExtraCmmSources :: BuildInfo -> [FilePath] -> BuildInfo+addExtraCmmSources :: BuildInfo -> [SymbolicPath Pkg File] -> BuildInfo addExtraCmmSources bi extras = bi{cmmSources = new} where new = ordNub (extras ++ cmmSources bi) -- | Add extra ASM sources generated by preprocessing to build -- information.-addExtraAsmSources :: BuildInfo -> [FilePath] -> BuildInfo+addExtraAsmSources :: BuildInfo -> [SymbolicPath Pkg File] -> BuildInfo addExtraAsmSources bi extras = bi{asmSources = new} where new = ordNub (extras ++ asmSources bi) -- | Add extra JS sources generated by preprocessing to build -- information.-addExtraJsSources :: BuildInfo -> [FilePath] -> BuildInfo+addExtraJsSources :: BuildInfo -> [SymbolicPath Pkg File] -> BuildInfo addExtraJsSources bi extras = bi{jsSources = new} where new = ordNub (extras ++ jsSources bi)@@ -585,10 +681,10 @@ new = ordNub (extras ++ otherModules bi) -- | Add extra source dir for generated modules.-addSrcDir :: BuildInfo -> FilePath -> BuildInfo+addSrcDir :: BuildInfo -> SymbolicPath Pkg (Dir Source) -> BuildInfo addSrcDir bi extra = bi{hsSourceDirs = new} where- new = ordNub (unsafeMakeSymbolicPath extra : hsSourceDirs bi)+ new = ordNub (extra : hsSourceDirs bi) replComponent :: ReplFlags@@ -598,7 +694,7 @@ -> [PPSuffixHandler] -> Component -> ComponentLocalBuildInfo- -> FilePath+ -> SymbolicPath Pkg (Dir Dist) -> IO () replComponent _ verbosity _ _ _ (CTest TestSuite{testInterface = TestSuiteUnsupported tt}) _ _ = dieWithException verbosity $ NoSupportBuildingTestSuite tt@@ -609,16 +705,16 @@ verbosity pkg_descr lbi0- suffixes+ suffixHandlers comp@( CTest test@TestSuite{testInterface = TestSuiteLibV09{}} ) clbi distPref = do- pwd <- getCurrentDirectory+ inplaceDir <- absoluteWorkingDirLBI lbi0 let (pkg, lib, libClbi, lbi, _, _, _) =- testSuiteLibV09AsLibAndExe pkg_descr test clbi lbi0 distPref pwd- preprocessComponent pkg_descr comp lbi clbi False verbosity suffixes+ testSuiteLibV09AsLibAndExe pkg_descr test clbi lbi0 inplaceDir distPref+ preprocessComponent pkg_descr comp lbi clbi False verbosity suffixHandlers extras <- preprocessExtras verbosity comp lbi let libbi = libBuildInfo lib lib' = lib{libBuildInfo = libbi{cSources = cSources libbi ++ extras}}@@ -628,12 +724,12 @@ verbosity pkg_descr lbi- suffixes+ suffixHandlers comp clbi _ = do- preprocessComponent pkg_descr comp lbi clbi False verbosity suffixes+ preprocessComponent pkg_descr comp lbi clbi False verbosity suffixHandlers extras <- preprocessExtras verbosity comp lbi case comp of CLib lib -> do@@ -693,8 +789,9 @@ -> TestSuite -> ComponentLocalBuildInfo -> LocalBuildInfo- -> FilePath- -> FilePath+ -> AbsolutePath (Dir Pkg)+ -- ^ absolute inplace dir+ -> SymbolicPath Pkg (Dir Dist) -> ( PackageDescription , Library , ComponentLocalBuildInfo@@ -708,8 +805,8 @@ test@TestSuite{testInterface = TestSuiteLibV09 _ m} clbi lbi- distPref- pwd =+ inplaceDir+ distPref = (pkg, lib, libClbi, lbi, ipi, exe, exeClbi) where bi = testBuildInfo test@@ -753,12 +850,7 @@ , testSuites = [] , subLibraries = [lib] }- ipi = inplaceInstalledPackageInfo pwd distPref pkg (mkAbiHash "") lib lbi libClbi- testDir =- buildDir lbi- </> stubName test- </> stubName test- ++ "-tmp"+ ipi = inplaceInstalledPackageInfo inplaceDir distPref pkg (mkAbiHash "") lib lbi libClbi testLibDep = Dependency pkgName'@@ -767,11 +859,11 @@ exe = Executable { exeName = mkUnqualComponentName $ stubName test- , modulePath = stubFilePath test+ , modulePath = makeRelativePathEx $ stubFilePath test , exeScope = ExecutablePublic , buildInfo = (testBuildInfo test)- { hsSourceDirs = [unsafeMakeSymbolicPath testDir]+ { hsSourceDirs = [coerceSymbolicPath $ testBuildDir lbi test] , targetBuildDepends = testLibDep : targetBuildDepends (testBuildInfo test)@@ -811,16 +903,28 @@ createInternalPackageDB :: Verbosity -> LocalBuildInfo- -> FilePath+ -> SymbolicPath Pkg (Dir Dist) -> IO PackageDB createInternalPackageDB verbosity lbi distPref = do existsAlready <- doesPackageDBExist dbPath when existsAlready $ deletePackageDB dbPath createPackageDB verbosity (compiler lbi) (withPrograms lbi) False dbPath- return (SpecificPackageDB dbPath)+ return (SpecificPackageDB dbRelPath) where- dbPath = internalPackageDBPath lbi distPref+ dbRelPath = internalPackageDBPath lbi distPref+ dbPath = interpretSymbolicPathLBI lbi dbRelPath +-- | Update the program database to include any build-tool-depends specified+-- in the given 'BuildInfo' on build tools internal to the current package.+--+-- This function:+--+-- - adds these internal build tools to the 'ProgramDb', including+-- paths to their respective data directories,+-- - adds their paths to the current 'progSearchPath', and adds the data+-- directory environment variable for the current package to the current+-- 'progOverrideEnv', so that any programs configured from now on will be+-- able to invoke these build tools. addInternalBuildTools :: PackageDescription -> LocalBuildInfo@@ -828,14 +932,31 @@ -> ProgramDb -> ProgramDb addInternalBuildTools pkg lbi bi progs =- foldr updateProgram progs internalBuildTools+ prependProgramSearchPathNoLogging+ internalToolPaths+ [pkgDataDirVar]+ $ foldr updateProgram progs internalBuildTools where+ internalToolPaths = map (takeDirectory . programPath) internalBuildTools+ pkgDataDirVar = (pkgPathEnvVar pkg "datadir", Just dataDirPath) internalBuildTools =- [ simpleConfiguredProgram toolName' (FoundOnSystem toolLocation)+ [ (simpleConfiguredProgram toolName' (FoundOnSystem toolLocation))+ { programOverrideEnv = [pkgDataDirVar]+ } | toolName <- getAllInternalToolDependencies pkg bi , let toolName' = unUnqualComponentName toolName- , let toolLocation = buildDir lbi </> toolName' </> toolName' <.> exeExtension (hostPlatform lbi)+ , let toolLocation =+ interpretSymbolicPathLBI lbi $+ buildDir lbi+ </> makeRelativePathEx (toolName' </> toolName' <.> exeExtension (hostPlatform lbi)) ]+ mbWorkDir = mbWorkDirLBI lbi+ rawDataDir = dataDir pkg+ dataDirPath+ | null $ getSymbolicPath rawDataDir =+ interpretSymbolicPath mbWorkDir sameDirectory+ | otherwise =+ interpretSymbolicPath mbWorkDir rawDataDir -- TODO: build separate libs in separate dirs so that we can build -- multiple libs, e.g. for 'LibTest' library-style test suites@@ -916,7 +1037,15 @@ let verbosity = fromFlag $ replVerbosity flags in case compilerFlavor (compiler lbi) of GHC -> GHC.replExe flags NoFlag pkg_descr lbi exe clbi- GHCJS -> GHCJS.replExe (replOptionsFlags $ replReplOptions flags) verbosity NoFlag pkg_descr lbi exe clbi+ GHCJS ->+ GHCJS.replExe+ (replOptionsFlags $ replReplOptions flags)+ verbosity+ NoFlag+ pkg_descr+ lbi+ exe+ clbi _ -> dieWithException verbosity REPLNotSupported replFLib@@ -979,7 +1108,7 @@ -- ^ The verbosity to use -> IO () componentInitialBuildSteps _distPref pkg_descr lbi clbi verbosity = do- let compBuildDir = componentBuildDir lbi clbi+ let compBuildDir = interpretSymbolicPathLBI lbi $ componentBuildDir lbi clbi createDirectoryIfMissingVerbose verbosity True compBuildDir writeBuiltinAutogenFiles verbosity pkg_descr lbi clbi {-# DEPRECATED@@ -987,20 +1116,23 @@ "This function does not prepare all source files for a component. Suggestion: use 'Setup repl <compName> --repl-multi-file=<fn>'." #-} --- | Pre-build steps for a component: creates the autogenerated files--- for a particular configured component.+-- | Creates the autogenerated files for a particular configured component,+-- and runs the pre-build hook. preBuildComponent- :: Verbosity+ :: (LocalBuildInfo -> TargetInfo -> IO ())+ -- ^ pre-build hook+ -> Verbosity -> LocalBuildInfo -- ^ Configuration information -> TargetInfo -> IO ()-preBuildComponent verbosity lbi tgt = do+preBuildComponent preBuildHook verbosity lbi tgt = do let pkg_descr = localPkgDescr lbi clbi = targetCLBI tgt- compBuildDir = componentBuildDir lbi clbi+ compBuildDir = interpretSymbolicPathLBI lbi $ componentBuildDir lbi clbi createDirectoryIfMissingVerbose verbosity True compBuildDir writeBuiltinAutogenFiles verbosity pkg_descr lbi clbi+ preBuildHook lbi tgt -- | Generate and write to disk all built-in autogenerated files -- for the specified component. These files will be put in the@@ -1106,4 +1238,4 @@ -- Write the contents of the file. rewriteFileLBS verbosity path contents where- autogenDir = autogenComponentModulesDir lbi clbi+ autogenDir = interpretSymbolicPathLBI lbi $ autogenComponentModulesDir lbi clbi
src/Distribution/Simple/Build/Inputs.hs view
@@ -18,13 +18,17 @@ , BuildingWhat (..) , LocalBuildInfo (..) , TargetInfo (..)+ , buildingWhatCommonFlags , buildingWhatVerbosity+ , buildingWhatWorkingDir , buildingWhatDistPref ) where import Distribution.Simple.Compiler-import Distribution.Simple.Setup (BuildingWhat (..), buildingWhatDistPref, buildingWhatVerbosity)+import Distribution.Simple.Setup hiding+ ( BuildFlags (buildVerbosity)+ ) import Distribution.Types.BuildInfo import Distribution.Types.Component import Distribution.Types.ComponentLocalBuildInfo
src/Distribution/Simple/BuildPaths.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} @@ -18,6 +19,9 @@ , srcPref , buildInfoPref , haddockDirName+ , haddockLibraryDirPath+ , haddockTestDirPath+ , haddockBenchmarkDirPath , hscolourPref , haddockPref , autogenPackageModulesDir@@ -25,12 +29,17 @@ , autogenPathsModuleName , autogenPackageInfoModuleName , cppHeaderName- , haddockName+ , haddockPath+ , haddockPackageLibraryName+ , haddockPackageLibraryName'+ , haddockLibraryName+ , haddockLibraryPath , mkGenericStaticLibName , mkLibName , mkProfLibName , mkGenericSharedLibName , mkSharedLibName+ , mkProfSharedLibName , mkStaticLibName , mkGenericSharedBundledLibName , exeExtension@@ -42,9 +51,14 @@ , getSourceFiles , getLibSourceFiles , getExeSourceFiles+ , getTestSourceFiles+ , getBenchmarkSourceFiles , getFLibSourceFiles , exeBuildDir , flibBuildDir+ , stubName+ , testBuildDir+ , benchmarkBuildDir ) where import Distribution.Compat.Prelude@@ -59,13 +73,12 @@ import Distribution.Simple.Errors import Distribution.Simple.LocalBuildInfo import Distribution.Simple.PreProcess.Types (builtinHaskellSuffixes)-import Distribution.Simple.Setup.Common (defaultDistPref)+import Distribution.Simple.Setup.Common import Distribution.Simple.Setup.Haddock (HaddockTarget (..)) import Distribution.Simple.Utils import Distribution.System import Distribution.Utils.Path import Distribution.Verbosity-import System.FilePath (normalise, (<.>), (</>)) -- --------------------------------------------------------------------------- -- Build directories and files@@ -73,33 +86,77 @@ srcPref :: FilePath -> FilePath srcPref distPref = distPref </> "src" -hscolourPref :: HaddockTarget -> FilePath -> PackageDescription -> FilePath+hscolourPref+ :: HaddockTarget+ -> SymbolicPath root (Dir Dist)+ -> PackageDescription+ -> SymbolicPath root (Dir Artifacts) hscolourPref = haddockPref -- | Build info json file, generated in every build-buildInfoPref :: FilePath -> FilePath-buildInfoPref distPref = distPref </> "build-info.json"+buildInfoPref+ :: SymbolicPath root (Dir Dist)+ -> SymbolicPath root File+buildInfoPref distPref = distPref </> makeRelativePathEx "build-info.json" -- | This is the name of the directory in which the generated haddocks -- should be stored. It does not include the @<dist>/doc/html@ prefix.+--+-- It is also used by `haddock-project` when constructing its output directory. haddockDirName :: HaddockTarget -> PackageDescription -> FilePath haddockDirName ForDevelopment = prettyShow . packageName haddockDirName ForHackage = (++ "-docs") . prettyShow . packageId +-- | This is the name of the directory in which the generated haddocks for+-- a (sub)library should be stored. It does not include the @<dist>/doc/html@+-- prefix.+--+-- It is also used by `haddock-project` when constructing its output directory.+haddockLibraryDirPath+ :: HaddockTarget+ -> PackageDescription+ -> Library+ -> FilePath+haddockLibraryDirPath haddockTarget pkg_descr lib =+ case libName lib of+ LSubLibName sublib_name ->+ haddockDirName haddockTarget pkg_descr </> prettyShow sublib_name+ _ -> haddockDirName haddockTarget pkg_descr++haddockTestDirPath+ :: HaddockTarget+ -> PackageDescription+ -> TestSuite+ -> FilePath+haddockTestDirPath haddockTarget pkg_descr test =+ haddockDirName haddockTarget pkg_descr </> prettyShow (testName test)++haddockBenchmarkDirPath+ :: HaddockTarget+ -> PackageDescription+ -> Benchmark+ -> FilePath+haddockBenchmarkDirPath haddockTarget pkg_descr bench =+ haddockDirName haddockTarget pkg_descr </> prettyShow (benchmarkName bench)+ -- | The directory to which generated haddock documentation should be written.-haddockPref :: HaddockTarget -> FilePath -> PackageDescription -> FilePath+haddockPref+ :: HaddockTarget+ -> SymbolicPath root (Dir Dist)+ -> PackageDescription+ -> SymbolicPath root (Dir Artifacts) haddockPref haddockTarget distPref pkg_descr =- distPref </> "doc" </> "html" </> haddockDirName haddockTarget pkg_descr+ distPref </> makeRelativePathEx ("doc" </> "html" </> haddockDirName haddockTarget pkg_descr) -- | The directory in which we put auto-generated modules for EVERY -- component in the package.-autogenPackageModulesDir :: LocalBuildInfo -> String-autogenPackageModulesDir lbi = buildDir lbi </> "global-autogen"+autogenPackageModulesDir :: LocalBuildInfo -> SymbolicPath Pkg (Dir Source)+autogenPackageModulesDir lbi = buildDir lbi </> makeRelativePathEx "global-autogen" -- | The directory in which we put auto-generated modules for a -- particular component.-autogenComponentModulesDir :: LocalBuildInfo -> ComponentLocalBuildInfo -> String-autogenComponentModulesDir lbi clbi = componentBuildDir lbi clbi </> "autogen"+autogenComponentModulesDir :: LocalBuildInfo -> ComponentLocalBuildInfo -> SymbolicPath Pkg (Dir Source)+autogenComponentModulesDir lbi clbi = componentBuildDir lbi clbi </> makeRelativePathEx "autogen" -- NB: Look at 'checkForeignDeps' for where a simplified version of this -- has been copy-pasted.@@ -125,9 +182,36 @@ fixchar '-' = '_' fixchar c = c -haddockName :: PackageDescription -> FilePath-haddockName pkg_descr = prettyShow (packageName pkg_descr) <.> "haddock"+haddockPath :: PackageDescription -> FilePath+haddockPath pkg_descr = prettyShow (packageName pkg_descr) <.> "haddock" +-- | A name of a (sub)library used by haddock, in the form+-- `<package>:<library>` if it is a sublibrary, or `<package>` if it is the+-- main library.+--+-- Used by `haddock-project` and `Distribution.Simple.Haddock`.+haddockPackageLibraryName :: PackageDescription -> Library -> String+haddockPackageLibraryName pkg_descr lib =+ haddockPackageLibraryName' (packageName pkg_descr) (libName lib)++haddockPackageLibraryName' :: PackageName -> LibraryName -> String+haddockPackageLibraryName' pkg_name lib_name =+ case lib_name of+ LSubLibName sublib_name ->+ prettyShow pkg_name ++ ":" ++ prettyShow sublib_name+ LMainLibName -> prettyShow pkg_name++-- | A name of a (sub)library used by haddock.+haddockLibraryName :: PackageDescription -> Library -> String+haddockLibraryName pkg_descr lib =+ case libName lib of+ LSubLibName sublib_name -> prettyShow sublib_name+ LMainLibName -> prettyShow (packageName pkg_descr)++-- | File path of the ".haddock" file.+haddockLibraryPath :: PackageDescription -> Library -> FilePath+haddockLibraryPath pkg_descr lib = haddockLibraryName pkg_descr lib <.> "haddock"+ -- ----------------------------------------------------------------------------- -- Source File helper @@ -136,14 +220,16 @@ -> LocalBuildInfo -> Library -> ComponentLocalBuildInfo- -> IO [(ModuleName.ModuleName, FilePath)]-getLibSourceFiles verbosity lbi lib clbi = getSourceFiles verbosity searchpaths modules+ -> IO [(ModuleName.ModuleName, SymbolicPath Pkg File)]+getLibSourceFiles verbosity lbi lib clbi =+ getSourceFiles verbosity mbWorkDir searchpaths modules where bi = libBuildInfo lib modules = allLibModules lib clbi+ mbWorkDir = mbWorkDirLBI lbi searchpaths =- componentBuildDir lbi clbi- : map getSymbolicPath (hsSourceDirs bi)+ coerceSymbolicPath (componentBuildDir lbi clbi)+ : hsSourceDirs bi ++ [ autogenComponentModulesDir lbi clbi , autogenPackageModulesDir lbi ]@@ -153,61 +239,133 @@ -> LocalBuildInfo -> Executable -> ComponentLocalBuildInfo- -> IO [(ModuleName.ModuleName, FilePath)]+ -> IO [(ModuleName.ModuleName, SymbolicPath Pkg 'File)] getExeSourceFiles verbosity lbi exe clbi = do- moduleFiles <- getSourceFiles verbosity searchpaths modules- srcMainPath <- findFileEx verbosity (map getSymbolicPath $ hsSourceDirs bi) (modulePath exe)+ moduleFiles <- getSourceFiles verbosity mbWorkDir searchpaths modules+ srcMainPath <- findFileCwd verbosity mbWorkDir (hsSourceDirs bi) (modulePath exe) return ((ModuleName.main, srcMainPath) : moduleFiles) where+ mbWorkDir = mbWorkDirLBI lbi bi = buildInfo exe modules = otherModules bi searchpaths = autogenComponentModulesDir lbi clbi : autogenPackageModulesDir lbi- : exeBuildDir lbi exe- : map getSymbolicPath (hsSourceDirs bi)+ : coerceSymbolicPath (exeBuildDir lbi exe)+ : hsSourceDirs bi +getTestSourceFiles+ :: Verbosity+ -> LocalBuildInfo+ -> TestSuite+ -> ComponentLocalBuildInfo+ -> IO [(ModuleName.ModuleName, SymbolicPath Pkg 'File)]+getTestSourceFiles verbosity lbi test@TestSuite{testInterface = TestSuiteExeV10 _ path} clbi = do+ moduleFiles <- getSourceFiles verbosity mbWorkDir searchpaths modules+ srcMainPath <- findFileCwd verbosity mbWorkDir (hsSourceDirs bi) path+ return ((ModuleName.main, srcMainPath) : moduleFiles)+ where+ mbWorkDir = mbWorkDirLBI lbi+ bi = testBuildInfo test+ modules = otherModules bi+ searchpaths =+ autogenComponentModulesDir lbi clbi+ : autogenPackageModulesDir lbi+ : coerceSymbolicPath (testBuildDir lbi test)+ : hsSourceDirs bi+getTestSourceFiles _ _ _ _ = return []++getBenchmarkSourceFiles+ :: Verbosity+ -> LocalBuildInfo+ -> Benchmark+ -> ComponentLocalBuildInfo+ -> IO [(ModuleName.ModuleName, SymbolicPath Pkg 'File)]+getBenchmarkSourceFiles verbosity lbi bench@Benchmark{benchmarkInterface = BenchmarkExeV10 _ path} clbi = do+ moduleFiles <- getSourceFiles verbosity mbWorkDir searchpaths modules+ srcMainPath <- findFileCwd verbosity mbWorkDir (hsSourceDirs bi) path+ return ((ModuleName.main, srcMainPath) : moduleFiles)+ where+ mbWorkDir = mbWorkDirLBI lbi+ bi = benchmarkBuildInfo bench+ modules = otherModules bi+ searchpaths =+ autogenComponentModulesDir lbi clbi+ : autogenPackageModulesDir lbi+ : coerceSymbolicPath (benchmarkBuildDir lbi bench)+ : hsSourceDirs bi+getBenchmarkSourceFiles _ _ _ _ = return []+ getFLibSourceFiles :: Verbosity -> LocalBuildInfo -> ForeignLib -> ComponentLocalBuildInfo- -> IO [(ModuleName.ModuleName, FilePath)]-getFLibSourceFiles verbosity lbi flib clbi = getSourceFiles verbosity searchpaths modules+ -> IO [(ModuleName.ModuleName, SymbolicPath Pkg File)]+getFLibSourceFiles verbosity lbi flib clbi =+ getSourceFiles verbosity mbWorkDir searchpaths modules where bi = foreignLibBuildInfo flib modules = otherModules bi+ mbWorkDir = mbWorkDirLBI lbi searchpaths = autogenComponentModulesDir lbi clbi : autogenPackageModulesDir lbi- : flibBuildDir lbi flib- : map getSymbolicPath (hsSourceDirs bi)+ : coerceSymbolicPath (flibBuildDir lbi flib)+ : hsSourceDirs bi getSourceFiles :: Verbosity- -> [FilePath]+ -> Maybe (SymbolicPath CWD ('Dir Pkg))+ -> [SymbolicPathX allowAbsolute Pkg (Dir Source)] -> [ModuleName.ModuleName]- -> IO [(ModuleName.ModuleName, FilePath)]-getSourceFiles verbosity dirs modules = flip traverse modules $ \m ->+ -> IO [(ModuleName.ModuleName, SymbolicPathX allowAbsolute Pkg File)]+getSourceFiles verbosity mbWorkDir dirs modules = flip traverse modules $ \m -> fmap ((,) m) $- findFileWithExtension builtinHaskellSuffixes dirs (ModuleName.toFilePath m)- >>= maybe (notFound m) (return . normalise)+ findFileCwdWithExtension+ mbWorkDir+ builtinHaskellSuffixes+ dirs+ (moduleNameSymbolicPath m)+ >>= maybe (notFound m) (return . normaliseSymbolicPath) where notFound module_ = dieWithException verbosity $ CantFindSourceModule module_ -- | The directory where we put build results for an executable-exeBuildDir :: LocalBuildInfo -> Executable -> FilePath-exeBuildDir lbi exe = buildDir lbi </> nm </> nm ++ "-tmp"+exeBuildDir :: LocalBuildInfo -> Executable -> SymbolicPath Pkg (Dir Build)+exeBuildDir lbi exe = buildDir lbi </> makeRelativePathEx (nm </> nm ++ "-tmp") where nm = unUnqualComponentName $ exeName exe -- | The directory where we put build results for a foreign library-flibBuildDir :: LocalBuildInfo -> ForeignLib -> FilePath-flibBuildDir lbi flib = buildDir lbi </> nm </> nm ++ "-tmp"+flibBuildDir :: LocalBuildInfo -> ForeignLib -> SymbolicPath Pkg (Dir Build)+flibBuildDir lbi flib = buildDir lbi </> makeRelativePathEx (nm </> nm ++ "-tmp") where nm = unUnqualComponentName $ foreignLibName flib +-- | The name of the stub executable associated with a library 'TestSuite'.+stubName :: TestSuite -> FilePath+stubName t = unUnqualComponentName (testName t) ++ "Stub"++-- | The directory where we put build results for a test suite+testBuildDir :: LocalBuildInfo -> TestSuite -> SymbolicPath Pkg (Dir Build)+testBuildDir lbi tst =+ buildDir lbi </> makeRelativePathEx testDir+ where+ testDir = case testInterface tst of+ TestSuiteLibV09{} ->+ stubName tst </> stubName tst ++ "-tmp"+ _ -> nm </> nm ++ "-tmp"+ nm = unUnqualComponentName $ testName tst++-- | The directory where we put build results for a benchmark suite+benchmarkBuildDir :: LocalBuildInfo -> Benchmark -> SymbolicPath Pkg (Dir Build)+benchmarkBuildDir lbi bm =+ buildDir lbi </> makeRelativePathEx (nm </> nm ++ "-tmp")+ where+ nm = unUnqualComponentName $ benchmarkName bm+ -- --------------------------------------------------------------------------- -- Library file names @@ -237,6 +395,10 @@ mkSharedLibName :: Platform -> CompilerId -> UnitId -> String mkSharedLibName platform comp lib = mkGenericSharedLibName platform comp (getHSLibraryName lib)++mkProfSharedLibName :: Platform -> CompilerId -> UnitId -> String+mkProfSharedLibName platform comp lib =+ mkGenericSharedLibName platform comp (getHSLibraryName lib ++ "_p") -- Static libs are named the same as shared libraries, only with -- a different extension.
src/Distribution/Simple/BuildTarget.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE FlexibleContexts #-}@@ -496,12 +497,12 @@ , cinfoStrName = componentStringName pkg (componentName c) , cinfoSrcDirs = map getSymbolicPath $ hsSourceDirs bi , cinfoModules = componentModules c- , cinfoHsFiles = componentHsFiles c- , cinfoAsmFiles = asmSources bi- , cinfoCmmFiles = cmmSources bi- , cinfoCFiles = cSources bi- , cinfoCxxFiles = cxxSources bi- , cinfoJsFiles = jsSources bi+ , cinfoHsFiles = map getSymbolicPath $ componentHsFiles c+ , cinfoAsmFiles = map getSymbolicPath $ asmSources bi+ , cinfoCmmFiles = map getSymbolicPath $ cmmSources bi+ , cinfoCFiles = map getSymbolicPath $ cSources bi+ , cinfoCxxFiles = map getSymbolicPath $ cxxSources bi+ , cinfoJsFiles = map getSymbolicPath $ jsSources bi } | c <- pkgComponents pkg , let bi = componentBuildInfo c@@ -529,7 +530,7 @@ componentModules (CTest test) = testModules test componentModules (CBench bench) = benchmarkModules bench -componentHsFiles :: Component -> [FilePath]+componentHsFiles :: Component -> [RelativePath Source File] componentHsFiles (CExe exe) = [modulePath exe] componentHsFiles ( CTest
+ src/Distribution/Simple/BuildWay.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE LambdaCase #-}++module Distribution.Simple.BuildWay where++data BuildWay = StaticWay | DynWay | ProfWay | ProfDynWay+ deriving (Eq, Ord, Show, Read, Enum)++-- | Returns the object/interface extension prefix for the given build way (e.g. "dyn_" for 'DynWay')+buildWayPrefix :: BuildWay -> String+buildWayPrefix = \case+ StaticWay -> ""+ ProfWay -> "p_"+ DynWay -> "dyn_"+ ProfDynWay -> "p_dyn_"
src/Distribution/Simple/Command.hs view
@@ -1,6 +1,8 @@ {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-} ----------------------------------------------------------------------------- @@ -64,6 +66,7 @@ -- * Option Descriptions , OptDescr (..)+ , fmapOptDescr , Description , SFlags , LFlags@@ -150,6 +153,16 @@ OptFlags {-False-} (Bool -> a -> a) (a -> Maybe Bool)++fmapOptDescr :: forall a b. (b -> a) -> (a -> (b -> b)) -> OptDescr a -> OptDescr b+fmapOptDescr x u = \case+ ReqArg d o p upd get -> ReqArg d o p (fmap m upd) (get . x)+ OptArg d o p upd (str, g) get -> OptArg d o p (fmap m upd) (str, m g) (get . x)+ ChoiceOpt opts -> ChoiceOpt $ fmap (\(d, o, upd, get) -> (d, o, m upd, get . x)) opts+ BoolOpt d true false upd get -> BoolOpt d true false (\b -> m $ upd b) (get . x)+ where+ m :: (a -> a) -> (b -> b)+ m upd_a b = u (upd_a $ x b) b -- | Short command line option strings type SFlags = [Char]
src/Distribution/Simple/Compiler.hs view
@@ -1,5 +1,9 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveFoldable #-}+{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveTraversable #-} ----------------------------------------------------------------------------- @@ -34,11 +38,21 @@ , compilerInfo -- * Support for package databases- , PackageDB (..)+ , PackageDB , PackageDBStack+ , PackageDBCWD+ , PackageDBStackCWD+ , PackageDBX (..)+ , PackageDBStackX+ , PackageDBS+ , PackageDBStackS , registrationPackageDB , absolutePackageDBPaths , absolutePackageDBPath+ , interpretPackageDB+ , interpretPackageDBStack+ , coercePackageDB+ , coercePackageDBStack -- * Support for optimisation levels , OptimisationLevel (..)@@ -62,6 +76,11 @@ , unitIdSupported , coverageSupported , profilingSupported+ , profilingDynamicSupported+ , profilingDynamicSupportedOrUnknown+ , profilingVanillaSupported+ , profilingVanillaSupportedOrUnknown+ , dynamicSupported , backpackSupported , arResponseFilesSupported , arDashLSupported@@ -82,7 +101,9 @@ import Distribution.Compiler import Distribution.Simple.Utils+import Distribution.Utils.Path import Distribution.Version+ import Language.Haskell.Extension import qualified Data.Map as Map (lookup)@@ -172,14 +193,17 @@ -- the file system. This can be used to build isolated environments of -- packages, for example to build a collection of related packages -- without installing them globally.-data PackageDB+--+-- Abstracted over+data PackageDBX fp = GlobalPackageDB | UserPackageDB- | SpecificPackageDB FilePath- deriving (Eq, Generic, Ord, Show, Read, Typeable)+ | -- | NB: the path might be relative or it might be absolute+ SpecificPackageDB fp+ deriving (Eq, Generic, Ord, Show, Read, Typeable, Functor, Foldable, Traversable) -instance Binary PackageDB-instance Structured PackageDB+instance Binary fp => Binary (PackageDBX fp)+instance Structured fp => Structured (PackageDBX fp) -- | We typically get packages from several databases, and stack them -- together. This type lets us be explicit about that stacking. For example@@ -196,25 +220,64 @@ -- we can use several custom package dbs and the user package db together. -- -- When it comes to writing, the top most (last) package is used.-type PackageDBStack = [PackageDB]+type PackageDBStackX from = [PackageDBX from] +type PackageDB = PackageDBX (SymbolicPath Pkg (Dir PkgDB))+type PackageDBStack = PackageDBStackX (SymbolicPath Pkg (Dir PkgDB))++type PackageDBS from = PackageDBX (SymbolicPath from (Dir PkgDB))+type PackageDBStackS from = PackageDBStackX (SymbolicPath from (Dir PkgDB))++type PackageDBCWD = PackageDBX FilePath+type PackageDBStackCWD = PackageDBStackX FilePath+ -- | Return the package that we should register into. This is the package db at -- the top of the stack.-registrationPackageDB :: PackageDBStack -> PackageDB+registrationPackageDB :: PackageDBStackX from -> PackageDBX from registrationPackageDB dbs = case safeLast dbs of Nothing -> error "internal error: empty package db set" Just p -> p -- | Make package paths absolute-absolutePackageDBPaths :: PackageDBStack -> IO PackageDBStack-absolutePackageDBPaths = traverse absolutePackageDBPath+absolutePackageDBPaths+ :: Maybe (SymbolicPath CWD (Dir Pkg))+ -> PackageDBStack+ -> IO PackageDBStack+absolutePackageDBPaths mbWorkDir = traverse $ absolutePackageDBPath mbWorkDir -absolutePackageDBPath :: PackageDB -> IO PackageDB-absolutePackageDBPath GlobalPackageDB = return GlobalPackageDB-absolutePackageDBPath UserPackageDB = return UserPackageDB-absolutePackageDBPath (SpecificPackageDB db) =- SpecificPackageDB `liftM` canonicalizePath db+absolutePackageDBPath+ :: Maybe (SymbolicPath CWD (Dir Pkg))+ -> PackageDB+ -> IO PackageDB+absolutePackageDBPath _ GlobalPackageDB = return GlobalPackageDB+absolutePackageDBPath _ UserPackageDB = return UserPackageDB+absolutePackageDBPath mbWorkDir (SpecificPackageDB db) = do+ let db' =+ case symbolicPathRelative_maybe db of+ Nothing -> getSymbolicPath db+ Just rel_path -> interpretSymbolicPath mbWorkDir rel_path+ SpecificPackageDB . makeSymbolicPath <$> canonicalizePath db' +interpretPackageDB :: Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDB -> PackageDBCWD+interpretPackageDB _ GlobalPackageDB = GlobalPackageDB+interpretPackageDB _ UserPackageDB = UserPackageDB+interpretPackageDB mbWorkDir (SpecificPackageDB db) =+ SpecificPackageDB (interpretSymbolicPath mbWorkDir db)++interpretPackageDBStack :: Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDBStack -> PackageDBStackCWD+interpretPackageDBStack mbWorkDir = map (interpretPackageDB mbWorkDir)++-- | Transform a package db using a FilePath into one using symbolic paths.+coercePackageDB :: PackageDBCWD -> PackageDBX (SymbolicPath CWD (Dir PkgDB))+coercePackageDB GlobalPackageDB = GlobalPackageDB+coercePackageDB UserPackageDB = UserPackageDB+coercePackageDB (SpecificPackageDB db) = SpecificPackageDB (makeSymbolicPath db)++coercePackageDBStack+ :: [PackageDBCWD]+ -> [PackageDBX (SymbolicPath CWD (Dir PkgDB))]+coercePackageDBStack = map coercePackageDB+ -- ------------------------------------------------------------ -- * Optimisation levels@@ -412,6 +475,49 @@ GHC -> True GHCJS -> True _ -> False++-- | Returns Just if we can certainly determine whether a way is supported+-- if we don't know, return Nothing+waySupported :: String -> Compiler -> Maybe Bool+waySupported way comp =+ case compilerFlavor comp of+ GHC ->+ -- Infomation about compiler ways is only accurately reported after+ -- 9.10.1. Which is useful as this is before profiling dynamic support+ -- was introduced. (See GHC #24881)+ if compilerVersion comp >= mkVersion [9, 10, 1]+ then case Map.lookup "RTS ways" (compilerProperties comp) of+ Just ways -> Just (way `elem` words ways)+ Nothing -> Just False+ else Nothing+ _ -> Nothing++-- | Either profiling is definitely supported or we don't know (so assume+-- it is)+profilingVanillaSupportedOrUnknown :: Compiler -> Bool+profilingVanillaSupportedOrUnknown comp = profilingVanillaSupported comp `elem` [Just True, Nothing]++-- | Is the compiler distributed with profiling libraries+profilingVanillaSupported :: Compiler -> Maybe Bool+profilingVanillaSupported comp = waySupported "p" comp++-- | Is the compiler distributed with profiling dynamic libraries+profilingDynamicSupported :: Compiler -> Maybe Bool+profilingDynamicSupported comp =+ -- Certainly not before this version, as it was not implemented yet.+ if compilerVersion comp <= mkVersion [9, 11, 0]+ then Just False+ else waySupported "p_dyn" comp++-- | Either profiling dynamic is definitely supported or we don't know (so assume+-- it is)+profilingDynamicSupportedOrUnknown :: Compiler -> Bool+profilingDynamicSupportedOrUnknown comp =+ profilingDynamicSupported comp `elem` [Just True, Nothing]++-- | Is the compiler distributed with dynamic libraries+dynamicSupported :: Compiler -> Maybe Bool+dynamicSupported comp = waySupported "dyn" comp -- | Does this compiler support a package database entry with: -- "visibility"?
src/Distribution/Simple/Configure.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE NamedFieldPuns #-}@@ -31,6 +32,7 @@ -- level. module Distribution.Simple.Configure ( configure+ , configure_setupHooks , writePersistBuildConfig , getConfigStateFile , getPersistBuildConfig@@ -79,15 +81,28 @@ import Distribution.PackageDescription.PrettyPrint import Distribution.Simple.BuildTarget import Distribution.Simple.BuildToolDepends+import Distribution.Simple.BuildWay import Distribution.Simple.Compiler import Distribution.Simple.LocalBuildInfo import Distribution.Simple.PackageIndex (InstalledPackageIndex, lookupUnitId) import qualified Distribution.Simple.PackageIndex as PackageIndex import Distribution.Simple.PreProcess import Distribution.Simple.Program-import Distribution.Simple.Program.Db (lookupProgramByName, modifyProgramSearchPath, prependProgramSearchPath)+import Distribution.Simple.Program.Db+ ( ProgramDb (..)+ , lookupProgramByName+ , modifyProgramSearchPath+ , prependProgramSearchPath+ , updateConfiguredProgs+ ) import Distribution.Simple.Setup.Common as Setup import Distribution.Simple.Setup.Config as Setup+import Distribution.Simple.SetupHooks.Internal+ ( ConfigureHooks (..)+ , applyComponentDiffs+ , noConfigureHooks+ )+import qualified Distribution.Simple.SetupHooks.Internal as SetupHooks import Distribution.Simple.Utils import Distribution.System import Distribution.Types.ComponentRequestedSpec@@ -131,6 +146,9 @@ , pretty , prettyShow )+import Distribution.Simple.Errors+import Distribution.Types.AnnotatedId+import Distribution.Utils.Path import Distribution.Utils.Structured (structuredDecodeOrFailIO, structuredEncode) import System.Directory ( canonicalizePath@@ -141,8 +159,6 @@ ) import System.FilePath ( isAbsolute- , takeDirectory- , (</>) ) import System.IO ( hClose@@ -165,8 +181,6 @@ import qualified Data.Maybe as M import qualified Data.Set as Set import qualified Distribution.Compat.NonEmptySet as NES-import Distribution.Simple.Errors-import Distribution.Types.AnnotatedId type UseExternalInternalDeps = Bool @@ -180,6 +194,9 @@ ConfigStateFileNoParse | -- | No file! ConfigStateFileMissing+ { cfgStateFileErrorCwd :: Maybe (SymbolicPath CWD (Dir Pkg))+ , cfgStateFileErrorFile :: SymbolicPath Pkg File+ } | -- | Mismatched version. ConfigStateFileBadVersion PackageIdentifier@@ -191,20 +208,20 @@ dispConfigStateFileError :: ConfigStateFileError -> Doc dispConfigStateFileError ConfigStateFileNoHeader = text "Saved package config file header is missing."- <+> text "Re-run the 'configure' command."+ <+> text "Re-run the 'Setup configure' command." dispConfigStateFileError ConfigStateFileBadHeader = text "Saved package config file header is corrupt."- <+> text "Re-run the 'configure' command."+ <+> text "Re-run the 'Setup configure' command." dispConfigStateFileError ConfigStateFileNoParse = text "Saved package config file is corrupt."- <+> text "Re-run the 'configure' command."-dispConfigStateFileError ConfigStateFileMissing =- text "Run the 'configure' command first."+ <+> text "Re-run the 'Setup configure' command."+dispConfigStateFileError ConfigStateFileMissing{} =+ text "Run the 'Setup configure' command first." dispConfigStateFileError (ConfigStateFileBadVersion oldCabal oldCompiler _) = text "Saved package config file is outdated:" $+$ badCabal $+$ badCompiler- $+$ text "Re-run the 'configure' command."+ $+$ text "Re-run the 'Setup configure' command." where badCabal = text "• the Cabal version changed from"@@ -228,12 +245,14 @@ -- missing, if the file cannot be read, or if the file was created by an older -- version of Cabal. getConfigStateFile- :: FilePath+ :: Maybe (SymbolicPath CWD (Dir Pkg))+ -> SymbolicPath Pkg File -- ^ The file path of the @setup-config@ file. -> IO LocalBuildInfo-getConfigStateFile filename = do+getConfigStateFile mbWorkDir setupConfigFile = do+ let filename = interpretSymbolicPath mbWorkDir setupConfigFile exists <- doesFileExist filename- unless exists $ throwIO ConfigStateFileMissing+ unless exists $ throwIO $ ConfigStateFileMissing mbWorkDir setupConfigFile -- 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@@ -258,48 +277,60 @@ -- | Read the 'localBuildInfoFile', returning either an error or the local build -- info. tryGetConfigStateFile- :: FilePath+ :: Maybe (SymbolicPath CWD (Dir Pkg))+ -- ^ Working directory.+ -> SymbolicPath Pkg File -- ^ The file path of the @setup-config@ file. -> IO (Either ConfigStateFileError LocalBuildInfo)-tryGetConfigStateFile = try . getConfigStateFile+tryGetConfigStateFile mbWorkDir = try . getConfigStateFile mbWorkDir -- | Try to read the 'localBuildInfoFile'. tryGetPersistBuildConfig- :: FilePath+ :: Maybe (SymbolicPath CWD (Dir Pkg))+ -- ^ Working directory.+ -> SymbolicPath Pkg (Dir Dist) -- ^ The @dist@ directory path. -> IO (Either ConfigStateFileError LocalBuildInfo)-tryGetPersistBuildConfig = try . getPersistBuildConfig+tryGetPersistBuildConfig mbWorkDir = try . getPersistBuildConfig mbWorkDir -- | 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+ :: Maybe (SymbolicPath CWD (Dir Pkg))+ -- ^ Working directory.+ -> SymbolicPath Pkg (Dir Dist) -- ^ The @dist@ directory path. -> IO LocalBuildInfo-getPersistBuildConfig = getConfigStateFile . localBuildInfoFile+getPersistBuildConfig mbWorkDir distPref =+ getConfigStateFile mbWorkDir $ localBuildInfoFile distPref -- | Try to read the 'localBuildInfoFile'. maybeGetPersistBuildConfig- :: FilePath+ :: Maybe (SymbolicPath CWD (Dir Pkg))+ -- ^ Working directory.+ -> SymbolicPath Pkg (Dir Dist) -- ^ The @dist@ directory path. -> IO (Maybe LocalBuildInfo)-maybeGetPersistBuildConfig =- liftM (either (const Nothing) Just) . tryGetPersistBuildConfig+maybeGetPersistBuildConfig mbWorkDir =+ liftM (either (const Nothing) Just) . tryGetPersistBuildConfig mbWorkDir -- | After running configure, output the 'LocalBuildInfo' to the -- 'localBuildInfoFile'. writePersistBuildConfig- :: FilePath+ :: Maybe (SymbolicPath CWD (Dir Pkg))+ -- ^ Working directory+ -> SymbolicPath Pkg (Dir Dist) -- ^ The @dist@ directory path. -> LocalBuildInfo -- ^ The 'LocalBuildInfo' to write. -> IO ()-writePersistBuildConfig distPref lbi = do- createDirectoryIfMissing False distPref- writeFileAtomic (localBuildInfoFile distPref) $+writePersistBuildConfig mbWorkDir distPref lbi = do+ createDirectoryIfMissing False (i distPref)+ writeFileAtomic (i $ localBuildInfoFile distPref) $ BLC8.unlines [showHeader pkgId, structuredEncode lbi] where+ i = interpretSymbolicPath mbWorkDir -- See Note [Symbolic paths] in Distribution.Utils.Path pkgId = localPackage lbi -- | Identifier of the current Cabal package.@@ -359,16 +390,22 @@ -- | Check that localBuildInfoFile is up-to-date with respect to the -- .cabal file.-checkPersistBuildConfigOutdated :: FilePath -> FilePath -> IO Bool-checkPersistBuildConfigOutdated distPref pkg_descr_file =- pkg_descr_file `moreRecentFile` localBuildInfoFile distPref+checkPersistBuildConfigOutdated+ :: Maybe (SymbolicPath CWD (Dir Pkg))+ -> SymbolicPath Pkg (Dir Dist)+ -> SymbolicPath Pkg File+ -> IO Bool+checkPersistBuildConfigOutdated mbWorkDir distPref pkg_descr_file =+ i pkg_descr_file `moreRecentFile` i (localBuildInfoFile distPref)+ where+ i = interpretSymbolicPath mbWorkDir -- See Note [Symbolic paths] in Distribution.Utils.Path -- | Get the path of @dist\/setup-config@. localBuildInfoFile- :: FilePath+ :: SymbolicPath Pkg (Dir Dist) -- ^ The @dist@ directory path.- -> FilePath-localBuildInfoFile distPref = distPref </> "setup-config"+ -> SymbolicPath Pkg File+localBuildInfoFile distPref = distPref </> makeRelativePathEx "setup-config" -- ----------------------------------------------------------------------------- @@ -380,18 +417,18 @@ -- from (in order of highest to lowest preference) the override prefix, the -- \"CABAL_BUILDDIR\" environment variable, or the default prefix. findDistPref- :: FilePath+ :: SymbolicPath Pkg (Dir Dist) -- ^ default \"dist\" prefix- -> Setup.Flag FilePath+ -> Setup.Flag (SymbolicPath Pkg (Dir Dist)) -- ^ override \"dist\" prefix- -> IO FilePath+ -> IO (SymbolicPath Pkg (Dir Dist)) findDistPref defDistPref overrideDistPref = do envDistPref <- liftM parseEnvDistPref (lookupEnv "CABAL_BUILDDIR") return $ fromFlagOrDefault defDistPref (mappend envDistPref overrideDistPref) where parseEnvDistPref env = case env of- Just distPref | not (null distPref) -> toFlag distPref+ Just distPref | not (null distPref) -> toFlag $ makeSymbolicPath distPref _ -> NoFlag -- | Return the \"dist/\" prefix, or the default prefix. The prefix is taken@@ -401,9 +438,9 @@ -- set. (The @*DistPref@ flags are always set to a definite value before -- invoking 'UserHooks'.) findDistPrefOrDefault- :: Setup.Flag FilePath+ :: Setup.Flag (SymbolicPath Pkg (Dir Dist)) -- ^ override \"dist\" prefix- -> IO FilePath+ -> IO (SymbolicPath Pkg (Dir Dist)) findDistPrefOrDefault = findDistPref defaultDistPref -- | Perform the \"@.\/setup configure@\" action.@@ -412,24 +449,106 @@ :: (GenericPackageDescription, HookedBuildInfo) -> ConfigFlags -> IO LocalBuildInfo-configure (g_pkg_descr, hookedBuildInfo) cfg = do- -- Cabal pre-configure- (lbc1, comp, platform, enabledComps) <- preConfigurePackage cfg g_pkg_descr+configure = configure_setupHooks noConfigureHooks - -- Cabal package-wide configure- (lbc2, pbd2, pkg_info) <-- finalizeAndConfigurePackage cfg lbc1 g_pkg_descr comp platform enabledComps+configure_setupHooks+ :: ConfigureHooks+ -> (GenericPackageDescription, HookedBuildInfo)+ -> ConfigFlags+ -> IO LocalBuildInfo+configure_setupHooks+ (ConfigureHooks{preConfPackageHook, postConfPackageHook, preConfComponentHook})+ (g_pkg_descr, hookedBuildInfo)+ cfg = do+ -- Cabal pre-configure+ let verbosity = fromFlag (configVerbosity cfg)+ distPref = fromFlag $ configDistPref cfg+ mbWorkDir = flagToMaybe $ configWorkingDir cfg+ (lbc0, comp, platform, enabledComps) <- preConfigurePackage cfg g_pkg_descr - -- Cabal per-component configure- externalPkgDeps <- finalCheckPackage g_pkg_descr pbd2 hookedBuildInfo pkg_info- configureComponents lbc2 pbd2 pkg_info externalPkgDeps+ -- Package-wide pre-configure hook+ lbc1 <-+ case preConfPackageHook of+ Nothing -> return lbc0+ Just pre_conf -> do+ let programDb0 = LBC.withPrograms lbc0+ programDb0' = programDb0{unconfiguredProgs = Map.empty}+ input =+ SetupHooks.PreConfPackageInputs+ { SetupHooks.configFlags = cfg+ , SetupHooks.localBuildConfig = lbc0{LBC.withPrograms = programDb0'}+ , -- Unconfigured programs are not supplied to the hook,+ -- as these cannot be passed over a serialisation boundary+ -- (see the "Binary ProgramDb" instance).+ SetupHooks.compiler = comp+ , SetupHooks.platform = platform+ }+ SetupHooks.PreConfPackageOutputs+ { SetupHooks.buildOptions = opts1+ , SetupHooks.extraConfiguredProgs = progs1+ } <-+ pre_conf input+ -- The package-wide pre-configure hook returns BuildOptions that+ -- overrides the one it was passed in, as well as an update to+ -- the ProgramDb in the form of new configured programs to add+ -- to the program database.+ return $+ lbc0+ { LBC.withBuildOptions = opts1+ , LBC.withPrograms =+ updateConfiguredProgs+ (`Map.union` progs1)+ programDb0+ } + -- Cabal package-wide configure+ (lbc2, pbd2, pkg_info) <-+ finalizeAndConfigurePackage cfg lbc1 g_pkg_descr comp platform enabledComps++ -- Package-wide post-configure hook+ for_ postConfPackageHook $ \postConfPkg -> do+ let input =+ SetupHooks.PostConfPackageInputs+ { SetupHooks.localBuildConfig = lbc2+ , SetupHooks.packageBuildDescr = pbd2+ }+ postConfPkg input++ -- Per-component pre-configure hook+ pkg_descr <- do+ let pkg_descr2 = LBC.localPkgDescr pbd2+ applyComponentDiffs+ verbosity+ ( \c -> for preConfComponentHook $ \computeDiff -> do+ let input =+ SetupHooks.PreConfComponentInputs+ { SetupHooks.localBuildConfig = lbc2+ , SetupHooks.packageBuildDescr = pbd2+ , SetupHooks.component = c+ }+ SetupHooks.PreConfComponentOutputs+ { SetupHooks.componentDiff = diff+ } <-+ computeDiff input+ return diff+ )+ pkg_descr2+ let pbd3 = pbd2{LBC.localPkgDescr = pkg_descr}++ -- Cabal per-component configure+ externalPkgDeps <- finalCheckPackage g_pkg_descr pbd3 hookedBuildInfo pkg_info+ lbi <- configureComponents lbc2 pbd3 pkg_info externalPkgDeps++ writePersistBuildConfig mbWorkDir distPref lbi++ return lbi+ preConfigurePackage :: ConfigFlags -> GenericPackageDescription -> IO (LBC.LocalBuildConfig, Compiler, Platform, ComponentRequestedSpec) preConfigurePackage cfg g_pkg_descr = do- let verbosity = fromFlag (configVerbosity cfg)+ let verbosity = fromFlag $ configVerbosity cfg -- Determine the component we are configuring, if a user specified -- one on the command line. We use a fake, flattened version of@@ -438,11 +557,12 @@ -- configure everything (the old behavior). (mb_cname :: Maybe ComponentName) <- do let flat_pkg_descr = flattenPackageDescription g_pkg_descr- targets <- readBuildTargets verbosity flat_pkg_descr (configArgs cfg)+ targets0 = configTargets cfg+ targets <- readBuildTargets verbosity flat_pkg_descr targets0 -- TODO: bleat if you use the module/file syntax let targets' = [cname | BuildTargetComponent cname <- targets] case targets' of- _ | null (configArgs cfg) -> return Nothing+ _ | null targets0 -> return Nothing [cname] -> return (Just cname) [] -> dieWithException verbosity NoValidComponent _ -> dieWithException verbosity ConfigureEitherSingleOrAll@@ -505,12 +625,14 @@ (lessVerbose verbosity) -- Where to build the package- let build_dir :: FilePath -- e.g. dist/build- build_dir = configFlagsBuildDir cfg+ let builddir :: SymbolicPath Pkg (Dir Build) -- e.g. dist/build+ builddir = setupFlagsBuildDir $ configCommonFlags cfg+ mbWorkDir = flagToMaybe $ configWorkingDir cfg -- NB: create this directory now so that all configure hooks get -- to see it. (In practice, the Configure build-type needs it before -- the postConfPackageHook runs.)- createDirectoryIfMissingVerbose (lessVerbose verbosity) True build_dir+ createDirectoryIfMissingVerbose (lessVerbose verbosity) True $+ interpretSymbolicPath mbWorkDir builddir lbc <- computeLocalBuildConfig cfg comp programDb00 return (lbc, comp, compPlatform, enabled)@@ -521,7 +643,8 @@ -> ProgramDb -> IO LBC.LocalBuildConfig computeLocalBuildConfig cfg comp programDb = do- let verbosity = fromFlag (configVerbosity cfg)+ let common = configCommonFlags cfg+ verbosity = fromFlag $ setupVerbosity common -- Decide if we're going to compile with split sections. split_sections :: Bool <- if not (fromFlag $ configSplitSections cfg)@@ -587,7 +710,7 @@ -- 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)+ not (GHC.compilerBuildWay comp `elem` [DynWay, ProfDynWay]) CompilerId GHCJS _ -> not (GHCJS.isDynamic comp) _ -> False@@ -612,7 +735,7 @@ CompilerId GHC _ -> -- if ghc is dynamic, then ghci needs a shared -- library, so we build one by default.- GHC.isDynamic comp+ GHC.compilerBuildWay comp == DynWay CompilerId GHCJS _ -> GHCJS.isDynamic comp _ -> False@@ -632,12 +755,6 @@ withFullyStaticExe_ = fromFlag $ configFullyStaticExe 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."- setProfiling <- configureProfiling verbosity cfg comp setCoverage <- configureCoverage verbosity cfg comp@@ -670,6 +787,7 @@ , withDynExe = withDynExe_ , withFullyStaticExe = withFullyStaticExe_ , withProfLib = False+ , withProfLibShared = False , withProfLibDetail = ProfDetailNone , withProfExe = False , withProfExeDetail = ProfDetailNone@@ -685,6 +803,20 @@ , relocatable = fromFlagOrDefault False $ configRelocatable cfg } + -- Dynamic executable, but no shared vanilla libraries+ when (LBC.withDynExe buildOptions && not (LBC.withProfExe buildOptions) && not (LBC.withSharedLib buildOptions)) $+ 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."++ -- Profiled dynamic executable, but no shared profiling libraries+ when (LBC.withDynExe buildOptions && LBC.withProfExe buildOptions && not (LBC.withProfLibShared buildOptions)) $+ warn verbosity $+ "Executables will use profiled dynamic linking, but a profiled shared library "+ ++ "is not being built. Linking will fail if any executables "+ ++ "depend on the library."+ return $ LBC.LocalBuildConfig { extraConfigArgs = [] -- Currently configure does not@@ -696,7 +828,7 @@ data PackageInfo = PackageInfo { internalPackageSet :: Set LibraryName- , promisedDepsSet :: Map (PackageName, ComponentName) ComponentId+ , promisedDepsSet :: Map (PackageName, ComponentName) PromisedComponent , installedPackageSet :: InstalledPackageIndex , requiredDepsMap :: Map (PackageName, ComponentName) InstalledPackageInfo }@@ -713,7 +845,8 @@ -> PackageDBStack -> IO (LBC.LocalBuildConfig, LBC.PackageBuildDescr) configurePackage cfg lbc0 pkg_descr00 flags enabled comp platform programDb0 packageDbs = do- let verbosity = fromFlag (configVerbosity cfg)+ let common = configCommonFlags cfg+ verbosity = fromFlag $ setupVerbosity common -- add extra include/lib dirs as specified in cfg pkg_descr0 = addExtraIncludeLibDirsFromConfigFlags pkg_descr00 cfg@@ -725,29 +858,33 @@ -- right before calling configurePackage? -- Configure certain external build tools, see below for which ones.- let requiredBuildTools = do- bi <- enabledBuildInfos pkg_descr0 enabled- -- First, we collect any tool dep that we know is external. This is,- -- in practice:- --- -- 1. `build-tools` entries on the whitelist- --- -- 2. `build-tool-depends` that aren't from the current package.- let externBuildToolDeps =- [ LegacyExeDependency (unUnqualComponentName eName) versionRange- | buildTool@(ExeDependency _ eName versionRange) <-- getAllToolDependencies pkg_descr0 bi- , not $ isInternal pkg_descr0 buildTool- ]- -- Second, we collect any build-tools entry we don't know how to- -- desugar. We'll never have any idea how to build them, so we just- -- hope they are already on the PATH.- let unknownBuildTools =- [ buildTool- | buildTool <- buildTools bi- , Nothing == desugarBuildTool pkg_descr0 buildTool- ]- externBuildToolDeps ++ unknownBuildTools+ let requiredBuildTools+ -- If --ignore-build-tools is set, no build tool is required:+ | fromFlagOrDefault False $ configIgnoreBuildTools cfg =+ []+ | otherwise = do+ bi <- enabledBuildInfos pkg_descr0 enabled+ -- First, we collect any tool dep that we know is external. This is,+ -- in practice:+ --+ -- 1. `build-tools` entries on the whitelist+ --+ -- 2. `build-tool-depends` that aren't from the current package.+ let externBuildToolDeps =+ [ LegacyExeDependency (unUnqualComponentName eName) versionRange+ | buildTool@(ExeDependency _ eName versionRange) <-+ getAllToolDependencies pkg_descr0 bi+ , not $ isInternal pkg_descr0 buildTool+ ]+ -- Second, we collect any build-tools entry we don't know how to+ -- desugar. We'll never have any idea how to build them, so we just+ -- hope they are already on the PATH.+ let unknownBuildTools =+ [ buildTool+ | buildTool <- buildTools bi+ , Nothing == desugarBuildTool pkg_descr0 buildTool+ ]+ externBuildToolDeps ++ unknownBuildTools programDb1 <- configureAllKnownPrograms (lessVerbose verbosity) programDb0@@ -807,7 +944,9 @@ -> ComponentRequestedSpec -> IO (LBC.LocalBuildConfig, LBC.PackageBuildDescr, PackageInfo) finalizeAndConfigurePackage cfg lbc0 g_pkg_descr comp platform enabled = do- let verbosity = fromFlag (configVerbosity cfg)+ let common = configCommonFlags cfg+ verbosity = fromFlag $ setupVerbosity common+ mbWorkDir = flagToMaybe $ setupWorkingDir common let programDb0 = LBC.withPrograms lbc0 -- What package database(s) to use@@ -822,6 +961,7 @@ getInstalledPackages (lessVerbose verbosity) comp+ mbWorkDir packageDbs programDb0 @@ -973,7 +1113,7 @@ -> LBC.PackageBuildDescr -> HookedBuildInfo -> PackageInfo- -> IO ([PreExistingComponent], [PromisedComponent])+ -> IO ([PreExistingComponent], [ConfiguredPromisedComponent]) finalCheckPackage g_pkg_descr ( LBC.PackageBuildDescr@@ -987,15 +1127,14 @@ hookedBuildInfo (PackageInfo{internalPackageSet, promisedDepsSet, installedPackageSet, requiredDepsMap}) = do- let verbosity = fromFlag (configVerbosity cfg)+ let common = configCommonFlags cfg+ verbosity = fromFlag $ setupVerbosity common+ cabalFileDir = packageRoot common use_external_internal_deps = case enabled of OneComponentRequestedSpec{} -> True ComponentRequestedSpec{} -> False - let cabalFileDir =- maybe "." takeDirectory $- flagToMaybe (configCabalFilePath cfg) checkCompilerProblems verbosity comp pkg_descr enabled checkPackageProblems verbosity@@ -1071,7 +1210,7 @@ :: LBC.LocalBuildConfig -> LBC.PackageBuildDescr -> PackageInfo- -> ([PreExistingComponent], [PromisedComponent])+ -> ([PreExistingComponent], [ConfiguredPromisedComponent]) -> IO LocalBuildInfo configureComponents lbc@(LBC.LocalBuildConfig{withPrograms = programDb})@@ -1085,7 +1224,8 @@ (PackageInfo{promisedDepsSet, installedPackageSet}) externalPkgDeps = do- let verbosity = fromFlag (configVerbosity cfg)+ let common = configCommonFlags cfg+ verbosity = fromFlag $ setupVerbosity common use_external_internal_deps = case enabled of OneComponentRequestedSpec{} -> True@@ -1140,7 +1280,9 @@ extraCoverageUnitIds = case enabled of -- Whole package configure, add package libs ComponentRequestedSpec{} -> mapMaybe mbCompUnitId buildComponents- -- Component configure, no need to do anything+ -- Component configure, no need to do anything since+ -- extra-coverage-for will be passed for all other components that+ -- should be covered. OneComponentRequestedSpec{} -> [] mbCompUnitId LibComponentLocalBuildInfo{componentUnitId} = Just componentUnitId mbCompUnitId _ = Nothing@@ -1165,6 +1307,9 @@ when (LBC.relocatable $ LBC.withBuildOptions lbc) $ checkRelocatable verbosity pkg_descr lbi + when (LBC.withDynExe $ LBC.withBuildOptions lbc) $+ checkSharedExes verbosity lbi+ -- TODO: This is not entirely correct, because the dirs may vary -- across libraries/executables let dirs = absoluteInstallDirs pkg_descr lbi NoCopyDest@@ -1228,8 +1373,8 @@ return lbi -mkPromisedDepsSet :: [GivenComponent] -> Map (PackageName, ComponentName) ComponentId-mkPromisedDepsSet comps = Map.fromList [((pn, CLibName ln), cid) | GivenComponent pn ln cid <- comps]+mkPromisedDepsSet :: [PromisedComponent] -> Map (PackageName, ComponentName) PromisedComponent+mkPromisedDepsSet comps = Map.fromList [((packageName pn, CLibName ln), p) | p@(PromisedComponent pn ln _) <- comps] -- | Adds the extra program paths from the flags provided to @configure@ as -- well as specified locations for certain known programs and their default@@ -1238,7 +1383,7 @@ mkProgramDb cfg initialProgramDb = do programDb <- modifyProgramSearchPath (getProgramSearchPath initialProgramDb ++) -- We need to have the paths to programs installed by build-tool-depends before all other paths- <$> prependProgramSearchPath (fromFlagOrDefault normal (configVerbosity cfg)) searchpath initialProgramDb+ <$> prependProgramSearchPath (fromFlagOrDefault normal (configVerbosity cfg)) searchpath [] initialProgramDb pure . userSpecifyArgss (configProgramArgs cfg) . userSpecifyPaths (configProgramPaths cfg)@@ -1332,7 +1477,7 @@ -- ^ installed set -> Set LibraryName -- ^ library components- -> Map (PackageName, ComponentName) ComponentId+ -> Map (PackageName, ComponentName) PromisedComponent -> Map (PackageName, ComponentName) InstalledPackageInfo -- ^ required dependencies -> (Dependency -> Bool)@@ -1494,14 +1639,14 @@ :: Verbosity -> UseExternalInternalDeps -> Set LibraryName- -> Map (PackageName, ComponentName) ComponentId+ -> Map (PackageName, ComponentName) PromisedComponent -> InstalledPackageIndex -- ^ installed packages -> Map (PackageName, ComponentName) InstalledPackageInfo -- ^ required deps -> PackageDescription -> ComponentRequestedSpec- -> IO ([PreExistingComponent], [PromisedComponent])+ -> IO ([PreExistingComponent], [ConfiguredPromisedComponent]) configureDependencies verbosity use_external_internal_deps@@ -1606,7 +1751,7 @@ -- -- Note that @--enable-executable-profiling@ also affects profiling -- of benchmarks and (non-detailed) test suites.-computeEffectiveProfiling :: ConfigFlags -> (Bool {- lib -}, Bool {- exe -})+computeEffectiveProfiling :: ConfigFlags -> (Bool {- lib vanilla-}, Bool {- lib shared -}, Bool {- exe -}) computeEffectiveProfiling cfg = -- The --profiling flag sets the default for both libs and exes, -- but can be overridden by --library-profiling, or the old deprecated@@ -1614,15 +1759,20 @@ -- -- The --profiling-detail and --library-profiling-detail flags behave -- similarly- let tryExeProfiling =+ let dynamicExe = fromFlagOrDefault False (configDynExe cfg)+ tryExeProfiling = fromFlagOrDefault False (mappend (configProf cfg) (configProfExe cfg)) tryLibProfiling = fromFlagOrDefault- tryExeProfiling- (mappend (configProf cfg) (configProfLib cfg))- in (tryLibProfiling, tryExeProfiling)+ (tryExeProfiling && not dynamicExe)+ (configProfLib cfg)+ tryLibProfilingShared =+ fromFlagOrDefault+ (tryExeProfiling && dynamicExe)+ (configProfShared cfg)+ in (tryLibProfiling, tryLibProfilingShared, tryExeProfiling) -- | Select and apply profiling settings for the build based on the -- 'ConfigFlags' and 'Compiler'.@@ -1632,7 +1782,7 @@ -> Compiler -> IO (LBC.BuildOptions -> LBC.BuildOptions) configureProfiling verbosity cfg comp = do- let (tryLibProfiling, tryExeProfiling) = computeEffectiveProfiling cfg+ let (tryLibProfiling, tryLibProfilingShared, tryExeProfiling) = computeEffectiveProfiling cfg tryExeProfileLevel = fromFlagOrDefault@@ -1659,8 +1809,8 @@ return ProfDetailDefault checkProfileLevel other = return other - (exeProfWithoutLibProf, applyProfiling) <-- if profilingSupported comp+ applyProfiling <-+ if profilingSupported comp && (profilingVanillaSupportedOrUnknown comp || profilingDynamicSupportedOrUnknown comp) then do exeLevel <- checkProfileLevel tryExeProfileLevel libLevel <- checkProfileLevel tryLibProfileLevel@@ -1671,11 +1821,46 @@ , LBC.withProfExe = tryExeProfiling , LBC.withProfExeDetail = exeLevel }- return (tryExeProfiling && not tryLibProfiling, apply)+ let compilerSupportsProfilingDynamic = profilingDynamicSupportedOrUnknown comp+ apply2 <-+ if compilerSupportsProfilingDynamic+ then -- Case 1: We support profiled shared libraries so turn on shared profiling+ -- libraries if the user asked for it.+ return $ \buildOptions -> apply buildOptions{LBC.withProfLibShared = tryLibProfilingShared}+ else -- Case 2: Compiler doesn't support profiling shared so turn them off+ do+ -- If we wanted to enable profiling shared libraries.. tell the+ -- user we couldn't.+ when (profilingVanillaSupportedOrUnknown comp && tryLibProfilingShared) $+ warn+ verbosity+ ( "The compiler "+ ++ showCompilerId comp+ ++ " does not support "+ ++ "profiling shared objects. Static profiled objects "+ ++ "will be built."+ )+ return $ \buildOptions ->+ let original_options = apply buildOptions+ in original_options+ { LBC.withProfLibShared = False+ , LBC.withProfLib = profilingVanillaSupportedOrUnknown comp && (tryLibProfilingShared || LBC.withProfLib original_options)+ , LBC.withDynExe = if LBC.withProfExe original_options then False else LBC.withDynExe original_options+ }++ when (tryExeProfiling && not (tryLibProfiling || tryLibProfilingShared)) $ do+ warn+ verbosity+ ( "Executables will be built with profiling, but library "+ ++ "profiling is disabled. Linking will fail if any executables "+ ++ "depend on the library."+ )+ return apply2 else do let apply buildOptions = buildOptions { LBC.withProfLib = False+ , LBC.withProfLibShared = False , LBC.withProfLibDetail = ProfDetailNone , LBC.withProfExe = False , LBC.withProfExeDetail = ProfDetailNone@@ -1688,15 +1873,7 @@ ++ " does not support " ++ "profiling. Profiling has been disabled." )- return (False, apply)-- when exeProfWithoutLibProf $- warn- verbosity- ( "Executables will be built with profiling, but library "- ++ "profiling is disabled. Linking will fail if any executables "- ++ "depend on the library."- )+ return apply return applyProfiling @@ -1735,11 +1912,11 @@ -- we need to build packages in the interactive ghci session, no matter -- whether they have been built before. -- Building them in the configure phase is then redundant and costs time.- PromisedDependency PromisedComponent+ PromisedDependency ConfiguredPromisedComponent | -- | An internal dependency ('PackageId' should be a library name) -- which we are going to have to build. (The -- 'PackageId' here is a hack to get a modest amount of- -- polymorphism out of the 'Package' typeclass.)+ -- polymorphism out of the Pkg' typeclass.) InternalDependency PackageId -- | Test for a package dependency and record the version we have installed.@@ -1748,7 +1925,7 @@ -- ^ Package id of current package -> Set LibraryName -- ^ package libraries- -> Map (PackageName, ComponentName) ComponentId+ -> Map (PackageName, ComponentName) PromisedComponent -- ^ Set of components that are promised, i.e. are not installed already. See 'PromisedDependency' for more details. -> InstalledPackageIndex -- ^ Installed packages@@ -1800,8 +1977,8 @@ -- We have to look it up externally do_external_external :: LibraryName -> Either FailedDependency DependencyResolution do_external_external lib- | Just cid <- Map.lookup (dep_pkgname, CLibName lib) promisedIndex =- return $ PromisedDependency (PromisedComponent dep_pkgname (AnnotatedId currentCabalId (CLibName lib) cid))+ | Just pc <- Map.lookup (dep_pkgname, CLibName lib) promisedIndex =+ return $ PromisedDependency (ConfiguredPromisedComponent dep_pkgname (AnnotatedId (promisedComponentPackage pc) (CLibName lib) (promisedComponentId pc))) do_external_external lib = do ipi <- case Map.lookup (dep_pkgname, CLibName lib) requiredDepsMap of -- If we know the exact pkg to use, then use it.@@ -1814,8 +1991,8 @@ do_external_internal :: LibraryName -> Either FailedDependency DependencyResolution do_external_internal lib- | Just cid <- Map.lookup (dep_pkgname, CLibName lib) promisedIndex =- return $ PromisedDependency (PromisedComponent dep_pkgname (AnnotatedId currentCabalId (CLibName lib) cid))+ | Just pc <- Map.lookup (dep_pkgname, CLibName lib) promisedIndex =+ return $ PromisedDependency (ConfiguredPromisedComponent dep_pkgname (AnnotatedId (promisedComponentPackage pc) (CLibName lib) (promisedComponentId pc))) do_external_internal lib = do ipi <- case Map.lookup (dep_pkgname, CLibName lib) requiredDepsMap of -- If we know the exact pkg to use, then use it.@@ -1859,11 +2036,12 @@ getInstalledPackages :: Verbosity -> Compiler- -> PackageDBStack+ -> Maybe (SymbolicPath CWD (Dir from))+ -> PackageDBStackX (SymbolicPath from (Dir PkgDB)) -- ^ The stack of package databases. -> ProgramDb -> IO InstalledPackageIndex-getInstalledPackages verbosity comp packageDBs progdb = do+getInstalledPackages verbosity comp mbWorkDir packageDBs progdb = do when (null packageDBs) $ dieWithException verbosity NoPackageDatabaseSpecified @@ -1871,15 +2049,16 @@ -- do not check empty packagedbs (ghc-pkg would error out) packageDBs' <- filterM packageDBExists packageDBs case compilerFlavor comp of- GHC -> GHC.getInstalledPackages verbosity comp packageDBs' progdb- GHCJS -> GHCJS.getInstalledPackages verbosity packageDBs' progdb- UHC -> UHC.getInstalledPackages verbosity comp packageDBs' progdb+ GHC -> GHC.getInstalledPackages verbosity comp mbWorkDir packageDBs' progdb+ GHCJS -> GHCJS.getInstalledPackages verbosity mbWorkDir packageDBs' progdb+ UHC -> UHC.getInstalledPackages verbosity comp mbWorkDir packageDBs' progdb HaskellSuite{} -> HaskellSuite.getInstalledPackages verbosity packageDBs' progdb flv -> dieWithException verbosity $ HowToFindInstalledPackages flv where- packageDBExists (SpecificPackageDB path) = do+ packageDBExists (SpecificPackageDB path0) = do+ let path = interpretSymbolicPath mbWorkDir path0 exists <- doesPathExist path unless exists $ warn verbosity $@@ -1900,31 +2079,34 @@ getPackageDBContents :: Verbosity -> Compiler+ -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDB -> ProgramDb -> IO InstalledPackageIndex-getPackageDBContents verbosity comp packageDB progdb = do+getPackageDBContents verbosity comp mbWorkDir packageDB progdb = do info verbosity "Reading installed packages..." case compilerFlavor comp of- GHC -> GHC.getPackageDBContents verbosity packageDB progdb- GHCJS -> GHCJS.getPackageDBContents verbosity packageDB progdb+ GHC -> GHC.getPackageDBContents verbosity mbWorkDir packageDB progdb+ GHCJS -> GHCJS.getPackageDBContents verbosity mbWorkDir packageDB progdb -- For other compilers, try to fall back on 'getInstalledPackages'.- _ -> getInstalledPackages verbosity comp [packageDB] progdb+ _ -> getInstalledPackages verbosity comp mbWorkDir [packageDB] progdb -- | A set of files (or directories) that can be monitored to detect when -- there might have been a change in the installed packages. getInstalledPackagesMonitorFiles :: Verbosity -> Compiler- -> PackageDBStack+ -> Maybe (SymbolicPath CWD ('Dir from))+ -> PackageDBStackS from -> ProgramDb -> Platform -> IO [FilePath]-getInstalledPackagesMonitorFiles verbosity comp packageDBs progdb platform =+getInstalledPackagesMonitorFiles verbosity comp mbWorkDir packageDBs progdb platform = case compilerFlavor comp of GHC -> GHC.getInstalledPackagesMonitorFiles verbosity+ mbWorkDir platform progdb packageDBs@@ -1948,8 +2130,9 @@ -> [UnitId] -- ^ The unit ids to lookup in the installed packages -> IO [InstalledPackageInfo]-getInstalledPackagesById verbosity LocalBuildInfo{compiler = comp, withPackageDB = pkgDb, withPrograms = progDb} mkException unitids = do- ipindex <- getInstalledPackages verbosity comp pkgDb progDb+getInstalledPackagesById verbosity lbi@LocalBuildInfo{compiler = comp, withPackageDB = pkgDb, withPrograms = progDb} mkException unitids = do+ let mbWorkDir = mbWorkDirLBI lbi+ ipindex <- getInstalledPackages verbosity comp mbWorkDir pkgDb progDb mapM ( \uid -> case lookupUnitId ipindex uid of Nothing -> dieWithException verbosity (mkException uid)@@ -1961,7 +2144,7 @@ -- @--global@, @--user@ and @--package-db=global|user|clear|$file@. -- This function combines the global/user flag and interprets the package-db -- flag into a single package db stack.-interpretPackageDbFlags :: Bool -> [Maybe PackageDB] -> PackageDBStack+interpretPackageDbFlags :: Bool -> [Maybe (PackageDBX fp)] -> PackageDBStackX fp interpretPackageDbFlags userInstall specificDBs = extra initialStack specificDBs where@@ -2078,55 +2261,77 @@ verbosity progdb (LegacyExeDependency progName verRange) =- case lookupKnownProgram progName progdb of- Nothing ->- -- Try to configure it as a 'simpleProgram' automatically- --- -- There's a bit of a story behind this line. In old versions- -- of Cabal, there were only internal build-tools dependencies. So the- -- behavior in this case was:- --- -- - If a build-tool dependency was internal, don't do- -- any checking.- --- -- - If it was external, call 'configureRequiredProgram' to- -- "configure" the executable. In particular, if- -- the program was not "known" (present in 'ProgramDb'),- -- then we would just error. This was fine, because- -- the only way a program could be executed from 'ProgramDb'- -- is if some library code from Cabal actually called it,- -- and the pre-existing Cabal code only calls known- -- programs from 'defaultProgramDb', and so if it- -- is calling something else, you have a Custom setup- -- script, and in that case you are expected to register- -- the program you want to call in the ProgramDb.- --- -- OK, so that was fine, until I (ezyang, in 2016) refactored- -- Cabal to support per-component builds. In this case, what- -- was previously an internal build-tool dependency now became- -- an external one, and now previously "internal" dependencies- -- are now external. But these are permitted to exist even- -- when they are not previously configured (something that- -- can only occur by a Custom script.)+ case lookupProgramByName progName progdb of+ Just prog ->+ -- If the program has already been configured, use it+ -- (as long as the version is compatible). --- -- So, I decided, "Fine, let's just accept these in any- -- case." Thus this line. The alternative would have been to- -- somehow detect when a build-tools dependency was "internal" (by- -- looking at the unflattened package description) but this- -- would also be incompatible with future work to support- -- external executable dependencies: we definitely cannot- -- assume they will be preinitialized in the 'ProgramDb'.- configureProgram verbosity (simpleProgram progName) progdb- Just prog- -- requireProgramVersion always requires the program have a version- -- but if the user says "build-depends: foo" ie no version constraint- -- then we should not fail if we cannot discover the program version.- | verRange == anyVersion -> do- (_, progdb') <- requireProgram verbosity prog progdb- return progdb'- | otherwise -> do- (_, _, progdb') <- requireProgramVersion verbosity prog verRange progdb- return progdb'+ -- Not doing so means falling back to the "simpleProgram" path below,+ -- which might fail if the program has custom logic to find a version+ -- (such as hsc2hs).+ let loc = locationPath $ programLocation prog+ in case programVersion prog of+ Nothing+ | verRange == anyVersion ->+ return progdb+ | otherwise ->+ dieWithException verbosity $!+ UnknownVersionDb (programId prog) verRange loc+ Just version+ | withinRange version verRange ->+ return progdb+ | otherwise ->+ dieWithException verbosity $!+ BadVersionDb (programId prog) version verRange loc+ Nothing ->+ -- Otherwise, try to configure it as a 'simpleProgram' automatically+ case lookupKnownProgram progName progdb of+ Nothing ->+ -- There's a bit of a story behind this line. In old versions+ -- of Cabal, there were only internal build-tools dependencies. So the+ -- behavior in this case was:+ --+ -- - If a build-tool dependency was internal, don't do+ -- any checking.+ --+ -- - If it was external, call 'configureRequiredProgram' to+ -- "configure" the executable. In particular, if+ -- the program was not "known" (present in 'ProgramDb'),+ -- then we would just error. This was fine, because+ -- the only way a program could be executed from 'ProgramDb'+ -- is if some library code from Cabal actually called it,+ -- and the pre-existing Cabal code only calls known+ -- programs from 'defaultProgramDb', and so if it+ -- is calling something else, you have a Custom setup+ -- script, and in that case you are expected to register+ -- the program you want to call in the ProgramDb.+ --+ -- OK, so that was fine, until I (ezyang, in 2016) refactored+ -- Cabal to support per-component builds. In this case, what+ -- was previously an internal build-tool dependency now became+ -- an external one, and now previously "internal" dependencies+ -- are now external. But these are permitted to exist even+ -- when they are not previously configured (something that+ -- can only occur by a Custom script.)+ --+ -- So, I decided, "Fine, let's just accept these in any+ -- case." Thus this line. The alternative would have been to+ -- somehow detect when a build-tools dependency was "internal" (by+ -- looking at the unflattened package description) but this+ -- would also be incompatible with future work to support+ -- external executable dependencies: we definitely cannot+ -- assume they will be preinitialized in the 'ProgramDb'.+ configureProgram verbosity (simpleProgram progName) progdb+ Just prog+ -- requireProgramVersion always requires the program have a version+ -- but if the user says "build-depends: foo" ie no version constraint+ -- then we should not fail if we cannot discover the program version.+ | verRange == anyVersion -> do+ (_, progdb') <- requireProgram verbosity prog progdb+ return progdb'+ | otherwise -> do+ (_, _, progdb') <- requireProgramVersion verbosity prog verRange progdb+ return progdb' -- ----------------------------------------------------------------------------- -- Configuring pkg-config package dependencies@@ -2240,11 +2445,11 @@ (extraLibsStatic') = filter ("-l" `isPrefixOf`) ldflags_static (extraLibDirsStatic') = filter ("-L" `isPrefixOf`) ldflags_static in mempty- { includeDirs = map (drop 2) includeDirs'+ { includeDirs = map (makeSymbolicPath . drop 2) includeDirs' , extraLibs = map (drop 2) extraLibs'- , extraLibDirs = map (drop 2) extraLibDirs'+ , extraLibDirs = map (makeSymbolicPath . drop 2) extraLibDirs' , extraLibsStatic = map (drop 2) extraLibsStatic'- , extraLibDirsStatic = map (drop 2) extraLibDirsStatic'+ , extraLibDirsStatic = map (makeSymbolicPath . drop 2) extraLibDirsStatic' , ccOptions = cflags' , ldOptions = ldflags'' }@@ -2257,12 +2462,14 @@ -> IO (Compiler, Platform, ProgramDb) configCompilerAuxEx cfg = do programDb <- mkProgramDb cfg defaultProgramDb+ let common = configCommonFlags cfg+ verbosity = fromFlag $ setupVerbosity common configCompilerEx (flagToMaybe $ configHcFlavor cfg) (flagToMaybe $ configHcPath cfg) (flagToMaybe $ configHcPkg cfg) programDb- (fromFlag (configVerbosity cfg))+ verbosity configCompilerEx :: Maybe CompilerFlavor@@ -2293,8 +2500,7 @@ checkForeignDeps pkg lbi verbosity = ifBuildsWith allHeaders- (commonCcArgs ++ makeLdArgs allLibs) -- I'm feeling- -- lucky+ (commonCcArgs ++ makeLdArgs allLibs) -- I'm feeling lucky (return ()) ( do missingLibs <- findMissingLibs@@ -2302,7 +2508,7 @@ explainErrors missingHdr missingLibs ) where- allHeaders = collectField includes+ allHeaders = collectField (fmap getSymbolicPath . includes) allLibs = collectField $ if withFullyStaticExe lbi@@ -2327,24 +2533,24 @@ -- including file. As such we need to take drastic measures -- and delete the offending file in the source directory. checkDuplicateHeaders = do- let relIncDirs = filter (not . isAbsolute) (collectField includeDirs)+ let relIncDirs = filter (not . isAbsolute) (collectField (fmap getSymbolicPath . includeDirs)) isHeader = isSuffixOf ".h" genHeaders <- for relIncDirs $ \dir -> fmap (dir </>) . filter isHeader- <$> listDirectory (buildDir lbi </> dir) `catchIO` (\_ -> return [])+ <$> listDirectory (i (buildDir lbi) </> dir) `catchIO` (\_ -> return []) srcHeaders <- for relIncDirs $ \dir -> fmap (dir </>) . filter isHeader- <$> listDirectory (baseDir lbi </> dir) `catchIO` (\_ -> return [])+ <$> listDirectory (baseDir </> dir) `catchIO` (\_ -> return []) let commonHeaders = concat genHeaders `intersect` concat srcHeaders for_ commonHeaders $ \hdr -> do warn verbosity $ "Duplicate header found in "- ++ (buildDir lbi </> hdr)+ ++ (getSymbolicPath (buildDir lbi) </> hdr) ++ " and "- ++ (baseDir lbi </> hdr)+ ++ (baseDir </> hdr) ++ "; removing "- ++ (baseDir lbi </> hdr)- removeFile (baseDir lbi </> hdr)+ ++ (baseDir </> hdr)+ removeFile (baseDir </> hdr) findOffendingHdr = ifBuildsWith@@ -2379,29 +2585,34 @@ libExists lib = builds (makeProgram []) (makeLdArgs [lib]) - baseDir lbi' = fromMaybe "." (takeDirectory <$> cabalFilePath lbi')+ common = configCommonFlags $ configFlags lbi+ baseDir = packageRoot common + -- See Note [Symbolic paths] in Distribution.Utils.Path+ i = interpretSymbolicPathLBI lbi+ mbWorkDir = mbWorkDirLBI lbi+ commonCppArgs = platformDefines lbi -- TODO: This is a massive hack, to work around the -- fact that the test performed here should be -- PER-component (c.f. the "I'm Feeling Lucky"; we -- should NOT be glomming everything together.)- ++ ["-I" ++ buildDir lbi </> "autogen"]+ ++ ["-I" ++ i (buildDir lbi </> makeRelativePathEx "autogen")] -- `configure' may generate headers in the build directory- ++ [ "-I" ++ buildDir lbi </> dir- | dir <- ordNub (collectField includeDirs)- , not (isAbsolute dir)+ ++ [ "-I" ++ i (buildDir lbi </> unsafeCoerceSymbolicPath dir)+ | dir <- mapMaybe symbolicPathRelative_maybe $ ordNub (collectField includeDirs) ] -- we might also reference headers from the -- packages directory.- ++ [ "-I" ++ baseDir lbi </> dir- | dir <- ordNub (collectField includeDirs)- , not (isAbsolute dir)+ ++ [ "-I" ++ baseDir </> getSymbolicPath dir+ | dir <- mapMaybe symbolicPathRelative_maybe $ ordNub (collectField includeDirs) ]- ++ [ "-I" ++ dir | dir <- ordNub (collectField includeDirs), isAbsolute dir+ ++ [ "-I" ++ dir+ | dir <- ordNub (collectField (fmap getSymbolicPath . includeDirs))+ , isAbsolute dir ]- ++ ["-I" ++ baseDir lbi]+ ++ ["-I" ++ baseDir] ++ collectField cppOptions ++ collectField ccOptions ++ [ "-I" ++ dir@@ -2428,7 +2639,7 @@ ] commonLdArgs =- [ "-L" ++ dir+ [ "-L" ++ getSymbolicPath dir | dir <- ordNub $ collectField@@ -2461,20 +2672,22 @@ allBi = enabledBuildInfos pkg (componentEnabledSpec lbi) deps = PackageIndex.topologicalOrder (installedPkgs lbi) + builds :: String -> [ProgArg] -> IO Bool builds program args = do- tempDir <- getTemporaryDirectory- withTempFile tempDir ".c" $ \cName cHnd ->- withTempFile tempDir "" $ \oNname oHnd -> do+ tempDir <- makeSymbolicPath <$> getTemporaryDirectory+ withTempFileCwd mbWorkDir tempDir ".c" $ \cName cHnd ->+ withTempFileCwd mbWorkDir tempDir "" $ \oNname oHnd -> do hPutStrLn cHnd program hClose cHnd hClose oHnd _ <-- getDbProgramOutput+ getDbProgramOutputCwd verbosity+ mbWorkDir gccProgram (withPrograms lbi)- (cName : "-o" : oNname : args)+ (getSymbolicPath cName : "-o" : getSymbolicPath oNname : args) return True `catchIO` (\_ -> return False) `catchExit` (\_ -> return False)@@ -2511,6 +2724,18 @@ classEW (PackageDistSuspiciousWarn _) = Nothing classEW (PackageDistInexcusable _) = Nothing +-- | Perform checks if a shared executable can be built+checkSharedExes+ :: Verbosity+ -> LocalBuildInfo+ -> IO ()+checkSharedExes verbosity lbi =+ when (os == Windows) $+ dieWithException verbosity $+ NoOSSupport os "shared executables"+ where+ (Platform _ os) = hostPlatform lbi+ -- | Preform checks if a relocatable build is allowed checkRelocatable :: Verbosity@@ -2533,7 +2758,7 @@ checkOS = unless (os `elem` [OSX, Linux]) $ dieWithException verbosity $- NoOSSupport os+ NoOSSupport os "relocatable builds" where (Platform _ os) = hostPlatform lbi @@ -2580,7 +2805,7 @@ -- prefix of the package depsPrefixRelative = do pkgr <- GHC.pkgRoot verbosity lbi (registrationPackageDB (withPackageDB lbi))- traverse_ (doCheck pkgr) ipkgs+ traverse_ (doCheck $ getSymbolicPath pkgr) ipkgs where doCheck pkgr ipkg | maybe False (== pkgr) (IPI.pkgRoot ipkg) =
src/Distribution/Simple/ConfigureScript.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE RankNTypes #-}@@ -23,6 +24,7 @@ -- local import Distribution.PackageDescription import Distribution.Pretty+import Distribution.Simple.Configure (findDistPrefOrDefault) import Distribution.Simple.Errors import Distribution.Simple.LocalBuildInfo import Distribution.Simple.Program@@ -30,18 +32,13 @@ import Distribution.Simple.Setup.Common import Distribution.Simple.Setup.Config import Distribution.Simple.Utils-import Distribution.System (buildPlatform)+import Distribution.System (Platform, buildPlatform) import Distribution.Utils.NubList-import Distribution.Verbosity+import Distribution.Utils.Path -- Base-import System.FilePath- ( dropDrive- , searchPathSeparator- , splitDirectories- , takeDirectory- , (</>)- )+import System.Directory (createDirectoryIfMissing, doesFileExist)+import qualified System.FilePath as FilePath #ifdef mingw32_HOST_OS import System.FilePath (normalise, splitDrive) #endif@@ -53,13 +50,25 @@ import qualified Data.Map as Map runConfigureScript- :: Verbosity- -> ConfigFlags- -> LocalBuildInfo+ :: ConfigFlags+ -> FlagAssignment+ -> ProgramDb+ -> Platform+ -- ^ host platform -> IO ()-runConfigureScript verbosity flags lbi = do+runConfigureScript cfg flags programDb hp = do+ let commonCfg = configCommonFlags cfg+ verbosity = fromFlag $ setupVerbosity commonCfg+ dist_dir <- findDistPrefOrDefault $ setupDistPref commonCfg+ let build_dir = dist_dir </> makeRelativePathEx "build"+ mbWorkDir = flagToMaybe $ setupWorkingDir commonCfg+ configureScriptPath = packageRoot commonCfg </> "configure"+ confExists <- doesFileExist configureScriptPath+ unless confExists $+ dieWithException verbosity (ConfigureScriptNotFound configureScriptPath)+ configureFile <-+ makeAbsolute $ configureScriptPath env <- getEnvironment- let programDb = withPrograms lbi (ccProg, ccFlags) <- configureCCompiler verbosity programDb ccProgShort <- getShortPathName ccProg -- The C compiler's compilation and linker flags (e.g.@@ -68,9 +77,8 @@ -- to ccFlags -- We don't try and tell configure which ld to use, as we don't have -- a way to pass its flags too- configureFile <-- makeAbsolute $- fromMaybe "." (takeDirectory <$> cabalFilePath lbi) </> "configure"++ let configureFile' = toUnix configureFile -- autoconf is fussy about filenames, and has a set of forbidden -- characters that can't appear in the build directory, etc: -- https://www.gnu.org/software/autoconf/manual/autoconf.html#File-System-Conventions@@ -84,9 +92,8 @@ -- TODO: We don't check for colons, tildes or leading dashes. We -- also should check the builddir's path, destdir, and all other -- paths as well.- let configureFile' = toUnix configureFile for_ badAutoconfCharacters $ \(c, cname) ->- when (c `elem` dropDrive configureFile') $+ when (c `elem` FilePath.dropDrive configureFile') $ warn verbosity $ concat [ "The path to the './configure' script, '"@@ -116,7 +123,7 @@ Map.fromListWith (<>) [ (flagEnvVar flag, (flag, bool) :| [])- | (flag, bool) <- unFlagAssignment $ flagAssignment lbi+ | (flag, bool) <- unFlagAssignment flags ] -- A map from env vars to flag names to the single flag we will go with cabalFlagMapDeconflicted :: Map String (FlagName, Bool) <-@@ -148,14 +155,14 @@ ] ++ [ ( "CABAL_FLAGS"- , Just $ unwords [showFlagValue fv | fv <- unFlagAssignment $ flagAssignment lbi]+ , Just $ unwords [showFlagValue fv | fv <- unFlagAssignment flags] ) ]- let extraPath = fromNubList $ configProgramPathExtra flags+ let extraPath = fromNubList $ configProgramPathExtra cfg let cflagsEnv = maybe (unwords ccFlags) (++ (" " ++ unwords ccFlags)) $ lookup "CFLAGS" env- spSep = [searchPathSeparator]+ spSep = [FilePath.searchPathSeparator] pathEnv = maybe (intercalate spSep extraPath)@@ -165,23 +172,24 @@ ("CFLAGS", Just cflagsEnv) : [("PATH", Just pathEnv) | not (null extraPath)] ++ cabalFlagEnv- hp = hostPlatform lbi maybeHostFlag = if hp == buildPlatform then [] else ["--host=" ++ show (pretty hp)] args' = configureFile' : args ++ ["CC=" ++ ccProgShort] ++ maybeHostFlag shProg = simpleProgram "sh"- progDb <- prependProgramSearchPath verbosity extraPath emptyProgramDb+ progDb <- prependProgramSearchPath verbosity extraPath [] emptyProgramDb shConfiguredProg <- lookupProgram shProg `fmap` configureProgram verbosity shProg progDb case shConfiguredProg of- Just sh ->+ Just sh -> do+ let build_in = interpretSymbolicPath mbWorkDir build_dir+ createDirectoryIfMissing True build_in runProgramInvocation verbosity $ (programInvocation (sh{programOverrideEnv = overEnv}) args')- { progInvokeCwd = Just (buildDir lbi)+ { progInvokeCwd = Just build_in } Nothing -> dieWithException verbosity NotFoundMsg where- args = configureArgs backwardsCompatHack flags+ args = configureArgs backwardsCompatHack cfg backwardsCompatHack = False -- | Convert Windows path to Unix ones@@ -191,10 +199,10 @@ (l, rest) = case splitDrive tmp of ([], x) -> ("/" , x) (h:_, x) -> ('/':h:"/", x)- parts = splitDirectories rest+ parts = FilePath.splitDirectories rest in l ++ intercalate "/" parts #else-toUnix s = intercalate "/" $ splitDirectories s+toUnix s = intercalate "/" $ FilePath.splitDirectories s #endif badAutoconfCharacters :: [(Char, String)]
src/Distribution/Simple/Errors.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE LambdaCase #-}+ ----------------------------------------------------------------------------- -- Module : Distribution.Simple.Errors@@ -20,18 +22,15 @@ import Distribution.InstalledPackageInfo import Distribution.ModuleName import Distribution.Package-import Distribution.PackageDescription (FlagName, UnqualComponentName)+import Distribution.PackageDescription import Distribution.Pretty ( Pretty (pretty) , prettyShow ) import Distribution.Simple.InstallDirs import Distribution.Simple.PreProcess.Types (Suffix)+import Distribution.Simple.SetupHooks.Errors import Distribution.System (OS)-import Distribution.Types.BenchmarkType-import Distribution.Types.LibraryName-import Distribution.Types.PkgconfigVersion-import Distribution.Types.TestType import Distribution.Types.VersionRange.Internal () import Distribution.Version import Text.PrettyPrint@@ -116,7 +115,7 @@ | CheckSemaphoreSupport | NoLibraryForPackage | SanityCheckHookedBuildInfo UnqualComponentName- | ConfigureScriptNotFound+ | ConfigureScriptNotFound FilePath | NoValidComponent | ConfigureEitherSingleOrAll | ConfigCIDValidForPreComponent@@ -139,7 +138,7 @@ | BadVersion String String PkgconfigVersion | UnknownCompilerException | NoWorkingGcc- | NoOSSupport OS+ | NoOSSupport OS String | NoCompilerSupport String | InstallDirsNotPrefixRelative (InstallDirs FilePath) | ExplainErrors (Maybe (Either [Char] [Char])) [String]@@ -153,8 +152,7 @@ | Couldn'tFindTestProgLibV09 FilePath | TestCoverageSupportLibV09 | RawSystemStdout String- | FindFileCwd FilePath- | FindFileEx FilePath+ | FindFile FilePath | FindModuleFileEx ModuleName [Suffix] [FilePath] | MultipleFilesWithExtension String | NoDesc@@ -173,6 +171,7 @@ | BadVersionDb String Version VersionRange FilePath | UnknownVersionDb String VersionRange FilePath | MissingCoveredInstalledLibrary UnitId+ | SetupHooksException SetupHooksException deriving (Show, Typeable) exceptionCode :: CabalException -> Int@@ -285,8 +284,7 @@ Couldn'tFindTestProgLibV09{} -> 9012 TestCoverageSupportLibV09{} -> 1076 RawSystemStdout{} -> 3098- FindFileCwd{} -> 4765- FindFileEx{} -> 2115+ FindFile{} -> 2115 FindModuleFileEx{} -> 6663 MultipleFilesWithExtension{} -> 3333 NoDesc{} -> 7654@@ -305,6 +303,8 @@ BadVersionDb{} -> 8038 UnknownVersionDb{} -> 1008 MissingCoveredInstalledLibrary{} -> 9341+ SetupHooksException err ->+ setupHooksExceptionCode err versionRequirement :: VersionRange -> String versionRequirement range@@ -314,13 +314,13 @@ exceptionMessage :: CabalException -> String exceptionMessage e = case e of NoBenchMarkProgram cmd -> "Could not find benchmark program \"" ++ cmd ++ "\". Did you build the package first?"- EnableBenchMark -> "No benchmarks enabled. Did you remember to configure with " ++ "\'--enable-benchmarks\'?"+ EnableBenchMark -> "No benchmarks enabled. Did you remember to \'Setup configure\' with " ++ "\'--enable-benchmarks\'?" BenchMarkNameDisabled bmName -> "Package configured with benchmark " ++ bmName ++ " disabled." NoBenchMark bmName -> "no such benchmark: " ++ bmName NoLibraryFound -> "No executables and no library found. Nothing to do." CompilerNotInstalled compilerFlavor -> "installing with " ++ prettyShow compilerFlavor ++ "is not implemented" CantFindIncludeFile file -> "can't find include file " ++ file- UnsupportedTestSuite testType -> "Unsupported test suite type: " ++ testType+ UnsupportedTestSuite test_type -> "Unsupported test suite type: " ++ test_type UnsupportedBenchMark benchMarkType -> "Unsupported benchmark type: " ++ benchMarkType NoIncludeFileFound f -> "can't find include file " ++ f NoModuleFound m suffixes ->@@ -331,8 +331,8 @@ ++ ".\n" ++ "If the module " ++ "is autogenerated it should be added to 'autogen-modules'."- RegMultipleInstancePkg -> "HcPkg.register: the compiler does not support,registering multiple instances of packages."- SuppressingChecksOnFile -> "HcPkg.register: the compiler does not support ,suppressing checks on files."+ RegMultipleInstancePkg -> "HcPkg.register: the compiler does not support registering multiple instances of packages."+ SuppressingChecksOnFile -> "HcPkg.register: the compiler does not support suppressing checks on files." NoSupportDirStylePackageDb -> "HcPkg.writeRegistrationFileDirectly: compiler does not support dir style package dbs" OnlySupportSpecificPackageDb -> "HcPkg.writeRegistrationFileDirectly: only supports SpecificPackageDB for now" FailedToParseOutputDescribe programId pkgId -> "failed to parse output of '" ++ programId ++ " describe " ++ prettyShow pkgId ++ "'"@@ -353,7 +353,7 @@ ++ " but " ++ "haddock is using GHC version " ++ prettyShow haddockGhcVersion- MustHaveSharedLibraries -> "Must have vanilla or shared libraries " ++ "enabled in order to run haddock"+ MustHaveSharedLibraries -> "Must have vanilla or shared libraries enabled in order to run haddock" HaddockPackageFlags inf -> "internal error when calculating transitive " ++ "package dependencies.\nDebug info: "@@ -362,7 +362,7 @@ FailedToDetermineTarget -> "Failed to determine target." NoMultipleTargets -> "The 'repl' command does not support multiple targets at once." REPLNotSupported -> "A REPL is not supported with this compiler."- NoSupportBuildingTestSuite testType -> "No support for building test suite type " ++ show testType+ NoSupportBuildingTestSuite test_type -> "No support for building test suite type " ++ show test_type NoSupportBuildingBenchMark benchMarkType -> "No support for building benchmark type " ++ show benchMarkType BuildingNotSupportedWithCompiler -> "Building is not supported with this compiler." ProvideHaskellSuiteTool msg -> show msg@@ -391,7 +391,7 @@ GlobalPackageDBLimitation -> "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 https://gitlab.haskell.org/ghc/ghc/-/issues/5977"+ ++ "the future, see https://gitlab.haskell.org/ghc/ghc/-/issues/5977" GlobalPackageDBSpecifiedFirst -> "If the global package db is specified, it must be " ++ "specified first and cannot be specified multiple times"@@ -487,8 +487,7 @@ ++ "suite type " ++ prettyShow tt NoSupportForPreProcessingBenchmark tt ->- "No support for preprocessing benchmark "- ++ "type "+ "No support for preprocessing benchmark type " ++ prettyShow tt CantFindSourceForPreProcessFile errorStr -> errorStr NoSupportPreProcessingTestExtras tt ->@@ -511,11 +510,11 @@ SanityCheckHookedBuildInfo exe1 -> "The buildinfo contains info for an executable called '" ++ prettyShow exe1- ++ "' but the package does not have a "+ ++ "' but the package does not have an " ++ "executable with that name."- ConfigureScriptNotFound -> "configure script not found."+ ConfigureScriptNotFound fp -> "configure script not found at " ++ fp ++ "." NoValidComponent -> "No valid component targets found"- ConfigureEitherSingleOrAll -> "Can only configure either single component or all of them"+ ConfigureEitherSingleOrAll -> "Can only configure either a single component or all of them" ConfigCIDValidForPreComponent -> "--cid is only supported for per-component configure" SanityCheckForEnableComponents -> "--enable-tests/--enable-benchmarks are incompatible with"@@ -525,23 +524,23 @@ ++ " are incompatible with each other." UnsupportedLanguages pkgId compilerId langs -> "The package "- ++ prettyShow (pkgId)+ ++ prettyShow pkgId ++ " requires the following languages which are not " ++ "supported by "- ++ prettyShow (compilerId)+ ++ prettyShow compilerId ++ ": " ++ intercalate ", " langs UnsupportedLanguageExtension pkgId compilerId exts -> "The package "- ++ prettyShow (pkgId)+ ++ prettyShow pkgId ++ " requires the following language extensions which are not " ++ "supported by "- ++ prettyShow (compilerId)+ ++ prettyShow compilerId ++ ": " ++ intercalate ", " exts CantFindForeignLibraries unsupportedFLibs -> "Cannot build some foreign libraries: "- ++ intercalate "," unsupportedFLibs+ ++ intercalate ", " unsupportedFLibs ExpectedAbsoluteDirectory fPath -> "expected an absolute directory name for --prefix: " ++ fPath FlagsNotSpecified diffFlags -> "'--exact-configuration' was given, "@@ -572,7 +571,7 @@ ++ "' refers to a library which is defined within the same " ++ "package. To use this feature the package must specify at " ++ "least 'cabal-version: >= 1.8'."- ReportFailedDependencies failed hackageUrl -> (intercalate "\n\n" (map reportFailedDependency failed))+ ReportFailedDependencies failed hackageUrl -> intercalate "\n\n" (map reportFailedDependency failed) where reportFailedDependency (DependencyNotExists pkgname) = "there is no version of "@@ -617,15 +616,16 @@ NoWorkingGcc -> unlines [ "No working gcc"- , "This package depends on foreign library but we cannot "+ , "This package depends on a 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." ]- NoOSSupport os ->+ NoOSSupport os what -> "Operating system: " ++ prettyShow os- ++ ", does not support relocatable builds"+ ++ ", does not support "+ ++ what NoCompilerSupport comp -> "Compiler: " ++ comp@@ -673,8 +673,8 @@ ++ "where it is." ++ "If the library file does exist, it may contain errors that " ++ "are caught by the C compiler at the preprocessing stage. "- ++ "In this case you can re-run configure with the verbosity "- ++ "flag -v3 to see the error messages."+ ++ "In this case you can re-run 'Setup configure' with the "+ ++ "verbosity flag -v3 to see the error messages." messagePlural = "This problem can usually be solved by installing the system " ++ "packages that provide these libraries (you may need the "@@ -684,18 +684,18 @@ ++ "where they are." ++ "If the library files do exist, it may contain errors that " ++ "are caught by the C compiler at the preprocessing stage. "- ++ "In this case you can re-run configure with the verbosity "- ++ "flag -v3 to see the error messages."+ ++ "In this case you can re-run 'Setup configure' with the "+ ++ "verbosity flag -v3 to see the error messages." headerCppMessage = "If the header file does exist, it may contain errors that " ++ "are caught by the C compiler at the preprocessing stage. "- ++ "In this case you can re-run configure with the verbosity "- ++ "flag -v3 to see the error messages."+ ++ "In this case you can re-run 'Setup configure' with the "+ ++ "verbosity flag -v3 to see the error messages." headerCcMessage = "The header file contains a compile error. "- ++ "You can re-run configure with the verbosity flag "+ ++ "You can re-run 'Setup configure' with the verbosity flag " ++ "-v3 to see the error messages from the C compiler."- CheckPackageProblems errors -> (intercalate "\n\n" $ errors)+ CheckPackageProblems errors -> intercalate "\n\n" errors LibDirDepsPrefixNotRelative l p -> "Library directory of a dependency: " ++ show l@@ -726,8 +726,7 @@ ++ "\". Did you build the package first?" TestCoverageSupportLibV09 -> "Test coverage is only supported for packages with a library component." RawSystemStdout errors -> errors- FindFileCwd fileName -> fileName ++ " doesn't exist"- FindFileEx fileName -> fileName ++ " doesn't exist"+ FindFile fileName -> fileName ++ " doesn't exist" FindModuleFileEx mod_name extensions searchPath -> "Could not find module: " ++ prettyShow mod_name@@ -757,7 +756,7 @@ RegisMultiplePkgNotSupported -> "Registering multiple package instances is not yet supported for this compiler" RegisteringNotImplemented -> "Registering is not implemented for this compiler" NoTestSuitesEnabled ->- "No test suites enabled. Did you remember to configure with "+ "No test suites enabled. Did you remember to 'Setup configure' with " ++ "\'--enable-tests\'?" TestNameDisabled tName -> "Package configured with test suite "@@ -799,3 +798,5 @@ "Failed to find the installed unit '" ++ prettyShow unitId ++ "' in package database stack."+ SetupHooksException err ->+ setupHooksExceptionMessage err
+ src/Distribution/Simple/FileMonitor/Types.hs view
@@ -0,0 +1,217 @@+{-# LANGUAGE DeriveGeneric #-}++-- |+-- Module: Distribution.Simple.FileMonitor.Types+--+-- Types for monitoring files and directories.+module Distribution.Simple.FileMonitor.Types+ ( -- * Globs with respect to a root+ RootedGlob (..)+ , FilePathRoot (..)+ , Glob++ -- * File monitoring+ , MonitorFilePath (..)+ , MonitorKindFile (..)+ , MonitorKindDir (..)++ -- ** Utility constructors of t'MonitorFilePath'+ , monitorFile+ , monitorFileHashed+ , monitorNonExistentFile+ , monitorFileExistence+ , monitorDirectory+ , monitorNonExistentDirectory+ , monitorDirectoryExistence+ , monitorFileOrDirectory+ , monitorFileGlob+ , monitorFileGlobExistence+ , monitorFileSearchPath+ , monitorFileHashedSearchPath+ )+where++import Distribution.Compat.Prelude+import Distribution.Simple.Glob.Internal+ ( Glob (..)+ )++import qualified Distribution.Compat.CharParsing as P+import Distribution.Parsec+import Distribution.Pretty+import qualified Text.PrettyPrint as Disp++--------------------------------------------------------------------------------+-- Rooted globs.+--++-- | A file path specified by globbing, relative+-- to some root directory.+data RootedGlob+ = RootedGlob+ FilePathRoot+ -- ^ what the glob is relative to+ Glob+ -- ^ the glob+ deriving (Eq, Show, Generic)++instance Binary RootedGlob+instance Structured RootedGlob++data FilePathRoot+ = FilePathRelative+ | -- | e.g. @"/"@, @"c:\"@ or result of 'takeDrive'+ FilePathRoot FilePath+ | FilePathHomeDir+ deriving (Eq, Show, Generic)++instance Binary FilePathRoot+instance Structured FilePathRoot++------------------------------------------------------------------------------+-- Types for specifying files to monitor+--++-- | A description of a file (or set of files) to monitor for changes.+--+-- Where file paths are relative they are relative to a common directory+-- (e.g. project root), not necessarily the process current directory.+data MonitorFilePath+ = MonitorFile+ { monitorKindFile :: !MonitorKindFile+ , monitorKindDir :: !MonitorKindDir+ , monitorPath :: !FilePath+ }+ | MonitorFileGlob+ { monitorKindFile :: !MonitorKindFile+ , monitorKindDir :: !MonitorKindDir+ , monitorPathGlob :: !RootedGlob+ }+ deriving (Eq, Show, Generic)++data MonitorKindFile+ = FileExists+ | FileModTime+ | FileHashed+ | FileNotExists+ deriving (Eq, Show, Generic)++data MonitorKindDir+ = DirExists+ | DirModTime+ | DirNotExists+ deriving (Eq, Show, Generic)++instance Binary MonitorFilePath+instance Binary MonitorKindFile+instance Binary MonitorKindDir++instance Structured MonitorFilePath+instance Structured MonitorKindFile+instance Structured MonitorKindDir++-- | Monitor a single file for changes, based on its modification time.+-- The monitored file is considered to have changed if it no longer+-- exists or if its modification time has changed.+monitorFile :: FilePath -> MonitorFilePath+monitorFile = MonitorFile FileModTime DirNotExists++-- | Monitor a single file for changes, based on its modification time+-- and content hash. The monitored file is considered to have changed if+-- it no longer exists or if its modification time and content hash have+-- changed.+monitorFileHashed :: FilePath -> MonitorFilePath+monitorFileHashed = MonitorFile FileHashed DirNotExists++-- | Monitor a single non-existent file for changes. The monitored file+-- is considered to have changed if it exists.+monitorNonExistentFile :: FilePath -> MonitorFilePath+monitorNonExistentFile = MonitorFile FileNotExists DirNotExists++-- | Monitor a single file for existence only. The monitored file is+-- considered to have changed if it no longer exists.+monitorFileExistence :: FilePath -> MonitorFilePath+monitorFileExistence = MonitorFile FileExists DirNotExists++-- | Monitor a single directory for changes, based on its modification+-- time. The monitored directory is considered to have changed if it no+-- longer exists or if its modification time has changed.+monitorDirectory :: FilePath -> MonitorFilePath+monitorDirectory = MonitorFile FileNotExists DirModTime++-- | Monitor a single non-existent directory for changes. The monitored+-- directory is considered to have changed if it exists.+monitorNonExistentDirectory :: FilePath -> MonitorFilePath+-- Just an alias for monitorNonExistentFile, since you can't+-- tell the difference between a non-existent directory and+-- a non-existent file :)+monitorNonExistentDirectory = monitorNonExistentFile++-- | Monitor a single directory for existence. The monitored directory is+-- considered to have changed only if it no longer exists.+monitorDirectoryExistence :: FilePath -> MonitorFilePath+monitorDirectoryExistence = MonitorFile FileNotExists DirExists++-- | Monitor a single file or directory for changes, based on its modification+-- time. The monitored file is considered to have changed if it no longer+-- exists or if its modification time has changed.+monitorFileOrDirectory :: FilePath -> MonitorFilePath+monitorFileOrDirectory = MonitorFile FileModTime DirModTime++-- | Monitor a set of files (or directories) identified by a file glob.+-- The monitored glob is considered to have changed if the set of files+-- matching the glob changes (i.e. creations or deletions), or for files if the+-- modification time and content hash of any matching file has changed.+monitorFileGlob :: RootedGlob -> MonitorFilePath+monitorFileGlob = MonitorFileGlob FileHashed DirExists++-- | Monitor a set of files (or directories) identified by a file glob for+-- existence only. The monitored glob is considered to have changed if the set+-- of files matching the glob changes (i.e. creations or deletions).+monitorFileGlobExistence :: RootedGlob -> MonitorFilePath+monitorFileGlobExistence = MonitorFileGlob FileExists DirExists++-- | Creates a list of files to monitor when you search for a file which+-- unsuccessfully looked in @notFoundAtPaths@ before finding it at+-- @foundAtPath@.+monitorFileSearchPath :: [FilePath] -> FilePath -> [MonitorFilePath]+monitorFileSearchPath notFoundAtPaths foundAtPath =+ monitorFile foundAtPath+ : map monitorNonExistentFile notFoundAtPaths++-- | Similar to 'monitorFileSearchPath', but also instructs us to+-- monitor the hash of the found file.+monitorFileHashedSearchPath :: [FilePath] -> FilePath -> [MonitorFilePath]+monitorFileHashedSearchPath notFoundAtPaths foundAtPath =+ monitorFileHashed foundAtPath+ : map monitorNonExistentFile notFoundAtPaths++------------------------------------------------------------------------------+-- Parsing & pretty-printing+--++instance Pretty RootedGlob where+ pretty (RootedGlob root pathglob) = pretty root Disp.<> pretty pathglob++instance Parsec RootedGlob where+ parsec = do+ root <- parsec+ case root of+ FilePathRelative -> RootedGlob root <$> parsec+ _ -> RootedGlob root <$> parsec <|> pure (RootedGlob root GlobDirTrailing)++instance Pretty FilePathRoot where+ pretty FilePathRelative = Disp.empty+ pretty (FilePathRoot root) = Disp.text root+ pretty FilePathHomeDir = Disp.char '~' Disp.<> Disp.char '/'++instance Parsec FilePathRoot where+ parsec = root <|> P.try home <|> P.try drive <|> pure FilePathRelative+ where+ root = FilePathRoot "/" <$ P.char '/'+ home = FilePathHomeDir <$ P.string "~/"+ drive = do+ dr <- P.satisfy $ \c -> (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')+ _ <- P.char ':'+ _ <- P.char '/' <|> P.char '\\'+ return (FilePathRoot (toUpper dr : ":\\"))
src/Distribution/Simple/GHC.hs view
@@ -1,8 +1,10 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TupleSections #-} -----------------------------------------------------------------------------@@ -60,7 +62,7 @@ , Internal.componentCcGhcOptions , getGhcAppDir , getLibDir- , isDynamic+ , compilerBuildWay , getGlobalPackageDB , pkgRoot @@ -82,6 +84,7 @@ import Distribution.Compat.Prelude import Prelude () +import Control.Arrow ((***)) import Control.Monad (forM_) import Data.List (stripPrefix) import qualified Data.Map as Map@@ -95,8 +98,8 @@ import Distribution.Simple.BuildPaths import Distribution.Simple.Compiler import Distribution.Simple.Errors-import Distribution.Simple.Flag (Flag (..), toFlag) import qualified Distribution.Simple.GHC.Build as GHC+import Distribution.Simple.GHC.Build.Modules (BuildWay (..)) import Distribution.Simple.GHC.Build.Utils import Distribution.Simple.GHC.EnvironmentParser import Distribution.Simple.GHC.ImplInfo@@ -110,7 +113,7 @@ import Distribution.Simple.Program.GHC import qualified Distribution.Simple.Program.HcPkg as HcPkg import qualified Distribution.Simple.Program.Strip as Strip-import Distribution.Simple.Setup.Common (extraCompilationArtifacts)+import Distribution.Simple.Setup.Common import Distribution.Simple.Setup.Repl import Distribution.Simple.Utils import Distribution.System@@ -118,6 +121,7 @@ import Distribution.Types.ParStrat import Distribution.Types.TargetInfo import Distribution.Utils.NubList+import Distribution.Utils.Path import Distribution.Verbosity import Distribution.Version import Language.Haskell.Extension@@ -130,9 +134,8 @@ , getDirectoryContents ) import System.FilePath- ( takeDirectory- , (<.>)- , (</>)+ ( isRelative+ , takeDirectory ) import qualified System.Info #ifndef mingw32_HOST_OS@@ -392,24 +395,26 @@ -- | Given a single package DB, return all installed packages. getPackageDBContents :: Verbosity- -> PackageDB+ -> Maybe (SymbolicPath CWD (Dir from))+ -> PackageDBX (SymbolicPath from (Dir PkgDB)) -> ProgramDb -> IO InstalledPackageIndex-getPackageDBContents verbosity packagedb progdb = do- pkgss <- getInstalledPackages' verbosity [packagedb] progdb+getPackageDBContents verbosity mbWorkDir packagedb progdb = do+ pkgss <- getInstalledPackages' verbosity mbWorkDir [packagedb] progdb toPackageIndex verbosity pkgss progdb -- | Given a package DB stack, return all installed packages. getInstalledPackages :: Verbosity -> Compiler- -> PackageDBStack+ -> Maybe (SymbolicPath CWD (Dir from))+ -> PackageDBStackX (SymbolicPath from (Dir PkgDB)) -> ProgramDb -> IO InstalledPackageIndex-getInstalledPackages verbosity comp packagedbs progdb = do+getInstalledPackages verbosity comp mbWorkDir packagedbs progdb = do checkPackageDbEnvVar verbosity checkPackageDbStack verbosity comp packagedbs- pkgss <- getInstalledPackages' verbosity packagedbs progdb+ pkgss <- getInstalledPackages' verbosity mbWorkDir packagedbs progdb index <- toPackageIndex verbosity pkgss progdb return $! hackRtsPackage index where@@ -425,7 +430,7 @@ -- 'getInstalledPackages'. toPackageIndex :: Verbosity- -> [(PackageDB, [InstalledPackageInfo])]+ -> [(PackageDBX a, [InstalledPackageInfo])] -> ProgramDb -> IO InstalledPackageIndex toPackageIndex verbosity pkgss progdb = do@@ -488,7 +493,7 @@ checkPackageDbEnvVar verbosity = Internal.checkPackageDbEnvVar verbosity "GHC" "GHC_PACKAGE_PATH" -checkPackageDbStack :: Verbosity -> Compiler -> PackageDBStack -> IO ()+checkPackageDbStack :: Eq fp => Verbosity -> Compiler -> PackageDBStackX fp -> IO () checkPackageDbStack verbosity comp = if flagPackageConf implInfo then checkPackageDbStackPre76 verbosity@@ -496,7 +501,7 @@ where implInfo = ghcVersionImplInfo (compilerVersion comp) -checkPackageDbStackPost76 :: Verbosity -> PackageDBStack -> IO ()+checkPackageDbStackPost76 :: Eq fp => Verbosity -> PackageDBStackX fp -> IO () checkPackageDbStackPost76 _ (GlobalPackageDB : rest) | GlobalPackageDB `notElem` rest = return () checkPackageDbStackPost76 verbosity rest@@ -504,7 +509,7 @@ dieWithException verbosity CheckPackageDbStackPost76 checkPackageDbStackPost76 _ _ = return () -checkPackageDbStackPre76 :: Verbosity -> PackageDBStack -> IO ()+checkPackageDbStackPre76 :: Eq fp => Verbosity -> PackageDBStackX fp -> IO () checkPackageDbStackPre76 _ (GlobalPackageDB : rest) | GlobalPackageDB `notElem` rest = return () checkPackageDbStackPre76 verbosity rest@@ -525,38 +530,45 @@ -- | Get the packages from specific PackageDBs, not cumulative. getInstalledPackages' :: Verbosity- -> [PackageDB]+ -> Maybe (SymbolicPath CWD (Dir from))+ -> [PackageDBX (SymbolicPath from (Dir PkgDB))] -> ProgramDb- -> IO [(PackageDB, [InstalledPackageInfo])]-getInstalledPackages' verbosity packagedbs progdb =+ -> IO [(PackageDBX (SymbolicPath from (Dir PkgDB)), [InstalledPackageInfo])]+getInstalledPackages' verbosity mbWorkDir packagedbs progdb = sequenceA [ do- pkgs <- HcPkg.dump (hcPkgInfo progdb) verbosity packagedb+ pkgs <- HcPkg.dump (hcPkgInfo progdb) verbosity mbWorkDir packagedb return (packagedb, pkgs) | packagedb <- packagedbs ] getInstalledPackagesMonitorFiles- :: Verbosity+ :: forall from+ . Verbosity+ -> Maybe (SymbolicPath CWD (Dir from)) -> Platform -> ProgramDb- -> [PackageDB]+ -> [PackageDBS from] -> IO [FilePath]-getInstalledPackagesMonitorFiles verbosity platform progdb =+getInstalledPackagesMonitorFiles verbosity mbWorkDir platform progdb = traverse getPackageDBPath where- getPackageDBPath :: PackageDB -> IO FilePath+ getPackageDBPath :: PackageDBS from -> IO FilePath getPackageDBPath GlobalPackageDB = selectMonitorFile =<< getGlobalPackageDB verbosity ghcProg getPackageDBPath UserPackageDB = selectMonitorFile =<< getUserPackageDB verbosity ghcProg platform- getPackageDBPath (SpecificPackageDB path) = selectMonitorFile path+ getPackageDBPath (SpecificPackageDB path) = selectMonitorFile (interpretSymbolicPath mbWorkDir path) -- GHC has old style file dbs, and new style directory dbs. -- Note that for dir style dbs, we only need to monitor the cache file, not -- the whole directory. The ghc program itself only reads the cache file -- so it's safe to only monitor this one file.- selectMonitorFile path = do+ selectMonitorFile path0 = do+ let path =+ if isRelative path0+ then interpretSymbolicPath mbWorkDir (makeRelativePathEx path0)+ else path0 isFileStyle <- doesFileExist path if isFileStyle then return path@@ -577,7 +589,11 @@ -> IO () buildLib flags numJobs pkg lbi lib clbi = GHC.build numJobs pkg $- PreBuildComponentInputs (BuildNormal flags) lbi (TargetInfo clbi (CLib lib))+ PreBuildComponentInputs+ { buildingWhat = BuildNormal flags+ , localBuildInfo = lbi+ , targetInfo = TargetInfo clbi (CLib lib)+ } replLib :: ReplFlags@@ -589,7 +605,11 @@ -> IO () replLib flags numJobs pkg lbi lib clbi = GHC.build numJobs pkg $- PreBuildComponentInputs (BuildRepl flags) lbi (TargetInfo clbi (CLib lib))+ PreBuildComponentInputs+ { buildingWhat = BuildRepl flags+ , localBuildInfo = lbi+ , targetInfo = TargetInfo clbi (CLib lib)+ } -- | Start a REPL without loading any source files. startInterpreter@@ -607,7 +627,7 @@ } checkPackageDbStack verbosity comp packageDBs (ghcProg, _) <- requireProgram verbosity ghcProgram progdb- runGHC verbosity ghcProg comp platform replOpts+ runGHC verbosity ghcProg comp platform Nothing replOpts -- ----------------------------------------------------------------------------- -- Building an executable or foreign library@@ -623,7 +643,16 @@ -> IO () buildFLib v numJobs pkg lbi flib clbi = GHC.build numJobs pkg $- PreBuildComponentInputs (BuildNormal mempty{buildVerbosity = toFlag v}) lbi (TargetInfo clbi (CFLib flib))+ PreBuildComponentInputs+ { buildingWhat =+ BuildNormal $+ mempty+ { buildCommonFlags =+ mempty{setupVerbosity = toFlag v}+ }+ , localBuildInfo = lbi+ , targetInfo = TargetInfo clbi (CFLib flib)+ } replFLib :: ReplFlags@@ -635,7 +664,11 @@ -> IO () replFLib replFlags njobs pkg lbi flib clbi = GHC.build njobs pkg $- PreBuildComponentInputs (BuildRepl replFlags) lbi (TargetInfo clbi (CFLib flib))+ PreBuildComponentInputs+ { buildingWhat = BuildRepl replFlags+ , localBuildInfo = lbi+ , targetInfo = TargetInfo clbi (CFLib flib)+ } -- | Build an executable with GHC. buildExe@@ -648,7 +681,16 @@ -> IO () buildExe v njobs pkg lbi exe clbi = GHC.build njobs pkg $- PreBuildComponentInputs (BuildNormal mempty{buildVerbosity = toFlag v}) lbi (TargetInfo clbi (CExe exe))+ PreBuildComponentInputs+ { buildingWhat =+ BuildNormal $+ mempty+ { buildCommonFlags =+ mempty{setupVerbosity = toFlag v}+ }+ , localBuildInfo = lbi+ , targetInfo = TargetInfo clbi (CExe exe)+ } replExe :: ReplFlags@@ -660,7 +702,11 @@ -> IO () replExe replFlags njobs pkg lbi exe clbi = GHC.build njobs pkg $- PreBuildComponentInputs (BuildRepl replFlags) lbi (TargetInfo clbi (CExe exe))+ PreBuildComponentInputs+ { buildingWhat = BuildRepl replFlags+ , localBuildInfo = lbi+ , targetInfo = TargetInfo clbi (CExe exe)+ } -- | Extracts a String representing a hash of the ABI of a built -- library. It can fail if the library has not yet been built.@@ -676,6 +722,7 @@ libBi = libBuildInfo lib comp = compiler lbi platform = hostPlatform lbi+ mbWorkDir = mbWorkDirLBI lbi vanillaArgs = (Internal.componentGhcOptions verbosity lbi libBi clbi (componentBuildDir lbi clbi)) `mappend` mempty@@ -689,7 +736,7 @@ , ghcOptFPic = toFlag True , ghcOptHiSuffix = toFlag "dyn_hi" , ghcOptObjSuffix = toFlag "dyn_o"- , ghcOptExtra = hcSharedOptions GHC libBi+ , ghcOptExtra = hcOptions GHC libBi ++ hcSharedOptions GHC libBi } profArgs = vanillaArgs@@ -701,20 +748,37 @@ (withProfLibDetail lbi) , ghcOptHiSuffix = toFlag "p_hi" , ghcOptObjSuffix = toFlag "p_o"- , ghcOptExtra = hcProfOptions GHC libBi+ , ghcOptExtra = hcOptions GHC libBi ++ hcProfOptions GHC libBi }- ghcArgs- | withVanillaLib lbi = vanillaArgs- | withSharedLib lbi = sharedArgs- | withProfLib lbi = profArgs- | otherwise = error "libAbiHash: Can't find an enabled library way"+ profDynArgs =+ vanillaArgs+ `mappend` mempty+ { ghcOptProfilingMode = toFlag True+ , ghcOptProfilingAuto =+ Internal.profDetailLevelFlag+ True+ (withProfLibDetail lbi)+ , ghcOptDynLinkMode = toFlag GhcDynamicOnly+ , ghcOptFPic = toFlag True+ , ghcOptHiSuffix = toFlag "p_dyn_hi"+ , ghcOptObjSuffix = toFlag "p_dyn_o"+ , ghcOptExtra = hcOptions GHC libBi ++ hcProfSharedOptions GHC libBi+ }+ ghcArgs =+ let (libWays, _, _) = buildWays lbi+ in case libWays (componentIsIndefinite clbi) of+ (ProfDynWay : _) -> profDynArgs+ (ProfWay : _) -> profArgs+ (StaticWay : _) -> vanillaArgs+ (DynWay : _) -> sharedArgs+ _ -> error "libAbiHash: Can't find an enabled library way" (ghcProg, _) <- requireProgram verbosity ghcProgram (withPrograms lbi) hash <- getProgramInvocationOutput verbosity- =<< ghcInvocation verbosity ghcProg comp platform ghcArgs+ =<< ghcInvocation verbosity ghcProg comp platform mbWorkDir ghcArgs return (takeWhile (not . isSpace) hash) @@ -826,80 +890,100 @@ -> ComponentLocalBuildInfo -> IO () installLib verbosity lbi targetDir dynlibTargetDir _builtDir pkg lib clbi = do+ let+ (wantedLibWays, _, _) = buildWays lbi+ isIndef = componentIsIndefinite clbi+ libWays = wantedLibWays isIndef++ info verbosity ("Wanted install ways: " ++ show libWays)+ -- copy .hi files over:- whenVanilla $ copyModuleFiles $ Suffix "hi"- whenProf $ copyModuleFiles $ Suffix "p_hi"- whenShared $ copyModuleFiles $ Suffix "dyn_hi"+ forM_ (wantedLibWays isIndef) $ \w -> case w of+ StaticWay -> copyModuleFiles (Suffix "hi")+ DynWay -> copyModuleFiles (Suffix "dyn_hi")+ ProfWay -> copyModuleFiles (Suffix "p_hi")+ ProfDynWay -> copyModuleFiles (Suffix "p_dyn_hi") -- copy extra compilation artifacts that ghc plugins may produce copyDirectoryIfExists extraCompilationArtifacts -- copy the built library files over:- whenHasCode $ do- whenVanilla $ do- sequence_- [ installOrdinary+ when (has_code && hasLib) $ do+ forM_ libWays $ \w -> case w of+ StaticWay -> do+ sequence_+ [ installOrdinary+ builtDir+ targetDir+ (mkGenericStaticLibName (l ++ f))+ | l <-+ getHSLibraryName+ (componentUnitId clbi)+ : (extraBundledLibs (libBuildInfo lib))+ , f <- "" : extraLibFlavours (libBuildInfo lib)+ ]+ whenGHCi $ installOrdinary builtDir targetDir ghciLibName+ ProfWay -> do+ installOrdinary builtDir targetDir profileLibName+ whenGHCi $ installOrdinary builtDir targetDir ghciProfLibName+ ProfDynWay -> do+ installShared builtDir- targetDir- (mkGenericStaticLibName (l ++ f))- | l <-- getHSLibraryName- (componentUnitId clbi)- : (extraBundledLibs (libBuildInfo lib))- , f <- "" : extraLibFlavours (libBuildInfo lib)- ]- whenGHCi $ installOrdinary builtDir targetDir ghciLibName- whenProf $ do- installOrdinary builtDir targetDir profileLibName- whenGHCi $ installOrdinary builtDir targetDir ghciProfLibName- whenShared $- if- -- The behavior for "extra-bundled-libraries" changed in version 2.5.0.- -- See ghc issue #15837 and Cabal PR #5855.- | specVersion pkg < CabalSpecV3_0 -> do- sequence_- [ installShared- builtDir- dynlibTargetDir- (mkGenericSharedLibName platform compiler_id (l ++ f))- | l <- getHSLibraryName uid : extraBundledLibs (libBuildInfo lib)- , f <- "" : extraDynLibFlavours (libBuildInfo lib)- ]- | otherwise -> do- sequence_- [ installShared- builtDir- dynlibTargetDir- ( mkGenericSharedLibName- platform- compiler_id- (getHSLibraryName uid ++ f)- )- | f <- "" : extraDynLibFlavours (libBuildInfo lib)- ]- sequence_- [ do- files <- getDirectoryContents builtDir- let l' =- mkGenericSharedBundledLibName- platform- compiler_id- l- forM_ files $ \file ->- when (l' `isPrefixOf` file) $ do- isFile <- doesFileExist (builtDir </> file)- when isFile $ do- installShared- builtDir- dynlibTargetDir- file- | l <- extraBundledLibs (libBuildInfo lib)- ]+ dynlibTargetDir+ (mkProfSharedLibName platform compiler_id uid)+ DynWay -> do+ if+ -- The behavior for "extra-bundled-libraries" changed in version 2.5.0.+ -- See ghc issue #15837 and Cabal PR #5855.+ | specVersion pkg < CabalSpecV3_0 -> do+ sequence_+ [ installShared+ builtDir+ dynlibTargetDir+ (mkGenericSharedLibName platform compiler_id (l ++ f))+ | l <- getHSLibraryName uid : extraBundledLibs (libBuildInfo lib)+ , f <- "" : extraDynLibFlavours (libBuildInfo lib)+ ]+ | otherwise -> do+ sequence_+ [ installShared+ builtDir+ dynlibTargetDir+ ( mkGenericSharedLibName+ platform+ compiler_id+ (getHSLibraryName uid ++ f)+ )+ | f <- "" : extraDynLibFlavours (libBuildInfo lib)+ ]+ sequence_+ [ do+ files <- getDirectoryContents (i builtDir)+ let l' =+ mkGenericSharedBundledLibName+ platform+ compiler_id+ (l ++ f)+ forM_ files $ \file ->+ when (l' `isPrefixOf` file) $ do+ isFile <- doesFileExist (i $ builtDir </> makeRelativePathEx file)+ when isFile $ do+ installShared+ builtDir+ dynlibTargetDir+ file+ | l <- extraBundledLibs (libBuildInfo lib)+ , f <- "" : extraDynLibFlavours (libBuildInfo lib)+ ] where+ -- See Note [Symbolic paths] in Distribution.Utils.Path+ i = interpretSymbolicPathLBI lbi+ builtDir = componentBuildDir lbi clbi+ mbWorkDir = mbWorkDirLBI lbi install isShared srcDir dstDir name = do- let src = srcDir </> name+ let src = i $ srcDir </> makeRelativePathEx name dst = dstDir </> name createDirectoryIfMissingVerbose verbosity True dstDir@@ -918,13 +1002,15 @@ installOrdinary = install False installShared = install True - copyModuleFiles ext =- findModuleFilesEx verbosity [builtDir] [ext] (allLibModules lib clbi)- >>= installOrdinaryFiles verbosity targetDir+ copyModuleFiles ext = do+ files <- findModuleFilesCwd verbosity mbWorkDir [builtDir] [ext] (allLibModules lib clbi)+ let files' = map (i *** getSymbolicPath) files+ installOrdinaryFiles verbosity targetDir files' + copyDirectoryIfExists :: RelativePath Build (Dir Artifacts) -> IO () copyDirectoryIfExists dirName = do- let src = builtDir </> dirName- dst = targetDir </> dirName+ let src = i $ builtDir </> dirName+ dst = targetDir </> getSymbolicPath dirName dirExists <- doesDirectoryExist src when dirExists $ copyDirectoryRecursive verbosity src dst @@ -947,11 +1033,7 @@ Platform JavaScript _ -> True _ -> False has_code = not (componentIsIndefinite clbi)- whenHasCode = when has_code- whenVanilla = when (hasLib && withVanillaLib lbi)- whenProf = when (hasLib && withProfLib lbi && has_code) whenGHCi = when (hasLib && withGHCiLib lbi && has_code)- whenShared = when (hasLib && withSharedLib lbi && has_code) -- ----------------------------------------------------------------------------- -- Registering@@ -977,20 +1059,22 @@ registerPackage :: Verbosity -> ProgramDb- -> PackageDBStack+ -> Maybe (SymbolicPath CWD (Dir from))+ -> PackageDBStackS from -> InstalledPackageInfo -> HcPkg.RegisterOptions -> IO ()-registerPackage verbosity progdb packageDbs installedPkgInfo registerOptions =+registerPackage verbosity progdb mbWorkDir packageDbs installedPkgInfo registerOptions = HcPkg.register (hcPkgInfo progdb) verbosity+ mbWorkDir packageDbs installedPkgInfo registerOptions -pkgRoot :: Verbosity -> LocalBuildInfo -> PackageDB -> IO FilePath-pkgRoot verbosity lbi = pkgRoot'+pkgRoot :: Verbosity -> LocalBuildInfo -> PackageDB -> IO (SymbolicPath CWD (Dir Pkg))+pkgRoot verbosity lbi = fmap makeSymbolicPath . pkgRoot' where pkgRoot' GlobalPackageDB = let ghcProg = fromMaybe (error "GHC.pkgRoot: no ghc program") $ lookupProgram ghcProgram (withPrograms lbi)@@ -1006,9 +1090,12 @@ : prettyShow 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+ -- does not yet exist. 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)+ pkgRoot' (SpecificPackageDB fp) =+ return $+ takeDirectory $+ interpretSymbolicPathLBI lbi fp
src/Distribution/Simple/GHC/Build.hs view
@@ -1,30 +1,33 @@+{-# LANGUAGE DataKinds #-}+ module Distribution.Simple.GHC.Build where import Distribution.Compat.Prelude import Prelude () import Control.Monad.IO.Class-import qualified Data.Set as Set import Distribution.PackageDescription as PD hiding (buildInfo) import Distribution.Simple.Build.Inputs import Distribution.Simple.Flag (Flag) import Distribution.Simple.GHC.Build.ExtraSources import Distribution.Simple.GHC.Build.Link import Distribution.Simple.GHC.Build.Modules-import Distribution.Simple.GHC.Build.Utils (withDynFLib)+import Distribution.Simple.GHC.Build.Utils (isHaskell) import Distribution.Simple.LocalBuildInfo-import Distribution.Simple.Program+import Distribution.Simple.Program.Builtin (ghcProgram)+import Distribution.Simple.Program.Db (requireProgram) import Distribution.Simple.Utils-import Distribution.Types.ComponentLocalBuildInfo (componentIsIndefinite)++import Distribution.Types.ComponentLocalBuildInfo+import Distribution.Types.PackageName.Magic (fakePackageId) import Distribution.Types.ParStrat import Distribution.Utils.NubList (fromNubListR)-import System.Directory hiding (exeExtension)-import System.FilePath+import Distribution.Utils.Path -{--Note [Build Target Dir vs Target Dir]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+import System.FilePath (splitDirectories) +{- Note [Build Target Dir vs Target Dir]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Where to place the build result (targetDir) and the build artifacts (buildTargetDir). \* For libraries, targetDir == buildTargetDir, where both the library and@@ -47,7 +50,7 @@ invocations that different OSes constrain us to. Cabal invocations can rapidly reach this limit, in part, due to the long length of cabal v2 prefixes. To minimize the likelihood, we use-`makeRelativeToCurrentDirectory` to shorten the paths used in invocations+`tryMakeRelativeToWorkingDir` to shorten the paths used in invocations (see da6321bb). However, in executables, we don't do this. It seems that we don't need to do it@@ -68,73 +71,68 @@ build numJobs pkg_descr pbci = do let verbosity = buildVerbosity pbci- component = buildComponent pbci isLib = buildIsLib pbci lbi = localBuildInfo pbci clbi = buildCLBI pbci+ isIndef = componentIsIndefinite clbi+ mbWorkDir = mbWorkDirLBI lbi+ i = interpretSymbolicPathLBI lbi -- See Note [Symbolic paths] in Distribution.Utils.Path -- Create a few directories for building the component -- See Note [Build Target Dir vs Target Dir]- let targetDir_absolute = componentBuildDir lbi clbi- buildTargetDir_absolute+ let targetDir0 :: SymbolicPath Pkg ('Dir Build)+ targetDir0 = componentBuildDir lbi clbi+ buildTargetDir0 :: SymbolicPath Pkg ('Dir Artifacts)+ buildTargetDir0 -- Libraries use the target dir for building (see above)- | isLib = targetDir_absolute+ | isLib = coerceSymbolicPath targetDir0 -- In other cases, use targetDir/<name-of-target-dir>-tmp- | targetDirName : _ <- reverse $ splitDirectories targetDir_absolute =- targetDir_absolute </> (targetDirName ++ "-tmp")+ | targetDirName : _ <- reverse $ splitDirectories $ getSymbolicPath targetDir0 =+ coerceSymbolicPath targetDir0 </> makeRelativePathEx (targetDirName ++ "-tmp") | otherwise = error "GHC.build: targetDir is empty" liftIO $ do- createDirectoryIfMissingVerbose verbosity True targetDir_absolute- createDirectoryIfMissingVerbose verbosity True buildTargetDir_absolute+ createDirectoryIfMissingVerbose verbosity True $ i targetDir0+ createDirectoryIfMissingVerbose verbosity True $ i buildTargetDir0 -- See Note [Build Target Dir vs Target Dir] as well- _targetDir <- liftIO $ makeRelativeToCurrentDirectory targetDir_absolute+ let targetDir = targetDir0 -- NB: no 'makeRelative' buildTargetDir <-- -- To preserve the previous behaviour, we don't use relative dirs for- -- executables. Historically, this isn't needed to reduce the CLI limit- -- (unlike for libraries) because we link executables with the module names- -- instead of passing the path to object file -- that's something else we- -- can now fix after the refactor lands. if isLib- then liftIO $ makeRelativeToCurrentDirectory buildTargetDir_absolute- else return buildTargetDir_absolute+ then -- NB: this might fail to make the buildTargetDir relative,+ -- as noted in #9776. Oh well.+ tryMakeRelative mbWorkDir buildTargetDir0+ else return buildTargetDir0+ -- To preserve the previous behaviour, we don't use relative dirs for+ -- executables. Historically, this isn't needed to reduce the CLI limit+ -- (unlike for libraries) because we link executables with the module names+ -- instead of passing the path to object file -- that's something else we+ -- can now fix after the refactor lands. (ghcProg, _) <- liftIO $ requireProgram verbosity ghcProgram (withPrograms lbi) - -- Determine in which ways we want to build the component- let- wantVanilla = if isLib then withVanillaLib lbi else False- -- Arguably, wantStatic should be "withFullyStaticExe lbi" for executables,- -- but it was not before the refactor.- wantStatic = if isLib then withStaticLib lbi else not (wantDynamic || wantProf)- wantDynamic = case component of- CLib{} -> withSharedLib lbi- CFLib flib -> withDynFLib flib- CExe{} -> withDynExe lbi- CTest{} -> withDynExe lbi- CBench{} -> withDynExe lbi- wantProf = if isLib then withProfLib lbi else withProfExe lbi-- -- See also Note [Building Haskell Modules accounting for TH] in Distribution.Simple.GHC.Build.Modules- -- We build static by default if no other way is wanted.- -- For executables and foreign libraries, there should only be one wanted way.- wantedWays =- Set.fromList $- -- If building a library, we accumulate all the ways,- -- otherwise, we take just one.- (if isLib then id else take 1) $- [ProfWay | wantProf]- -- I don't see why we shouldn't build with dynamic- -- indefinite components.- <> [DynWay | wantDynamic && not (componentIsIndefinite clbi)]- <> [StaticWay | wantStatic || wantVanilla || not (wantDynamic || wantProf)]-- liftIO $ info verbosity ("Wanted build ways: " ++ show (Set.toList wantedWays))+ let wantedWays@(wantedLibWays, _, wantedExeWay) = buildWays lbi + liftIO $ info verbosity ("Wanted build ways(" ++ show isLib ++ "): " ++ show (if isLib then wantedLibWays isIndef else [wantedExeWay])) -- We need a separate build and link phase, and C sources must be compiled -- after Haskell modules, because C sources may depend on stub headers -- generated from compiling Haskell modules (#842, #3294).- buildOpts <- buildHaskellModules numJobs ghcProg pkg_descr buildTargetDir_absolute wantedWays pbci- extraSources <- buildAllExtraSources ghcProg buildTargetDir pbci- linkOrLoadComponent ghcProg pkg_descr (fromNubListR extraSources) (buildTargetDir, targetDir_absolute) (wantedWays, buildOpts) pbci+ (mbMainFile, inputModules) <- componentInputs buildTargetDir pkg_descr pbci+ let (hsMainFile, nonHsMainFile) =+ case mbMainFile of+ Just mainFile+ | PD.package pkg_descr == fakePackageId+ || isHaskell (getSymbolicPath mainFile) ->+ (Just mainFile, Nothing)+ | otherwise ->+ (Nothing, Just mainFile)+ Nothing -> (Nothing, Nothing)+ buildOpts <- buildHaskellModules numJobs ghcProg hsMainFile inputModules buildTargetDir (wantedLibWays isIndef) pbci+ extraSources <- buildAllExtraSources nonHsMainFile ghcProg buildTargetDir wantedWays pbci+ linkOrLoadComponent+ ghcProg+ pkg_descr+ (fromNubListR extraSources)+ (buildTargetDir, targetDir)+ (wantedWays, buildOpts)+ pbci
src/Distribution/Simple/GHC/Build/ExtraSources.hs view
@@ -1,6 +1,8 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DisambiguateRecordFields #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE RankNTypes #-} module Distribution.Simple.GHC.Build.ExtraSources where @@ -16,26 +18,30 @@ import Distribution.Types.Component import Distribution.Types.TargetInfo +import Distribution.Simple.Build.Inputs+import Distribution.Simple.GHC.Build.Modules import Distribution.Simple.GHC.Build.Utils import Distribution.Simple.LocalBuildInfo import Distribution.Simple.Program.Types import Distribution.System (Arch (JavaScript), Platform (..)) import Distribution.Types.ComponentLocalBuildInfo-import Distribution.Types.Executable+import Distribution.Utils.Path import Distribution.Verbosity (Verbosity) -import Distribution.Simple.Build.Inputs- -- | An action that builds all the extra build sources of a component, i.e. C, -- C++, Js, Asm, C-- sources. buildAllExtraSources- :: ConfiguredProgram+ :: Maybe (SymbolicPath Pkg File)+ -- ^ An optional non-Haskell Main file+ -> ConfiguredProgram -- ^ The GHC configured program- -> FilePath+ -> SymbolicPath Pkg (Dir Artifacts) -- ^ The build directory for this target+ -> (Bool -> [BuildWay], Bool -> BuildWay, BuildWay)+ -- ^ Needed build ways -> PreBuildComponentInputs -- ^ The context and component being built in it.- -> IO (NubListR FilePath)+ -> IO (NubListR (SymbolicPath Pkg File)) -- ^ Returns the (nubbed) list of extra sources that were built buildAllExtraSources = mconcat@@ -51,43 +57,50 @@ , buildJsSources , buildAsmSources , buildCmmSources- :: ConfiguredProgram+ :: Maybe (SymbolicPath Pkg File)+ -- ^ An optional non-Haskell Main file+ -> ConfiguredProgram -- ^ The GHC configured program- -> FilePath+ -> SymbolicPath Pkg (Dir Artifacts) -- ^ The build directory for this target+ -> (Bool -> [BuildWay], Bool -> BuildWay, BuildWay)+ -- ^ Needed build ways -> PreBuildComponentInputs -- ^ The context and component being built in it.- -> IO (NubListR FilePath)+ -> IO (NubListR (SymbolicPath Pkg File)) -- ^ Returns the list of extra sources that were built-buildCSources =+buildCSources mbMainFile = buildExtraSources "C Sources" Internal.componentCcGhcOptions- True- ( \c ->- cSources (componentBuildInfo c)- ++ case c of- CExe exe | isC (modulePath exe) -> [modulePath exe]- _otherwise -> []+ ( \c -> do+ let cFiles = cSources (componentBuildInfo c)+ case c of+ CExe{}+ | Just main <- mbMainFile+ , isC $ getSymbolicPath main ->+ cFiles ++ [main]+ _otherwise -> cFiles )-buildCxxSources =+buildCxxSources mbMainFile = buildExtraSources "C++ Sources" Internal.componentCxxGhcOptions- True- ( \c ->- cxxSources (componentBuildInfo c)- ++ case c of- CExe exe | isCxx (modulePath exe) -> [modulePath exe]- _otherwise -> []+ ( \c -> do+ let cxxFiles = cxxSources (componentBuildInfo c)+ case c of+ CExe{}+ | Just main <- mbMainFile+ , isCxx $ getSymbolicPath main ->+ cxxFiles ++ [main]+ _otherwise -> cxxFiles )-buildJsSources ghcProg buildTargetDir = do+buildJsSources _mbMainFile ghcProg buildTargetDir neededWays = do Platform hostArch _ <- hostPlatform <$> localBuildInfo let hasJsSupport = hostArch == JavaScript buildExtraSources "JS Sources" Internal.componentJsGhcOptions- False ( \c -> if hasJsSupport then -- JS files are C-like with GHC's JS backend: they are@@ -99,17 +112,16 @@ ) ghcProg buildTargetDir-buildAsmSources =+ neededWays+buildAsmSources _mbMainFile = buildExtraSources "Assembler Sources" Internal.componentAsmGhcOptions- True (asmSources . componentBuildInfo)-buildCmmSources =+buildCmmSources _mbMainFile = buildExtraSources "C-- Sources" Internal.componentCmmGhcOptions- True (cmmSources . componentBuildInfo) -- | Create 'PreBuildComponentRules' for a given type of extra build sources@@ -118,16 +130,19 @@ buildExtraSources :: String -- ^ String describing the extra sources being built, for printing.- -> (Verbosity -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo -> FilePath -> FilePath -> GhcOptions)+ -> ( Verbosity+ -> LocalBuildInfo+ -> BuildInfo+ -> ComponentLocalBuildInfo+ -> SymbolicPath Pkg (Dir Artifacts)+ -> SymbolicPath Pkg File+ -> GhcOptions+ ) -- ^ Function to determine the @'GhcOptions'@ for the -- invocation of GHC when compiling these extra sources (e.g. -- @'Internal.componentCxxGhcOptions'@, -- @'Internal.componentCmmGhcOptions'@)- -> Bool- -- ^ Some types of build sources should not be built in the dynamic way, namely, JS sources.- -- I'm not entirely sure this remains true after we migrate to supporting GHC's JS backend rather than GHCJS.- -- Boolean for "do we allow building these sources the dynamic way?"- -> (Component -> [FilePath])+ -> (Component -> [SymbolicPath Pkg File]) -- ^ View the extra sources of a component, typically from -- the build info (e.g. @'asmSources'@, @'cSources'@). -- @'Executable'@ components might additionally add the@@ -135,104 +150,107 @@ -- if it should be compiled as the rest of them. -> ConfiguredProgram -- ^ The GHC configured program- -> FilePath+ -> SymbolicPath Pkg (Dir Artifacts) -- ^ The build directory for this target+ -> (Bool -> [BuildWay], Bool -> BuildWay, BuildWay)+ -- ^ Needed build ways -> PreBuildComponentInputs -- ^ The context and component being built in it.- -> IO (NubListR FilePath)+ -> IO (NubListR (SymbolicPath Pkg File)) -- ^ Returns the list of extra sources that were built-buildExtraSources description componentSourceGhcOptions wantDyn viewSources ghcProg buildTargetDir =- \PreBuildComponentInputs{buildingWhat, localBuildInfo = lbi, targetInfo} ->- let- bi = componentBuildInfo (targetComponent targetInfo)- verbosity = buildingWhatVerbosity buildingWhat- clbi = targetCLBI targetInfo-- sources = viewSources (targetComponent targetInfo)+buildExtraSources+ description+ componentSourceGhcOptions+ viewSources+ ghcProg+ buildTargetDir+ (neededLibWays, neededFLibWay, neededExeWay) =+ \PreBuildComponentInputs{buildingWhat, localBuildInfo = lbi, targetInfo} -> do+ let+ bi = componentBuildInfo (targetComponent targetInfo)+ verbosity = buildingWhatVerbosity buildingWhat+ clbi = targetCLBI targetInfo+ isIndef = componentIsIndefinite clbi+ mbWorkDir = mbWorkDirLBI lbi+ i = interpretSymbolicPath mbWorkDir+ sources = viewSources (targetComponent targetInfo)+ comp = compiler lbi+ platform = hostPlatform lbi+ runGhcProg = runGHC verbosity ghcProg comp platform - comp = compiler lbi- platform = hostPlatform lbi- -- Instead of keeping this logic here, we really just want to- -- receive as an input the `neededWays` from GHC/Build.build and build- -- accordingly, since we've already determined the extra needed ways- -- needed for e.g. template haskell. Although we'd have to account for 'wantDyn'.- isGhcDynamic = isDynamic comp- doingTH = usesTemplateHaskellOrQQ bi- forceSharedLib = doingTH && isGhcDynamic- runGhcProg = runGHC verbosity ghcProg comp platform+ buildAction :: SymbolicPath Pkg File -> IO ()+ buildAction sourceFile = do+ let baseSrcOpts =+ componentSourceGhcOptions+ verbosity+ lbi+ bi+ clbi+ buildTargetDir+ sourceFile+ vanillaSrcOpts =+ -- -fPIC is used in case you are using the repl+ -- of a dynamically linked GHC+ baseSrcOpts{ghcOptFPic = toFlag True}+ profSrcOpts =+ vanillaSrcOpts+ `mappend` mempty+ { ghcOptProfilingMode = toFlag True+ }+ sharedSrcOpts =+ vanillaSrcOpts+ `mappend` mempty+ { ghcOptFPic = toFlag True+ , ghcOptDynLinkMode = toFlag GhcDynamicOnly+ }+ profSharedSrcOpts =+ vanillaSrcOpts+ `mappend` mempty+ { ghcOptProfilingMode = toFlag True+ , ghcOptFPic = toFlag True+ , ghcOptDynLinkMode = toFlag GhcDynamicOnly+ }+ -- TODO: Placing all Haskell, C, & C++ objects in a single directory+ -- Has the potential for file collisions. In general we would+ -- consider this a user error. However, we should strive to+ -- add a warning if this occurs.+ odir = fromFlag (ghcOptObjDir vanillaSrcOpts) - buildAction sourceFile = do- let baseSrcOpts =- componentSourceGhcOptions- verbosity- lbi- bi- clbi- buildTargetDir- sourceFile- vanillaSrcOpts- -- Dynamic GHC requires C sources to be built- -- with -fPIC for REPL to work. See #2207.- | isGhcDynamic && wantDyn = baseSrcOpts{ghcOptFPic = toFlag True}- | otherwise = baseSrcOpts- profSrcOpts =- vanillaSrcOpts- `mappend` mempty- { ghcOptProfilingMode = toFlag True- }- sharedSrcOpts =- vanillaSrcOpts- `mappend` mempty- { ghcOptFPic = toFlag True- , ghcOptDynLinkMode = toFlag GhcDynamicOnly- }- -- TODO: Placing all Haskell, C, & C++ objects in a single directory- -- Has the potential for file collisions. In general we would- -- consider this a user error. However, we should strive to- -- add a warning if this occurs.- odir = fromFlag (ghcOptObjDir vanillaSrcOpts)- compileIfNeeded opts = do- needsRecomp <- checkNeedsRecompilation sourceFile opts- when needsRecomp $ runGhcProg opts+ compileIfNeeded :: GhcOptions -> IO ()+ compileIfNeeded opts = do+ needsRecomp <- checkNeedsRecompilation mbWorkDir sourceFile opts+ when needsRecomp $ runGhcProg mbWorkDir opts - -- TODO: This whole section can be streamlined to the- -- wantedWays+neededWays logic used in Build/Modules.hs- createDirectoryIfMissingVerbose verbosity True odir- case targetComponent targetInfo of- -- For libraries, we compile extra objects in the three ways: vanilla, shared, and profiled.- -- We suffix shared objects with .dyn_o and profiled ones with .p_o.- CLib _lib- -- Unless for repl, in which case we only need the vanilla way- | BuildRepl _ <- buildingWhat ->- compileIfNeeded vanillaSrcOpts- | otherwise ->- do+ createDirectoryIfMissingVerbose verbosity True (i odir)+ case targetComponent targetInfo of+ -- For libraries, we compile extra objects in the four ways: vanilla, shared, profiled and profiled shared.+ -- We suffix shared objects with `.dyn_o`, profiled ones with `.p_o` and profiled shared ones with `.p_dyn_o`.+ CLib _lib+ -- Unless for repl, in which case we only need the vanilla way+ | BuildRepl _ <- buildingWhat -> compileIfNeeded vanillaSrcOpts- when (wantDyn && (forceSharedLib || withSharedLib lbi)) $- compileIfNeeded sharedSrcOpts{ghcOptObjSuffix = toFlag "dyn_o"}- when (withProfLib lbi) $- compileIfNeeded profSrcOpts{ghcOptObjSuffix = toFlag "p_o"}-- -- For foreign libraries, we determine with which options to build the- -- objects (vanilla vs shared vs profiled)- CFLib flib- | withProfExe lbi -> -- It doesn't sound right to query "ProfExe" for a foreign library...- compileIfNeeded profSrcOpts- | withDynFLib flib && wantDyn ->- compileIfNeeded sharedSrcOpts- | otherwise ->- compileIfNeeded vanillaSrcOpts- -- For the remaining component types (Exec, Test, Bench), we also- -- determine with which options to build the objects (vanilla vs shared vs- -- profiled), but predicate is the same for the three kinds.- _exeLike- | withProfExe lbi ->- compileIfNeeded profSrcOpts- | withDynExe lbi && wantDyn ->- compileIfNeeded sharedSrcOpts- | otherwise ->- compileIfNeeded vanillaSrcOpts- in+ | otherwise ->+ do+ forM_ (neededLibWays isIndef) $ \case+ StaticWay -> compileIfNeeded vanillaSrcOpts+ DynWay -> compileIfNeeded sharedSrcOpts{ghcOptObjSuffix = toFlag "dyn_o"}+ ProfWay -> compileIfNeeded profSrcOpts{ghcOptObjSuffix = toFlag "p_o"}+ ProfDynWay -> compileIfNeeded profSharedSrcOpts{ghcOptObjSuffix = toFlag "p_dyn_o"}+ CFLib flib ->+ case neededFLibWay (withDynFLib flib) of+ StaticWay -> compileIfNeeded vanillaSrcOpts+ DynWay -> compileIfNeeded sharedSrcOpts+ ProfWay -> compileIfNeeded profSrcOpts+ ProfDynWay -> compileIfNeeded profSharedSrcOpts+ -- For the remaining component types (Exec, Test, Bench), we also+ -- determine with which options to build the objects (vanilla vs shared vs+ -- profiled), but predicate is the same for the three kinds.+ _exeLike ->+ case neededExeWay of+ StaticWay -> compileIfNeeded vanillaSrcOpts+ DynWay -> compileIfNeeded sharedSrcOpts+ ProfWay -> compileIfNeeded profSrcOpts+ ProfDynWay -> compileIfNeeded profSharedSrcOpts -- build any sources if (null sources || componentIsIndefinite clbi) then return mempty
src/Distribution/Simple/GHC/Build/Link.hs view
@@ -1,12 +1,13 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeApplications #-} module Distribution.Simple.GHC.Build.Link where import Distribution.Compat.Prelude import Prelude () -import Control.Exception (assert)-import Control.Monad (forM_) import Control.Monad.IO.Class import qualified Data.ByteString.Lazy.Char8 as BS import qualified Data.Set as Set@@ -35,15 +36,27 @@ import Distribution.Simple.Program.GHC import qualified Distribution.Simple.Program.Ld as Ld import Distribution.Simple.Setup.Common+import Distribution.Simple.Setup.Config import Distribution.Simple.Setup.Repl import Distribution.Simple.Utils import Distribution.System import Distribution.Types.ComponentLocalBuildInfo import Distribution.Utils.NubList+import Distribution.Utils.Path import Distribution.Verbosity import Distribution.Version+ import System.Directory+ ( createDirectoryIfMissing+ , doesDirectoryExist+ , doesFileExist+ , removeFile+ , renameFile+ ) import System.FilePath+ ( isRelative+ , replaceExtension+ ) -- | Links together the object files of the Haskell modules and extra sources -- using the context in which the component is being built.@@ -54,129 +67,161 @@ -- ^ The configured GHC program that will be used for linking -> PackageDescription -- ^ The package description containing the component being built- -> [FilePath]+ -> [SymbolicPath Pkg File] -- ^ The full list of extra build sources (all C, C++, Js, -- Asm, and Cmm sources), which were compiled to object -- files.- -> (FilePath, FilePath)+ -> (SymbolicPath Pkg (Dir Artifacts), SymbolicPath Pkg (Dir Build)) -- ^ The build target dir, and the target dir. -- See Note [Build Target Dir vs Target Dir] in Distribution.Simple.GHC.Build- -> (Set.Set BuildWay, BuildWay -> GhcOptions)+ -> ((Bool -> [BuildWay], Bool -> BuildWay, BuildWay), BuildWay -> GhcOptions) -- ^ The set of build ways wanted based on the user opts, and a function to -- convert a build way into the set of ghc options that were used to build -- that way. -> PreBuildComponentInputs -- ^ The context and component being built in it. -> IO ()-linkOrLoadComponent ghcProg pkg_descr extraSources (buildTargetDir, targetDir) (wantedWays, buildOpts) pbci = do- let- verbosity = buildVerbosity pbci- target = targetInfo pbci- component = buildComponent pbci- what = buildingWhat pbci- lbi = localBuildInfo pbci- bi = buildBI pbci- clbi = buildCLBI pbci+linkOrLoadComponent+ ghcProg+ pkg_descr+ extraSources+ (buildTargetDir, targetDir)+ ((wantedLibWays, wantedFLibWay, wantedExeWay), buildOpts)+ pbci = do+ let+ verbosity = buildVerbosity pbci+ target = targetInfo pbci+ component = buildComponent pbci+ what = buildingWhat pbci+ lbi = localBuildInfo pbci+ bi = buildBI pbci+ clbi = buildCLBI pbci+ isIndef = componentIsIndefinite clbi+ mbWorkDir = mbWorkDirLBI lbi - -- ensure extra lib dirs exist before passing to ghc- cleanedExtraLibDirs <- liftIO $ filterM doesDirectoryExist (extraLibDirs bi)- cleanedExtraLibDirsStatic <- liftIO $ filterM doesDirectoryExist (extraLibDirsStatic bi)+ -- See Note [Symbolic paths] in Distribution.Utils.Path+ i = interpretSymbolicPathLBI lbi - let- extraSourcesObjs = map (`replaceExtension` objExtension) extraSources+ -- ensure extra lib dirs exist before passing to ghc+ cleanedExtraLibDirs <- liftIO $ filterM (doesDirectoryExist . i) (extraLibDirs bi)+ cleanedExtraLibDirsStatic <- liftIO $ filterM (doesDirectoryExist . i) (extraLibDirsStatic bi) - -- TODO: Shouldn't we use withStaticLib for libraries and something else- -- for foreign libs in the three cases where we use `withFullyStaticExe` below?- linkerOpts rpaths =- mempty- { ghcOptLinkOptions =- PD.ldOptions bi- ++ [ "-static"- | withFullyStaticExe lbi- ]- -- Pass extra `ld-options` given- -- through to GHC's linker.- ++ maybe- []- programOverrideArgs- (lookupProgram ldProgram (withPrograms lbi))- , ghcOptLinkLibs =- if withFullyStaticExe lbi- then extraLibsStatic bi- else extraLibs bi- , ghcOptLinkLibPath =- toNubListR $+ let+ extraSourcesObjs :: [RelativePath Artifacts File]+ extraSourcesObjs =+ [ makeRelativePathEx $ getSymbolicPath src `replaceExtension` objExtension+ | src <- extraSources+ ]++ -- TODO: Shouldn't we use withStaticLib for libraries and something else+ -- for foreign libs in the three cases where we use `withFullyStaticExe` below?+ linkerOpts rpaths =+ mempty+ { ghcOptLinkOptions =+ PD.ldOptions bi+ ++ [ "-static"+ | withFullyStaticExe lbi+ ]+ -- Pass extra `ld-options` given+ -- through to GHC's linker.+ ++ maybe+ []+ programOverrideArgs+ (lookupProgram ldProgram (withPrograms lbi))+ , ghcOptLinkLibs = if withFullyStaticExe lbi- then cleanedExtraLibDirsStatic- else cleanedExtraLibDirs- , ghcOptLinkFrameworks = toNubListR $ PD.frameworks bi- , ghcOptLinkFrameworkDirs = toNubListR $ PD.extraFrameworkDirs bi- , ghcOptInputFiles = toNubListR [buildTargetDir </> x | x <- extraSourcesObjs]- , ghcOptNoLink = Flag False- , ghcOptRPaths = rpaths- }- case what of- BuildRepl replFlags -> liftIO $ do- let- -- For repl we use the vanilla (static) ghc options- staticOpts = buildOpts StaticWay- replOpts =- staticOpts- { -- Repl options use Static as the base, but doesn't need to pass -static.- -- However, it maybe should, for uniformity.- ghcOptDynLinkMode = NoFlag- , ghcOptExtra =- Internal.filterGhciFlags- (ghcOptExtra staticOpts)- <> replOptionsFlags (replReplOptions replFlags)- , ghcOptInputModules = replNoLoad (replReplOptions replFlags) (ghcOptInputModules staticOpts)- , ghcOptInputFiles = replNoLoad (replReplOptions replFlags) (ghcOptInputFiles staticOpts)- }- -- 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.- --- -- TODO: The repl doesn't use the runtime paths from linkerOpts- -- (ghcOptRPaths), which looks like a bug. After the refactor we- -- can fix this.- `mappend` linkerOpts mempty- `mappend` mempty- { ghcOptMode = toFlag GhcModeInteractive- , ghcOptOptimisation = toFlag GhcNoOptimisation+ then extraLibsStatic bi+ else extraLibs bi+ , ghcOptLinkLibPath =+ toNubListR $+ if withFullyStaticExe lbi+ then cleanedExtraLibDirsStatic+ else cleanedExtraLibDirs+ , ghcOptLinkFrameworks = toNubListR $ map getSymbolicPath $ PD.frameworks bi+ , ghcOptLinkFrameworkDirs = toNubListR $ PD.extraFrameworkDirs bi+ , ghcOptInputFiles =+ toNubListR+ [ coerceSymbolicPath $ buildTargetDir </> obj+ | obj <- extraSourcesObjs+ ]+ , ghcOptNoLink = Flag False+ , ghcOptRPaths = rpaths+ }++ case what of+ BuildRepl replFlags -> liftIO $ do+ let+ -- For repl we use the vanilla (static) ghc options+ staticOpts = buildOpts StaticWay+ replOpts =+ staticOpts+ { -- Repl options use Static as the base, but doesn't need to pass -static.+ -- However, it maybe should, for uniformity.+ ghcOptDynLinkMode = NoFlag+ , ghcOptExtra =+ Internal.filterGhciFlags+ (ghcOptExtra staticOpts)+ <> replOptionsFlags (replReplOptions replFlags) }+ -- 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.+ --+ -- TODO: The repl doesn't use the runtime paths from linkerOpts+ -- (ghcOptRPaths), which looks like a bug. After the refactor we+ -- can fix this.+ `mappend` linkerOpts mempty+ `mappend` mempty+ { ghcOptMode = toFlag GhcModeInteractive+ , ghcOptOptimisation = toFlag GhcNoOptimisation+ }+ replOpts_final =+ replOpts+ { ghcOptInputModules = replNoLoad (replReplOptions replFlags) (ghcOptInputModules replOpts)+ , ghcOptInputFiles = replNoLoad (replReplOptions replFlags) (ghcOptInputFiles replOpts)+ } - -- 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 (case component of CLib lib -> null (allLibModules lib clbi); _ -> False) $- warn verbosity "No exposed modules"- runReplOrWriteFlags ghcProg lbi replFlags replOpts (pkgName (PD.package pkg_descr)) target- _otherwise ->- let- runGhcProg = runGHC verbosity ghcProg comp platform- platform = hostPlatform lbi- comp = compiler lbi- in- when (not $ componentIsIndefinite clbi) $ do- -- If not building dynamically, we don't pass any runtime paths.- rpaths <- if DynWay `Set.member` wantedWays then getRPaths pbci else return (toNubListR [])- liftIO $ do- info verbosity "Linking..."- let linkExeLike name = linkExecutable (linkerOpts rpaths) (wantedWays, buildOpts) targetDir name runGhcProg lbi- case component of- CLib lib -> linkLibrary buildTargetDir cleanedExtraLibDirs pkg_descr verbosity runGhcProg lib lbi clbi extraSources rpaths wantedWays- CFLib flib -> linkFLib flib bi lbi (linkerOpts rpaths) (wantedWays, buildOpts) targetDir runGhcProg- CExe exe -> linkExeLike (exeName exe)- CTest test -> linkExeLike (testName test)- CBench bench -> linkExeLike (benchmarkName bench)+ -- 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 (case component of CLib lib -> null (allLibModules lib clbi); _ -> False) $+ warn verbosity "No exposed modules"+ runReplOrWriteFlags ghcProg lbi replFlags replOpts_final (pkgName (PD.package pkg_descr)) target+ _otherwise ->+ let+ runGhcProg = runGHC verbosity ghcProg comp platform mbWorkDir+ platform = hostPlatform lbi+ comp = compiler lbi+ get_rpaths ways =+ if DynWay `Set.member` ways then getRPaths pbci else return (toNubListR [])+ in+ when (not $ componentIsIndefinite clbi) $ do+ -- If not building dynamically, we don't pass any runtime paths.+ liftIO $ do+ info verbosity "Linking..."+ let linkExeLike name = do+ rpaths <- get_rpaths (Set.singleton wantedExeWay)+ linkExecutable (linkerOpts rpaths) (wantedExeWay, buildOpts) targetDir name runGhcProg lbi+ case component of+ CLib lib -> do+ let libWays = wantedLibWays isIndef+ rpaths <- get_rpaths (Set.fromList libWays)+ linkLibrary buildTargetDir cleanedExtraLibDirs pkg_descr verbosity runGhcProg lib lbi clbi extraSources rpaths libWays+ CFLib flib -> do+ let flib_way = wantedFLibWay (withDynFLib flib)+ rpaths <- get_rpaths (Set.singleton flib_way)+ linkFLib flib bi lbi (linkerOpts rpaths) (flib_way, buildOpts) targetDir runGhcProg+ CExe exe -> linkExeLike (exeName exe)+ CTest test -> linkExeLike (testName test)+ CBench bench -> linkExeLike (benchmarkName bench) -- | Link a library component linkLibrary- :: FilePath+ :: SymbolicPath Pkg (Dir Artifacts) -- ^ The library target build directory- -> [FilePath]+ -> [SymbolicPath Pkg (Dir Lib)] -- ^ The list of extra lib dirs that exist (aka "cleaned") -> PackageDescription -- ^ The package description containing this library@@ -186,15 +231,18 @@ -> Library -> LocalBuildInfo -> ComponentLocalBuildInfo- -> [FilePath]+ -> [SymbolicPath Pkg File] -- ^ Extra build sources (that were compiled to objects) -> NubListR FilePath -- ^ A list with the runtime-paths (rpaths), or empty if not linking dynamically- -> Set.Set BuildWay+ -> [BuildWay] -- ^ Wanted build ways and corresponding build options -> IO () linkLibrary buildTargetDir cleanedExtraLibDirs pkg_descr verbosity runGhcProg lib lbi clbi extraSources rpaths wantedWays = do let+ common = configCommonFlags $ configFlags lbi+ mbWorkDir = flagToMaybe $ setupWorkingDir common+ compiler_id = compilerId comp comp = compiler lbi ghcVersion = compilerVersion comp@@ -202,16 +250,19 @@ uid = componentUnitId clbi libBi = libBuildInfo lib Platform _hostArch hostOS = hostPlatform lbi- vanillaLibFilePath = buildTargetDir </> mkLibName uid- profileLibFilePath = buildTargetDir </> mkProfLibName uid+ vanillaLibFilePath = buildTargetDir </> makeRelativePathEx (mkLibName uid)+ profileLibFilePath = buildTargetDir </> makeRelativePathEx (mkProfLibName uid) sharedLibFilePath = buildTargetDir- </> mkSharedLibName (hostPlatform lbi) compiler_id uid+ </> makeRelativePathEx (mkSharedLibName (hostPlatform lbi) compiler_id uid)+ profSharedLibFilePath =+ buildTargetDir+ </> makeRelativePathEx (mkProfSharedLibName (hostPlatform lbi) compiler_id uid) staticLibFilePath = buildTargetDir- </> mkStaticLibName (hostPlatform lbi) compiler_id uid- ghciLibFilePath = buildTargetDir </> Internal.mkGHCiLibName uid- ghciProfLibFilePath = buildTargetDir </> Internal.mkGHCiProfLibName uid+ </> makeRelativePathEx (mkStaticLibName (hostPlatform lbi) compiler_id uid)+ ghciLibFilePath = buildTargetDir </> makeRelativePathEx (Internal.mkGHCiLibName uid)+ ghciProfLibFilePath = buildTargetDir </> makeRelativePathEx (Internal.mkGHCiProfLibName uid) libInstallPath = libdir $ absoluteComponentInstallDirs@@ -222,7 +273,11 @@ sharedLibInstallPath = libInstallPath </> mkSharedLibName (hostPlatform lbi) compiler_id uid+ profSharedLibInstallPath =+ libInstallPath+ </> mkProfSharedLibName (hostPlatform lbi) compiler_id uid + getObjFiles :: BuildWay -> IO [SymbolicPath Pkg File] getObjFiles way = mconcat [ Internal.getHaskellObjects@@ -233,20 +288,34 @@ buildTargetDir (buildWayPrefix way ++ objExtension) True- , pure $- map (buildTargetDir </>) $- map ((`replaceExtension` (buildWayPrefix way ++ objExtension))) extraSources+ , pure $ map (srcObjPath way) extraSources , catMaybes <$> sequenceA- [ findFileWithExtension+ [ findFileCwdWithExtension+ mbWorkDir [Suffix $ buildWayPrefix way ++ objExtension] [buildTargetDir]- (ModuleName.toFilePath x ++ "_stub")+ xPath | ghcVersion < mkVersion [7, 2] -- ghc-7.2+ does not make _stub.o files , x <- allLibModules lib clbi+ , let xPath :: RelativePath Artifacts File+ xPath = makeRelativePathEx $ ModuleName.toFilePath x ++ "_stub" ] ] + -- Get the @.o@ path from a source path (e.g. @.hs@),+ -- in the library target build directory.+ srcObjPath :: BuildWay -> SymbolicPath Pkg File -> SymbolicPath Pkg File+ srcObjPath way srcPath =+ case symbolicPathRelative_maybe objPath of+ -- Absolute path: should already be in the target build directory+ -- (e.g. a preprocessed file)+ -- TODO: assert this?+ Nothing -> objPath+ Just objRelPath -> coerceSymbolicPath buildTargetDir </> objRelPath+ where+ objPath = srcPath `replaceExtensionSymbolicPath` (buildWayPrefix way ++ objExtension)+ -- I'm fairly certain that, just like the executable, we can keep just the -- module input list, and point to the right sources dir (as is already -- done), and GHC will pick up the right suffix (p_ for profile, dyn_ when@@ -291,11 +360,12 @@ -- 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 :: [SymbolicPath Pkg File] -> GhcOptions ghcSharedLinkArgs dynObjectFiles = ghcBaseLinkArgs { ghcOptShared = toFlag True , ghcOptDynLinkMode = toFlag GhcDynamicOnly- , ghcOptInputFiles = toNubListR dynObjectFiles+ , ghcOptInputFiles = toNubListR $ map coerceSymbolicPath dynObjectFiles , 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@@ -307,15 +377,41 @@ else mempty , ghcOptLinkLibs = extraLibs libBi , ghcOptLinkLibPath = toNubListR $ cleanedExtraLibDirs- , ghcOptLinkFrameworks = toNubListR $ PD.frameworks libBi+ , ghcOptLinkFrameworks = toNubListR $ map getSymbolicPath $ PD.frameworks libBi , ghcOptLinkFrameworkDirs = toNubListR $ PD.extraFrameworkDirs libBi , ghcOptRPaths = rpaths }+ ghcProfSharedLinkArgs pdynObjectFiles =+ ghcBaseLinkArgs+ { ghcOptShared = toFlag True+ , ghcOptProfilingMode = toFlag True+ , ghcOptProfilingAuto =+ Internal.profDetailLevelFlag+ True+ (withProfLibDetail lbi)+ , ghcOptDynLinkMode = toFlag GhcDynamicOnly+ , ghcOptInputFiles = toNubListR pdynObjectFiles+ , ghcOptOutputFile = toFlag profSharedLibFilePath+ , -- 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 < mkVersion [7, 8]+ then toFlag profSharedLibInstallPath+ else mempty+ , ghcOptLinkLibs = extraLibs libBi+ , ghcOptLinkLibPath = toNubListR $ cleanedExtraLibDirs+ , ghcOptLinkFrameworks = toNubListR $ map getSymbolicPath $ PD.frameworks libBi+ , ghcOptLinkFrameworkDirs =+ toNubListR $ PD.extraFrameworkDirs libBi+ , ghcOptRPaths = rpaths+ } ghcStaticLinkArgs staticObjectFiles = ghcBaseLinkArgs { ghcOptStaticLib = toFlag True- , ghcOptInputFiles = toNubListR staticObjectFiles+ , ghcOptInputFiles = toNubListR $ map coerceSymbolicPath staticObjectFiles , ghcOptOutputFile = toFlag staticLibFilePath , ghcOptLinkLibs = extraLibs libBi , -- TODO: Shouldn't this use cleanedExtraLibDirsStatic instead?@@ -325,6 +421,7 @@ staticObjectFiles <- getObjFiles StaticWay profObjectFiles <- getObjFiles ProfWay dynamicObjectFiles <- getObjFiles DynWay+ profDynamicObjectFiles <- getObjFiles ProfDynWay let linkWay = \case@@ -338,6 +435,8 @@ ldProg ghciProfLibFilePath profObjectFiles+ ProfDynWay -> do+ runGhcProg $ ghcProfSharedLinkArgs profDynamicObjectFiles DynWay -> do runGhcProg $ ghcSharedLinkArgs dynamicObjectFiles StaticWay -> do@@ -367,10 +466,10 @@ linkExecutable :: (GhcOptions) -- ^ The linker-specific GHC options- -> (Set.Set BuildWay, BuildWay -> GhcOptions)+ -> (BuildWay, BuildWay -> GhcOptions) -- ^ The wanted build ways and corresponding GhcOptions that were -- used to compile the modules in that way.- -> FilePath+ -> SymbolicPath Pkg (Dir Build) -- ^ The target dir (2024-01:note: not the same as build target -- dir, see Note [Build Target Dir vs Target Dir] in Distribution.Simple.GHC.Build) -> UnqualComponentName@@ -379,28 +478,27 @@ -- ^ Run the configured GHC program -> LocalBuildInfo -> IO ()-linkExecutable linkerOpts (wantedWays, buildOpts) targetDir targetName runGhcProg lbi = do- -- When building an executable, we should only "want" one build way.- assert (Set.size wantedWays == 1) $- forM_ wantedWays $ \way -> do- let baseOpts = buildOpts way- linkOpts =- baseOpts- `mappend` linkerOpts- `mappend` mempty- { -- If there are no input Haskell files we pass -no-hs-main, and- -- assume there is a main function in another non-haskell object- ghcOptLinkNoHsMain = toFlag (ghcOptInputFiles baseOpts == mempty && ghcOptInputScripts baseOpts == mempty)- }- comp = compiler lbi+linkExecutable linkerOpts (way, buildOpts) targetDir targetName runGhcProg lbi = do+ let baseOpts = buildOpts way+ linkOpts =+ baseOpts+ `mappend` linkerOpts+ `mappend` mempty+ { -- If there are no input Haskell files we pass -no-hs-main, and+ -- assume there is a main function in another non-haskell object+ ghcOptLinkNoHsMain = toFlag (ghcOptInputFiles baseOpts == mempty && ghcOptInputScripts baseOpts == mempty)+ }+ comp = compiler lbi - -- Work around old GHCs not relinking in this- -- situation, see #3294- let target = targetDir </> exeTargetName (hostPlatform lbi) targetName- when (compilerVersion comp < mkVersion [7, 7]) $ do- e <- doesFileExist target- when e (removeFile target)- runGhcProg linkOpts{ghcOptOutputFile = toFlag target}+ -- Work around old GHCs not relinking in this+ -- situation, see #3294+ let target =+ targetDir </> makeRelativePathEx (exeTargetName (hostPlatform lbi) targetName)+ when (compilerVersion comp < mkVersion [7, 7]) $ do+ let targetPath = interpretSymbolicPathLBI lbi target+ e <- doesFileExist targetPath+ when e (removeFile targetPath)+ runGhcProg linkOpts{ghcOptOutputFile = toFlag target} -- | Link a foreign library component linkFLib@@ -409,16 +507,16 @@ -> LocalBuildInfo -> (GhcOptions) -- ^ The linker-specific GHC options- -> (Set.Set BuildWay, BuildWay -> GhcOptions)+ -> (BuildWay, BuildWay -> GhcOptions) -- ^ The wanted build ways and corresponding GhcOptions that were -- used to compile the modules in that way.- -> FilePath+ -> SymbolicPath Pkg (Dir Build) -- ^ The target dir (2024-01:note: not the same as build target -- dir, see Note [Build Target Dir vs Target Dir] in Distribution.Simple.GHC.Build) -> (GhcOptions -> IO ()) -- ^ Run the configured GHC program -> IO ()-linkFLib flib bi lbi linkerOpts (wantedWays, buildOpts) targetDir runGhcProg = do+linkFLib flib bi lbi linkerOpts (way, buildOpts) targetDir runGhcProg = do let comp = compiler lbi @@ -432,7 +530,7 @@ | otherwise = mempty { ghcOptLinkLibs = rtsOptLinkLibs- , ghcOptLinkLibPath = toNubListR $ rtsLibPaths rtsInfo+ , ghcOptLinkLibPath = toNubListR $ map makeSymbolicPath $ rtsLibPaths rtsInfo } where threaded = hasThreaded bi@@ -450,8 +548,8 @@ else statRtsVanillaLib (rtsStaticInfo rtsInfo) ] - linkOpts :: BuildWay -> GhcOptions- linkOpts way = case foreignLibType flib of+ linkOpts :: GhcOptions+ linkOpts = case foreignLibType flib of ForeignLibNativeShared -> (buildOpts way) `mappend` linkerOpts@@ -460,7 +558,7 @@ { ghcOptLinkNoHsMain = toFlag True , ghcOptShared = toFlag True , ghcOptFPic = toFlag True- , ghcOptLinkModDefFiles = toNubListR $ foreignLibModDefFile flib+ , ghcOptLinkModDefFiles = toNubListR $ fmap getSymbolicPath $ foreignLibModDefFile flib } ForeignLibNativeStatic -> -- this should be caught by buildFLib@@ -473,11 +571,10 @@ -- soname on supported platforms. See also the note for -- @flibBuildName@. let buildName = flibBuildName lbi flib- -- There should not be more than one wanted way when building an flib- assert (Set.size wantedWays == 1) $- forM_ wantedWays $ \way -> do- runGhcProg (linkOpts way){ghcOptOutputFile = toFlag (targetDir </> buildName)}- renameFile (targetDir </> buildName) (targetDir </> flibTargetName lbi flib)+ let outFile = targetDir </> makeRelativePathEx buildName+ runGhcProg linkOpts{ghcOptOutputFile = toFlag outFile}+ let i = interpretSymbolicPathLBI lbi+ renameFile (i outFile) (i targetDir </> flibTargetName lbi flib) -- | Calculate the RPATHs for the component we are building. --@@ -534,7 +631,9 @@ OSX -> "@loader_path" _ -> "$ORIGIN" relPath p = if isRelative p then hostPref </> p else p- rpaths = toNubListR (map relPath libraryPaths) <> toNubListR (extraLibDirs bi)+ rpaths =+ toNubListR (map relPath libraryPaths)+ <> toNubListR (map getSymbolicPath $ extraLibDirs bi) return rpaths else return mempty @@ -628,10 +727,12 @@ clbi = targetCLBI target comp = compiler lbi platform = hostPlatform lbi+ common = configCommonFlags $ configFlags lbi+ mbWorkDir = mbWorkDirLBI lbi+ verbosity = fromFlag $ setupVerbosity common in case replOptionsFlagOutput (replReplOptions rflags) of- NoFlag -> runGHC (fromFlag $ replVerbosity rflags) ghcProg comp platform ghcOpts+ NoFlag -> runGHC verbosity ghcProg comp platform mbWorkDir ghcOpts Flag out_dir -> do- src_dir <- getCurrentDirectory let uid = componentUnitId clbi this_unit = prettyShow uid reexported_modules = [mn | LibComponentLocalBuildInfo{} <- [clbi], IPI.ExposedModule mn (Just{}) <- componentExposedModules clbi]@@ -639,7 +740,9 @@ extra_opts = concat $ [ ["-this-package-name", prettyShow pkg_name]- , ["-working-dir", src_dir]+ , case mbWorkDir of+ Nothing -> []+ Just wd -> ["-working-dir", getSymbolicPath wd] ] ++ [ ["-reexported-module", prettyShow m] | m <- reexported_modules ]
src/Distribution/Simple/GHC/Build/Modules.hs view
@@ -1,9 +1,16 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE RankNTypes #-} {-# LANGUAGE TupleSections #-} -module Distribution.Simple.GHC.Build.Modules (buildHaskellModules, BuildWay (..), buildWayPrefix) where+module Distribution.Simple.GHC.Build.Modules+ ( buildHaskellModules+ , BuildWay (..)+ , buildWayPrefix+ , componentInputs+ ) where import Control.Monad.IO.Class import Distribution.Compat.Prelude@@ -15,6 +22,7 @@ import qualified Distribution.PackageDescription as PD import Distribution.Pretty import Distribution.Simple.Build.Inputs+import Distribution.Simple.BuildWay import Distribution.Simple.Compiler import Distribution.Simple.GHC.Build.Utils import qualified Distribution.Simple.GHC.Internal as Internal@@ -34,7 +42,8 @@ import Distribution.Types.TestSuite import Distribution.Types.TestSuiteInterface import Distribution.Utils.NubList-import System.FilePath+import Distribution.Utils.Path+import System.FilePath () {- Note [Building Haskell Modules accounting for TH]@@ -94,13 +103,15 @@ -- ^ The parallelism strategy (e.g. num of jobs) -> ConfiguredProgram -- ^ The GHC configured program- -> PD.PackageDescription- -- ^ The package description- -> FilePath+ -> Maybe (SymbolicPath Pkg File)+ -- ^ Optional path to a Haskell Main file to build+ -> [ModuleName]+ -- ^ The Haskell modules to build+ -> SymbolicPath Pkg ('Dir Artifacts) -- ^ The path to the build directory for this target, which -- has already been created.- -> Set.Set BuildWay- -- ^ The set of wanted build ways according to user options+ -> [BuildWay]+ -- ^ The set of needed build ways according to user options -> PreBuildComponentInputs -- ^ The context and component being built in it. -> IO (BuildWay -> GhcOptions)@@ -108,7 +119,7 @@ -- invocation used to compile the component in that 'BuildWay'. -- This can be useful in, eg, a linker invocation, in which we want to use the -- same options and list the same inputs as those used for building.-buildHaskellModules numJobs ghcProg pkg_descr buildTargetDir wantedWays pbci = do+buildHaskellModules numJobs ghcProg mbMainFile inputModules buildTargetDir neededLibWays pbci = do -- See Note [Building Haskell Modules accounting for TH] let@@ -119,6 +130,7 @@ bi = buildBI pbci what = buildingWhat pbci comp = buildCompiler pbci+ i = interpretSymbolicPathLBI lbi -- See Note [Symbolic paths] in Distribution.Utils.Path -- If this component will be loaded into a repl, we don't compile the modules at all. forRepl@@ -133,17 +145,16 @@ let isCoverageEnabled = if isLib then libCoverage lbi else exeCoverage lbi hpcdir way | forRepl = mempty -- HPC is not supported in ghci- | isCoverageEnabled = Flag $ Hpc.mixDir (buildTargetDir </> extraCompilationArtifacts) way+ | isCoverageEnabled = Flag $ Hpc.mixDir (coerceSymbolicPath $ coerceSymbolicPath buildTargetDir </> extraCompilationArtifacts) way | otherwise = mempty - (inputFiles, inputModules) <- componentInputs buildTargetDir pkg_descr pbci- let- runGhcProg = runGHC verbosity ghcProg comp platform+ mbWorkDir = mbWorkDirLBI lbi+ runGhcProg = runGHC verbosity ghcProg comp platform mbWorkDir platform = hostPlatform lbi - -- See Note [Building Haskell Modules accounting for TH]- doingTH = usesTemplateHaskellOrQQ bi+ (hsMains, scriptMains) =+ partition (isHaskell . getSymbolicPath) (maybeToList mbMainFile) -- We define the base opts which are shared across different build ways in -- 'buildHaskellModules'@@ -158,16 +169,8 @@ ghcOptNoLink = if isLib then NoFlag else toFlag True , ghcOptNumJobs = numJobs , ghcOptInputModules = toNubListR inputModules- , ghcOptInputFiles =- toNubListR $- if PD.package pkg_descr == fakePackageId- then filter isHaskell inputFiles- else inputFiles- , ghcOptInputScripts =- toNubListR $- if PD.package pkg_descr == fakePackageId- then filter (not . isHaskell) inputFiles- else []+ , ghcOptInputFiles = toNubListR hsMains+ , ghcOptInputScripts = toNubListR scriptMains , ghcOptExtra = buildWayExtraHcOptions way GHC bi , ghcOptHiSuffix = optSuffixFlag (buildWayPrefix way) "hi" , ghcOptObjSuffix = optSuffixFlag (buildWayPrefix way) "o"@@ -195,6 +198,18 @@ (if isLib then True else False) ((if isLib then withProfLibDetail else withProfExeDetail) lbi) }+ profDynOpts =+ (baseOpts ProfDynWay)+ { ghcOptDynLinkMode = toFlag GhcDynamicOnly -- use -dynamic+ , -- TODO: Does it hurt to set -fPIC for executables?+ ghcOptFPic = toFlag True -- use -fPIC+ , ghcOptProfilingMode = toFlag True+ , ghcOptProfilingAuto =+ Internal.profDetailLevelFlag+ (if isLib then True else False)+ ((if isLib then withProfLibDetail else withProfExeDetail) lbi)+ }+ -- Options for building both static and dynamic way at the same time, using -- the GHC flag -static and -dynamic-too dynTooOpts =@@ -207,45 +222,84 @@ -- (Note that `baseOtps StaticWay = hcStaticOptions`, not hcSharedOpts) } + profDynTooOpts =+ (baseOpts ProfWay)+ { ghcOptDynLinkMode = toFlag GhcStaticAndDynamic -- use -dynamic-too+ , -- TODO: Does it hurt to set -fPIC for executables?+ ghcOptFPic = toFlag True -- use -fPIC+ , ghcOptProfilingMode = toFlag True+ , ghcOptProfilingAuto =+ Internal.profDetailLevelFlag+ (if isLib then True else False)+ ((if isLib then withProfLibDetail else withProfExeDetail) lbi)+ , ghcOptDynHiSuffix = toFlag (buildWayPrefix ProfDynWay ++ "hi")+ , ghcOptDynObjSuffix = toFlag (buildWayPrefix ProfDynWay ++ "o")+ , ghcOptHPCDir = hpcdir Hpc.ProfDyn+ -- Should we pass hcSharedOpts in the -dynamic-too ghc invocation?+ -- (Note that `baseOtps StaticWay = hcStaticOptions`, not hcSharedOpts)+ }+ -- Determines how to build for each way, also serves as the base options -- for loading modules in 'linkOrLoadComponent' buildOpts way = case way of StaticWay -> staticOpts DynWay -> dynOpts ProfWay -> profOpts-- defaultGhcWay = if isDynamic comp then DynWay else StaticWay+ ProfDynWay -> profDynOpts -- If there aren't modules, or if we're loading the modules in repl, don't build.- unless (forRepl || (null inputFiles && null inputModules)) $ liftIO $ do+ unless (forRepl || (isNothing mbMainFile && null inputModules)) $ liftIO $ do -- See Note [Building Haskell Modules accounting for TH] let- neededWays =- wantedWays- <> Set.fromList- -- TODO: You also don't need to build the GHC way when doing TH if- -- you are using an external interpreter!!- [defaultGhcWay | doingTH && defaultGhcWay `Set.notMember` wantedWays]+ neededLibWaysSet = Set.fromList neededLibWays -- If we need both static and dynamic, use dynamic-too instead of -- compiling twice (if we support it) useDynamicToo =- StaticWay `Set.member` neededWays- && DynWay `Set.member` neededWays+ StaticWay `Set.member` neededLibWaysSet+ && DynWay `Set.member` neededLibWaysSet && supportsDynamicToo comp && null (hcSharedOptions GHC bi) + useProfDynamicToo =+ ProfWay `Set.member` neededLibWaysSet+ && ProfDynWay `Set.member` neededLibWaysSet+ && supportsDynamicToo comp+ && null (hcSharedOptions GHC bi)++ defaultGhcWay = compilerBuildWay comp++ order w+ | w == defaultGhcWay = 0+ | otherwise = fromEnum w + 1+ -- The ways we'll build, in order orderedBuilds- -- If we can use dynamic-too, do it first. The default GHC way can only- -- be static or dynamic, so, if we build both right away, any modules- -- possibly needed by TH later (e.g. if building profiled) are already built.+ -- We need to make sure that the way which is the way the compiler is built+ -- is built first so that Template Haskell works.+ | useProfDynamicToo && useDynamicToo =+ if defaultGhcWay `elem` [ProfDynWay, ProfWay]+ then [buildProfAndProfDynamicToo, buildStaticAndDynamicToo]+ else [buildStaticAndDynamicToo, buildProfAndProfDynamicToo]+ | useProfDynamicToo && not useDynamicToo =+ if defaultGhcWay `elem` [ProfDynWay, ProfWay]+ then+ [buildProfAndProfDynamicToo]+ ++ (runGhcProg . buildOpts <$> neededLibWays \\ [ProfDynWay, ProfWay])+ else+ (runGhcProg . buildOpts <$> neededLibWays \\ [ProfDynWay, ProfWay])+ ++ [buildProfAndProfDynamicToo] | useDynamicToo =- [buildStaticAndDynamicToo]- ++ (runGhcProg . buildOpts <$> Set.toList neededWays \\ [StaticWay, DynWay])+ if defaultGhcWay `elem` [StaticWay, DynWay]+ then+ [buildStaticAndDynamicToo]+ ++ (runGhcProg . buildOpts <$> neededLibWays \\ [StaticWay, DynWay])+ else+ (runGhcProg . buildOpts <$> neededLibWays \\ [StaticWay, DynWay])+ ++ [buildStaticAndDynamicToo] -- Otherwise, we need to ensure the defaultGhcWay is built first | otherwise =- runGhcProg . buildOpts <$> sortOn (\w -> if w == defaultGhcWay then 0 else fromEnum w + 1) (Set.toList neededWays)+ runGhcProg . buildOpts <$> sortOn order neededLibWays buildStaticAndDynamicToo = do runGhcProg dynTooOpts@@ -257,29 +311,33 @@ -- static and dynamically linked executables. We copy -- the modules interfaces so they are available under -- both ways.- copyDirectoryRecursive verbosity dynDir vanillaDir+ copyDirectoryRecursive verbosity (i dynDir) (i vanillaDir) _ -> return ()++ buildProfAndProfDynamicToo = do+ runGhcProg profDynTooOpts+ case (hpcdir Hpc.ProfDyn, hpcdir Hpc.Prof) of+ (Flag profDynDir, Flag profDir) ->+ -- 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 (i profDynDir) (i profDir)+ _ -> return () in -- REVIEW:ADD? info verbosity "Building Haskell Sources..." sequence_ orderedBuilds return buildOpts -data BuildWay = StaticWay | DynWay | ProfWay- deriving (Eq, Ord, Show, Enum)---- | Returns the object/interface extension prefix for the given build way (e.g. "dyn_" for 'DynWay')-buildWayPrefix :: BuildWay -> String-buildWayPrefix = \case- StaticWay -> ""- ProfWay -> "p_"- DynWay -> "dyn_"- -- | Returns the corresponding 'Hpc.Way' for a 'BuildWay' buildWayHpcWay :: BuildWay -> Hpc.Way buildWayHpcWay = \case StaticWay -> Hpc.Vanilla ProfWay -> Hpc.Prof DynWay -> Hpc.Dyn+ ProfDynWay -> Hpc.ProfDyn -- | Returns a function to extract the extra haskell compiler options from a -- 'BuildInfo' and 'CompilerFlavor'@@ -288,47 +346,48 @@ StaticWay -> hcStaticOptions ProfWay -> hcProfOptions DynWay -> hcSharedOptions+ ProfDynWay -> hcProfSharedOptions --- | Returns a pair of the Haskell input files and Haskell modules of the--- component being built.+-- | Returns a pair of the main file and Haskell modules of the component being+-- built. The main file is not necessarily a Haskell file. It could also be+-- e.g. a C source, or, a Haskell repl script (that does not necessarily have+-- an extension). ----- The "input files" are either the path to the main Haskell module, or a repl--- script (that does not necessarily have an extension).+-- The main file is Nothing if the component is not executable. componentInputs- :: FilePath+ :: SymbolicPath Pkg (Dir Artifacts) -- ^ Target build dir -> PD.PackageDescription -> PreBuildComponentInputs -- ^ The context and component being built in it.- -> IO ([FilePath], [ModuleName])- -- ^ The Haskell input files, and the Haskell modules-componentInputs buildTargetDir pkg_descr pbci = do- let- verbosity = buildVerbosity pbci- component = buildComponent pbci- clbi = buildCLBI pbci-+ -> IO (Maybe (SymbolicPath Pkg File), [ModuleName])+ -- ^ The main input file, and the Haskell modules+componentInputs buildTargetDir pkg_descr pbci = case component of CLib lib ->- pure ([], allLibModules lib clbi)+ pure (Nothing, allLibModules lib clbi) CFLib flib ->- pure ([], foreignLibModules flib)+ pure (Nothing, foreignLibModules flib) CExe Executable{buildInfo = bi', modulePath} ->- exeLikeInputs verbosity bi' modulePath+ exeLikeInputs bi' modulePath CTest TestSuite{testBuildInfo = bi', testInterface = TestSuiteExeV10 _ mainFile} ->- exeLikeInputs verbosity bi' mainFile+ exeLikeInputs bi' mainFile CBench Benchmark{benchmarkBuildInfo = bi', benchmarkInterface = BenchmarkExeV10 _ mainFile} ->- exeLikeInputs verbosity bi' mainFile+ exeLikeInputs bi' mainFile CTest TestSuite{} -> error "testSuiteExeV10AsExe: wrong kind" CBench Benchmark{} -> error "benchmarkExeV10asExe: wrong kind" where- exeLikeInputs verbosity bnfo modulePath = liftIO $ do- main <- findExecutableMain verbosity buildTargetDir (bnfo, modulePath)+ verbosity = buildVerbosity pbci+ component = buildComponent pbci+ clbi = buildCLBI pbci+ mbWorkDir = mbWorkDirLBI $ localBuildInfo pbci+ exeLikeInputs bnfo modulePath = liftIO $ do+ main <- findExecutableMain verbosity mbWorkDir buildTargetDir (bnfo, modulePath) let mainModName = exeMainModuleName bnfo otherModNames = otherModules bnfo -- Scripts have fakePackageId and are always Haskell but can have any extension.- if isHaskell main || PD.package pkg_descr == fakePackageId+ if isHaskell (getSymbolicPath main) || PD.package pkg_descr == fakePackageId then if PD.specVersion pkg_descr < CabalSpecV2_0 && (mainModName `elem` otherModNames) then do@@ -347,6 +406,6 @@ "Enabling workaround for Main module '" ++ prettyShow mainModName ++ "' listed in 'other-modules' illegally!"- return ([main], filter (/= mainModName) otherModNames)- else return ([main], otherModNames)- else return ([], otherModNames)+ return (Just main, filter (/= mainModName) otherModNames)+ else return (Just main, otherModNames)+ else return (Just main, otherModNames)
src/Distribution/Simple/GHC/Build/Utils.hs view
@@ -1,3 +1,6 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE RankNTypes #-}+ module Distribution.Simple.GHC.Build.Utils where import Distribution.Compat.Prelude@@ -10,6 +13,7 @@ import Distribution.PackageDescription as PD import Distribution.PackageDescription.Utils (cabalBug) import Distribution.Simple.BuildPaths+import Distribution.Simple.BuildWay import Distribution.Simple.Compiler import qualified Distribution.Simple.GHC.Internal as Internal import Distribution.Simple.Program.GHC@@ -17,36 +21,48 @@ import Distribution.Simple.Utils import Distribution.System import Distribution.Types.LocalBuildInfo-import Distribution.Utils.Path (getSymbolicPath)+ ( LocalBuildInfo (hostPlatform)+ )+import Distribution.Utils.Path import Distribution.Verbosity import System.FilePath ( replaceExtension , takeExtension- , (<.>)- , (</>) ) -- | Find the path to the entry point of an executable (typically specified in--- @main-is@, and found in @hs-source-dirs@).+-- @main-is@, and found in @hs-source-dirs@ -- yes, even when @main-is@ is not a Haskell file). findExecutableMain :: Verbosity- -> FilePath+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -> SymbolicPath Pkg (Dir build) -- ^ Build directory- -> (BuildInfo, FilePath)+ -> (BuildInfo, RelativePath Source File) -- ^ The build info and module path of an executable-like component (Exe, Test, Bench)- -> IO FilePath+ -> IO (SymbolicPath Pkg File) -- ^ The path to the main source file.-findExecutableMain verbosity bdir (bnfo, modPath) =- findFileEx verbosity (bdir : map getSymbolicPath (hsSourceDirs bnfo)) modPath+findExecutableMain verbosity mbWorkDir buildDir (bnfo, modPath) =+ findFileCwd verbosity mbWorkDir (coerceSymbolicPath buildDir : hsSourceDirs bnfo) modPath -- | Does this compiler support the @-dynamic-too@ option supportsDynamicToo :: Compiler -> Bool supportsDynamicToo = Internal.ghcLookupProperty "Support dynamic-too" +compilerBuildWay :: Compiler -> BuildWay+compilerBuildWay c =+ case (isDynamic c, isProfiled c) of+ (True, True) -> ProfDynWay+ (True, False) -> DynWay+ (False, True) -> ProfWay+ (False, False) -> StaticWay+ -- | Is this compiler's RTS dynamically linked? isDynamic :: Compiler -> Bool isDynamic = Internal.ghcLookupProperty "GHC Dynamic" +isProfiled :: Compiler -> Bool+isProfiled = Internal.ghcLookupProperty "GHC Profiled"+ -- | Should we dynamically link the foreign library, based on its 'foreignLibType'? withDynFLib :: ForeignLib -> Bool withDynFLib flib =@@ -72,18 +88,31 @@ -- | Returns True if the modification date of the given source file is newer than -- the object file we last compiled for it, or if no object file exists yet.-checkNeedsRecompilation :: FilePath -> GhcOptions -> IO Bool-checkNeedsRecompilation filename opts = filename `moreRecentFile` oname+checkNeedsRecompilation+ :: Maybe (SymbolicPath CWD (Dir Pkg))+ -> SymbolicPath Pkg File+ -> GhcOptions+ -> IO Bool+checkNeedsRecompilation mbWorkDir filename opts =+ i filename `moreRecentFile` oname where- oname = getObjectFileName filename opts+ oname = getObjectFileName mbWorkDir filename opts+ i = interpretSymbolicPath mbWorkDir -- See Note [Symbolic paths] in Distribution.Utils.Path -- | Finds the object file name of the given source file-getObjectFileName :: FilePath -> GhcOptions -> FilePath-getObjectFileName filename opts = oname+getObjectFileName+ :: Maybe (SymbolicPath CWD (Dir Pkg))+ -> SymbolicPath Pkg File+ -> GhcOptions+ -> FilePath+getObjectFileName mbWorkDir filename opts = oname where- odir = fromFlag (ghcOptObjDir opts)+ i = interpretSymbolicPath mbWorkDir -- See Note [Symbolic paths] in Distribution.Utils.Path+ odir = i $ fromFlag (ghcOptObjDir opts) oext = fromFlagOrDefault "o" (ghcOptObjSuffix opts)- oname = odir </> replaceExtension filename oext+ -- NB: the filepath might be absolute, e.g. if it is the path to+ -- an autogenerated .hs file.+ oname = odir </> replaceExtension (getSymbolicPath filename) oext -- | Target name for a foreign library (the actual file name) --
src/Distribution/Simple/GHC/EnvironmentParser.hs view
@@ -11,8 +11,6 @@ import Prelude () import Distribution.Simple.Compiler- ( PackageDB (..)- ) import Distribution.Simple.GHC.Internal ( GhcEnvironmentFileEntry (..) )@@ -26,7 +24,7 @@ , parseFromFile ) -parseEnvironmentFileLine :: Parser GhcEnvironmentFileEntry+parseEnvironmentFileLine :: Parser (GhcEnvironmentFileEntry FilePath) parseEnvironmentFileLine = GhcEnvFileComment <$> comment <|> GhcEnvFilePackageId <$> unitId@@ -50,10 +48,10 @@ instance Exception ParseErrorExc -parseGhcEnvironmentFile :: Parser [GhcEnvironmentFileEntry]+parseGhcEnvironmentFile :: Parser [GhcEnvironmentFileEntry FilePath] parseGhcEnvironmentFile = parseEnvironmentFileLine `P.sepEndBy` P.endOfLine <* P.eof -readGhcEnvironmentFile :: FilePath -> IO [GhcEnvironmentFileEntry]+readGhcEnvironmentFile :: FilePath -> IO [GhcEnvironmentFileEntry FilePath] readGhcEnvironmentFile path = either (throwIO . ParseErrorExc) return =<< parseFromFile parseGhcEnvironmentFile path
src/Distribution/Simple/GHC/Internal.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} @@ -74,12 +75,12 @@ import Distribution.Simple.Setup.Common (extraCompilationArtifacts) import Distribution.Simple.Utils import Distribution.System-import Distribution.Types.ComponentId (ComponentId) import Distribution.Types.ComponentLocalBuildInfo+import Distribution.Types.GivenComponent import Distribution.Types.LocalBuildInfo import Distribution.Types.TargetInfo import Distribution.Types.UnitId-import Distribution.Utils.NubList (toNubListR)+import Distribution.Utils.NubList (NubListR, toNubListR) import Distribution.Utils.Path import Distribution.Verbosity import Distribution.Version (Version)@@ -90,8 +91,6 @@ ( takeDirectory , takeExtension , takeFileName- , (<.>)- , (</>) ) import System.IO (hClose, hPutStrLn) @@ -127,6 +126,7 @@ { programFindLocation = findProg stripProgramName extraStripPath } where+ compilerDir, base_dir, mingwBinDir :: FilePath compilerDir = takeDirectory (programPath ghcProg) base_dir = takeDirectory compilerDir mingwBinDir = base_dir </> "mingw" </> "bin"@@ -338,13 +338,33 @@ else extensions0 return extensions1 +includePaths+ :: LocalBuildInfo+ -> BuildInfo+ -> ComponentLocalBuildInfo+ -> SymbolicPath Pkg p+ -> NubListR (SymbolicPath Pkg (Dir Include))+includePaths lbi bi clbi odir =+ toNubListR $+ [ coerceSymbolicPath $ autogenComponentModulesDir lbi clbi+ , coerceSymbolicPath $ autogenPackageModulesDir lbi+ , coerceSymbolicPath odir+ ]+ -- includes relative to the package+ ++ includeDirs bi+ -- potential includes generated by `configure'+ -- in the build directory+ ++ [ buildDir lbi </> dir+ | dir <- mapMaybe (symbolicPathRelative_maybe . unsafeCoerceSymbolicPath) $ includeDirs bi+ ]+ componentCcGhcOptions :: Verbosity -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo- -> FilePath- -> FilePath+ -> SymbolicPath Pkg (Dir Artifacts)+ -> SymbolicPath Pkg File -> GhcOptions componentCcGhcOptions verbosity lbi bi clbi odir filename = mempty@@ -353,17 +373,7 @@ ghcOptVerbosity = toFlag (min verbosity normal) , ghcOptMode = toFlag GhcModeCompile , ghcOptInputFiles = toNubListR [filename]- , ghcOptCppIncludePath =- toNubListR $- [ autogenComponentModulesDir lbi clbi- , autogenPackageModulesDir lbi- , odir- ]- -- includes relative to the package- ++ includeDirs bi- -- potential includes generated by `configure'- -- in the build directory- ++ [buildDir lbi </> dir | dir <- includeDirs bi]+ , ghcOptCppIncludePath = includePaths lbi bi clbi odir , ghcOptHideAllPackages = toFlag True , ghcOptPackageDBs = withPackageDB lbi , ghcOptPackages = toNubListR $ mkGhcOptPackages (promisedPkgs lbi) clbi@@ -392,8 +402,8 @@ -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo- -> FilePath- -> FilePath+ -> SymbolicPath Pkg (Dir Artifacts)+ -> SymbolicPath Pkg File -> GhcOptions componentCxxGhcOptions verbosity lbi bi clbi odir filename = mempty@@ -402,17 +412,7 @@ ghcOptVerbosity = toFlag (min verbosity normal) , ghcOptMode = toFlag GhcModeCompile , ghcOptInputFiles = toNubListR [filename]- , ghcOptCppIncludePath =- toNubListR $- [ autogenComponentModulesDir lbi clbi- , autogenPackageModulesDir lbi- , odir- ]- -- includes relative to the package- ++ includeDirs bi- -- potential includes generated by `configure'- -- in the build directory- ++ [buildDir lbi </> dir | dir <- includeDirs bi]+ , ghcOptCppIncludePath = includePaths lbi bi clbi odir , ghcOptHideAllPackages = toFlag True , ghcOptPackageDBs = withPackageDB lbi , ghcOptPackages = toNubListR $ mkGhcOptPackages (promisedPkgs lbi) clbi@@ -441,8 +441,8 @@ -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo- -> FilePath- -> FilePath+ -> SymbolicPath Pkg (Dir Artifacts)+ -> SymbolicPath Pkg File -> GhcOptions componentAsmGhcOptions verbosity lbi bi clbi odir filename = mempty@@ -451,17 +451,7 @@ ghcOptVerbosity = toFlag (min verbosity normal) , ghcOptMode = toFlag GhcModeCompile , ghcOptInputFiles = toNubListR [filename]- , ghcOptCppIncludePath =- toNubListR $- [ autogenComponentModulesDir lbi clbi- , autogenPackageModulesDir lbi- , odir- ]- -- includes relative to the package- ++ includeDirs bi- -- potential includes generated by `configure'- -- in the build directory- ++ [buildDir lbi </> dir | dir <- includeDirs bi]+ , ghcOptCppIncludePath = includePaths lbi bi clbi odir , ghcOptHideAllPackages = toFlag True , ghcOptPackageDBs = withPackageDB lbi , ghcOptPackages = toNubListR $ mkGhcOptPackages (promisedPkgs lbi) clbi@@ -485,8 +475,8 @@ -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo- -> FilePath- -> FilePath+ -> SymbolicPath Pkg (Dir Artifacts)+ -> SymbolicPath Pkg File -> GhcOptions componentJsGhcOptions verbosity lbi bi clbi odir filename = mempty@@ -495,17 +485,7 @@ ghcOptVerbosity = toFlag (min verbosity normal) , ghcOptMode = toFlag GhcModeCompile , ghcOptInputFiles = toNubListR [filename]- , ghcOptCppIncludePath =- toNubListR $- [ autogenComponentModulesDir lbi clbi- , autogenPackageModulesDir lbi- , odir- ]- -- includes relative to the package- ++ includeDirs bi- -- potential includes generated by `configure'- -- in the build directory- ++ [buildDir lbi </> dir | dir <- includeDirs bi]+ , ghcOptCppIncludePath = includePaths lbi bi clbi odir , ghcOptHideAllPackages = toFlag True , ghcOptPackageDBs = withPackageDB lbi , ghcOptPackages = toNubListR $ mkGhcOptPackages (promisedPkgs lbi) clbi@@ -517,7 +497,7 @@ -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo- -> FilePath+ -> SymbolicPath Pkg (Dir build) -> GhcOptions componentGhcOptions verbosity lbi bi clbi odir = let implInfo = getImplInfo $ compiler lbi@@ -561,35 +541,25 @@ , ghcOptSourcePathClear = toFlag True , ghcOptSourcePath = toNubListR $- map getSymbolicPath (hsSourceDirs bi)- ++ [odir]+ (hsSourceDirs bi)+ ++ [coerceSymbolicPath odir] ++ [autogenComponentModulesDir lbi clbi] ++ [autogenPackageModulesDir lbi]- , ghcOptCppIncludePath =- toNubListR $- [ autogenComponentModulesDir lbi clbi- , autogenPackageModulesDir lbi- , odir- ]- -- includes relative to the package- ++ includeDirs bi- -- potential includes generated by `configure'- -- in the build directory- ++ [buildDir lbi </> dir | dir <- includeDirs bi]+ , ghcOptCppIncludePath = includePaths lbi bi clbi odir , ghcOptCppOptions = cppOptions bi , ghcOptCppIncludes = toNubListR $- [autogenComponentModulesDir lbi clbi </> cppHeaderName]- , ghcOptFfiIncludes = toNubListR $ includes bi- , ghcOptObjDir = toFlag odir- , ghcOptHiDir = toFlag odir- , ghcOptHieDir = bool NoFlag (toFlag $ odir </> extraCompilationArtifacts </> "hie") $ flagHie implInfo- , ghcOptStubDir = toFlag odir- , ghcOptOutputDir = toFlag odir+ [coerceSymbolicPath (autogenComponentModulesDir lbi clbi </> makeRelativePathEx cppHeaderName)]+ , ghcOptFfiIncludes = toNubListR $ map getSymbolicPath $ includes bi+ , ghcOptObjDir = toFlag $ coerceSymbolicPath odir+ , ghcOptHiDir = toFlag $ coerceSymbolicPath odir+ , ghcOptHieDir = bool NoFlag (toFlag $ coerceSymbolicPath odir </> (extraCompilationArtifacts </> makeRelativePathEx "hie")) $ flagHie implInfo+ , ghcOptStubDir = toFlag $ coerceSymbolicPath odir+ , ghcOptOutputDir = toFlag $ coerceSymbolicPath odir , ghcOptOptimisation = toGhcOptimisation (withOptimization lbi) , ghcOptDebugInfo = toFlag (withDebugInfo lbi) , ghcOptExtra = hcOptions GHC bi- , ghcOptExtraPath = toNubListR $ exe_paths+ , ghcOptExtraPath = toNubListR exe_paths , ghcOptLanguage = toFlag (fromMaybe Haskell98 (defaultLanguage bi)) , -- Unsupported extensions have already been checked by configure ghcOptExtensions = toNubListR $ usedExtensions bi@@ -613,8 +583,8 @@ -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo- -> FilePath- -> FilePath+ -> SymbolicPath Pkg (Dir Artifacts)+ -> SymbolicPath Pkg File -> GhcOptions componentCmmGhcOptions verbosity lbi bi clbi odir filename = mempty@@ -623,21 +593,11 @@ ghcOptVerbosity = toFlag (min verbosity normal) , ghcOptMode = toFlag GhcModeCompile , ghcOptInputFiles = toNubListR [filename]- , ghcOptCppIncludePath =- toNubListR $- [ autogenComponentModulesDir lbi clbi- , autogenPackageModulesDir lbi- , odir- ]- -- includes relative to the package- ++ includeDirs bi- -- potential includes generated by `configure'- -- in the build directory- ++ [buildDir lbi </> dir | dir <- includeDirs bi]+ , ghcOptCppIncludePath = includePaths lbi bi clbi odir , ghcOptCppOptions = cppOptions bi , ghcOptCppIncludes = toNubListR $- [autogenComponentModulesDir lbi clbi </> cppHeaderName]+ [autogenComponentModulesDir lbi clbi </> makeRelativePathEx cppHeaderName] , ghcOptHideAllPackages = toFlag True , ghcOptPackageDBs = withPackageDB lbi , ghcOptPackages = toNubListR $ mkGhcOptPackages (promisedPkgs lbi) clbi@@ -679,20 +639,20 @@ -> Library -> LocalBuildInfo -> ComponentLocalBuildInfo- -> FilePath+ -> SymbolicPath Pkg (Dir Artifacts) -> String -> Bool- -> IO [FilePath]+ -> IO [SymbolicPath Pkg File] getHaskellObjects _implInfo lib lbi clbi pref wanted_obj_ext allow_split_objs | splitObjs lbi && allow_split_objs = do let splitSuffix = "_" ++ wanted_obj_ext ++ "_split" dirs =- [ pref </> (ModuleName.toFilePath x ++ splitSuffix)+ [ pref </> makeRelativePathEx (ModuleName.toFilePath x ++ splitSuffix) | x <- allLibModules lib clbi ]- objss <- traverse getDirectoryContents dirs+ objss <- traverse (getDirectoryContents . i) dirs let objs =- [ dir </> obj+ [ dir </> makeRelativePathEx obj | (objs', dir) <- zip objss dirs , obj <- objs' , let obj_ext = takeExtension obj@@ -701,16 +661,18 @@ return objs | otherwise = return- [ pref </> ModuleName.toFilePath x <.> wanted_obj_ext+ [ pref </> makeRelativePathEx (ModuleName.toFilePath x <.> wanted_obj_ext) | x <- allLibModules lib clbi ]+ where+ i = interpretSymbolicPathLBI lbi -- | Create the required packaged arguments, but filtering out package arguments which -- aren't yet built, but promised. This filtering is used when compiling C/Cxx/Asm files, -- and is a hack to avoid passing bogus `-package` arguments to GHC. The assumption being that -- in 99% of cases we will include the right `-package` so that the C file finds the right headers. mkGhcOptPackages- :: Map (PackageName, ComponentName) ComponentId+ :: Map (PackageName, ComponentName) PromisedComponent -> ComponentLocalBuildInfo -> [(OpenUnitId, ModuleRenaming)] mkGhcOptPackages promisedPkgsMap clbi =@@ -718,7 +680,7 @@ ] where -- Promised deps are going to be simple UnitIds- promised_cids = Set.fromList (map newSimpleUnitId (Map.elems promisedPkgsMap))+ promised_cids = Set.fromList (map (newSimpleUnitId . promisedComponentId) (Map.elems promisedPkgsMap)) substTopDir :: FilePath -> IPI.InstalledPackageInfo -> IPI.InstalledPackageInfo substTopDir topDir ipo =@@ -804,7 +766,7 @@ -- Constructing GHC environment files -- | The kinds of entries we can stick in a @.ghc.environment@ file.-data GhcEnvironmentFileEntry+data GhcEnvironmentFileEntry fp = -- | @-- a comment@ GhcEnvFileComment String | -- | @package-id foo-1.0-4fe301a...@@@ -812,7 +774,7 @@ | -- | @global-package-db@, -- @user-package-db@ or -- @package-db blah/package.conf.d/@- GhcEnvFilePackageDb PackageDB+ GhcEnvFilePackageDb (PackageDBX fp) | -- | @clear-package-db@ GhcEnvFileClearPackageDbStack deriving (Eq, Ord, Show)@@ -823,9 +785,9 @@ -- If you need to do anything more complicated then either use this as a basis -- and add more entries, or just make all the entries directly. simpleGhcEnvironmentFile- :: PackageDBStack+ :: PackageDBStackX fp -> [UnitId]- -> [GhcEnvironmentFileEntry]+ -> [GhcEnvironmentFileEntry fp] simpleGhcEnvironmentFile packageDBs pkgids = GhcEnvFileClearPackageDbStack : map GhcEnvFilePackageDb packageDBs@@ -843,7 +805,7 @@ -- ^ the GHC target platform -> Version -- ^ the GHC version- -> [GhcEnvironmentFileEntry]+ -> [GhcEnvironmentFileEntry FilePath] -- ^ the content -> IO FilePath writeGhcEnvironmentFile directory platform ghcversion entries = do@@ -858,12 +820,12 @@ ".ghc.environment." ++ ghcPlatformAndVersionString platform ghcversion -- | Render a bunch of GHC environment file entries-renderGhcEnvironmentFile :: [GhcEnvironmentFileEntry] -> String+renderGhcEnvironmentFile :: [GhcEnvironmentFileEntry FilePath] -> String renderGhcEnvironmentFile = unlines . map renderGhcEnvironmentFileEntry -- | Render an individual GHC environment file entry-renderGhcEnvironmentFileEntry :: GhcEnvironmentFileEntry -> String+renderGhcEnvironmentFileEntry :: GhcEnvironmentFileEntry FilePath -> String renderGhcEnvironmentFileEntry entry = case entry of GhcEnvFileComment comment -> format comment where
src/Distribution/Simple/GHCJS.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TupleSections #-}@@ -84,6 +85,7 @@ import Distribution.Verbosity (Verbosity) import Distribution.Version +import Control.Arrow ((***)) import Control.Monad (msum) import Data.Char (isLower) import qualified Data.Map as Map@@ -100,8 +102,6 @@ , replaceExtension , takeDirectory , takeExtension- , (<.>)- , (</>) ) import qualified System.Info @@ -313,29 +313,31 @@ -- | Given a single package DB, return all installed packages. getPackageDBContents :: Verbosity- -> PackageDB+ -> Maybe (SymbolicPath CWD (Dir from))+ -> PackageDBX (SymbolicPath from (Dir PkgDB)) -> ProgramDb -> IO InstalledPackageIndex-getPackageDBContents verbosity packagedb progdb = do- pkgss <- getInstalledPackages' verbosity [packagedb] progdb+getPackageDBContents verbosity mbWorkDir packagedb progdb = do+ pkgss <- getInstalledPackages' verbosity mbWorkDir [packagedb] progdb toPackageIndex verbosity pkgss progdb -- | Given a package DB stack, return all installed packages. getInstalledPackages :: Verbosity- -> PackageDBStack+ -> Maybe (SymbolicPath CWD (Dir from))+ -> PackageDBStackX (SymbolicPath from (Dir PkgDB)) -> ProgramDb -> IO InstalledPackageIndex-getInstalledPackages verbosity packagedbs progdb = do+getInstalledPackages verbosity mbWorkDir packagedbs progdb = do checkPackageDbEnvVar verbosity checkPackageDbStack verbosity packagedbs- pkgss <- getInstalledPackages' verbosity packagedbs progdb+ pkgss <- getInstalledPackages' verbosity mbWorkDir packagedbs progdb index <- toPackageIndex verbosity pkgss progdb return $! index toPackageIndex :: Verbosity- -> [(PackageDB, [InstalledPackageInfo])]+ -> [(PackageDBX a, [InstalledPackageInfo])] -> ProgramDb -> IO InstalledPackageIndex toPackageIndex verbosity pkgss progdb = do@@ -391,7 +393,7 @@ checkPackageDbEnvVar verbosity = Internal.checkPackageDbEnvVar verbosity "GHCJS" "GHCJS_PACKAGE_PATH" -checkPackageDbStack :: Verbosity -> PackageDBStack -> IO ()+checkPackageDbStack :: Eq fp => Verbosity -> PackageDBStackX fp -> IO () checkPackageDbStack _ (GlobalPackageDB : rest) | GlobalPackageDB `notElem` rest = return () checkPackageDbStack verbosity rest@@ -402,13 +404,14 @@ getInstalledPackages' :: Verbosity- -> [PackageDB]+ -> Maybe (SymbolicPath CWD (Dir from))+ -> [PackageDBX (SymbolicPath from (Dir PkgDB))] -> ProgramDb- -> IO [(PackageDB, [InstalledPackageInfo])]-getInstalledPackages' verbosity packagedbs progdb =+ -> IO [(PackageDBX (SymbolicPath from (Dir PkgDB)), [InstalledPackageInfo])]+getInstalledPackages' verbosity mbWorkDir packagedbs progdb = sequenceA [ do- pkgs <- HcPkg.dump (hcPkgInfo progdb) verbosity packagedb+ pkgs <- HcPkg.dump (hcPkgInfo progdb) verbosity mbWorkDir packagedb return (packagedb, pkgs) | packagedb <- packagedbs ]@@ -417,10 +420,11 @@ getInstalledPackagesMonitorFiles :: Verbosity -> Platform+ -> Maybe (SymbolicPath CWD (Dir Pkg)) -> ProgramDb -> [PackageDB] -> IO [FilePath]-getInstalledPackagesMonitorFiles verbosity platform progdb =+getInstalledPackagesMonitorFiles verbosity platform mbWorkDir progdb = traverse getPackageDBPath where getPackageDBPath :: PackageDB -> IO FilePath@@ -428,13 +432,17 @@ selectMonitorFile =<< getGlobalPackageDB verbosity ghcjsProg getPackageDBPath UserPackageDB = selectMonitorFile =<< getUserPackageDB verbosity ghcjsProg platform- getPackageDBPath (SpecificPackageDB path) = selectMonitorFile path+ getPackageDBPath (SpecificPackageDB path) = selectMonitorFile (interpretSymbolicPath mbWorkDir path) -- GHC has old style file dbs, and new style directory dbs. -- Note that for dir style dbs, we only need to monitor the cache file, not -- the whole directory. The ghc program itself only reads the cache file -- so it's safe to only monitor this one file.- selectMonitorFile path = do+ selectMonitorFile path0 = do+ let path =+ if isRelative path0+ then interpretSymbolicPath mbWorkDir (makeRelativePathEx path0)+ else path0 isFileStyle <- doesFileExist path if isFileStyle then return path@@ -499,9 +507,15 @@ implInfo = getImplInfo comp platform@(Platform _hostArch _hostOS) = hostPlatform lbi has_code = not (componentIsIndefinite clbi)+ mbWorkDir = mbWorkDirLBI lbi + -- See Note [Symbolic paths] in Distribution.Utils.Path+ i = interpretSymbolicPathLBI lbi+ u :: SymbolicPathX allowAbs Pkg to -> FilePath+ u = getSymbolicPath+ (ghcjsProg, _) <- requireProgram verbosity ghcjsProgram (withPrograms lbi)- let runGhcjsProg = runGHC verbosity ghcjsProg comp platform+ let runGhcjsProg = runGHC verbosity ghcjsProg comp platform mbWorkDir let libBi = libBuildInfo lib @@ -518,15 +532,15 @@ let isCoverageEnabled = libCoverage lbi hpcdir way | forRepl = mempty -- HPC is not supported in ghci- | isCoverageEnabled = toFlag $ Hpc.mixDir (libTargetDir </> extraCompilationArtifacts) way+ | isCoverageEnabled = toFlag $ Hpc.mixDir (coerceSymbolicPath libTargetDir </> coerceSymbolicPath extraCompilationArtifacts) way | otherwise = mempty - createDirectoryIfMissingVerbose verbosity True libTargetDir+ createDirectoryIfMissingVerbose verbosity True $ i libTargetDir -- TODO: do we need to put hs-boot files into place for mutually recursive -- modules? let cLikeFiles = fromNubListR $ toNubListR (cSources libBi) <> toNubListR (cxxSources libBi) jsSrcs = jsSources libBi- cObjs = map (`replaceExtension` objExtension) cLikeFiles+ cObjs = map ((`replaceExtensionSymbolicPath` objExtension)) cLikeFiles baseOpts = componentGhcOptions verbosity lbi libBi clbi libTargetDir linkJsLibOpts = mempty@@ -534,9 +548,9 @@ [ "-link-js-lib" , getHSLibraryName uid , "-js-lib-outputdir"- , libTargetDir+ , u libTargetDir ]- ++ jsSrcs+ ++ map u jsSrcs } vanillaOptsNoJsLib = baseOpts@@ -569,7 +583,7 @@ , ghcOptFPic = toFlag True , -- ghcOptHiSuffix = toFlag "dyn_hi", -- ghcOptObjSuffix = toFlag "dyn_o",- ghcOptExtra = hcSharedOptions GHC libBi+ ghcOptExtra = hcOptions GHC libBi ++ hcSharedOptions GHC libBi , ghcOptHPCDir = hpcdir Hpc.Dyn } @@ -605,7 +619,7 @@ -- static and dynamically linked executables. We copy -- the modules interfaces so they are available under -- both ways.- copyDirectoryRecursive verbosity dynDir vanillaDir+ copyDirectoryRecursive verbosity (i dynDir) (i vanillaDir) _ -> return () else if isGhcjsDynamic@@ -690,11 +704,11 @@ info verbosity "Linking..." let cSharedObjs = map- (`replaceExtension` ("dyn_" ++ objExtension))+ ((`replaceExtensionSymbolicPath` ("dyn_" ++ objExtension))) (cSources libBi ++ cxxSources libBi) compiler_id = compilerId (compiler lbi)- sharedLibFilePath = libTargetDir </> mkSharedLibName (hostPlatform lbi) compiler_id uid- staticLibFilePath = libTargetDir </> mkStaticLibName (hostPlatform lbi) compiler_id uid+ sharedLibFilePath = libTargetDir </> makeRelativePathEx (mkSharedLibName (hostPlatform lbi) compiler_id uid)+ staticLibFilePath = libTargetDir </> makeRelativePathEx (mkStaticLibName (hostPlatform lbi) compiler_id uid) let stubObjs = [] stubSharedObjs = []@@ -722,7 +736,7 @@ lib lbi clbi- libTargetDir+ (coerceSymbolicPath libTargetDir) objExtension True hSharedObjs <-@@ -733,7 +747,7 @@ lib lbi clbi- libTargetDir+ (coerceSymbolicPath libTargetDir) ("dyn_" ++ objExtension) False else return []@@ -743,11 +757,11 @@ let staticObjectFiles = hObjs- ++ map (libTargetDir </>) cObjs+ ++ map (makeSymbolicPath . (getSymbolicPath libTargetDir </>) . getSymbolicPath) cObjs ++ stubObjs dynamicObjectFiles = hSharedObjs- ++ map (libTargetDir </>) cSharedObjs+ ++ map (makeSymbolicPath . (getSymbolicPath libTargetDir </>) . getSymbolicPath) cSharedObjs ++ stubSharedObjs -- After the relocation lib is created we invoke ghc -shared -- with the dependencies spelled out as -package arguments@@ -758,7 +772,7 @@ , ghcOptDynLinkMode = toFlag GhcDynamicOnly , ghcOptInputFiles = toNubListR dynamicObjectFiles , ghcOptOutputFile = toFlag sharedLibFilePath- , ghcOptExtra = hcSharedOptions GHC libBi+ , ghcOptExtra = hcOptions GHC libBi ++ hcSharedOptions GHC libBi , -- 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.@@ -789,7 +803,7 @@ Internal.mkGhcOptPackages mempty clbi , ghcOptLinkLibs = extraLibs libBi , ghcOptLinkLibPath = toNubListR $ extraLibDirs libBi- , ghcOptLinkFrameworks = toNubListR $ PD.frameworks libBi+ , ghcOptLinkFrameworks = toNubListR $ map getSymbolicPath $ PD.frameworks libBi , ghcOptLinkFrameworkDirs = toNubListR $ PD.extraFrameworkDirs libBi , ghcOptRPaths = rpaths@@ -863,7 +877,7 @@ } checkPackageDbStack verbosity packageDBs (ghcjsProg, _) <- requireProgram verbosity ghcjsProgram progdb- runGHC verbosity ghcjsProg comp platform replOpts+ runGHC verbosity ghcjsProg comp platform Nothing replOpts -- ----------------------------------------------------------------------------- -- Building an executable or foreign library@@ -1037,7 +1051,7 @@ ForeignLibTypeUnknown -> cabalBug "unknown foreign lib type" -gbuildModDefFiles :: GBuildMode -> [FilePath]+gbuildModDefFiles :: GBuildMode -> [RelativePath Source File] gbuildModDefFiles (GBuildExe _) = [] gbuildModDefFiles (GReplExe _ _) = [] gbuildModDefFiles (GBuildFLib flib) = foreignLibModDefFile flib@@ -1103,21 +1117,22 @@ -- -- Used to correctly build and link sources. data BuildSources = BuildSources- { cSourcesFiles :: [FilePath]- , cxxSourceFiles :: [FilePath]- , inputSourceFiles :: [FilePath]+ { cSourcesFiles :: [SymbolicPath Pkg File]+ , cxxSourceFiles :: [SymbolicPath Pkg File]+ , inputSourceFiles :: [SymbolicPath Pkg File] , inputSourceModules :: [ModuleName] } -- | Locate and return the 'BuildSources' required to build and link. gbuildSources :: Verbosity+ -> Maybe (SymbolicPath CWD ('Dir Pkg)) -> PackageId -> CabalSpecVersion- -> FilePath+ -> SymbolicPath Pkg (Dir Source) -> GBuildMode -> IO BuildSources-gbuildSources verbosity pkgId specVer tmpDir bm =+gbuildSources verbosity mbWorkDir pkgId specVer tmpDir bm = case bm of GBuildExe exe -> exeSources exe GReplExe _ exe -> exeSources exe@@ -1126,12 +1141,13 @@ where exeSources :: Executable -> IO BuildSources exeSources exe@Executable{buildInfo = bnfo, modulePath = modPath} = do- main <- findFileEx verbosity (tmpDir : map getSymbolicPath (hsSourceDirs bnfo)) modPath+ main <- findFileCwd verbosity mbWorkDir (tmpDir : hsSourceDirs bnfo) modPath let mainModName = fromMaybe ModuleName.main $ exeMainModuleName exe otherModNames = exeModules exe+ haskellMain = isHaskell (getSymbolicPath main) -- Scripts have fakePackageId and are always Haskell but can have any extension.- if isHaskell main || pkgId == fakePackageId+ if haskellMain || pkgId == fakePackageId then if specVer < CabalSpecV2_0 && (mainModName `elem` otherModNames) then do@@ -1168,7 +1184,7 @@ } else let (csf, cxxsf)- | isCxx main = (cSources bnfo, main : cxxSources bnfo)+ | isCxx (getSymbolicPath main) = (cSources bnfo, main : cxxSources bnfo) -- if main is not a Haskell source -- and main is not a C++ source -- then we assume that it is a C source@@ -1215,7 +1231,8 @@ GBuildFLib{} -> mempty comp = compiler lbi platform = hostPlatform lbi- runGhcProg = runGHC verbosity ghcjsProg comp platform+ mbWorkDir = mbWorkDirLBI lbi+ runGhcProg = runGHC verbosity ghcjsProg comp platform mbWorkDir let (bnfo, threaded) = case bm of GBuildFLib _ -> popThreadedFlag (gbuildInfo bm)@@ -1223,11 +1240,15 @@ -- the name that GHC really uses (e.g., with .exe on Windows for executables) let targetName = gbuildTargetName lbi bm- let targetDir = buildDir lbi </> (gbuildName bm)- let tmpDir = targetDir </> (gbuildName bm ++ "-tmp")- createDirectoryIfMissingVerbose verbosity True targetDir- createDirectoryIfMissingVerbose verbosity True tmpDir+ targetDir = buildDir lbi </> makeRelativePathEx (gbuildName bm)+ tmpDir = targetDir </> makeRelativePathEx (gbuildName bm ++ "-tmp") + -- See Note [Symbolic paths] in Distribution.Utils.Path+ i = interpretSymbolicPath mbWorkDir++ createDirectoryIfMissingVerbose verbosity True $ i targetDir+ createDirectoryIfMissingVerbose verbosity True $ i tmpDir+ -- TODO: do we need to put hs-boot files into place for mutually recursive -- modules? FIX: what about exeName.hi-boot? @@ -1236,11 +1257,11 @@ let isCoverageEnabled = exeCoverage lbi hpcdir way | gbuildIsRepl bm = mempty -- HPC is not supported in ghci- | isCoverageEnabled = toFlag $ Hpc.mixDir (tmpDir </> extraCompilationArtifacts) way+ | isCoverageEnabled = toFlag $ Hpc.mixDir (tmpDir </> coerceSymbolicPath extraCompilationArtifacts) way | otherwise = mempty rpaths <- getRPaths lbi clbi- buildSources <- gbuildSources verbosity (package pkg_descr) (specVersion pkg_descr) tmpDir bm+ buildSources <- gbuildSources verbosity mbWorkDir (package pkg_descr) (specVersion pkg_descr) tmpDir bm let cSrcs = cSourcesFiles buildSources cxxSrcs = cxxSourceFiles buildSources@@ -1248,8 +1269,8 @@ inputModules = inputSourceModules buildSources isGhcDynamic = isDynamic comp dynamicTooSupported = supportsDynamicToo comp- cObjs = map (`replaceExtension` objExtension) cSrcs- cxxObjs = map (`replaceExtension` objExtension) cxxSrcs+ cObjs = map ((`replaceExtensionSymbolicPath` objExtension)) cSrcs+ cxxObjs = map ((`replaceExtensionSymbolicPath` objExtension)) cxxSrcs needDynamic = gbuildNeedDynamic lbi bm needProfiling = withProfExe lbi @@ -1267,12 +1288,12 @@ , ghcOptInputFiles = toNubListR $ if package pkg_descr == fakePackageId- then filter isHaskell inputFiles+ then filter (isHaskell . getSymbolicPath) inputFiles else inputFiles , ghcOptInputScripts = toNubListR $ if package pkg_descr == fakePackageId- then filter (not . isHaskell) inputFiles+ then filter (not . isHaskell . getSymbolicPath) inputFiles else [] , ghcOptInputModules = toNubListR inputModules , -- for all executable components (exe/test/bench),@@ -1309,7 +1330,7 @@ ghcOptFPic = toFlag True , ghcOptHiSuffix = toFlag "dyn_hi" , ghcOptObjSuffix = toFlag "dyn_o"- , ghcOptExtra = hcSharedOptions GHC bnfo+ , ghcOptExtra = hcOptions GHC bnfo ++ hcSharedOptions GHC bnfo , ghcOptHPCDir = hpcdir Hpc.Dyn } dynTooOpts =@@ -1327,13 +1348,14 @@ , ghcOptLinkLibPath = toNubListR $ extraLibDirs bnfo , ghcOptLinkFrameworks = toNubListR $- PD.frameworks bnfo+ map getSymbolicPath $+ PD.frameworks bnfo , ghcOptLinkFrameworkDirs = toNubListR $ PD.extraFrameworkDirs bnfo , ghcOptInputFiles = toNubListR- [tmpDir </> x | x <- cObjs ++ cxxObjs]+ [makeSymbolicPath $ getSymbolicPath tmpDir </> getSymbolicPath x | x <- cObjs ++ cxxObjs] } dynLinkerOpts = mempty@@ -1449,8 +1471,8 @@ -- consider this a user error. However, we should strive to -- add a warning if this occurs. odir = fromFlag (ghcOptObjDir opts)- createDirectoryIfMissingVerbose verbosity True odir- needsRecomp <- checkNeedsRecompilation filename opts+ createDirectoryIfMissingVerbose verbosity True (i odir)+ needsRecomp <- checkNeedsRecompilation mbWorkDir filename opts when needsRecomp $ runGhcProg opts | filename <- cxxSrcs@@ -1491,8 +1513,8 @@ | needDynamic = sharedCcOpts | otherwise = vanillaCcOpts odir = fromFlag (ghcOptObjDir opts)- createDirectoryIfMissingVerbose verbosity True odir- needsRecomp <- checkNeedsRecompilation filename opts+ createDirectoryIfMissingVerbose verbosity True (i odir)+ needsRecomp <- checkNeedsRecompilation mbWorkDir filename opts when needsRecomp $ runGhcProg opts | filename <- cSrcs@@ -1516,10 +1538,11 @@ info verbosity "Linking..." -- Work around old GHCs not relinking in this -- situation, see #3294- let target = targetDir </> targetName+ let target = targetDir </> makeRelativePathEx targetName when (compilerVersion comp < mkVersion [7, 7]) $ do- e <- doesFileExist target- when e (removeFile target)+ let targetPath = i target+ e <- doesFileExist targetPath+ when e (removeFile targetPath) runGhcProg linkOpts{ghcOptOutputFile = toFlag target} GBuildFLib flib -> do let rtsInfo = extractRtsInfo lbi@@ -1543,9 +1566,9 @@ { ghcOptLinkNoHsMain = toFlag True , ghcOptShared = toFlag True , ghcOptLinkLibs = rtsOptLinkLibs- , ghcOptLinkLibPath = toNubListR $ rtsLibPaths rtsInfo+ , ghcOptLinkLibPath = toNubListR $ map makeSymbolicPath $ rtsLibPaths rtsInfo , ghcOptFPic = toFlag True- , ghcOptLinkModDefFiles = toNubListR $ gbuildModDefFiles bm+ , ghcOptLinkModDefFiles = toNubListR $ fmap getSymbolicPath $ gbuildModDefFiles bm } ForeignLibNativeStatic -> -- this should be caught by buildFLib@@ -1559,8 +1582,9 @@ -- @flibBuildName@. info verbosity "Linking..." let buildName = flibBuildName lbi flib- runGhcProg linkOpts{ghcOptOutputFile = toFlag (targetDir </> buildName)}- renameFile (targetDir </> buildName) (targetDir </> targetName)+ buildFile = targetDir </> makeRelativePathEx buildName+ runGhcProg linkOpts{ghcOptOutputFile = toFlag buildFile}+ renameFile (i buildFile) (i targetDir </> targetName) data DynamicRtsInfo = DynamicRtsInfo { dynRtsVanillaLib :: FilePath@@ -1629,18 +1653,31 @@ -- | Returns True if the modification date of the given source file is newer than -- the object file we last compiled for it, or if no object file exists yet.-checkNeedsRecompilation :: FilePath -> GhcOptions -> IO Bool-checkNeedsRecompilation filename opts = filename `moreRecentFile` oname+checkNeedsRecompilation+ :: Maybe (SymbolicPath CWD (Dir Pkg))+ -> SymbolicPath Pkg File+ -> GhcOptions+ -> IO Bool+checkNeedsRecompilation mbWorkDir filename opts =+ i filename `moreRecentFile` oname where- oname = getObjectFileName filename opts+ oname = getObjectFileName mbWorkDir filename opts+ i = interpretSymbolicPath mbWorkDir -- See Note [Symbolic paths] in Distribution.Utils.Path -- | Finds the object file name of the given source file-getObjectFileName :: FilePath -> GhcOptions -> FilePath-getObjectFileName filename opts = oname+getObjectFileName+ :: Maybe (SymbolicPath CWD (Dir Pkg))+ -> SymbolicPath Pkg File+ -> GhcOptions+ -> FilePath+getObjectFileName mbWorkDir filename opts = oname where- odir = fromFlag (ghcOptObjDir opts)+ i = interpretSymbolicPath mbWorkDir -- See Note [Symbolic paths] in Distribution.Utils.Path+ odir = i $ fromFlag (ghcOptObjDir opts) oext = fromFlagOrDefault "o" (ghcOptObjSuffix opts)- oname = odir </> replaceExtension filename oext+ -- NB: the filepath might be absolute, e.g. if it is the path to+ -- an autogenerated .hs file.+ oname = odir </> replaceExtension (getSymbolicPath filename) oext -- | Calculate the RPATHs for the component we are building. --@@ -1730,6 +1767,7 @@ libBi = libBuildInfo lib comp = compiler lbi platform = hostPlatform lbi+ mbWorkDir = mbWorkDirLBI lbi vanillaArgs = (componentGhcOptions verbosity lbi libBi clbi (componentBuildDir lbi clbi)) `mappend` mempty@@ -1743,7 +1781,7 @@ , ghcOptFPic = toFlag True , ghcOptHiSuffix = toFlag "js_dyn_hi" , ghcOptObjSuffix = toFlag "js_dyn_o"- , ghcOptExtra = hcSharedOptions GHC libBi+ , ghcOptExtra = hcOptions GHC libBi ++ hcSharedOptions GHC libBi } profArgs = vanillaArgs@@ -1767,7 +1805,7 @@ hash <- getProgramInvocationOutput verbosity- =<< ghcInvocation verbosity ghcjsProg comp platform ghcArgs+ =<< ghcInvocation verbosity ghcjsProg comp platform mbWorkDir ghcArgs return (takeWhile (not . isSpace) hash) componentGhcOptions@@ -1775,7 +1813,7 @@ -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo- -> FilePath+ -> SymbolicPath Pkg (Dir build) -> GhcOptions componentGhcOptions verbosity lbi bi clbi odir = let opts = Internal.componentGhcOptions verbosity lbi bi clbi odir@@ -1812,7 +1850,7 @@ exeFileName = exeName' fixedExeBaseName = progprefix ++ exeName' ++ progsuffix installBinary dest = do- runDbProgram verbosity ghcjsProgram (withPrograms lbi) $+ runDbProgramCwd verbosity (mbWorkDirLBI lbi) ghcjsProgram (withPrograms lbi) $ [ "--install-executable" , buildPref </> exeName' </> exeFileName , "-o"@@ -1891,10 +1929,12 @@ , f <- "" : extraDynLibFlavours (libBuildInfo lib) ] where+ i = interpretSymbolicPathLBI lbi -- See Note [Symbolic paths] in Distribution.Utils.Path builtDir' = componentBuildDir lbi clbi+ mbWorkDir = mbWorkDirLBI lbi install isShared isJS srcDir dstDir name = do- let src = srcDir </> name+ let src = i $ srcDir </> makeRelativePathEx name dst = dstDir </> name createDirectoryIfMissingVerbose verbosity True dstDir @@ -1912,9 +1952,10 @@ installOrdinary = install False True installShared = install True True - copyModuleFiles ext =- findModuleFilesEx verbosity [builtDir'] [ext] (allLibModules lib clbi)- >>= installOrdinaryFiles verbosity targetDir+ copyModuleFiles ext = do+ files <- findModuleFilesCwd verbosity mbWorkDir [builtDir'] [ext] (allLibModules lib clbi)+ let files' = map (i *** getSymbolicPath) files+ installOrdinaryFiles verbosity targetDir files' compiler_id = compilerId (compiler lbi) platform = hostPlatform lbi@@ -1985,14 +2026,16 @@ registerPackage :: Verbosity -> ProgramDb- -> PackageDBStack+ -> Maybe (SymbolicPath CWD (Dir from))+ -> PackageDBStackS from -> InstalledPackageInfo -> HcPkg.RegisterOptions -> IO ()-registerPackage verbosity progdb packageDbs installedPkgInfo registerOptions =+registerPackage verbosity progdb mbWorkDir packageDbs installedPkgInfo registerOptions = HcPkg.register (hcPkgInfo progdb) verbosity+ mbWorkDir packageDbs installedPkgInfo registerOptions@@ -2020,7 +2063,10 @@ -- fail. createDirectoryIfMissing True rootDir return rootDir- pkgRoot' (SpecificPackageDB fp) = return (takeDirectory fp)+ pkgRoot' (SpecificPackageDB fp) =+ return $+ takeDirectory $+ interpretSymbolicPathLBI lbi fp -- | Get the JavaScript file name and command and arguments to run a -- program compiled by GHCJS
src/Distribution/Simple/Glob.hs view
@@ -1,6 +1,8 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE RankNTypes #-} ----------------------------------------------------------------------------- @@ -22,6 +24,8 @@ , GlobResult (..) , globMatches , fileGlobMatches+ , matchGlob+ , matchGlobPieces , matchDirFileGlob , matchDirFileGlobWithDie , runDirFileGlob@@ -39,20 +43,82 @@ import Distribution.Compat.Prelude import Prelude () -import Distribution.CabalSpecVersion (CabalSpecVersion)+import Distribution.CabalSpecVersion+ ( CabalSpecVersion (..)+ )+import Distribution.Pretty import Distribution.Simple.Errors ( CabalException (MatchDirFileGlob, MatchDirFileGlobErrors) ) import Distribution.Simple.Glob.Internal-import Distribution.Simple.Utils (dieWithException, warn)-import Distribution.Verbosity (Verbosity)+import Distribution.Simple.Utils+ ( debug+ , dieWithException+ , getDirectoryContentsRecursive+ , warn+ )+import Distribution.Utils.Path+import Distribution.Verbosity+ ( Verbosity+ , silent+ ) +import Control.Monad (mapM)+import Data.List (stripPrefix)+import System.Directory+import System.FilePath hiding ((<.>), (</>))+ ------------------------------------------------------------------------------- -- * Matching -------------------------------------------------------------------------------- +-- | Match a 'Glob' against the file system, starting from a+-- given root directory. The results are all relative to the given root.+--+-- @since 3.12.0.0+matchGlob :: FilePath -> Glob -> IO [FilePath]+matchGlob root glob =+ -- For this function, which is the general globbing one (doesn't care about+ -- cabal spec, used e.g. for monitoring), we consider all matches.+ mapMaybe+ ( \case+ GlobMatch a -> Just a+ GlobWarnMultiDot a -> Just a+ GlobMatchesDirectory a -> Just a+ GlobMissingDirectory{} -> Nothing+ )+ <$> runDirFileGlob silent Nothing root glob++-- | Match a globbing pattern against a file path component+matchGlobPieces :: GlobPieces -> String -> Bool+matchGlobPieces = goStart+ where+ -- From the man page, glob(7):+ -- "If a filename starts with a '.', this character must be+ -- matched explicitly."++ go, goStart :: [GlobPiece] -> String -> Bool++ goStart (WildCard : _) ('.' : _) = False+ goStart (Union globs : rest) cs =+ any+ (\glob -> goStart (glob ++ rest) cs)+ globs+ goStart rest cs = go rest cs++ go [] "" = True+ go (Literal lit : rest) cs+ | Just cs' <- stripPrefix lit cs =+ go rest cs'+ | otherwise = False+ go [WildCard] "" = True+ go (WildCard : rest) (c : cs) = go rest (c : cs) || go (WildCard : rest) cs+ go (Union globs : rest) cs = any (\glob -> go (glob ++ rest) cs) globs+ go [] (_ : _) = False+ go (_ : _) "" = False+ -- | Extract the matches from a list of 'GlobResult's. -- -- Note: throws away the 'GlobMissingDirectory' results; chances are@@ -75,7 +141,12 @@ -- prefix. -- -- The second 'FilePath' is the glob itself.-matchDirFileGlob :: Verbosity -> CabalSpecVersion -> FilePath -> FilePath -> IO [FilePath]+matchDirFileGlob+ :: Verbosity+ -> CabalSpecVersion+ -> Maybe (SymbolicPath CWD (Dir dir))+ -> SymbolicPathX allowAbs dir file+ -> IO [SymbolicPathX allowAbs dir file] matchDirFileGlob v = matchDirFileGlobWithDie v dieWithException -- | Like 'matchDirFileGlob' but with customizable 'die'@@ -83,45 +154,351 @@ -- @since 3.6.0.0 matchDirFileGlobWithDie :: Verbosity- -> (Verbosity -> CabalException -> IO [FilePath])+ -> (forall res. Verbosity -> CabalException -> IO [res]) -> CabalSpecVersion- -> FilePath+ -> Maybe (SymbolicPath CWD (Dir dir))+ -> SymbolicPathX allowAbs dir file+ -> IO [SymbolicPathX allowAbs dir file]+matchDirFileGlobWithDie verbosity rip version mbWorkDir symPath =+ let rawFilePath = getSymbolicPath symPath+ dir = maybe "." getSymbolicPath mbWorkDir+ in case parseFileGlob version rawFilePath of+ Left err -> rip verbosity $ MatchDirFileGlob (explainGlobSyntaxError rawFilePath err)+ Right glob -> do+ results <- runDirFileGlob verbosity (Just version) dir glob+ let missingDirectories =+ [missingDir | GlobMissingDirectory missingDir <- results]+ matches = globMatches results+ directoryMatches = [a | GlobMatchesDirectory a <- results]++ let errors :: [String]+ errors =+ [ "filepath wildcard '"+ ++ rawFilePath+ ++ "' refers to the directory"+ ++ " '"+ ++ missingDir+ ++ "', which does not exist or is not a directory."+ | missingDir <- missingDirectories+ ]+ ++ [ "filepath wildcard '" ++ rawFilePath ++ "' does not match any files."+ | null matches && null directoryMatches+ -- we don't error out on directory matches, simply warn about them and ignore.+ ]++ warns :: [String]+ warns =+ [ "Ignoring directory '" ++ path ++ "'" ++ " listed in a Cabal package field which should only include files (not directories)."+ | path <- directoryMatches+ ]++ if null errors+ then do+ unless (null warns) $+ warn verbosity $+ unlines warns+ return $ map unsafeMakeSymbolicPath matches+ else rip verbosity $ MatchDirFileGlobErrors errors++-------------------------------------------------------------------------------++-- * Parsing & printing++--------------------------------------------------------------------------------+-- Filepaths with globs may be parsed in the special context is globbing in+-- cabal package fields, such as `data-files`. In that case, we restrict the+-- globbing syntax to that supported by the cabal spec version in use.+-- Otherwise, we parse the globs to the extent of our globbing features+-- (wildcards `*`, unions `{a,b,c}`, and directory-recursive wildcards `**`).++-- ** Parsing globs in a cabal package++parseFileGlob :: CabalSpecVersion -> FilePath -> Either GlobSyntaxError Glob+parseFileGlob version filepath = case reverse (splitDirectories filepath) of+ [] ->+ Left EmptyGlob+ (filename : "**" : segments)+ | allowGlobStar -> do+ finalSegment <- case splitExtensions filename of+ ("*", ext)+ | '*' `elem` ext -> Left StarInExtension+ | null ext -> Left NoExtensionOnStar+ | otherwise -> Right (GlobDirRecursive [WildCard, Literal ext])+ _+ | allowLiteralFilenameGlobStar ->+ Right (GlobDirRecursive [Literal filename])+ | otherwise ->+ Left LiteralFileNameGlobStar++ foldM addStem finalSegment segments+ | otherwise -> Left VersionDoesNotSupportGlobStar+ (filename : segments) -> do+ pat <- case splitExtensions filename of+ ("*", ext)+ | not allowGlob -> Left VersionDoesNotSupportGlob+ | '*' `elem` ext -> Left StarInExtension+ | null ext -> Left NoExtensionOnStar+ | otherwise -> Right (GlobFile [WildCard, Literal ext])+ (_, ext)+ | '*' `elem` ext -> Left StarInExtension+ | '*' `elem` filename -> Left StarInFileName+ | otherwise -> Right (GlobFile [Literal filename])++ foldM addStem pat segments+ where+ addStem pat seg+ | '*' `elem` seg = Left StarInDirectory+ | otherwise = Right (GlobDir [Literal seg] pat)+ allowGlob = version >= CabalSpecV1_6+ allowGlobStar = version >= CabalSpecV2_4+ allowLiteralFilenameGlobStar = version >= CabalSpecV3_8++enableMultidot :: CabalSpecVersion -> Bool+enableMultidot version+ | version >= CabalSpecV2_4 = True+ | otherwise = False++--------------------------------------------------------------------------------+-- Parse and printing utils+--------------------------------------------------------------------------------++-- ** Cabal package globbing errors++data GlobSyntaxError+ = StarInDirectory+ | StarInFileName+ | StarInExtension+ | NoExtensionOnStar+ | EmptyGlob+ | LiteralFileNameGlobStar+ | VersionDoesNotSupportGlobStar+ | VersionDoesNotSupportGlob+ deriving (Eq, Show)++explainGlobSyntaxError :: FilePath -> GlobSyntaxError -> String+explainGlobSyntaxError filepath StarInDirectory =+ "invalid file glob '"+ ++ filepath+ ++ "'. A wildcard '**' is only allowed as the final parent"+ ++ " directory. Stars must not otherwise appear in the parent"+ ++ " directories."+explainGlobSyntaxError filepath StarInExtension =+ "invalid file glob '"+ ++ filepath+ ++ "'. Wildcards '*' are only allowed as the"+ ++ " file's base name, not in the file extension."+explainGlobSyntaxError filepath StarInFileName =+ "invalid file glob '"+ ++ filepath+ ++ "'. Wildcards '*' may only totally replace the"+ ++ " file's base name, not only parts of it."+explainGlobSyntaxError filepath NoExtensionOnStar =+ "invalid file glob '"+ ++ filepath+ ++ "'. If a wildcard '*' is used it must be with an file extension."+explainGlobSyntaxError filepath LiteralFileNameGlobStar =+ "invalid file glob '"+ ++ filepath+ ++ "'. Prior to 'cabal-version: 3.8'"+ ++ " if a wildcard '**' is used as a parent directory, the"+ ++ " file's base name must be a wildcard '*'."+explainGlobSyntaxError _ EmptyGlob =+ "invalid file glob. A glob cannot be the empty string."+explainGlobSyntaxError filepath VersionDoesNotSupportGlobStar =+ "invalid file glob '"+ ++ filepath+ ++ "'. Using the double-star syntax requires 'cabal-version: 2.4'"+ ++ " or greater. Alternatively, for compatibility with earlier Cabal"+ ++ " versions, list the included directories explicitly."+explainGlobSyntaxError filepath VersionDoesNotSupportGlob =+ "invalid file glob '"+ ++ filepath+ ++ "'. Using star wildcards requires 'cabal-version: >= 1.6'. "+ ++ "Alternatively if you require compatibility with earlier Cabal "+ ++ "versions then list all the files explicitly."++-- Note throughout that we use splitDirectories, not splitPath. On+-- Posix, this makes no difference, but, because Windows accepts both+-- slash and backslash as its path separators, if we left in the+-- separators from the glob we might not end up properly normalised.++data GlobResult a+ = -- | The glob matched the value supplied.+ GlobMatch a+ | -- | The glob did not match the value supplied because the+ -- cabal-version is too low and the extensions on the file did+ -- not precisely match the glob's extensions, but rather the+ -- glob was a proper suffix of the file's extensions; i.e., if+ -- not for the low cabal-version, it would have matched.+ GlobWarnMultiDot a+ | -- | The glob couldn't match because the directory named doesn't+ -- exist. The directory will be as it appears in the glob (i.e.,+ -- relative to the directory passed to 'matchDirFileGlob', and,+ -- for 'data-files', relative to 'data-dir').+ GlobMissingDirectory a+ | -- | The glob matched a directory when we were looking for files only.+ -- It didn't match a file!+ --+ -- @since 3.12.0.0+ GlobMatchesDirectory a+ deriving (Show, Eq, Ord, Functor)++-- | Match files against a pre-parsed glob, starting in a directory.+--+-- The 'Version' argument must be the spec version of the package+-- description being processed, as globs behave slightly differently+-- in different spec versions.+--+-- The 'FilePath' argument is the directory that the glob is relative+-- to. It must be a valid directory (and hence it can't be the empty+-- string). The returned values will not include this prefix.+runDirFileGlob+ :: Verbosity+ -> Maybe CabalSpecVersion+ -- ^ If the glob we are running should care about the cabal spec, and warnings such as 'GlobWarnMultiDot', then this should be the version.+ -- If you want to run a glob but don't care about any of the cabal-spec restrictions on globs, use 'Nothing'! -> FilePath- -> IO [FilePath]-matchDirFileGlobWithDie verbosity rip version dir filepath = case parseFileGlob version filepath of- Left err -> rip verbosity $ MatchDirFileGlob (explainGlobSyntaxError filepath err)- Right glob -> do- results <- runDirFileGlob verbosity (Just version) dir glob- let missingDirectories =- [missingDir | GlobMissingDirectory missingDir <- results]- matches = globMatches results- directoryMatches = [a | GlobMatchesDirectory a <- results]+ -> Glob+ -> IO [GlobResult FilePath]+runDirFileGlob verbosity mspec rawRoot pat = do+ -- The default data-dir is null. Our callers -should- be+ -- converting that to '.' themselves, but it's a certainty that+ -- some future call-site will forget and trigger a really+ -- hard-to-debug failure if we don't check for that here.+ when (null rawRoot) $+ warn verbosity $+ "Null dir passed to runDirFileGlob; interpreting it "+ ++ "as '.'. This is probably an internal error."+ let root = if null rawRoot then "." else rawRoot+ debug verbosity $ "Expanding glob '" ++ show (pretty pat) ++ "' in directory '" ++ root ++ "'."+ -- This function might be called from the project root with dir as+ -- ".". Walking the tree starting there involves going into .git/+ -- and dist-newstyle/, which is a lot of work for no reward, so+ -- extract the constant prefix from the pattern and start walking+ -- there, and only walk as much as we need to: recursively if **,+ -- the whole directory if *, and just the specific file if it's a+ -- literal.+ let+ (prefixSegments, variablePattern) = splitConstantPrefix pat+ joinedPrefix = joinPath prefixSegments - let errors :: [String]- errors =- [ "filepath wildcard '"- ++ filepath- ++ "' refers to the directory"- ++ " '"- ++ missingDir- ++ "', which does not exist or is not a directory."- | missingDir <- missingDirectories- ]- ++ [ "filepath wildcard '" ++ filepath ++ "' does not match any files."- | null matches && null directoryMatches- -- we don't error out on directory matches, simply warn about them and ignore.- ]+ -- The glob matching function depends on whether we care about the cabal version or not+ doesGlobMatch :: GlobPieces -> String -> Maybe (GlobResult ())+ doesGlobMatch glob str = case mspec of+ Just spec -> checkNameMatches spec glob str+ Nothing -> if matchGlobPieces glob str then Just (GlobMatch ()) else Nothing - warns :: [String]- warns =- [ "Ignoring directory '" ++ path ++ "'" ++ " listed in a Cabal package field which should only include files (not directories)."- | path <- directoryMatches- ]+ go (GlobFile glob) dir = do+ entries <- getDirectoryContents (root </> dir)+ catMaybes+ <$> mapM+ ( \s -> do+ -- When running a glob from a Cabal package description (i.e.+ -- when a cabal spec version is passed as an argument), we+ -- disallow matching a @GlobFile@ against a directory, preferring+ -- @GlobDir dir GlobDirTrailing@ to specify a directory match.+ isFile <- maybe (return True) (const $ doesFileExist (root </> dir </> s)) mspec+ let match = (dir </> s <$) <$> doesGlobMatch glob s+ return $+ if isFile+ then match+ else case match of+ Just (GlobMatch x) -> Just $ GlobMatchesDirectory x+ Just (GlobWarnMultiDot x) -> Just $ GlobMatchesDirectory x+ Just (GlobMatchesDirectory x) -> Just $ GlobMatchesDirectory x+ Just (GlobMissingDirectory x) -> Just $ GlobMissingDirectory x -- this should never match, unless you are in a file-delete-heavy concurrent setting i guess+ Nothing -> Nothing+ )+ entries+ go (GlobDirRecursive glob) dir = do+ entries <- getDirectoryContentsRecursive (root </> dir)+ return $+ mapMaybe+ ( \s -> do+ globMatch <- doesGlobMatch glob (takeFileName s)+ pure ((dir </> s) <$ globMatch)+ )+ entries+ go (GlobDir glob globPath) dir = do+ entries <- getDirectoryContents (root </> dir)+ subdirs <-+ filterM+ ( \subdir ->+ doesDirectoryExist+ (root </> dir </> subdir)+ )+ $ filter (matchGlobPieces glob) entries+ concat <$> traverse (\subdir -> go globPath (dir </> subdir)) subdirs+ go GlobDirTrailing dir = return [GlobMatch dir] - if null errors- then do- unless (null warns) $- warn verbosity $- unlines warns- return matches- else rip verbosity $ MatchDirFileGlobErrors errors+ directoryExists <- doesDirectoryExist (root </> joinedPrefix)+ if directoryExists+ then go variablePattern joinedPrefix+ else return [GlobMissingDirectory joinedPrefix]+ where+ -- \| Extract the (possibly null) constant prefix from the pattern.+ -- This has the property that, if @(pref, final) = splitConstantPrefix pat@,+ -- then @pat === foldr GlobDir final pref@.+ splitConstantPrefix :: Glob -> ([FilePath], Glob)+ splitConstantPrefix = unfoldr' step+ where+ step (GlobDir [Literal seg] pat') = Right (seg, pat')+ step pat' = Left pat'++ unfoldr' :: (a -> Either r (b, a)) -> a -> ([b], r)+ unfoldr' f a = case f a of+ Left r -> ([], r)+ Right (b, a') -> case unfoldr' f a' of+ (bs, r) -> (b : bs, r)++-- | Is the root of this relative glob path a directory-recursive wildcard, e.g. @**/*.txt@ ?+isRecursiveInRoot :: Glob -> Bool+isRecursiveInRoot (GlobDirRecursive _) = True+isRecursiveInRoot _ = False++-- | Check how the string matches the glob under this cabal version+checkNameMatches :: CabalSpecVersion -> GlobPieces -> String -> Maybe (GlobResult ())+checkNameMatches spec glob candidate+ -- Check if glob matches in its general form+ | matchGlobPieces glob candidate =+ -- if multidot is supported, then this is a clean match+ if enableMultidot spec+ then pure (GlobMatch ())+ else -- if not, issue a warning saying multidot is needed for the match++ let (_, candidateExts) = splitExtensions $ takeFileName candidate+ extractExts :: GlobPieces -> Maybe String+ extractExts [] = Nothing+ extractExts [Literal lit]+ -- Any literal terminating a glob, and which does have an extension,+ -- returns that extension. Otherwise, recurse until Nothing is returned.+ | let ext = takeExtensions lit+ , ext /= "" =+ Just ext+ extractExts (_ : x) = extractExts x+ in case extractExts glob of+ Just exts+ | exts == candidateExts ->+ return (GlobMatch ())+ | exts `isSuffixOf` candidateExts ->+ return (GlobWarnMultiDot ())+ _ -> return (GlobMatch ())+ | otherwise = empty++-- | How/does the glob match the given filepath, according to the cabal version?+-- Since this is pure, we don't make a distinction between matching on+-- directories or files (i.e. this function won't return 'GlobMatchesDirectory')+fileGlobMatches :: CabalSpecVersion -> Glob -> FilePath -> Maybe (GlobResult ())+fileGlobMatches version g path = go g (splitDirectories path)+ where+ go GlobDirTrailing [] = Just (GlobMatch ())+ go (GlobFile glob) [file] = checkNameMatches version glob file+ go (GlobDirRecursive glob) dirs+ | [] <- reverse dirs =+ Nothing -- @dir/**/x.txt@ should not match @dir/hello@+ | file : _ <- reverse dirs =+ checkNameMatches version glob file+ go (GlobDir glob globPath) (dir : dirs) = do+ _ <- checkNameMatches version glob dir -- we only care if dir segment matches+ go globPath dirs+ go _ _ = Nothing
src/Distribution/Simple/Glob/Internal.hs view
@@ -20,20 +20,9 @@ import Distribution.Compat.Prelude import Prelude () -import Control.Monad (mapM)-+import qualified Distribution.Compat.CharParsing as P import Distribution.Parsec import Distribution.Pretty--import Distribution.CabalSpecVersion-import Distribution.Simple.Utils-import Distribution.Verbosity hiding (normal)--import Data.List (stripPrefix)-import System.Directory-import System.FilePath--import qualified Distribution.Compat.CharParsing as P import qualified Text.PrettyPrint as Disp --------------------------------------------------------------------------------@@ -70,116 +59,8 @@ instance Binary GlobPiece instance Structured GlobPiece ------------------------------------------------------------------------------------ * Matching- ------------------------------------------------------------------------------------ | Match a 'Glob' against the file system, starting from a--- given root directory. The results are all relative to the given root.------ @since 3.12.0.0-matchGlob :: FilePath -> Glob -> IO [FilePath]-matchGlob root glob =- -- For this function, which is the general globbing one (doesn't care about- -- cabal spec, used e.g. for monitoring), we consider all matches.- mapMaybe- ( \case- GlobMatch a -> Just a- GlobWarnMultiDot a -> Just a- GlobMatchesDirectory a -> Just a- GlobMissingDirectory{} -> Nothing- )- <$> runDirFileGlob silent Nothing root glob---- | Match a globbing pattern against a file path component-matchGlobPieces :: GlobPieces -> String -> Bool-matchGlobPieces = goStart- where- -- From the man page, glob(7):- -- "If a filename starts with a '.', this character must be- -- matched explicitly."-- go, goStart :: [GlobPiece] -> String -> Bool-- goStart (WildCard : _) ('.' : _) = False- goStart (Union globs : rest) cs =- any- (\glob -> goStart (glob ++ rest) cs)- globs- goStart rest cs = go rest cs-- go [] "" = True- go (Literal lit : rest) cs- | Just cs' <- stripPrefix lit cs =- go rest cs'- | otherwise = False- go [WildCard] "" = True- go (WildCard : rest) (c : cs) = go rest (c : cs) || go (WildCard : rest) cs- go (Union globs : rest) cs = any (\glob -> go (glob ++ rest) cs) globs- go [] (_ : _) = False- go (_ : _) "" = False------------------------------------------------------------------------------------- * Parsing & printing------------------------------------------------------------------------------------- Filepaths with globs may be parsed in the special context is globbing in--- cabal package fields, such as `data-files`. In that case, we restrict the--- globbing syntax to that supported by the cabal spec version in use.--- Otherwise, we parse the globs to the extent of our globbing features--- (wildcards `*`, unions `{a,b,c}`, and directory-recursive wildcards `**`).---- ** Parsing globs in a cabal package--parseFileGlob :: CabalSpecVersion -> FilePath -> Either GlobSyntaxError Glob-parseFileGlob version filepath = case reverse (splitDirectories filepath) of- [] ->- Left EmptyGlob- (filename : "**" : segments)- | allowGlobStar -> do- finalSegment <- case splitExtensions filename of- ("*", ext)- | '*' `elem` ext -> Left StarInExtension- | null ext -> Left NoExtensionOnStar- | otherwise -> Right (GlobDirRecursive [WildCard, Literal ext])- _- | allowLiteralFilenameGlobStar ->- Right (GlobDirRecursive [Literal filename])- | otherwise ->- Left LiteralFileNameGlobStar-- foldM addStem finalSegment segments- | otherwise -> Left VersionDoesNotSupportGlobStar- (filename : segments) -> do- pat <- case splitExtensions filename of- ("*", ext)- | not allowGlob -> Left VersionDoesNotSupportGlob- | '*' `elem` ext -> Left StarInExtension- | null ext -> Left NoExtensionOnStar- | otherwise -> Right (GlobFile [WildCard, Literal ext])- (_, ext)- | '*' `elem` ext -> Left StarInExtension- | '*' `elem` filename -> Left StarInFileName- | otherwise -> Right (GlobFile [Literal filename])-- foldM addStem pat segments- where- addStem pat seg- | '*' `elem` seg = Left StarInDirectory- | otherwise = Right (GlobDir [Literal seg] pat)- allowGlob = version >= CabalSpecV1_6- allowGlobStar = version >= CabalSpecV2_4- allowLiteralFilenameGlobStar = version >= CabalSpecV3_8--enableMultidot :: CabalSpecVersion -> Bool-enableMultidot version- | version >= CabalSpecV2_4 = True- | otherwise = False---- ** Parsing globs otherwise+-- Parsing & pretty-printing instance Pretty Glob where pretty (GlobDir glob pathglob) =@@ -226,10 +107,6 @@ normal = P.satisfy (\c -> not (isGlobEscapedChar c) && c /= '/' && c /= '\\') escape = P.try $ P.char '\\' >> P.satisfy isGlobEscapedChar ------------------------------------------------------------------------------------ Parse and printing utils---------------------------------------------------------------------------------- dispGlobPieces :: GlobPieces -> Disp.Doc dispGlobPieces = Disp.hcat . map dispPiece where@@ -254,244 +131,3 @@ isGlobEscapedChar '}' = True isGlobEscapedChar ',' = True isGlobEscapedChar _ = False---- ** Cabal package globbing errors--data GlobSyntaxError- = StarInDirectory- | StarInFileName- | StarInExtension- | NoExtensionOnStar- | EmptyGlob- | LiteralFileNameGlobStar- | VersionDoesNotSupportGlobStar- | VersionDoesNotSupportGlob- deriving (Eq, Show)--explainGlobSyntaxError :: FilePath -> GlobSyntaxError -> String-explainGlobSyntaxError filepath StarInDirectory =- "invalid file glob '"- ++ filepath- ++ "'. A wildcard '**' is only allowed as the final parent"- ++ " directory. Stars must not otherwise appear in the parent"- ++ " directories."-explainGlobSyntaxError filepath StarInExtension =- "invalid file glob '"- ++ filepath- ++ "'. Wildcards '*' are only allowed as the"- ++ " file's base name, not in the file extension."-explainGlobSyntaxError filepath StarInFileName =- "invalid file glob '"- ++ filepath- ++ "'. Wildcards '*' may only totally replace the"- ++ " file's base name, not only parts of it."-explainGlobSyntaxError filepath NoExtensionOnStar =- "invalid file glob '"- ++ filepath- ++ "'. If a wildcard '*' is used it must be with an file extension."-explainGlobSyntaxError filepath LiteralFileNameGlobStar =- "invalid file glob '"- ++ filepath- ++ "'. Prior to 'cabal-version: 3.8'"- ++ " if a wildcard '**' is used as a parent directory, the"- ++ " file's base name must be a wildcard '*'."-explainGlobSyntaxError _ EmptyGlob =- "invalid file glob. A glob cannot be the empty string."-explainGlobSyntaxError filepath VersionDoesNotSupportGlobStar =- "invalid file glob '"- ++ filepath- ++ "'. Using the double-star syntax requires 'cabal-version: 2.4'"- ++ " or greater. Alternatively, for compatibility with earlier Cabal"- ++ " versions, list the included directories explicitly."-explainGlobSyntaxError filepath VersionDoesNotSupportGlob =- "invalid file glob '"- ++ filepath- ++ "'. Using star wildcards requires 'cabal-version: >= 1.6'. "- ++ "Alternatively if you require compatibility with earlier Cabal "- ++ "versions then list all the files explicitly."---- Note throughout that we use splitDirectories, not splitPath. On--- Posix, this makes no difference, but, because Windows accepts both--- slash and backslash as its path separators, if we left in the--- separators from the glob we might not end up properly normalised.--data GlobResult a- = -- | The glob matched the value supplied.- GlobMatch a- | -- | The glob did not match the value supplied because the- -- cabal-version is too low and the extensions on the file did- -- not precisely match the glob's extensions, but rather the- -- glob was a proper suffix of the file's extensions; i.e., if- -- not for the low cabal-version, it would have matched.- GlobWarnMultiDot a- | -- | The glob couldn't match because the directory named doesn't- -- exist. The directory will be as it appears in the glob (i.e.,- -- relative to the directory passed to 'matchDirFileGlob', and,- -- for 'data-files', relative to 'data-dir').- GlobMissingDirectory a- | -- | The glob matched a directory when we were looking for files only.- -- It didn't match a file!- --- -- @since 3.12.0.0- GlobMatchesDirectory a- deriving (Show, Eq, Ord, Functor)---- | Match files against a pre-parsed glob, starting in a directory.------ The 'Version' argument must be the spec version of the package--- description being processed, as globs behave slightly differently--- in different spec versions.------ The 'FilePath' argument is the directory that the glob is relative--- to. It must be a valid directory (and hence it can't be the empty--- string). The returned values will not include this prefix.-runDirFileGlob- :: Verbosity- -> Maybe CabalSpecVersion- -- ^ If the glob we are running should care about the cabal spec, and warnings such as 'GlobWarnMultiDot', then this should be the version.- -- If you want to run a glob but don't care about any of the cabal-spec restrictions on globs, use 'Nothing'!- -> FilePath- -> Glob- -> IO [GlobResult FilePath]-runDirFileGlob verbosity mspec rawRoot pat = do- -- The default data-dir is null. Our callers -should- be- -- converting that to '.' themselves, but it's a certainty that- -- some future call-site will forget and trigger a really- -- hard-to-debug failure if we don't check for that here.- when (null rawRoot) $- warn verbosity $- "Null dir passed to runDirFileGlob; interpreting it "- ++ "as '.'. This is probably an internal error."- let root = if null rawRoot then "." else rawRoot- debug verbosity $ "Expanding glob '" ++ show (pretty pat) ++ "' in directory '" ++ root ++ "'."- -- This function might be called from the project root with dir as- -- ".". Walking the tree starting there involves going into .git/- -- and dist-newstyle/, which is a lot of work for no reward, so- -- extract the constant prefix from the pattern and start walking- -- there, and only walk as much as we need to: recursively if **,- -- the whole directory if *, and just the specific file if it's a- -- literal.- let- (prefixSegments, variablePattern) = splitConstantPrefix pat- joinedPrefix = joinPath prefixSegments-- -- The glob matching function depends on whether we care about the cabal version or not- doesGlobMatch :: GlobPieces -> String -> Maybe (GlobResult ())- doesGlobMatch glob str = case mspec of- Just spec -> checkNameMatches spec glob str- Nothing -> if matchGlobPieces glob str then Just (GlobMatch ()) else Nothing-- go (GlobFile glob) dir = do- entries <- getDirectoryContents (root </> dir)- catMaybes- <$> mapM- ( \s -> do- -- When running a glob from a Cabal package description (i.e.- -- when a cabal spec version is passed as an argument), we- -- disallow matching a @GlobFile@ against a directory, preferring- -- @GlobDir dir GlobDirTrailing@ to specify a directory match.- isFile <- maybe (return True) (const $ doesFileExist (root </> dir </> s)) mspec- let match = (dir </> s <$) <$> doesGlobMatch glob s- return $- if isFile- then match- else case match of- Just (GlobMatch x) -> Just $ GlobMatchesDirectory x- Just (GlobWarnMultiDot x) -> Just $ GlobMatchesDirectory x- Just (GlobMatchesDirectory x) -> Just $ GlobMatchesDirectory x- Just (GlobMissingDirectory x) -> Just $ GlobMissingDirectory x -- this should never match, unless you are in a file-delete-heavy concurrent setting i guess- Nothing -> Nothing- )- entries- go (GlobDirRecursive glob) dir = do- entries <- getDirectoryContentsRecursive (root </> dir)- return $- mapMaybe- ( \s -> do- globMatch <- doesGlobMatch glob (takeFileName s)- pure ((dir </> s) <$ globMatch)- )- entries- go (GlobDir glob globPath) dir = do- entries <- getDirectoryContents (root </> dir)- subdirs <-- filterM- ( \subdir ->- doesDirectoryExist- (root </> dir </> subdir)- )- $ filter (matchGlobPieces glob) entries- concat <$> traverse (\subdir -> go globPath (dir </> subdir)) subdirs- go GlobDirTrailing dir = return [GlobMatch dir]-- directoryExists <- doesDirectoryExist (root </> joinedPrefix)- if directoryExists- then go variablePattern joinedPrefix- else return [GlobMissingDirectory joinedPrefix]- where- -- \| Extract the (possibly null) constant prefix from the pattern.- -- This has the property that, if @(pref, final) = splitConstantPrefix pat@,- -- then @pat === foldr GlobDir final pref@.- splitConstantPrefix :: Glob -> ([FilePath], Glob)- splitConstantPrefix = unfoldr' step- where- step (GlobDir [Literal seg] pat') = Right (seg, pat')- step pat' = Left pat'-- unfoldr' :: (a -> Either r (b, a)) -> a -> ([b], r)- unfoldr' f a = case f a of- Left r -> ([], r)- Right (b, a') -> case unfoldr' f a' of- (bs, r) -> (b : bs, r)---- | Is the root of this relative glob path a directory-recursive wildcard, e.g. @**/*.txt@ ?-isRecursiveInRoot :: Glob -> Bool-isRecursiveInRoot (GlobDirRecursive _) = True-isRecursiveInRoot _ = False---- | Check how the string matches the glob under this cabal version-checkNameMatches :: CabalSpecVersion -> GlobPieces -> String -> Maybe (GlobResult ())-checkNameMatches spec glob candidate- -- Check if glob matches in its general form- | matchGlobPieces glob candidate =- -- if multidot is supported, then this is a clean match- if enableMultidot spec- then pure (GlobMatch ())- else -- if not, issue a warning saying multidot is needed for the match-- let (_, candidateExts) = splitExtensions $ takeFileName candidate- extractExts :: GlobPieces -> Maybe String- extractExts [] = Nothing- extractExts [Literal lit]- -- Any literal terminating a glob, and which does have an extension,- -- returns that extension. Otherwise, recurse until Nothing is returned.- | let ext = takeExtensions lit- , ext /= "" =- Just ext- extractExts (_ : x) = extractExts x- in case extractExts glob of- Just exts- | exts == candidateExts ->- return (GlobMatch ())- | exts `isSuffixOf` candidateExts ->- return (GlobWarnMultiDot ())- _ -> return (GlobMatch ())- | otherwise = empty---- | How/does the glob match the given filepath, according to the cabal version?--- Since this is pure, we don't make a distinction between matching on--- directories or files (i.e. this function won't return 'GlobMatchesDirectory')-fileGlobMatches :: CabalSpecVersion -> Glob -> FilePath -> Maybe (GlobResult ())-fileGlobMatches version g path = go g (splitDirectories path)- where- go GlobDirTrailing [] = Just (GlobMatch ())- go (GlobFile glob) [file] = checkNameMatches version glob file- go (GlobDirRecursive glob) dirs- | [] <- reverse dirs =- Nothing -- @dir/**/x.txt@ should not match @dir/hello@- | file : _ <- reverse dirs =- checkNameMatches version glob file- go (GlobDir glob globPath) (dir : dirs) = do- _ <- checkNameMatches version glob dir -- we only care if dir segment matches- go globPath dirs- go _ _ = Nothing
src/Distribution/Simple/Haddock.hs view
@@ -1,1227 +1,1617 @@-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE RankNTypes #-}----------------------------------------------------------------------------------- |--- Module : Distribution.Simple.Haddock--- Copyright : Isaac Jones 2003-2005--- License : BSD3------ Maintainer : cabal-devel@haskell.org--- Portability : portable------ This module deals with the @haddock@ and @hscolour@ commands.--- It uses information about installed packages (from @ghc-pkg@) to find the--- locations of documentation for dependent packages, so it can create links.------ The @hscolour@ support allows generating HTML versions of the original--- source, with coloured syntax highlighting.-module Distribution.Simple.Haddock- ( haddock- , createHaddockIndex- , hscolour- , haddockPackagePaths- , Visibility (..)- ) where--import Distribution.Compat.Prelude-import Prelude ()--import qualified Distribution.Simple.GHC as GHC-import qualified Distribution.Simple.GHCJS as GHCJS---- local--import Distribution.Backpack (OpenModule)-import Distribution.Backpack.DescribeUnitId-import Distribution.InstalledPackageInfo (InstalledPackageInfo)-import qualified Distribution.InstalledPackageInfo as InstalledPackageInfo-import qualified Distribution.ModuleName as ModuleName-import Distribution.Package-import Distribution.PackageDescription-import Distribution.Parsec (simpleParsec)-import Distribution.Pretty-import Distribution.Simple.Build-import Distribution.Simple.BuildPaths-import Distribution.Simple.BuildTarget-import Distribution.Simple.Compiler-import Distribution.Simple.Flag-import Distribution.Simple.Glob (matchDirFileGlob)-import Distribution.Simple.InstallDirs-import Distribution.Simple.LocalBuildInfo hiding (substPathTemplate)-import qualified Distribution.Simple.PackageIndex as PackageIndex-import Distribution.Simple.PreProcess-import Distribution.Simple.Program-import Distribution.Simple.Program.GHC-import qualified Distribution.Simple.Program.HcPkg as HcPkg-import Distribution.Simple.Program.ResponseFile-import Distribution.Simple.Register-import Distribution.Simple.Setup.Haddock-import Distribution.Simple.Setup.Hscolour-import Distribution.Simple.Utils-import Distribution.System-import Distribution.Types.ComponentLocalBuildInfo-import Distribution.Types.ExposedModule-import Distribution.Types.LocalBuildInfo-import Distribution.Types.TargetInfo-import Distribution.Utils.NubList-import qualified Distribution.Utils.ShortText as ShortText-import Distribution.Version--import Distribution.Verbosity-import Language.Haskell.Extension--import Distribution.Compat.Semigroup (All (..), Any (..))--import Control.Monad-import Data.Either (rights)--import Distribution.Simple.Errors-import System.Directory (doesDirectoryExist, doesFileExist, getCurrentDirectory)-import System.FilePath (isAbsolute, normalise, (<.>), (</>))-import System.IO (hClose, hPutStrLn, hSetEncoding, utf8)---- --------------------------------------------------------------------------------- Types---- | A record that represents the arguments to the haddock executable, a product--- monoid.-data HaddockArgs = HaddockArgs- { 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).- , argLinkedSource :: Flag Bool- -- ^ Generate hyperlinked sources- , argQuickJump :: Flag Bool- -- ^ Generate quickjump index- , argCssFile :: Flag FilePath- -- ^ Optional custom CSS file.- , argContents :: Flag String- -- ^ Optional URL to contents page.- , argGenContents :: Flag Bool- -- ^ Generate contents- , argIndex :: Flag String- -- ^ Optional URL to index page.- , argGenIndex :: Flag Bool- -- ^ Generate index- , argBaseUrl :: Flag String- -- ^ Optional base url from which static files will be loaded.- , argVerbose :: Any- , argOutput :: Flag [Output]- -- ^ HTML or Hoogle doc or both? Required.- , argInterfaces :: [(FilePath, Maybe String, Maybe String, Visibility)]- -- ^ [(Interface file, URL to the HTML docs and hyperlinked-source for links)].- , argOutputDir :: Directory- -- ^ Where to generate the documentation.- , argTitle :: Flag String- -- ^ Page title, required.- , argPrologue :: Flag String- -- ^ Prologue text, required for 'haddock', ignored by 'haddocks'.- , argPrologueFile :: Flag FilePath- -- ^ Prologue file name, ignored by 'haddock', optional for 'haddocks'.- , argGhcOptions :: GhcOptions- -- ^ Additional flags to pass to GHC.- , argGhcLibDir :: Flag FilePath- -- ^ To find the correct GHC, required.- , argReexports :: [OpenModule]- -- ^ Re-exported modules- , argTargets :: [FilePath]- -- ^ Modules to process.- , argLib :: Flag String- -- ^ haddock's static \/ auxiliary files.- }- deriving (Generic)---- | The FilePath of a directory, it's a monoid under '(</>)'.-newtype Directory = Dir {unDir' :: FilePath} deriving (Read, Show, Eq, Ord)--unDir :: Directory -> FilePath-unDir = normalise . unDir'--type Template = String--data Output = Html | Hoogle- deriving (Eq)---- --------------------------------------------------------------------------------- Haddock support---- | Get Haddock program and check if it matches the request-getHaddockProg- :: Verbosity- -> ProgramDb- -> Compiler- -> HaddockArgs- -> Flag Bool- -- ^ quickjump feature- -> IO (ConfiguredProgram, Version)-getHaddockProg verbosity programDb comp args quickJumpFlag = do- let HaddockArgs- { argQuickJump- , argOutput- } = args- hoogle = Hoogle `elem` fromFlagOrDefault [] argOutput-- (haddockProg, version, _) <-- requireProgramVersion- verbosity- haddockProgram- (orLaterVersion (mkVersion [2, 0]))- programDb-- -- various sanity checks- when (hoogle && version < mkVersion [2, 2]) $- dieWithException verbosity NoSupportForHoogle-- when (fromFlag argQuickJump && version < mkVersion [2, 19]) $ do- let msg = "Haddock prior to 2.19 does not support the --quickjump flag."- alt = "The generated documentation won't have the QuickJump feature."- if Flag True == quickJumpFlag- then dieWithException verbosity NoSupportForQuickJumpFlag- else warn verbosity (msg ++ "\n" ++ alt)-- haddockGhcVersionStr <-- getProgramOutput- verbosity- haddockProg- ["--ghc-version"]- case (simpleParsec haddockGhcVersionStr, compilerCompatVersion GHC comp) of- (Nothing, _) -> dieWithException verbosity NoGHCVersionFromHaddock- (_, Nothing) -> dieWithException verbosity NoGHCVersionFromCompiler- (Just haddockGhcVersion, Just ghcVersion)- | haddockGhcVersion == ghcVersion -> return ()- | otherwise -> dieWithException verbosity $ HaddockAndGHCVersionDoesntMatch ghcVersion haddockGhcVersion-- return (haddockProg, version)--haddock- :: PackageDescription- -> LocalBuildInfo- -> [PPSuffixHandler]- -> HaddockFlags- -> IO ()-haddock pkg_descr _ _ haddockFlags- | not (hasLibs pkg_descr)- && not (fromFlag $ haddockExecutables haddockFlags)- && not (fromFlag $ haddockTestSuites haddockFlags)- && not (fromFlag $ haddockBenchmarks haddockFlags)- && not (fromFlag $ haddockForeignLibs haddockFlags) =- warn (fromFlag $ haddockVerbosity haddockFlags) $- "No documentation was generated as this package does not contain "- ++ "a library. Perhaps you want to use the --executables, --tests,"- ++ " --benchmarks or --foreign-libraries flags."-haddock pkg_descr lbi suffixes flags' = do- let verbosity = flag haddockVerbosity- comp = compiler lbi- platform = hostPlatform lbi-- quickJmpFlag = haddockQuickJump flags'- flags = case haddockTarget of- ForDevelopment -> flags'- ForHackage ->- flags'- { haddockHoogle = Flag True- , haddockHtml = Flag True- , haddockHtmlLocation = Flag (pkg_url ++ "/docs")- , haddockContents = Flag (toPathTemplate pkg_url)- , haddockLinkedSource = Flag True- , haddockQuickJump = Flag True- }- pkg_url = "/package/$pkg-$version"- flag f = fromFlag $ f flags-- tmpFileOpts =- defaultTempFileOptions- { optKeepTempFiles = flag haddockKeepTempFiles- }- htmlTemplate =- fmap toPathTemplate . flagToMaybe . haddockHtmlLocation $- flags- haddockTarget =- fromFlagOrDefault ForDevelopment (haddockForHackage flags')-- libdirArgs <- getGhcLibDir verbosity lbi- -- The haddock-output-dir flag overrides any other documentation placement concerns.- -- The point is to give the user full freedom over the location if they need it.- let overrideWithOutputDir args = case haddockOutputDir flags of- NoFlag -> args- Flag dir -> args{argOutputDir = Dir dir}- let commonArgs =- overrideWithOutputDir $- mconcat- [ libdirArgs- , fromFlags (haddockTemplateEnv lbi (packageId pkg_descr)) flags- , fromPackageDescription haddockTarget pkg_descr- ]-- (haddockProg, version) <-- getHaddockProg verbosity (withPrograms lbi) comp commonArgs quickJmpFlag-- -- We fall back to using HsColour only for versions of Haddock which don't- -- support '--hyperlinked-sources'.- let using_hscolour = flag haddockLinkedSource && version < mkVersion [2, 17]- when using_hscolour $- hscolour'- (warn verbosity)- haddockTarget- pkg_descr- lbi- suffixes- (defaultHscolourFlags `mappend` haddockToHscolour flags)-- targets <- readTargetInfos verbosity pkg_descr lbi (haddockArgs flags)-- let- targets' =- case targets of- [] -> allTargetsInBuildOrder' pkg_descr lbi- _ -> targets-- internalPackageDB <-- createInternalPackageDB verbosity lbi (flag haddockDistPref)-- (\f -> foldM_ f (installedPkgs lbi) targets') $ \index target -> do- let component = targetComponent target- clbi = targetCLBI target-- preBuildComponent verbosity lbi target-- let- lbi' =- lbi- { withPackageDB = withPackageDB lbi ++ [internalPackageDB]- , installedPkgs = index- }-- preprocessComponent pkg_descr component lbi' clbi False verbosity suffixes- let- doExe com = case (compToExe com) of- Just exe -> do- withTempDirectoryEx verbosity tmpFileOpts (buildDir lbi') "tmp" $- \tmp -> do- exeArgs <-- fromExecutable- verbosity- tmp- lbi'- clbi- htmlTemplate- version- exe- let exeArgs' = commonArgs `mappend` exeArgs- runHaddock- verbosity- tmpFileOpts- comp- platform- haddockProg- True- exeArgs'- Nothing -> do- warn- (fromFlag $ haddockVerbosity flags)- "Unsupported component, skipping..."- return ()- -- We define 'smsg' once and then reuse it inside the case, so that- -- we don't say we are running Haddock when we actually aren't- -- (e.g., Haddock is not run on non-libraries)- smsg :: IO ()- smsg =- setupMessage'- verbosity- "Running Haddock on"- (packageId pkg_descr)- (componentLocalName clbi)- (maybeComponentInstantiatedWith clbi)- case component of- CLib lib -> do- withTempDirectoryEx verbosity tmpFileOpts (buildDir lbi) "tmp" $- \tmp -> do- smsg- libArgs <-- fromLibrary- verbosity- tmp- lbi'- clbi- htmlTemplate- version- lib- let libArgs' = commonArgs `mappend` libArgs- runHaddock verbosity tmpFileOpts comp platform haddockProg True libArgs'-- pwd <- getCurrentDirectory-- let- ipi =- inplaceInstalledPackageInfo- pwd- (flag haddockDistPref)- pkg_descr- (mkAbiHash "inplace")- lib- lbi'- clbi-- debug verbosity $- "Registering inplace:\n"- ++ (InstalledPackageInfo.showInstalledPackageInfo ipi)-- registerPackage- verbosity- (compiler lbi')- (withPrograms lbi')- (withPackageDB lbi')- ipi- HcPkg.defaultRegisterOptions- { HcPkg.registerMultiInstance = True- }-- return $ PackageIndex.insert ipi index- CFLib flib ->- when- (flag haddockForeignLibs)- ( do- withTempDirectoryEx verbosity tmpFileOpts (buildDir lbi') "tmp" $- \tmp -> do- smsg- flibArgs <-- fromForeignLib- verbosity- tmp- lbi'- clbi- htmlTemplate- version- flib- let libArgs' = commonArgs `mappend` flibArgs- runHaddock verbosity tmpFileOpts comp platform haddockProg True libArgs'- )- >> return index- CExe _ -> when (flag haddockExecutables) (smsg >> doExe component) >> return index- CTest _ -> when (flag haddockTestSuites) (smsg >> doExe component) >> return index- CBench _ -> when (flag haddockBenchmarks) (smsg >> doExe component) >> return index-- for_ (extraDocFiles pkg_descr) $ \fpath -> do- files <- matchDirFileGlob verbosity (specVersion pkg_descr) "." fpath- for_ files $ copyFileTo verbosity (unDir $ argOutputDir commonArgs)---- | Execute 'Haddock' configured with 'HaddocksFlags'. It is used to build--- index and contents for documentation of multiple packages.-createHaddockIndex- :: Verbosity- -> ProgramDb- -> Compiler- -> Platform- -> HaddockProjectFlags- -> IO ()-createHaddockIndex verbosity programDb comp platform flags = do- let args = fromHaddockProjectFlags flags- (haddockProg, _version) <-- getHaddockProg verbosity programDb comp args (Flag True)- runHaddock verbosity defaultTempFileOptions comp platform haddockProg False args---- --------------------------------------------------------------------------------- Contributions to HaddockArgs (see also Doctest.hs for very similar code).--fromFlags :: PathTemplateEnv -> HaddockFlags -> HaddockArgs-fromFlags env flags =- mempty- { argHideModules =- ( maybe mempty (All . not) $- flagToMaybe (haddockInternal flags)- , mempty- )- , argLinkSource =- if fromFlag (haddockLinkedSource flags)- then- Flag- ( "src/%{MODULE/./-}.html"- , "src/%{MODULE/./-}.html#%{NAME}"- , "src/%{MODULE/./-}.html#line-%{LINE}"- )- else NoFlag- , argLinkedSource = haddockLinkedSource flags- , argQuickJump = haddockQuickJump flags- , argCssFile = haddockCss flags- , argContents =- fmap- (fromPathTemplate . substPathTemplate env)- (haddockContents flags)- , argGenContents = Flag False- , argIndex =- fmap- (fromPathTemplate . substPathTemplate env)- (haddockIndex flags)- , argGenIndex = Flag False- , argBaseUrl = haddockBaseUrl flags- , argLib = haddockLib flags- , argVerbose =- maybe mempty (Any . (>= deafening))- . flagToMaybe- $ haddockVerbosity flags- , argOutput =- Flag $ case [Html | Flag True <- [haddockHtml flags]]- ++ [Hoogle | Flag True <- [haddockHoogle flags]] of- [] -> [Html]- os -> os- , argOutputDir = maybe mempty Dir . flagToMaybe $ haddockDistPref flags- , argGhcOptions = mempty{ghcOptExtra = ghcArgs}- }- where- ghcArgs = fromMaybe [] . lookup "ghc" . haddockProgramArgs $ flags--fromHaddockProjectFlags :: HaddockProjectFlags -> HaddockArgs-fromHaddockProjectFlags flags =- mempty- { argOutputDir = Dir (fromFlag $ haddockProjectDir flags)- , argQuickJump = Flag True- , argGenContents = Flag True- , argGenIndex = Flag True- , argPrologueFile = haddockProjectPrologue flags- , argInterfaces = fromFlagOrDefault [] (haddockProjectInterfaces flags)- , argLinkedSource = Flag True- , argLib = haddockProjectLib flags- }--fromPackageDescription :: HaddockTarget -> PackageDescription -> HaddockArgs-fromPackageDescription haddockTarget pkg_descr =- mempty- { argInterfaceFile = Flag $ haddockName pkg_descr- , argPackageName = Flag $ packageId $ pkg_descr- , argOutputDir =- Dir $- "doc" </> "html" </> haddockDirName haddockTarget pkg_descr- , argPrologue =- Flag $- ShortText.fromShortText $- if ShortText.null desc- then synopsis pkg_descr- else desc- , argTitle = Flag $ showPkg ++ subtitle- }- where- desc = description pkg_descr- showPkg = prettyShow (packageId pkg_descr)- subtitle- | ShortText.null (synopsis pkg_descr) = ""- | otherwise = ": " ++ ShortText.fromShortText (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--mkHaddockArgs- :: Verbosity- -> FilePath- -> LocalBuildInfo- -> ComponentLocalBuildInfo- -> Maybe PathTemplate- -- ^ template for HTML location- -> Version- -> [FilePath]- -> BuildInfo- -> IO HaddockArgs-mkHaddockArgs verbosity tmp lbi clbi htmlTemplate haddockVersion inFiles bi = do- ifaceArgs <- getInterfaces verbosity lbi clbi htmlTemplate- let vanillaOpts =- (componentGhcOptions normal lbi bi clbi (buildDir lbi))- { -- Noooooooooo!!!!!111- -- haddock stomps on our precious .hi- -- and .o files. Workaround by telling- -- haddock to write them elsewhere.- ghcOptObjDir = toFlag tmp- , ghcOptHiDir = toFlag tmp- , ghcOptStubDir = toFlag tmp- }- `mappend` getGhcCppOpts haddockVersion bi- sharedOpts =- vanillaOpts- { ghcOptDynLinkMode = toFlag GhcDynamicOnly- , ghcOptFPic = toFlag True- , ghcOptHiSuffix = toFlag "dyn_hi"- , ghcOptObjSuffix = toFlag "dyn_o"- , ghcOptExtra = hcSharedOptions GHC bi- }- opts <-- if withVanillaLib lbi- then return vanillaOpts- else- if withSharedLib lbi- then return sharedOpts- else dieWithException verbosity MustHaveSharedLibraries-- return- ifaceArgs- { argGhcOptions = opts- , argTargets = inFiles- , argReexports = getReexports clbi- }--fromLibrary- :: Verbosity- -> FilePath- -> LocalBuildInfo- -> ComponentLocalBuildInfo- -> Maybe PathTemplate- -- ^ template for HTML location- -> Version- -> Library- -> IO HaddockArgs-fromLibrary verbosity tmp lbi clbi htmlTemplate haddockVersion lib = do- inFiles <- map snd `fmap` getLibSourceFiles verbosity lbi lib clbi- args <-- mkHaddockArgs- verbosity- tmp- lbi- clbi- htmlTemplate- haddockVersion- inFiles- (libBuildInfo lib)- return- args- { argHideModules = (mempty, otherModules (libBuildInfo lib))- }--fromExecutable- :: Verbosity- -> FilePath- -> LocalBuildInfo- -> ComponentLocalBuildInfo- -> Maybe PathTemplate- -- ^ template for HTML location- -> Version- -> Executable- -> IO HaddockArgs-fromExecutable verbosity tmp lbi clbi htmlTemplate haddockVersion exe = do- inFiles <- map snd `fmap` getExeSourceFiles verbosity lbi exe clbi- args <-- mkHaddockArgs- verbosity- tmp- lbi- clbi- htmlTemplate- haddockVersion- inFiles- (buildInfo exe)- return- args- { argOutputDir = Dir $ unUnqualComponentName $ exeName exe- , argTitle = Flag $ unUnqualComponentName $ exeName exe- }--fromForeignLib- :: Verbosity- -> FilePath- -> LocalBuildInfo- -> ComponentLocalBuildInfo- -> Maybe PathTemplate- -- ^ template for HTML location- -> Version- -> ForeignLib- -> IO HaddockArgs-fromForeignLib verbosity tmp lbi clbi htmlTemplate haddockVersion flib = do- inFiles <- map snd `fmap` getFLibSourceFiles verbosity lbi flib clbi- args <-- mkHaddockArgs- verbosity- tmp- lbi- clbi- htmlTemplate- haddockVersion- inFiles- (foreignLibBuildInfo flib)- return- args- { argOutputDir = Dir $ unUnqualComponentName $ foreignLibName flib- , argTitle = Flag $ unUnqualComponentName $ foreignLibName flib- }--compToExe :: Component -> Maybe Executable-compToExe comp =- case comp of- CTest test@TestSuite{testInterface = TestSuiteExeV10 _ f} ->- Just- Executable- { exeName = testName test- , modulePath = f- , exeScope = ExecutablePublic- , buildInfo = testBuildInfo test- }- CBench bench@Benchmark{benchmarkInterface = BenchmarkExeV10 _ f} ->- Just- Executable- { exeName = benchmarkName bench- , modulePath = f- , exeScope = ExecutablePublic- , buildInfo = benchmarkBuildInfo bench- }- CExe exe -> Just exe- _ -> Nothing--getInterfaces- :: Verbosity- -> LocalBuildInfo- -> ComponentLocalBuildInfo- -> Maybe PathTemplate- -- ^ template for HTML location- -> IO HaddockArgs-getInterfaces verbosity lbi clbi htmlTemplate = do- (packageFlags, warnings) <- haddockPackageFlags verbosity lbi clbi htmlTemplate- traverse_ (warn (verboseUnmarkOutput verbosity)) warnings- return $- mempty- { argInterfaces = packageFlags- }--getReexports :: ComponentLocalBuildInfo -> [OpenModule]-getReexports LibComponentLocalBuildInfo{componentExposedModules = mods} =- mapMaybe exposedReexport mods-getReexports _ = []--getGhcCppOpts- :: Version- -> BuildInfo- -> GhcOptions-getGhcCppOpts haddockVersion bi =- mempty- { ghcOptExtensions = toNubListR [EnableExtension CPP | needsCpp]- , ghcOptCppOptions = defines- }- where- needsCpp = EnableExtension CPP `elem` usedExtensions bi- defines = [haddockVersionMacro]- haddockVersionMacro =- "-D__HADDOCK_VERSION__="- ++ show (v1 * 1000 + v2 * 10 + v3)- where- (v1, v2, v3) = case versionNumbers haddockVersion of- [] -> (0, 0, 0)- [x] -> (x, 0, 0)- [x, y] -> (x, y, 0)- (x : y : z : _) -> (x, y, z)--getGhcLibDir- :: Verbosity- -> LocalBuildInfo- -> IO HaddockArgs-getGhcLibDir verbosity lbi = do- 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}---- ---------------------------------------------------------------------------------- | Call haddock with the specified arguments.-runHaddock- :: Verbosity- -> TempFileOptions- -> Compiler- -> Platform- -> ConfiguredProgram- -> Bool- -- ^ require targets- -> HaddockArgs- -> IO ()-runHaddock verbosity tmpFileOpts comp platform haddockProg requireTargets args- | requireTargets && null (argTargets args) =- warn verbosity $- "Haddocks are being requested, but there aren't any modules given "- ++ "to create documentation for."- | otherwise = do- let haddockVersion =- fromMaybe- (error "unable to determine haddock version")- (programVersion haddockProg)- renderArgs verbosity tmpFileOpts haddockVersion comp platform args $- \(flags, result) -> do- runProgram verbosity haddockProg flags-- notice verbosity $ "Documentation created: " ++ result--renderArgs- :: Verbosity- -> TempFileOptions- -> Version- -> Compiler- -> Platform- -> HaddockArgs- -> (([String], FilePath) -> IO a)- -> IO a-renderArgs verbosity tmpFileOpts version comp platform args k = do- let haddockSupportsUTF8 = version >= mkVersion [2, 14, 4]- haddockSupportsResponseFiles = version > mkVersion [2, 16, 2]- createDirectoryIfMissingVerbose verbosity True outputDir- case argPrologue args of- Flag prologueText ->- withTempFileEx tmpFileOpts outputDir "haddock-prologue.txt" $- \prologueFileName h -> do- do- when haddockSupportsUTF8 (hSetEncoding h utf8)- hPutStrLn h prologueText- hClose h- let pflag = "--prologue=" ++ prologueFileName- renderedArgs = pflag : renderPureArgs version comp platform args- if haddockSupportsResponseFiles- then- withResponseFile- verbosity- tmpFileOpts- outputDir- "haddock-response.txt"- (if haddockSupportsUTF8 then Just utf8 else Nothing)- renderedArgs- (\responseFileName -> k (["@" ++ responseFileName], result))- else k (renderedArgs, result)- _ -> do- let renderedArgs =- ( case argPrologueFile args of- Flag pfile -> ["--prologue=" ++ pfile]- _ -> []- )- <> renderPureArgs version comp platform args- if haddockSupportsResponseFiles- then- withResponseFile- verbosity- tmpFileOpts- outputDir- "haddock-response.txt"- (if haddockSupportsUTF8 then Just utf8 else Nothing)- renderedArgs- (\responseFileName -> k (["@" ++ responseFileName], result))- else k (renderedArgs, result)- where- outputDir = (unDir $ argOutputDir args)- isNotArgContents = isNothing (flagToMaybe $ argContents args)- isNotArgIndex = isNothing (flagToMaybe $ argIndex args)- isArgGenIndex = fromFlagOrDefault False (argGenIndex args)- -- Haddock, when generating HTML, does not generate an index if the options- -- --use-contents or --use-index are passed to it. See- -- https://haskell-haddock.readthedocs.io/en/latest/invoking.html#cmdoption-use-contents- isIndexGenerated = isArgGenIndex && isNotArgContents && isNotArgIndex- result =- intercalate ", "- . map- ( \o ->- outputDir- </> case o of- Html- | isIndexGenerated ->- "index.html"- Html- | otherwise ->- mempty- Hoogle -> pkgstr <.> "txt"- )- . fromFlagOrDefault [Html]- . argOutput- $ args- where- pkgstr = prettyShow $ packageName pkgid- pkgid = arg argPackageName- arg f = fromFlag $ f args--renderPureArgs :: Version -> Compiler -> Platform -> HaddockArgs -> [String]-renderPureArgs version comp platform args =- concat- [ map (\f -> "--dump-interface=" ++ unDir (argOutputDir args) </> f)- . flagToList- . argInterfaceFile- $ args- , if haddockSupportsPackageName- then- maybe- []- ( \pkg ->- [ "--package-name=" ++ prettyShow (pkgName pkg)- , "--package-version=" ++ prettyShow (pkgVersion pkg)- ]- )- . flagToMaybe- . argPackageName- $ args- else []- , ["--since-qual=external" | isVersion 2 20]- , [ "--quickjump" | isVersion 2 19, True <- flagToList . argQuickJump $ args- ]- , ["--hyperlinked-source" | isHyperlinkedSource]- , (\(All b, xs) -> bool (map (("--hide=" ++) . prettyShow) xs) [] b)- . argHideModules- $ args- , bool ["--ignore-all-exports"] [] . getAny . argIgnoreExports $ args- , -- Haddock's --source-* options are ignored once --hyperlinked-source is- -- set.- -- See https://haskell-haddock.readthedocs.io/en/latest/invoking.html#cmdoption-hyperlinked-source- -- To avoid Haddock's warning, we only set --source-* options if- -- --hyperlinked-source is not set.- if isHyperlinkedSource- then []- else- maybe- []- ( \(m, e, l) ->- [ "--source-module=" ++ m- , "--source-entity=" ++ e- ]- ++ if isVersion 2 14- then ["--source-entity-line=" ++ l]- else []- )- . flagToMaybe- . argLinkSource- $ args- , maybe [] ((: []) . ("--css=" ++)) . flagToMaybe . argCssFile $ args- , maybe [] ((: []) . ("--use-contents=" ++)) . flagToMaybe . argContents $ args- , bool ["--gen-contents"] [] . fromFlagOrDefault False . argGenContents $ args- , maybe [] ((: []) . ("--use-index=" ++)) . flagToMaybe . argIndex $ args- , bool ["--gen-index"] [] . fromFlagOrDefault False . argGenIndex $ args- , maybe [] ((: []) . ("--base-url=" ++)) . flagToMaybe . argBaseUrl $ args- , bool [] [verbosityFlag] . getAny . argVerbose $ args- , map (\o -> case o of Hoogle -> "--hoogle"; Html -> "--html")- . fromFlagOrDefault []- . argOutput- $ args- , renderInterfaces . argInterfaces $ args- , (: []) . ("--odir=" ++) . unDir . argOutputDir $ args- , maybe- []- ( (: [])- . ("--title=" ++)- . ( bool- (++ " (internal documentation)")- id- (getAny $ argIgnoreExports args)- )- )- . flagToMaybe- . argTitle- $ args- , [ "--optghc=" ++ opt | let opts = argGhcOptions args, opt <- renderGhcOptions comp platform opts- ]- , maybe [] (\l -> ["-B" ++ l]) $- flagToMaybe (argGhcLibDir args) -- error if Nothing?- , -- https://github.com/haskell/haddock/pull/547- [ "--reexport=" ++ prettyShow r- | r <- argReexports args- , isVersion 2 19- ]- , argTargets $ args- , maybe [] ((: []) . ("--lib=" ++)) . flagToMaybe . argLib $ args- ]- where- renderInterfaces = map renderInterface-- renderInterface :: (FilePath, Maybe FilePath, Maybe FilePath, Visibility) -> String- renderInterface (i, html, hypsrc, visibility) =- "--read-interface="- ++ intercalate- ","- ( concat- [ [fromMaybe "" html]- , -- only render hypsrc path if html path- -- is given and hyperlinked-source is- -- enabled-- [ case (html, hypsrc) of- (Nothing, _) -> ""- (_, Nothing) -> ""- (_, Just x)- | isVersion 2 17- , fromFlagOrDefault False . argLinkedSource $ args ->- x- | otherwise ->- ""- ]- , if haddockSupportsVisibility- then- [ case visibility of- Visible -> "visible"- Hidden -> "hidden"- ]- else []- , [i]- ]- )-- bool a b c = if c then a else b- isVersion major minor = version >= mkVersion [major, minor]- verbosityFlag- | isVersion 2 5 = "--verbosity=1"- | otherwise = "--verbose"- haddockSupportsVisibility = version >= mkVersion [2, 26, 1]- haddockSupportsPackageName = version > mkVersion [2, 16]- haddockSupportsHyperlinkedSource = isVersion 2 17- isHyperlinkedSource =- haddockSupportsHyperlinkedSource- && fromFlagOrDefault False (argLinkedSource args)--------------------------------------------------------------------------------------- | Given a list of 'InstalledPackageInfo's, return a list of interfaces and--- HTML paths, and an optional warning for packages with missing documentation.-haddockPackagePaths- :: [InstalledPackageInfo]- -> Maybe (InstalledPackageInfo -> FilePath)- -> IO- ( [ ( FilePath -- path to interface- -- file- , Maybe FilePath -- url to html- -- documentation- , Maybe FilePath -- url to hyperlinked- -- source- , Visibility- )- ]- , Maybe String -- warning about- -- missing documentation- )-haddockPackagePaths ipkgs mkHtmlPath = do- interfaces <-- sequenceA- [ case interfaceAndHtmlPath ipkg of- Nothing -> return (Left (packageId ipkg))- Just (interface, html) -> do- (html', hypsrc') <-- case html of- Just htmlPath -> do- let hypSrcPath = htmlPath </> defaultHyperlinkedSourceDirectory- hypSrcExists <- doesDirectoryExist hypSrcPath- return $- ( Just (fixFileUrl htmlPath)- , if hypSrcExists- then Just (fixFileUrl hypSrcPath)- else Nothing- )- Nothing -> return (Nothing, Nothing)-- exists <- doesFileExist interface- if exists- then return (Right (interface, html', hypsrc', Visible))- else return (Left pkgid)- | ipkg <- ipkgs- , let pkgid = packageId ipkg- , pkgName pkgid `notElem` noHaddockWhitelist- ]-- let missing = [pkgid | Left pkgid <- interfaces]- warning =- "The documentation for the following packages are not "- ++ "installed. No links will be generated to these packages: "- ++ intercalate ", " (map prettyShow missing)- flags = rights interfaces-- return (flags, if null missing then Nothing else Just warning)- where- -- Don't warn about missing documentation for these packages. See #1231.- noHaddockWhitelist = map mkPackageName ["rts"]-- -- Actually extract interface and HTML paths from an 'InstalledPackageInfo'.- interfaceAndHtmlPath- :: InstalledPackageInfo- -> Maybe (FilePath, Maybe FilePath)- interfaceAndHtmlPath pkg = do- interface <- listToMaybe (InstalledPackageInfo.haddockInterfaces pkg)- html <- case mkHtmlPath of- Nothing -> listToMaybe (InstalledPackageInfo.haddockHTMLs pkg)- Just mkPath -> Just (mkPath pkg)- return (interface, if null html then Nothing else Just html)-- -- The 'haddock-html' field in the hc-pkg output is often set as a- -- native path, but we need it as a URL. See #1064. Also don't "fix"- -- the path if it is an interpolated one.- fixFileUrl f- | Nothing <- mkHtmlPath- , isAbsolute f =- "file://" ++ f- | otherwise = f-- -- 'src' is the default hyperlinked source directory ever since. It is- -- not possible to configure that directory in any way in haddock.- defaultHyperlinkedSourceDirectory = "src"--haddockPackageFlags- :: Verbosity- -> LocalBuildInfo- -> ComponentLocalBuildInfo- -> Maybe PathTemplate- -> IO- ( [ ( FilePath -- path to interface- -- file- , Maybe FilePath -- url to html- -- documentation- , Maybe FilePath -- url to hyperlinked- -- source- , Visibility- )- ]- , Maybe String -- warning about- -- missing documentation- )-haddockPackageFlags verbosity lbi clbi htmlTemplate = do- let allPkgs = installedPkgs lbi- directDeps = map fst (componentPackageDeps clbi)- transitiveDeps <- case PackageIndex.dependencyClosure allPkgs directDeps of- Left x -> return x- Right inf ->- dieWithException verbosity $ HaddockPackageFlags inf-- haddockPackagePaths (PackageIndex.allPackages transitiveDeps) mkHtmlPath- where- mkHtmlPath = fmap expandTemplateVars htmlTemplate- expandTemplateVars tmpl pkg =- fromPathTemplate . substPathTemplate (env pkg) $ tmpl- env pkg = haddockTemplateEnv lbi (packageId pkg)--haddockTemplateEnv :: LocalBuildInfo -> PackageIdentifier -> PathTemplateEnv-haddockTemplateEnv lbi pkg_id =- (PrefixVar, prefix (installDirTemplates lbi))- -- We want the legacy unit ID here, because it gives us nice paths- -- (Haddock people don't care about the dependencies)- : initialPathTemplateEnv- pkg_id- (mkLegacyUnitId pkg_id)- (compilerInfo (compiler lbi))- (hostPlatform lbi)---- --------------------------------------------------------------------------------- hscolour support.--hscolour- :: PackageDescription- -> LocalBuildInfo- -> [PPSuffixHandler]- -> HscolourFlags- -> IO ()-hscolour = hscolour' dieNoVerbosity ForDevelopment--hscolour'- :: (String -> IO ())- -- ^ Called when the 'hscolour' exe is not found.- -> HaddockTarget- -> PackageDescription- -> LocalBuildInfo- -> [PPSuffixHandler]- -> HscolourFlags- -> IO ()-hscolour' onNoHsColour haddockTarget pkg_descr lbi suffixes flags =- either (\excep -> onNoHsColour $ exceptionMessage excep) (\(hscolourProg, _, _) -> go hscolourProg)- =<< lookupProgramVersion- verbosity- hscolourProgram- (orLaterVersion (mkVersion [1, 8]))- (withPrograms lbi)- where- go :: ConfiguredProgram -> IO ()- go hscolourProg = do- warn verbosity $- "the 'cabal hscolour' command is deprecated in favour of 'cabal "- ++ "haddock --hyperlink-source' and will be removed in the next major "- ++ "release."-- setupMessage verbosity "Running hscolour for" (packageId pkg_descr)- createDirectoryIfMissingVerbose verbosity True $- hscolourPref haddockTarget distPref pkg_descr-- withAllComponentsInBuildOrder pkg_descr lbi $ \comp clbi -> do- let tgt = TargetInfo clbi comp- preBuildComponent verbosity lbi tgt- preprocessComponent pkg_descr comp lbi clbi False verbosity suffixes- let- doExe com = case (compToExe com) of- Just exe -> do- let outputDir =- hscolourPref haddockTarget distPref pkg_descr- </> unUnqualComponentName (exeName exe)- </> "src"- runHsColour hscolourProg outputDir =<< getExeSourceFiles verbosity lbi exe clbi- Nothing -> do- warn- (fromFlag $ hscolourVerbosity flags)- "Unsupported component, skipping..."- return ()- case comp of- CLib lib -> do- let outputDir = hscolourPref haddockTarget distPref pkg_descr </> "src"- runHsColour hscolourProg outputDir =<< getLibSourceFiles verbosity lbi lib clbi- CFLib flib -> do- let outputDir =- hscolourPref haddockTarget distPref pkg_descr- </> unUnqualComponentName (foreignLibName flib)- </> "src"- runHsColour hscolourProg outputDir =<< getFLibSourceFiles verbosity lbi flib clbi- CExe _ -> when (fromFlag (hscolourExecutables flags)) $ doExe comp- CTest _ -> when (fromFlag (hscolourTestSuites flags)) $ doExe comp- CBench _ -> when (fromFlag (hscolourBenchmarks flags)) $ doExe comp-- stylesheet = flagToMaybe (hscolourCSS flags)-- verbosity = fromFlag (hscolourVerbosity flags)- distPref = fromFlag (hscolourDistPref flags)-- runHsColour prog outputDir moduleFiles = do- createDirectoryIfMissingVerbose verbosity True outputDir-- case stylesheet of -- copy the CSS file- Nothing- | programVersion prog >= Just (mkVersion [1, 9]) ->- runProgram- verbosity- prog- ["-print-css", "-o" ++ outputDir </> "hscolour.css"]- | otherwise -> return ()- Just s -> copyFileVerbose verbosity s (outputDir </> "hscolour.css")-- for_ moduleFiles $ \(m, inFile) ->- runProgram- verbosity- prog- ["-css", "-anchor", "-o" ++ outFile m, inFile]- where- outFile m =- outputDir- </> intercalate "-" (ModuleName.components m) <.> "html"--haddockToHscolour :: HaddockFlags -> HscolourFlags-haddockToHscolour flags =- HscolourFlags- { hscolourCSS = haddockHscolourCss flags- , hscolourExecutables = haddockExecutables flags- , hscolourTestSuites = haddockTestSuites flags- , hscolourBenchmarks = haddockBenchmarks flags- , hscolourForeignLibs = haddockForeignLibs flags- , hscolourVerbosity = haddockVerbosity flags- , hscolourDistPref = haddockDistPref flags- , hscolourCabalFilePath = haddockCabalFilePath flags+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}++-----------------------------------------------------------------------------++-- |+-- Module : Distribution.Simple.Haddock+-- Copyright : Isaac Jones 2003-2005+-- License : BSD3+--+-- Maintainer : cabal-devel@haskell.org+-- Portability : portable+--+-- This module deals with the @haddock@ and @hscolour@ commands.+-- It uses information about installed packages (from @ghc-pkg@) to find the+-- locations of documentation for dependent packages, so it can create links.+--+-- The @hscolour@ support allows generating HTML versions of the original+-- source, with coloured syntax highlighting.+module Distribution.Simple.Haddock+ ( haddock+ , haddock_setupHooks+ , createHaddockIndex+ , hscolour+ , hscolour_setupHooks+ , haddockPackagePaths+ , Visibility (..)+ ) where++import Distribution.Compat.Prelude+import Prelude ()++import qualified Distribution.Simple.GHC as GHC+import qualified Distribution.Simple.GHCJS as GHCJS++-- local++import Distribution.Backpack (OpenModule)+import Distribution.Backpack.DescribeUnitId+import Distribution.Compat.Semigroup (All (..), Any (..))+import Distribution.InstalledPackageInfo (InstalledPackageInfo)+import qualified Distribution.InstalledPackageInfo as InstalledPackageInfo+import qualified Distribution.ModuleName as ModuleName+import Distribution.Package+import Distribution.PackageDescription+import Distribution.Parsec (simpleParsec)+import Distribution.Pretty+import Distribution.Simple.Build+import Distribution.Simple.BuildPaths+import Distribution.Simple.BuildTarget+import Distribution.Simple.Compiler+import Distribution.Simple.Errors+import Distribution.Simple.Flag+import Distribution.Simple.Glob (matchDirFileGlob)+import Distribution.Simple.InstallDirs+import Distribution.Simple.LocalBuildInfo hiding (substPathTemplate)+import qualified Distribution.Simple.PackageIndex as PackageIndex+import Distribution.Simple.PreProcess+import Distribution.Simple.Program+import Distribution.Simple.Program.GHC+import qualified Distribution.Simple.Program.HcPkg as HcPkg+import Distribution.Simple.Program.ResponseFile+import Distribution.Simple.Register+import Distribution.Simple.Setup.Common+import Distribution.Simple.Setup.Haddock+import Distribution.Simple.Setup.Hscolour+import Distribution.Simple.SetupHooks.Internal+ ( BuildHooks (..)+ , BuildingWhat (..)+ , noBuildHooks+ )+import qualified Distribution.Simple.SetupHooks.Internal as SetupHooks+import qualified Distribution.Simple.SetupHooks.Rule as SetupHooks+import Distribution.Simple.Utils+import Distribution.System+import Distribution.Types.ComponentLocalBuildInfo+import Distribution.Types.ExposedModule+import Distribution.Types.LocalBuildInfo+import Distribution.Types.TargetInfo+import Distribution.Utils.Path hiding+ ( Dir+ )+import qualified Distribution.Utils.Path as Path+import qualified Distribution.Utils.ShortText as ShortText+import Distribution.Verbosity+import Distribution.Version++import Control.Monad+import Data.Bool (bool)+import Data.Either (rights)+import System.Directory (doesDirectoryExist, doesFileExist)+import System.FilePath (isAbsolute, normalise)+import System.IO (hClose, hPutStrLn, hSetEncoding, utf8)++-- ------------------------------------------------------------------------------+-- Types++-- | A record that represents the arguments to the haddock executable, a product+-- monoid.+data HaddockArgs = HaddockArgs+ { argInterfaceFile :: Flag FilePath+ -- ^ Path to the interface file, relative to argOutputDir, required.+ , argPackageName :: Flag PackageIdentifier+ -- ^ Package name, required.+ , argComponentName :: Flag String+ -- ^ Optional name used to construct haddock's `--package-name` option for+ -- various components (tests suites, sublibriaries, etc).+ , 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).+ , argLinkedSource :: Flag Bool+ -- ^ Generate hyperlinked sources+ , argQuickJump :: Flag Bool+ -- ^ Generate quickjump index+ , argCssFile :: Flag FilePath+ -- ^ Optional custom CSS file.+ , argContents :: Flag String+ -- ^ Optional URL to contents page.+ , argGenContents :: Flag Bool+ -- ^ Generate contents+ , argIndex :: Flag String+ -- ^ Optional URL to index page.+ , argGenIndex :: Flag Bool+ -- ^ Generate index+ , argBaseUrl :: Flag String+ -- ^ Optional base url from which static files will be loaded.+ , argVerbose :: Any+ , argOutput :: Flag [Output]+ -- ^ HTML or Hoogle doc or both? Required.+ , argInterfaces :: [(FilePath, Maybe String, Maybe String, Visibility)]+ -- ^ [(Interface file, URL to the HTML docs and hyperlinked-source for links)].+ , argOutputDir :: Directory+ -- ^ Where to generate the documentation.+ , argTitle :: Flag String+ -- ^ Page title, required.+ , argPrologue :: Flag String+ -- ^ Prologue text, required for 'haddock', ignored by 'haddocks'.+ , argPrologueFile :: Flag FilePath+ -- ^ Prologue file name, ignored by 'haddock', optional for 'haddocks'.+ , argGhcOptions :: GhcOptions+ -- ^ Additional flags to pass to GHC.+ , argGhcLibDir :: Flag FilePath+ -- ^ To find the correct GHC, required.+ , argReexports :: [OpenModule]+ -- ^ Re-exported modules+ , argTargets :: [FilePath]+ -- ^ Modules to process.+ , argResourcesDir :: Flag String+ -- ^ haddock's static \/ auxiliary files.+ , argUseUnicode :: Flag Bool+ -- ^ haddock's `--use-unicode` flag+ }+ deriving (Generic)++-- | The FilePath of a directory, it's a monoid under '(</>)'.+newtype Directory = Dir {unDir' :: FilePath} deriving (Read, Show, Eq, Ord)++-- NB: only correct at the top-level, after we have combined monoidally+-- the top-level output directory with the component subdir.+unDir :: Directory -> SymbolicPath Pkg (Path.Dir Artifacts)+unDir = makeSymbolicPath . normalise . unDir'++type Template = String++data Output = Html | Hoogle+ deriving (Eq)++-- ------------------------------------------------------------------------------+-- Haddock support++-- | Get Haddock program and check if it matches the request+getHaddockProg+ :: Verbosity+ -> ProgramDb+ -> Compiler+ -> HaddockArgs+ -> Flag Bool+ -- ^ quickjump feature+ -> IO (ConfiguredProgram, Version)+getHaddockProg verbosity programDb comp args quickJumpFlag = do+ let HaddockArgs+ { argQuickJump+ , argOutput+ } = args+ hoogle = Hoogle `elem` fromFlagOrDefault [] argOutput++ (haddockProg, version, _) <-+ requireProgramVersion+ verbosity+ haddockProgram+ (orLaterVersion (mkVersion [2, 0]))+ programDb++ -- various sanity checks+ when (hoogle && version < mkVersion [2, 2]) $+ dieWithException verbosity NoSupportForHoogle++ when (fromFlag argQuickJump && version < mkVersion [2, 19]) $ do+ let msg = "Haddock prior to 2.19 does not support the --quickjump flag."+ alt = "The generated documentation won't have the QuickJump feature."+ if Flag True == quickJumpFlag+ then dieWithException verbosity NoSupportForQuickJumpFlag+ else warn verbosity (msg ++ "\n" ++ alt)++ haddockGhcVersionStr <-+ getProgramOutput+ verbosity+ haddockProg+ ["--ghc-version"]+ case (simpleParsec haddockGhcVersionStr, compilerCompatVersion GHC comp) of+ (Nothing, _) -> dieWithException verbosity NoGHCVersionFromHaddock+ (_, Nothing) -> dieWithException verbosity NoGHCVersionFromCompiler+ (Just haddockGhcVersion, Just ghcVersion)+ | haddockGhcVersion == ghcVersion -> return ()+ | otherwise -> dieWithException verbosity $ HaddockAndGHCVersionDoesntMatch ghcVersion haddockGhcVersion++ return (haddockProg, version)++haddock+ :: PackageDescription+ -> LocalBuildInfo+ -> [PPSuffixHandler]+ -> HaddockFlags+ -> IO ()+haddock = haddock_setupHooks noBuildHooks++haddock_setupHooks+ :: BuildHooks+ -> PackageDescription+ -> LocalBuildInfo+ -> [PPSuffixHandler]+ -> HaddockFlags+ -> IO ()+haddock_setupHooks+ _+ pkg_descr+ _+ _+ haddockFlags+ | not (hasLibs pkg_descr)+ && not (fromFlag $ haddockExecutables haddockFlags)+ && not (fromFlag $ haddockTestSuites haddockFlags)+ && not (fromFlag $ haddockBenchmarks haddockFlags)+ && not (fromFlag $ haddockForeignLibs haddockFlags) =+ warn (fromFlag $ setupVerbosity $ haddockCommonFlags haddockFlags) $+ "No documentation was generated as this package does not contain "+ ++ "a library. Perhaps you want to use the --executables, --tests,"+ ++ " --benchmarks or --foreign-libraries flags."+haddock_setupHooks+ (BuildHooks{preBuildComponentRules = mbPbcRules})+ pkg_descr+ lbi+ suffixes+ flags' = do+ let verbosity = fromFlag $ haddockVerbosity flags+ mbWorkDir = flagToMaybe $ haddockWorkingDir flags+ comp = compiler lbi+ platform = hostPlatform lbi++ quickJmpFlag = haddockQuickJump flags'+ flags = case haddockTarget of+ ForDevelopment -> flags'+ ForHackage ->+ flags'+ { haddockHoogle = Flag True+ , haddockHtml = Flag True+ , haddockHtmlLocation = Flag (pkg_url ++ "/docs")+ , haddockContents = Flag (toPathTemplate pkg_url)+ , haddockLinkedSource = Flag True+ , haddockQuickJump = Flag True+ }+ pkg_url = "/package/$pkg-$version"+ flag f = fromFlag $ f flags++ tmpFileOpts =+ defaultTempFileOptions+ { optKeepTempFiles = flag haddockKeepTempFiles+ }+ htmlTemplate =+ fmap toPathTemplate . flagToMaybe . haddockHtmlLocation $+ flags+ haddockTarget =+ fromFlagOrDefault ForDevelopment (haddockForHackage flags')++ libdirArgs <- getGhcLibDir verbosity lbi+ -- The haddock-output-dir flag overrides any other documentation placement concerns.+ -- The point is to give the user full freedom over the location if they need it.+ let overrideWithOutputDir args = case haddockOutputDir flags of+ NoFlag -> args+ Flag dir -> args{argOutputDir = Dir dir}+ let commonArgs =+ overrideWithOutputDir $+ mconcat+ [ libdirArgs+ , fromFlags (haddockTemplateEnv lbi (packageId pkg_descr)) flags+ , fromPackageDescription haddockTarget pkg_descr+ ]++ (haddockProg, version) <-+ getHaddockProg verbosity (withPrograms lbi) comp commonArgs quickJmpFlag++ -- We fall back to using HsColour only for versions of Haddock which don't+ -- support '--hyperlinked-sources'.+ let using_hscolour = flag haddockLinkedSource && version < mkVersion [2, 17]+ when using_hscolour $+ hscolour'+ noBuildHooks+ -- NB: we are not passing the user BuildHooks here,+ -- because we are already running the pre/post build hooks+ -- for Haddock.+ (warn verbosity)+ haddockTarget+ pkg_descr+ lbi+ suffixes+ (defaultHscolourFlags `mappend` haddockToHscolour flags)++ targets <- readTargetInfos verbosity pkg_descr lbi (haddockTargets flags)++ let+ targets' =+ case targets of+ [] -> allTargetsInBuildOrder' pkg_descr lbi+ _ -> targets++ internalPackageDB <-+ createInternalPackageDB verbosity lbi (flag $ setupDistPref . haddockCommonFlags)++ (\f -> foldM_ f (installedPkgs lbi) targets') $ \index target -> do+ let+ component = targetComponent target+ clbi = targetCLBI target+ bi = componentBuildInfo component+ -- Include any build-tool-depends on build tools internal to the current package.+ progs' = addInternalBuildTools pkg_descr lbi bi (withPrograms lbi)+ lbi' =+ lbi+ { withPrograms = progs'+ , withPackageDB = withPackageDB lbi ++ [internalPackageDB]+ , installedPkgs = index+ }++ runPreBuildHooks :: LocalBuildInfo -> TargetInfo -> IO ()+ runPreBuildHooks lbi2 tgt =+ let inputs =+ SetupHooks.PreBuildComponentInputs+ { SetupHooks.buildingWhat = BuildHaddock flags+ , SetupHooks.localBuildInfo = lbi2+ , SetupHooks.targetInfo = tgt+ }+ in for_ mbPbcRules $ \pbcRules -> do+ (ruleFromId, _mons) <- SetupHooks.computeRules verbosity inputs pbcRules+ SetupHooks.executeRules verbosity lbi2 tgt ruleFromId++ -- See Note [Hi Haddock Recompilation Avoidance]+ reusingGHCCompilationArtifacts verbosity tmpFileOpts mbWorkDir lbi bi clbi version $ \haddockArtifactsDirs -> do+ preBuildComponent runPreBuildHooks verbosity lbi' target+ preprocessComponent pkg_descr component lbi' clbi False verbosity suffixes+ let+ doExe com = case (compToExe com) of+ Just exe -> do+ exeArgs <-+ fromExecutable+ verbosity+ haddockArtifactsDirs+ lbi'+ clbi+ htmlTemplate+ haddockTarget+ pkg_descr+ exe+ commonArgs+ runHaddock+ verbosity+ mbWorkDir+ tmpFileOpts+ comp+ platform+ haddockProg+ True+ exeArgs+ Nothing -> do+ warn+ verbosity+ "Unsupported component, skipping..."+ return ()+ -- We define 'smsg' once and then reuse it inside the case, so that+ -- we don't say we are running Haddock when we actually aren't+ -- (e.g., Haddock is not run on non-libraries)+ smsg :: IO ()+ smsg =+ setupMessage'+ verbosity+ "Running Haddock on"+ (packageId pkg_descr)+ (componentLocalName clbi)+ (maybeComponentInstantiatedWith clbi)+ ipi <- case component of+ CLib lib -> do+ smsg+ libArgs <-+ fromLibrary+ verbosity+ haddockArtifactsDirs+ lbi'+ clbi+ htmlTemplate+ haddockTarget+ pkg_descr+ lib+ commonArgs+ runHaddock+ verbosity+ mbWorkDir+ tmpFileOpts+ comp+ platform+ haddockProg+ True+ libArgs+ inplaceDir <- absoluteWorkingDirLBI lbi++ let+ ipi =+ inplaceInstalledPackageInfo+ inplaceDir+ (flag $ setupDistPref . haddockCommonFlags)+ pkg_descr+ (mkAbiHash "inplace")+ lib+ lbi'+ clbi++ debug verbosity $+ "Registering inplace:\n"+ ++ (InstalledPackageInfo.showInstalledPackageInfo ipi)++ registerPackage+ verbosity+ (compiler lbi')+ (withPrograms lbi')+ mbWorkDir+ (withPackageDB lbi')+ ipi+ HcPkg.defaultRegisterOptions+ { HcPkg.registerMultiInstance = True+ }++ return $ PackageIndex.insert ipi index+ CFLib flib ->+ when+ (flag haddockForeignLibs)+ ( do+ smsg+ flibArgs <-+ fromForeignLib+ verbosity+ haddockArtifactsDirs+ lbi'+ clbi+ htmlTemplate+ haddockTarget+ pkg_descr+ flib+ commonArgs+ runHaddock+ verbosity+ mbWorkDir+ tmpFileOpts+ comp+ platform+ haddockProg+ True+ flibArgs+ )+ >> return index+ CExe _ -> when (flag haddockExecutables) (smsg >> doExe component) >> return index+ CTest test -> do+ when (flag haddockTestSuites) $ do+ smsg+ testArgs <-+ fromTest+ verbosity+ haddockArtifactsDirs+ lbi'+ clbi+ htmlTemplate+ haddockTarget+ pkg_descr+ test+ commonArgs+ runHaddock+ verbosity+ mbWorkDir+ tmpFileOpts+ comp+ platform+ haddockProg+ True+ testArgs+ return index+ CBench bench -> do+ when (flag haddockBenchmarks) $ do+ smsg+ benchArgs <-+ fromBenchmark+ verbosity+ haddockArtifactsDirs+ lbi'+ clbi+ htmlTemplate+ haddockTarget+ pkg_descr+ bench+ commonArgs+ runHaddock+ verbosity+ mbWorkDir+ tmpFileOpts+ comp+ platform+ haddockProg+ True+ benchArgs+ return index++ return ipi++ for_ (extraDocFiles pkg_descr) $ \fpath -> do+ files <- matchDirFileGlob verbosity (specVersion pkg_descr) mbWorkDir fpath+ let targetDir = Dir $ unDir' (argOutputDir commonArgs) </> haddockDirName haddockTarget pkg_descr+ for_ files $+ copyFileToCwd verbosity mbWorkDir (unDir targetDir)++-- | Execute 'Haddock' configured with 'HaddocksFlags'. It is used to build+-- index and contents for documentation of multiple packages.+createHaddockIndex+ :: Verbosity+ -> ProgramDb+ -> Compiler+ -> Platform+ -> Maybe (SymbolicPath CWD (Path.Dir Pkg))+ -> HaddockProjectFlags+ -> IO ()+createHaddockIndex verbosity programDb comp platform mbWorkDir flags = do+ let args = fromHaddockProjectFlags flags+ (haddockProg, _version) <-+ getHaddockProg verbosity programDb comp args (Flag True)+ runHaddock verbosity mbWorkDir defaultTempFileOptions comp platform haddockProg False args++-- ------------------------------------------------------------------------------+-- Contributions to HaddockArgs (see also Doctest.hs for very similar code).++fromFlags :: PathTemplateEnv -> HaddockFlags -> HaddockArgs+fromFlags env flags =+ mempty+ { argHideModules =+ ( maybe mempty (All . not) $+ flagToMaybe (haddockInternal flags)+ , mempty+ )+ , argLinkSource =+ if fromFlag (haddockLinkedSource flags)+ then+ Flag+ ( "src/%{MODULE/./-}.html"+ , "src/%{MODULE/./-}.html#%{NAME}"+ , "src/%{MODULE/./-}.html#line-%{LINE}"+ )+ else NoFlag+ , argLinkedSource = haddockLinkedSource flags+ , argQuickJump = haddockQuickJump flags+ , argCssFile = haddockCss flags+ , argContents =+ fmap+ (fromPathTemplate . substPathTemplate env)+ (haddockContents flags)+ , argGenContents = Flag False+ , argIndex =+ fmap+ (fromPathTemplate . substPathTemplate env)+ (haddockIndex flags)+ , argGenIndex = Flag False+ , argBaseUrl = haddockBaseUrl flags+ , argResourcesDir = haddockResourcesDir flags+ , argVerbose =+ maybe mempty (Any . (>= deafening))+ . flagToMaybe+ $ setupVerbosity commonFlags+ , argOutput =+ Flag $ case [Html | Flag True <- [haddockHtml flags]]+ ++ [Hoogle | Flag True <- [haddockHoogle flags]] of+ [] -> [Html]+ os -> os+ , argOutputDir = maybe mempty (Dir . getSymbolicPath) . flagToMaybe $ setupDistPref commonFlags+ , argGhcOptions = mempty{ghcOptExtra = ghcArgs}+ , argUseUnicode = haddockUseUnicode flags+ }+ where+ ghcArgs = fromMaybe [] . lookup "ghc" . haddockProgramArgs $ flags+ commonFlags = haddockCommonFlags flags++fromHaddockProjectFlags :: HaddockProjectFlags -> HaddockArgs+fromHaddockProjectFlags flags =+ mempty+ { argOutputDir = Dir (fromFlag $ haddockProjectDir flags)+ , argQuickJump = Flag True+ , argGenContents = Flag True+ , argGenIndex = Flag True+ , argPrologueFile = haddockProjectPrologue flags+ , argInterfaces = fromFlagOrDefault [] (haddockProjectInterfaces flags)+ , argLinkedSource = Flag True+ , argResourcesDir = haddockProjectResourcesDir flags+ }++fromPackageDescription :: HaddockTarget -> PackageDescription -> HaddockArgs+fromPackageDescription _haddockTarget pkg_descr =+ mempty+ { argInterfaceFile = Flag $ haddockPath pkg_descr+ , argPackageName = Flag $ packageId $ pkg_descr+ , argOutputDir = Dir $ "doc" </> "html"+ , argPrologue =+ Flag $+ ShortText.fromShortText $+ if ShortText.null desc+ then synopsis pkg_descr+ else desc+ , argTitle = Flag $ showPkg ++ subtitle+ }+ where+ desc = description pkg_descr+ showPkg = prettyShow (packageId pkg_descr)+ subtitle+ | ShortText.null (synopsis pkg_descr) = ""+ | otherwise = ": " ++ ShortText.fromShortText (synopsis pkg_descr)++componentGhcOptions+ :: Verbosity+ -> LocalBuildInfo+ -> BuildInfo+ -> ComponentLocalBuildInfo+ -> SymbolicPath Pkg (Path.Dir build)+ -> 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++{-+Note [Hi Haddock Recompilation Avoidance]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Starting with Haddock 2.28, we no longer want to run Haddock's GHC session in+an arbitrary temporary directory. Doing so always causes recompilation during+documentation generation, which can now be avoided thanks to Hi Haddock.++Instead, we want to re-use the interface and object files produced by GHC.+We copy these intermediate files produced by GHC to temporary directories and+point haddock to them.++The reason why we can't use the GHC files /inplace/ is that haddock may have to+recompile (e.g. because of `haddock-options`). In that case, we want to be sure+the files produced by GHC do not get overwritten.++See https://github.com/haskell/cabal/pull/9177 for discussion.++(W.1) As it turns out, -stubdir is included in GHC's recompilation fingerprint.+This means that if we use a temporary directory for stubfiles produced by GHC+for the haddock invocation, haddock will trigger full recompilation since the+stubdir would be different.++So we don't use a temporary stubdir, despite the tmp o-dir and hi-dir:++We want to avoid at all costs haddock accidentally overwriting o-files and+hi-files (e.g. if a user specified haddock-option triggers recompilation), and+thus copy them to a temporary directory to pass them on to haddock. However,+stub files are much less problematic since ABI-incompatibility isn't at play+here, that is, there doesn't seem to be a GHC flag that could accidentally make+a stub file incompatible with the one produced by GHC from the same module.+-}++mkHaddockArgs+ :: Verbosity+ -> (SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts))+ -- ^ Directories for -hidir, -odir, and -stubdir to GHC through Haddock.+ -- See Note [Hi Haddock Recompilation Avoidance]+ -> LocalBuildInfo+ -> ComponentLocalBuildInfo+ -> Maybe PathTemplate+ -- ^ template for HTML location+ -> [SymbolicPath Pkg File]+ -> BuildInfo+ -> IO HaddockArgs+mkHaddockArgs verbosity (tmpObjDir, tmpHiDir, tmpStubDir) lbi clbi htmlTemplate inFiles bi = do+ let+ vanillaOpts' =+ componentGhcOptions normal lbi bi clbi (buildDir lbi)+ vanillaOpts =+ vanillaOpts'+ { -- See Note [Hi Haddock Recompilation Avoidance]+ ghcOptObjDir = toFlag tmpObjDir+ , ghcOptHiDir = toFlag tmpHiDir+ , ghcOptStubDir = toFlag tmpStubDir+ }+ sharedOpts =+ vanillaOpts+ { ghcOptDynLinkMode = toFlag GhcDynamicOnly+ , ghcOptFPic = toFlag True+ , ghcOptHiSuffix = toFlag "dyn_hi"+ , ghcOptObjSuffix = toFlag "dyn_o"+ , ghcOptExtra = hcSharedOptions GHC bi+ }+ ifaceArgs <- getInterfaces verbosity lbi clbi htmlTemplate+ opts <-+ if withVanillaLib lbi+ then return vanillaOpts+ else+ if withSharedLib lbi+ then return sharedOpts+ else dieWithException verbosity MustHaveSharedLibraries++ return+ ifaceArgs+ { argGhcOptions = opts+ , argTargets = map getSymbolicPath inFiles+ , argReexports = getReexports clbi+ }++fromLibrary+ :: Verbosity+ -> (SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts))+ -- ^ Directories for -hidir, -odir, and -stubdir to GHC through Haddock.+ -- See Note [Hi Haddock Recompilation Avoidance]+ -> LocalBuildInfo+ -> ComponentLocalBuildInfo+ -> Maybe PathTemplate+ -- ^ template for HTML location+ -> HaddockTarget+ -> PackageDescription+ -> Library+ -> HaddockArgs+ -- ^ common args+ -> IO HaddockArgs+fromLibrary verbosity haddockArtifactsDirs lbi clbi htmlTemplate haddockTarget pkg_descr lib commonArgs = do+ inFiles <- map snd `fmap` getLibSourceFiles verbosity lbi lib clbi+ args <-+ mkHaddockArgs+ verbosity+ haddockArtifactsDirs+ lbi+ clbi+ htmlTemplate+ inFiles+ (libBuildInfo lib)+ let args' =+ commonArgs+ <> args+ { argOutputDir =+ Dir $ haddockLibraryDirPath haddockTarget pkg_descr lib+ , argInterfaceFile = Flag $ haddockLibraryPath pkg_descr lib+ }+ args'' =+ args'+ { argHideModules = (mempty, otherModules (libBuildInfo lib))+ , argTitle = Flag $ haddockPackageLibraryName pkg_descr lib+ , argComponentName = toFlag (haddockPackageLibraryName' (pkgName (package pkg_descr)) (libName lib))+ , -- we need to accommodate for `argOutputDir`, see `haddockLibraryPath`+ argBaseUrl = case (libName lib, argBaseUrl args') of+ (LSubLibName _, Flag url) -> Flag $ ".." </> url+ (_, a) -> a+ , argContents = case (libName lib, argContents args') of+ (LSubLibName _, Flag url) -> Flag $ ".." </> url+ (_, a) -> a+ , argIndex = case (libName lib, argIndex args') of+ (LSubLibName _, Flag url) -> Flag $ ".." </> url+ (_, a) -> a+ }+ return args''++fromExecutable+ :: Verbosity+ -> (SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts))+ -- ^ Directories for -hidir, -odir, and -stubdir to GHC through Haddock.+ -- See Note [Hi Haddock Recompilation Avoidance]+ -> LocalBuildInfo+ -> ComponentLocalBuildInfo+ -> Maybe PathTemplate+ -- ^ template for HTML location+ -> HaddockTarget+ -> PackageDescription+ -> Executable+ -> HaddockArgs+ -- ^ common args+ -> IO HaddockArgs+fromExecutable verbosity haddockArtifactsDirs lbi clbi htmlTemplate haddockTarget pkg_descr exe commonArgs = do+ inFiles <- map snd `fmap` getExeSourceFiles verbosity lbi exe clbi+ args <-+ mkHaddockArgs+ verbosity+ haddockArtifactsDirs+ lbi+ clbi+ htmlTemplate+ inFiles+ (buildInfo exe)+ let args' =+ commonArgs+ <> args+ { argOutputDir =+ Dir $+ haddockDirName haddockTarget pkg_descr+ </> unUnqualComponentName (exeName exe)+ }+ return+ args'+ { argTitle = Flag $ unUnqualComponentName $ exeName exe+ , -- we need to accommodate `argOutputDir`+ argBaseUrl = case argBaseUrl args' of+ Flag url -> Flag $ ".." </> url+ NoFlag -> NoFlag+ , argContents = case argContents args' of+ Flag url -> Flag $ ".." </> url+ NoFlag -> NoFlag+ , argIndex = case argIndex args' of+ Flag url -> Flag $ ".." </> url+ NoFlag -> NoFlag+ }++fromTest+ :: Verbosity+ -> (SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts))+ -- ^ Directories for -hidir, -odir, and -stubdir to GHC through Haddock.+ -- See Note [Hi Haddock Recompilation Avoidance]+ -> LocalBuildInfo+ -> ComponentLocalBuildInfo+ -> Maybe PathTemplate+ -- ^ template for HTML location+ -> HaddockTarget+ -> PackageDescription+ -> TestSuite+ -> HaddockArgs+ -- ^ common args+ -> IO HaddockArgs+fromTest verbosity haddockArtifactsDirs lbi clbi htmlTemplate haddockTarget pkg_descr test commonArgs = do+ inFiles <- map snd `fmap` getTestSourceFiles verbosity lbi test clbi+ args <-+ mkHaddockArgs+ verbosity+ haddockArtifactsDirs+ lbi+ clbi+ htmlTemplate+ inFiles+ (testBuildInfo test)+ let args' =+ commonArgs+ <> args+ { argOutputDir =+ Dir $+ haddockDirName haddockTarget pkg_descr+ </> unUnqualComponentName (testName test)+ }+ return+ args'+ { argTitle = Flag $ prettyShow (packageName pkg_descr)+ , argComponentName = Flag $ prettyShow (packageName pkg_descr) ++ ":" ++ unUnqualComponentName (testName test)+ , -- we need to accommodate `argOutputDir`+ argBaseUrl = case argBaseUrl args' of+ Flag url -> Flag $ ".." </> url+ NoFlag -> NoFlag+ , argContents = case argContents args' of+ Flag url -> Flag $ ".." </> url+ NoFlag -> NoFlag+ , argIndex = case argIndex args' of+ Flag url -> Flag $ ".." </> url+ NoFlag -> NoFlag+ }++fromBenchmark+ :: Verbosity+ -> (SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts))+ -- ^ Directories for -hidir, -odir, and -stubdir to GHC through Haddock.+ -- See Note [Hi Haddock Recompilation Avoidance]+ -> LocalBuildInfo+ -> ComponentLocalBuildInfo+ -> Maybe PathTemplate+ -- ^ template for HTML location+ -> HaddockTarget+ -> PackageDescription+ -> Benchmark+ -> HaddockArgs+ -- ^ common args+ -> IO HaddockArgs+fromBenchmark verbosity haddockArtifactsDirs lbi clbi htmlTemplate haddockTarget pkg_descr bench commonArgs = do+ inFiles <- map snd `fmap` getBenchmarkSourceFiles verbosity lbi bench clbi+ args <-+ mkHaddockArgs+ verbosity+ haddockArtifactsDirs+ lbi+ clbi+ htmlTemplate+ inFiles+ (benchmarkBuildInfo bench)+ let args' =+ commonArgs+ <> args+ { argOutputDir =+ Dir $+ haddockDirName haddockTarget pkg_descr+ </> unUnqualComponentName (benchmarkName bench)+ }+ return+ args'+ { argTitle = Flag $ prettyShow (packageName pkg_descr)+ , argComponentName = Flag $ prettyShow (packageName pkg_descr) ++ ":" ++ unUnqualComponentName (benchmarkName bench)+ , -- we need to accommodate `argOutputDir`+ argBaseUrl = case argBaseUrl args' of+ Flag url -> Flag $ ".." </> url+ NoFlag -> NoFlag+ , argContents = case argContents args' of+ Flag url -> Flag $ ".." </> url+ NoFlag -> NoFlag+ , argIndex = case argIndex args' of+ Flag url -> Flag $ ".." </> url+ NoFlag -> NoFlag+ }++fromForeignLib+ :: Verbosity+ -> (SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts))+ -- ^ Directories for -hidir, -odir, and -stubdir to GHC through Haddock.+ -- See Note [Hi Haddock Recompilation Avoidance]+ -> LocalBuildInfo+ -> ComponentLocalBuildInfo+ -> Maybe PathTemplate+ -- ^ template for HTML location+ -> HaddockTarget+ -> PackageDescription+ -> ForeignLib+ -> HaddockArgs+ -- ^ common args+ -> IO HaddockArgs+fromForeignLib verbosity haddockArtifactsDirs lbi clbi htmlTemplate haddockTarget pkg_descr flib commonArgs = do+ inFiles <- map snd `fmap` getFLibSourceFiles verbosity lbi flib clbi+ args <-+ mkHaddockArgs+ verbosity+ haddockArtifactsDirs+ lbi+ clbi+ htmlTemplate+ inFiles+ (foreignLibBuildInfo flib)+ let args' =+ commonArgs+ <> args+ { argOutputDir =+ Dir $+ haddockDirName haddockTarget pkg_descr+ </> unUnqualComponentName (foreignLibName flib)+ }+ return+ args'+ { argTitle = Flag $ unUnqualComponentName $ foreignLibName flib+ , -- we need to accommodate `argOutputDir`+ argBaseUrl = case argBaseUrl args' of+ Flag url -> Flag $ ".." </> url+ NoFlag -> NoFlag+ , argContents = case argContents args' of+ Flag url -> Flag $ ".." </> url+ NoFlag -> NoFlag+ , argIndex = case argIndex args' of+ Flag url -> Flag $ ".." </> url+ NoFlag -> NoFlag+ }++compToExe :: Component -> Maybe Executable+compToExe comp =+ case comp of+ CTest test@TestSuite{testInterface = TestSuiteExeV10 _ f} ->+ Just+ Executable+ { exeName = testName test+ , modulePath = f+ , exeScope = ExecutablePublic+ , buildInfo = testBuildInfo test+ }+ CBench bench@Benchmark{benchmarkInterface = BenchmarkExeV10 _ f} ->+ Just+ Executable+ { exeName = benchmarkName bench+ , modulePath = f+ , exeScope = ExecutablePublic+ , buildInfo = benchmarkBuildInfo bench+ }+ CExe exe -> Just exe+ _ -> Nothing++getInterfaces+ :: Verbosity+ -> LocalBuildInfo+ -> ComponentLocalBuildInfo+ -> Maybe PathTemplate+ -- ^ template for HTML location+ -> IO HaddockArgs+getInterfaces verbosity lbi clbi htmlTemplate = do+ (packageFlags, warnings) <- haddockPackageFlags verbosity lbi clbi htmlTemplate+ traverse_ (warn (verboseUnmarkOutput verbosity)) warnings+ return $+ mempty+ { argInterfaces = packageFlags+ }++getReexports :: ComponentLocalBuildInfo -> [OpenModule]+getReexports LibComponentLocalBuildInfo{componentExposedModules = mods} =+ mapMaybe exposedReexport mods+getReexports _ = []++getGhcLibDir+ :: Verbosity+ -> LocalBuildInfo+ -> IO HaddockArgs+getGhcLibDir verbosity lbi = do+ 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}++-- | If Hi Haddock is supported, this function creates temporary directories+-- and copies existing interface and object files produced by GHC into them,+-- then passes them off to the given continuation.+--+-- If Hi Haddock is _not_ supported, we can't re-use GHC's compilation files.+-- Instead, we use a clean temporary directory to the continuation,+-- with no hope for recompilation avoidance.+--+-- See Note [Hi Haddock Recompilation Avoidance]+reusingGHCCompilationArtifacts+ :: Verbosity+ -> TempFileOptions+ -> Maybe (SymbolicPath CWD (Path.Dir Pkg))+ -- ^ Working directory+ -> LocalBuildInfo+ -> BuildInfo+ -> ComponentLocalBuildInfo+ -> Version+ -- ^ Haddock's version+ -> ((SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts), SymbolicPath Pkg (Path.Dir Artifacts)) -> IO r)+ -- ^ Continuation+ -> IO r+reusingGHCCompilationArtifacts verbosity tmpFileOpts mbWorkDir lbi bi clbi version act+ | version >= mkVersion [2, 28, 0] = do+ withTempDirectoryCwdEx verbosity tmpFileOpts mbWorkDir (distPrefLBI lbi) "haddock-objs" $ \tmpObjDir ->+ withTempDirectoryCwdEx verbosity tmpFileOpts mbWorkDir (distPrefLBI lbi) "haddock-his" $ \tmpHiDir -> do+ -- Re-use ghc's interface and obj files, but first copy them to+ -- somewhere where it is safe if haddock overwrites them+ let+ vanillaOpts = componentGhcOptions normal lbi bi clbi (buildDir lbi)+ i = interpretSymbolicPath mbWorkDir+ copyDir ghcDir tmpDir = copyDirectoryRecursive verbosity (i $ fromFlag $ ghcDir vanillaOpts) (i tmpDir)+ copyDir ghcOptObjDir tmpObjDir+ copyDir ghcOptHiDir tmpHiDir+ -- copyDir ghcOptStubDir tmpStubDir -- (see W.1 in Note [Hi Haddock Recompilation Avoidance])++ act (tmpObjDir, tmpHiDir, fromFlag $ ghcOptHiDir vanillaOpts)+ | otherwise = do+ withTempDirectoryCwdEx verbosity tmpFileOpts mbWorkDir (distPrefLBI lbi) "tmp" $+ \tmpFallback -> act (tmpFallback, tmpFallback, tmpFallback)++-- ------------------------------------------------------------------------------++-- | Call haddock with the specified arguments.+runHaddock+ :: Verbosity+ -> Maybe (SymbolicPath CWD (Path.Dir Pkg))+ -> TempFileOptions+ -> Compiler+ -> Platform+ -> ConfiguredProgram+ -> Bool+ -- ^ require targets+ -> HaddockArgs+ -> IO ()+runHaddock verbosity mbWorkDir tmpFileOpts comp platform haddockProg requireTargets args+ | requireTargets && null (argTargets args) =+ warn verbosity $+ "Haddocks are being requested, but there aren't any modules given "+ ++ "to create documentation for."+ | otherwise = do+ let haddockVersion =+ fromMaybe+ (error "unable to determine haddock version")+ (programVersion haddockProg)+ renderArgs verbosity mbWorkDir tmpFileOpts haddockVersion comp platform args $+ \flags result -> do+ runProgramCwd verbosity mbWorkDir haddockProg flags+ notice verbosity $ "Documentation created: " ++ result++renderArgs+ :: forall a+ . Verbosity+ -> Maybe (SymbolicPath CWD (Path.Dir Pkg))+ -> TempFileOptions+ -> Version+ -> Compiler+ -> Platform+ -> HaddockArgs+ -> ([String] -> FilePath -> IO a)+ -> IO a+renderArgs verbosity mbWorkDir tmpFileOpts version comp platform args k = do+ let haddockSupportsUTF8 = version >= mkVersion [2, 14, 4]+ haddockSupportsResponseFiles = version > mkVersion [2, 16, 2]+ createDirectoryIfMissingVerbose verbosity True (i outputDir)+ let withPrologueArgs prologueArgs =+ let renderedArgs = prologueArgs <> renderPureArgs version comp platform args+ in if haddockSupportsResponseFiles+ then+ withResponseFile+ verbosity+ tmpFileOpts+ mbWorkDir+ outputDir+ "haddock-response.txt"+ (if haddockSupportsUTF8 then Just utf8 else Nothing)+ renderedArgs+ (\responseFileName -> k ["@" ++ responseFileName] result)+ else k renderedArgs result+ case (argPrologueFile args, argPrologue args) of+ (Flag pfile, _) ->+ withPrologueArgs ["--prologue=" ++ pfile]+ (_, Flag prologueText) ->+ withTempFileEx tmpFileOpts mbWorkDir outputDir "haddock-prologue.txt" $+ \prologueFileName h -> do+ when haddockSupportsUTF8 (hSetEncoding h utf8)+ hPutStrLn h prologueText+ hClose h+ withPrologueArgs ["--prologue=" ++ u prologueFileName]+ (NoFlag, NoFlag) ->+ withPrologueArgs []+ where+ -- See Note [Symbolic paths] in Distribution.Utils.Path+ i = interpretSymbolicPath mbWorkDir+ u :: SymbolicPath Pkg to -> FilePath+ u = interpretSymbolicPathCWD++ outputDir = coerceSymbolicPath $ unDir $ argOutputDir args+ isNotArgContents = isNothing (flagToMaybe $ argContents args)+ isNotArgIndex = isNothing (flagToMaybe $ argIndex args)+ isArgGenIndex = fromFlagOrDefault False (argGenIndex args)+ -- Haddock, when generating HTML, does not generate an index if the options+ -- --use-contents or --use-index are passed to it. See+ -- https://haskell-haddock.readthedocs.io/en/latest/invoking.html#cmdoption-use-contents+ isIndexGenerated = isArgGenIndex && isNotArgContents && isNotArgIndex+ result =+ intercalate ", "+ . map+ ( \o ->+ i outputDir+ </> case o of+ Html+ | isIndexGenerated ->+ "index.html"+ Html+ | otherwise ->+ mempty+ Hoogle -> pkgstr <.> "txt"+ )+ . fromFlagOrDefault [Html]+ . argOutput+ $ args+ where+ pkgstr = prettyShow $ packageName pkgid+ pkgid = arg argPackageName+ arg f = fromFlag $ f args++renderPureArgs :: Version -> Compiler -> Platform -> HaddockArgs -> [String]+renderPureArgs version comp platform args =+ concat+ [ map (\f -> "--dump-interface=" ++ u (unDir (argOutputDir args)) </> f)+ . flagToList+ . argInterfaceFile+ $ args+ , if haddockSupportsPackageName+ then+ maybe+ []+ ( \pkg ->+ [ "--package-name="+ ++ case argComponentName args of+ Flag name -> name+ _ -> prettyShow (pkgName pkg)+ , "--package-version=" ++ prettyShow (pkgVersion pkg)+ ]+ )+ . flagToMaybe+ . argPackageName+ $ args+ else []+ , ["--since-qual=external" | isVersion 2 20]+ , [ "--quickjump" | isVersion 2 19, True <- flagToList . argQuickJump $ args+ ]+ , ["--hyperlinked-source" | isHyperlinkedSource]+ , (\(All b, xs) -> bool [] (map (("--hide=" ++) . prettyShow) xs) b)+ . argHideModules+ $ args+ , bool [] ["--ignore-all-exports"] . getAny . argIgnoreExports $ args+ , -- Haddock's --source-* options are ignored once --hyperlinked-source is+ -- set.+ -- See https://haskell-haddock.readthedocs.io/en/latest/invoking.html#cmdoption-hyperlinked-source+ -- To avoid Haddock's warning, we only set --source-* options if+ -- --hyperlinked-source is not set.+ if isHyperlinkedSource+ then []+ else+ maybe+ []+ ( \(m, e, l) ->+ [ "--source-module=" ++ m+ , "--source-entity=" ++ e+ ]+ ++ if isVersion 2 14+ then ["--source-entity-line=" ++ l]+ else []+ )+ . flagToMaybe+ . argLinkSource+ $ args+ , maybe [] ((: []) . ("--css=" ++)) . flagToMaybe . argCssFile $ args+ , maybe [] ((: []) . ("--use-contents=" ++)) . flagToMaybe . argContents $ args+ , bool [] ["--gen-contents"] . fromFlagOrDefault False . argGenContents $ args+ , maybe [] ((: []) . ("--use-index=" ++)) . flagToMaybe . argIndex $ args+ , bool [] ["--gen-index"] . fromFlagOrDefault False . argGenIndex $ args+ , maybe [] ((: []) . ("--base-url=" ++)) . flagToMaybe . argBaseUrl $ args+ , bool [verbosityFlag] [] . getAny . argVerbose $ args+ , map (\o -> case o of Hoogle -> "--hoogle"; Html -> "--html")+ . fromFlagOrDefault []+ . argOutput+ $ args+ , renderInterfaces . argInterfaces $ args+ , (: []) . ("--odir=" ++) . u . unDir . argOutputDir $ args+ , maybe+ []+ ( (: [])+ . ("--title=" ++)+ . ( bool+ id+ (++ " (internal documentation)")+ (getAny $ argIgnoreExports args)+ )+ )+ . flagToMaybe+ . argTitle+ $ args+ , [ "--optghc=" ++ opt | let opts = argGhcOptions args, opt <- renderGhcOptions comp platform opts+ ]+ , maybe [] (\l -> ["-B" ++ l]) $+ flagToMaybe (argGhcLibDir args) -- error if Nothing?+ , -- https://github.com/haskell/haddock/pull/547+ [ "--reexport=" ++ prettyShow r+ | r <- argReexports args+ , isVersion 2 19+ ]+ , argTargets $ args+ , maybe [] ((: []) . (resourcesDirFlag ++)) . flagToMaybe . argResourcesDir $ args+ , -- Do not re-direct compilation output to a temporary directory (--no-tmp-comp-dir)+ -- We pass this option by default to haddock to avoid recompilation+ -- See Note [Hi Haddock Recompilation Avoidance]+ ["--no-tmp-comp-dir" | version >= mkVersion [2, 28, 0]]+ , bool [] ["--use-unicode"] . fromFlagOrDefault False . argUseUnicode $ args+ ]+ where+ -- See Note [Symbolic paths] in Distribution.Utils.Path+ u = interpretSymbolicPathCWD+ renderInterfaces = map renderInterface++ renderInterface :: (FilePath, Maybe FilePath, Maybe FilePath, Visibility) -> String+ renderInterface (i, html, hypsrc, visibility) =+ "--read-interface="+ ++ intercalate+ ","+ ( concat+ [ [fromMaybe "" html]+ , -- only render hypsrc path if html path+ -- is given and hyperlinked-source is+ -- enabled++ [ case (html, hypsrc) of+ (Nothing, _) -> ""+ (_, Nothing) -> ""+ (_, Just x)+ | isVersion 2 17+ , fromFlagOrDefault False . argLinkedSource $ args ->+ x+ | otherwise ->+ ""+ ]+ , if haddockSupportsVisibility+ then+ [ case visibility of+ Visible -> "visible"+ Hidden -> "hidden"+ ]+ else []+ , [i]+ ]+ )++ isVersion major minor = version >= mkVersion [major, minor]+ verbosityFlag+ | isVersion 2 5 = "--verbosity=1"+ | otherwise = "--verbose"+ resourcesDirFlag+ | isVersion 2 29 = "--resources-dir="+ | otherwise = "--lib="+ haddockSupportsVisibility = version >= mkVersion [2, 26, 1]+ haddockSupportsPackageName = version > mkVersion [2, 16]+ haddockSupportsHyperlinkedSource = isVersion 2 17+ isHyperlinkedSource =+ haddockSupportsHyperlinkedSource+ && fromFlagOrDefault False (argLinkedSource args)++---------------------------------------------------------------------------------++-- | Given a list of 'InstalledPackageInfo's, return a list of interfaces and+-- HTML paths, and an optional warning for packages with missing documentation.+haddockPackagePaths+ :: [InstalledPackageInfo]+ -> Maybe (InstalledPackageInfo -> FilePath)+ -> IO+ ( [ ( FilePath -- path to interface+ -- file+ , Maybe FilePath -- url to html+ -- documentation+ , Maybe FilePath -- url to hyperlinked+ -- source+ , Visibility+ )+ ]+ , Maybe String -- warning about+ -- missing documentation+ )+haddockPackagePaths ipkgs mkHtmlPath = do+ interfaces <-+ sequenceA+ [ case interfaceAndHtmlPath ipkg of+ Nothing -> do+ return (Left (packageId ipkg))+ Just (interface, html) -> do+ (html', hypsrc') <-+ case html of+ Just htmlPath -> do+ let hypSrcPath = htmlPath </> defaultHyperlinkedSourceDirectory+ hypSrcExists <- doesDirectoryExist hypSrcPath+ return $+ ( Just (fixFileUrl htmlPath)+ , if hypSrcExists+ then Just (fixFileUrl hypSrcPath)+ else Nothing+ )+ Nothing -> return (Nothing, Nothing)++ exists <- doesFileExist interface+ if exists+ then return (Right (interface, html', hypsrc', Visible))+ else return (Left pkgid)+ | ipkg <- ipkgs+ , let pkgid = packageId ipkg+ , pkgName pkgid `notElem` noHaddockWhitelist+ ]++ let missing = [pkgid | Left pkgid <- interfaces]+ warning =+ "The documentation for the following packages are not "+ ++ "installed. No links will be generated to these packages: "+ ++ intercalate ", " (map prettyShow missing)+ flags = rights interfaces++ return (flags, if null missing then Nothing else Just warning)+ where+ -- Don't warn about missing documentation for these packages. See #1231.+ noHaddockWhitelist = map mkPackageName ["rts"]++ -- Actually extract interface and HTML paths from an 'InstalledPackageInfo'.+ interfaceAndHtmlPath+ :: InstalledPackageInfo+ -> Maybe (FilePath, Maybe FilePath)+ interfaceAndHtmlPath pkg = do+ interface <- listToMaybe (InstalledPackageInfo.haddockInterfaces pkg)+ html <- case mkHtmlPath of+ Nothing -> listToMaybe (InstalledPackageInfo.haddockHTMLs pkg)+ Just mkPath -> Just (mkPath pkg)+ return (interface, if null html then Nothing else Just html)++ -- The 'haddock-html' field in the hc-pkg output is often set as a+ -- native path, but we need it as a URL. See #1064. Also don't "fix"+ -- the path if it is an interpolated one.+ fixFileUrl f+ | Nothing <- mkHtmlPath+ , isAbsolute f =+ "file://" ++ f+ | otherwise = f++ -- 'src' is the default hyperlinked source directory ever since. It is+ -- not possible to configure that directory in any way in haddock.+ defaultHyperlinkedSourceDirectory = "src"++haddockPackageFlags+ :: Verbosity+ -> LocalBuildInfo+ -> ComponentLocalBuildInfo+ -> Maybe PathTemplate+ -> IO+ ( [ ( FilePath -- path to interface+ -- file+ , Maybe FilePath -- url to html+ -- documentation+ , Maybe FilePath -- url to hyperlinked+ -- source+ , Visibility+ )+ ]+ , Maybe String -- warning about+ -- missing documentation+ )+haddockPackageFlags verbosity lbi clbi htmlTemplate = do+ let allPkgs = installedPkgs lbi+ directDeps = map fst (componentPackageDeps clbi)+ transitiveDeps <- case PackageIndex.dependencyClosure allPkgs directDeps of+ Left x -> return x+ Right inf ->+ dieWithException verbosity $ HaddockPackageFlags inf++ haddockPackagePaths (PackageIndex.allPackages transitiveDeps) mkHtmlPath+ where+ mkHtmlPath = fmap expandTemplateVars htmlTemplate+ expandTemplateVars tmpl pkg =+ fromPathTemplate . substPathTemplate (env pkg) $ tmpl+ env pkg = haddockTemplateEnv lbi (packageId pkg)++haddockTemplateEnv :: LocalBuildInfo -> PackageIdentifier -> PathTemplateEnv+haddockTemplateEnv lbi pkg_id =+ (PrefixVar, prefix (installDirTemplates lbi))+ -- We want the legacy unit ID here, because it gives us nice paths+ -- (Haddock people don't care about the dependencies)+ : initialPathTemplateEnv+ pkg_id+ (mkLegacyUnitId pkg_id)+ (compilerInfo (compiler lbi))+ (hostPlatform lbi)++-- ------------------------------------------------------------------------------+-- hscolour support.++hscolour+ :: PackageDescription+ -> LocalBuildInfo+ -> [PPSuffixHandler]+ -> HscolourFlags+ -> IO ()+hscolour = hscolour_setupHooks noBuildHooks++hscolour_setupHooks+ :: BuildHooks+ -> PackageDescription+ -> LocalBuildInfo+ -> [PPSuffixHandler]+ -> HscolourFlags+ -> IO ()+hscolour_setupHooks setupHooks =+ hscolour' setupHooks dieNoVerbosity ForDevelopment++hscolour'+ :: BuildHooks+ -> (String -> IO ())+ -- ^ Called when the 'hscolour' exe is not found.+ -> HaddockTarget+ -> PackageDescription+ -> LocalBuildInfo+ -> [PPSuffixHandler]+ -> HscolourFlags+ -> IO ()+hscolour'+ (BuildHooks{preBuildComponentRules = mbPbcRules})+ onNoHsColour+ haddockTarget+ pkg_descr+ lbi+ suffixes+ flags =+ either (\excep -> onNoHsColour $ exceptionMessage excep) (\(hscolourProg, _, _) -> go hscolourProg)+ =<< lookupProgramVersion+ verbosity+ hscolourProgram+ (orLaterVersion (mkVersion [1, 8]))+ (withPrograms lbi)+ where+ common = hscolourCommonFlags flags+ verbosity = fromFlag $ setupVerbosity common+ distPref = fromFlag $ setupDistPref common+ mbWorkDir = mbWorkDirLBI lbi+ i = interpretSymbolicPathLBI lbi -- See Note [Symbolic paths] in Distribution.Utils.Path+ u :: SymbolicPath Pkg to -> FilePath+ u = interpretSymbolicPathCWD++ go :: ConfiguredProgram -> IO ()+ go hscolourProg = do+ warn verbosity $+ "the 'cabal hscolour' command is deprecated in favour of 'cabal "+ ++ "haddock --hyperlink-source' and will be removed in the next major "+ ++ "release."++ setupMessage verbosity "Running hscolour for" (packageId pkg_descr)+ createDirectoryIfMissingVerbose verbosity True $+ i $+ hscolourPref haddockTarget distPref pkg_descr++ withAllComponentsInBuildOrder pkg_descr lbi $ \comp clbi -> do+ let tgt = TargetInfo clbi comp+ runPreBuildHooks :: LocalBuildInfo -> TargetInfo -> IO ()+ runPreBuildHooks lbi2 target =+ let inputs =+ SetupHooks.PreBuildComponentInputs+ { SetupHooks.buildingWhat = BuildHscolour flags+ , SetupHooks.localBuildInfo = lbi2+ , SetupHooks.targetInfo = target+ }+ in for_ mbPbcRules $ \pbcRules -> do+ (ruleFromId, _mons) <- SetupHooks.computeRules verbosity inputs pbcRules+ SetupHooks.executeRules verbosity lbi2 tgt ruleFromId+ preBuildComponent runPreBuildHooks verbosity lbi tgt+ preprocessComponent pkg_descr comp lbi clbi False verbosity suffixes+ let+ doExe com = case (compToExe com) of+ Just exe -> do+ let outputDir =+ hscolourPref haddockTarget distPref pkg_descr+ </> makeRelativePathEx (unUnqualComponentName (exeName exe) </> "src")+ runHsColour hscolourProg outputDir =<< getExeSourceFiles verbosity lbi exe clbi+ Nothing -> do+ warn verbosity "Unsupported component, skipping..."+ return ()+ case comp of+ CLib lib -> do+ let outputDir = hscolourPref haddockTarget distPref pkg_descr </> makeRelativePathEx "src"+ runHsColour hscolourProg outputDir =<< getLibSourceFiles verbosity lbi lib clbi+ CFLib flib -> do+ let outputDir =+ hscolourPref haddockTarget distPref pkg_descr+ </> makeRelativePathEx+ ( unUnqualComponentName (foreignLibName flib)+ </> "src"+ )+ runHsColour hscolourProg outputDir =<< getFLibSourceFiles verbosity lbi flib clbi+ CExe _ -> when (fromFlag (hscolourExecutables flags)) $ doExe comp+ CTest _ -> when (fromFlag (hscolourTestSuites flags)) $ doExe comp+ CBench _ -> when (fromFlag (hscolourBenchmarks flags)) $ doExe comp++ stylesheet = flagToMaybe (hscolourCSS flags)++ runHsColour+ :: ConfiguredProgram+ -> SymbolicPath Pkg to+ -> [(ModuleName.ModuleName, SymbolicPath Pkg to1)]+ -> IO ()+ runHsColour prog outputDir moduleFiles = do+ createDirectoryIfMissingVerbose verbosity True (i outputDir)++ case stylesheet of -- copy the CSS file+ Nothing+ | programVersion prog >= Just (mkVersion [1, 9]) ->+ runProgramCwd+ verbosity+ mbWorkDir+ prog+ ["-print-css", "-o" ++ u outputDir </> "hscolour.css"]+ | otherwise -> return ()+ Just s -> copyFileVerbose verbosity s (i outputDir </> "hscolour.css")++ for_ moduleFiles $ \(m, inFile) ->+ runProgramCwd+ verbosity+ mbWorkDir+ prog+ ["-css", "-anchor", "-o" ++ outFile m, u inFile]+ where+ outFile m =+ i outputDir+ </> intercalate "-" (ModuleName.components m)+ <.> "html"++haddockToHscolour :: HaddockFlags -> HscolourFlags+haddockToHscolour flags =+ HscolourFlags+ { hscolourCommonFlags = haddockCommonFlags flags+ , hscolourCSS = haddockHscolourCss flags+ , hscolourExecutables = haddockExecutables flags+ , hscolourTestSuites = haddockTestSuites flags+ , hscolourBenchmarks = haddockBenchmarks flags+ , hscolourForeignLibs = haddockForeignLibs flags } -- ------------------------------------------------------------------------------
src/Distribution/Simple/HaskellSuite.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} @@ -129,7 +130,8 @@ -- if we need something like that as well. getInstalledPackages :: Verbosity- -> PackageDBStack+ -- Not migrated to work with --working-dir but this is legacy dead code+ -> PackageDBStackX (SymbolicPath from (Dir PkgDB)) -> ProgramDb -> IO InstalledPackageIndex getInstalledPackages verbosity packagedbs progdb =@@ -179,23 +181,23 @@ let odir = buildDir lbi bi = libBuildInfo lib- srcDirs = map getSymbolicPath (hsSourceDirs bi) ++ [odir]+ srcDirs = map u (hsSourceDirs bi) ++ [u odir] dbStack = withPackageDB lbi language = fromMaybe Haskell98 (defaultLanguage bi) progdb = withPrograms lbi pkgid = packageId pkg_descr-- runDbProgram verbosity haskellSuiteProgram progdb $- ["compile", "--build-dir", odir]+ u = interpretSymbolicPathCWD -- See Note [Symbolic paths] in Distribution.Utils.Path+ runDbProgramCwd verbosity (mbWorkDirLBI lbi) haskellSuiteProgram progdb $+ ["compile", "--build-dir", u odir] ++ concat [["-i", d] | d <- srcDirs] ++ concat [ ["-I", d] | d <-- [ autogenComponentModulesDir lbi clbi- , autogenPackageModulesDir lbi- , odir+ [ u $ autogenComponentModulesDir lbi clbi+ , u $ autogenPackageModulesDir lbi+ , u odir ]- ++ includeDirs bi+ ++ map u (includeDirs bi) ] ++ [packageDbOpt pkgDb | pkgDb <- dbStack] ++ ["--package-name", prettyShow pkgid]@@ -223,7 +225,8 @@ -> IO () installLib verbosity lbi targetDir dynlibTargetDir builtDir pkg lib clbi = do let progdb = withPrograms lbi- runDbProgram verbosity haskellSuitePkgProgram progdb $+ wdir = mbWorkDirLBI lbi+ runDbProgramCwd verbosity wdir haskellSuitePkgProgram progdb $ [ "install-library" , "--build-dir" , builtDir@@ -239,7 +242,7 @@ registerPackage :: Verbosity -> ProgramDb- -> PackageDBStack+ -> PackageDBStackS from -> InstalledPackageInfo -> IO () registerPackage verbosity progdb packageDbs installedPkgInfo = do@@ -261,7 +264,7 @@ progdb ["init", dbPath] -packageDbOpt :: PackageDB -> String+packageDbOpt :: PackageDBX (SymbolicPath from (Dir PkgDB)) -> String packageDbOpt GlobalPackageDB = "--global" packageDbOpt UserPackageDB = "--user"-packageDbOpt (SpecificPackageDB db) = "--package-db=" ++ db+packageDbOpt (SpecificPackageDB db) = "--package-db=" ++ interpretSymbolicPathCWD db
src/Distribution/Simple/Hpc.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RankNTypes #-}@@ -36,7 +37,11 @@ ) import qualified Distribution.PackageDescription as PD import Distribution.Pretty-import Distribution.Simple.LocalBuildInfo (LocalBuildInfo (..))+import Distribution.Simple.LocalBuildInfo+ ( LocalBuildInfo (..)+ , interpretSymbolicPathLBI+ , mbWorkDirLBI+ ) import Distribution.Simple.Program ( hpcProgram , requireProgramVersion@@ -44,64 +49,66 @@ import Distribution.Simple.Program.Hpc (markup, union) import Distribution.Simple.Utils (notice) import Distribution.Types.UnqualComponentName+import Distribution.Utils.Path import Distribution.Verbosity (Verbosity ()) import Distribution.Version (anyVersion)+ import System.Directory (createDirectoryIfMissing, doesFileExist)-import System.FilePath -- ------------------------------------------------------------------------- -- Haskell Program Coverage -data Way = Vanilla | Prof | Dyn+data Way = Vanilla | Prof | Dyn | ProfDyn deriving (Bounded, Enum, Eq, Read, Show) hpcDir- :: FilePath+ :: SymbolicPath Pkg (Dir Dist) -- ^ \"dist/\" prefix -> Way- -> FilePath+ -> SymbolicPath Pkg (Dir Artifacts) -- ^ Directory containing component's HPC .mix files-hpcDir distPref way = distPref </> "hpc" </> wayDir+hpcDir distPref way = distPref </> makeRelativePathEx ("hpc" </> wayDir) where wayDir = case way of Vanilla -> "vanilla" Prof -> "prof" Dyn -> "dyn"+ ProfDyn -> "prof_dyn" mixDir- :: FilePath+ :: SymbolicPath Pkg (Dir Dist) -- ^ \"dist/\" prefix -> Way- -> FilePath+ -> SymbolicPath Pkg (Dir Mix) -- ^ Directory containing test suite's .mix files-mixDir distPref way = hpcDir distPref way </> "mix"+mixDir distPref way = hpcDir distPref way </> makeRelativePathEx "mix" tixDir- :: FilePath+ :: SymbolicPath Pkg (Dir Dist) -- ^ \"dist/\" prefix -> Way- -> FilePath+ -> SymbolicPath Pkg (Dir Tix) -- ^ Directory containing test suite's .tix files-tixDir distPref way = hpcDir distPref way </> "tix"+tixDir distPref way = hpcDir distPref way </> makeRelativePathEx "tix" -- | Path to the .tix file containing a test suite's sum statistics. tixFilePath- :: FilePath+ :: SymbolicPath Pkg (Dir Dist) -- ^ \"dist/\" prefix -> Way -> FilePath -- ^ Component name- -> FilePath+ -> SymbolicPath Pkg File -- ^ Path to test suite's .tix file-tixFilePath distPref way name = tixDir distPref way </> name <.> "tix"+tixFilePath distPref way name = tixDir distPref way </> makeRelativePathEx (name <.> "tix") htmlDir- :: FilePath+ :: SymbolicPath Pkg (Dir Dist) -- ^ \"dist/\" prefix -> Way- -> FilePath+ -> SymbolicPath Pkg (Dir Artifacts) -- ^ Path to test suite's HTML markup directory-htmlDir distPref way = hpcDir distPref way </> "html"+htmlDir distPref way = hpcDir distPref way </> makeRelativePathEx "html" -- | 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.@@ -114,7 +121,7 @@ -- | Haskell Program Coverage information required to produce a valid HPC -- report through the `hpc markup` call for the package libraries. data HPCMarkupInfo = HPCMarkupInfo- { pathsToLibsArtifacts :: [FilePath]+ { pathsToLibsArtifacts :: [SymbolicPath Pkg (Dir Artifacts)] -- ^ The paths to the library components whose modules are included in the -- coverage report , libsModulesToInclude :: [ModuleName]@@ -126,14 +133,16 @@ :: Verbosity -> HPCMarkupInfo -> LocalBuildInfo- -> FilePath+ -> SymbolicPath Pkg (Dir Dist) -- ^ Testsuite \"dist/\" prefix -> PD.PackageDescription -> [TestSuite] -> IO () markupPackage verbosity HPCMarkupInfo{pathsToLibsArtifacts, libsModulesToInclude} lbi testDistPref pkg_descr suites = do let tixFiles = map (tixFilePath testDistPref way) testNames- tixFilesExist <- traverse doesFileExist tixFiles+ mbWorkDir = mbWorkDirLBI lbi+ i = interpretSymbolicPathLBI lbi -- See Note [Symbolic paths] in Distribution.Utils.Path+ tixFilesExist <- traverse (doesFileExist . i) tixFiles when (and tixFilesExist) $ do -- behaviour of 'markup' depends on version, so we need *a* version -- but no particular one@@ -165,16 +174,16 @@ let excluded = concatMap testModules suites ++ [main] pkgName = prettyShow $ PD.package pkg_descr summedTixFile = tixFilePath testDistPref way pkgName- createDirectoryIfMissing True $ takeDirectory summedTixFile- union hpc verbosity tixFiles summedTixFile excluded+ createDirectoryIfMissing True $ i $ takeDirectorySymbolicPath summedTixFile+ union mbWorkDir hpc verbosity tixFiles summedTixFile excluded return summedTixFile - markup hpc hpcVer verbosity tixFile mixDirs htmlDir' libsModulesToInclude+ markup mbWorkDir hpc hpcVer verbosity tixFile mixDirs htmlDir' libsModulesToInclude notice verbosity $ "Package coverage report written to "- ++ htmlDir'+ ++ i htmlDir' </> "hpc_index.html" where way = guessWay lbi testNames = fmap (unUnqualComponentName . testName) suites- mixDirs = map (`mixDir` way) pathsToLibsArtifacts+ mixDirs = map ((`mixDir` way) . coerceSymbolicPath) pathsToLibsArtifacts
src/Distribution/Simple/Install.hs view
@@ -1,4 +1,7 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RankNTypes #-} -----------------------------------------------------------------------------@@ -17,11 +20,15 @@ -- compiler-specific functions to do the rest. module Distribution.Simple.Install ( install+ , install_setupHooks+ , installFileGlob ) where import Distribution.Compat.Prelude import Prelude () +import Distribution.CabalSpecVersion (CabalSpecVersion)+ import Distribution.Types.ExecutableScope import Distribution.Types.ForeignLib import Distribution.Types.LocalBuildInfo@@ -31,40 +38,44 @@ import Distribution.Package import Distribution.PackageDescription-import Distribution.Simple.BuildPaths (haddockName, haddockPref)+import Distribution.Simple.BuildPaths (haddockPath, haddockPref) import Distribution.Simple.BuildTarget import Distribution.Simple.Compiler ( CompilerFlavor (..) , compilerFlavor )-import Distribution.Simple.Flag- ( fromFlag- ) import Distribution.Simple.Glob (matchDirFileGlob) import Distribution.Simple.LocalBuildInfo+import Distribution.Simple.Setup.Config import Distribution.Simple.Setup.Copy ( CopyFlags (..) ) import Distribution.Simple.Setup.Haddock ( HaddockTarget (ForDevelopment) )+import Distribution.Simple.SetupHooks.Internal+ ( InstallHooks (..)+ )+import qualified Distribution.Simple.SetupHooks.Internal as SetupHooks import Distribution.Simple.Utils ( createDirectoryIfMissingVerbose , dieWithException , info , installDirectoryContents , installOrdinaryFile+ , isAbsoluteOnAnyPlatform , isInSearchPath , noticeNoWrap , warn )-import Distribution.Utils.Path (getSymbolicPath)+import Distribution.Utils.Path import Distribution.Compat.Graph (IsNode (..)) import Distribution.Simple.Errors import qualified Distribution.Simple.GHC as GHC import qualified Distribution.Simple.GHCJS as GHCJS import qualified Distribution.Simple.HaskellSuite as HaskellSuite+import Distribution.Simple.Setup.Common import qualified Distribution.Simple.UHC as UHC import System.Directory@@ -72,10 +83,8 @@ , doesFileExist ) import System.FilePath- ( isRelative- , takeDirectory+ ( takeDirectory , takeFileName- , (</>) ) import Distribution.Pretty@@ -96,32 +105,56 @@ -> CopyFlags -- ^ flags sent to copy or install -> IO ()-install pkg_descr lbi flags = do- checkHasLibsOrExes- targets <- readTargetInfos verbosity pkg_descr lbi (copyArgs flags)+install = install_setupHooks SetupHooks.noInstallHooks - copyPackage verbosity pkg_descr lbi distPref copydest+install_setupHooks+ :: InstallHooks+ -> PackageDescription+ -- ^ information from the .cabal file+ -> LocalBuildInfo+ -- ^ information from the configure step+ -> CopyFlags+ -- ^ flags sent to copy or install+ -> IO ()+install_setupHooks+ (InstallHooks{installComponentHook})+ pkg_descr+ lbi+ flags = do+ checkHasLibsOrExes+ targets <- readTargetInfos verbosity pkg_descr lbi (copyTargets flags) - -- It's not necessary to do these in build-order, but it's harmless- withNeededTargetsInBuildOrder' pkg_descr lbi (map nodeKey targets) $ \target ->- let comp = targetComponent target- clbi = targetCLBI target- in copyComponent verbosity pkg_descr lbi comp clbi copydest- where- distPref = fromFlag (copyDistPref flags)- verbosity = fromFlag (copyVerbosity flags)- copydest = fromFlag (copyDest flags)+ copyPackage verbosity pkg_descr lbi distPref copydest - checkHasLibsOrExes =- unless (hasLibs pkg_descr || hasForeignLibs pkg_descr || hasExes pkg_descr) $- warn verbosity "No executables and no library found. Nothing to do."+ -- It's not necessary to do these in build-order, but it's harmless+ withNeededTargetsInBuildOrder' pkg_descr lbi (map nodeKey targets) $ \target -> do+ let comp = targetComponent target+ clbi = targetCLBI target+ copyComponent verbosity pkg_descr lbi comp clbi copydest+ for_ installComponentHook $ \instAction ->+ let inputs =+ SetupHooks.InstallComponentInputs+ { copyFlags = flags+ , localBuildInfo = lbi+ , targetInfo = target+ }+ in instAction inputs+ where+ common = copyCommonFlags flags+ distPref = fromFlag $ setupDistPref common+ verbosity = fromFlag $ setupVerbosity common+ copydest = fromFlag (copyDest flags) + checkHasLibsOrExes =+ unless (hasLibs pkg_descr || hasForeignLibs pkg_descr || hasExes pkg_descr) $+ warn verbosity "No executables and no library found. Nothing to do."+ -- | Copy package global files. copyPackage :: Verbosity -> PackageDescription -> LocalBuildInfo- -> FilePath+ -> SymbolicPath Pkg (Dir Dist) -> CopyDest -> IO () copyPackage verbosity pkg_descr lbi distPref copydest = do@@ -134,17 +167,19 @@ , htmldir = htmlPref , haddockdir = interfacePref } = absoluteInstallCommandDirs pkg_descr lbi (localUnitId lbi) copydest+ mbWorkDir = mbWorkDirLBI lbi+ i = interpretSymbolicPath mbWorkDir -- See Note [Symbolic paths] in Distribution.Utils.Path -- Install (package-global) data files- installDataFiles verbosity pkg_descr dataPref+ installDataFiles verbosity mbWorkDir pkg_descr $ makeSymbolicPath dataPref -- Install (package-global) Haddock files -- TODO: these should be done per-library- docExists <- doesDirectoryExist $ haddockPref ForDevelopment distPref pkg_descr+ docExists <- doesDirectoryExist $ i $ haddockPref ForDevelopment distPref pkg_descr info verbosity ( "directory "- ++ haddockPref ForDevelopment distPref pkg_descr+ ++ getSymbolicPath (haddockPref ForDevelopment distPref pkg_descr) ++ " does exist: " ++ show docExists )@@ -155,7 +190,7 @@ createDirectoryIfMissingVerbose verbosity True htmlPref installDirectoryContents verbosity- (haddockPref ForDevelopment distPref pkg_descr)+ (i $ haddockPref ForDevelopment distPref pkg_descr) htmlPref -- setPermissionsRecursive [Read] htmlPref -- The haddock interface file actually already got installed@@ -164,25 +199,26 @@ -- copy in htmlPref first. let haddockInterfaceFileSrc = haddockPref ForDevelopment distPref pkg_descr- </> haddockName pkg_descr- haddockInterfaceFileDest = interfacePref </> haddockName pkg_descr+ </> makeRelativePathEx (haddockPath pkg_descr)+ haddockInterfaceFileDest = interfacePref </> haddockPath pkg_descr -- We only generate the haddock interface file for libs, So if the -- package consists only of executables there will not be one:- exists <- doesFileExist haddockInterfaceFileSrc+ exists <- doesFileExist $ i haddockInterfaceFileSrc when exists $ do createDirectoryIfMissingVerbose verbosity True interfacePref installOrdinaryFile verbosity- haddockInterfaceFileSrc+ (i haddockInterfaceFileSrc) haddockInterfaceFileDest let lfiles = licenseFiles pkg_descr unless (null lfiles) $ do createDirectoryIfMissingVerbose verbosity True docPref- for_ lfiles $ \lfile' -> do- let lfile :: FilePath- lfile = getSymbolicPath lfile'- installOrdinaryFile verbosity lfile (docPref </> takeFileName lfile)+ for_ lfiles $ \lfile -> do+ installOrdinaryFile+ verbosity+ (i lfile)+ (docPref </> takeFileName (getSymbolicPath lfile)) -- | Copy files associated with a component. copyComponent@@ -199,7 +235,7 @@ , dynlibdir = dynlibPref , includedir = incPref } = absoluteInstallCommandDirs pkg_descr lbi (componentUnitId clbi) copydest- buildPref = componentBuildDir lbi clbi+ buildPref = interpretSymbolicPathLBI lbi $ componentBuildDir lbi clbi case libName lib of LMainLibName -> noticeNoWrap verbosity ("Installing library in " ++ libPref)@@ -230,7 +266,7 @@ { flibdir = flibPref , includedir = incPref } = absoluteComponentInstallDirs pkg_descr lbi (componentUnitId clbi) copydest- buildPref = componentBuildDir lbi clbi+ buildPref = interpretSymbolicPathLBI lbi $ componentBuildDir lbi clbi noticeNoWrap verbosity ("Installing foreign library " ++ unUnqualComponentName (foreignLibName flib) ++ " in " ++ flibPref) installIncludeFiles verbosity (foreignLibBuildInfo flib) lbi buildPref incPref@@ -243,7 +279,7 @@ let installDirs = absoluteComponentInstallDirs pkg_descr lbi (componentUnitId clbi) copydest -- the installers know how to find the actual location of the -- binaries- buildPref = buildDir lbi+ buildPref = interpretSymbolicPathLBI lbi $ buildDir lbi uid = componentUnitId clbi pkgid = packageId pkg_descr binPref@@ -280,29 +316,57 @@ copyComponent _ _ _ (CTest _) _ _ = return () -- | Install the files listed in data-files-installDataFiles :: Verbosity -> PackageDescription -> FilePath -> IO ()-installDataFiles verbosity pkg_descr destDataDir =- for_ (dataFiles pkg_descr) $ \glob -> do- let srcDataDirRaw = dataDir pkg_descr- srcDataDir =- if null srcDataDirRaw- then "."- else srcDataDirRaw- files <- matchDirFileGlob verbosity (specVersion pkg_descr) srcDataDir glob- for_ files $ \file' -> do- let src = srcDataDir </> file'- dst = destDataDir </> file'- createDirectoryIfMissingVerbose verbosity True (takeDirectory dst)- installOrdinaryFile verbosity src dst+installDataFiles+ :: Verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -> PackageDescription+ -> SymbolicPath Pkg (Dir DataDir)+ -> IO ()+installDataFiles verbosity mbWorkDir pkg_descr destDataDir =+ traverse_+ (installFileGlob verbosity (specVersion pkg_descr) mbWorkDir (srcDataDir, destDataDir))+ (dataFiles pkg_descr)+ where+ srcDataDirRaw = getSymbolicPath $ dataDir pkg_descr+ srcDataDir :: Maybe (SymbolicPath CWD (Dir DataDir))+ srcDataDir+ | null srcDataDirRaw =+ Nothing+ | isAbsoluteOnAnyPlatform srcDataDirRaw =+ Just $ makeSymbolicPath srcDataDirRaw+ | otherwise =+ Just $ fromMaybe sameDirectory mbWorkDir </> makeRelativePathEx srcDataDirRaw +-- | Install the files specified by the given glob pattern.+installFileGlob+ :: Verbosity+ -> CabalSpecVersion+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -> (Maybe (SymbolicPath CWD (Dir DataDir)), SymbolicPath Pkg (Dir DataDir))+ -- ^ @(src_dir, dest_dir)@+ -> RelativePath DataDir File+ -- ^ file glob pattern+ -> IO ()+installFileGlob verbosity spec_version mbWorkDir (srcDir, destDir) glob = do+ files <- matchDirFileGlob verbosity spec_version srcDir glob+ for_ files $ \file' -> do+ let src = getSymbolicPath (fromMaybe sameDirectory srcDir </> file')+ dst = interpretSymbolicPath mbWorkDir (destDir </> file')+ createDirectoryIfMissingVerbose verbosity True (takeDirectory dst)+ installOrdinaryFile verbosity src dst+ -- | Install the files listed in install-includes for a library installIncludeFiles :: Verbosity -> BuildInfo -> LocalBuildInfo -> FilePath -> FilePath -> IO () installIncludeFiles verbosity libBi lbi buildPref destIncludeDir = do- let relincdirs = "." : filter isRelative (includeDirs libBi)+ let relincdirs = sameDirectory : mapMaybe symbolicPathRelative_maybe (includeDirs libBi) incdirs =- [baseDir lbi </> dir | dir <- relincdirs]- ++ [buildPref </> dir | dir <- relincdirs]- incs <- traverse (findInc incdirs) (installIncludes libBi)+ [ root </> getSymbolicPath dir+ | -- NB: both baseDir and buildPref are already interpreted,+ -- so we don't need to interpret these paths in the call to findInc.+ dir <- relincdirs+ , root <- [baseDir lbi, buildPref]+ ]+ incs <- traverse (findInc incdirs . getSymbolicPath) (installIncludes libBi) sequence_ [ do createDirectoryIfMissingVerbose verbosity True destDir@@ -312,7 +376,7 @@ destDir = takeDirectory destFile ] where- baseDir lbi' = fromMaybe "" (takeDirectory <$> cabalFilePath lbi')+ baseDir lbi' = packageRoot $ configCommonFlags $ configFlags lbi' findInc [] file = dieWithException verbosity $ CantFindIncludeFile file findInc (dir : dirs) file = do let path = dir </> file
src/Distribution/Simple/InstallDirs.hs view
@@ -344,6 +344,8 @@ CopyToDb FilePath deriving (Eq, Show, Generic) +-- TODO: are these paths absolute or relative? Relative to what?+ instance Binary CopyDest instance Structured CopyDest
src/Distribution/Simple/LocalBuildInfo.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE FlexibleContexts #-}@@ -29,9 +30,13 @@ -- * Convenience accessors , buildDir- , cabalFilePath+ , packageRoot , progPrefix , progSuffix+ , interpretSymbolicPathLBI+ , mbWorkDirLBI+ , absoluteWorkingDirLBI+ , buildWays -- * Buildable package components , Component (..)@@ -91,6 +96,7 @@ import Distribution.PackageDescription import Distribution.Pretty import Distribution.Simple.Compiler+import Distribution.Simple.Flag import Distribution.Simple.InstallDirs hiding ( absoluteInstallDirs , prefixRelativeInstallDirs@@ -98,36 +104,67 @@ ) import qualified Distribution.Simple.InstallDirs as InstallDirs import Distribution.Simple.PackageIndex+import Distribution.Simple.Setup.Common+import Distribution.Simple.Setup.Config import Distribution.Simple.Utils+import Distribution.Utils.Path import Data.List (stripPrefix)-import System.FilePath--import System.Directory (canonicalizePath, doesDirectoryExist)+import qualified System.Directory as Directory+ ( canonicalizePath+ , doesDirectoryExist+ ) -- ----------------------------------------------------------------------------- -- Configuration information of buildable components -componentBuildDir :: LocalBuildInfo -> ComponentLocalBuildInfo -> FilePath+componentBuildDir :: LocalBuildInfo -> ComponentLocalBuildInfo -> SymbolicPath Pkg (Dir Build) -- For now, we assume that libraries/executables/test-suites/benchmarks -- are only ever built once. With Backpack, we need a special case for -- libraries so that we can handle building them multiple times. componentBuildDir lbi clbi =- buildDir lbi- </> case componentLocalName clbi of- CLibName LMainLibName ->- if prettyShow (componentUnitId clbi) == prettyShow (componentComponentId clbi)- then ""- else prettyShow (componentUnitId clbi)- CLibName (LSubLibName s) ->- if prettyShow (componentUnitId clbi) == prettyShow (componentComponentId clbi)- then unUnqualComponentName s- else prettyShow (componentUnitId clbi)- CFLibName s -> unUnqualComponentName s- CExeName s -> unUnqualComponentName s- CTestName s -> unUnqualComponentName s- CBenchName s -> unUnqualComponentName s+ (buildDir lbi </>) $+ makeRelativePathEx $+ case componentLocalName clbi of+ CLibName LMainLibName ->+ if prettyShow (componentUnitId clbi) == prettyShow (componentComponentId clbi)+ then ""+ else prettyShow (componentUnitId clbi)+ CLibName (LSubLibName s) ->+ if prettyShow (componentUnitId clbi) == prettyShow (componentComponentId clbi)+ then unUnqualComponentName s+ else prettyShow (componentUnitId clbi)+ CFLibName s -> unUnqualComponentName s+ CExeName s -> unUnqualComponentName s+ CTestName s -> unUnqualComponentName s+ CBenchName s -> unUnqualComponentName s +-- | Interpret a symbolic path with respect to the working directory+-- stored in 'LocalBuildInfo'.+--+-- Use this before directly interacting with the file system.+--+-- NB: when invoking external programs (such as @GHC@), it is preferable to set+-- the working directory of the process rather than calling this function, as+-- this function will turn relative paths into absolute paths if the working+-- directory is an absolute path. This can degrade error messages, or worse,+-- break the behaviour entirely (because the program might expect certain paths+-- to be relative).+--+-- See Note [Symbolic paths] in Distribution.Utils.Path+interpretSymbolicPathLBI :: LocalBuildInfo -> SymbolicPathX allowAbsolute Pkg to -> FilePath+interpretSymbolicPathLBI lbi =+ interpretSymbolicPath (mbWorkDirLBI lbi)++-- | Retrieve an optional working directory from 'LocalBuildInfo'.+mbWorkDirLBI :: LocalBuildInfo -> Maybe (SymbolicPath CWD (Dir Pkg))+mbWorkDirLBI =+ flagToMaybe . setupWorkingDir . configCommonFlags . configFlags++-- | Absolute path to the current working directory.+absoluteWorkingDirLBI :: LocalBuildInfo -> IO (AbsolutePath (Dir Pkg))+absoluteWorkingDirLBI lbi = absoluteWorkingDir (mbWorkDirLBI lbi)+ -- | Perform the action on each enabled 'library' in the package -- description with the 'ComponentLocalBuildInfo'. withLibLBI@@ -272,7 +309,7 @@ internalLibs = map getLibDir internalCLBIs -} getLibDir sub_clbi- | inplace = componentBuildDir lbi sub_clbi+ | inplace = interpretSymbolicPathLBI lbi $ componentBuildDir lbi sub_clbi | otherwise = dynlibdir (absoluteComponentInstallDirs pkgDescr lbi (componentUnitId sub_clbi) NoCopyDest) -- Why do we go through all the trouble of a hand-crafting@@ -318,9 +355,9 @@ -- '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+ exists <- Directory.doesDirectoryExist p if exists- then canonicalizePath p+ then Directory.canonicalizePath p else return p -- | Get all module names that needed to be built by GHC; i.e., all
src/Distribution/Simple/PackageDescription.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE DataKinds #-}+ ----------------------------------------------------------------------------- -- |@@ -37,15 +39,29 @@ ) import Distribution.Simple.Errors import Distribution.Simple.Utils (dieWithException, equating, warn)+import Distribution.Utils.Path import Distribution.Verbosity (Verbosity, normal)+import GHC.Stack import System.Directory (doesFileExist) import Text.Printf (printf) -readGenericPackageDescription :: Verbosity -> FilePath -> IO GenericPackageDescription-readGenericPackageDescription = readAndParseFile parseGenericPackageDescription+readGenericPackageDescription+ :: HasCallStack+ => Verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -> SymbolicPath Pkg File+ -> IO GenericPackageDescription+readGenericPackageDescription =+ readAndParseFile parseGenericPackageDescription -readHookedBuildInfo :: Verbosity -> FilePath -> IO HookedBuildInfo-readHookedBuildInfo = readAndParseFile parseHookedBuildInfo+readHookedBuildInfo+ :: Verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -- ^ working directory+ -> SymbolicPath Pkg File+ -> IO HookedBuildInfo+readHookedBuildInfo =+ readAndParseFile parseHookedBuildInfo -- | Helper combinator to do parsing plumbing for files. --@@ -58,16 +74,20 @@ -- ^ File contents to final value parser -> Verbosity -- ^ Verbosity level- -> FilePath+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -- ^ Working directory+ -> SymbolicPath Pkg File -- ^ File to read -> IO a-readAndParseFile parser verbosity fpath = do- exists <- doesFileExist fpath+readAndParseFile parser verbosity mbWorkDir fpath = do+ let ipath = interpretSymbolicPath mbWorkDir fpath+ upath = getSymbolicPath fpath+ exists <- doesFileExist ipath unless exists $ dieWithException verbosity $- ErrorParsingFileDoesntExist fpath- bs <- BS.readFile fpath- parseString parser verbosity fpath bs+ ErrorParsingFileDoesntExist upath+ bs <- BS.readFile ipath+ parseString parser verbosity upath bs parseString :: (BS.ByteString -> ParseResult a)
src/Distribution/Simple/PreProcess.hs view
@@ -1,5 +1,7 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeApplications #-} ----------------------------------------------------------------------------- @@ -22,6 +24,7 @@ module Distribution.Simple.PreProcess ( preprocessComponent , preprocessExtras+ , preprocessFile , knownSuffixHandlers , ppSuffixes , PPSuffixHandler@@ -51,7 +54,6 @@ import Distribution.Backpack.DescribeUnitId import qualified Distribution.InstalledPackageInfo as Installed import Distribution.ModuleName (ModuleName)-import qualified Distribution.ModuleName as ModuleName import Distribution.Package import Distribution.PackageDescription as PD import Distribution.Simple.BuildPaths@@ -71,16 +73,14 @@ import Distribution.Utils.Path import Distribution.Verbosity import Distribution.Version+ import System.Directory (doesDirectoryExist, doesFileExist) import System.FilePath- ( dropExtensions- , normalise+ ( normalise , replaceExtension , splitExtension , takeDirectory , takeExtensions- , (<.>)- , (</>) ) import System.Info (arch, os) @@ -89,7 +89,7 @@ -- between modules. unsorted :: Verbosity- -> [FilePath]+ -> [path] -> [ModuleName] -> IO [ModuleName] unsorted _ _ ms = pure ms@@ -98,7 +98,10 @@ -- preprocessor: just takes the path to the build directory and uses -- this to search for C sources with names that match the -- preprocessor's output name format.-type PreProcessorExtras = FilePath -> IO [FilePath]+type PreProcessorExtras =+ Maybe (SymbolicPath CWD (Dir Pkg))+ -> SymbolicPath Pkg (Dir Source)+ -> IO [RelativePath Source File] mkSimplePreProcessor :: (FilePath -> FilePath -> Verbosity -> IO ())@@ -157,58 +160,51 @@ case comp of (CLib lib@Library{libBuildInfo = bi}) -> do let dirs =- map getSymbolicPath (hsSourceDirs bi)+ hsSourceDirs bi ++ [autogenComponentModulesDir lbi clbi, autogenPackageModulesDir lbi] let hndlrs = localHandlers bi mods <- orderingFromHandlers verbosity dirs hndlrs (allLibModules lib clbi)- for_ (map ModuleName.toFilePath mods) $+ for_ (map moduleNameSymbolicPath mods) $ pre dirs (componentBuildDir lbi clbi) hndlrs- (CFLib flib@ForeignLib{foreignLibBuildInfo = bi, foreignLibName = nm}) -> do- let nm' = unUnqualComponentName nm- let flibDir = buildDir lbi </> nm' </> nm' ++ "-tmp"+ (CFLib flib@ForeignLib{foreignLibBuildInfo = bi}) -> do+ let flibDir = flibBuildDir lbi flib dirs =- map getSymbolicPath (hsSourceDirs bi)+ hsSourceDirs bi ++ [ autogenComponentModulesDir lbi clbi , autogenPackageModulesDir lbi ] let hndlrs = localHandlers bi mods <- orderingFromHandlers verbosity dirs hndlrs (foreignLibModules flib)- for_ (map ModuleName.toFilePath mods) $+ for_ (map moduleNameSymbolicPath mods) $ pre dirs flibDir hndlrs- (CExe exe@Executable{buildInfo = bi, exeName = nm}) -> do- let nm' = unUnqualComponentName nm- let exeDir = buildDir lbi </> nm' </> nm' ++ "-tmp"+ (CExe exe@Executable{buildInfo = bi}) -> do+ let exeDir = exeBuildDir lbi exe dirs =- map getSymbolicPath (hsSourceDirs bi)+ hsSourceDirs bi ++ [ autogenComponentModulesDir lbi clbi , autogenPackageModulesDir lbi ] let hndlrs = localHandlers bi mods <- orderingFromHandlers verbosity dirs hndlrs (otherModules bi)- for_ (map ModuleName.toFilePath mods) $+ for_ (map moduleNameSymbolicPath mods) $ pre dirs exeDir hndlrs- pre (map getSymbolicPath (hsSourceDirs bi)) exeDir (localHandlers bi) $- dropExtensions (modulePath exe)- CTest test@TestSuite{testName = nm} -> do- let nm' = unUnqualComponentName nm+ pre (hsSourceDirs bi) exeDir (localHandlers bi) $+ dropExtensionsSymbolicPath (modulePath exe)+ CTest test@TestSuite{} -> do+ let testDir = testBuildDir lbi test case testInterface test of TestSuiteExeV10 _ f ->- preProcessTest test f $ buildDir lbi </> nm' </> nm' ++ "-tmp"+ preProcessTest test f testDir TestSuiteLibV09 _ _ -> do- let testDir =- buildDir lbi- </> stubName test- </> stubName test- ++ "-tmp"- writeSimpleTestStub test testDir- preProcessTest test (stubFilePath test) testDir+ writeSimpleTestStub test (i testDir)+ preProcessTest test (makeRelativePathEx $ stubFilePath test) testDir TestSuiteUnsupported tt -> dieWithException verbosity $ NoSupportForPreProcessingTest tt- CBench bm@Benchmark{benchmarkName = nm} -> do- let nm' = unUnqualComponentName nm+ CBench bm@Benchmark{} -> do+ let benchDir = benchmarkBuildDir lbi bm case benchmarkInterface bm of BenchmarkExeV10 _ f ->- preProcessBench bm f $ buildDir lbi </> nm' </> nm' ++ "-tmp"+ preProcessBench bm f benchDir BenchmarkUnsupported tt -> dieWithException verbosity $ NoSupportForPreProcessingBenchmark tt where@@ -217,8 +213,10 @@ builtinCSuffixes = map Suffix cSourceExtensions builtinSuffixes = builtinHaskellSuffixes ++ builtinCSuffixes localHandlers bi = [(ext, h bi lbi clbi) | (ext, h) <- handlers]+ mbWorkDir = mbWorkDirLBI lbi+ i = interpretSymbolicPathLBI lbi -- See Note [Symbolic paths] in Distribution.Utils.Path pre dirs dir lhndlrs fp =- preprocessFile (map unsafeMakeSymbolicPath dirs) dir isSrcDist fp verbosity builtinSuffixes lhndlrs True+ preprocessFile mbWorkDir dirs dir isSrcDist fp verbosity builtinSuffixes lhndlrs True preProcessTest test = preProcessComponent (testBuildInfo test)@@ -231,36 +229,37 @@ preProcessComponent :: BuildInfo -> [ModuleName]- -> FilePath- -> FilePath+ -> RelativePath Source File+ -> SymbolicPath Pkg (Dir Build) -> IO ()- preProcessComponent bi modules exePath dir = do+ preProcessComponent bi modules exePath outputDir = do let biHandlers = localHandlers bi sourceDirs =- map getSymbolicPath (hsSourceDirs bi)+ hsSourceDirs bi ++ [ autogenComponentModulesDir lbi clbi , autogenPackageModulesDir lbi ] sequence_ [ preprocessFile- (map unsafeMakeSymbolicPath sourceDirs)- dir+ mbWorkDir+ sourceDirs+ outputDir isSrcDist- (ModuleName.toFilePath modu)+ (moduleNameSymbolicPath modu) verbosity builtinSuffixes biHandlers False | modu <- modules ]- -- XXX: what we do here (re SymbolicPath dir)- -- XXX: 2020-10-15 do we rely here on CWD being the PackageDir?- -- Note we don't fail on missing in this case, because the main file may be generated later (i.e. by a test code generator)+ -- Note we don't fail on missing in this case, because the main file+ -- may be generated later (i.e. by a test code generator) preprocessFile- (unsafeMakeSymbolicPath dir : hsSourceDirs bi)- dir+ mbWorkDir+ (coerceSymbolicPath outputDir : hsSourceDirs bi)+ outputDir isSrcDist- (dropExtensions $ exePath)+ (dropExtensionsSymbolicPath $ exePath) verbosity builtinSuffixes biHandlers@@ -273,13 +272,15 @@ -- | Find the first extension of the file that exists, and preprocess it -- if required. preprocessFile- :: [SymbolicPath PackageDir SourceDir]+ :: Maybe (SymbolicPath CWD (Dir Pkg))+ -- ^ package directory location+ -> [SymbolicPath Pkg (Dir Source)] -- ^ source directories- -> FilePath+ -> SymbolicPath Pkg (Dir Build) -- ^ build directory -> Bool -- ^ preprocess for sdist- -> FilePath+ -> RelativePath Source File -- ^ module file name -> Verbosity -- ^ verbosity@@ -290,32 +291,35 @@ -> Bool -- ^ fail on missing file -> IO ()-preprocessFile searchLoc buildLoc forSDist baseFile verbosity builtinSuffixes handlers failOnMissing = do+preprocessFile mbWorkDir searchLoc buildLoc forSDist baseFile verbosity builtinSuffixes handlers failOnMissing = do -- look for files in the various source dirs with this module name -- and a file extension of a known preprocessor- psrcFiles <- findFileWithExtension' (map fst handlers) (map getSymbolicPath searchLoc) baseFile+ psrcFiles <- findFileCwdWithExtension' mbWorkDir (map fst handlers) searchLoc baseFile case psrcFiles of -- no preprocessor file exists, look for an ordinary source file -- just to make sure one actually exists at all for this module.- -- Note: by looking in the target/output build dir too, we allow++ -- Note [Dodgy build dirs for preprocessors]+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ -- By looking in the target/output build dir too, we allow -- source files to appear magically in the target build dir without -- any corresponding "real" source file. This lets custom Setup.hs -- files generate source modules directly into the build dir without -- the rest of the build system being aware of it (somewhat dodgy) Nothing -> do- bsrcFiles <- findFileWithExtension builtinSuffixes (buildLoc : map getSymbolicPath searchLoc) baseFile+ bsrcFiles <- findFileCwdWithExtension mbWorkDir builtinSuffixes (buildAsSrcLoc : searchLoc) baseFile case (bsrcFiles, failOnMissing) of (Nothing, True) -> dieWithException verbosity $ CantFindSourceForPreProcessFile $ "can't find source for "- ++ baseFile+ ++ getSymbolicPath baseFile ++ " in " ++ intercalate ", " (map getSymbolicPath searchLoc) _ -> return () -- found a pre-processable file in one of the source dirs Just (psrcLoc, psrcRelFile) -> do- let (srcStem, ext) = splitExtension psrcRelFile+ let (srcStem, ext) = splitExtension $ getSymbolicPath psrcRelFile psrcFile = psrcLoc </> psrcRelFile pp = fromMaybe@@ -333,20 +337,22 @@ when (not forSDist || forSDist && platformIndependent pp) $ do -- look for existing pre-processed source file in the dest dir to -- see if we really have to re-run the preprocessor.- ppsrcFiles <- findFileWithExtension builtinSuffixes [buildLoc] baseFile+ ppsrcFiles <- findFileCwdWithExtension mbWorkDir builtinSuffixes [buildAsSrcLoc] baseFile recomp <- case ppsrcFiles of Nothing -> return True Just ppsrcFile ->- psrcFile `moreRecentFile` ppsrcFile+ i psrcFile `moreRecentFile` i ppsrcFile when recomp $ do- let destDir = buildLoc </> dirName srcStem+ let destDir = i buildLoc </> takeDirectory srcStem createDirectoryIfMissingVerbose verbosity True destDir runPreProcessorWithHsBootHack pp- (psrcLoc, psrcRelFile)- (buildLoc, srcStem <.> "hs")+ (getSymbolicPath $ psrcLoc, getSymbolicPath $ psrcRelFile)+ (getSymbolicPath $ buildLoc, srcStem <.> "hs") where- dirName = takeDirectory+ i = interpretSymbolicPath mbWorkDir -- See Note [Symbolic paths] in Distribution.Utils.Path+ buildAsSrcLoc :: SymbolicPath Pkg (Dir Source)+ buildAsSrcLoc = coerceSymbolicPath buildLoc -- FIXME: This is a somewhat nasty hack. GHC requires that hs-boot files -- be in the same place as the hs files, so if we put the hs file in dist/@@ -384,8 +390,9 @@ { platformIndependent = False , ppOrdering = unsorted , runPreProcessor = mkSimplePreProcessor $ \inFile outFile verbosity ->- runDbProgram+ runDbProgramCwd verbosity+ (mbWorkDirLBI lbi) greencardProgram (withPrograms lbi) (["-tffi", "-o" ++ outFile, inFile])@@ -435,7 +442,7 @@ program anyVersion (withPrograms lbi)- runProgram verbosity prog $+ runProgramCwd verbosity (mbWorkDirLBI lbi) prog $ ["-E", "-cpp"] -- This is a bit of an ugly hack. We're going to -- unlit the file ourselves later on if appropriate,@@ -443,10 +450,14 @@ -- double-unlitted. In the future we might switch to -- using cpphs --unlit instead. ++ (if xHs version then ["-x", "hs"] else [])- ++ ["-optP-include", "-optP" ++ (autogenComponentModulesDir lbi clbi </> cppHeaderName)]+ ++ ["-optP-include", "-optP" ++ u (autogenComponentModulesDir lbi clbi </> makeRelativePathEx cppHeaderName)] ++ ["-o", outFile, inFile] ++ extraArgs }+ where+ -- See Note [Symbolic paths] in Distribution.Utils.Path+ u :: SymbolicPath Pkg to -> FilePath+ u = interpretSymbolicPathCWD ppCpphs :: [String] -> BuildInfo -> LocalBuildInfo -> ComponentLocalBuildInfo -> PreProcessor ppCpphs extraArgs _bi lbi clbi =@@ -460,17 +471,21 @@ cpphsProgram anyVersion (withPrograms lbi)- runProgram verbosity cpphsProg $+ runProgramCwd verbosity (mbWorkDirLBI lbi) cpphsProg $ ("-O" ++ outFile) : inFile : "--noline" : "--strip" : ( if cpphsVersion >= mkVersion [1, 6]- then ["--include=" ++ (autogenComponentModulesDir lbi clbi </> cppHeaderName)]+ then ["--include=" ++ u (autogenComponentModulesDir lbi clbi </> makeRelativePathEx cppHeaderName)] else [] ) ++ extraArgs }+ where+ -- See Note [Symbolic paths] in Distribution.Utils.Path+ u :: SymbolicPath Pkg to -> FilePath+ u = interpretSymbolicPathCWD ppHsc2hs :: BuildInfo -> LocalBuildInfo -> ComponentLocalBuildInfo -> PreProcessor ppHsc2hs bi lbi clbi =@@ -485,6 +500,7 @@ hsc2hsProgram anyVersion (withPrograms lbi)+ let runHsc2hs = runProgramCwd verbosity mbWorkDir hsc2hsProg -- See Trac #13896 and https://github.com/haskell/cabal/issues/3122. let isCross = hostPlatform lbi /= buildPlatform prependCrossFlags = if isCross then ("-x" :) else id@@ -495,16 +511,22 @@ withResponseFile verbosity defaultTempFileOptions- (takeDirectory outFile)+ mbWorkDir+ (makeSymbolicPath $ takeDirectory outFile) "hsc2hs-response.txt" Nothing pureArgs ( \responseFileName ->- runProgram verbosity hsc2hsProg (prependCrossFlags ["@" ++ responseFileName])+ runHsc2hs (prependCrossFlags ["@" ++ responseFileName]) )- else runProgram verbosity hsc2hsProg (prependCrossFlags pureArgs)+ else runHsc2hs (prependCrossFlags pureArgs) } where+ -- See Note [Symbolic paths] in Distribution.Utils.Path+ u :: SymbolicPathX allowAbs Pkg to -> FilePath+ u = interpretSymbolicPathCWD+ mbWorkDir = mbWorkDirLBI lbi+ -- Returns a list of command line arguments that can either be passed -- directly, or via a response file. genPureArgs :: Version -> ConfiguredProgram -> String -> String -> [String]@@ -528,7 +550,7 @@ ] ++ [ "--lflag=" ++ arg | isOSX- , opt <- PD.frameworks bi ++ concatMap Installed.frameworks pkgs+ , opt <- map getSymbolicPath (PD.frameworks bi) ++ concatMap Installed.frameworks pkgs , arg <- ["-framework", opt] ] -- Note that on ELF systems, wherever we use -L, we must also use -R@@ -538,8 +560,10 @@ ++ ["--cflag=" ++ opt | opt <- platformDefines lbi] -- Options from the current package:- ++ ["--cflag=-I" ++ dir | dir <- PD.includeDirs bi]- ++ ["--cflag=-I" ++ buildDir lbi </> dir | dir <- PD.includeDirs bi]+ ++ ["--cflag=-I" ++ u dir | dir <- PD.includeDirs bi]+ ++ [ "--cflag=-I" ++ u (buildDir lbi </> unsafeCoerceSymbolicPath relDir)+ | relDir <- mapMaybe symbolicPathRelative_maybe $ PD.includeDirs bi+ ] ++ [ "--cflag=" ++ opt | opt <- PD.ccOptions bi@@ -555,19 +579,19 @@ ] ++ [ "--cflag=" ++ opt | opt <-- [ "-I" ++ autogenComponentModulesDir lbi clbi- , "-I" ++ autogenPackageModulesDir lbi+ [ "-I" ++ u (autogenComponentModulesDir lbi clbi)+ , "-I" ++ u (autogenPackageModulesDir lbi) , "-include"- , autogenComponentModulesDir lbi clbi </> cppHeaderName+ , u $ autogenComponentModulesDir lbi clbi </> makeRelativePathEx cppHeaderName ] ]- ++ [ "--lflag=-L" ++ opt+ ++ [ "--lflag=-L" ++ u opt | opt <- if withFullyStaticExe lbi then PD.extraLibDirsStatic bi else PD.extraLibDirs bi ]- ++ [ "--lflag=-Wl,-R," ++ opt+ ++ [ "--lflag=-Wl,-R," ++ u opt | isELF , opt <- if withFullyStaticExe lbi@@ -643,9 +667,10 @@ _ -> error "No (or multiple) ghc rts package is registered!!" ppHsc2hsExtras :: PreProcessorExtras-ppHsc2hsExtras buildBaseDir =- filter ("_hsc.c" `isSuffixOf`)- `fmap` getDirectoryContentsRecursive buildBaseDir+ppHsc2hsExtras mbWorkDir buildBaseDir = do+ fs <- getDirectoryContentsRecursive $ interpretSymbolicPath mbWorkDir buildBaseDir+ let hscCFiles = filter ("_hsc.c" `isSuffixOf`) fs+ return $ map makeRelativePathEx hscCFiles ppC2hs :: BuildInfo -> LocalBuildInfo -> ComponentLocalBuildInfo -> PreProcessor ppC2hs bi lbi clbi =@@ -663,11 +688,11 @@ (orLaterVersion (mkVersion [0, 15])) (withPrograms lbi) (gccProg, _) <- requireProgram verbosity gccProgram (withPrograms lbi)- runProgram verbosity c2hsProg $+ runProgramCwd verbosity mbWorkDir c2hsProg $ -- Options from the current package: ["--cpp=" ++ programPath gccProg, "--cppopts=-E"] ++ ["--cppopts=" ++ opt | opt <- getCppOptions bi lbi]- ++ ["--cppopts=-include" ++ (autogenComponentModulesDir lbi clbi </> cppHeaderName)]+ ++ ["--cppopts=-include" ++ u (autogenComponentModulesDir lbi clbi </> makeRelativePathEx cppHeaderName)] ++ ["--include=" ++ outBaseDir] -- Options from dependent packages ++ [ "--cppopts=" ++ opt@@ -698,11 +723,17 @@ } where pkgs = PackageIndex.topologicalOrder (installedPkgs lbi)+ mbWorkDir = mbWorkDirLBI lbi+ -- See Note [Symbolic paths] in Distribution.Utils.Path+ u :: SymbolicPath Pkg to -> FilePath+ u = interpretSymbolicPathCWD ppC2hsExtras :: PreProcessorExtras-ppC2hsExtras d =- filter (\p -> takeExtensions p == ".chs.c")- `fmap` getDirectoryContentsRecursive d+ppC2hsExtras mbWorkDir buildBaseDir = do+ fs <- getDirectoryContentsRecursive $ interpretSymbolicPath mbWorkDir buildBaseDir+ return $+ map makeRelativePathEx $+ filter (\p -> takeExtensions p == ".chs.c") fs -- TODO: perhaps use this with hsc2hs too -- TODO: remove cc-options from cpphs for cabal-version: >= 1.10@@ -713,7 +744,7 @@ getCppOptions bi lbi = platformDefines lbi ++ cppOptions bi- ++ ["-I" ++ dir | dir <- PD.includeDirs bi]+ ++ ["-I" ++ getSymbolicPath dir | dir <- PD.includeDirs bi] ++ [opt | opt@('-' : c : _) <- PD.ccOptions bi ++ PD.cxxOptions bi, c `elem` "DIU"] platformDefines :: LocalBuildInfo -> [String]@@ -833,8 +864,9 @@ { platformIndependent = False , ppOrdering = unsorted , runPreProcessor = mkSimplePreProcessor $ \inFile outFile verbosity ->- runDbProgram+ runDbProgramCwd verbosity+ (mbWorkDirLBI lbi) prog (withPrograms lbi) (args ++ ["-o", outFile, inFile])@@ -866,41 +898,37 @@ :: Verbosity -> Component -> LocalBuildInfo- -> IO [FilePath]+ -> IO [SymbolicPath Pkg File] preprocessExtras verbosity comp lbi = case comp of CLib _ -> pp $ buildDir lbi- (CExe Executable{exeName = nm}) -> do- let nm' = unUnqualComponentName nm- pp $ buildDir lbi </> nm' </> nm' ++ "-tmp"- (CFLib ForeignLib{foreignLibName = nm}) -> do- let nm' = unUnqualComponentName nm- pp $ buildDir lbi </> nm' </> nm' ++ "-tmp"- CTest test -> do- let nm' = unUnqualComponentName $ testName test+ (CExe exe@Executable{}) -> pp $ exeBuildDir lbi exe+ (CFLib flib@ForeignLib{}) -> pp $ flibBuildDir lbi flib+ CTest test -> case testInterface test of- TestSuiteExeV10 _ _ ->- pp $ buildDir lbi </> nm' </> nm' ++ "-tmp"- TestSuiteLibV09 _ _ ->- pp $ buildDir lbi </> stubName test </> stubName test ++ "-tmp" TestSuiteUnsupported tt -> dieWithException verbosity $ NoSupportPreProcessingTestExtras tt- CBench bm -> do- let nm' = unUnqualComponentName $ benchmarkName bm+ _ -> pp $ testBuildDir lbi test+ CBench bm -> case benchmarkInterface bm of- BenchmarkExeV10 _ _ ->- pp $ buildDir lbi </> nm' </> nm' ++ "-tmp" BenchmarkUnsupported tt -> dieWithException verbosity $ NoSupportPreProcessingBenchmarkExtras tt+ _ -> pp $ benchmarkBuildDir lbi bm where- pp :: FilePath -> IO [FilePath]- pp dir = do- b <- doesDirectoryExist dir+ pp :: SymbolicPath Pkg (Dir Build) -> IO [SymbolicPath Pkg File]+ pp builddir = do+ -- Use the build dir as a source dir.+ let dir :: SymbolicPath Pkg (Dir Source)+ dir = coerceSymbolicPath builddir+ mbWorkDir = mbWorkDirLBI lbi+ b <- doesDirectoryExist (interpretSymbolicPathLBI lbi dir) if b- then- (map (dir </>) . filter not_sub . concat)- <$> for- knownExtrasHandlers- (withLexicalCallStack (\f -> f dir))+ then do+ xs <- for knownExtrasHandlers $ withLexicalCallStack $ \f -> f mbWorkDir dir+ let not_subs =+ map (dir </>) $+ filter (not_sub . getSymbolicPath) $+ concat xs+ return not_subs else pure [] -- TODO: This is a terrible hack to work around #3545 while we don't -- reorganize the directory layout. Basically, for the main
src/Distribution/Simple/PreProcess/Types.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}@@ -18,6 +19,7 @@ module Distribution.Simple.PreProcess.Types ( Suffix (..) , PreProcessor (..)+ , PreProcessCommand , builtinHaskellSuffixes , builtinHaskellBootSuffixes )@@ -28,6 +30,7 @@ import Distribution.ModuleName (ModuleName) import Distribution.Pretty+import Distribution.Utils.Path import Distribution.Verbosity import qualified Text.PrettyPrint as Disp @@ -78,7 +81,7 @@ ppOrdering :: Verbosity- -> [FilePath] -- Source directories+ -> [SymbolicPath Pkg (Dir Source)] -- Source directories -> [ModuleName] -- Module names -> IO [ModuleName] -- Sorted modules @@ -88,11 +91,21 @@ -- -- @since 3.8.1.0 , runPreProcessor- :: (FilePath, FilePath) -- Location of the source file relative to a base dir- -> (FilePath, FilePath) -- Output file name, relative to an output base dir- -> Verbosity -- verbosity- -> IO () -- Should exit if the preprocessor fails+ :: PreProcessCommand }++-- | A command to run a given preprocessor on a single source file.+--+-- The input and output file paths are passed in as arguments, as it is+-- the build system and not the package author which chooses the location of+-- source files.+type PreProcessCommand =+ (FilePath, FilePath)+ -- ^ Location of the source file relative to a base dir+ -> (FilePath, FilePath)+ -- ^ Output file name, relative to an output base dir+ -> Verbosity+ -> IO () -- Should exit if the preprocessor fails -- | A suffix (or file extension). --
src/Distribution/Simple/Program.hs view
@@ -1,3 +1,11 @@+{- FUTUREWORK:+ -+ - Currently the logic in this module is not tested.+ -+ - Ideally, a set of unit tests that check whether certain+ - flags trigger recompilation should be added.+ - -}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} @@ -51,6 +59,7 @@ , ProgArg , ProgramLocation (..) , runProgram+ , runProgramCwd , getProgramOutput , suppressOverrideArgs @@ -93,7 +102,9 @@ , requireProgramVersion , needProgram , runDbProgram+ , runDbProgramCwd , getDbProgramOutput+ , getDbProgramOutputCwd -- * Programs that Cabal knows about , ghcProgram@@ -132,6 +143,7 @@ import Distribution.Simple.Program.Run import Distribution.Simple.Program.Types import Distribution.Simple.Utils+import Distribution.Utils.Path import Distribution.Verbosity -- | Runs the given configured program.@@ -146,6 +158,20 @@ runProgram verbosity prog args = runProgramInvocation verbosity (programInvocation prog args) +-- | Runs the given configured program.+runProgramCwd+ :: Verbosity+ -- ^ Verbosity+ -> Maybe (SymbolicPath CWD (Dir to))+ -- ^ Working directory+ -> ConfiguredProgram+ -- ^ The program to run+ -> [ProgArg]+ -- ^ Any /extra/ arguments to add+ -> IO ()+runProgramCwd verbosity mbWorkDir prog args =+ runProgramInvocation verbosity (programInvocationCwd mbWorkDir prog args)+ -- | Runs the given configured program and gets the output. getProgramOutput :: Verbosity@@ -169,11 +195,27 @@ -> [ProgArg] -- ^ Any /extra/ arguments to add -> IO ()-runDbProgram verbosity prog programDb args =+runDbProgram verbosity prog progDb args =+ runDbProgramCwd verbosity Nothing prog progDb args++-- | Looks up the given program in the program database and runs it.+runDbProgramCwd+ :: Verbosity+ -- ^ verbosity+ -> Maybe (SymbolicPath CWD (Dir to))+ -- ^ working directory+ -> Program+ -- ^ The program to run+ -> ProgramDb+ -- ^ look up the program here+ -> [ProgArg]+ -- ^ Any /extra/ arguments to add+ -> IO ()+runDbProgramCwd verbosity mbWorkDir prog programDb args = case lookupProgram prog programDb of Nothing -> dieWithException verbosity $ ProgramNotFound (programName prog)- Just configuredProg -> runProgram verbosity configuredProg args+ Just configuredProg -> runProgramCwd verbosity mbWorkDir configuredProg args -- | Looks up the given program in the program database and runs it. getDbProgramOutput@@ -186,7 +228,25 @@ -> [ProgArg] -- ^ Any /extra/ arguments to add -> IO String-getDbProgramOutput verbosity prog programDb args =+getDbProgramOutput verb prog progDb args =+ getDbProgramOutputCwd verb Nothing prog progDb args++-- | Looks up the given program in the program database and runs it.+getDbProgramOutputCwd+ :: Verbosity+ -- ^ verbosity+ -> Maybe (SymbolicPath CWD (Dir to))+ -- ^ working directory+ -> Program+ -- ^ The program to run+ -> ProgramDb+ -- ^ look up the program here+ -> [ProgArg]+ -- ^ Any /extra/ arguments to add+ -> IO String+getDbProgramOutputCwd verbosity mbWorkDir prog programDb args = case lookupProgram prog programDb of Nothing -> dieWithException verbosity $ ProgramNotFound (programName prog)- Just configuredProg -> getProgramOutput verbosity configuredProg args+ Just configuredProg ->+ getProgramInvocationOutput verbosity $+ programInvocationCwd mbWorkDir configuredProg args
src/Distribution/Simple/Program/Ar.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE NondecreasingIndentation #-} {-# LANGUAGE OverloadedStrings #-}@@ -25,10 +26,7 @@ import qualified Data.ByteString.Char8 as BS8 import Distribution.Compat.CopyFile (filesEqual) import Distribution.Simple.Compiler (arDashLSupported, arResponseFilesSupported)-import Distribution.Simple.Flag- ( fromFlagOrDefault- )-import Distribution.Simple.LocalBuildInfo (LocalBuildInfo (..))+import Distribution.Simple.LocalBuildInfo (LocalBuildInfo (..), mbWorkDirLBI) import Distribution.Simple.Program ( ProgramInvocation , arProgram@@ -39,29 +37,32 @@ ) import Distribution.Simple.Program.Run ( multiStageProgramInvocation- , programInvocation+ , programInvocationCwd , runProgramInvocation )+import Distribution.Simple.Setup.Common import Distribution.Simple.Setup.Config ( configUseResponseFiles ) import Distribution.Simple.Utils ( defaultTempFileOptions , dieWithLocation'- , withTempDirectory+ , withTempDirectoryCwd ) import Distribution.System ( Arch (..) , OS (..) , Platform (..) )+import Distribution.Utils.Path import Distribution.Verbosity ( Verbosity , deafening , verbose )+ import System.Directory (doesFileExist, renameFile)-import System.FilePath (splitFileName, (</>))+import System.FilePath (splitFileName) import System.IO ( Handle , IOMode (ReadWriteMode)@@ -75,14 +76,21 @@ createArLibArchive :: Verbosity -> LocalBuildInfo- -> FilePath- -> [FilePath]+ -> SymbolicPath Pkg File+ -> [SymbolicPath Pkg File] -> IO () createArLibArchive verbosity lbi targetPath files = do- (ar, _) <- requireProgram verbosity arProgram progDb+ (arProg, _) <- requireProgram verbosity arProgram progDb - let (targetDir, targetName) = splitFileName targetPath- withTempDirectory verbosity targetDir "objs" $ \tmpDir -> do+ let (targetDir0, targetName0) = splitFileName $ getSymbolicPath targetPath+ targetDir = makeSymbolicPath targetDir0+ targetName = makeRelativePathEx targetName0+ mbWorkDir = mbWorkDirLBI lbi+ -- See Note [Symbolic paths] in Distribution.Utils.Path+ i = interpretSymbolicPath mbWorkDir+ u :: SymbolicPath Pkg to -> FilePath+ u = interpretSymbolicPathCWD+ withTempDirectoryCwd verbosity mbWorkDir targetDir "objs" $ \tmpDir -> do let tmpPath = tmpDir </> targetName -- The args to use with "ar" are actually rather subtle and system-dependent.@@ -105,7 +113,8 @@ -- When we need to call ar multiple times we use "ar q" and for the last -- call on OSX we use "ar qs" so that it'll make the index. - let simpleArgs = case hostOS of+ let simpleArgs, initialArgs, finalArgs :: [String]+ simpleArgs = case hostOS of OSX -> ["-r", "-s"] _ | dashLSupported -> ["-qL"] _ -> ["-r"]@@ -116,12 +125,13 @@ _ | dashLSupported -> ["-qL"] _ -> ["-q"] - extraArgs = verbosityOpts verbosity ++ [tmpPath]+ extraArgs = verbosityOpts verbosity ++ [u tmpPath] - simple = programInvocation ar (simpleArgs ++ extraArgs)- initial = programInvocation ar (initialArgs ++ extraArgs)+ ar = programInvocationCwd mbWorkDir arProg+ simple = ar (simpleArgs ++ extraArgs)+ initial = ar (initialArgs ++ extraArgs) middle = initial- final = programInvocation ar (finalArgs ++ extraArgs)+ final = ar (finalArgs ++ extraArgs) oldVersionManualOverride = fromFlagOrDefault False $ configUseResponseFiles $ configFlags lbi@@ -130,10 +140,9 @@ dashLSupported = arDashLSupported (compiler lbi) - invokeWithResponesFile :: FilePath -> ProgramInvocation- invokeWithResponesFile atFile =- programInvocation ar $- simpleArgs ++ extraArgs ++ ['@' : atFile]+ invokeWithResponseFile :: FilePath -> ProgramInvocation+ invokeWithResponseFile atFile =+ (ar $ simpleArgs ++ extraArgs ++ ['@' : atFile]) if oldVersionManualOverride || responseArgumentsNotSupported then@@ -143,18 +152,18 @@ multiStageProgramInvocation simple (initial, middle, final)- files+ (map getSymbolicPath files) ]- else withResponseFile verbosity defaultTempFileOptions tmpDir "ar.rsp" Nothing files $- \path -> runProgramInvocation verbosity $ invokeWithResponesFile path+ else withResponseFile verbosity defaultTempFileOptions mbWorkDir tmpDir "ar.rsp" Nothing (map getSymbolicPath files) $+ \path -> runProgramInvocation verbosity $ invokeWithResponseFile path unless ( hostArch == Arm -- See #1537 || hostOS == AIX )- $ wipeMetadata verbosity tmpPath -- AIX uses its own "ar" format variant- equal <- filesEqual tmpPath targetPath- unless equal $ renameFile tmpPath targetPath+ $ wipeMetadata verbosity (i tmpPath) -- AIX uses its own "ar" format variant+ equal <- filesEqual (i tmpPath) (i targetPath)+ unless equal $ renameFile (i tmpPath) (i targetPath) where progDb = withPrograms lbi Platform hostArch hostOS = hostPlatform lbi
src/Distribution/Simple/Program/Builtin.hs view
@@ -226,21 +226,13 @@ -- during the configure phase. haskellSuiteProgram :: Program haskellSuiteProgram =- (simpleProgram "haskell-suite")- { -- pretend that the program exists, otherwise it won't be in the- -- "configured" state- programFindLocation = \_verbosity _searchPath ->- return $ Just ("haskell-suite-dummy-location", [])- }+ simpleProgram "haskell-suite" -- This represent a haskell-suite package manager. See the comments for -- haskellSuiteProgram. haskellSuitePkgProgram :: Program haskellSuitePkgProgram =- (simpleProgram "haskell-suite-pkg")- { programFindLocation = \_verbosity _searchPath ->- return $ Just ("haskell-suite-pkg-dummy-location", [])- }+ simpleProgram "haskell-suite-pkg" happyProgram :: Program happyProgram =
src/Distribution/Simple/Program/Db.hs view
@@ -26,7 +26,7 @@ -- don't have to write all the PATH logic inside Setup.lhs. module Distribution.Simple.Program.Db ( -- * The collection of configured programs we can run- ProgramDb+ ProgramDb (..) , emptyProgramDb , defaultProgramDb , restoreProgramDb@@ -35,6 +35,7 @@ , addKnownProgram , addKnownPrograms , prependProgramSearchPath+ , prependProgramSearchPathNoLogging , lookupKnownProgram , knownPrograms , getProgramSearchPath@@ -53,6 +54,7 @@ -- ** Query and manipulate the program db , configureProgram+ , configureUnconfiguredProgram , configureAllKnownPrograms , unconfigureProgram , lookupProgramVersion@@ -60,6 +62,12 @@ , requireProgram , requireProgramVersion , needProgram++ -- * Internal functions+ , UnconfiguredProgs+ , ConfiguredProgs+ , updateUnconfiguredProgs+ , updateConfiguredProgs ) where import Distribution.Compat.Prelude@@ -95,6 +103,7 @@ data ProgramDb = ProgramDb { unconfiguredProgs :: UnconfiguredProgs , progSearchPath :: ProgramSearchPath+ , progOverrideEnv :: [(String, Maybe String)] , configuredProgs :: ConfiguredProgs } deriving (Typeable)@@ -104,7 +113,7 @@ type ConfiguredProgs = Map.Map String ConfiguredProgram emptyProgramDb :: ProgramDb-emptyProgramDb = ProgramDb Map.empty defaultProgramSearchPath Map.empty+emptyProgramDb = ProgramDb Map.empty defaultProgramSearchPath [] Map.empty defaultProgramDb :: ProgramDb defaultProgramDb = restoreProgramDb builtinPrograms emptyProgramDb@@ -144,14 +153,17 @@ instance Binary ProgramDb where put db = do put (progSearchPath db)+ put (progOverrideEnv db) put (configuredProgs db) get = do searchpath <- get+ overrides <- get progs <- get return $! emptyProgramDb { progSearchPath = searchpath+ , progOverrideEnv = overrides , configuredProgs = progs } @@ -162,6 +174,7 @@ 0 "ProgramDb" [ structure (Proxy :: Proxy ProgramSearchPath)+ , structure (Proxy :: Proxy [(String, Maybe String)]) , structure (Proxy :: Proxy ConfiguredProgs) ] @@ -223,20 +236,33 @@ setProgramSearchPath (f $ getProgramSearchPath db) db -- | Modify the current 'ProgramSearchPath' used by the 'ProgramDb'--- by prepending the provided extra paths. Also logs the added paths--- in info verbosity.+-- by prepending the provided extra paths.+--+-- - Logs the added paths in info verbosity.+-- - Prepends environment variable overrides. prependProgramSearchPath :: Verbosity -> [FilePath]+ -> [(String, Maybe FilePath)] -> ProgramDb -> IO ProgramDb-prependProgramSearchPath verbosity extraPaths db =- if not $ null extraPaths- then do- logExtraProgramSearchPath verbosity extraPaths- pure $ modifyProgramSearchPath (map ProgramSearchPathDir extraPaths ++) db- else pure db+prependProgramSearchPath verbosity extraPaths extraEnv db = do+ unless (null extraPaths) $+ logExtraProgramSearchPath verbosity extraPaths+ unless (null extraEnv) $+ logExtraProgramOverrideEnv verbosity extraEnv+ return $ prependProgramSearchPathNoLogging extraPaths extraEnv db +prependProgramSearchPathNoLogging+ :: [FilePath]+ -> [(String, Maybe String)]+ -> ProgramDb+ -> ProgramDb+prependProgramSearchPathNoLogging extraPaths extraEnv db =+ let db' = modifyProgramSearchPath (nub . (map ProgramSearchPathDir extraPaths ++)) db+ db'' = db'{progOverrideEnv = extraEnv ++ progOverrideEnv db'}+ in 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.@@ -338,11 +364,13 @@ -- --------------------------- -- Configuring known programs --- | Try to configure a specific program. If the program is already included in--- the collection of unconfigured programs then we use any user-supplied--- location and arguments. If the program gets configured successfully it gets--- added to the configured collection.+-- | Try to configure a specific program and add it to the program database. --+-- If the program is already included in the collection of unconfigured programs,+-- then we use any user-supplied location and arguments.+-- If the program gets configured successfully, it gets added to the configured+-- collection.+-- -- Note that it is not a failure if the program cannot be configured. It's only -- a failure if the user supplied a location and the program could not be found -- at that location.@@ -357,6 +385,25 @@ -> ProgramDb -> IO ProgramDb configureProgram verbosity prog progdb = do+ mbConfiguredProg <- configureUnconfiguredProgram verbosity prog progdb+ case mbConfiguredProg of+ Nothing -> return progdb+ Just configuredProg -> do+ let progdb' =+ updateConfiguredProgs+ (Map.insert (programName prog) configuredProg)+ progdb+ return progdb'++-- | Try to configure a specific program. If the program is already included in+-- the collection of unconfigured programs then we use any user-supplied+-- location and arguments.+configureUnconfiguredProgram+ :: Verbosity+ -> Program+ -> ProgramDb+ -> IO (Maybe ConfiguredProgram)+configureUnconfiguredProgram verbosity prog progdb = do let name = programName prog maybeLocation <- case userSpecifiedPath prog progdb of Nothing ->@@ -372,7 +419,7 @@ (dieWithException verbosity $ ConfigureProgram name path) (return . Just . swap . fmap UserSpecified . swap) case maybeLocation of- Nothing -> return progdb+ Nothing -> return Nothing Just (location, triedLocations) -> do version <- programFindVersion prog verbosity (locationPath location) newPath <- programSearchPathAsPATHVar (progSearchPath progdb)@@ -382,13 +429,13 @@ , programVersion = version , programDefaultArgs = [] , programOverrideArgs = userSpecifiedArgs prog progdb- , programOverrideEnv = [("PATH", Just newPath)]+ , programOverrideEnv = [("PATH", Just newPath)] ++ progOverrideEnv progdb , programProperties = Map.empty , programLocation = location , programMonitorFiles = triedLocations } configuredProg' <- programPostConf prog verbosity configuredProg- return (updateConfiguredProgs (Map.insert name configuredProg') progdb)+ return $ Just configuredProg' -- | Configure a bunch of programs using 'configureProgram'. Just a 'foldM'. configurePrograms
src/Distribution/Simple/Program/Find.hs view
@@ -33,6 +33,7 @@ , findProgramOnSearchPath , programSearchPathAsPATHVar , logExtraProgramSearchPath+ , logExtraProgramOverrideEnv , getSystemSearchPath , getExtraPathEnv , simpleProgram@@ -73,6 +74,19 @@ info verbosity . unlines $ "Including the following directories in PATH:" : map ("- " ++) extraPaths++logExtraProgramOverrideEnv+ :: Verbosity+ -> [(String, Maybe String)]+ -> IO ()+logExtraProgramOverrideEnv verbosity extraEnv =+ info verbosity . unlines $+ "Including the following environment variable overrides:"+ : [ "- " ++ case mbVal of+ Nothing -> "unset " ++ var+ Just val -> var ++ "=" ++ val+ | (var, mbVal) <- extraEnv+ ] findProgramOnSearchPath :: Verbosity
src/Distribution/Simple/Program/GHC.hs view
@@ -1,9 +1,11 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-} module Distribution.Simple.Program.GHC ( GhcOptions (..)@@ -34,16 +36,18 @@ import Distribution.Simple.Program.Types import Distribution.System import Distribution.Types.ComponentId+import Distribution.Types.ParStrat import Distribution.Utils.NubList+import Distribution.Utils.Path import Distribution.Verbosity import Distribution.Version+ import Language.Haskell.Extension import Data.List (stripPrefix) import qualified Data.Map as Map import Data.Monoid (All (..), Any (..), Endo (..)) import qualified Data.Set as Set-import Distribution.Types.ParStrat normaliseGhcArgs :: Maybe Version -> PackageDescription -> [String] -> [String] normaliseGhcArgs (Just ghcVersion) PackageDescription{..} ghcArgs@@ -320,6 +324,8 @@ , "-ddpr-cols" , "-dtrace-level" , "-fghci-hist-size"+ , "-dinitial-unique"+ , "-dunique-increment" ] , from [8, 2] ["-fmax-uncovered-patterns", "-fmax-errors"] , from [8, 4] $ to [8, 6] ["-fmax-valid-substitutions"]@@ -419,13 +425,13 @@ , ----------------------- -- Inputs and outputs - ghcOptInputFiles :: NubListR FilePath+ ghcOptInputFiles :: NubListR (SymbolicPath Pkg File) -- ^ The main input files; could be .hs, .hi, .c, .o, depending on mode.- , ghcOptInputScripts :: NubListR FilePath+ , ghcOptInputScripts :: NubListR (SymbolicPath Pkg File) -- ^ Script files with irregular extensions that need -x hs. , ghcOptInputModules :: NubListR ModuleName -- ^ The names of input Haskell modules, mainly for @--make@ mode.- , ghcOptOutputFile :: Flag FilePath+ , ghcOptOutputFile :: Flag (SymbolicPath Pkg File) -- ^ Location for output file; the @ghc -o@ flag. , ghcOptOutputDynFile :: Flag FilePath -- ^ Location for dynamic output file in 'GhcStaticAndDynamic' mode;@@ -433,7 +439,7 @@ , ghcOptSourcePathClear :: Flag Bool -- ^ Start with an empty search path for Haskell source files; -- the @ghc -i@ flag (@-i@ on its own with no path argument).- , ghcOptSourcePath :: NubListR FilePath+ , ghcOptSourcePath :: NubListR (SymbolicPath Pkg (Dir Source)) -- ^ Search path for Haskell source files; the @ghc -i@ flag. , ------------- -- Packages@@ -474,13 +480,13 @@ ghcOptLinkLibs :: [FilePath] -- ^ Names of libraries to link in; the @ghc -l@ flag.- , ghcOptLinkLibPath :: NubListR FilePath+ , ghcOptLinkLibPath :: NubListR (SymbolicPath Pkg (Dir Lib)) -- ^ Search path for libraries to link in; the @ghc -L@ flag. , ghcOptLinkOptions :: [String] -- ^ Options to pass through to the linker; the @ghc -optl@ flag. , ghcOptLinkFrameworks :: NubListR String -- ^ OSX only: frameworks to link in; the @ghc -framework@ flag.- , ghcOptLinkFrameworkDirs :: NubListR String+ , ghcOptLinkFrameworkDirs :: NubListR (SymbolicPath Pkg (Dir Framework)) -- ^ OSX only: Search path for frameworks to link in; the -- @ghc -framework-path@ flag. , ghcOptLinkRts :: Flag Bool@@ -503,9 +509,9 @@ -- ^ Options to pass through to the Assembler. , ghcOptCppOptions :: [String] -- ^ Options to pass through to CPP; the @ghc -optP@ flag.- , ghcOptCppIncludePath :: NubListR FilePath+ , ghcOptCppIncludePath :: NubListR (SymbolicPath Pkg (Dir Include)) -- ^ Search path for CPP includes like header files; the @ghc -I@ flag.- , ghcOptCppIncludes :: NubListR FilePath+ , ghcOptCppIncludes :: NubListR (SymbolicPath Pkg File) -- ^ Extra header files to include at CPP stage; the @ghc -optP-include@ flag. , ghcOptFfiIncludes :: NubListR FilePath -- ^ Extra header files to include for old-style FFI; the @ghc -#include@ flag.@@ -538,7 +544,7 @@ -- ^ Use the \"split object files\" feature; the @ghc -split-objs@ flag. , ghcOptNumJobs :: Flag ParStrat -- ^ Run N jobs simultaneously (if possible).- , ghcOptHPCDir :: Flag FilePath+ , ghcOptHPCDir :: Flag (SymbolicPath Pkg (Dir Mix)) -- ^ Enable coverage analysis; the @ghc -fhpc -hpcdir@ flags. , ---------------- -- GHCi@@ -554,11 +560,11 @@ -- ^ only in 'GhcStaticAndDynamic' mode , ghcOptDynObjSuffix :: Flag String -- ^ only in 'GhcStaticAndDynamic' mode- , ghcOptHiDir :: Flag FilePath- , ghcOptHieDir :: Flag FilePath- , ghcOptObjDir :: Flag FilePath- , ghcOptOutputDir :: Flag FilePath- , ghcOptStubDir :: Flag FilePath+ , ghcOptHiDir :: Flag (SymbolicPath Pkg (Dir Artifacts))+ , ghcOptHieDir :: Flag (SymbolicPath Pkg (Dir Artifacts))+ , ghcOptObjDir :: Flag (SymbolicPath Pkg (Dir Artifacts))+ , ghcOptOutputDir :: Flag (SymbolicPath Pkg (Dir Artifacts))+ , ghcOptStubDir :: Flag (SymbolicPath Pkg (Dir Artifacts)) , -------------------- -- Creating libraries @@ -573,7 +579,7 @@ ghcOptVerbosity :: Flag Verbosity -- ^ Get GHC to be quiet or verbose with what it's doing; the @ghc -v@ flag.- , ghcOptExtraPath :: NubListR FilePath+ , ghcOptExtraPath :: NubListR (SymbolicPath Pkg (Dir Build)) -- ^ Put the extra folders in the PATH environment variable we invoke -- GHC with , ghcOptCabal :: Flag Bool@@ -633,27 +639,38 @@ -> ConfiguredProgram -> Compiler -> Platform+ -> Maybe (SymbolicPath CWD (Dir Pkg)) -> GhcOptions -> IO ()-runGHC verbosity ghcProg comp platform opts = do- runProgramInvocation verbosity =<< ghcInvocation verbosity ghcProg comp platform opts+runGHC verbosity ghcProg comp platform mbWorkDir opts = do+ runProgramInvocation verbosity+ =<< ghcInvocation verbosity ghcProg comp platform mbWorkDir opts ghcInvocation :: Verbosity -> ConfiguredProgram -> Compiler -> Platform+ -> Maybe (SymbolicPath CWD (Dir Pkg)) -> GhcOptions -> IO ProgramInvocation-ghcInvocation verbosity ghcProg comp platform opts = do+ghcInvocation verbosity ghcProg comp platform mbWorkDir opts = do -- NOTE: GHC is the only program whose path we modify with more values than -- the standard @extra-prog-path@, namely the folders of the executables in -- the components, see @componentGhcOptions@. let envOverrides = programOverrideEnv ghcProg- extraPath <- getExtraPathEnv verbosity envOverrides (fromNubListR (ghcOptExtraPath opts))+ extraPath <-+ getExtraPathEnv verbosity envOverrides $+ map getSymbolicPath $+ fromNubListR $+ ghcOptExtraPath opts let ghcProg' = ghcProg{programOverrideEnv = envOverrides ++ extraPath}+ return $+ programInvocationCwd mbWorkDir ghcProg' $+ renderGhcOptions comp platform opts - pure $ programInvocation ghcProg' (renderGhcOptions comp platform opts)+-- TODO: use the -working-dir GHC flag instead of setting the process+-- working directory, as this improves error messages. renderGhcOptions :: Compiler -> Platform -> GhcOptions -> [String] renderGhcOptions comp _platform@(Platform _arch os) opts@@ -721,7 +738,7 @@ _ -> ["-split-objs" | flagBool ghcOptSplitObjs] , case flagToMaybe (ghcOptHPCDir opts) of Nothing -> []- Just hpcdir -> ["-fhpc", "-hpcdir", hpcdir]+ Just hpcdir -> ["-fhpc", "-hpcdir", u hpcdir] , if parmakeSupported comp then case ghcOptNumJobs opts of NoFlag -> []@@ -751,25 +768,25 @@ , concat [["-hisuf", suf] | suf <- flag ghcOptHiSuffix] , concat [["-dynosuf", suf] | suf <- flag ghcOptDynObjSuffix] , concat [["-dynhisuf", suf] | suf <- flag ghcOptDynHiSuffix]- , concat [["-outputdir", dir] | dir <- flag ghcOptOutputDir]- , concat [["-odir", dir] | dir <- flag ghcOptObjDir]- , concat [["-hidir", dir] | dir <- flag ghcOptHiDir]- , concat [["-hiedir", dir] | dir <- flag ghcOptHieDir]- , concat [["-stubdir", dir] | dir <- flag ghcOptStubDir]+ , concat [["-outputdir", u dir] | dir <- flag ghcOptOutputDir]+ , concat [["-odir", u dir] | dir <- flag ghcOptObjDir]+ , concat [["-hidir", u dir] | dir <- flag ghcOptHiDir]+ , concat [["-hiedir", u dir] | dir <- flag ghcOptHieDir]+ , concat [["-stubdir", u dir] | dir <- flag ghcOptStubDir] , ----------------------- -- Source search path ["-i" | flagBool ghcOptSourcePathClear]- , ["-i" ++ dir | dir <- flags ghcOptSourcePath]+ , ["-i" ++ u dir | dir <- flags ghcOptSourcePath] , -------------------- -------------------- -- CPP, C, and C++ stuff - ["-I" ++ dir | dir <- flags ghcOptCppIncludePath]+ ["-I" ++ u dir | dir <- flags ghcOptCppIncludePath] , ["-optP" ++ opt | opt <- ghcOptCppOptions opts] , concat- [ ["-optP-include", "-optP" ++ inc]+ [ ["-optP-include", "-optP" ++ u inc] | inc <- flags ghcOptCppIncludes ] , ["-optc" ++ opt | opt <- ghcOptCcOptions opts]@@ -785,7 +802,7 @@ ["-optl" ++ opt | opt <- ghcOptLinkOptions opts] , ["-l" ++ lib | lib <- ghcOptLinkLibs opts]- , ["-L" ++ dir | dir <- flags ghcOptLinkLibPath]+ , ["-L" ++ u dir | dir <- flags ghcOptLinkLibPath] , if isOSX then concat@@ -796,7 +813,7 @@ , if isOSX then concat- [ ["-framework-path", path]+ [ ["-framework-path", u path] | path <- flags ghcOptLinkFrameworkDirs ] else []@@ -839,7 +856,7 @@ , ["-hide-all-packages" | flagBool ghcOptHideAllPackages] , ["-Wmissing-home-modules" | flagBool ghcOptWarnMissingHomeModules] , ["-no-auto-link-packages" | flagBool ghcOptNoAutoLinkPackages]- , packageDbArgs implInfo (ghcOptPackageDBs opts)+ , packageDbArgs implInfo (interpretPackageDBStack Nothing (ghcOptPackageDBs opts)) , concat $ let space "" = "" space xs = ' ' : xs@@ -874,10 +891,10 @@ -- Specify the input file(s) first, so that in ghci the `main-is` module is -- in scope instead of the first module defined in `other-modules`.- flags ghcOptInputFiles- , concat [["-x", "hs", script] | script <- flags ghcOptInputScripts]+ map u $ flags ghcOptInputFiles+ , concat [["-x", "hs", u script] | script <- flags ghcOptInputScripts] , [prettyShow modu | modu <- flags ghcOptInputModules]- , concat [["-o", out] | out <- flag ghcOptOutputFile]+ , concat [["-o", u out] | out <- flag ghcOptOutputFile] , concat [["-dyno", out] | out <- flag ghcOptOutputDynFile] , --------------- -- Extra@@ -885,6 +902,9 @@ ghcOptExtra opts ] where+ -- See Note [Symbolic paths] in Distribution.Utils.Path+ u :: SymbolicPath Pkg to -> FilePath+ u = interpretSymbolicPathCWD implInfo = getImplInfo comp isOSX = os == OSX flag flg = flagToList (flg opts)@@ -898,7 +918,7 @@ | otherwise = ["-w", "-v0"] -- | GHC <7.6 uses '-package-conf' instead of '-package-db'.-packageDbArgsConf :: PackageDBStack -> [String]+packageDbArgsConf :: PackageDBStackCWD -> [String] packageDbArgsConf dbstack = case dbstack of (GlobalPackageDB : UserPackageDB : dbs) -> concatMap specific dbs (GlobalPackageDB : dbs) ->@@ -915,7 +935,7 @@ -- | GHC >= 7.6 uses the '-package-db' flag. See -- https://gitlab.haskell.org/ghc/ghc/-/issues/5977.-packageDbArgsDb :: PackageDBStack -> [String]+packageDbArgsDb :: PackageDBStackCWD -> [String] -- special cases to make arguments prettier in common scenarios packageDbArgsDb dbstack = case dbstack of (GlobalPackageDB : UserPackageDB : dbs)@@ -934,7 +954,7 @@ isSpecific (SpecificPackageDB _) = True isSpecific _ = False -packageDbArgs :: GhcImplInfo -> PackageDBStack -> [String]+packageDbArgs :: GhcImplInfo -> PackageDBStackCWD -> [String] packageDbArgs implInfo | flagPackageConf implInfo = packageDbArgsConf | otherwise = packageDbArgsDb
src/Distribution/Simple/Program/HcPkg.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-}@@ -58,10 +59,16 @@ import Distribution.Types.ComponentId import Distribution.Types.PackageId import Distribution.Types.UnitId+import Distribution.Utils.Path import Distribution.Verbosity import Data.List (stripPrefix)-import System.FilePath as FilePath (isPathSeparator, joinPath, splitDirectories, splitPath, (<.>), (</>))+import System.FilePath as FilePath+ ( isPathSeparator+ , joinPath+ , splitDirectories+ , splitPath+ ) import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as LBS@@ -103,12 +110,18 @@ -- | Run @hc-pkg@ using a given package DB stack, directly forwarding the -- provided command-line arguments to it.-invoke :: HcPkgInfo -> Verbosity -> PackageDBStack -> [String] -> IO ()-invoke hpi verbosity dbStack extraArgs =+invoke+ :: HcPkgInfo+ -> Verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -> PackageDBStack+ -> [String]+ -> IO ()+invoke hpi verbosity mbWorkDir dbStack extraArgs = runProgramInvocation verbosity invocation where args = packageDbStackOpts hpi dbStack ++ extraArgs- invocation = programInvocation (hcPkgProgram hpi) args+ invocation = programInvocationCwd mbWorkDir (hcPkgProgram hpi) args -- | Additional variations in the behaviour for 'register'. data RegisterOptions = RegisterOptions@@ -141,11 +154,12 @@ register :: HcPkgInfo -> Verbosity- -> PackageDBStack+ -> Maybe (SymbolicPath CWD (Dir from))+ -> PackageDBStackS from -> InstalledPackageInfo -> RegisterOptions -> IO ()-register hpi verbosity packagedbs pkgInfo registerOptions+register hpi verbosity mbWorkDir packagedbs pkgInfo registerOptions | registerMultiInstance registerOptions , not (nativeMultiInstance hpi || recacheMultiInstance hpi) = dieWithException verbosity RegMultipleInstancePkg@@ -165,27 +179,28 @@ , recacheMultiInstance hpi = do let pkgdb = registrationPackageDB packagedbs- writeRegistrationFileDirectly verbosity hpi pkgdb pkgInfo- recache hpi verbosity pkgdb+ writeRegistrationFileDirectly verbosity hpi mbWorkDir pkgdb pkgInfo+ recache hpi verbosity mbWorkDir pkgdb | otherwise = runProgramInvocation verbosity- (registerInvocation hpi verbosity packagedbs pkgInfo registerOptions)+ (registerInvocation hpi verbosity mbWorkDir packagedbs pkgInfo registerOptions) writeRegistrationFileDirectly :: Verbosity -> HcPkgInfo- -> PackageDB+ -> Maybe (SymbolicPath CWD (Dir from))+ -> PackageDBS from -> InstalledPackageInfo -> IO ()-writeRegistrationFileDirectly verbosity hpi (SpecificPackageDB dir) pkgInfo+writeRegistrationFileDirectly verbosity hpi mbWorkDir (SpecificPackageDB dir) pkgInfo | supportsDirDbs hpi = do- let pkgfile = dir </> prettyShow (installedUnitId pkgInfo) <.> "conf"+ let pkgfile = interpretSymbolicPath mbWorkDir dir </> prettyShow (installedUnitId pkgInfo) <.> "conf" writeUTF8File pkgfile (showInstalledPackageInfo pkgInfo) | otherwise = dieWithException verbosity NoSupportDirStylePackageDb-writeRegistrationFileDirectly verbosity _ _ _ =+writeRegistrationFileDirectly verbosity _ _ _ _ = -- We don't know here what the dir for the global or user dbs are, -- if that's needed it'll require a bit more plumbing to support. dieWithException verbosity OnlySupportSpecificPackageDb@@ -193,39 +208,51 @@ -- | Call @hc-pkg@ to unregister a package -- -- > hc-pkg unregister [pkgid] [--user | --global | --package-db]-unregister :: HcPkgInfo -> Verbosity -> PackageDB -> PackageId -> IO ()-unregister hpi verbosity packagedb pkgid =+unregister :: HcPkgInfo -> Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDB -> PackageId -> IO ()+unregister hpi verbosity mbWorkDir packagedb pkgid = runProgramInvocation verbosity- (unregisterInvocation hpi verbosity packagedb pkgid)+ (unregisterInvocation hpi verbosity mbWorkDir packagedb pkgid) -- | Call @hc-pkg@ to recache the registered packages. -- -- > hc-pkg recache [--user | --global | --package-db]-recache :: HcPkgInfo -> Verbosity -> PackageDB -> IO ()-recache hpi verbosity packagedb =+recache :: HcPkgInfo -> Verbosity -> Maybe (SymbolicPath CWD (Dir from)) -> PackageDBS from -> IO ()+recache hpi verbosity mbWorkDir packagedb = runProgramInvocation verbosity- (recacheInvocation hpi verbosity packagedb)+ (recacheInvocation hpi verbosity mbWorkDir packagedb) -- | Call @hc-pkg@ to expose a package. -- -- > hc-pkg expose [pkgid] [--user | --global | --package-db]-expose :: HcPkgInfo -> Verbosity -> PackageDB -> PackageId -> IO ()-expose hpi verbosity packagedb pkgid =+expose+ :: HcPkgInfo+ -> Verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -> PackageDB+ -> PackageId+ -> IO ()+expose hpi verbosity mbWorkDir packagedb pkgid = runProgramInvocation verbosity- (exposeInvocation hpi verbosity packagedb pkgid)+ (exposeInvocation hpi verbosity mbWorkDir packagedb pkgid) -- | Call @hc-pkg@ to retrieve a specific package -- -- > hc-pkg describe [pkgid] [--user | --global | --package-db]-describe :: HcPkgInfo -> Verbosity -> PackageDBStack -> PackageId -> IO [InstalledPackageInfo]-describe hpi verbosity packagedb pid = do+describe+ :: HcPkgInfo+ -> Verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -> PackageDBStack+ -> PackageId+ -> IO [InstalledPackageInfo]+describe hpi verbosity mbWorkDir packagedb pid = do output <- getProgramInvocationLBS verbosity- (describeInvocation hpi verbosity packagedb pid)+ (describeInvocation hpi verbosity mbWorkDir packagedb pid) `catchIO` \_ -> return mempty case parsePackages output of@@ -235,20 +262,31 @@ -- | Call @hc-pkg@ to hide a package. -- -- > hc-pkg hide [pkgid] [--user | --global | --package-db]-hide :: HcPkgInfo -> Verbosity -> PackageDB -> PackageId -> IO ()-hide hpi verbosity packagedb pkgid =+hide+ :: HcPkgInfo+ -> Verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -> PackageDB+ -> PackageId+ -> IO ()+hide hpi verbosity mbWorkDir packagedb pkgid = runProgramInvocation verbosity- (hideInvocation hpi verbosity packagedb pkgid)+ (hideInvocation hpi verbosity mbWorkDir packagedb pkgid) -- | Call @hc-pkg@ to get all the details of all the packages in the given -- package database.-dump :: HcPkgInfo -> Verbosity -> PackageDB -> IO [InstalledPackageInfo]-dump hpi verbosity packagedb = do+dump+ :: HcPkgInfo+ -> Verbosity+ -> Maybe (SymbolicPath CWD (Dir from))+ -> PackageDBX (SymbolicPath from (Dir PkgDB))+ -> IO [InstalledPackageInfo]+dump hpi verbosity mbWorkDir packagedb = do output <- getProgramInvocationLBS verbosity- (dumpInvocation hpi verbosity packagedb)+ (dumpInvocation hpi verbosity mbWorkDir packagedb) `catchIO` \e -> dieWithException verbosity $ DumpFailed (programId (hcPkgProgram hpi)) (displayException e) @@ -364,13 +402,14 @@ list :: HcPkgInfo -> Verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDB -> IO [PackageId]-list hpi verbosity packagedb = do+list hpi verbosity mbWorkDir packagedb = do output <- getProgramInvocationOutput verbosity- (listInvocation hpi verbosity packagedb)+ (listInvocation hpi verbosity mbWorkDir packagedb) `catchIO` \_ -> dieWithException verbosity $ ListFailed (programId (hcPkgProgram hpi)) case parsePackageIds output of@@ -394,12 +433,13 @@ registerInvocation :: HcPkgInfo -> Verbosity- -> PackageDBStack+ -> Maybe (SymbolicPath CWD (Dir from))+ -> PackageDBStackS from -> InstalledPackageInfo -> RegisterOptions -> ProgramInvocation-registerInvocation hpi verbosity packagedbs pkgInfo registerOptions =- (programInvocation (hcPkgProgram hpi) (args "-"))+registerInvocation hpi verbosity mbWorkDir packagedbs pkgInfo registerOptions =+ (programInvocationCwd mbWorkDir (hcPkgProgram hpi) (args "-")) { progInvokeInput = Just $ IODataText $ showInstalledPackageInfo pkgInfo , progInvokeInputEncoding = IOEncodingUTF8 }@@ -423,43 +463,47 @@ unregisterInvocation :: HcPkgInfo -> Verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDB -> PackageId -> ProgramInvocation-unregisterInvocation hpi verbosity packagedb pkgid =- programInvocation (hcPkgProgram hpi) $+unregisterInvocation hpi verbosity mbWorkDir packagedb pkgid =+ programInvocationCwd mbWorkDir (hcPkgProgram hpi) $ ["unregister", packageDbOpts hpi packagedb, prettyShow pkgid] ++ verbosityOpts hpi verbosity recacheInvocation :: HcPkgInfo -> Verbosity- -> PackageDB+ -> Maybe (SymbolicPath CWD (Dir from))+ -> PackageDBS from -> ProgramInvocation-recacheInvocation hpi verbosity packagedb =- programInvocation (hcPkgProgram hpi) $+recacheInvocation hpi verbosity mbWorkDir packagedb =+ programInvocationCwd mbWorkDir (hcPkgProgram hpi) $ ["recache", packageDbOpts hpi packagedb] ++ verbosityOpts hpi verbosity exposeInvocation :: HcPkgInfo -> Verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDB -> PackageId -> ProgramInvocation-exposeInvocation hpi verbosity packagedb pkgid =- programInvocation (hcPkgProgram hpi) $+exposeInvocation hpi verbosity mbWorkDir packagedb pkgid =+ programInvocationCwd mbWorkDir (hcPkgProgram hpi) $ ["expose", packageDbOpts hpi packagedb, prettyShow pkgid] ++ verbosityOpts hpi verbosity describeInvocation :: HcPkgInfo -> Verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDBStack -> PackageId -> ProgramInvocation-describeInvocation hpi verbosity packagedbs pkgid =- programInvocation (hcPkgProgram hpi) $+describeInvocation hpi verbosity mbWorkDir packagedbs pkgid =+ programInvocationCwd mbWorkDir (hcPkgProgram hpi) $ ["describe", prettyShow pkgid] ++ packageDbStackOpts hpi packagedbs ++ verbosityOpts hpi verbosity@@ -467,17 +511,23 @@ hideInvocation :: HcPkgInfo -> Verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDB -> PackageId -> ProgramInvocation-hideInvocation hpi verbosity packagedb pkgid =- programInvocation (hcPkgProgram hpi) $+hideInvocation hpi verbosity mbWorkDir packagedb pkgid =+ programInvocationCwd mbWorkDir (hcPkgProgram hpi) $ ["hide", packageDbOpts hpi packagedb, prettyShow pkgid] ++ verbosityOpts hpi verbosity -dumpInvocation :: HcPkgInfo -> Verbosity -> PackageDB -> ProgramInvocation-dumpInvocation hpi _verbosity packagedb =- (programInvocation (hcPkgProgram hpi) args)+dumpInvocation+ :: HcPkgInfo+ -> Verbosity+ -> Maybe (SymbolicPath CWD (Dir from))+ -> PackageDBX (SymbolicPath from (Dir PkgDB))+ -> ProgramInvocation+dumpInvocation hpi _verbosity mbWorkDir packagedb =+ (programInvocationCwd mbWorkDir (hcPkgProgram hpi) args) { progInvokeOutputEncoding = IOEncodingUTF8 } where@@ -488,9 +538,14 @@ -- We use verbosity level 'silent' because it is important that we -- do not contaminate the output with info/debug messages. -listInvocation :: HcPkgInfo -> Verbosity -> PackageDB -> ProgramInvocation-listInvocation hpi _verbosity packagedb =- (programInvocation (hcPkgProgram hpi) args)+listInvocation+ :: HcPkgInfo+ -> Verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -> PackageDB+ -> ProgramInvocation+listInvocation hpi _verbosity mbWorkDir packagedb =+ (programInvocationCwd mbWorkDir (hcPkgProgram hpi) args) { progInvokeOutputEncoding = IOEncodingUTF8 } where@@ -501,7 +556,7 @@ -- We use verbosity level 'silent' because it is important that we -- do not contaminate the output with info/debug messages. -packageDbStackOpts :: HcPkgInfo -> PackageDBStack -> [String]+packageDbStackOpts :: HcPkgInfo -> PackageDBStackS from -> [String] packageDbStackOpts hpi dbstack | noPkgDbStack hpi = [packageDbOpts hpi (registrationPackageDB dbstack)] | otherwise = case dbstack of@@ -515,7 +570,7 @@ : map specific dbs _ -> ierror where- specific (SpecificPackageDB db) = "--" ++ packageDbFlag hpi ++ "=" ++ db+ specific (SpecificPackageDB db) = "--" ++ packageDbFlag hpi ++ "=" ++ interpretSymbolicPathCWD db specific _ = ierror ierror :: a ierror = error ("internal error: unexpected package db stack: " ++ show dbstack)@@ -527,10 +582,10 @@ | otherwise = "package-db" -packageDbOpts :: HcPkgInfo -> PackageDB -> String+packageDbOpts :: HcPkgInfo -> PackageDBX (SymbolicPath from (Dir PkgDB)) -> String packageDbOpts _ GlobalPackageDB = "--global" packageDbOpts _ UserPackageDB = "--user"-packageDbOpts hpi (SpecificPackageDB db) = "--" ++ packageDbFlag hpi ++ "=" ++ db+packageDbOpts hpi (SpecificPackageDB db) = "--" ++ packageDbFlag hpi ++ "=" ++ interpretSymbolicPathCWD db verbosityOpts :: HcPkgInfo -> Verbosity -> [String] verbosityOpts hpi v
src/Distribution/Simple/Program/Hpc.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} @@ -19,13 +20,12 @@ import Distribution.Compat.Prelude import Prelude () -import System.Directory (makeRelativeToCurrentDirectory)- import Distribution.ModuleName import Distribution.Pretty import Distribution.Simple.Program.Run import Distribution.Simple.Program.Types import Distribution.Simple.Utils+import Distribution.Utils.Path import Distribution.Verbosity import Distribution.Version @@ -37,19 +37,20 @@ -- library as a dependency can still work, but those that include the library -- modules directly (in other-modules) don't. markup- :: ConfiguredProgram+ :: Maybe (SymbolicPath CWD (Dir Pkg))+ -> ConfiguredProgram -> Version -> Verbosity- -> FilePath+ -> SymbolicPath Pkg File -- ^ Path to .tix file- -> [FilePath]+ -> [SymbolicPath Pkg (Dir Mix)] -- ^ Paths to .mix file directories- -> FilePath+ -> SymbolicPath Pkg (Dir Artifacts) -- ^ Path where html output should be located -> [ModuleName] -- ^ List of modules to include in the report -> IO ()-markup hpc hpcVer verbosity tixFile hpcDirs destDir included = do+markup mbWorkDir hpc hpcVer verbosity tixFile hpcDirs destDir included = do hpcDirs' <- if withinRange hpcVer (orLaterVersion version07) then return hpcDirs@@ -69,69 +70,72 @@ return passedDirs -- Prior to GHC 8.0, hpc assumes all .mix paths are relative.- hpcDirs'' <- traverse makeRelativeToCurrentDirectory hpcDirs'+ hpcDirs'' <- traverse (tryMakeRelative mbWorkDir) hpcDirs' runProgramInvocation verbosity- (markupInvocation hpc tixFile hpcDirs'' destDir included)+ (markupInvocation mbWorkDir hpc tixFile hpcDirs'' destDir included) where version07 = mkVersion [0, 7] (passedDirs, droppedDirs) = splitAt 1 hpcDirs markupInvocation- :: ConfiguredProgram- -> FilePath+ :: Maybe (SymbolicPath CWD (Dir Pkg))+ -> ConfiguredProgram+ -> SymbolicPath Pkg File -- ^ Path to .tix file- -> [FilePath]+ -> [SymbolicPath Pkg (Dir Mix)] -- ^ Paths to .mix file directories- -> FilePath+ -> SymbolicPath Pkg (Dir Artifacts) -- ^ Path where html output should be -- located -> [ModuleName] -- ^ List of modules to include -> ProgramInvocation-markupInvocation hpc tixFile hpcDirs destDir included =+markupInvocation mbWorkDir hpc tixFile hpcDirs destDir included = let args = [ "markup"- , tixFile- , "--destdir=" ++ destDir+ , getSymbolicPath tixFile+ , "--destdir=" ++ getSymbolicPath destDir ]- ++ map ("--hpcdir=" ++) hpcDirs+ ++ map (("--hpcdir=" ++) . getSymbolicPath) hpcDirs ++ [ "--include=" ++ prettyShow moduleName | moduleName <- included ]- in programInvocation hpc args+ in programInvocationCwd mbWorkDir hpc args union- :: ConfiguredProgram+ :: Maybe (SymbolicPath CWD (Dir Pkg))+ -> ConfiguredProgram -> Verbosity- -> [FilePath]+ -> [SymbolicPath Pkg File] -- ^ Paths to .tix files- -> FilePath+ -> SymbolicPath Pkg File -- ^ Path to resultant .tix file -> [ModuleName] -- ^ List of modules to exclude from union -> IO ()-union hpc verbosity tixFiles outFile excluded =+union mbWorkDir hpc verbosity tixFiles outFile excluded = runProgramInvocation verbosity- (unionInvocation hpc tixFiles outFile excluded)+ (unionInvocation mbWorkDir hpc tixFiles outFile excluded) unionInvocation- :: ConfiguredProgram- -> [FilePath]+ :: Maybe (SymbolicPath CWD (Dir Pkg))+ -> ConfiguredProgram+ -> [SymbolicPath Pkg File] -- ^ Paths to .tix files- -> FilePath+ -> SymbolicPath Pkg File -- ^ Path to resultant .tix file -> [ModuleName] -- ^ List of modules to exclude from union -> ProgramInvocation-unionInvocation hpc tixFiles outFile excluded =- programInvocation hpc $+unionInvocation mbWorkDir hpc tixFiles outFile excluded =+ programInvocationCwd mbWorkDir hpc $ concat [ ["sum", "--union"]- , tixFiles- , ["--output=" ++ outFile]+ , map getSymbolicPath tixFiles+ , ["--output=" ++ getSymbolicPath outFile] , [ "--exclude=" ++ prettyShow moduleName | moduleName <- excluded ]
src/Distribution/Simple/Program/Ld.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} @@ -22,14 +23,14 @@ import Distribution.Simple.Flag ( fromFlagOrDefault )-import Distribution.Simple.LocalBuildInfo (LocalBuildInfo (..))+import Distribution.Simple.LocalBuildInfo (LocalBuildInfo (..), mbWorkDirLBI) import Distribution.Simple.Program.ResponseFile ( withResponseFile ) import Distribution.Simple.Program.Run ( ProgramInvocation , multiStageProgramInvocation- , programInvocation+ , programInvocationCwd , runProgramInvocation ) import Distribution.Simple.Program.Types@@ -41,6 +42,7 @@ import Distribution.Simple.Utils ( defaultTempFileOptions )+import Distribution.Utils.Path import Distribution.Verbosity ( Verbosity )@@ -48,59 +50,63 @@ import System.Directory ( renameFile )-import System.FilePath- ( takeDirectory- , (<.>)- ) -- | Call @ld -r@ to link a bunch of object files together. combineObjectFiles :: Verbosity -> LocalBuildInfo -> ConfiguredProgram- -> FilePath- -> [FilePath]+ -> SymbolicPath Pkg File+ -> [SymbolicPath Pkg File] -> IO ()-combineObjectFiles verbosity lbi ld target files = do+combineObjectFiles verbosity lbi ldProg target files = do -- Unlike "ar", the "ld" tool is not designed to be used with xargs. That is, -- if we have more object files than fit on a single command line then we -- have a slight problem. What we have to do is link files in batches into -- a temp object file and then include that one in the next batch. - let simpleArgs = ["-r", "-o", target]+ let+ -- See Note [Symbolic paths] in Distribution.Utils.Path+ u :: SymbolicPath Pkg to -> FilePath+ u = interpretSymbolicPathCWD+ i = interpretSymbolicPath mbWorkDir+ mbWorkDir = mbWorkDirLBI lbi - initialArgs = ["-r", "-o", target]- middleArgs = ["-r", "-o", target, tmpfile]- finalArgs = middleArgs+ simpleArgs = ["-r", "-o", u target]+ initialArgs = ["-r", "-o", u target]+ middleArgs = ["-r", "-o", u target, u tmpfile]+ finalArgs = middleArgs - simple = programInvocation ld simpleArgs- initial = programInvocation ld initialArgs- middle = programInvocation ld middleArgs- final = programInvocation ld finalArgs+ ld = programInvocationCwd (mbWorkDirLBI lbi) ldProg+ simple = ld simpleArgs+ initial = ld initialArgs+ middle = ld middleArgs+ final = ld finalArgs - targetDir = takeDirectory target+ targetDir = takeDirectorySymbolicPath target - invokeWithResponesFile :: FilePath -> ProgramInvocation- invokeWithResponesFile atFile =- programInvocation ld $ simpleArgs ++ ['@' : atFile]+ invokeWithResponseFile :: FilePath -> ProgramInvocation+ invokeWithResponseFile atFile =+ ld $ simpleArgs ++ ['@' : atFile] - oldVersionManualOverride =- fromFlagOrDefault False $ configUseResponseFiles $ configFlags lbi- -- Whether ghc's ar supports response files is a good proxy for- -- whether ghc's ld supports them as well.- responseArgumentsNotSupported =- not (arResponseFilesSupported (compiler lbi))+ oldVersionManualOverride =+ fromFlagOrDefault False $ configUseResponseFiles $ configFlags lbi+ -- Whether ghc's ar supports response files is a good proxy for+ -- whether ghc's ld supports them as well.+ responseArgumentsNotSupported =+ not (arResponseFilesSupported (compiler lbi)) - if oldVersionManualOverride || responseArgumentsNotSupported- then run $ multiStageProgramInvocation simple (initial, middle, final) files- else withResponseFile verbosity defaultTempFileOptions targetDir "ld.rsp" Nothing files $- \path -> runProgramInvocation verbosity $ invokeWithResponesFile path- where- tmpfile = target <.> "tmp" -- perhaps should use a proper temp file run :: [ProgramInvocation] -> IO () run [] = return () run [inv] = runProgramInvocation verbosity inv run (inv : invs) = do runProgramInvocation verbosity inv- renameFile target tmpfile+ renameFile (i target) (i tmpfile) run invs++ if oldVersionManualOverride || responseArgumentsNotSupported+ then run $ multiStageProgramInvocation simple (initial, middle, final) (map getSymbolicPath files)+ else withResponseFile verbosity defaultTempFileOptions mbWorkDir targetDir "ld.rsp" Nothing (map getSymbolicPath files) $+ \path -> runProgramInvocation verbosity $ invokeWithResponseFile path+ where+ tmpfile = target <.> "tmp" -- perhaps should use a proper temp file
src/Distribution/Simple/Program/ResponseFile.hs view
@@ -1,5 +1,7 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeApplications #-} ---------------------------------------------------------------------------- @@ -19,14 +21,17 @@ import Distribution.Compat.Prelude import Distribution.Simple.Utils (TempFileOptions, debug, withTempFileEx)+import Distribution.Utils.Path import Distribution.Verbosity withResponseFile :: Verbosity -> TempFileOptions- -> FilePath- -- ^ Working directory to create response file in.- -> FilePath+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -- ^ Working directory+ -> SymbolicPath Pkg (Dir Response)+ -- ^ Directory to create response file in.+ -> String -- ^ Template for response file name. -> Maybe TextEncoding -- ^ Encoding to use for response file contents.@@ -34,10 +39,14 @@ -- ^ Arguments to put into response file. -> (FilePath -> IO a) -> IO a-withResponseFile verbosity tmpFileOpts workDir fileNameTemplate encoding arguments f =- withTempFileEx tmpFileOpts workDir fileNameTemplate $ \responseFileName hf -> do+withResponseFile verbosity tmpFileOpts mbWorkDir responseDir fileNameTemplate encoding arguments f =+ withTempFileEx tmpFileOpts mbWorkDir responseDir fileNameTemplate $ \responsePath hf -> do+ let responseFileName = getSymbolicPath responsePath traverse_ (hSetEncoding hf) encoding- let responseContents = unlines $ map escapeResponseFileArg arguments+ let responseContents =+ unlines $+ map escapeResponseFileArg $+ arguments hPutStr hf responseContents hClose hf debug verbosity $ responseFileName ++ " contents: <<<"
src/Distribution/Simple/Program/Run.hs view
@@ -1,6 +1,9 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-} ----------------------------------------------------------------------------- @@ -19,6 +22,7 @@ , emptyProgramInvocation , simpleProgramInvocation , programInvocation+ , programInvocationCwd , multiStageProgramInvocation , runProgramInvocation , getProgramInvocationOutput@@ -36,6 +40,7 @@ import Distribution.Simple.Program.Types import Distribution.Simple.Utils import Distribution.Utils.Generic+import Distribution.Utils.Path import Distribution.Verbosity import qualified Data.ByteString.Lazy as LBS@@ -79,14 +84,20 @@ , progInvokeOutputEncoding = IOEncodingText } -simpleProgramInvocation :: FilePath -> [String] -> ProgramInvocation+simpleProgramInvocation+ :: FilePath+ -> [String]+ -> ProgramInvocation simpleProgramInvocation path args = emptyProgramInvocation { progInvokePath = path , progInvokeArgs = args } -programInvocation :: ConfiguredProgram -> [String] -> ProgramInvocation+programInvocation+ :: ConfiguredProgram+ -> [String]+ -> ProgramInvocation programInvocation prog args = emptyProgramInvocation { progInvokePath = programPath prog@@ -97,6 +108,17 @@ , progInvokeEnv = programOverrideEnv prog } +programInvocationCwd+ :: forall to+ . Maybe (SymbolicPath CWD (Dir to))+ -> ConfiguredProgram+ -> [String]+ -> ProgramInvocation+programInvocationCwd mbWorkDir prog args =+ (programInvocation prog args)+ { progInvokeCwd = fmap getSymbolicPath mbWorkDir+ }+ runProgramInvocation :: Verbosity -> ProgramInvocation -> IO () runProgramInvocation verbosity@@ -107,7 +129,7 @@ , progInvokeCwd = Nothing , progInvokeInput = Nothing } =- rawSystemExit verbosity path args+ rawSystemExit verbosity Nothing path args runProgramInvocation verbosity ProgramInvocation
src/Distribution/Simple/Program/Types.hs view
@@ -107,7 +107,7 @@ ProgramSearchPathDir FilePath | -- | The system default ProgramSearchPathDefault- deriving (Eq, Generic, Typeable)+ deriving (Show, Eq, Generic, Typeable) instance Binary ProgramSearchPathEntry instance Structured ProgramSearchPathEntry
src/Distribution/Simple/Register.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} @@ -76,14 +77,16 @@ import Distribution.Simple.Program import qualified Distribution.Simple.Program.HcPkg as HcPkg import Distribution.Simple.Program.Script+import Distribution.Simple.Setup.Common import Distribution.Simple.Setup.Register import Distribution.Simple.Utils import Distribution.System import Distribution.Utils.MapAccum+import Distribution.Utils.Path import Distribution.Verbosity as Verbosity import Distribution.Version import System.Directory-import System.FilePath (isAbsolute, (<.>), (</>))+import System.FilePath (isAbsolute) import qualified Data.ByteString.Lazy.Char8 as BS.Char8 @@ -96,34 +99,30 @@ -> RegisterFlags -- ^ Install in the user's database?; verbose -> IO ()-register pkg_descr lbi0 flags =+register pkg_descr lbi0 flags = do -- Duncan originally asked for us to not register/install files -- when there was no public library. But with per-component -- configure, we legitimately need to install internal libraries -- so that we can get them. So just unconditionally install.- doRegister- where- doRegister = do- targets <- readTargetInfos verbosity pkg_descr lbi0 (regArgs flags)+ let verbosity = fromFlag $ registerVerbosity flags+ targets <- readTargetInfos verbosity pkg_descr lbi0 $ registerTargets flags - -- It's important to register in build order, because ghc-pkg- -- will complain if a dependency is not registered.- let componentsToRegister =- neededTargetsInBuildOrder' pkg_descr lbi0 (map nodeKey targets)+ -- It's important to register in build order, because ghc-pkg+ -- will complain if a dependency is not registered.+ let componentsToRegister =+ neededTargetsInBuildOrder' pkg_descr lbi0 (map nodeKey targets) - (_, ipi_mbs) <-- mapAccumM `flip` installedPkgs lbi0 `flip` componentsToRegister $ \index tgt ->- case targetComponent tgt of- CLib lib -> do- let clbi = targetCLBI tgt- lbi = lbi0{installedPkgs = index}- ipi <- generateOne pkg_descr lib lbi clbi flags- return (Index.insert ipi index, Just ipi)- _ -> return (index, Nothing)+ (_, ipi_mbs) <-+ mapAccumM `flip` installedPkgs lbi0 `flip` componentsToRegister $ \index tgt ->+ case targetComponent tgt of+ CLib lib -> do+ let clbi = targetCLBI tgt+ lbi = lbi0{installedPkgs = index}+ ipi <- generateOne pkg_descr lib lbi clbi flags+ return (Index.insert ipi index, Just ipi)+ _ -> return (index, Nothing) - registerAll pkg_descr lbi0 flags (catMaybes ipi_mbs)- where- verbosity = fromFlag (regVerbosity flags)+ registerAll pkg_descr lbi0 flags (catMaybes ipi_mbs) generateOne :: PackageDescription@@ -134,7 +133,7 @@ -> IO InstalledPackageInfo generateOne pkg lib lbi clbi regFlags = do- absPackageDBs <- absolutePackageDBPaths packageDbs+ absPackageDBs <- absolutePackageDBPaths mbWorkDir packageDbs installedPkgInfo <- generateRegistrationInfo verbosity@@ -149,6 +148,7 @@ info verbosity (IPI.showInstalledPackageInfo installedPkgInfo) return installedPkgInfo where+ common = registerCommonFlags regFlags inplace = fromFlag (regInPlace regFlags) reloc = relocatable lbi -- FIXME: there's really no guarantee this will work.@@ -158,8 +158,9 @@ nub $ withPackageDB lbi ++ maybeToList (flagToMaybe (regPackageDB regFlags))- distPref = fromFlag (regDistPref regFlags)- verbosity = fromFlag (regVerbosity regFlags)+ distPref = fromFlag $ setupDistPref common+ verbosity = fromFlag $ setupVerbosity common+ mbWorkDir = flagToMaybe $ setupWorkingDir common registerAll :: PackageDescription@@ -195,15 +196,17 @@ verbosity (compiler lbi) (withPrograms lbi)+ (mbWorkDirLBI lbi) packageDbs ipi HcPkg.defaultRegisterOptions where modeGenerateRegFile = isJust (flagToMaybe (regGenPkgConf regFlags)) regFile =- fromMaybe- (prettyShow (packageId pkg) <.> "conf")- (fromFlag (regGenPkgConf regFlags))+ interpretSymbolicPathLBI lbi $+ fromMaybe+ (makeSymbolicPath (prettyShow (packageId pkg) <.> "conf"))+ (fromFlag (regGenPkgConf regFlags)) modeGenerateRegScript = fromFlag (regGenScript regFlags) @@ -214,7 +217,9 @@ nub $ withPackageDB lbi ++ maybeToList (flagToMaybe (regPackageDB regFlags))- verbosity = fromFlag (regVerbosity regFlags)+ common = registerCommonFlags regFlags+ verbosity = fromFlag (setupVerbosity common)+ mbWorkDir = mbWorkDirLBI lbi writeRegistrationFileOrDirectory = do -- Handles overwriting both directory and file@@ -245,7 +250,7 @@ "Registration scripts are not implemented for this compiler" (compiler lbi) (withPrograms lbi)- (writeHcPkgRegisterScript verbosity ipis packageDbs)+ (writeHcPkgRegisterScript verbosity mbWorkDir ipis packageDbs) generateRegistrationInfo :: Verbosity@@ -255,13 +260,11 @@ -> ComponentLocalBuildInfo -> Bool -> Bool- -> FilePath+ -> SymbolicPath Pkg (Dir Dist) -> PackageDB -> IO InstalledPackageInfo generateRegistrationInfo verbosity pkg lib lbi clbi inplace reloc distPref packageDb = do- -- TODO: eliminate pwd!- pwd <- getCurrentDirectory-+ inplaceDir <- absoluteWorkingDirLBI lbi installedPkgInfo <- if inplace then -- NB: With an inplace installation, the user may run './Setup@@ -270,7 +273,7 @@ return ( inplaceInstalledPackageInfo- pwd+ inplaceDir distPref pkg (mkAbiHash "inplace")@@ -306,7 +309,7 @@ abiHash :: Verbosity -> PackageDescription- -> FilePath+ -> SymbolicPath Pkg (Dir Dist) -> LocalBuildInfo -> Library -> ComponentLocalBuildInfo@@ -395,16 +398,17 @@ :: Verbosity -> Compiler -> ProgramDb+ -> Maybe (SymbolicPath CWD (Dir Pkg)) -> PackageDBStack -> [String] -> IO ()-invokeHcPkg verbosity comp progdb dbStack extraArgs =+invokeHcPkg verbosity comp progdb mbWorkDir dbStack extraArgs = withHcPkg verbosity "invokeHcPkg" comp progdb- (\hpi -> HcPkg.invoke hpi verbosity dbStack extraArgs)+ (\hpi -> HcPkg.invoke hpi verbosity mbWorkDir dbStack extraArgs) withHcPkg :: Verbosity@@ -423,34 +427,37 @@ :: Verbosity -> Compiler -> ProgramDb- -> PackageDBStack+ -> Maybe (SymbolicPath CWD (Dir from))+ -> PackageDBStackS from -> InstalledPackageInfo -> HcPkg.RegisterOptions -> IO ()-registerPackage verbosity comp progdb packageDbs installedPkgInfo registerOptions =+registerPackage verbosity comp progdb mbWorkDir packageDbs installedPkgInfo registerOptions = case compilerFlavor comp of- GHC -> GHC.registerPackage verbosity progdb packageDbs installedPkgInfo registerOptions- GHCJS -> GHCJS.registerPackage verbosity progdb packageDbs installedPkgInfo registerOptions+ GHC -> GHC.registerPackage verbosity progdb mbWorkDir packageDbs installedPkgInfo registerOptions+ GHCJS -> GHCJS.registerPackage verbosity progdb mbWorkDir packageDbs installedPkgInfo registerOptions HaskellSuite{} -> HaskellSuite.registerPackage verbosity progdb packageDbs installedPkgInfo _ | HcPkg.registerMultiInstance registerOptions -> dieWithException verbosity RegisMultiplePkgNotSupported- UHC -> UHC.registerPackage verbosity comp progdb packageDbs installedPkgInfo+ UHC -> UHC.registerPackage verbosity mbWorkDir comp progdb packageDbs installedPkgInfo _ -> dieWithException verbosity RegisteringNotImplemented writeHcPkgRegisterScript :: Verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg)) -> [InstalledPackageInfo] -> PackageDBStack -> HcPkg.HcPkgInfo -> IO ()-writeHcPkgRegisterScript verbosity ipis packageDbs hpi = do+writeHcPkgRegisterScript verbosity mbWorkDir ipis packageDbs hpi = do let genScript installedPkgInfo = let invocation = HcPkg.registerInvocation hpi Verbosity.normal+ mbWorkDir packageDbs installedPkgInfo HcPkg.defaultRegisterOptions@@ -459,14 +466,15 @@ -- TODO: Do something more robust here regScript = unlines scripts - info verbosity ("Creating package registration script: " ++ regScriptFileName)- writeUTF8File regScriptFileName regScript- setFileExecutable regScriptFileName+ let out_file = interpretSymbolicPath mbWorkDir regScriptFileName+ info verbosity ("Creating package registration script: " ++ out_file)+ writeUTF8File out_file regScript+ setFileExecutable out_file -regScriptFileName :: FilePath+regScriptFileName :: SymbolicPath Pkg File regScriptFileName = case buildOS of- Windows -> "register.bat"- _ -> "register.sh"+ Windows -> makeSymbolicPath "register.bat"+ _ -> makeSymbolicPath "register.sh" -- ----------------------------------------------------------------------------- -- Making the InstalledPackageInfo@@ -531,7 +539,7 @@ , IPI.extraLibrariesStatic = extraLibsStatic bi , IPI.extraGHCiLibraries = extraGHCiLibs bi , IPI.includeDirs = absinc ++ adjustRelIncDirs relinc- , IPI.includes = includes bi+ , IPI.includes = map getSymbolicPath $ includes bi , IPI.depends = depends , IPI.abiDepends = [] -- due to #5465 , IPI.ccOptions = [] -- Note. NOT ccOptions bi!@@ -539,9 +547,9 @@ -- to C compilations in other packages. , IPI.cxxOptions = [] -- Also. NOT cxxOptions bi! , IPI.ldOptions = ldOptions bi- , IPI.frameworks = frameworks bi- , IPI.frameworkDirs = extraFrameworkDirs bi- , IPI.haddockInterfaces = [haddockdir installDirs </> haddockName pkg]+ , IPI.frameworks = map getSymbolicPath $ frameworks bi+ , IPI.frameworkDirs = map getSymbolicPath $ extraFrameworkDirs bi+ , IPI.haddockInterfaces = [haddockdir installDirs </> haddockLibraryPath pkg lib] , IPI.haddockHTMLs = [htmldir installDirs] , IPI.pkgRoot = Nothing , IPI.libVisibility = libVisibility lib@@ -555,7 +563,7 @@ -- TODO: unclear what the root cause of the -- duplication is, but we nub it here for now: depends = ordNub $ map fst (componentPackageDeps clbi)- (absinc, relinc) = partition isAbsolute (includeDirs bi)+ (absinc, relinc) = partition isAbsolute (map getSymbolicPath $ includeDirs bi) hasModules = not $ null (allLibModules lib clbi) comp = compiler lbi hasLibrary =@@ -570,6 +578,7 @@ hasJsSupport = case hostPlatform lbi of Platform JavaScript _ -> True _ -> False+ extraLibDirs' = map getSymbolicPath $ extraLibDirs bi libdirsStatic | hasLibrary = libdir installDirs : extraLibDirsStaticOrFallback | otherwise = extraLibDirsStaticOrFallback@@ -578,20 +587,20 @@ -- distinction between fully static linking and otherwise. -- Fall back to the normal library dirs in that case. extraLibDirsStaticOrFallback = case extraLibDirsStatic bi of- [] -> extraLibDirs bi- dirs -> dirs+ [] -> extraLibDirs'+ dirs -> map getSymbolicPath dirs (libdirs, dynlibdirs) | not hasLibrary =- (extraLibDirs bi, [])+ (extraLibDirs', []) -- the dynamic-library-dirs defaults to the library-dirs if not specified, -- so this works whether the dynamic-library-dirs field is supported or not | libraryDynDirSupported comp =- ( libdir installDirs : extraLibDirs bi- , dynlibdir installDirs : extraLibDirs bi+ ( libdir installDirs : extraLibDirs'+ , dynlibdir installDirs : extraLibDirs' ) | otherwise =- (libdir installDirs : dynlibdir installDirs : extraLibDirs bi, [])+ (libdir installDirs : dynlibdir installDirs : extraLibDirs', []) -- the compiler doesn't understand the dynamic-library-dirs field so we -- add the dyn directory to the "normal" list in the library-dirs field@@ -601,9 +610,8 @@ -- -- This function knows about the layout of in place packages. inplaceInstalledPackageInfo- :: FilePath- -- ^ top of the build tree- -> FilePath+ :: AbsolutePath (Dir Pkg)+ -> SymbolicPath Pkg (Dir Dist) -- ^ location of the dist tree -> PackageDescription -> AbiHash@@ -621,22 +629,27 @@ clbi installDirs where+ i = interpretSymbolicPathAbsolute inplaceDir -- See Note [Symbolic paths] in Distribution.Utils.Path adjustRelativeIncludeDirs = concatMap $ \d ->- [ inplaceDir </> d -- local include-dir- , inplaceDir </> libTargetDir </> d -- autogen include-dir+ [ i $ makeRelativePathEx d -- local include-dir+ , i $ libTargetDir </> makeRelativePathEx d -- autogen include-dir ] libTargetDir = componentBuildDir lbi clbi installDirs = (absoluteComponentInstallDirs pkg lbi (componentUnitId clbi) NoCopyDest)- { libdir = inplaceDir </> libTargetDir- , dynlibdir = inplaceDir </> libTargetDir- , datadir = inplaceDir </> dataDir pkg- , docdir = inplaceDocdir+ { libdir = i libTargetDir+ , dynlibdir = i libTargetDir+ , datadir =+ let rawDataDir = dataDir pkg+ in if null $ getSymbolicPath rawDataDir+ then i sameDirectory+ else i rawDataDir+ , docdir = i inplaceDocdir , htmldir = inplaceHtmldir , haddockdir = inplaceHtmldir }- inplaceDocdir = inplaceDir </> distPref </> "doc"- inplaceHtmldir = inplaceDocdir </> "html" </> prettyShow (packageName pkg)+ inplaceDocdir = distPref </> makeRelativePathEx "doc"+ inplaceHtmldir = i $ inplaceDocdir </> makeRelativePathEx ("html" </> prettyShow (packageName pkg)) -- | Construct 'InstalledPackageInfo' for the final install location of a -- library package.@@ -673,7 +686,7 @@ -> Library -> LocalBuildInfo -> ComponentLocalBuildInfo- -> FilePath+ -> SymbolicPath CWD ('Dir Pkg) -> InstalledPackageInfo relocatableInstalledPackageInfo pkg abi_hash lib lbi clbi pkgroot = generalInstalledPackageInfo@@ -693,7 +706,7 @@ bi = libBuildInfo lib installDirs =- fmap (("${pkgroot}" </>) . shortRelativePath pkgroot) $+ fmap (("${pkgroot}" </>) . shortRelativePath (getSymbolicPath pkgroot)) $ absoluteComponentInstallDirs pkg lbi (componentUnitId clbi) NoCopyDest -- -----------------------------------------------------------------------------@@ -702,17 +715,20 @@ unregister :: PackageDescription -> LocalBuildInfo -> RegisterFlags -> IO () unregister pkg lbi regFlags = do let pkgid = packageId pkg+ common = registerCommonFlags regFlags genScript = fromFlag (regGenScript regFlags)- verbosity = fromFlag (regVerbosity regFlags)+ verbosity = fromFlag (setupVerbosity common) packageDb = fromFlagOrDefault (registrationPackageDB (withPackageDB lbi)) (regPackageDB regFlags)+ mbWorkDir = mbWorkDirLBI lbi unreg hpi = let invocation = HcPkg.unregisterInvocation hpi Verbosity.normal+ mbWorkDir packageDb pkgid in if genScript@@ -734,8 +750,8 @@ Windows -> "unregister.bat" _ -> "unregister.sh" -internalPackageDBPath :: LocalBuildInfo -> FilePath -> FilePath+internalPackageDBPath :: LocalBuildInfo -> SymbolicPath Pkg (Dir Dist) -> SymbolicPath Pkg (Dir PkgDB) internalPackageDBPath lbi distPref = case compilerFlavor (compiler lbi) of UHC -> UHC.inplacePackageDbPath lbi- _ -> distPref </> "package.conf.inplace"+ _ -> distPref </> makeRelativePathEx "package.conf.inplace"
src/Distribution/Simple/Setup.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-}@@ -38,12 +39,13 @@ , emptyGlobalFlags , defaultGlobalFlags , globalCommand+ , CommonSetupFlags (..)+ , defaultCommonSetupFlags , ConfigFlags (..) , emptyConfigFlags , defaultConfigFlags , configureCommand , configPrograms- , configAbsolutePaths , readPackageDb , readPackageDbList , showPackageDb@@ -133,12 +135,14 @@ , falseArg , optionVerbosity , BuildingWhat (..)+ , buildingWhatCommonFlags , buildingWhatVerbosity+ , buildingWhatWorkingDir , buildingWhatDistPref ) where -import GHC.Generics (Generic)-import Prelude (FilePath, Show, ($))+import Distribution.Compat.Prelude+import Prelude () import Distribution.Simple.Flag import Distribution.Simple.InstallDirs@@ -155,13 +159,20 @@ import Distribution.Simple.Setup.Hscolour import Distribution.Simple.Setup.Install import Distribution.Simple.Setup.Register+ ( RegisterFlags (..)+ , defaultRegisterFlags+ , emptyRegisterFlags+ , registerCommand+ , unregisterCommand+ ) import Distribution.Simple.Setup.Repl import Distribution.Simple.Setup.SDist import Distribution.Simple.Setup.Test+import Distribution.Utils.Path import Distribution.Verbosity (Verbosity) --- | What kind of build are we doing?+-- | What kind of build phase are we doing/hooking into? -- -- Is this a normal build, or is it perhaps for running an interactive -- session or Haddock?@@ -176,20 +187,22 @@ BuildHscolour HscolourFlags deriving (Generic, Show) +buildingWhatCommonFlags :: BuildingWhat -> CommonSetupFlags+buildingWhatCommonFlags = \case+ BuildNormal flags -> buildCommonFlags flags+ BuildRepl flags -> replCommonFlags flags+ BuildHaddock flags -> haddockCommonFlags flags+ BuildHscolour flags -> hscolourCommonFlags flags+ buildingWhatVerbosity :: BuildingWhat -> Verbosity-buildingWhatVerbosity = \case- BuildNormal flags -> fromFlag $ buildVerbosity flags- BuildRepl flags -> fromFlag $ replVerbosity flags- BuildHaddock flags -> fromFlag $ haddockVerbosity flags- BuildHscolour flags -> fromFlag $ hscolourVerbosity flags+buildingWhatVerbosity = fromFlag . setupVerbosity . buildingWhatCommonFlags -buildingWhatDistPref :: BuildingWhat -> FilePath-buildingWhatDistPref = \case- BuildNormal flags -> fromFlag $ buildDistPref flags- BuildRepl flags -> fromFlag $ replDistPref flags- BuildHaddock flags -> fromFlag $ haddockDistPref flags- BuildHscolour flags -> fromFlag $ hscolourDistPref flags+buildingWhatWorkingDir :: BuildingWhat -> Maybe (SymbolicPath CWD (Dir Pkg))+buildingWhatWorkingDir = flagToMaybe . setupWorkingDir . buildingWhatCommonFlags +buildingWhatDistPref :: BuildingWhat -> SymbolicPath Pkg (Dir Dist)+buildingWhatDistPref = fromFlag . setupDistPref . buildingWhatCommonFlags+ -- The test cases kinda have to be rewritten from the ground up... :/ -- hunitTests :: [Test] -- hunitTests =@@ -233,3 +246,6 @@ * quickCheck to test permutations of arguments * what other options can we over-ride with a command-line flag? -}++instance Binary BuildingWhat+instance Structured BuildingWhat
src/Distribution/Simple/Setup/Benchmark.hs view
@@ -1,8 +1,11 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ViewPatterns #-} ----------------------------------------------------------------------------- @@ -18,7 +21,15 @@ -- Definition of the benchmarking command-line options. -- See: @Distribution.Simple.Setup@ module Distribution.Simple.Setup.Benchmark- ( BenchmarkFlags (..)+ ( BenchmarkFlags+ ( BenchmarkCommonFlags+ , benchmarkVerbosity+ , benchmarkDistPref+ , benchmarkCabalFilePath+ , benchmarkWorkingDir+ , benchmarkTargets+ , ..+ ) , emptyBenchmarkFlags , defaultBenchmarkFlags , benchmarkCommand@@ -29,13 +40,12 @@ import Prelude () import Distribution.Simple.Command hiding (boolOpt, boolOpt')-import Distribution.Simple.Flag import Distribution.Simple.InstallDirs+import Distribution.Simple.Setup.Common import Distribution.Simple.Utils+import Distribution.Utils.Path import Distribution.Verbosity -import Distribution.Simple.Setup.Common- -- ------------------------------------------------------------ -- * Benchmark flags@@ -43,20 +53,42 @@ -- ------------------------------------------------------------ data BenchmarkFlags = BenchmarkFlags- { benchmarkDistPref :: Flag FilePath- , benchmarkVerbosity :: Flag Verbosity+ { benchmarkCommonFlags :: !CommonSetupFlags , benchmarkOptions :: [PathTemplate] } deriving (Show, Generic, Typeable) +pattern BenchmarkCommonFlags+ :: Flag Verbosity+ -> Flag (SymbolicPath Pkg (Dir Dist))+ -> Flag (SymbolicPath CWD (Dir Pkg))+ -> Flag (SymbolicPath Pkg File)+ -> [String]+ -> BenchmarkFlags+pattern BenchmarkCommonFlags+ { benchmarkVerbosity+ , benchmarkDistPref+ , benchmarkWorkingDir+ , benchmarkCabalFilePath+ , benchmarkTargets+ } <-+ ( benchmarkCommonFlags ->+ CommonSetupFlags+ { setupVerbosity = benchmarkVerbosity+ , setupDistPref = benchmarkDistPref+ , setupWorkingDir = benchmarkWorkingDir+ , setupCabalFilePath = benchmarkCabalFilePath+ , setupTargets = benchmarkTargets+ }+ )+ instance Binary BenchmarkFlags instance Structured BenchmarkFlags defaultBenchmarkFlags :: BenchmarkFlags defaultBenchmarkFlags = BenchmarkFlags- { benchmarkDistPref = NoFlag- , benchmarkVerbosity = Flag normal+ { benchmarkCommonFlags = defaultCommonSetupFlags , benchmarkOptions = [] } @@ -82,43 +114,40 @@ benchmarkOptions' :: ShowOrParseArgs -> [OptionField BenchmarkFlags] benchmarkOptions' showOrParseArgs =- [ optionVerbosity- benchmarkVerbosity- (\v flags -> flags{benchmarkVerbosity = v})- , optionDistPref- benchmarkDistPref- (\d flags -> flags{benchmarkDistPref = d})- showOrParseArgs- , option- []- ["benchmark-options"]- ( "give extra options to benchmark executables "- ++ "(name templates can use $pkgid, $compiler, "- ++ "$os, $arch, $benchmark)"- )- benchmarkOptions- (\v flags -> flags{benchmarkOptions = v})- ( reqArg'- "TEMPLATES"- (map toPathTemplate . splitArgs)- (const [])- )- , option- []- ["benchmark-option"]- ( "give extra option to benchmark executables "- ++ "(no need to quote options containing spaces, "- ++ "name template can use $pkgid, $compiler, "- ++ "$os, $arch, $benchmark)"- )- benchmarkOptions- (\v flags -> flags{benchmarkOptions = v})- ( reqArg'- "TEMPLATE"- (\x -> [toPathTemplate x])- (map fromPathTemplate)- )- ]+ withCommonSetupOptions+ benchmarkCommonFlags+ (\c f -> f{benchmarkCommonFlags = c})+ showOrParseArgs+ [ option+ []+ ["benchmark-options"]+ ( "give extra options to benchmark executables "+ ++ "(name templates can use $pkgid, $compiler, "+ ++ "$os, $arch, $benchmark)"+ )+ benchmarkOptions+ (\v flags -> flags{benchmarkOptions = v})+ ( reqArg'+ "TEMPLATES"+ (map toPathTemplate . splitArgs)+ (const [])+ )+ , option+ []+ ["benchmark-option"]+ ( "give extra option to benchmark executables "+ ++ "(no need to quote options containing spaces, "+ ++ "name template can use $pkgid, $compiler, "+ ++ "$os, $arch, $benchmark)"+ )+ benchmarkOptions+ (\v flags -> flags{benchmarkOptions = v})+ ( reqArg'+ "TEMPLATE"+ (\x -> [toPathTemplate x])+ (map fromPathTemplate)+ )+ ] emptyBenchmarkFlags :: BenchmarkFlags emptyBenchmarkFlags = mempty
src/Distribution/Simple/Setup/Build.hs view
@@ -1,8 +1,11 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ViewPatterns #-} ----------------------------------------------------------------------------- @@ -18,7 +21,15 @@ -- Definition of the build command-line options. -- See: @Distribution.Simple.Setup@ module Distribution.Simple.Setup.Build- ( BuildFlags (..)+ ( BuildFlags+ ( BuildCommonFlags+ , buildVerbosity+ , buildDistPref+ , buildCabalFilePath+ , buildWorkingDir+ , buildTargets+ , ..+ ) , emptyBuildFlags , defaultBuildFlags , buildCommand@@ -32,12 +43,12 @@ import Distribution.Simple.Command hiding (boolOpt, boolOpt') import Distribution.Simple.Flag import Distribution.Simple.Program+import Distribution.Simple.Setup.Common import Distribution.Simple.Utils import Distribution.Types.DumpBuildInfo+import Distribution.Utils.Path import Distribution.Verbosity -import Distribution.Simple.Setup.Common- -- ------------------------------------------------------------ -- * Build flags@@ -45,33 +56,49 @@ -- ------------------------------------------------------------ data BuildFlags = BuildFlags- { buildProgramPaths :: [(String, FilePath)]+ { buildCommonFlags :: !CommonSetupFlags+ , buildProgramPaths :: [(String, FilePath)] , buildProgramArgs :: [(String, [String])]- , buildDistPref :: Flag FilePath- , buildVerbosity :: Flag Verbosity , buildNumJobs :: Flag (Maybe Int) , buildUseSemaphore :: Flag String- , -- TODO: this one should not be here, it's just that the silly- -- UserHooks stop us from passing extra info in other ways- buildArgs :: [String]- , buildCabalFilePath :: Flag FilePath } deriving (Read, Show, Generic, Typeable) +pattern BuildCommonFlags+ :: Flag Verbosity+ -> Flag (SymbolicPath Pkg (Dir Dist))+ -> Flag (SymbolicPath CWD (Dir Pkg))+ -> Flag (SymbolicPath Pkg File)+ -> [String]+ -> BuildFlags+pattern BuildCommonFlags+ { buildVerbosity+ , buildDistPref+ , buildWorkingDir+ , buildCabalFilePath+ , buildTargets+ } <-+ ( buildCommonFlags ->+ CommonSetupFlags+ { setupVerbosity = buildVerbosity+ , setupDistPref = buildDistPref+ , setupWorkingDir = buildWorkingDir+ , setupCabalFilePath = buildCabalFilePath+ , setupTargets = buildTargets+ }+ )+ instance Binary BuildFlags instance Structured BuildFlags defaultBuildFlags :: BuildFlags defaultBuildFlags = BuildFlags- { buildProgramPaths = mempty+ { buildCommonFlags = defaultCommonSetupFlags+ , buildProgramPaths = mempty , buildProgramArgs = []- , buildDistPref = mempty- , buildVerbosity = Flag normal , buildNumJobs = mempty , buildUseSemaphore = NoFlag- , buildArgs = []- , buildCabalFilePath = mempty } buildCommand :: ProgramDb -> CommandUI BuildFlags@@ -110,16 +137,7 @@ , "COMPONENTS [FLAGS]" ] , commandDefaultFlags = defaultBuildFlags- , commandOptions = \showOrParseArgs ->- [ optionVerbosity- buildVerbosity- (\v flags -> flags{buildVerbosity = v})- , optionDistPref- buildDistPref- (\d flags -> flags{buildDistPref = d})- showOrParseArgs- ]- ++ buildOptions progDb showOrParseArgs+ , commandOptions = buildOptions progDb } buildOptions@@ -127,17 +145,22 @@ -> ShowOrParseArgs -> [OptionField BuildFlags] buildOptions progDb showOrParseArgs =- [ optionNumJobs- buildNumJobs- (\v flags -> flags{buildNumJobs = v})- , option- []- ["semaphore"]- "semaphore"- buildUseSemaphore- (\v flags -> flags{buildUseSemaphore = v})- (reqArg' "SEMAPHORE" Flag flagToList)- ]+ withCommonSetupOptions+ buildCommonFlags+ (\c f -> f{buildCommonFlags = c})+ showOrParseArgs+ ( [ optionNumJobs+ buildNumJobs+ (\v flags -> flags{buildNumJobs = v})+ , option+ []+ ["semaphore"]+ "semaphore"+ buildUseSemaphore+ (\v flags -> flags{buildUseSemaphore = v})+ (reqArg' "SEMAPHORE" Flag flagToList)+ ]+ ) ++ programDbPaths progDb showOrParseArgs
src/Distribution/Simple/Setup/Clean.hs view
@@ -1,8 +1,11 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ViewPatterns #-} ----------------------------------------------------------------------------- @@ -18,7 +21,15 @@ -- Definition of the clean command-line options. -- See: @Distribution.Simple.Setup@ module Distribution.Simple.Setup.Clean- ( CleanFlags (..)+ ( CleanFlags+ ( CleanCommonFlags+ , cleanVerbosity+ , cleanDistPref+ , cleanCabalFilePath+ , cleanWorkingDir+ , cleanTargets+ , ..+ ) , emptyCleanFlags , defaultCleanFlags , cleanCommand@@ -29,9 +40,9 @@ import Distribution.Simple.Command hiding (boolOpt, boolOpt') import Distribution.Simple.Flag-import Distribution.Verbosity- import Distribution.Simple.Setup.Common+import Distribution.Utils.Path+import Distribution.Verbosity -- ------------------------------------------------------------ @@ -40,23 +51,43 @@ -- ------------------------------------------------------------ data CleanFlags = CleanFlags- { cleanSaveConf :: Flag Bool- , cleanDistPref :: Flag FilePath- , cleanVerbosity :: Flag Verbosity- , cleanCabalFilePath :: Flag FilePath+ { cleanCommonFlags :: !CommonSetupFlags+ , cleanSaveConf :: Flag Bool } deriving (Show, Generic, Typeable) +pattern CleanCommonFlags+ :: Flag Verbosity+ -> Flag (SymbolicPath Pkg (Dir Dist))+ -> Flag (SymbolicPath CWD (Dir Pkg))+ -> Flag (SymbolicPath Pkg File)+ -> [String]+ -> CleanFlags+pattern CleanCommonFlags+ { cleanVerbosity+ , cleanDistPref+ , cleanWorkingDir+ , cleanCabalFilePath+ , cleanTargets+ } <-+ ( cleanCommonFlags ->+ CommonSetupFlags+ { setupVerbosity = cleanVerbosity+ , setupDistPref = cleanDistPref+ , setupWorkingDir = cleanWorkingDir+ , setupCabalFilePath = cleanCabalFilePath+ , setupTargets = cleanTargets+ }+ )+ instance Binary CleanFlags instance Structured CleanFlags defaultCleanFlags :: CleanFlags defaultCleanFlags = CleanFlags- { cleanSaveConf = Flag False- , cleanDistPref = NoFlag- , cleanVerbosity = Flag normal- , cleanCabalFilePath = mempty+ { cleanCommonFlags = defaultCommonSetupFlags+ , cleanSaveConf = Flag False } cleanCommand :: CommandUI CleanFlags@@ -71,19 +102,18 @@ "Usage: " ++ pname ++ " clean [FLAGS]\n" , commandDefaultFlags = defaultCleanFlags , commandOptions = \showOrParseArgs ->- [ optionVerbosity cleanVerbosity (\v flags -> flags{cleanVerbosity = v})- , optionDistPref- cleanDistPref- (\d flags -> flags{cleanDistPref = d})- showOrParseArgs- , option- "s"- ["save-configure"]- "Do not remove the configuration file (dist/setup-config) during cleaning. Saves need to reconfigure."- cleanSaveConf- (\v flags -> flags{cleanSaveConf = v})- trueArg- ]+ withCommonSetupOptions+ cleanCommonFlags+ (\c f -> f{cleanCommonFlags = c})+ showOrParseArgs+ [ option+ "s"+ ["save-configure"]+ "Do not remove the configuration file (dist/setup-config) during cleaning. Saves need to reconfigure."+ cleanSaveConf+ (\v flags -> flags{cleanSaveConf = v})+ trueArg+ ] } emptyCleanFlags :: CleanFlags
src/Distribution/Simple/Setup/Common.hs view
@@ -1,6 +1,8 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} @@ -18,7 +20,10 @@ -- Common utilities for defining command-line options. -- See: @Distribution.Simple.Setup@ module Distribution.Simple.Setup.Common- ( CopyDest (..)+ ( CommonSetupFlags (..)+ , defaultCommonSetupFlags+ , withCommonSetupOptions+ , CopyDest (..) , configureCCompiler , configureLinker , programDbOption@@ -44,6 +49,7 @@ , trueArg , falseArg , reqArgFlag+ , reqSymbolicPathArgFlag , optionVerbosity , optionNumJobs ) where@@ -58,16 +64,92 @@ import Distribution.Simple.InstallDirs import Distribution.Simple.Program import Distribution.Simple.Utils+import Distribution.Utils.Path import Distribution.Verbosity +--------------------------------------------------------------------------------++-- | A datatype that stores common flags for different invocations+-- of a @Setup@ executable, e.g. configure, build, install.+data CommonSetupFlags = CommonSetupFlags+ { setupVerbosity :: !(Flag Verbosity)+ -- ^ Verbosity+ , setupWorkingDir :: !(Flag (SymbolicPath CWD (Dir Pkg)))+ -- ^ Working directory (optional)+ , setupDistPref :: !(Flag (SymbolicPath Pkg (Dir Dist)))+ -- ^ Build directory+ , setupCabalFilePath :: !(Flag (SymbolicPath Pkg File))+ -- ^ Which Cabal file to use (optional)+ , setupTargets :: [String]+ -- ^ Which targets is this Setup invocation relative to?+ --+ -- TODO: this one should not be here, it's just that the silly+ -- UserHooks stop us from passing extra info in other ways+ }+ deriving (Eq, Show, Read, Generic)++instance Binary CommonSetupFlags+instance Structured CommonSetupFlags++instance Semigroup CommonSetupFlags where+ (<>) = gmappend++instance Monoid CommonSetupFlags where+ mempty = gmempty+ mappend = (<>)++defaultCommonSetupFlags :: CommonSetupFlags+defaultCommonSetupFlags =+ CommonSetupFlags+ { setupVerbosity = Flag normal+ , setupWorkingDir = NoFlag+ , setupDistPref = NoFlag+ , setupCabalFilePath = NoFlag+ , setupTargets = []+ }++commonSetupOptions :: ShowOrParseArgs -> [OptionField CommonSetupFlags]+commonSetupOptions showOrParseArgs =+ [ optionVerbosity+ setupVerbosity+ (\v flags -> flags{setupVerbosity = v})+ , optionDistPref+ setupDistPref+ (\d flags -> flags{setupDistPref = d})+ showOrParseArgs+ , option+ ""+ ["cabal-file"]+ "use this Cabal file"+ setupCabalFilePath+ (\v flags -> flags{setupCabalFilePath = v})+ (reqSymbolicPathArgFlag "PATH")+ -- NB: no --working-dir flag, as that value is populated using the+ -- global flag (see Distribution.Simple.Setup.Global.globalCommand).+ ]++withCommonSetupOptions+ :: (flags -> CommonSetupFlags)+ -> (CommonSetupFlags -> flags -> flags)+ -> ShowOrParseArgs+ -> [OptionField flags]+ -> [OptionField flags]+withCommonSetupOptions getCommon setCommon showOrParseArgs opts =+ map fmapOptionField (commonSetupOptions showOrParseArgs) ++ opts+ where+ fmapOptionField (OptionField nm descr) =+ OptionField nm (map (fmapOptDescr getCommon setCommon) descr)++--------------------------------------------------------------------------------+ -- FIXME Not sure where this should live-defaultDistPref :: FilePath-defaultDistPref = "dist"+defaultDistPref :: SymbolicPath Pkg (Dir Dist)+defaultDistPref = makeSymbolicPath "dist" -- | The name of the directory where optional compilation artifacts -- go, such as ghc plugins and .hie files.-extraCompilationArtifacts :: FilePath-extraCompilationArtifacts = "extra-compilation-artifacts"+extraCompilationArtifacts :: RelativePath Build (Dir Artifacts)+extraCompilationArtifacts = makeRelativePathEx "extra-compilation-artifacts" -- | Help text for @test@ and @bench@ commands. testOrBenchmarkHelpText@@ -248,8 +330,8 @@ reqArgFlag ad = reqArg ad (succeedReadE Flag) flagToList optionDistPref- :: (flags -> Flag FilePath)- -> (Flag FilePath -> flags -> flags)+ :: (flags -> Flag (SymbolicPath Pkg (Dir Dist)))+ -> (Flag (SymbolicPath Pkg (Dir Dist)) -> flags -> flags) -> ShowOrParseArgs -> OptionField flags optionDistPref get set = \showOrParseArgs ->@@ -258,15 +340,32 @@ (distPrefFlagName showOrParseArgs) ( "The directory where Cabal puts generated build files " ++ "(default "- ++ defaultDistPref+ ++ getSymbolicPath defaultDistPref ++ ")" ) get set- (reqArgFlag "DIR")+ (reqSymbolicPathArgFlag "DIR") where distPrefFlagName ShowArgs = ["builddir"] distPrefFlagName ParseArgs = ["builddir", "distdir", "distpref"]++reqSymbolicPathArgFlag+ :: ArgPlaceHolder+ -> SFlags+ -> LFlags+ -> Description+ -> (b -> Flag (SymbolicPath from to))+ -> (Flag (SymbolicPath from to) -> b -> b)+ -> OptDescr b+reqSymbolicPathArgFlag title sf lf d get set =+ reqArgFlag+ title+ sf+ lf+ d+ (fmap getSymbolicPath . get)+ (set . fmap makeSymbolicPath) optionVerbosity :: (flags -> Flag Verbosity)
src/Distribution/Simple/Setup/Config.hs view
@@ -1,8 +1,11 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ViewPatterns #-} ----------------------------------------------------------------------------- @@ -18,12 +21,19 @@ -- Definition of the configure command-line options. -- See: @Distribution.Simple.Setup@ module Distribution.Simple.Setup.Config- ( ConfigFlags (..)+ ( ConfigFlags+ ( ConfigCommonFlags+ , configVerbosity+ , configDistPref+ , configCabalFilePath+ , configWorkingDir+ , configTargets+ , ..+ ) , emptyConfigFlags , defaultConfigFlags , configureCommand , configPrograms- , configAbsolutePaths , readPackageDb , readPackageDbList , showPackageDb@@ -37,6 +47,8 @@ import Prelude () import qualified Distribution.Compat.CharParsing as P+import Distribution.Compat.Semigroup (Last' (..), Option' (..))+import Distribution.Compat.Stack import Distribution.Compiler import Distribution.ModuleName import Distribution.PackageDescription@@ -48,6 +60,7 @@ import Distribution.Simple.Flag import Distribution.Simple.InstallDirs import Distribution.Simple.Program+import Distribution.Simple.Setup.Common import Distribution.Simple.Utils import Distribution.Types.ComponentId import Distribution.Types.DumpBuildInfo@@ -56,13 +69,10 @@ import Distribution.Types.PackageVersionConstraint import Distribution.Types.UnitId import Distribution.Utils.NubList+import Distribution.Utils.Path import Distribution.Verbosity-import qualified Text.PrettyPrint as Disp -import Distribution.Compat.Semigroup (Last' (..), Option' (..))-import Distribution.Compat.Stack--import Distribution.Simple.Setup.Common+import qualified Text.PrettyPrint as Disp -- ------------------------------------------------------------ @@ -76,9 +86,7 @@ -- should be updated. -- IMPORTANT: every time a new flag is added, it should be added to the Eq instance data ConfigFlags = ConfigFlags- { -- This is the same hack as in 'buildArgs' and 'copyArgs'.- -- TODO: Stop using this eventually when 'UserHooks' gets changed- configArgs :: [String]+ { configCommonFlags :: !CommonSetupFlags , -- FIXME: the configPrograms is only here to pass info through to configure -- because the type of configure is constrained by the UserHooks. -- when we change UserHooks next we should pass the initial@@ -119,6 +127,8 @@ , configProf :: Flag Bool -- ^ Enable profiling in the library -- and executables.+ , configProfShared :: Flag Bool+ -- ^ Enable shared profiling objects , configProfDetail :: Flag ProfDetailLevel -- ^ Profiling detail level -- in the library and executables.@@ -137,16 +147,16 @@ -- ^ Installation -- paths , configScratchDir :: Flag FilePath- , configExtraLibDirs :: [FilePath]+ , configExtraLibDirs :: [SymbolicPath Pkg (Dir Lib)] -- ^ path to search for extra libraries- , configExtraLibDirsStatic :: [FilePath]+ , configExtraLibDirsStatic :: [SymbolicPath Pkg (Dir Lib)] -- ^ path to search for extra -- libraries when linking -- fully static executables- , configExtraFrameworkDirs :: [FilePath]+ , configExtraFrameworkDirs :: [SymbolicPath Pkg (Dir Framework)] -- ^ path to search for extra -- frameworks (OS X only)- , configExtraIncludeDirs :: [FilePath]+ , configExtraIncludeDirs :: [SymbolicPath Pkg (Dir Include)] -- ^ path to search for header files , configIPID :: Flag String -- ^ explicit IPID to be used@@ -156,12 +166,6 @@ -- ^ be as deterministic as possible -- (e.g., invariant over GHC, database, -- etc). Used by the test suite- , configDistPref :: Flag FilePath- -- ^ "dist" prefix- , configCabalFilePath :: Flag FilePath- -- ^ Cabal file to use- , configVerbosity :: Flag Verbosity- -- ^ verbosity level , configUserInstall :: Flag Bool -- ^ The --user\/--global flag , configPackageDBs :: [Maybe PackageDB]@@ -181,7 +185,7 @@ -- dependencies. , configDependencies :: [GivenComponent] -- ^ The packages depended on which already exist- , configPromisedDependencies :: [GivenComponent]+ , configPromisedDependencies :: [PromisedComponent] -- ^ The packages depended on which doesn't yet exist (i.e. promised). -- Promising dependencies enables us to configure components in parallel, -- and avoids expensive builds if they are not necessary.@@ -226,9 +230,37 @@ -- testsuites run with @--enable-coverage@. Notably, this list must exclude -- indefinite libraries and instantiations because HPC does not support -- backpack (Nov. 2023).+ , configIgnoreBuildTools :: Flag Bool+ -- ^ When this flag is set, all tools declared in `build-tool`s and+ -- `build-tool-depends` will be ignored. This allows a Cabal package with+ -- build-tool-dependencies to be built even if the tool is not found. } deriving (Generic, Read, Show, Typeable) +pattern ConfigCommonFlags+ :: Flag Verbosity+ -> Flag (SymbolicPath Pkg (Dir Dist))+ -> Flag (SymbolicPath CWD (Dir Pkg))+ -> Flag (SymbolicPath Pkg File)+ -> [String]+ -> ConfigFlags+pattern ConfigCommonFlags+ { configVerbosity+ , configDistPref+ , configWorkingDir+ , configCabalFilePath+ , configTargets+ } <-+ ( configCommonFlags ->+ CommonSetupFlags+ { setupVerbosity = configVerbosity+ , setupDistPref = configDistPref+ , setupWorkingDir = configWorkingDir+ , setupCabalFilePath = configCabalFilePath+ , setupTargets = configTargets+ }+ )+ instance Binary ConfigFlags instance Structured ConfigFlags @@ -244,7 +276,8 @@ instance Eq ConfigFlags where (==) a b = -- configPrograms skipped: not user specified, has no Eq instance- equal configProgramPaths+ equal configCommonFlags+ && equal configProgramPaths && equal configProgramArgs && equal configProgramPathExtra && equal configHcFlavor@@ -259,6 +292,7 @@ && equal configProfExe && equal configProf && equal configProfDetail+ && equal configProfShared && equal configProfLibDetail && equal configConfigureArgs && equal configOptimization@@ -271,8 +305,6 @@ && equal configExtraIncludeDirs && equal configIPID && equal configDeterministic- && equal configDistPref- && equal configVerbosity && equal configUserInstall && equal configPackageDBs && equal configGHCiLib@@ -294,22 +326,17 @@ && equal configDebugInfo && equal configDumpBuildInfo && equal configUseResponseFiles+ && equal configAllowDependingOnPrivateLibs && equal configCoverageFor+ && equal configIgnoreBuildTools where equal f = on (==) f a b -configAbsolutePaths :: ConfigFlags -> IO ConfigFlags-configAbsolutePaths f =- (\v -> f{configPackageDBs = v})- `liftM` traverse- (maybe (return Nothing) (liftM Just . absolutePackageDBPath))- (configPackageDBs f)- {- FOURMOLU_DISABLE -} defaultConfigFlags :: ProgramDb -> ConfigFlags defaultConfigFlags progDb = emptyConfigFlags- { configArgs = []+ { configCommonFlags = defaultCommonSetupFlags , configPrograms_ = Option' (Just (Last' progDb)) , configHcFlavor = maybe NoFlag Flag defaultCompilerFlavor , configVanillaLib = Flag True@@ -325,9 +352,6 @@ , configOptimization = Flag NormalOptimisation , configProgPrefix = Flag (toPathTemplate "") , configProgSuffix = Flag (toPathTemplate "")- , configDistPref = NoFlag- , configCabalFilePath = NoFlag- , configVerbosity = Flag normal , configUserInstall = Flag False -- TODO: reverse this #if defined(mingw32_HOST_OS) -- See #8062 and GHC #21019.@@ -401,54 +425,44 @@ configureOptions :: ShowOrParseArgs -> [OptionField ConfigFlags] configureOptions showOrParseArgs =- [ optionVerbosity- configVerbosity- (\v flags -> flags{configVerbosity = v})- , optionDistPref- configDistPref- (\d flags -> flags{configDistPref = d})- showOrParseArgs- , option- []- ["compiler"]- "compiler"- configHcFlavor- (\v flags -> flags{configHcFlavor = v})- ( choiceOpt- [ (Flag GHC, ("g", ["ghc"]), "compile with GHC")- , (Flag GHCJS, ([], ["ghcjs"]), "compile with GHCJS")- , (Flag UHC, ([], ["uhc"]), "compile with UHC")- , -- "haskell-suite" compiler id string will be replaced- -- by a more specific one during the configure stage+ withCommonSetupOptions+ configCommonFlags+ (\c f -> f{configCommonFlags = c})+ showOrParseArgs+ [ option+ []+ ["compiler"]+ "compiler"+ configHcFlavor+ (\v flags -> flags{configHcFlavor = v})+ ( choiceOpt+ [ (Flag GHC, ("g", ["ghc"]), "compile with GHC")+ , (Flag GHCJS, ([], ["ghcjs"]), "compile with GHCJS")+ , (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"])- , "compile with a haskell-suite compiler"- )- ]- )- , option- ""- ["cabal-file"]- "use this Cabal file"- configCabalFilePath- (\v flags -> flags{configCabalFilePath = v})- (reqArgFlag "PATH")- , option- "w"- ["with-compiler"]- "give the path to a particular compiler"- configHcPath- (\v flags -> flags{configHcPath = v})- (reqArgFlag "PATH")- , option- ""- ["with-hc-pkg"]- "give the path to the package tool"- configHcPkg- (\v flags -> flags{configHcPkg = v})- (reqArgFlag "PATH")- ]+ ( Flag (HaskellSuite "haskell-suite")+ , ([], ["haskell-suite"])+ , "compile with a haskell-suite compiler"+ )+ ]+ )+ , option+ "w"+ ["with-compiler"]+ "give the path to a particular compiler"+ configHcPath+ (\v flags -> flags{configHcPath = v})+ (reqArgFlag "PATH")+ , option+ ""+ ["with-hc-pkg"]+ "give the path to the package tool"+ configHcPkg+ (\v flags -> flags{configHcPkg = v})+ (reqArgFlag "PATH")+ ] ++ map liftInstallDirs installDirsOptions ++ [ option ""@@ -515,6 +529,13 @@ (boolOpt [] []) , option ""+ ["profiling-shared"]+ "Build profiling shared libraries"+ configProfShared+ (\v flags -> flags{configProfShared = v})+ (boolOpt [] [])+ , option+ "" ["executable-profiling"] "Executable profiling (DEPRECATED)" configProfExe@@ -683,7 +704,7 @@ "A list of directories to search for header files" configExtraIncludeDirs (\v flags -> flags{configExtraIncludeDirs = v})- (reqArg' "PATH" (\x -> [x]) id)+ (reqArg' "PATH" (\x -> [makeSymbolicPath x]) (fmap getSymbolicPath)) , option "" ["deterministic"]@@ -711,21 +732,21 @@ "A list of directories to search for external libraries" configExtraLibDirs (\v flags -> flags{configExtraLibDirs = v})- (reqArg' "PATH" (\x -> [x]) id)+ (reqArg' "PATH" (\x -> [makeSymbolicPath x]) (fmap getSymbolicPath)) , option "" ["extra-lib-dirs-static"] "A list of directories to search for external libraries when linking fully static executables" configExtraLibDirsStatic (\v flags -> flags{configExtraLibDirsStatic = v})- (reqArg' "PATH" (\x -> [x]) id)+ (reqArg' "PATH" (\x -> [makeSymbolicPath x]) (fmap getSymbolicPath)) , option "" ["extra-framework-dirs"] "A list of directories to search for external frameworks (OS X only)" configExtraFrameworkDirs (\v flags -> flags{configExtraFrameworkDirs = v})- (reqArg' "PATH" (\x -> [x]) id)+ (reqArg' "PATH" (\x -> [makeSymbolicPath x]) (fmap getSymbolicPath)) , option "" ["extra-prog-path"]@@ -758,13 +779,13 @@ , option "" ["promised-dependency"]- "A list of promised dependencies. E.g., --promised-dependency=\"void=void-0.5.8-177d5cdf20962d0581fe2e4932a6c309\""+ "A list of promised dependencies. E.g., --promised-dependency=\"void-0.5.8=void-0.5.8-177d5cdf20962d0581fe2e4932a6c309\"" configPromisedDependencies (\v flags -> flags{configPromisedDependencies = v}) ( reqArg- "NAME[:COMPONENT_NAME]=CID"- (parsecToReadE (const "dependency expected") ((\x -> [x]) `fmap` parsecGivenComponent))- (map prettyGivenComponent)+ "NAME-VER[:COMPONENT_NAME]=CID"+ (parsecToReadE (const "dependency expected") ((\x -> [x]) `fmap` parsecPromisedComponent))+ (map prettyPromisedComponent) ) , option ""@@ -851,6 +872,15 @@ (Flag . (: []) . fromString) (fmap prettyShow . fromFlagOrDefault []) )+ , option+ ""+ ["ignore-build-tools"]+ ( "Ignore build tool dependencies. "+ ++ "If set, declared build tools needn't be found for compilation to proceed."+ )+ configIgnoreBuildTools+ (\v flags -> flags{configIgnoreBuildTools = v})+ trueArg ] where liftInstallDirs =@@ -875,7 +905,7 @@ readPackageDb "clear" = Nothing readPackageDb "global" = Just GlobalPackageDB readPackageDb "user" = Just UserPackageDB-readPackageDb other = Just (SpecificPackageDB other)+readPackageDb other = Just (SpecificPackageDB (makeSymbolicPath other)) showPackageDbList :: [Maybe PackageDB] -> [String] showPackageDbList = map showPackageDb@@ -887,11 +917,34 @@ showPackageDb Nothing = "clear" showPackageDb (Just GlobalPackageDB) = "global" showPackageDb (Just UserPackageDB) = "user"-showPackageDb (Just (SpecificPackageDB db)) = db+showPackageDb (Just (SpecificPackageDB db)) = getSymbolicPath db showProfDetailLevelFlag :: Flag ProfDetailLevel -> [String] showProfDetailLevelFlag NoFlag = [] showProfDetailLevelFlag (Flag dl) = [showProfDetailLevel dl]++parsecPromisedComponent :: ParsecParser PromisedComponent+parsecPromisedComponent = do+ pn <- parsec+ ln <- P.option LMainLibName $ do+ _ <- P.char ':'+ ucn <- parsec+ return $+ if unUnqualComponentName ucn == unPackageName (pkgName pn)+ then LMainLibName+ else LSubLibName ucn+ _ <- P.char '='+ cid <- parsec+ return $ PromisedComponent pn ln cid++prettyPromisedComponent :: PromisedComponent -> String+prettyPromisedComponent (PromisedComponent pn cn cid) =+ prettyShow pn+ ++ case cn of+ LMainLibName -> ""+ LSubLibName n -> ":" ++ prettyShow n+ ++ "="+ ++ prettyShow cid parsecGivenComponent :: ParsecParser GivenComponent parsecGivenComponent = do
src/Distribution/Simple/Setup/Copy.hs view
@@ -1,8 +1,11 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ViewPatterns #-} ----------------------------------------------------------------------------- @@ -18,7 +21,15 @@ -- Definition of the copy command-line options. -- See: @Distribution.Simple.Setup@ module Distribution.Simple.Setup.Copy- ( CopyFlags (..)+ ( CopyFlags+ ( CopyCommonFlags+ , copyVerbosity+ , copyDistPref+ , copyCabalFilePath+ , copyWorkingDir+ , copyTargets+ , ..+ ) , emptyCopyFlags , defaultCopyFlags , copyCommand@@ -31,11 +42,11 @@ import Distribution.Simple.Command hiding (boolOpt, boolOpt') import Distribution.Simple.Flag import Distribution.Simple.InstallDirs+import Distribution.Simple.Setup.Common import Distribution.Simple.Utils+import Distribution.Utils.Path import Distribution.Verbosity -import Distribution.Simple.Setup.Common- -- ------------------------------------------------------------ -- * Copy flags@@ -44,28 +55,43 @@ -- | Flags to @copy@: (destdir, copy-prefix (backwards compat), verbosity) data CopyFlags = CopyFlags- { copyDest :: Flag CopyDest- , copyDistPref :: Flag FilePath- , copyVerbosity :: Flag Verbosity- , -- This is the same hack as in 'buildArgs'. But I (ezyang) don't- -- think it's a hack, it's the right way to make hooks more robust- -- TODO: Stop using this eventually when 'UserHooks' gets changed- copyArgs :: [String]- , copyCabalFilePath :: Flag FilePath+ { copyCommonFlags :: !CommonSetupFlags+ , copyDest :: Flag CopyDest } deriving (Show, Generic) +pattern CopyCommonFlags+ :: Flag Verbosity+ -> Flag (SymbolicPath Pkg (Dir Dist))+ -> Flag (SymbolicPath CWD (Dir Pkg))+ -> Flag (SymbolicPath Pkg File)+ -> [String]+ -> CopyFlags+pattern CopyCommonFlags+ { copyVerbosity+ , copyDistPref+ , copyWorkingDir+ , copyCabalFilePath+ , copyTargets+ } <-+ ( copyCommonFlags ->+ CommonSetupFlags+ { setupVerbosity = copyVerbosity+ , setupDistPref = copyDistPref+ , setupWorkingDir = copyWorkingDir+ , setupCabalFilePath = copyCabalFilePath+ , setupTargets = copyTargets+ }+ )+ instance Binary CopyFlags instance Structured CopyFlags defaultCopyFlags :: CopyFlags defaultCopyFlags = CopyFlags- { copyDest = Flag NoCopyDest- , copyDistPref = NoFlag- , copyVerbosity = Flag normal- , copyArgs = []- , copyCabalFilePath = mempty+ { copyCommonFlags = defaultCommonSetupFlags+ , copyDest = Flag NoCopyDest } copyCommand :: CommandUI CopyFlags@@ -106,41 +132,40 @@ copyOptions :: ShowOrParseArgs -> [OptionField CopyFlags] copyOptions showOrParseArgs =- [ optionVerbosity copyVerbosity (\v flags -> flags{copyVerbosity = v})- , optionDistPref- copyDistPref- (\d flags -> flags{copyDistPref = d})- showOrParseArgs- , option- ""- ["destdir"]- "directory to copy files to, prepended to installation directories"- copyDest- ( \v flags -> case copyDest flags of- Flag (CopyToDb _) -> error "Use either 'destdir' or 'target-package-db'."- _ -> flags{copyDest = v}- )- ( reqArg- "DIR"- (succeedReadE (Flag . CopyTo))- (\f -> case f of Flag (CopyTo p) -> [p]; _ -> [])- )- , option- ""- ["target-package-db"]- "package database to copy files into. Required when using ${pkgroot} prefix."- copyDest- ( \v flags -> case copyDest flags of- NoFlag -> flags{copyDest = v}- Flag NoCopyDest -> flags{copyDest = v}- _ -> error "Use either 'destdir' or 'target-package-db'."- )- ( reqArg- "DATABASE"- (succeedReadE (Flag . CopyToDb))- (\f -> case f of Flag (CopyToDb p) -> [p]; _ -> [])- )- ]+ withCommonSetupOptions+ copyCommonFlags+ (\c f -> f{copyCommonFlags = c})+ showOrParseArgs+ [ option+ ""+ ["destdir"]+ "directory to copy files to, prepended to installation directories"+ copyDest+ ( \v flags -> case copyDest flags of+ Flag (CopyToDb _) -> error "Use either 'destdir' or 'target-package-db'."+ _ -> flags{copyDest = v}+ )+ ( reqArg+ "DIR"+ (succeedReadE (Flag . CopyTo))+ (\f -> case f of Flag (CopyTo p) -> [p]; _ -> [])+ )+ , option+ ""+ ["target-package-db"]+ "package database to copy files into. Required when using ${pkgroot} prefix."+ copyDest+ ( \v flags -> case copyDest flags of+ NoFlag -> flags{copyDest = v}+ Flag NoCopyDest -> flags{copyDest = v}+ _ -> error "Use either 'destdir' or 'target-package-db'."+ )+ ( reqArg+ "DATABASE"+ (succeedReadE (Flag . CopyToDb))+ (\f -> case f of Flag (CopyToDb p) -> [p]; _ -> [])+ )+ ] emptyCopyFlags :: CopyFlags emptyCopyFlags = mempty
src/Distribution/Simple/Setup/Global.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-}@@ -30,6 +31,7 @@ import Distribution.Simple.Command hiding (boolOpt, boolOpt') import Distribution.Simple.Flag import Distribution.Simple.Setup.Common+import Distribution.Utils.Path -- ------------------------------------------------------------ @@ -47,6 +49,7 @@ data GlobalFlags = GlobalFlags { globalVersion :: Flag Bool , globalNumericVersion :: Flag Bool+ , globalWorkingDir :: Flag (SymbolicPath CWD (Dir Pkg)) } deriving (Generic, Typeable) @@ -55,6 +58,7 @@ GlobalFlags { globalVersion = Flag False , globalNumericVersion = Flag False+ , globalWorkingDir = NoFlag } globalCommand :: [Command action] -> CommandUI GlobalFlags@@ -108,6 +112,13 @@ globalNumericVersion (\v flags -> flags{globalNumericVersion = v}) trueArg+ , option+ ""+ ["working-dir"]+ "Set working directory"+ globalWorkingDir+ (\v flags -> flags{globalWorkingDir = v})+ (reqSymbolicPathArgFlag "DIR") ] }
src/Distribution/Simple/Setup/Haddock.hs view
@@ -1,8 +1,11 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ViewPatterns #-} ----------------------------------------------------------------------------- @@ -19,7 +22,15 @@ -- See: @Distribution.Simple.Setup@ module Distribution.Simple.Setup.Haddock ( HaddockTarget (..)- , HaddockFlags (..)+ , HaddockFlags+ ( HaddockCommonFlags+ , haddockVerbosity+ , haddockDistPref+ , haddockCabalFilePath+ , haddockWorkingDir+ , haddockTargets+ , ..+ ) , emptyHaddockFlags , defaultHaddockFlags , haddockCommand@@ -42,10 +53,11 @@ import Distribution.Simple.Flag import Distribution.Simple.InstallDirs import Distribution.Simple.Program+import Distribution.Simple.Setup.Common+import Distribution.Utils.Path import Distribution.Verbosity-import qualified Text.PrettyPrint as Disp -import Distribution.Simple.Setup.Common+import qualified Text.PrettyPrint as Disp -- ------------------------------------------------------------ @@ -81,7 +93,8 @@ ] data HaddockFlags = HaddockFlags- { haddockProgramPaths :: [(String, FilePath)]+ { haddockCommonFlags :: !CommonSetupFlags+ , haddockProgramPaths :: [(String, FilePath)] , haddockProgramArgs :: [(String, [String])] , haddockHoogle :: Flag Bool , haddockHtml :: Flag Bool@@ -98,24 +111,46 @@ , haddockHscolourCss :: Flag FilePath , haddockContents :: Flag PathTemplate , haddockIndex :: Flag PathTemplate- , haddockDistPref :: Flag FilePath , haddockKeepTempFiles :: Flag Bool- , haddockVerbosity :: Flag Verbosity- , haddockCabalFilePath :: Flag FilePath , haddockBaseUrl :: Flag String- , haddockLib :: Flag String+ , haddockResourcesDir :: Flag String , haddockOutputDir :: Flag FilePath- , haddockArgs :: [String]+ , haddockUseUnicode :: Flag Bool } deriving (Show, Generic, Typeable) +pattern HaddockCommonFlags+ :: Flag Verbosity+ -> Flag (SymbolicPath Pkg (Dir Dist))+ -> Flag (SymbolicPath CWD (Dir Pkg))+ -> Flag (SymbolicPath Pkg File)+ -> [String]+ -> HaddockFlags+pattern HaddockCommonFlags+ { haddockVerbosity+ , haddockDistPref+ , haddockWorkingDir+ , haddockCabalFilePath+ , haddockTargets+ } <-+ ( haddockCommonFlags ->+ CommonSetupFlags+ { setupVerbosity = haddockVerbosity+ , setupDistPref = haddockDistPref+ , setupWorkingDir = haddockWorkingDir+ , setupCabalFilePath = haddockCabalFilePath+ , setupTargets = haddockTargets+ }+ )+ instance Binary HaddockFlags instance Structured HaddockFlags defaultHaddockFlags :: HaddockFlags defaultHaddockFlags = HaddockFlags- { haddockProgramPaths = mempty+ { haddockCommonFlags = defaultCommonSetupFlags+ , haddockProgramPaths = mempty , haddockProgramArgs = [] , haddockHoogle = Flag False , haddockHtml = Flag False@@ -131,15 +166,12 @@ , haddockQuickJump = Flag False , haddockHscolourCss = NoFlag , haddockContents = NoFlag- , haddockDistPref = NoFlag , haddockKeepTempFiles = Flag False- , haddockVerbosity = Flag normal- , haddockCabalFilePath = mempty , haddockIndex = NoFlag , haddockBaseUrl = NoFlag- , haddockLib = NoFlag+ , haddockResourcesDir = NoFlag , haddockOutputDir = NoFlag- , haddockArgs = mempty+ , haddockUseUnicode = Flag False } haddockCommand :: CommandUI HaddockFlags@@ -182,176 +214,180 @@ haddockOptions :: ShowOrParseArgs -> [OptionField HaddockFlags] haddockOptions showOrParseArgs =- [ optionVerbosity- haddockVerbosity- (\v flags -> flags{haddockVerbosity = v})- , optionDistPref- haddockDistPref- (\d flags -> flags{haddockDistPref = d})- showOrParseArgs- , option- ""- ["keep-temp-files"]- "Keep temporary files"- haddockKeepTempFiles- (\b flags -> flags{haddockKeepTempFiles = b})- trueArg- , option- ""- ["hoogle"]- "Generate a hoogle database"- haddockHoogle- (\v flags -> flags{haddockHoogle = v})- trueArg- , option- ""- ["html"]- "Generate HTML documentation (the default)"- haddockHtml- (\v flags -> flags{haddockHtml = v})- trueArg- , option- ""- ["html-location"]- "Location of HTML documentation for pre-requisite packages"- haddockHtmlLocation- (\v flags -> flags{haddockHtmlLocation = v})- (reqArgFlag "URL")- , option- ""- ["for-hackage"]- "Collection of flags to generate documentation suitable for upload to hackage"- haddockForHackage- (\v flags -> flags{haddockForHackage = v})- (noArg (Flag ForHackage))- , option- ""- ["executables"]- "Run haddock for Executables targets"- haddockExecutables- (\v flags -> flags{haddockExecutables = v})- trueArg- , option- ""- ["tests"]- "Run haddock for Test Suite targets"- haddockTestSuites- (\v flags -> flags{haddockTestSuites = v})- trueArg- , option- ""- ["benchmarks"]- "Run haddock for Benchmark targets"- haddockBenchmarks- (\v flags -> flags{haddockBenchmarks = v})- trueArg- , option- ""- ["foreign-libraries"]- "Run haddock for Foreign Library targets"- haddockForeignLibs- (\v flags -> flags{haddockForeignLibs = v})- trueArg- , option- ""- ["all"]- "Run haddock for all targets"- ( \f ->- allFlags- [ haddockExecutables f- , haddockTestSuites f- , haddockBenchmarks f- , haddockForeignLibs f- ]- )- ( \v flags ->- flags- { haddockExecutables = v- , haddockTestSuites = v- , haddockBenchmarks = v- , haddockForeignLibs = v- }- )- trueArg- , option- ""- ["internal"]- "Run haddock for internal modules and include all symbols"- haddockInternal- (\v flags -> flags{haddockInternal = v})- trueArg- , option- ""- ["css"]- "Use PATH as the haddock stylesheet"- haddockCss- (\v flags -> flags{haddockCss = v})- (reqArgFlag "PATH")- , option- ""- ["hyperlink-source", "hyperlink-sources", "hyperlinked-source"]- "Hyperlink the documentation to the source code"- haddockLinkedSource- (\v flags -> flags{haddockLinkedSource = v})- trueArg- , option- ""- ["quickjump"]- "Generate an index for interactive documentation navigation"- haddockQuickJump- (\v flags -> flags{haddockQuickJump = v})- trueArg- , option- ""- ["hscolour-css"]- "Use PATH as the HsColour stylesheet"- haddockHscolourCss- (\v flags -> flags{haddockHscolourCss = v})- (reqArgFlag "PATH")- , option- ""- ["contents-location"]- "Bake URL in as the location for the contents page"- haddockContents- (\v flags -> flags{haddockContents = v})- ( reqArg'- "URL"- (toFlag . toPathTemplate)- (flagToList . fmap fromPathTemplate)- )- , option- ""- ["index-location"]- "Use a separately-generated HTML index"- haddockIndex- (\v flags -> flags{haddockIndex = v})- ( reqArg'- "URL"- (toFlag . toPathTemplate)- (flagToList . fmap fromPathTemplate)- )- , option- ""- ["base-url"]- "Base URL for static files."- haddockBaseUrl- (\v flags -> flags{haddockBaseUrl = v})- (reqArgFlag "URL")- , option- ""- ["lib"]- "location of Haddocks static / auxiliary files"- haddockLib- (\v flags -> flags{haddockLib = v})- (reqArgFlag "DIR")- , option- ""- ["output-dir"]- "Generate haddock documentation into this directory. This flag is provided as a technology preview and is subject to change in the next releases."- haddockOutputDir- (\v flags -> flags{haddockOutputDir = v})- (reqArgFlag "DIR")- ]+ withCommonSetupOptions+ haddockCommonFlags+ (\c f -> f{haddockCommonFlags = c})+ showOrParseArgs+ [ option+ ""+ ["keep-temp-files"]+ "Keep temporary files"+ haddockKeepTempFiles+ (\b flags -> flags{haddockKeepTempFiles = b})+ trueArg+ , option+ ""+ ["hoogle"]+ "Generate a hoogle database"+ haddockHoogle+ (\v flags -> flags{haddockHoogle = v})+ trueArg+ , option+ ""+ ["html"]+ "Generate HTML documentation (the default)"+ haddockHtml+ (\v flags -> flags{haddockHtml = v})+ trueArg+ , option+ ""+ ["html-location"]+ "Location of HTML documentation for pre-requisite packages"+ haddockHtmlLocation+ (\v flags -> flags{haddockHtmlLocation = v})+ (reqArgFlag "URL")+ , option+ ""+ ["for-hackage"]+ "Collection of flags to generate documentation suitable for upload to hackage"+ haddockForHackage+ (\v flags -> flags{haddockForHackage = v})+ (noArg (Flag ForHackage))+ , option+ ""+ ["executables"]+ "Run haddock for Executables targets"+ haddockExecutables+ (\v flags -> flags{haddockExecutables = v})+ trueArg+ , option+ ""+ ["tests"]+ "Run haddock for Test Suite targets"+ haddockTestSuites+ (\v flags -> flags{haddockTestSuites = v})+ trueArg+ , option+ ""+ ["benchmarks"]+ "Run haddock for Benchmark targets"+ haddockBenchmarks+ (\v flags -> flags{haddockBenchmarks = v})+ trueArg+ , option+ ""+ ["foreign-libraries"]+ "Run haddock for Foreign Library targets"+ haddockForeignLibs+ (\v flags -> flags{haddockForeignLibs = v})+ trueArg+ , option+ ""+ ["all"]+ "Run haddock for all targets"+ ( \f ->+ allFlags+ [ haddockExecutables f+ , haddockTestSuites f+ , haddockBenchmarks f+ , haddockForeignLibs f+ ]+ )+ ( \v flags ->+ flags+ { haddockExecutables = v+ , haddockTestSuites = v+ , haddockBenchmarks = v+ , haddockForeignLibs = v+ }+ )+ trueArg+ , option+ ""+ ["internal"]+ "Run haddock for internal modules and include all symbols"+ haddockInternal+ (\v flags -> flags{haddockInternal = v})+ trueArg+ , option+ ""+ ["css"]+ "Use PATH as the haddock stylesheet"+ haddockCss+ (\v flags -> flags{haddockCss = v})+ (reqArgFlag "PATH")+ , option+ ""+ ["hyperlink-source", "hyperlink-sources", "hyperlinked-source"]+ "Hyperlink the documentation to the source code"+ haddockLinkedSource+ (\v flags -> flags{haddockLinkedSource = v})+ trueArg+ , option+ ""+ ["quickjump"]+ "Generate an index for interactive documentation navigation"+ haddockQuickJump+ (\v flags -> flags{haddockQuickJump = v})+ trueArg+ , option+ ""+ ["hscolour-css"]+ "Use PATH as the HsColour stylesheet"+ haddockHscolourCss+ (\v flags -> flags{haddockHscolourCss = v})+ (reqArgFlag "PATH")+ , option+ ""+ ["contents-location"]+ "Bake URL in as the location for the contents page"+ haddockContents+ (\v flags -> flags{haddockContents = v})+ ( reqArg'+ "URL"+ (toFlag . toPathTemplate)+ (flagToList . fmap fromPathTemplate)+ )+ , option+ ""+ ["index-location"]+ "Use a separately-generated HTML index"+ haddockIndex+ (\v flags -> flags{haddockIndex = v})+ ( reqArg'+ "URL"+ (toFlag . toPathTemplate)+ (flagToList . fmap fromPathTemplate)+ )+ , option+ ""+ ["base-url"]+ "Base URL for static files."+ haddockBaseUrl+ (\v flags -> flags{haddockBaseUrl = v})+ (reqArgFlag "URL")+ , option+ ""+ ["resources-dir"]+ "location of Haddocks static / auxiliary files"+ haddockResourcesDir+ (\v flags -> flags{haddockResourcesDir = v})+ (reqArgFlag "DIR")+ , option+ ""+ ["output-dir"]+ "Generate haddock documentation into this directory. This flag is provided as a technology preview and is subject to change in the next releases."+ haddockOutputDir+ (\v flags -> flags{haddockOutputDir = v})+ (reqArgFlag "DIR")+ , option+ ""+ ["use-unicode"]+ "Pass --use-unicode option to haddock"+ haddockUseUnicode+ (\v flags -> flags{haddockUseUnicode = v})+ trueArg+ ] emptyHaddockFlags :: HaddockFlags emptyHaddockFlags = mempty@@ -413,8 +449,8 @@ haddockProjectKeepTempFiles :: Flag Bool , haddockProjectVerbosity :: Flag Verbosity , -- haddockBaseUrl is not supported, a fixed value is provided- haddockProjectLib :: Flag String- , haddockProjectOutputDir :: Flag FilePath+ haddockProjectResourcesDir :: Flag String+ , haddockProjectUseUnicode :: Flag Bool } deriving (Show, Generic, Typeable) @@ -437,9 +473,9 @@ , haddockProjectHscolourCss = NoFlag , haddockProjectKeepTempFiles = Flag False , haddockProjectVerbosity = Flag normal- , haddockProjectLib = NoFlag- , haddockProjectOutputDir = NoFlag+ , haddockProjectResourcesDir = NoFlag , haddockProjectInterfaces = NoFlag+ , haddockProjectUseUnicode = NoFlag } haddockProjectCommand :: CommandUI HaddockProjectFlags@@ -550,6 +586,27 @@ trueArg , option ""+ ["all", "haddock-all"]+ "Run haddock for all targets"+ ( \f ->+ allFlags+ [ haddockProjectExecutables f+ , haddockProjectTestSuites f+ , haddockProjectBenchmarks f+ , haddockProjectForeignLibs f+ ]+ )+ ( \v flags ->+ flags+ { haddockProjectExecutables = v+ , haddockProjectTestSuites = v+ , haddockProjectBenchmarks = v+ , haddockProjectForeignLibs = v+ }+ )+ trueArg+ , option+ "" ["internal"] "Run haddock for internal modules and include all symbols" haddockProjectInternal@@ -581,18 +638,18 @@ (\v flags -> flags{haddockProjectVerbosity = v}) , option ""- ["lib"]+ ["resources-dir"] "location of Haddocks static / auxiliary files"- haddockProjectLib- (\v flags -> flags{haddockProjectLib = v})+ haddockProjectResourcesDir+ (\v flags -> flags{haddockProjectResourcesDir = v}) (reqArgFlag "DIR") , option ""- ["output-dir"]- "Generate haddock documentation into this directory. This flag is provided as a technology preview and is subject to change in the next releases."- haddockProjectOutputDir- (\v flags -> flags{haddockProjectOutputDir = v})- (reqArgFlag "DIR")+ ["use-unicode"]+ "Pass --use-unicode option to haddock"+ haddockProjectUseUnicode+ (\v flags -> flags{haddockProjectUseUnicode = v})+ trueArg ] emptyHaddockProjectFlags :: HaddockProjectFlags
src/Distribution/Simple/Setup/Hscolour.hs view
@@ -1,8 +1,11 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ViewPatterns #-} ----------------------------------------------------------------------------- @@ -18,7 +21,15 @@ -- Definition of the hscolour command-line options. -- See: @Distribution.Simple.Setup@ module Distribution.Simple.Setup.Hscolour- ( HscolourFlags (..)+ ( HscolourFlags+ ( HscolourCommonFlags+ , hscolourVerbosity+ , hscolourDistPref+ , hscolourCabalFilePath+ , hscolourWorkingDir+ , hscolourTargets+ , ..+ ) , emptyHscolourFlags , defaultHscolourFlags , hscolourCommand@@ -29,9 +40,9 @@ import Distribution.Simple.Command hiding (boolOpt, boolOpt') import Distribution.Simple.Flag-import Distribution.Verbosity- import Distribution.Simple.Setup.Common+import Distribution.Utils.Path+import Distribution.Verbosity -- ------------------------------------------------------------ @@ -40,17 +51,39 @@ -- ------------------------------------------------------------ data HscolourFlags = HscolourFlags- { hscolourCSS :: Flag FilePath+ { hscolourCommonFlags :: !CommonSetupFlags+ , hscolourCSS :: Flag FilePath , hscolourExecutables :: Flag Bool , hscolourTestSuites :: Flag Bool , hscolourBenchmarks :: Flag Bool , hscolourForeignLibs :: Flag Bool- , hscolourDistPref :: Flag FilePath- , hscolourVerbosity :: Flag Verbosity- , hscolourCabalFilePath :: Flag FilePath } deriving (Show, Generic, Typeable) +pattern HscolourCommonFlags+ :: Flag Verbosity+ -> Flag (SymbolicPath Pkg (Dir Dist))+ -> Flag (SymbolicPath CWD (Dir Pkg))+ -> Flag (SymbolicPath Pkg File)+ -> [String]+ -> HscolourFlags+pattern HscolourCommonFlags+ { hscolourVerbosity+ , hscolourDistPref+ , hscolourWorkingDir+ , hscolourCabalFilePath+ , hscolourTargets+ } <-+ ( hscolourCommonFlags ->+ CommonSetupFlags+ { setupVerbosity = hscolourVerbosity+ , setupDistPref = hscolourDistPref+ , setupWorkingDir = hscolourWorkingDir+ , setupCabalFilePath = hscolourCabalFilePath+ , setupTargets = hscolourTargets+ }+ )+ instance Binary HscolourFlags instance Structured HscolourFlags @@ -60,14 +93,12 @@ defaultHscolourFlags :: HscolourFlags defaultHscolourFlags = HscolourFlags- { hscolourCSS = NoFlag+ { hscolourCommonFlags = defaultCommonSetupFlags+ , hscolourCSS = NoFlag , hscolourExecutables = Flag False , hscolourTestSuites = Flag False , hscolourBenchmarks = Flag False- , hscolourDistPref = NoFlag , hscolourForeignLibs = Flag False- , hscolourVerbosity = Flag normal- , hscolourCabalFilePath = mempty } instance Monoid HscolourFlags where@@ -90,68 +121,65 @@ "Usage: " ++ pname ++ " hscolour [FLAGS]\n" , commandDefaultFlags = defaultHscolourFlags , commandOptions = \showOrParseArgs ->- [ optionVerbosity- hscolourVerbosity- (\v flags -> flags{hscolourVerbosity = v})- , optionDistPref- hscolourDistPref- (\d flags -> flags{hscolourDistPref = d})- showOrParseArgs- , option- ""- ["executables"]- "Run hscolour for Executables targets"- hscolourExecutables- (\v flags -> flags{hscolourExecutables = v})- trueArg- , option- ""- ["tests"]- "Run hscolour for Test Suite targets"- hscolourTestSuites- (\v flags -> flags{hscolourTestSuites = v})- trueArg- , option- ""- ["benchmarks"]- "Run hscolour for Benchmark targets"- hscolourBenchmarks- (\v flags -> flags{hscolourBenchmarks = v})- trueArg- , option- ""- ["foreign-libraries"]- "Run hscolour for Foreign Library targets"- hscolourForeignLibs- (\v flags -> flags{hscolourForeignLibs = v})- trueArg- , option- ""- ["all"]- "Run hscolour for all targets"- ( \f ->- allFlags- [ hscolourExecutables f- , hscolourTestSuites f- , hscolourBenchmarks f- , hscolourForeignLibs f- ]- )- ( \v flags ->- flags- { hscolourExecutables = v- , hscolourTestSuites = v- , hscolourBenchmarks = v- , hscolourForeignLibs = v- }- )- trueArg- , option- ""- ["css"]- "Use a cascading style sheet"- hscolourCSS- (\v flags -> flags{hscolourCSS = v})- (reqArgFlag "PATH")- ]+ withCommonSetupOptions+ hscolourCommonFlags+ (\c f -> f{hscolourCommonFlags = c})+ showOrParseArgs+ [ option+ ""+ ["executables"]+ "Run hscolour for Executables targets"+ hscolourExecutables+ (\v flags -> flags{hscolourExecutables = v})+ trueArg+ , option+ ""+ ["tests"]+ "Run hscolour for Test Suite targets"+ hscolourTestSuites+ (\v flags -> flags{hscolourTestSuites = v})+ trueArg+ , option+ ""+ ["benchmarks"]+ "Run hscolour for Benchmark targets"+ hscolourBenchmarks+ (\v flags -> flags{hscolourBenchmarks = v})+ trueArg+ , option+ ""+ ["foreign-libraries"]+ "Run hscolour for Foreign Library targets"+ hscolourForeignLibs+ (\v flags -> flags{hscolourForeignLibs = v})+ trueArg+ , option+ ""+ ["all"]+ "Run hscolour for all targets"+ ( \f ->+ allFlags+ [ hscolourExecutables f+ , hscolourTestSuites f+ , hscolourBenchmarks f+ , hscolourForeignLibs f+ ]+ )+ ( \v flags ->+ flags+ { hscolourExecutables = v+ , hscolourTestSuites = v+ , hscolourBenchmarks = v+ , hscolourForeignLibs = v+ }+ )+ trueArg+ , option+ ""+ ["css"]+ "Use a cascading style sheet"+ hscolourCSS+ (\v flags -> flags{hscolourCSS = v})+ (reqArgFlag "PATH")+ ] }
src/Distribution/Simple/Setup/Install.hs view
@@ -1,8 +1,11 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ViewPatterns #-} ----------------------------------------------------------------------------- @@ -18,7 +21,15 @@ -- Definition of the install command-line options. -- See: @Distribution.Simple.Setup@ module Distribution.Simple.Setup.Install- ( InstallFlags (..)+ ( InstallFlags+ ( InstallCommonFlags+ , installVerbosity+ , installDistPref+ , installCabalFilePath+ , installWorkingDir+ , installTargets+ , ..+ ) , emptyInstallFlags , defaultInstallFlags , installCommand@@ -32,11 +43,11 @@ import Distribution.Simple.Compiler import Distribution.Simple.Flag import Distribution.Simple.InstallDirs+import Distribution.Simple.Setup.Common import Distribution.Simple.Utils+import Distribution.Utils.Path import Distribution.Verbosity -import Distribution.Simple.Setup.Common- -- ------------------------------------------------------------ -- * Install flags@@ -45,28 +56,46 @@ -- | Flags to @install@: (package db, verbosity) data InstallFlags = InstallFlags- { installPackageDB :: Flag PackageDB+ { installCommonFlags :: !CommonSetupFlags+ , installPackageDB :: Flag PackageDB , installDest :: Flag CopyDest- , installDistPref :: Flag FilePath , installUseWrapper :: Flag Bool , installInPlace :: Flag Bool- , installVerbosity :: Flag Verbosity- , -- this is only here, because we can not- -- change the hooks API.- installCabalFilePath :: Flag FilePath } deriving (Show, Generic) +pattern InstallCommonFlags+ :: Flag Verbosity+ -> Flag (SymbolicPath Pkg (Dir Dist))+ -> Flag (SymbolicPath CWD (Dir Pkg))+ -> Flag (SymbolicPath Pkg File)+ -> [String]+ -> InstallFlags+pattern InstallCommonFlags+ { installVerbosity+ , installDistPref+ , installWorkingDir+ , installCabalFilePath+ , installTargets+ } <-+ ( installCommonFlags ->+ CommonSetupFlags+ { setupVerbosity = installVerbosity+ , setupDistPref = installDistPref+ , setupWorkingDir = installWorkingDir+ , setupCabalFilePath = installCabalFilePath+ , setupTargets = installTargets+ }+ )+ defaultInstallFlags :: InstallFlags defaultInstallFlags = InstallFlags- { installPackageDB = NoFlag+ { installCommonFlags = defaultCommonSetupFlags+ , installPackageDB = NoFlag , installDest = Flag NoCopyDest- , installDistPref = NoFlag , installUseWrapper = Flag False , installInPlace = Flag False- , installVerbosity = Flag normal- , installCabalFilePath = mempty } installCommand :: CommandUI InstallFlags@@ -84,24 +113,24 @@ , commandUsage = \pname -> "Usage: " ++ pname ++ " install [FLAGS]\n" , commandDefaultFlags = defaultInstallFlags- , commandOptions = \showOrParseArgs -> case showOrParseArgs of- ShowArgs ->- filter- ( (`notElem` ["target-package-db"])- . optionName- )- $ installOptions ShowArgs- ParseArgs -> installOptions ParseArgs+ , commandOptions = \showOrParseArgs ->+ withCommonSetupOptions+ installCommonFlags+ (\c f -> f{installCommonFlags = c})+ showOrParseArgs+ $ case showOrParseArgs of+ ShowArgs ->+ filter+ ( (`notElem` ["target-package-db"])+ . optionName+ )+ installOptions+ ParseArgs -> installOptions } -installOptions :: ShowOrParseArgs -> [OptionField InstallFlags]-installOptions showOrParseArgs =- [ optionVerbosity installVerbosity (\v flags -> flags{installVerbosity = v})- , optionDistPref- installDistPref- (\d flags -> flags{installDistPref = d})- showOrParseArgs- , option+installOptions :: [OptionField InstallFlags]+installOptions =+ [ option "" ["inplace"] "install the package in the install subdirectory of the dist prefix, so it can be used without being installed"
src/Distribution/Simple/Setup/Register.hs view
@@ -1,8 +1,11 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ViewPatterns #-} ----------------------------------------------------------------------------- @@ -18,7 +21,15 @@ -- Definition of the register command-line options. -- See: @Distribution.Simple.Setup@ module Distribution.Simple.Setup.Register- ( RegisterFlags (..)+ ( RegisterFlags+ ( RegisterCommonFlags+ , registerVerbosity+ , registerDistPref+ , registerCabalFilePath+ , registerWorkingDir+ , registerTargets+ , ..+ ) , emptyRegisterFlags , defaultRegisterFlags , registerCommand@@ -31,9 +42,9 @@ import Distribution.Simple.Command hiding (boolOpt, boolOpt') import Distribution.Simple.Compiler import Distribution.Simple.Flag-import Distribution.Verbosity- import Distribution.Simple.Setup.Common+import Distribution.Utils.Path+import Distribution.Verbosity -- ------------------------------------------------------------ @@ -44,31 +55,48 @@ -- | Flags to @register@ and @unregister@: (user package, gen-script, -- in-place, verbosity) data RegisterFlags = RegisterFlags- { regPackageDB :: Flag PackageDB+ { registerCommonFlags :: !CommonSetupFlags+ , regPackageDB :: Flag PackageDB , regGenScript :: Flag Bool- , regGenPkgConf :: Flag (Maybe FilePath)+ , regGenPkgConf :: Flag (Maybe (SymbolicPath Pkg (Dir PkgConf))) , regInPlace :: Flag Bool- , regDistPref :: Flag FilePath , regPrintId :: Flag Bool- , regVerbosity :: Flag Verbosity- , -- Same as in 'buildArgs' and 'copyArgs'- regArgs :: [String]- , regCabalFilePath :: Flag FilePath } deriving (Show, Generic, Typeable) +pattern RegisterCommonFlags+ :: Flag Verbosity+ -> Flag (SymbolicPath Pkg (Dir Dist))+ -> Flag (SymbolicPath CWD (Dir Pkg))+ -> Flag (SymbolicPath Pkg File)+ -> [String]+ -> RegisterFlags+pattern RegisterCommonFlags+ { registerVerbosity+ , registerDistPref+ , registerWorkingDir+ , registerCabalFilePath+ , registerTargets+ } <-+ ( registerCommonFlags ->+ CommonSetupFlags+ { setupVerbosity = registerVerbosity+ , setupDistPref = registerDistPref+ , setupWorkingDir = registerWorkingDir+ , setupCabalFilePath = registerCabalFilePath+ , setupTargets = registerTargets+ }+ )+ defaultRegisterFlags :: RegisterFlags defaultRegisterFlags = RegisterFlags- { regPackageDB = NoFlag+ { registerCommonFlags = defaultCommonSetupFlags+ , regPackageDB = NoFlag , regGenScript = Flag False , regGenPkgConf = NoFlag , regInPlace = Flag False- , regDistPref = NoFlag , regPrintId = Flag False- , regArgs = []- , regCabalFilePath = mempty- , regVerbosity = Flag normal } registerCommand :: CommandUI RegisterFlags@@ -83,59 +111,58 @@ "Usage: " ++ pname ++ " register [FLAGS]\n" , commandDefaultFlags = defaultRegisterFlags , commandOptions = \showOrParseArgs ->- [ optionVerbosity regVerbosity (\v flags -> flags{regVerbosity = v})- , optionDistPref- regDistPref- (\d flags -> flags{regDistPref = d})- showOrParseArgs- , option- ""- ["packageDB"]- ""- regPackageDB- (\v flags -> flags{regPackageDB = v})- ( choiceOpt- [- ( Flag UserPackageDB- , ([], ["user"])- , "upon registration, register this package in the user's local package database"- )- ,- ( Flag GlobalPackageDB- , ([], ["global"])- , "(default)upon registration, register this package in the system-wide package database"- )- ]- )- , option- ""- ["inplace"]- "register the package in the build location, so it can be used without being installed"- regInPlace- (\v flags -> flags{regInPlace = v})- trueArg- , option- ""- ["gen-script"]- "instead of registering, generate a script to register later"- regGenScript- (\v flags -> flags{regGenScript = v})- trueArg- , option- ""- ["gen-pkg-config"]- "instead of registering, generate a package registration file/directory"- 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- ]+ withCommonSetupOptions+ registerCommonFlags+ (\c f -> f{registerCommonFlags = c})+ showOrParseArgs+ $ [ option+ ""+ ["packageDB"]+ ""+ regPackageDB+ (\v flags -> flags{regPackageDB = v})+ ( choiceOpt+ [+ ( Flag UserPackageDB+ , ([], ["user"])+ , "upon registration, register this package in the user's local package database"+ )+ ,+ ( Flag GlobalPackageDB+ , ([], ["global"])+ , "(default)upon registration, register this package in the system-wide package database"+ )+ ]+ )+ , option+ ""+ ["inplace"]+ "register the package in the build location, so it can be used without being installed"+ regInPlace+ (\v flags -> flags{regInPlace = v})+ trueArg+ , option+ ""+ ["gen-script"]+ "instead of registering, generate a script to register later"+ regGenScript+ (\v flags -> flags{regGenScript = v})+ trueArg+ , option+ ""+ ["gen-pkg-config"]+ "instead of registering, generate a package registration file/directory"+ regGenPkgConf+ (\v flags -> flags{regGenPkgConf = v})+ (optArg' "PKG" (Flag . fmap makeSymbolicPath) (flagToList . fmap (fmap getSymbolicPath)))+ , option+ ""+ ["print-ipid"]+ "print the installed package ID calculated for this package"+ regPrintId+ (\v flags -> flags{regPrintId = v})+ trueArg+ ] } unregisterCommand :: CommandUI RegisterFlags@@ -150,38 +177,37 @@ "Usage: " ++ pname ++ " unregister [FLAGS]\n" , commandDefaultFlags = defaultRegisterFlags , commandOptions = \showOrParseArgs ->- [ optionVerbosity regVerbosity (\v flags -> flags{regVerbosity = v})- , optionDistPref- regDistPref- (\d flags -> flags{regDistPref = d})- showOrParseArgs- , option- ""- ["user"]- ""- regPackageDB- (\v flags -> flags{regPackageDB = v})- ( choiceOpt- [- ( Flag UserPackageDB- , ([], ["user"])- , "unregister this package in the user's local package database"- )- ,- ( Flag GlobalPackageDB- , ([], ["global"])- , "(default) unregister this package in the system-wide package database"- )- ]- )- , option- ""- ["gen-script"]- "Instead of performing the unregister command, generate a script to unregister later"- regGenScript- (\v flags -> flags{regGenScript = v})- trueArg- ]+ withCommonSetupOptions+ registerCommonFlags+ (\c f -> f{registerCommonFlags = c})+ showOrParseArgs+ $ [ option+ ""+ ["user"]+ ""+ regPackageDB+ (\v flags -> flags{regPackageDB = v})+ ( choiceOpt+ [+ ( Flag UserPackageDB+ , ([], ["user"])+ , "unregister this package in the user's local package database"+ )+ ,+ ( Flag GlobalPackageDB+ , ([], ["global"])+ , "(default) unregister this package in the system-wide package database"+ )+ ]+ )+ , option+ ""+ ["gen-script"]+ "Instead of performing the unregister command, generate a script to unregister later"+ regGenScript+ (\v flags -> flags{regGenScript = v})+ trueArg+ ] } emptyRegisterFlags :: RegisterFlags
src/Distribution/Simple/Setup/Repl.hs view
@@ -1,8 +1,11 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ViewPatterns #-} ----------------------------------------------------------------------------- @@ -18,7 +21,15 @@ -- Definition of the repl command-line options. -- See: @Distribution.Simple.Setup@ module Distribution.Simple.Setup.Repl- ( ReplFlags (..)+ ( ReplFlags+ ( ReplCommonFlags+ , replVerbosity+ , replDistPref+ , replCabalFilePath+ , replWorkingDir+ , replTargets+ , ..+ ) , defaultReplFlags , replCommand , ReplOptions (..)@@ -32,11 +43,11 @@ import Distribution.Simple.Command hiding (boolOpt, boolOpt') import Distribution.Simple.Flag import Distribution.Simple.Program+import Distribution.Simple.Setup.Common import Distribution.Simple.Utils+import Distribution.Utils.Path import Distribution.Verbosity -import Distribution.Simple.Setup.Common- -- ------------------------------------------------------------ -- * REPL Flags@@ -50,6 +61,30 @@ } deriving (Show, Generic, Typeable) +pattern ReplCommonFlags+ :: Flag Verbosity+ -> Flag (SymbolicPath Pkg (Dir Dist))+ -> Flag (SymbolicPath CWD (Dir Pkg))+ -> Flag (SymbolicPath Pkg File)+ -> [String]+ -> ReplFlags+pattern ReplCommonFlags+ { replVerbosity+ , replDistPref+ , replWorkingDir+ , replCabalFilePath+ , replTargets+ } <-+ ( replCommonFlags ->+ CommonSetupFlags+ { setupVerbosity = replVerbosity+ , setupDistPref = replDistPref+ , setupWorkingDir = replWorkingDir+ , setupCabalFilePath = replCabalFilePath+ , setupTargets = replTargets+ }+ )+ instance Binary ReplOptions instance Structured ReplOptions @@ -61,10 +96,9 @@ (<>) = gmappend data ReplFlags = ReplFlags- { replProgramPaths :: [(String, FilePath)]+ { replCommonFlags :: !CommonSetupFlags+ , replProgramPaths :: [(String, FilePath)] , replProgramArgs :: [(String, [String])]- , replDistPref :: Flag FilePath- , replVerbosity :: Flag Verbosity , replReload :: Flag Bool , replReplOptions :: ReplOptions }@@ -76,10 +110,9 @@ defaultReplFlags :: ReplFlags defaultReplFlags = ReplFlags- { replProgramPaths = mempty+ { replCommonFlags = defaultCommonSetupFlags+ , replProgramPaths = mempty , replProgramArgs = []- , replDistPref = NoFlag- , replVerbosity = Flag normal , replReload = Flag False , replReplOptions = mempty }@@ -143,38 +176,37 @@ 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})- showOrParseArgs- : programDbPaths+ withCommonSetupOptions+ replCommonFlags+ (\c f -> f{replCommonFlags = c})+ showOrParseArgs+ $ programDbPaths progDb showOrParseArgs replProgramPaths (\v flags -> flags{replProgramPaths = v})- ++ programDbOption- progDb- showOrParseArgs- replProgramArgs- (\v flags -> flags{replProgramArgs = v})- ++ programDbOptions- progDb- showOrParseArgs- replProgramArgs- (\v flags -> flags{replProgramArgs = v})- ++ case showOrParseArgs of- ParseArgs ->- [ option- ""- ["reload"]- "Used from within an interpreter to update files."- replReload- (\v flags -> flags{replReload = v})- trueArg- ]- _ -> []- ++ map liftReplOption (replOptions showOrParseArgs)+ ++ programDbOption+ progDb+ showOrParseArgs+ replProgramArgs+ (\v flags -> flags{replProgramArgs = v})+ ++ programDbOptions+ progDb+ showOrParseArgs+ replProgramArgs+ (\v flags -> flags{replProgramArgs = v})+ ++ case showOrParseArgs of+ ParseArgs ->+ [ option+ ""+ ["reload"]+ "Used from within an interpreter to update files."+ replReload+ (\v flags -> flags{replReload = v})+ trueArg+ ]+ _ -> []+ ++ map liftReplOption (replOptions showOrParseArgs) } where liftReplOption = liftOption replReplOptions (\v flags -> flags{replReplOptions = v})
src/Distribution/Simple/Setup/SDist.hs view
@@ -1,8 +1,11 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ViewPatterns #-} ----------------------------------------------------------------------------- @@ -18,7 +21,15 @@ -- Definition of the sdist command-line options. -- See: @Distribution.Simple.Setup@ module Distribution.Simple.Setup.SDist- ( SDistFlags (..)+ ( SDistFlags+ ( SDistCommonFlags+ , sDistVerbosity+ , sDistDistPref+ , sDistCabalFilePath+ , sDistWorkingDir+ , sDistTargets+ , ..+ ) , emptySDistFlags , defaultSDistFlags , sdistCommand@@ -29,9 +40,9 @@ import Distribution.Simple.Command hiding (boolOpt, boolOpt') import Distribution.Simple.Flag-import Distribution.Verbosity- import Distribution.Simple.Setup.Common+import Distribution.Utils.Path+import Distribution.Verbosity -- ------------------------------------------------------------ @@ -41,22 +52,44 @@ -- | Flags to @sdist@: (snapshot, verbosity) data SDistFlags = SDistFlags- { sDistSnapshot :: Flag Bool+ { sDistCommonFlags :: !CommonSetupFlags+ , sDistSnapshot :: Flag Bool , sDistDirectory :: Flag FilePath- , sDistDistPref :: Flag FilePath , sDistListSources :: Flag FilePath- , sDistVerbosity :: Flag Verbosity } deriving (Show, Generic, Typeable) +pattern SDistCommonFlags+ :: Flag Verbosity+ -> Flag (SymbolicPath Pkg (Dir Dist))+ -> Flag (SymbolicPath CWD (Dir Pkg))+ -> Flag (SymbolicPath Pkg File)+ -> [String]+ -> SDistFlags+pattern SDistCommonFlags+ { sDistVerbosity+ , sDistDistPref+ , sDistWorkingDir+ , sDistCabalFilePath+ , sDistTargets+ } <-+ ( sDistCommonFlags ->+ CommonSetupFlags+ { setupVerbosity = sDistVerbosity+ , setupDistPref = sDistDistPref+ , setupWorkingDir = sDistWorkingDir+ , setupCabalFilePath = sDistCabalFilePath+ , setupTargets = sDistTargets+ }+ )+ defaultSDistFlags :: SDistFlags defaultSDistFlags = SDistFlags- { sDistSnapshot = Flag False+ { sDistCommonFlags = defaultCommonSetupFlags+ , sDistSnapshot = Flag False , sDistDirectory = mempty- , sDistDistPref = NoFlag , sDistListSources = mempty- , sDistVerbosity = Flag normal } sdistCommand :: CommandUI SDistFlags@@ -71,35 +104,34 @@ "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"]- "Just write a list of the package's sources to a file"- sDistListSources- (\v flags -> flags{sDistListSources = v})- (reqArgFlag "FILE")- , option- ""- ["snapshot"]- "Produce a snapshot source distribution"- sDistSnapshot- (\v flags -> flags{sDistSnapshot = v})- trueArg- , option- ""- ["output-directory"]- ( "Generate a source distribution in the given directory, "- ++ "without creating a tarball"- )- sDistDirectory- (\v flags -> flags{sDistDirectory = v})- (reqArgFlag "DIR")- ]+ withCommonSetupOptions+ sDistCommonFlags+ (\c f -> f{sDistCommonFlags = c})+ showOrParseArgs+ [ option+ ""+ ["list-sources"]+ "Just write a list of the package's sources to a file"+ sDistListSources+ (\v flags -> flags{sDistListSources = v})+ (reqArgFlag "FILE")+ , option+ ""+ ["snapshot"]+ "Produce a snapshot source distribution"+ sDistSnapshot+ (\v flags -> flags{sDistSnapshot = v})+ trueArg+ , option+ ""+ ["output-directory"]+ ( "Generate a source distribution in the given directory, "+ ++ "without creating a tarball"+ )+ sDistDirectory+ (\v flags -> flags{sDistDirectory = v})+ (reqArgFlag "DIR")+ ] } emptySDistFlags :: SDistFlags
src/Distribution/Simple/Setup/Test.hs view
@@ -1,8 +1,11 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ViewPatterns #-} ----------------------------------------------------------------------------- @@ -18,7 +21,15 @@ -- Definition of the testing command-line options. -- See: @Distribution.Simple.Setup@ module Distribution.Simple.Setup.Test- ( TestFlags (..)+ ( TestFlags+ ( TestCommonFlags+ , testVerbosity+ , testDistPref+ , testCabalFilePath+ , testWorkingDir+ , testTargets+ , ..+ ) , emptyTestFlags , defaultTestFlags , testCommand@@ -36,11 +47,12 @@ import Distribution.Simple.Command hiding (boolOpt, boolOpt') import Distribution.Simple.Flag import Distribution.Simple.InstallDirs+import Distribution.Simple.Setup.Common import Distribution.Simple.Utils+import Distribution.Utils.Path import Distribution.Verbosity-import qualified Text.PrettyPrint as Disp -import Distribution.Simple.Setup.Common+import qualified Text.PrettyPrint as Disp -- ------------------------------------------------------------ @@ -80,8 +92,7 @@ a <> b = if a < b then b else a data TestFlags = TestFlags- { testDistPref :: Flag FilePath- , testVerbosity :: Flag Verbosity+ { testCommonFlags :: !CommonSetupFlags , testHumanLog :: Flag PathTemplate , testMachineLog :: Flag PathTemplate , testShowDetails :: Flag TestShowDetails@@ -93,14 +104,37 @@ } deriving (Show, Generic, Typeable) +pattern TestCommonFlags+ :: Flag Verbosity+ -> Flag (SymbolicPath Pkg (Dir Dist))+ -> Flag (SymbolicPath CWD (Dir Pkg))+ -> Flag (SymbolicPath Pkg File)+ -> [String]+ -> TestFlags+pattern TestCommonFlags+ { testVerbosity+ , testDistPref+ , testWorkingDir+ , testCabalFilePath+ , testTargets+ } <-+ ( testCommonFlags ->+ CommonSetupFlags+ { setupVerbosity = testVerbosity+ , setupDistPref = testDistPref+ , setupWorkingDir = testWorkingDir+ , setupCabalFilePath = testCabalFilePath+ , setupTargets = testTargets+ }+ )+ instance Binary TestFlags instance Structured TestFlags defaultTestFlags :: TestFlags defaultTestFlags = TestFlags- { testDistPref = NoFlag- , testVerbosity = Flag normal+ { testCommonFlags = defaultCommonSetupFlags , testHumanLog = toFlag $ toPathTemplate $ "$pkgid-$test-suite.log" , testMachineLog = toFlag $ toPathTemplate $ "$pkgid.log" , testShowDetails = toFlag Direct@@ -132,116 +166,115 @@ testOptions' :: ShowOrParseArgs -> [OptionField TestFlags] testOptions' showOrParseArgs =- [ optionVerbosity testVerbosity (\v flags -> flags{testVerbosity = v})- , optionDistPref- testDistPref- (\d flags -> flags{testDistPref = d})- showOrParseArgs- , option- []- ["log"]- ( "Log all test suite results to file (name template can use "- ++ "$pkgid, $compiler, $os, $arch, $test-suite, $result)"- )- testHumanLog- (\v flags -> flags{testHumanLog = v})- ( reqArg'- "TEMPLATE"- (toFlag . toPathTemplate)- (flagToList . fmap fromPathTemplate)- )- , option- []- ["machine-log"]- ( "Produce a machine-readable log file (name template can use "- ++ "$pkgid, $compiler, $os, $arch, $result)"- )- testMachineLog- (\v flags -> flags{testMachineLog = v})- ( reqArg'- "TEMPLATE"- (toFlag . toPathTemplate)- (flagToList . fmap fromPathTemplate)- )- , 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. "- ++ "'streaming': show results of test cases in real time."- ++ "'direct': send results of test cases in real time; no log file."- )- testShowDetails- (\v flags -> flags{testShowDetails = v})- ( reqArg- "FILTER"- ( parsecToReadE- ( \_ ->- "--show-details flag expects one of "- ++ intercalate- ", "- (map prettyShow knownTestShowDetails)- )- (fmap toFlag parsec)- )- (flagToList . fmap prettyShow)- )- , option- []- ["keep-tix-files"]- "keep .tix files for HPC between test runs"- testKeepTix- (\v flags -> flags{testKeepTix = v})- trueArg- , option- []- ["test-wrapper"]- "Run test through a wrapper."- testWrapper- (\v flags -> flags{testWrapper = v})- ( reqArg'- "FILE"- (toFlag :: FilePath -> Flag FilePath)- (flagToList :: Flag FilePath -> [FilePath])- )- , option- []- ["fail-when-no-test-suites"]- ("Exit with failure when no test suites are found.")- testFailWhenNoTestSuites- (\v flags -> flags{testFailWhenNoTestSuites = v})- trueArg- , option- []- ["test-options"]- ( "give extra options to test executables "- ++ "(name templates can use $pkgid, $compiler, "- ++ "$os, $arch, $test-suite)"- )- testOptions- (\v flags -> flags{testOptions = v})- ( reqArg'- "TEMPLATES"- (map toPathTemplate . splitArgs)- (const [])- )- , option- []- ["test-option"]- ( "give extra option to test executables "- ++ "(no need to quote options containing spaces, "- ++ "name template can use $pkgid, $compiler, "- ++ "$os, $arch, $test-suite)"- )- testOptions- (\v flags -> flags{testOptions = v})- ( reqArg'- "TEMPLATE"- (\x -> [toPathTemplate x])- (map fromPathTemplate)- )- ]+ withCommonSetupOptions+ testCommonFlags+ (\c f -> f{testCommonFlags = c})+ showOrParseArgs+ [ option+ []+ ["log"]+ ( "Log all test suite results to file (name template can use "+ ++ "$pkgid, $compiler, $os, $arch, $test-suite, $result)"+ )+ testHumanLog+ (\v flags -> flags{testHumanLog = v})+ ( reqArg'+ "TEMPLATE"+ (toFlag . toPathTemplate)+ (flagToList . fmap fromPathTemplate)+ )+ , option+ []+ ["machine-log"]+ ( "Produce a machine-readable log file (name template can use "+ ++ "$pkgid, $compiler, $os, $arch, $result)"+ )+ testMachineLog+ (\v flags -> flags{testMachineLog = v})+ ( reqArg'+ "TEMPLATE"+ (toFlag . toPathTemplate)+ (flagToList . fmap fromPathTemplate)+ )+ , 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. "+ ++ "'streaming': show results of test cases in real time."+ ++ "'direct': send results of test cases in real time; no log file."+ )+ testShowDetails+ (\v flags -> flags{testShowDetails = v})+ ( reqArg+ "FILTER"+ ( parsecToReadE+ ( \_ ->+ "--show-details flag expects one of "+ ++ intercalate+ ", "+ (map prettyShow knownTestShowDetails)+ )+ (fmap toFlag parsec)+ )+ (flagToList . fmap prettyShow)+ )+ , option+ []+ ["keep-tix-files"]+ "keep .tix files for HPC between test runs"+ testKeepTix+ (\v flags -> flags{testKeepTix = v})+ trueArg+ , option+ []+ ["test-wrapper"]+ "Run test through a wrapper."+ testWrapper+ (\v flags -> flags{testWrapper = v})+ ( reqArg'+ "FILE"+ (toFlag :: FilePath -> Flag FilePath)+ (flagToList :: Flag FilePath -> [FilePath])+ )+ , option+ []+ ["fail-when-no-test-suites"]+ ("Exit with failure when no test suites are found.")+ testFailWhenNoTestSuites+ (\v flags -> flags{testFailWhenNoTestSuites = v})+ trueArg+ , option+ []+ ["test-options"]+ ( "give extra options to test executables "+ ++ "(name templates can use $pkgid, $compiler, "+ ++ "$os, $arch, $test-suite)"+ )+ testOptions+ (\v flags -> flags{testOptions = v})+ ( reqArg'+ "TEMPLATES"+ (map toPathTemplate . splitArgs)+ (const [])+ )+ , option+ []+ ["test-option"]+ ( "give extra option to test executables "+ ++ "(no need to quote options containing spaces, "+ ++ "name template can use $pkgid, $compiler, "+ ++ "$os, $arch, $test-suite)"+ )+ testOptions+ (\v flags -> flags{testOptions = v})+ ( reqArg'+ "TEMPLATE"+ (\x -> [toPathTemplate x])+ (map fromPathTemplate)+ )+ ] emptyTestFlags :: TestFlags emptyTestFlags = mempty
+ src/Distribution/Simple/SetupHooks/Errors.hs view
@@ -0,0 +1,231 @@+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE StandaloneDeriving #-}++-----------------------------------------------------------------------------++-- Module : Distribution.Simple.SetupHooks.Errors+-- Copyright :+-- License :+--+-- Maintainer :+-- Portability :+--+-- Exceptions for the Hooks build-type.++module Distribution.Simple.SetupHooks.Errors+ ( SetupHooksException (..)+ , CannotApplyComponentDiffReason (..)+ , IllegalComponentDiffReason (..)+ , RulesException (..)+ , setupHooksExceptionCode+ , setupHooksExceptionMessage+ ) where++import Distribution.PackageDescription+import Distribution.Simple.SetupHooks.Rule+import qualified Distribution.Simple.SetupHooks.Rule as Rule+import Distribution.Types.Component++import qualified Data.Graph as Graph+import Data.List+ ( intercalate+ )+import qualified Data.List.NonEmpty as NE+import qualified Data.Tree as Tree++--------------------------------------------------------------------------------++-- | An error involving the @SetupHooks@ module of a package with+-- Hooks build-type.+data SetupHooksException+ = -- | Cannot apply a diff to a component in a per-component configure hook.+ CannotApplyComponentDiff CannotApplyComponentDiffReason+ | -- | An error with pre-build rules.+ RulesException RulesException+ deriving (Show)++-- | AN error involving the @Rules@ in the @SetupHooks@ module of a+-- package with the Hooks build-type.+data RulesException+ = -- | There are cycles in the dependency graph of fine-grained rules.+ CyclicRuleDependencies+ (NE.NonEmpty (RuleBinary, [Graph.Tree RuleBinary]))+ | -- | When executing fine-grained rules compiled into the external hooks+ -- executable, we failed to find dependencies of a rule.+ CantFindSourceForRuleDependencies+ RuleBinary+ (NE.NonEmpty Rule.Location)+ -- ^ missing dependencies+ | -- | When executing fine-grained rules compiled into the external hooks+ -- executable, a rule failed to generate the outputs it claimed it would.+ MissingRuleOutputs+ RuleBinary+ (NE.NonEmpty Rule.Location)+ -- ^ missing outputs+ | -- | An invalid reference to a rule output, e.g. an out-of-range+ -- index.+ InvalidRuleOutputIndex+ RuleId+ -- ^ rule+ RuleId+ -- ^ dependency+ (NE.NonEmpty Rule.Location)+ -- ^ outputs of dependency+ Word+ -- ^ the invalid index+ | -- | A duplicate 'RuleId' in the construction of pre-build rules.+ DuplicateRuleId !RuleId !Rule !Rule++deriving instance Show RulesException++data CannotApplyComponentDiffReason+ = MismatchedComponentTypes Component Component+ | IllegalComponentDiff Component (NE.NonEmpty IllegalComponentDiffReason)+ deriving (Show)++data IllegalComponentDiffReason+ = CannotChangeName+ | CannotChangeComponentField String+ | CannotChangeBuildInfoField String+ deriving (Show)++setupHooksExceptionCode :: SetupHooksException -> Int+setupHooksExceptionCode = \case+ CannotApplyComponentDiff rea ->+ cannotApplyComponentDiffCode rea+ RulesException rea ->+ rulesExceptionCode rea++rulesExceptionCode :: RulesException -> Int+rulesExceptionCode = \case+ CyclicRuleDependencies{} -> 9077+ CantFindSourceForRuleDependencies{} -> 1071+ MissingRuleOutputs{} -> 3498+ InvalidRuleOutputIndex{} -> 1173+ DuplicateRuleId{} -> 7717++setupHooksExceptionMessage :: SetupHooksException -> String+setupHooksExceptionMessage = \case+ CannotApplyComponentDiff reason ->+ cannotApplyComponentDiffMessage reason+ RulesException reason ->+ rulesExceptionMessage reason++rulesExceptionMessage :: RulesException -> String+rulesExceptionMessage = \case+ CyclicRuleDependencies cycles ->+ unlines $+ ("Hooks: cycle" ++ plural ++ " in dependency structure of rules:")+ : map showCycle (NE.toList cycles)+ where+ plural :: String+ plural+ | NE.length cycles >= 2 =+ "s"+ | otherwise =+ ""+ showCycle :: (RuleBinary, [Graph.Tree RuleBinary]) -> String+ showCycle (r, rs) =+ unlines . map (" " ++) . lines $+ Tree.drawTree $+ fmap showRule $+ Tree.Node r rs+ CantFindSourceForRuleDependencies _r deps ->+ unlines $+ ("Pre-build rules: can't find source for rule " ++ what ++ ":")+ : map (\d -> " - " <> show d) depsL+ where+ depsL = NE.toList deps+ what+ | length depsL == 1 =+ "dependency"+ | otherwise =+ "dependencies"+ MissingRuleOutputs _r reslts ->+ unlines $+ ("Pre-build rule did not generate expected result" <> plural <> ":")+ : map (\res -> " - " <> show res) resultsL+ where+ resultsL = NE.toList reslts+ plural+ | length resultsL == 1 =+ ""+ | otherwise =+ "s"+ InvalidRuleOutputIndex rId depRuleId outputs i -> unlines [header, body]+ where+ header = "Invalid index '" ++ show i ++ "' in dependency of " ++ show rId ++ "."+ nbOutputs = NE.length outputs+ body+ | (fromIntegral i :: Int) >= 0 =+ unwords+ [ "The dependency"+ , show depRuleId+ , "only has"+ , show nbOutputs+ , "output" ++ plural ++ "."+ ]+ | otherwise =+ "The index is too large."+ plural = if nbOutputs == 1 then "" else "s"+ DuplicateRuleId rId r1 r2 ->+ unlines $+ [ "Duplicate pre-build rule (" <> show rId <> ")"+ , " - " <> showRule (ruleBinary r1)+ , " - " <> showRule (ruleBinary r2)+ ]+ where+ showRule :: RuleBinary -> String+ showRule (Rule{staticDependencies = deps, results = reslts}) =+ "Rule: " ++ showDeps deps ++ " --> " ++ show (NE.toList reslts)++showDeps :: [Rule.Dependency] -> String+showDeps deps = "[" ++ intercalate ", " (map showDep deps) ++ "]"++showDep :: Rule.Dependency -> String+showDep = \case+ RuleDependency (RuleOutput{outputOfRule = rId, outputIndex = i}) ->+ "(" ++ show rId ++ ")[" ++ show i ++ "]"+ FileDependency loc -> show loc++cannotApplyComponentDiffCode :: CannotApplyComponentDiffReason -> Int+cannotApplyComponentDiffCode = \case+ MismatchedComponentTypes{} -> 9491+ IllegalComponentDiff{} -> 7634++cannotApplyComponentDiffMessage :: CannotApplyComponentDiffReason -> String+cannotApplyComponentDiffMessage = \case+ MismatchedComponentTypes comp diff ->+ unlines+ [ "Hooks: mismatched component types in per-component configure hook."+ , "Trying to apply " ++ what ++ " diff to " ++ to ++ "."+ ]+ where+ what = case diff of+ CLib{} -> "a library"+ CFLib{} -> "a foreign library"+ CExe{} -> "an executable"+ CTest{} -> "a testsuite"+ CBench{} -> "a benchmark"+ to = case componentName comp of+ nm@(CExeName{}) -> "an " ++ showComponentName nm+ nm -> "a " ++ showComponentName nm+ IllegalComponentDiff comp reasons ->+ unlines $+ ("Hooks: illegal component diff in per-component pre-configure hook for " ++ what ++ ":")+ : map mk_rea (NE.toList reasons)+ where+ mk_rea err = " - " ++ illegalComponentDiffMessage err ++ "."+ what = case componentName comp of+ CLibName LMainLibName -> "main library"+ nm -> showComponentName nm++illegalComponentDiffMessage :: IllegalComponentDiffReason -> String+illegalComponentDiffMessage = \case+ CannotChangeName ->+ "cannot change the name of a component"+ CannotChangeComponentField fld ->+ "cannot change component field '" ++ fld ++ "'"+ CannotChangeBuildInfoField fld ->+ "cannot change BuildInfo field '" ++ fld ++ "'"
+ src/Distribution/Simple/SetupHooks/Internal.hs view
@@ -0,0 +1,1096 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE TypeApplications #-}++-- |+-- Module: Distribution.Simple.SetupHooks.Internal+--+-- Internal implementation module.+-- Users of @build-type: Hooks@ should import "Distribution.Simple.SetupHooks"+-- instead.+module Distribution.Simple.SetupHooks.Internal+ ( -- * The setup hooks datatype+ SetupHooks (..)+ , noSetupHooks++ -- * Configure hooks+ , ConfigureHooks (..)+ , noConfigureHooks++ -- ** Per-package configure hooks+ , PreConfPackageInputs (..)+ , PreConfPackageOutputs (..)+ , noPreConfPackageOutputs+ , PreConfPackageHook+ , PostConfPackageInputs (..)+ , PostConfPackageHook++ -- ** Per-component configure hooks+ , PreConfComponentInputs (..)+ , PreConfComponentOutputs (..)+ , noPreConfComponentOutputs+ , PreConfComponentHook+ , ComponentDiff (..)+ , emptyComponentDiff+ , buildInfoComponentDiff+ , LibraryDiff+ , ForeignLibDiff+ , ExecutableDiff+ , TestSuiteDiff+ , BenchmarkDiff+ , BuildInfoDiff++ -- * Build hooks+ , BuildHooks (..)+ , noBuildHooks+ , BuildingWhat (..)+ , buildingWhatVerbosity+ , buildingWhatWorkingDir+ , buildingWhatDistPref++ -- ** Pre-build rules+ , PreBuildComponentInputs (..)+ , PreBuildComponentRules++ -- ** Post-build hook+ , PostBuildComponentInputs (..)+ , PostBuildComponentHook++ -- * Install hooks+ , InstallHooks (..)+ , noInstallHooks+ , InstallComponentInputs (..)+ , InstallComponentHook++ -- * Internals++ -- ** Per-component hook utilities+ , applyComponentDiffs+ , forComponents_++ -- ** Executing build rules+ , executeRules++ -- ** HookedBuildInfo compatibility code+ , hookedBuildInfoComponents+ , hookedBuildInfoComponentDiff_maybe+ )+where++import Distribution.Compat.Prelude+import Prelude ()++import Distribution.Compat.Lens ((.~))+import Distribution.PackageDescription+import Distribution.Simple.BuildPaths+import Distribution.Simple.Compiler (Compiler (..))+import Distribution.Simple.Errors+import Distribution.Simple.LocalBuildInfo+import Distribution.Simple.Program.Db+import Distribution.Simple.Setup+ ( BuildingWhat (..)+ , buildingWhatDistPref+ , buildingWhatVerbosity+ , buildingWhatWorkingDir+ )+import Distribution.Simple.Setup.Build (BuildFlags (..))+import Distribution.Simple.Setup.Config (ConfigFlags (..))+import Distribution.Simple.Setup.Copy (CopyFlags (..))+import Distribution.Simple.SetupHooks.Errors+import Distribution.Simple.SetupHooks.Rule+import qualified Distribution.Simple.SetupHooks.Rule as Rule+import Distribution.Simple.Utils+import Distribution.System (Platform (..))+import Distribution.Utils.Path++import qualified Distribution.Types.BuildInfo.Lens as BI (buildInfo)+import Distribution.Types.LocalBuildConfig as LBC+import Distribution.Types.TargetInfo+import Distribution.Verbosity++import qualified Data.ByteString.Lazy as LBS+import Data.Coerce (coerce)+import qualified Data.Graph as Graph+import qualified Data.List.NonEmpty as NE+import qualified Data.Map as Map+import qualified Data.Set as Set++import System.Directory (doesFileExist)++--------------------------------------------------------------------------------+-- SetupHooks++-- | Hooks into the @cabal@ build phases.+--+-- Usage:+--+-- - In your @.cabal@ file, declare @build-type: Hooks@+-- (with a @cabal-version@ greater than or equal to @3.14@),+-- - In your @.cabal@ file, include a @custom-setup@ stanza+-- which declares the dependencies of your @SetupHooks@ module;+-- this will usually contain a dependency on the @Cabal-hooks@ package.+-- - Provide a @SetupHooks.hs@ module next to your @.cabal@ file;+-- it must export @setupHooks :: SetupHooks@.+data SetupHooks = SetupHooks+ { configureHooks :: ConfigureHooks+ -- ^ Hooks into the configure phase.+ , buildHooks :: BuildHooks+ -- ^ Hooks into the build phase.+ --+ -- These hooks are relevant to any build-like phase,+ -- such as repl or haddock.+ , installHooks :: InstallHooks+ -- ^ Hooks into the copy/install phase.+ }++-- | 'SetupHooks' can be combined monoidally. This is useful to combine+-- setup hooks defined by another package with your own package-specific+-- hooks.+--+-- __Warning__: this 'Semigroup' instance is not commutative.+instance Semigroup SetupHooks where+ SetupHooks+ { configureHooks = conf1+ , buildHooks = build1+ , installHooks = inst1+ }+ <> SetupHooks+ { configureHooks = conf2+ , buildHooks = build2+ , installHooks = inst2+ } =+ SetupHooks+ { configureHooks = conf1 <> conf2+ , buildHooks = build1 <> build2+ , installHooks = inst1 <> inst2+ }++instance Monoid SetupHooks where+ mempty = noSetupHooks++-- | Empty hooks.+noSetupHooks :: SetupHooks+noSetupHooks =+ SetupHooks+ { configureHooks = noConfigureHooks+ , buildHooks = noBuildHooks+ , installHooks = noInstallHooks+ }++--------------------------------------------------------------------------------+-- Configure hooks.++type PreConfPackageHook = PreConfPackageInputs -> IO PreConfPackageOutputs++-- | Inputs to the package-wide pre-configure step.+data PreConfPackageInputs = PreConfPackageInputs+ { configFlags :: ConfigFlags+ , localBuildConfig :: LocalBuildConfig+ -- ^ Warning: the 'ProgramDb' in the 'withPrograms' field+ -- will not contain any unconfigured programs.+ , compiler :: Compiler+ , platform :: Platform+ }+ deriving (Generic, Show)++-- | Outputs of the package-wide pre-configure step.+--+-- Prefer using 'noPreConfPackageOutputs' and overriding the fields+-- you care about, to avoid depending on implementation details+-- of this datatype.+data PreConfPackageOutputs = PreConfPackageOutputs+ { buildOptions :: BuildOptions+ , extraConfiguredProgs :: ConfiguredProgs+ }+ deriving (Generic, Show)++-- | Use this smart constructor to declare an empty set of changes+-- by the package-wide pre-configure hook, and override the fields you+-- care about.+--+-- Use this rather than v'PreConfPackageOutputs' to avoid relying on+-- internal implementation details of the latter.+noPreConfPackageOutputs :: PreConfPackageInputs -> PreConfPackageOutputs+noPreConfPackageOutputs (PreConfPackageInputs{localBuildConfig = lbc}) =+ PreConfPackageOutputs+ { buildOptions = LBC.withBuildOptions lbc+ , extraConfiguredProgs = Map.empty+ }++-- | Package-wide post-configure step.+--+-- Perform side effects. Last opportunity for any package-wide logic;+-- any subsequent hooks work per-component.+type PostConfPackageHook = PostConfPackageInputs -> IO ()++-- | Inputs to the package-wide post-configure step.+data PostConfPackageInputs = PostConfPackageInputs+ { localBuildConfig :: LocalBuildConfig+ , packageBuildDescr :: PackageBuildDescr+ }+ deriving (Generic, Show)++-- | Per-component pre-configure step.+--+-- For each component of the package, this hook can perform side effects,+-- and return a diff to the passed in component, e.g. to declare additional+-- autogenerated modules.+type PreConfComponentHook = PreConfComponentInputs -> IO PreConfComponentOutputs++-- | Inputs to the per-component pre-configure step.+data PreConfComponentInputs = PreConfComponentInputs+ { localBuildConfig :: LocalBuildConfig+ , packageBuildDescr :: PackageBuildDescr+ , component :: Component+ }+ deriving (Generic, Show)++-- | Outputs of the per-component pre-configure step.+--+-- Prefer using 'noPreComponentOutputs' and overriding the fields+-- you care about, to avoid depending on implementation details+-- of this datatype.+data PreConfComponentOutputs = PreConfComponentOutputs+ { componentDiff :: ComponentDiff+ }+ deriving (Generic, Show)++-- | Use this smart constructor to declare an empty set of changes+-- by a per-component pre-configure hook, and override the fields you+-- care about.+--+-- Use this rather than v'PreConfComponentOutputs' to avoid relying on+-- internal implementation details of the latter.+noPreConfComponentOutputs :: PreConfComponentInputs -> PreConfComponentOutputs+noPreConfComponentOutputs (PreConfComponentInputs{component = comp}) =+ PreConfComponentOutputs+ { componentDiff = emptyComponentDiff (componentName comp)+ }++-- | Configure-time hooks.+--+-- Order of execution:+--+-- - 'preConfPackageHook',+-- - configure the package,+-- - 'postConfPackageHook',+-- - 'preConfComponentHook',+-- - configure the components.+data ConfigureHooks = ConfigureHooks+ { preConfPackageHook :: Maybe PreConfPackageHook+ -- ^ Package-wide pre-configure hook. See 'PreConfPackageHook'.+ , postConfPackageHook :: Maybe PostConfPackageHook+ -- ^ Package-wide post-configure hook. See 'PostConfPackageHook'.+ , preConfComponentHook :: Maybe PreConfComponentHook+ -- ^ Per-component pre-configure hook. See 'PreConfComponentHook'.+ }++-- Note: these configure hooks don't track any kind of dependency information,+-- so we won't know when the configuration is out of date and should be re-done.+-- This seems okay: it should only matter while developing the package, in which+-- case it seems acceptable to rely on the user re-configuring.++instance Semigroup ConfigureHooks where+ ConfigureHooks+ { preConfPackageHook = prePkg1+ , postConfPackageHook = postPkg1+ , preConfComponentHook = preComp1+ }+ <> ConfigureHooks+ { preConfPackageHook = prePkg2+ , postConfPackageHook = postPkg2+ , preConfComponentHook = preComp2+ } =+ ConfigureHooks+ { preConfPackageHook =+ coerce+ ((<>) @(Maybe PreConfPkgSemigroup))+ prePkg1+ prePkg2+ , postConfPackageHook =+ postPkg1 <> postPkg2+ , preConfComponentHook =+ coerce+ ((<>) @(Maybe PreConfComponentSemigroup))+ preComp1+ preComp2+ }++instance Monoid ConfigureHooks where+ mempty = noConfigureHooks++-- | Empty configure phase hooks.+noConfigureHooks :: ConfigureHooks+noConfigureHooks =+ ConfigureHooks+ { preConfPackageHook = Nothing+ , postConfPackageHook = Nothing+ , preConfComponentHook = Nothing+ }++-- | A newtype to hang off the @Semigroup PreConfPackageHook@ instance.+newtype PreConfPkgSemigroup = PreConfPkgSemigroup PreConfPackageHook++instance Semigroup PreConfPkgSemigroup where+ PreConfPkgSemigroup f1 <> PreConfPkgSemigroup f2 =+ PreConfPkgSemigroup $+ \inputs@( PreConfPackageInputs+ { configFlags = cfg+ , compiler = comp+ , platform = plat+ , localBuildConfig = lbc0+ }+ ) ->+ do+ PreConfPackageOutputs+ { buildOptions = opts1+ , extraConfiguredProgs = progs1+ } <-+ f1 inputs+ PreConfPackageOutputs+ { buildOptions = opts2+ , extraConfiguredProgs = progs2+ } <-+ f2 $+ PreConfPackageInputs+ { configFlags = cfg+ , compiler = comp+ , platform = plat+ , localBuildConfig =+ lbc0+ { LBC.withPrograms =+ updateConfiguredProgs (`Map.union` progs1) $+ LBC.withPrograms lbc0+ , LBC.withBuildOptions = opts1+ }+ }+ return $+ PreConfPackageOutputs+ { buildOptions = opts2+ , extraConfiguredProgs = progs1 <> progs2+ }++-- | A newtype to hang off the @Semigroup PreConfComponentHook@ instance.+newtype PreConfComponentSemigroup = PreConfComponentSemigroup PreConfComponentHook++instance Semigroup PreConfComponentSemigroup where+ PreConfComponentSemigroup f1 <> PreConfComponentSemigroup f2 =+ PreConfComponentSemigroup $ \inputs ->+ do+ PreConfComponentOutputs+ { componentDiff = diff1+ } <-+ f1 inputs+ PreConfComponentOutputs+ { componentDiff = diff2+ } <-+ f2 inputs+ return $+ PreConfComponentOutputs+ { componentDiff = diff1 <> diff2+ }++--------------------------------------------------------------------------------+-- Build setup hooks.++data PreBuildComponentInputs = PreBuildComponentInputs+ { buildingWhat :: BuildingWhat+ -- ^ what kind of build phase are we hooking into?+ , localBuildInfo :: LocalBuildInfo+ -- ^ information about the package+ , targetInfo :: TargetInfo+ -- ^ information about an individual component+ }+ deriving (Generic, Show)++type PreBuildComponentRules = Rules PreBuildComponentInputs++data PostBuildComponentInputs = PostBuildComponentInputs+ { buildFlags :: BuildFlags+ , localBuildInfo :: LocalBuildInfo+ , targetInfo :: TargetInfo+ }+ deriving (Generic, Show)++type PostBuildComponentHook = PostBuildComponentInputs -> IO ()++-- | Build-time hooks.+data BuildHooks = BuildHooks+ { preBuildComponentRules :: Maybe PreBuildComponentRules+ -- ^ Per-component fine-grained pre-build rules.+ , postBuildComponentHook :: Maybe PostBuildComponentHook+ -- ^ Per-component post-build hook.+ }++-- Note that the pre-build hook consists of a function which takes a component+-- as an argument (as part of the targetInfo field) and returns a collection of+-- pre-build rules.+--+-- One might wonder why it isn't instead a collection of pre-build rules, one+-- for each component. The reason is that Backpack creates components on-the-fly+-- through instantiation, which means e.g. that a single component name can+-- resolve to multiple components. This means we really need to pass in the+-- components to the function, as we don't know the full details (e.g. their+-- unit ids) ahead of time.++instance Semigroup BuildHooks where+ BuildHooks+ { preBuildComponentRules = rs1+ , postBuildComponentHook = post1+ }+ <> BuildHooks+ { preBuildComponentRules = rs2+ , postBuildComponentHook = post2+ } =+ BuildHooks+ { preBuildComponentRules = rs1 <> rs2+ , postBuildComponentHook = post1 <> post2+ }++instance Monoid BuildHooks where+ mempty = noBuildHooks++-- | Empty build hooks.+noBuildHooks :: BuildHooks+noBuildHooks =+ BuildHooks+ { preBuildComponentRules = Nothing+ , postBuildComponentHook = Nothing+ }++--------------------------------------------------------------------------------+-- Install setup hooks.++data InstallComponentInputs = InstallComponentInputs+ { copyFlags :: CopyFlags+ , localBuildInfo :: LocalBuildInfo+ , targetInfo :: TargetInfo+ }+ deriving (Generic, Show)++-- | A per-component install hook,+-- which can only perform side effects (e.g. copying files).+type InstallComponentHook = InstallComponentInputs -> IO ()++-- | Copy/install hooks.+data InstallHooks = InstallHooks+ { installComponentHook :: Maybe InstallComponentHook+ -- ^ Per-component install hook.+ }++instance Semigroup InstallHooks where+ InstallHooks+ { installComponentHook = inst1+ }+ <> InstallHooks+ { installComponentHook = inst2+ } =+ InstallHooks+ { installComponentHook = inst1 <> inst2+ }++instance Monoid InstallHooks where+ mempty = noInstallHooks++-- | Empty copy/install hooks.+noInstallHooks :: InstallHooks+noInstallHooks =+ InstallHooks+ { installComponentHook = Nothing+ }++--------------------------------------------------------------------------------+-- Per-component configure hook implementation details.++type LibraryDiff = Library+type ForeignLibDiff = ForeignLib+type ExecutableDiff = Executable+type TestSuiteDiff = TestSuite+type BenchmarkDiff = Benchmark+type BuildInfoDiff = BuildInfo++-- | A diff to a Cabal 'Component', that gets combined monoidally into+-- an existing 'Component'.+newtype ComponentDiff = ComponentDiff {componentDiff :: Component}+ deriving (Semigroup, Show)++emptyComponentDiff :: ComponentName -> ComponentDiff+emptyComponentDiff name = ComponentDiff $+ case name of+ CLibName{} -> CLib emptyLibrary+ CFLibName{} -> CFLib emptyForeignLib+ CExeName{} -> CExe emptyExecutable+ CTestName{} -> CTest emptyTestSuite+ CBenchName{} -> CBench emptyBenchmark++buildInfoComponentDiff :: ComponentName -> BuildInfo -> ComponentDiff+buildInfoComponentDiff name bi = ComponentDiff $+ BI.buildInfo .~ bi $+ case name of+ CLibName{} -> CLib emptyLibrary+ CFLibName{} -> CFLib emptyForeignLib+ CExeName{} -> CExe emptyExecutable+ CTestName{} -> CTest emptyTestSuite+ CBenchName{} -> CBench emptyBenchmark++applyLibraryDiff :: Verbosity -> Library -> LibraryDiff -> IO Library+applyLibraryDiff verbosity lib diff =+ case illegalLibraryDiffReasons lib diff of+ [] -> return $ lib <> diff+ (r : rs) ->+ dieWithException verbosity $+ SetupHooksException $+ CannotApplyComponentDiff $+ IllegalComponentDiff (CLib lib) (r NE.:| rs)++illegalLibraryDiffReasons :: Library -> LibraryDiff -> [IllegalComponentDiffReason]+illegalLibraryDiffReasons+ lib+ Library+ { libName = nm+ , libExposed = e+ , libVisibility = vis+ , libBuildInfo = bi+ } =+ [ CannotChangeName+ | not $ nm == libName emptyLibrary || nm == libName lib+ ]+ ++ [ CannotChangeComponentField "libExposed"+ | not $ e == libExposed emptyLibrary || e == libExposed lib+ ]+ ++ [ CannotChangeComponentField "libVisibility"+ | not $ vis == libVisibility emptyLibrary || vis == libVisibility lib+ ]+ ++ illegalBuildInfoDiffReasons (libBuildInfo lib) bi++applyForeignLibDiff :: Verbosity -> ForeignLib -> ForeignLibDiff -> IO ForeignLib+applyForeignLibDiff verbosity flib diff =+ case illegalForeignLibDiffReasons flib diff of+ [] -> return $ flib <> diff+ (r : rs) ->+ dieWithException verbosity $+ SetupHooksException $+ CannotApplyComponentDiff $+ IllegalComponentDiff (CFLib flib) (r NE.:| rs)++illegalForeignLibDiffReasons :: ForeignLib -> ForeignLibDiff -> [IllegalComponentDiffReason]+illegalForeignLibDiffReasons+ flib+ ForeignLib+ { foreignLibName = nm+ , foreignLibType = ty+ , foreignLibOptions = opts+ , foreignLibVersionInfo = vi+ , foreignLibVersionLinux = linux+ , foreignLibModDefFile = defs+ , foreignLibBuildInfo = bi+ } =+ [ CannotChangeName+ | not $ nm == foreignLibName emptyForeignLib || nm == foreignLibName flib+ ]+ ++ [ CannotChangeComponentField "foreignLibType"+ | not $ ty == foreignLibType emptyForeignLib || ty == foreignLibType flib+ ]+ ++ [ CannotChangeComponentField "foreignLibOptions"+ | not $ opts == foreignLibOptions emptyForeignLib || opts == foreignLibOptions flib+ ]+ ++ [ CannotChangeComponentField "foreignLibVersionInfo"+ | not $ vi == foreignLibVersionInfo emptyForeignLib || vi == foreignLibVersionInfo flib+ ]+ ++ [ CannotChangeComponentField "foreignLibVersionLinux"+ | not $ linux == foreignLibVersionLinux emptyForeignLib || linux == foreignLibVersionLinux flib+ ]+ ++ [ CannotChangeComponentField "foreignLibModDefFile"+ | not $ defs == foreignLibModDefFile emptyForeignLib || defs == foreignLibModDefFile flib+ ]+ ++ illegalBuildInfoDiffReasons (foreignLibBuildInfo flib) bi++applyExecutableDiff :: Verbosity -> Executable -> ExecutableDiff -> IO Executable+applyExecutableDiff verbosity exe diff =+ case illegalExecutableDiffReasons exe diff of+ [] -> return $ exe <> diff+ (r : rs) ->+ dieWithException verbosity $+ SetupHooksException $+ CannotApplyComponentDiff $+ IllegalComponentDiff (CExe exe) (r NE.:| rs)++illegalExecutableDiffReasons :: Executable -> ExecutableDiff -> [IllegalComponentDiffReason]+illegalExecutableDiffReasons+ exe+ Executable+ { exeName = nm+ , modulePath = path+ , exeScope = scope+ , buildInfo = bi+ } =+ [ CannotChangeName+ | not $ nm == exeName emptyExecutable || nm == exeName exe+ ]+ ++ [ CannotChangeComponentField "modulePath"+ | not $ path == modulePath emptyExecutable || path == modulePath exe+ ]+ ++ [ CannotChangeComponentField "exeScope"+ | not $ scope == exeScope emptyExecutable || scope == exeScope exe+ ]+ ++ illegalBuildInfoDiffReasons (buildInfo exe) bi++applyTestSuiteDiff :: Verbosity -> TestSuite -> TestSuiteDiff -> IO TestSuite+applyTestSuiteDiff verbosity test diff =+ case illegalTestSuiteDiffReasons test diff of+ [] -> return $ test <> diff+ (r : rs) ->+ dieWithException verbosity $+ SetupHooksException $+ CannotApplyComponentDiff $+ IllegalComponentDiff (CTest test) (r NE.:| rs)++illegalTestSuiteDiffReasons :: TestSuite -> TestSuiteDiff -> [IllegalComponentDiffReason]+illegalTestSuiteDiffReasons+ test+ TestSuite+ { testName = nm+ , testInterface = iface+ , testCodeGenerators = gens+ , testBuildInfo = bi+ } =+ [ CannotChangeName+ | not $ nm == testName emptyTestSuite || nm == testName test+ ]+ ++ [ CannotChangeComponentField "testInterface"+ | not $ iface == testInterface emptyTestSuite || iface == testInterface test+ ]+ ++ [ CannotChangeComponentField "testCodeGenerators"+ | not $ gens == testCodeGenerators emptyTestSuite || gens == testCodeGenerators test+ ]+ ++ illegalBuildInfoDiffReasons (testBuildInfo test) bi++applyBenchmarkDiff :: Verbosity -> Benchmark -> BenchmarkDiff -> IO Benchmark+applyBenchmarkDiff verbosity bench diff =+ case illegalBenchmarkDiffReasons bench diff of+ [] -> return $ bench <> diff+ (r : rs) ->+ dieWithException verbosity $+ SetupHooksException $+ CannotApplyComponentDiff $+ IllegalComponentDiff (CBench bench) (r NE.:| rs)++illegalBenchmarkDiffReasons :: Benchmark -> BenchmarkDiff -> [IllegalComponentDiffReason]+illegalBenchmarkDiffReasons+ bench+ Benchmark+ { benchmarkName = nm+ , benchmarkInterface = iface+ , benchmarkBuildInfo = bi+ } =+ [ CannotChangeName+ | not $ nm == benchmarkName emptyBenchmark || nm == benchmarkName bench+ ]+ ++ [ CannotChangeComponentField "benchmarkInterface"+ | not $ iface == benchmarkInterface emptyBenchmark || iface == benchmarkInterface bench+ ]+ ++ illegalBuildInfoDiffReasons (benchmarkBuildInfo bench) bi++illegalBuildInfoDiffReasons :: BuildInfo -> BuildInfoDiff -> [IllegalComponentDiffReason]+illegalBuildInfoDiffReasons+ bi+ BuildInfo+ { buildable = can_build+ , buildTools = build_tools+ , buildToolDepends = build_tools_depends+ , pkgconfigDepends = pkgconfig_depends+ , frameworks = fworks+ , targetBuildDepends = target_build_depends+ } =+ map CannotChangeBuildInfoField $+ [ "buildable"+ | not $ can_build == buildable bi || can_build == buildable emptyBuildInfo+ ]+ ++ [ "buildTools"+ | not $ build_tools == buildTools bi || build_tools == buildTools emptyBuildInfo+ ]+ ++ [ "buildToolsDepends"+ | not $ build_tools_depends == buildToolDepends bi || build_tools_depends == buildToolDepends emptyBuildInfo+ ]+ ++ [ "pkgconfigDepends"+ | not $ pkgconfig_depends == pkgconfigDepends bi || pkgconfig_depends == pkgconfigDepends emptyBuildInfo+ ]+ ++ [ "frameworks"+ | not $ fworks == frameworks bi || fworks == frameworks emptyBuildInfo+ ]+ ++ [ "targetBuildDepends"+ | not $ target_build_depends == targetBuildDepends bi || target_build_depends == targetBuildDepends emptyBuildInfo+ ]++-- | Traverse the components of a 'PackageDescription'.+--+-- The function must preserve the component type, i.e. map a 'CLib' to a 'CLib',+-- a 'CExe' to a 'CExe', etc.+traverseComponents+ :: Applicative m+ => (Component -> m Component)+ -> PackageDescription+ -> m PackageDescription+traverseComponents f pd =+ upd_pd+ <$> traverse f_lib (library pd)+ <*> traverse f_lib (subLibraries pd)+ <*> traverse f_flib (foreignLibs pd)+ <*> traverse f_exe (executables pd)+ <*> traverse f_test (testSuites pd)+ <*> traverse f_bench (benchmarks pd)+ where+ f_lib lib = \case { CLib lib' -> lib'; c -> mismatch (CLib lib) c } <$> f (CLib lib)+ f_flib flib = \case { CFLib flib' -> flib'; c -> mismatch (CFLib flib) c } <$> f (CFLib flib)+ f_exe exe = \case { CExe exe' -> exe'; c -> mismatch (CExe exe) c } <$> f (CExe exe)+ f_test test = \case { CTest test' -> test'; c -> mismatch (CTest test) c } <$> f (CTest test)+ f_bench bench = \case { CBench bench' -> bench'; c -> mismatch (CBench bench) c } <$> f (CBench bench)++ upd_pd lib sublibs flibs exes tests benchs =+ pd+ { library = lib+ , subLibraries = sublibs+ , foreignLibs = flibs+ , executables = exes+ , testSuites = tests+ , benchmarks = benchs+ }++ -- This is a panic, because we maintain this invariant elsewhere:+ -- see 'componentDiffError' in 'applyComponentDiff', which catches an+ -- invalid per-component configure hook.+ mismatch c1 c2 =+ error $+ "Mismatched component types: "+ ++ showComponentName (componentName c1)+ ++ " "+ ++ showComponentName (componentName c2)+ ++ "."+{-# INLINEABLE traverseComponents #-}++applyComponentDiffs+ :: Verbosity+ -> (Component -> IO (Maybe ComponentDiff))+ -> PackageDescription+ -> IO PackageDescription+applyComponentDiffs verbosity f = traverseComponents apply_diff+ where+ apply_diff :: Component -> IO Component+ apply_diff c = do+ mbDiff <- f c+ case mbDiff of+ Just diff -> applyComponentDiff verbosity c diff+ Nothing -> return c++forComponents_ :: PackageDescription -> (Component -> IO ()) -> IO ()+forComponents_ pd f = getConst $ traverseComponents (Const . f) pd++applyComponentDiff+ :: Verbosity+ -> Component+ -> ComponentDiff+ -> IO Component+applyComponentDiff verbosity comp (ComponentDiff diff)+ | CLib lib <- comp+ , CLib lib_diff <- diff =+ CLib <$> applyLibraryDiff verbosity lib lib_diff+ | CFLib flib <- comp+ , CFLib flib_diff <- diff =+ CFLib <$> applyForeignLibDiff verbosity flib flib_diff+ | CExe exe <- comp+ , CExe exe_diff <- diff =+ CExe <$> applyExecutableDiff verbosity exe exe_diff+ | CTest test <- comp+ , CTest test_diff <- diff =+ CTest <$> applyTestSuiteDiff verbosity test test_diff+ | CBench bench <- comp+ , CBench bench_diff <- diff =+ CBench <$> applyBenchmarkDiff verbosity bench bench_diff+ | otherwise =+ componentDiffError $ MismatchedComponentTypes comp diff+ where+ -- The per-component configure hook specified a diff of the wrong type,+ -- e.g. tried to apply an executable diff to a library.+ componentDiffError err =+ dieWithException verbosity $+ SetupHooksException $+ CannotApplyComponentDiff err++--------------------------------------------------------------------------------+-- Running pre-build rules++-- | Run all pre-build rules.+--+-- This function should only be called internally within @Cabal@, as it is used+-- to implement the (legacy) Setup.hs interface. The build tool+-- (e.g. @cabal-install@ or @hls@) should instead go through the separate+-- hooks executable, which allows us to only rerun the out-of-date rules+-- (instead of running all of these rules at once).+executeRules+ :: Verbosity+ -> LocalBuildInfo+ -> TargetInfo+ -> Map RuleId Rule+ -> IO ()+executeRules =+ executeRulesUserOrSystem+ SUser+ (\_rId cmd -> sequenceA $ runRuleDynDepsCmd cmd)+ (\_rId cmd -> runRuleExecCmd cmd)++-- | Like 'executeRules', except it can be used when communicating with+-- an external hooks executable.+executeRulesUserOrSystem+ :: forall userOrSystem+ . SScope userOrSystem+ -> (RuleId -> RuleDynDepsCmd userOrSystem -> IO (Maybe ([Rule.Dependency], LBS.ByteString)))+ -> (RuleId -> RuleExecCmd userOrSystem -> IO ())+ -> Verbosity+ -> LocalBuildInfo+ -> TargetInfo+ -> Map RuleId (RuleData userOrSystem)+ -> IO ()+executeRulesUserOrSystem scope runDepsCmdData runCmdData verbosity lbi tgtInfo allRules = do+ -- Compute all extra dynamic dependency edges.+ dynDepsEdges <-+ flip Map.traverseMaybeWithKey allRules $+ \rId (Rule{ruleCommands = cmds}) ->+ runDepsCmdData rId (ruleDepsCmd cmds)++ -- Create a build graph of all the rules, with static and dynamic dependencies+ -- as edges.+ let+ (ruleGraph, ruleFromVertex, vertexFromRuleId) =+ Graph.graphFromEdges+ [ (rule, rId, nub $ mapMaybe directRuleDependencyMaybe allDeps)+ | (rId, rule) <- Map.toList allRules+ , let dynDeps = fromMaybe [] (fst <$> Map.lookup rId dynDepsEdges)+ allDeps = staticDependencies rule ++ dynDeps+ ]++ -- Topologically sort the graph of rules.+ sccs = Graph.scc ruleGraph+ cycles = mapMaybe $ \(Graph.Node v0 subforest) ->+ case subforest of+ []+ | r@(_, rId, deps) <- ruleFromVertex v0 ->+ if rId `elem` deps+ then Just (r, [])+ else Nothing+ v : vs ->+ Just+ ( ruleFromVertex v0+ , map (fmap ruleFromVertex) (v : vs)+ )++ -- Compute demanded rules.+ --+ -- SetupHooks TODO: maybe requiring all generated modules to appear+ -- in autogen-modules is excessive; we can look through all modules instead.+ autogenModPaths =+ map (\m -> moduleNameSymbolicPath m <.> "hs") $+ autogenModules $+ componentBuildInfo $+ targetComponent tgtInfo+ leafRule_maybe (rId, r) =+ if any ((r `ruleOutputsLocation`) . (Location compAutogenDir)) autogenModPaths+ then vertexFromRuleId rId+ else Nothing+ leafRules = mapMaybe leafRule_maybe $ Map.toList allRules+ demandedRuleVerts = Set.fromList $ concatMap (Graph.reachable ruleGraph) leafRules+ nonDemandedRuleVerts = Set.fromList (Graph.vertices ruleGraph) Set.\\ demandedRuleVerts++ case cycles sccs of+ -- If there are cycles in the dependency structure, don't execute+ -- any rules at all; just throw an error right off the bat.+ r : rs ->+ let getRule ((ru, _, _), js) = (toRuleBinary ru, fmap (fmap (\(rv, _, _) -> toRuleBinary rv)) js)+ in errorOut $+ CyclicRuleDependencies $+ fmap getRule (r NE.:| rs)+ -- Otherwise, run all the demanded rules in dependency order (in one go).+ -- (Fine-grained running of rules should happen in cabal-install or HLS,+ -- not in the Cabal library.)+ [] -> do+ -- Emit a warning if there are non-demanded rules.+ unless (null nonDemandedRuleVerts) $+ warn verbosity $+ unlines $+ "The following rules are not demanded and will not be run:"+ : concat+ [ [ " - " ++ show rId ++ ","+ , " generating " ++ show (NE.toList $ results r)+ ]+ | v <- Set.toList nonDemandedRuleVerts+ , let (r, rId, _) = ruleFromVertex v+ ]+ ++ [ "Possible reasons for this error:"+ , " - Some autogenerated modules were not declared"+ , " (in the package description or in the pre-configure hooks)"+ , " - The output location for an autogenerated module is incorrect,"+ , " (e.g. the file extension is incorrect, or"+ , " it is not in the appropriate 'autogenComponentModules' directory)"+ ]++ -- Run all the demanded rules, in dependency order.+ for_ sccs $ \(Graph.Node ruleVertex _) ->+ -- Don't run a rule unless it is demanded.+ unless (ruleVertex `Set.member` nonDemandedRuleVerts) $ do+ let ( r@Rule+ { ruleCommands = cmds+ , staticDependencies = staticDeps+ , results = reslts+ }+ , rId+ , _staticRuleDepIds+ ) =+ ruleFromVertex ruleVertex+ mbDyn = Map.lookup rId dynDepsEdges+ allDeps = staticDeps ++ fromMaybe [] (fst <$> mbDyn)+ -- Check that the dependencies the rule expects are indeed present.+ resolvedDeps <- traverse (resolveDependency verbosity rId allRules) allDeps+ missingRuleDeps <- filterM (missingDep mbWorkDir) resolvedDeps+ case NE.nonEmpty missingRuleDeps of+ Just missingDeps ->+ errorOut $ CantFindSourceForRuleDependencies (toRuleBinary r) missingDeps+ -- Dependencies OK: run the associated action.+ Nothing -> do+ let execCmd = ruleExecCmd scope cmds (snd <$> mbDyn)+ runCmdData rId execCmd+ -- Throw an error if running the action did not result in+ -- the generation of outputs that we expected it to.+ missingRuleResults <- filterM (missingDep mbWorkDir) $ NE.toList reslts+ for_ (NE.nonEmpty missingRuleResults) $ \missingResults ->+ errorOut $ MissingRuleOutputs (toRuleBinary r) missingResults+ return ()+ where+ toRuleBinary :: RuleData userOrSystem -> RuleBinary+ toRuleBinary = case scope of+ SUser -> ruleBinary+ SSystem -> id+ clbi = targetCLBI tgtInfo+ mbWorkDir = mbWorkDirLBI lbi+ compAutogenDir = autogenComponentModulesDir lbi clbi+ errorOut e =+ dieWithException verbosity $+ SetupHooksException $+ RulesException e++directRuleDependencyMaybe :: Rule.Dependency -> Maybe RuleId+directRuleDependencyMaybe (RuleDependency dep) = Just $ outputOfRule dep+directRuleDependencyMaybe (FileDependency{}) = Nothing++resolveDependency :: Verbosity -> RuleId -> Map RuleId (RuleData scope) -> Rule.Dependency -> IO Location+resolveDependency verbosity rId allRules = \case+ FileDependency l -> return l+ RuleDependency (RuleOutput{outputOfRule = depId, outputIndex = i}) ->+ case Map.lookup depId allRules of+ Nothing ->+ error $+ unlines $+ [ "Internal error: missing rule dependency."+ , "Rule: " ++ show rId+ , "Dependency: " ++ show depId+ ]+ Just (Rule{results = os}) ->+ let j :: Int+ j = fromIntegral i+ in case listToMaybe $ drop j $ NE.toList os of+ Just o+ | j >= 0 ->+ return o+ _ ->+ dieWithException verbosity $+ SetupHooksException $+ RulesException $+ InvalidRuleOutputIndex rId depId os i++-- | Does the rule output the given location?+ruleOutputsLocation :: RuleData scope -> Location -> Bool+ruleOutputsLocation (Rule{results = rs}) fp =+ any (\out -> normaliseLocation out == normaliseLocation fp) rs++normaliseLocation :: Location -> Location+normaliseLocation (Location base rel) =+ Location (normaliseSymbolicPath base) (normaliseSymbolicPath rel)++-- | Is the file we depend on missing?+missingDep :: Maybe (SymbolicPath CWD (Dir Pkg)) -> Location -> IO Bool+missingDep mbWorkDir loc = not <$> doesFileExist fp+ where+ fp = interpretSymbolicPath mbWorkDir (location loc)++--------------------------------------------------------------------------------+-- Compatibility with HookedBuildInfo.+--+-- NB: assumes that the components in HookedBuildInfo are:+-- - an (optional) main library,+-- - executables.+--+-- No support for named sublibraries, foreign libraries, tests or benchmarks,+-- because the HookedBuildInfo datatype doesn't specify what type of component+-- each component name is (so we assume they are executables).++hookedBuildInfoComponents :: HookedBuildInfo -> Set ComponentName+hookedBuildInfoComponents (mb_mainlib, exes) =+ Set.fromList $+ (case mb_mainlib of Nothing -> id; Just{} -> (CLibName LMainLibName :))+ [CExeName exe_nm | (exe_nm, _) <- exes]++hookedBuildInfoComponentDiff_maybe :: HookedBuildInfo -> ComponentName -> Maybe (IO ComponentDiff)+hookedBuildInfoComponentDiff_maybe (mb_mainlib, exes) comp_nm =+ case comp_nm of+ CLibName lib_nm ->+ case lib_nm of+ LMainLibName -> return . ComponentDiff . CLib . buildInfoLibraryDiff <$> mb_mainlib+ LSubLibName{} -> Nothing+ CExeName exe_nm ->+ let mb_exe = lookup exe_nm exes+ in return . ComponentDiff . CExe . buildInfoExecutableDiff <$> mb_exe+ CFLibName{} -> Nothing+ CTestName{} -> Nothing+ CBenchName{} -> Nothing++buildInfoLibraryDiff :: BuildInfo -> LibraryDiff+buildInfoLibraryDiff bi = emptyLibrary{libBuildInfo = bi}++buildInfoExecutableDiff :: BuildInfo -> ExecutableDiff+buildInfoExecutableDiff bi = emptyExecutable{buildInfo = bi}++--------------------------------------------------------------------------------+-- Instances for serialisation++deriving newtype instance Binary ComponentDiff+deriving newtype instance Structured ComponentDiff++instance Binary PreConfPackageInputs+instance Structured PreConfPackageInputs+instance Binary PreConfPackageOutputs+instance Structured PreConfPackageOutputs++instance Binary PostConfPackageInputs+instance Structured PostConfPackageInputs++instance Binary PreConfComponentInputs+instance Structured PreConfComponentInputs+instance Binary PreConfComponentOutputs+instance Structured PreConfComponentOutputs++instance Binary PreBuildComponentInputs+instance Structured PreBuildComponentInputs++instance Binary PostBuildComponentInputs+instance Structured PostBuildComponentInputs++instance Binary InstallComponentInputs+instance Structured InstallComponentInputs++--------------------------------------------------------------------------------
+ src/Distribution/Simple/SetupHooks/Rule.hs view
@@ -0,0 +1,1142 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MultiWayIf #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE QuantifiedConstraints #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilyDependencies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}++-- |+-- Module: Distribution.Simple.SetupHooks.Rule+--+-- Internal module that defines fine-grained rules for setup hooks.+-- Users should import 'Distribution.Simple.SetupHooks' instead.+module Distribution.Simple.SetupHooks.Rule+ ( -- * Rules++ -- ** Rule+ Rule+ , RuleData (..)+ , RuleId (..)+ , staticRule+ , dynamicRule++ -- ** Commands+ , RuleCommands (..)+ , Command+ , CommandData (..)+ , runCommand+ , mkCommand+ , Dict (..)++ -- *** Helpers for executing commands+ , RuleCmds+ , RuleDynDepsCmd+ , RuleExecCmd+ , DynDepsCmd (..)+ , DepsRes (..)+ , ruleDepsCmd+ , runRuleDynDepsCmd+ , ruleExecCmd+ , runRuleExecCmd++ -- ** Collections of rules+ , Rules (..)+ , Dependency (..)+ , RuleOutput (..)+ , rules+ , noRules++ -- ** Rule inputs/outputs+ , Location (..)+ , location++ -- ** File/directory monitoring+ , MonitorFilePath (..)+ , MonitorKindFile (..)+ , MonitorKindDir (..)++ -- *** Monadic API for generation of 'ActionId'+ , RulesM+ , RulesT (..)+ , RulesEnv (..)+ , computeRules++ -- * Internals+ , Scope (..)+ , SScope (..)+ , Static (..)+ , RuleBinary+ , ruleBinary+ )+where++import qualified Distribution.Compat.Binary as Binary+import Distribution.Compat.Prelude++import Distribution.ModuleName+ ( ModuleName+ )+import Distribution.Simple.FileMonitor.Types+import Distribution.Types.UnitId+import Distribution.Utils.Path+ ( FileOrDir (..)+ , Pkg+ , RelativePath+ , SymbolicPath+ , getSymbolicPath+ , (</>)+ )+import Distribution.Utils.ShortText+ ( ShortText+ )+import Distribution.Utils.Structured+ ( Structure (..)+ , Structured (..)+ , nominalStructure+ )+import Distribution.Verbosity+ ( Verbosity+ )++import Control.Monad.Fix+ ( MonadFix+ )+import Control.Monad.Trans+ ( MonadIO+ , MonadTrans (..)+ )+import qualified Control.Monad.Trans.Reader as Reader+import qualified Control.Monad.Trans.State as State+#if MIN_VERSION_transformers(0,5,6)+import qualified Control.Monad.Trans.Writer.CPS as Writer+#else+import qualified Control.Monad.Trans.Writer.Strict as Writer+#endif+import qualified Data.ByteString.Lazy as LBS+import qualified Data.List.NonEmpty as NE+import qualified Data.Map.Strict as Map+ ( empty+ )++import qualified Data.Kind as Hs+import Data.Type.Bool+ ( If+ )+import Data.Type.Equality+ ( (:~~:) (HRefl)+ , type (==)+ )+import GHC.Show+ ( showCommaSpace+ )+import GHC.StaticPtr+import GHC.TypeLits+ ( Symbol+ )+import System.IO.Unsafe+ ( unsafePerformIO+ )+import qualified Type.Reflection as Typeable+ ( SomeTypeRep (..)+ , TypeRep+ , eqTypeRep+ , typeRep+ , typeRepKind+ , withTypeable+ , pattern App+ )++import System.FilePath+ ( normalise+ )++--------------------------------------------------------------------------------++{- Note [Fine-grained hooks]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+To best understand how the framework of fine-grained build rules+fits into Cabal and the greater Haskell ecosystem, it is helpful to think+that we want build tools (such as cabal-install or HLS) to be able to call+individual build rules on-demand, so that e.g. when a user modifies a .xyz file+the associated preprocessor is re-run.++To do this, we need to perform two different kinds of invocations:++ Query: query the package for the rules that it provides, with their+ dependency information. This allows one to determine when each+ rule should be rerun.++ (For example, if one rule preprocesses *.xyz into *.hs, we need to+ re-run the rule whenever *.xyz is modified.)++ Run: run the relevant action, once one has determined that the rule+ has gone stale.++To do this, any Cabal package with Hooks build-type provides a SetupHooks+module which supports these queries; for example it can be compiled into+a separate executable which can be invoked in the manner described above.+-}++---------+-- Rules++-- | A unique identifier for a t'Rule'.+data RuleId = RuleId+ { ruleNameSpace :: !RulesNameSpace+ , ruleName :: !ShortText+ }+ deriving stock (Show, Eq, Ord, Generic)+ deriving anyclass (Binary, Structured)++data RulesNameSpace = RulesNameSpace+ { rulesUnitId :: !UnitId+ , rulesModuleName :: !ModuleName+ , rulesSrcLoc :: !(Int, Int)+ }+ deriving stock (Show, Eq, Ord, Generic)+ deriving anyclass (Binary, Structured)++-- | Internal function: create a 'RulesNameSpace' from a 'StaticPtrInfo'.+staticPtrNameSpace :: StaticPtrInfo -> RulesNameSpace+staticPtrNameSpace+ StaticPtrInfo+ { spInfoUnitId = unitId+ , spInfoModuleName = modName+ , spInfoSrcLoc = srcLoc+ } =+ RulesNameSpace+ { rulesUnitId = mkUnitId unitId+ , rulesModuleName = fromString modName+ , rulesSrcLoc = srcLoc+ }++-- | 'Rule's are defined with rich types by the package.+--+-- The build system only has a limited view of these; most data consists of+-- opaque 'ByteString's.+--+-- The 'Scope' data-type describes which side of this divide we are on.+data Scope+ = -- | User space (with rich types).+ User+ | -- | Build-system space (manipulation of raw data).+ System++data SScope (scope :: Scope) where+ SUser :: SScope User+ SSystem :: SScope System++type Rule = RuleData User+type RuleBinary = RuleData System++-- | A rule consists of:+--+-- - an action to run to execute the rule,+-- - a description of the rule inputs and outputs.+--+-- Use 'staticRule' or 'dynamicRule' to construct a rule, overriding specific+-- fields, rather than directly using the 'Rule' constructor.+data RuleData (scope :: Scope)+ = -- | Please use the 'staticRule' or 'dynamicRule' smart constructors+ -- instead of this constructor, in order to avoid relying on internal+ -- implementation details.+ Rule+ { ruleCommands :: !(RuleCmds scope)+ -- ^ To run this rule, which t'Command's should we execute?+ , staticDependencies :: ![Dependency]+ -- ^ Static dependencies of this rule.+ , results :: !(NE.NonEmpty Location)+ -- ^ Results of this rule.+ }+ deriving stock (Generic)++deriving stock instance Show (RuleData User)+deriving stock instance Eq (RuleData User)+deriving stock instance Eq (RuleData System)+deriving anyclass instance Binary (RuleData User)+deriving anyclass instance Binary (RuleData System)++-- | Trimmed down 'Show' instance, mostly for error messages.+instance Show RuleBinary where+ show (Rule{staticDependencies = deps, results = reslts, ruleCommands = cmds}) =+ what ++ ": " ++ showDeps deps ++ " --> " ++ show (NE.toList reslts)+ where+ what = case cmds of+ StaticRuleCommand{} -> "Rule"+ DynamicRuleCommands{} -> "Rule (dyn-deps)"+ showDeps :: [Dependency] -> String+ showDeps ds = "[" ++ intercalate ", " (map showDep ds) ++ "]"+ showDep :: Dependency -> String+ showDep = \case+ RuleDependency (RuleOutput{outputOfRule = rId, outputIndex = i}) ->+ "(" ++ show rId ++ ")[" ++ show i ++ "]"+ FileDependency loc -> show loc++-- | A rule with static dependencies.+--+-- Prefer using this smart constructor instead of v'Rule' whenever possible.+staticRule+ :: forall arg+ . Typeable arg+ => Command arg (IO ())+ -> [Dependency]+ -> NE.NonEmpty Location+ -> Rule+staticRule cmd dep res =+ Rule+ { ruleCommands =+ StaticRuleCommand+ { staticRuleCommand = cmd+ , staticRuleArgRep = Typeable.typeRep @arg+ }+ , staticDependencies = dep+ , results = res+ }++-- | A rule with dynamic dependencies.+--+-- Prefer using this smart constructor instead of v'Rule' whenever possible.+dynamicRule+ :: forall depsArg depsRes arg+ . (Typeable depsArg, Typeable depsRes, Typeable arg)+ => StaticPtr (Dict (Binary depsRes, Show depsRes, Eq depsRes))+ -> Command depsArg (IO ([Dependency], depsRes))+ -> Command arg (depsRes -> IO ())+ -> [Dependency]+ -> NE.NonEmpty Location+ -> Rule+dynamicRule dict depsCmd action dep res =+ Rule+ { ruleCommands =+ DynamicRuleCommands+ { dynamicRuleInstances = UserStatic dict+ , dynamicDeps = DynDepsCmd{dynDepsCmd = depsCmd}+ , dynamicRuleCommand = action+ , dynamicRuleTypeRep = Typeable.typeRep @(depsArg, depsRes, arg)+ }+ , staticDependencies = dep+ , results = res+ }++-----------------------+-- Rule inputs/outputs++-- | A (fully resolved) location of a dependency or result of a rule,+-- consisting of a base directory and of a file path relative to that base+-- directory path.+--+-- In practice, this will be something like @'Location' dir ('moduleNameSymbolicPath' mod <.> "hs")@,+-- where:+--+-- - for a file dependency, @dir@ is one of the Cabal search directories,+-- - for an output, @dir@ is a directory such as @autogenComponentModulesDir@+-- or @componentBuildDir@.+data Location where+ Location+ :: { locationBaseDir :: !(SymbolicPath Pkg (Dir baseDir))+ -- ^ Base directory.+ , locationRelPath :: !(RelativePath baseDir File)+ -- ^ File path relative to base directory (including file extension).+ }+ -> Location++instance Eq Location where+ Location b1 l1 == Location b2 l2 =+ (getSymbolicPath b1 == getSymbolicPath b2)+ && (getSymbolicPath l1 == getSymbolicPath l2)+instance Ord Location where+ compare (Location b1 l1) (Location b2 l2) =+ compare+ (getSymbolicPath b1, getSymbolicPath l1)+ (getSymbolicPath b2, getSymbolicPath l2)+instance Binary Location where+ put (Location base loc) = put (base, loc)+ get = Location <$> get <*> get+instance Structured Location where+ structure _ =+ Structure+ tr+ 0+ (show tr)+ [+ ( "Location"+ ,+ [ nominalStructure $ Proxy @(SymbolicPath Pkg (Dir (Tok "baseDir")))+ , nominalStructure $ Proxy @(RelativePath (Tok "baseDir") File)+ ]+ )+ ]+ where+ tr = Typeable.SomeTypeRep $ Typeable.typeRep @Location++-- | Get a (relative or absolute) un-interpreted path to a 'Location'.+location :: Location -> SymbolicPath Pkg File+location (Location base rel) = base </> rel++instance Show Location where+ showsPrec p (Location base rel) =+ showParen (p > 5) $+ showString (normalise $ getSymbolicPath base)+ . showString " </> "+ . showString (normalise $ getSymbolicPath rel)++-- 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 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 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).++-- | A dependency of a rule.+data Dependency+ = -- | A dependency on an output of another rule.+ RuleDependency !RuleOutput+ | -- | A direct dependency on a file at a particular location on disk.+ --+ -- This should not be used for files that are generated by other rules;+ -- use 'RuleDependency' instead.+ FileDependency !Location+ deriving stock (Show, Eq, Ord, Generic)+ deriving anyclass (Binary, Structured)++-- | A reference to an output of another rule.+data RuleOutput = RuleOutput+ { outputOfRule :: !RuleId+ -- ^ which rule's outputs are we referring to?+ , outputIndex :: !Word+ -- ^ which particular output of that rule?+ }+ deriving stock (Show, Eq, Ord, Generic)+ deriving anyclass (Binary, Structured)++---------+-- Rules++-- | Monad for constructing rules.+type RulesM a = RulesT IO a++-- | The environment within the monadic API.+data RulesEnv = RulesEnv+ { rulesEnvVerbosity :: !Verbosity+ , rulesEnvNameSpace :: !RulesNameSpace+ }++-- | Monad transformer for defining rules. Usually wraps the 'IO' monad,+-- allowing @IO@ actions to be performed using @liftIO@.+newtype RulesT m a = RulesT+ { runRulesT+ :: Reader.ReaderT+ RulesEnv+ ( State.StateT+ (Map RuleId Rule)+ (Writer.WriterT [MonitorFilePath] m)+ )+ a+ }+ deriving newtype (Functor, Applicative, Monad, MonadIO, MonadFix)++instance MonadTrans RulesT where+ lift = RulesT . lift . lift . lift++-- | A collection of t'Rule's.+--+-- Use the 'rules' smart constructor instead of directly using the v'Rules'+-- constructor.+--+-- - Rules are registered using 'registerRule',+-- - Monitored files or directories are declared using 'addRuleMonitors';+-- a change in these will trigger the recomputation of all rules.+--+-- The @env@ type parameter represents an extra argument, which usually+-- consists of information known to Cabal such as 'LocalBuildInfo' and+-- 'ComponentLocalBuildInfo'.+newtype Rules env = Rules {runRules :: env -> RulesM ()}++-- | __Warning__: this 'Semigroup' instance is not commutative.+instance Semigroup (Rules env) where+ (Rules rs1) <> (Rules rs2) =+ Rules $ \inputs -> do+ y1 <- rs1 inputs+ y2 <- rs2 inputs+ return $ y1 <> y2++instance Monoid (Rules env) where+ mempty = Rules $ const noRules++-- | An empty collection of rules.+noRules :: RulesM ()+noRules = return ()++-- | Construct a collection of rules with a given label.+--+-- A label for the rules can be constructed using the @static@ keyword,+-- using the @StaticPointers@ extension.+-- NB: separate calls to 'rules' should have different labels.+--+-- Example usage:+--+-- > myRules :: Rules env+-- > myRules = rules (static ()) $ \ env -> do { .. } -- use the monadic API here+rules+ :: StaticPtr label+ -- ^ unique label for this collection of rules+ -> (env -> RulesM ())+ -- ^ the computation of rules+ -> Rules env+rules label = rulesInNameSpace (staticPtrNameSpace $ staticPtrInfo label)++-- | Internal function to create a collection of rules.+--+-- API users should go through the 'rules' function instead.+rulesInNameSpace+ :: RulesNameSpace+ -- ^ rule namespace+ -> (env -> RulesM ())+ -- ^ the computation of rules+ -> Rules env+rulesInNameSpace nameSpace f =+ Rules $ \env -> RulesT $ do+ Reader.withReaderT (\rulesEnv -> rulesEnv{rulesEnvNameSpace = nameSpace}) $+ runRulesT $+ f env++-- | Internal function: run the monadic 'Rules' computations in order+-- to obtain all the 'Rule's with their 'RuleId's.+computeRules+ :: Verbosity+ -> env+ -> Rules env+ -> IO (Map RuleId Rule, [MonitorFilePath])+computeRules verbosity inputs (Rules rs) = do+ -- Bogus namespace to start with. This will be the first thing+ -- to be set when users use the 'rules' smart constructor.+ let noNameSpace =+ RulesNameSpace+ { rulesUnitId = mkUnitId ""+ , rulesModuleName = fromString ""+ , rulesSrcLoc = (0, 0)+ }+ env0 =+ RulesEnv+ { rulesEnvVerbosity = verbosity+ , rulesEnvNameSpace = noNameSpace+ }+ Writer.runWriterT $+ (`State.execStateT` Map.empty) $+ (`Reader.runReaderT` env0) $+ runRulesT $+ rs inputs++------------+-- Commands++-- | A static pointer (in user scope) or its key (in system scope).+data family Static (scope :: Scope) :: Hs.Type -> Hs.Type++newtype instance Static User fnTy = UserStatic {userStaticPtr :: StaticPtr fnTy}+newtype instance Static System fnTy = SystemStatic {userStaticKey :: StaticKey}+ deriving newtype (Eq, Ord, Show, Binary)++systemStatic :: Static User fnTy -> Static System fnTy+systemStatic (UserStatic ptr) = SystemStatic (staticKey ptr)++instance Show (Static User fnTy) where+ showsPrec p ptr = showsPrec p (systemStatic ptr)+instance Eq (Static User fnTy) where+ (==) = (==) `on` systemStatic+instance Ord (Static User fnTy) where+ compare = compare `on` systemStatic+instance Binary (Static User fnTy) where+ put = put . systemStatic+ get = do+ ptrKey <- get @StaticKey+ case unsafePerformIO $ unsafeLookupStaticPtr ptrKey of+ Just ptr -> return $ UserStatic ptr+ Nothing ->+ fail $+ unlines+ [ "Failed to look up static pointer key for action."+ , "NB: Binary instances for 'User' types cannot be used in external executables."+ ]++-- | A command consists of a statically-known action together with a+-- (possibly dynamic) argument to that action.+--+-- For example, the action can consist of running an executable+-- (such as @happy@ or @c2hs@), while the argument consists of the variable+-- component of the command, e.g. the specific file to run @happy@ on.+type Command = CommandData User++-- | Internal datatype used for commands, both for the Hooks API ('Command')+-- and for the build system.+data CommandData (scope :: Scope) (arg :: Hs.Type) (res :: Hs.Type) = Command+ { actionPtr :: !(Static scope (arg -> res))+ -- ^ The (statically-known) action to execute.+ , actionArg :: !(ScopedArgument scope arg)+ -- ^ The (possibly dynamic) argument to pass to the action.+ , cmdInstances :: !(Static scope (Dict (Binary arg, Show arg)))+ -- ^ Static evidence that the argument can be serialised and deserialised.+ }++-- | Construct a command.+--+-- Prefer using this smart constructor instead of v'Command' whenever possible.+mkCommand+ :: forall arg res+ . StaticPtr (Dict (Binary arg, Show arg))+ -> StaticPtr (arg -> res)+ -> arg+ -> Command arg res+mkCommand dict actionPtr arg =+ Command+ { actionPtr = UserStatic actionPtr+ , actionArg = ScopedArgument arg+ , cmdInstances = UserStatic dict+ }++-- | Run a 'Command'.+runCommand :: Command args res -> res+runCommand (Command{actionPtr = UserStatic ptr, actionArg = ScopedArgument arg}) =+ deRefStaticPtr ptr arg++-- | Commands to execute a rule:+--+-- - for a rule with static dependencies, a single command,+-- - for a rule with dynamic dependencies, a command for computing dynamic+-- dependencies, and a command for executing the rule.+data+ RuleCommands+ (scope :: Scope)+ (deps :: Scope -> Hs.Type -> Hs.Type -> Hs.Type)+ (ruleCmd :: Scope -> Hs.Type -> Hs.Type -> Hs.Type)+ where+ -- | A rule with statically-known dependencies.+ StaticRuleCommand+ :: forall arg deps ruleCmd scope+ . If+ (scope == System)+ (arg ~ LBS.ByteString)+ (() :: Hs.Constraint)+ => { staticRuleCommand :: !(ruleCmd scope arg (IO ()))+ -- ^ The command to execute the rule.+ , staticRuleArgRep :: !(If (scope == System) Typeable.SomeTypeRep (Typeable.TypeRep arg))+ -- ^ A 'TypeRep' for 'arg'.+ }+ -> RuleCommands scope deps ruleCmd+ DynamicRuleCommands+ :: forall depsArg depsRes arg deps ruleCmd scope+ . If+ (scope == System)+ (depsArg ~ LBS.ByteString, depsRes ~ LBS.ByteString, arg ~ LBS.ByteString)+ (() :: Hs.Constraint)+ => { dynamicRuleInstances :: !(Static scope (Dict (Binary depsRes, Show depsRes, Eq depsRes)))+ -- ^ A rule with dynamic dependencies, which consists of two parts:+ --+ -- - a dynamic dependency computation, that returns additional edges to+ -- be added to the build graph together with an additional piece of data,+ -- - the command to execute the rule itself, which receives the additional+ -- piece of data returned by the dependency computation.+ , -- \^ Static evidence used for serialisation, in order to pass the result+ -- of the dependency computation to the main rule action.+ dynamicDeps :: !(deps scope depsArg depsRes)+ -- ^ A dynamic dependency computation. The resulting dependencies+ -- will be injected into the build graph, and the result of the computation+ -- will be passed on to the command that executes the rule.+ , dynamicRuleCommand :: !(ruleCmd scope arg (depsRes -> IO ()))+ -- ^ The command to execute the rule. It will receive the result+ -- of the dynamic dependency computation.+ , dynamicRuleTypeRep+ :: !( If+ (scope == System)+ Typeable.SomeTypeRep+ (Typeable.TypeRep (depsArg, depsRes, arg))+ )+ -- ^ A 'TypeRep' for the triple @(depsArg,depsRes,arg)@.+ }+ -> RuleCommands scope deps ruleCmd++{- Note [Hooks Binary instances]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The Hooks API is strongly typed: users can declare rule commands with varying+types, e.g.++ staticRule+ :: forall arg+ . Typeable arg+ => Command arg (IO ())+ -> [Dependency]+ -> NE.NonEmpty Location+ -> Rule++allows a user to declare a 'Command' that receives an argument of type 'arg'+of their choosing.++This all makes sense within the Hooks API, but when communicating with an+external build system (such as cabal-install or HLS), these arguments are+treated as opaque blobs of data (in particular if the Hooks are compiled into+a separate executable, then the static pointers that contain the relevant+instances for these user-chosen types can only be dereferenced from within that+executable, and not on the side of the build system).++This means that, to enable Hooks to be communicated between the package and the+build system, we need:++ 1. Two representations of rules: one for the package author using the Hooks API,+ and one for the build system.+ 2. Compatibility in the 'Binary' instances for these two types. One needs to be+ able to serialise a 'User'-side 'Rule', and de-serialise it on the build system+ into a 'System'-side 'Rule' which contains some opaque bits of data, and+ vice-versa.++(1) is achieved using the 'Scope' parameter to the 'RuleData' datatype.+@Rule = RuleData User@ is the API-side representation, whereas+@RuleBinary = RuleData System@ is the build-system-side representation.++For (2), note that when we serialise a value of known type and known size, e.g.+an 'Int64', we are nevertheless required to also serialise its size. This is because,+on the build-system side, we don't have access to any of the types, and thus don't know+how much to read in order to reconstruct the associated opaque 'ByteString'.+To ensure we always serialise/deserialise including the length of the data,+the 'ScopedArgument' newtype is used, with a custom 'Binary' instance that always+incldues the length. We use this newtype:++ - in the definition of 'CommandData', for arguments to rules,+ - in the definition of 'DepsRes', for the result of dynamic dependency computations.+-}++newtype ScopedArgument (scope :: Scope) arg = ScopedArgument {getArg :: arg}+ deriving newtype (Eq, Ord, Show)++-- | Serialise/deserialise, always including the length of the payload.+instance Binary arg => Binary (ScopedArgument User arg) where+ put (ScopedArgument arg) = put @LBS.ByteString (Binary.encode arg)+ get = do+ dat <- get @LBS.ByteString+ case Binary.decodeOrFail dat of+ Left (_, _, err) -> fail err+ Right (_, _, res) -> return $ ScopedArgument res++-- | Serialise and deserialise a raw ByteString, leaving it untouched.+instance arg ~ LBS.ByteString => Binary (ScopedArgument System arg) where+ put (ScopedArgument arg) = put arg+ get = ScopedArgument <$> get++-- | A placeholder for a command that has been omitted, e.g. when we don't+-- care about serialising/deserialising one particular command in a datatype.+data NoCmd (scope :: Scope) arg res = CmdOmitted+ deriving stock (Generic, Eq, Ord, Show)+ deriving anyclass (Binary)++-- | A dynamic dependency command.+newtype DynDepsCmd scope depsArg depsRes = DynDepsCmd+ { dynDepsCmd+ :: CommandData scope depsArg (IO ([Dependency], depsRes))+ }++deriving newtype instance Show (DynDepsCmd User depsArg depsRes)+deriving newtype instance Eq (DynDepsCmd User depsArg depsRes)+deriving newtype instance Binary (DynDepsCmd User depsArg depsRes)+deriving newtype instance+ (arg ~ LBS.ByteString, depsRes ~ LBS.ByteString)+ => Eq (DynDepsCmd System arg depsRes)+deriving newtype instance+ (arg ~ LBS.ByteString, depsRes ~ LBS.ByteString)+ => Binary (DynDepsCmd System arg depsRes)++-- | The result of a dynamic dependency computation.+newtype DepsRes (scope :: Scope) depsArg depsRes = DepsRes+ { depsRes+ :: ScopedArgument scope depsRes -- See Note [Hooks Binary instances]+ }+ deriving newtype (Show, Eq, Ord)++deriving newtype instance+ Binary (ScopedArgument scope depsRes)+ => Binary (DepsRes scope depsArg depsRes)++-- | Both the rule command and the (optional) dynamic dependency command.+type RuleCmds scope = RuleCommands scope DynDepsCmd CommandData++-- | Only the (optional) dynamic dependency command.+type RuleDynDepsCmd scope = RuleCommands scope DynDepsCmd NoCmd++-- | The rule command together with the result of the (optional) dynamic+-- dependency computation.+type RuleExecCmd scope = RuleCommands scope DepsRes CommandData++-- | Project out the (optional) dependency computation command, so that+-- it can be serialised without serialising anything else.+ruleDepsCmd :: RuleCmds scope -> RuleDynDepsCmd scope+ruleDepsCmd = \case+ StaticRuleCommand+ { staticRuleCommand = _ :: CommandData scope args (IO ())+ , staticRuleArgRep = tr+ } ->+ StaticRuleCommand+ { staticRuleCommand = CmdOmitted :: NoCmd scope args (IO ())+ , staticRuleArgRep = tr+ }+ DynamicRuleCommands+ { dynamicRuleCommand = _ :: CommandData scope args (depsRes -> IO ())+ , dynamicRuleInstances = instsPtr+ , dynamicDeps = deps+ , dynamicRuleTypeRep = tr+ } ->+ DynamicRuleCommands+ { dynamicRuleInstances = instsPtr+ , dynamicDeps = deps+ , dynamicRuleCommand = CmdOmitted :: NoCmd scope args (depsRes -> IO ())+ , dynamicRuleTypeRep = tr+ }++-- | Obtain the (optional) 'IO' action that computes dynamic dependencies.+runRuleDynDepsCmd :: RuleDynDepsCmd User -> Maybe (IO ([Dependency], LBS.ByteString))+runRuleDynDepsCmd = \case+ StaticRuleCommand{} -> Nothing+ DynamicRuleCommands+ { dynamicRuleInstances = UserStatic instsPtr+ , dynamicDeps = DynDepsCmd{dynDepsCmd = depsCmd}+ }+ | Dict <- deRefStaticPtr instsPtr ->+ Just $ do+ (deps, depsRes) <- runCommand depsCmd+ -- See Note [Hooks Binary instances]+ return $ (deps, Binary.encode $ ScopedArgument @User depsRes)++-- | Project out the command for running the rule, passing in the result of+-- the dependency computation if there was one.+ruleExecCmd :: SScope scope -> RuleCmds scope -> Maybe LBS.ByteString -> RuleExecCmd scope+ruleExecCmd+ _+ StaticRuleCommand{staticRuleCommand = cmd, staticRuleArgRep = tr}+ _ =+ StaticRuleCommand{staticRuleCommand = cmd, staticRuleArgRep = tr}+ruleExecCmd+ scope+ DynamicRuleCommands+ { dynamicRuleInstances = instsPtr+ , dynamicRuleCommand = cmd :: CommandData scope arg (depsRes -> IO ())+ , dynamicDeps = _ :: DynDepsCmd scope depsArg depsRes+ , dynamicRuleTypeRep = tr+ }+ mbDepsResBinary =+ case mbDepsResBinary of+ Nothing ->+ error $+ unlines+ [ "Missing ByteString argument in 'ruleExecCmd'."+ , "Run 'runRuleDynDepsCmd' on the rule to obtain this data."+ ]+ Just depsResBinary ->+ case scope of+ SUser+ | Dict <- deRefStaticPtr (userStaticPtr instsPtr) ->+ DynamicRuleCommands+ { dynamicRuleInstances = instsPtr+ , dynamicRuleCommand = cmd+ , dynamicDeps = Binary.decode depsResBinary :: DepsRes User depsArg depsRes+ , dynamicRuleTypeRep = tr+ }+ SSystem ->+ DynamicRuleCommands+ { dynamicRuleInstances = instsPtr+ , dynamicRuleCommand = cmd+ , dynamicDeps = DepsRes $ ScopedArgument depsResBinary+ , dynamicRuleTypeRep = tr+ }++-- | Obtain the 'IO' action that executes a rule.+runRuleExecCmd :: RuleExecCmd User -> IO ()+runRuleExecCmd = \case+ StaticRuleCommand{staticRuleCommand = cmd} -> runCommand cmd+ DynamicRuleCommands+ { dynamicDeps = DepsRes (ScopedArgument{getArg = res})+ , dynamicRuleCommand = cmd+ } ->+ runCommand cmd res++--------------------------------------------------------------------------------+-- Instances++-- | A wrapper used to pass evidence of a constraint as an explicit value.+data Dict c where+ Dict :: c => Dict c++instance Show (CommandData User arg res) where+ showsPrec prec (Command{actionPtr = cmdPtr, actionArg = arg, cmdInstances = insts})+ | Dict <- deRefStaticPtr (userStaticPtr insts) =+ showParen (prec >= 11) $+ showString "Command {"+ . showString "actionPtrKey = "+ . shows cmdPtr+ . showCommaSpace+ . showString "actionArg = "+ . shows arg+ . showString "}"++instance Eq (CommandData User arg res) where+ Command{actionPtr = cmdPtr1, actionArg = arg1, cmdInstances = insts1}+ == Command{actionPtr = cmdPtr2, actionArg = arg2, cmdInstances = insts2}+ | cmdPtr1 == cmdPtr2+ , insts1 == insts2+ , Dict <- deRefStaticPtr (userStaticPtr insts1) =+ Binary.encode arg1 == Binary.encode arg2+ | otherwise =+ False+instance arg ~ LBS.ByteString => Eq (CommandData System arg res) where+ Command a1 b1 c1 == Command a2 b2 c2 =+ a1 == a2 && b1 == b2 && c1 == c2++instance Binary (CommandData User arg res) where+ put (Command{actionPtr = cmdPtr, actionArg = arg, cmdInstances = insts})+ | Dict <- deRefStaticPtr (userStaticPtr insts) =+ do+ put cmdPtr+ put insts+ put arg+ get = do+ cmdPtr <- get+ instsPtr <- get+ case deRefStaticPtr @(Dict (Binary arg, Show arg)) $ userStaticPtr instsPtr of+ Dict -> do+ arg <- get+ return $+ Command+ { actionPtr = cmdPtr+ , actionArg = arg+ , cmdInstances = instsPtr+ }+instance arg ~ LBS.ByteString => Binary (CommandData System arg res) where+ put (Command{actionPtr = cmdPtr, actionArg = arg, cmdInstances = insts}) =+ do+ put cmdPtr+ put insts+ put arg+ get = do+ cmdKey <- get+ instsKey <- get+ arg <- get+ return $ Command{actionPtr = cmdKey, actionArg = arg, cmdInstances = instsKey}++instance+ ( forall arg res. Show (ruleCmd User arg res)+ , forall depsArg depsRes. Show depsRes => Show (deps User depsArg depsRes)+ )+ => Show (RuleCommands User deps ruleCmd)+ where+ showsPrec prec (StaticRuleCommand{staticRuleCommand = cmd}) =+ showParen (prec >= 11) $+ showString "StaticRuleCommand {"+ . showString "staticRuleCommand = "+ . shows cmd+ . showString "}"+ showsPrec+ prec+ ( DynamicRuleCommands+ { dynamicDeps = deps+ , dynamicRuleCommand = cmd+ , dynamicRuleInstances = UserStatic instsPtr+ }+ )+ | Dict <- deRefStaticPtr instsPtr =+ showParen (prec >= 11) $+ showString "DynamicRuleCommands {"+ . showString "dynamicDeps = "+ . shows deps+ . showCommaSpace+ . showString "dynamicRuleCommand = "+ . shows cmd+ . showString "}"++instance+ ( forall arg res. Eq (ruleCmd User arg res)+ , forall depsArg depsRes. Eq depsRes => Eq (deps User depsArg depsRes)+ )+ => Eq (RuleCommands User deps ruleCmd)+ where+ StaticRuleCommand{staticRuleCommand = ruleCmd1 :: ruleCmd User arg1 (IO ()), staticRuleArgRep = tr1}+ == StaticRuleCommand{staticRuleCommand = ruleCmd2 :: ruleCmd User arg2 (IO ()), staticRuleArgRep = tr2}+ | Just HRefl <- Typeable.eqTypeRep tr1 tr2 =+ ruleCmd1 == ruleCmd2+ DynamicRuleCommands+ { dynamicDeps = depsCmd1 :: deps User depsArg1 depsRes1+ , dynamicRuleCommand = ruleCmd1 :: ruleCmd User arg1 (depsRes1 -> IO ())+ , dynamicRuleInstances = UserStatic instsPtr1+ , dynamicRuleTypeRep = tr1+ }+ == DynamicRuleCommands+ { dynamicDeps = depsCmd2 :: deps User depsArg2 depsRes2+ , dynamicRuleCommand = ruleCmd2 :: ruleCmd User arg2 (depsRes2 -> IO ())+ , dynamicRuleInstances = UserStatic instsPtr2+ , dynamicRuleTypeRep = tr2+ }+ | Just HRefl <- Typeable.eqTypeRep tr1 tr2+ , Dict <- deRefStaticPtr instsPtr1 =+ depsCmd1 == depsCmd2+ && ruleCmd1 == ruleCmd2+ && staticKey instsPtr1 == staticKey instsPtr2+ _ == _ = False++instance+ ( forall res. Eq (ruleCmd System LBS.ByteString res)+ , Eq (deps System LBS.ByteString LBS.ByteString)+ )+ => Eq (RuleCommands System deps ruleCmd)+ where+ StaticRuleCommand c1 d1 == StaticRuleCommand c2 d2 = c1 == c2 && d1 == d2+ DynamicRuleCommands a1 b1 c1 d1 == DynamicRuleCommands a2 b2 c2 d2 =+ a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2+ _ == _ = False++instance+ ( forall arg res. Binary (ruleCmd User arg res)+ , forall depsArg depsRes. Binary depsRes => Binary (deps User depsArg depsRes)+ )+ => Binary (RuleCommands User deps ruleCmd)+ where+ put = \case+ StaticRuleCommand+ { staticRuleCommand = ruleCmd :: ruleCmd User arg (IO ())+ , staticRuleArgRep = tr+ } -> do+ put @Word 0+ put (Typeable.SomeTypeRep tr)+ put ruleCmd+ DynamicRuleCommands+ { dynamicDeps = deps :: deps User depsArg depsRes+ , dynamicRuleCommand = ruleCmd :: ruleCmd User arg (depsRes -> IO ())+ , dynamicRuleInstances = instsPtr+ , dynamicRuleTypeRep = tr+ } | Dict <- deRefStaticPtr (userStaticPtr instsPtr) ->+ do+ put @Word 1+ put (Typeable.SomeTypeRep tr)+ put instsPtr+ put ruleCmd+ put deps+ get = do+ tag <- get @Word+ case tag of+ 0 -> do+ Typeable.SomeTypeRep (trArg :: Typeable.TypeRep arg) <- get+ if+ | Just HRefl <- Typeable.eqTypeRep (Typeable.typeRepKind trArg) (Typeable.typeRep @Hs.Type) ->+ do+ ruleCmd <- get @(ruleCmd User arg (IO ()))+ return $+ Typeable.withTypeable trArg $+ StaticRuleCommand+ { staticRuleCommand = ruleCmd+ , staticRuleArgRep = trArg+ }+ | otherwise ->+ error "internal error when decoding static rule command"+ _ -> do+ Typeable.SomeTypeRep (tr :: Typeable.TypeRep ty) <- get+ case tr of+ Typeable.App+ ( Typeable.App+ (Typeable.App (tup3Tr :: Typeable.TypeRep tup3) (trDepsArg :: Typeable.TypeRep depsArg))+ (trDepsRes :: Typeable.TypeRep depsRes)+ )+ (trArg :: Typeable.TypeRep arg)+ | Just HRefl <- Typeable.eqTypeRep tup3Tr (Typeable.typeRep @(,,)) -> do+ instsPtr <- get+ case deRefStaticPtr $ userStaticPtr instsPtr of+ (Dict :: Dict (Binary depsRes, Show depsRes, Eq depsRes)) ->+ do+ ruleCmd <- get @(ruleCmd User arg (depsRes -> IO ()))+ deps <- get @(deps User depsArg depsRes)+ return $+ Typeable.withTypeable trDepsArg $+ Typeable.withTypeable trDepsRes $+ Typeable.withTypeable trArg $+ DynamicRuleCommands+ { dynamicDeps = deps+ , dynamicRuleCommand = ruleCmd+ , dynamicRuleInstances = instsPtr+ , dynamicRuleTypeRep = tr+ }+ _ -> error "internal error when decoding dynamic rule commands"++-- | A token constructor used to define 'Structured' instances on types+-- that involve existential quantification.+data family Tok (arg :: Symbol) :: k++instance+ ( forall res. Binary (ruleCmd System LBS.ByteString res)+ , Binary (deps System LBS.ByteString LBS.ByteString)+ )+ => Binary (RuleCommands System deps ruleCmd)+ where+ put = \case+ StaticRuleCommand{staticRuleCommand = ruleCmd, staticRuleArgRep = sTr} -> do+ put @Word 0+ put sTr+ put ruleCmd+ DynamicRuleCommands+ { dynamicDeps = deps+ , dynamicRuleCommand = ruleCmd+ , dynamicRuleInstances = instsKey+ , dynamicRuleTypeRep = sTr+ } ->+ do+ put @Word 1+ put sTr+ put instsKey+ put ruleCmd+ put deps+ get = do+ tag <- get @Word+ case tag of+ 0 -> do+ sTr <- get @Typeable.SomeTypeRep+ ruleCmd <- get+ return $+ StaticRuleCommand+ { staticRuleCommand = ruleCmd+ , staticRuleArgRep = sTr+ }+ _ -> do+ sTr <- get @Typeable.SomeTypeRep+ instsKey <- get+ ruleCmd <- get+ deps <- get+ return $+ DynamicRuleCommands+ { dynamicDeps = deps+ , dynamicRuleCommand = ruleCmd+ , dynamicRuleInstances = instsKey+ , dynamicRuleTypeRep = sTr+ }++--------------------------------------------------------------------------------+-- Showing rules++ruleBinary :: Rule -> RuleBinary+ruleBinary = Binary.decode . Binary.encode
src/Distribution/Simple/ShowBuildInfo.hs view
@@ -1,4 +1,6 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-} -- | -- This module defines a simple JSON-based format for exporting basic@@ -76,21 +78,20 @@ import Distribution.PackageDescription import Distribution.Pretty import Distribution.Simple.Compiler (Compiler, compilerFlavor, showCompilerId)+import Distribution.Simple.LocalBuildInfo import Distribution.Simple.Program import Distribution.Simple.Setup.Build (BuildFlags) import Distribution.Simple.Utils (cabalVersion) import Distribution.Text-import Distribution.Types.Component-import Distribution.Types.ComponentLocalBuildInfo-import Distribution.Types.LocalBuildInfo import Distribution.Types.TargetInfo import Distribution.Utils.Json+import Distribution.Utils.Path import Distribution.Verbosity -- | Construct a JSON document describing the build information for a -- package. mkBuildInfo- :: FilePath+ :: AbsolutePath (Dir Pkg) -- ^ The source directory of the package -> PackageDescription -- ^ Mostly information from the .cabal file@@ -138,7 +139,7 @@ , "path" .= JsonString (programPath compilerProgram) ] -mkComponentInfo :: FilePath -> PackageDescription -> LocalBuildInfo -> ComponentLocalBuildInfo -> ([String], Json)+mkComponentInfo :: AbsolutePath (Dir Pkg) -> PackageDescription -> LocalBuildInfo -> ComponentLocalBuildInfo -> ([String], Json) mkComponentInfo wdir pkg_descr lbi clbi = ( warnings , JsonObject $@@ -147,9 +148,9 @@ , "unit-id" .= JsonString (prettyShow $ componentUnitId clbi) , "compiler-args" .= JsonArray (map JsonString compilerArgs) , "modules" .= JsonArray (map (JsonString . display) modules)- , "src-files" .= JsonArray (map JsonString sourceFiles)+ , "src-files" .= JsonArray (map (JsonString . getSymbolicPath) sourceFiles) , "hs-src-dirs" .= JsonArray (map (JsonString . prettyShow) $ hsSourceDirs bi)- , "src-dir" .= JsonString (addTrailingPathSeparator wdir)+ , "src-dir" .= JsonString (addTrailingPathSeparator (getAbsolutePath wdir)) ] <> cabalFile )@@ -188,7 +189,7 @@ BenchmarkUnsupported _ -> [] CFLib _ -> [] cabalFile- | Just fp <- pkgDescrFile lbi = [("cabal-file", JsonString fp)]+ | Just fp <- pkgDescrFile lbi = [("cabal-file", JsonString $ getSymbolicPath fp)] | otherwise = [] -- | Get the command-line arguments that would be passed@@ -200,8 +201,8 @@ -> ([String], [String]) getCompilerArgs bi lbi clbi = case compilerFlavor $ compiler lbi of- GHC -> ([], ghc)- GHCJS -> ([], ghc)+ GHC -> ([], ghcArgs)+ GHCJS -> ([], ghcArgs) c -> ( [ "ShowBuildInfo.getCompilerArgs: Don't know how to get build "@@ -212,6 +213,8 @@ ) where -- This is absolutely awful- ghc = GHC.renderGhcOptions (compiler lbi) (hostPlatform lbi) baseOpts- where- baseOpts = GHC.componentGhcOptions normal lbi bi clbi (buildDir lbi)+ ghcArgs =+ GHC.renderGhcOptions (compiler lbi) (hostPlatform lbi) baseOpts+ baseOpts =+ GHC.componentGhcOptions normal lbi bi clbi $+ buildDir lbi
src/Distribution/Simple/SrcDist.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} @@ -47,17 +48,18 @@ import Prelude () import Distribution.ModuleName-import qualified Distribution.ModuleName as ModuleName import Distribution.Package import Distribution.PackageDescription import Distribution.PackageDescription.Check hiding (doesFileExist) import Distribution.Pretty import Distribution.Simple.BuildPaths import Distribution.Simple.Configure (findDistPrefOrDefault)+import Distribution.Simple.Errors import Distribution.Simple.Flag import Distribution.Simple.Glob (matchDirFileGlobWithDie) import Distribution.Simple.PreProcess import Distribution.Simple.Program+import Distribution.Simple.Setup.Common import Distribution.Simple.Setup.SDist import Distribution.Simple.Utils import Distribution.Utils.Path@@ -66,9 +68,7 @@ import qualified Data.Map as Map import Data.Time (UTCTime, getCurrentTime, toGregorian, utctDay)-import Distribution.Simple.Errors import System.Directory (doesFileExist)-import System.FilePath (dropExtension, isRelative, (<.>), (</>)) import System.IO (IOMode (WriteMode), hPutStrLn, withFile) -- | Create a source distribution.@@ -83,15 +83,15 @@ -- ^ extra preprocessors (includes suffixes) -> IO () sdist pkg flags mkTmpDir pps = do- distPref <- findDistPrefOrDefault $ sDistDistPref flags- let targetPref = distPref- tmpTargetDir = mkTmpDir distPref+ distPref <- findDistPrefOrDefault $ setupDistPref common+ let targetPref = i distPref+ tmpTargetDir = mkTmpDir (i distPref) -- When given --list-sources, just output the list of sources to a file. case sDistListSources flags of Flag path -> withFile path WriteMode $ \outHandle -> do- ordinary <- listPackageSources verbosity "." pkg pps- traverse_ (hPutStrLn outHandle) ordinary+ ordinary <- listPackageSources verbosity mbWorkDir pkg pps+ traverse_ (hPutStrLn outHandle . getSymbolicPath) ordinary notice verbosity $ "List of package sources written to file '" ++ path ++ "'" NoFlag -> do -- do some QA@@ -117,11 +117,14 @@ generateSourceDir :: FilePath -> PackageDescription -> IO () generateSourceDir targetDir pkg' = do setupMessage verbosity "Building source dist for" (packageId pkg')- prepareTree verbosity pkg' targetDir pps+ prepareTree verbosity mbWorkDir pkg' targetDir pps when snapshot $ overwriteSnapshotPackageDesc verbosity pkg' targetDir - verbosity = fromFlag (sDistVerbosity flags)+ common = sDistCommonFlags flags+ verbosity = fromFlag $ setupVerbosity common+ mbWorkDir = flagToMaybe $ setupWorkingDir common+ i = interpretSymbolicPath mbWorkDir -- See Note [Symbolic paths] in Distribution.Utils.Path snapshot = fromFlag (sDistSnapshot flags) -- | List all source files of a package.@@ -131,14 +134,13 @@ listPackageSources :: Verbosity -- ^ verbosity- -> FilePath+ -> Maybe (SymbolicPath CWD (Dir Pkg)) -- ^ directory with cabal file -> PackageDescription -- ^ info from the cabal file -> [PPSuffixHandler] -- ^ extra preprocessors (include suffixes)- -> IO [FilePath]- -- ^ relative paths+ -> IO [SymbolicPath Pkg File] listPackageSources verbosity cwd pkg_descr0 pps = do -- Call helpers that actually do all work. listPackageSources' verbosity dieWithException cwd pkg_descr pps@@ -153,19 +155,18 @@ listPackageSourcesWithDie :: Verbosity -- ^ verbosity- -> (Verbosity -> CabalException -> IO [FilePath])+ -> (forall res. Verbosity -> CabalException -> IO [res]) -- ^ 'die'' alternative. -- Since 'die'' prefixes the error message with 'errorPrefix', -- whatever is passed in here and wants to die should do the same. -- See issue #7331.- -> FilePath+ -> Maybe (SymbolicPath CWD (Dir Pkg)) -- ^ directory with cabal file -> PackageDescription -- ^ info from the cabal file -> [PPSuffixHandler] -- ^ extra preprocessors (include suffixes)- -> IO [FilePath]- -- ^ relative paths+ -> IO [SymbolicPath Pkg File] listPackageSourcesWithDie verbosity rip cwd pkg_descr0 pps = do -- Call helpers that actually do all work. listPackageSources' verbosity rip cwd pkg_descr pps@@ -175,20 +176,19 @@ listPackageSources' :: Verbosity -- ^ verbosity- -> (Verbosity -> CabalException -> IO [FilePath])+ -> (forall res. Verbosity -> CabalException -> IO [res]) -- ^ 'die'' alternative. -- Since 'die'' prefixes the error message with 'errorPrefix', -- whatever is passed in here and wants to die should do the same. -- See issue #7331.- -> FilePath+ -> Maybe (SymbolicPath CWD (Dir Pkg)) -- ^ directory with cabal file -> PackageDescription -- ^ info from the cabal file -> [PPSuffixHandler] -- ^ extra preprocessors (include suffixes)- -> IO [FilePath]- -- ^ relative paths-listPackageSources' verbosity rip cwd pkg_descr pps =+ -> IO [SymbolicPath Pkg File]+listPackageSources' verbosity rip mbWorkDir pkg_descr pps = fmap concat . sequenceA $ [ -- Library sources. fmap concat@@ -198,22 +198,22 @@ , signatures = sigs , libBuildInfo = libBi } ->- allSourcesBuildInfo verbosity rip cwd libBi pps (modules ++ sigs)+ allSourcesBuildInfo verbosity rip mbWorkDir libBi pps (modules ++ sigs) , -- Executables sources. fmap concat . withAllExe $ \Executable{modulePath = mainPath, buildInfo = exeBi} -> do- biSrcs <- allSourcesBuildInfo verbosity rip cwd exeBi pps []- mainSrc <- findMainExeFile verbosity cwd exeBi pps mainPath+ biSrcs <- allSourcesBuildInfo verbosity rip mbWorkDir exeBi pps []+ mainSrc <- findMainExeFile verbosity mbWorkDir exeBi pps mainPath return (mainSrc : biSrcs) , -- Foreign library sources fmap concat . withAllFLib $ \flib@(ForeignLib{foreignLibBuildInfo = flibBi}) -> do- biSrcs <- allSourcesBuildInfo verbosity rip cwd flibBi pps []+ biSrcs <- allSourcesBuildInfo verbosity rip mbWorkDir flibBi pps [] defFiles <- traverse- (findModDefFile verbosity cwd flibBi pps)+ (findModDefFile verbosity mbWorkDir flibBi pps) (foreignLibModDefFile flib) return (defFiles ++ biSrcs) , -- Test suites sources.@@ -223,11 +223,11 @@ let bi = testBuildInfo t case testInterface t of TestSuiteExeV10 _ mainPath -> do- biSrcs <- allSourcesBuildInfo verbosity rip cwd bi pps []- srcMainFile <- findMainExeFile verbosity cwd bi pps mainPath+ biSrcs <- allSourcesBuildInfo verbosity rip mbWorkDir bi pps []+ srcMainFile <- findMainExeFile verbosity mbWorkDir bi pps mainPath return (srcMainFile : biSrcs) TestSuiteLibV09 _ m ->- allSourcesBuildInfo verbosity rip cwd bi pps [m]+ allSourcesBuildInfo verbosity rip mbWorkDir bi pps [m] TestSuiteUnsupported tp -> rip verbosity $ UnsupportedTestSuite (show tp) , -- Benchmarks sources.@@ -237,8 +237,8 @@ let bi = benchmarkBuildInfo bm case benchmarkInterface bm of BenchmarkExeV10 _ mainPath -> do- biSrcs <- allSourcesBuildInfo verbosity rip cwd bi pps []- srcMainFile <- findMainExeFile verbosity cwd bi pps mainPath+ biSrcs <- allSourcesBuildInfo verbosity rip mbWorkDir bi pps []+ srcMainFile <- findMainExeFile verbosity mbWorkDir bi pps mainPath return (srcMainFile : biSrcs) BenchmarkUnsupported tp -> rip verbosity $ UnsupportedBenchMark (show tp)@@ -248,34 +248,45 @@ $ \filename -> do let srcDataDirRaw = dataDir pkg_descr- srcDataDir- | null srcDataDirRaw = "."- | otherwise = srcDataDirRaw- matchDirFileGlobWithDie verbosity rip (specVersion pkg_descr) cwd (srcDataDir </> filename)+ srcDataFile :: SymbolicPath Pkg File+ srcDataFile+ | null (getSymbolicPath srcDataDirRaw) = sameDirectory </> filename+ | otherwise = srcDataDirRaw </> filename+ fmap coerceSymbolicPath+ <$> matchDirFileGlobWithDie verbosity rip (specVersion pkg_descr) mbWorkDir srcDataFile , -- Extra source files. fmap concat . for (extraSrcFiles pkg_descr) $ \fpath ->- matchDirFileGlobWithDie verbosity rip (specVersion pkg_descr) cwd fpath+ fmap relativeSymbolicPath+ <$> matchDirFileGlobWithDie verbosity rip (specVersion pkg_descr) mbWorkDir fpath , -- Extra doc files. fmap concat . for (extraDocFiles pkg_descr) $ \filename ->- matchDirFileGlobWithDie verbosity rip (specVersion pkg_descr) cwd filename+ fmap (coerceSymbolicPath . relativeSymbolicPath)+ <$> matchDirFileGlobWithDie verbosity rip (specVersion pkg_descr) mbWorkDir filename+ , -- Extra files.+ fmap concat . for (extraFiles pkg_descr) $ \fpath ->+ fmap relativeSymbolicPath+ <$> matchDirFileGlobWithDie verbosity rip (specVersion pkg_descr) mbWorkDir fpath , -- License file(s).- return (map getSymbolicPath $ licenseFiles pkg_descr)+ return (map (relativeSymbolicPath . coerceSymbolicPath) $ licenseFiles pkg_descr) , -- Install-include files, without autogen-include files fmap concat . withAllLib $ \l -> do let lbi = libBuildInfo l- incls = filter (`notElem` autogenIncludes lbi) (installIncludes lbi)- relincdirs = "." : filter isRelative (includeDirs lbi)- traverse (fmap snd . findIncludeFile verbosity cwd relincdirs) incls+ incls = fmap getSymbolicPath $ filter (`notElem` autogenIncludes lbi) (installIncludes lbi)+ relincdirs = fmap getSymbolicPath $ sameDirectory : mapMaybe symbolicPathRelative_maybe (includeDirs lbi)+ traverse (fmap (makeSymbolicPath . snd) . findIncludeFile verbosity cwd relincdirs) incls , -- Setup script, if it exists.- fmap (maybe [] (\f -> [f])) $ findSetupFile cwd+ fmap (maybe [] (\f -> [makeSymbolicPath f])) $ findSetupFile cwd+ , -- SetupHooks script, if it exists.+ fmap (maybe [] (\f -> [makeSymbolicPath f])) $ findSetupHooksFile cwd , -- The .cabal file itself.- fmap (\d -> [d]) (tryFindPackageDescCwd verbosity cwd ".")+ fmap (\d -> [d]) (coerceSymbolicPath . relativeSymbolicPath <$> tryFindPackageDesc verbosity mbWorkDir) ] where+ cwd = maybe "." getSymbolicPath mbWorkDir -- We have to deal with all libs and executables, so we have local -- versions of these functions that ignore the 'buildable' attribute: withAllLib action = traverse action (allLibraries pkg_descr)@@ -288,6 +299,8 @@ prepareTree :: Verbosity -- ^ verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -- ^ working directory -> PackageDescription -- ^ info from the cabal file -> FilePath@@ -295,11 +308,12 @@ -> [PPSuffixHandler] -- ^ extra preprocessors (includes suffixes) -> IO ()-prepareTree verbosity pkg_descr0 targetDir pps = do- ordinary <- listPackageSources verbosity "." pkg_descr pps- installOrdinaryFiles verbosity targetDir (zip (repeat []) ordinary)+prepareTree verbosity mbWorkDir pkg_descr0 targetDir pps = do+ ordinary <- listPackageSources verbosity mbWorkDir pkg_descr pps+ installOrdinaryFiles verbosity targetDir (zip (repeat []) $ map i ordinary) maybeCreateDefaultSetupScript targetDir where+ i = interpretSymbolicPath mbWorkDir -- See Note [Symbolic paths] in Distribution.Utils.Path pkg_descr = filterAutogenModules pkg_descr0 -- | Find the setup script file, if it exists.@@ -317,6 +331,21 @@ setupHs = "Setup.hs" setupLhs = "Setup.lhs" +-- | Find the setup hooks script file, if it exists.+findSetupHooksFile :: FilePath -> IO (Maybe FilePath)+findSetupHooksFile targetDir = do+ hsExists <- doesFileExist (targetDir </> setupHs)+ lhsExists <- doesFileExist (targetDir </> setupLhs)+ if hsExists+ then return (Just setupHs)+ else+ if lhsExists+ then return (Just setupLhs)+ else return Nothing+ where+ setupHs = "SetupHooks.hs"+ setupLhs = "SetupHooks.lhs"+ -- | Create a default setup script in the target directory, if it doesn't exist. maybeCreateDefaultSetupScript :: FilePath -> IO () maybeCreateDefaultSetupScript targetDir = do@@ -333,31 +362,36 @@ -- | Find the main executable file. findMainExeFile :: Verbosity- -> FilePath- -- ^ cwd+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -- ^ working directory -> BuildInfo -> [PPSuffixHandler]- -> FilePath+ -> RelativePath Source File -- ^ main-is- -> IO FilePath+ -> IO (SymbolicPath Pkg File) findMainExeFile verbosity cwd exeBi pps mainPath = do ppFile <- findFileCwdWithExtension cwd (ppSuffixes pps)- (map getSymbolicPath (hsSourceDirs exeBi))- (dropExtension mainPath)+ (hsSourceDirs exeBi)+ (dropExtensionsSymbolicPath mainPath) case ppFile of- Nothing -> findFileCwd verbosity cwd (map getSymbolicPath (hsSourceDirs exeBi)) mainPath+ Nothing -> findFileCwd verbosity cwd (hsSourceDirs exeBi) mainPath Just pp -> return pp -- | Find a module definition file -- -- TODO: I don't know if this is right findModDefFile- :: Verbosity -> FilePath -> BuildInfo -> [PPSuffixHandler] -> FilePath -> IO FilePath+ :: Verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -> BuildInfo+ -> [PPSuffixHandler]+ -> RelativePath Source File+ -> IO (SymbolicPath Pkg File) findModDefFile verbosity cwd flibBi _pps modDefPath =- findFileCwd verbosity cwd ("." : map getSymbolicPath (hsSourceDirs flibBi)) modDefPath+ findFileCwd verbosity cwd (sameDirectory : hsSourceDirs flibBi) modDefPath -- | Given a list of include paths, try to find the include file named -- @f@. Return the name of the file and the full path, or exit with error if@@ -365,7 +399,7 @@ findIncludeFile :: Verbosity -> FilePath -> [FilePath] -> String -> IO (String, FilePath) findIncludeFile verbosity _ [] f = dieWithException verbosity $ NoIncludeFileFound f findIncludeFile verbosity cwd (d : ds) f = do- let path = (d </> f)+ let path = d </> f b <- doesFileExist (cwd </> path) if b then return (f, path) else findIncludeFile verbosity cwd ds f @@ -402,6 +436,8 @@ prepareSnapshotTree :: Verbosity -- ^ verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -- ^ working directory -> PackageDescription -- ^ info from the cabal file -> FilePath@@ -409,8 +445,8 @@ -> [PPSuffixHandler] -- ^ extra preprocessors (includes suffixes) -> IO ()-prepareSnapshotTree verbosity pkg targetDir pps = do- prepareTree verbosity pkg targetDir pps+prepareSnapshotTree verbosity mbWorkDir pkg targetDir pps = do+ prepareTree verbosity mbWorkDir pkg targetDir pps overwriteSnapshotPackageDesc verbosity pkg targetDir overwriteSnapshotPackageDesc@@ -424,7 +460,7 @@ overwriteSnapshotPackageDesc verbosity pkg targetDir = do -- We could just writePackageDescription targetDescFile pkg_descr, -- but that would lose comments and formatting.- descFile <- defaultPackageDesc verbosity+ descFile <- getSymbolicPath <$> defaultPackageDescCwd verbosity withUTF8FileContents descFile $ writeUTF8File (targetDir </> descFile) . unlines@@ -493,37 +529,37 @@ -- | Given a buildinfo, return the names of all source files. allSourcesBuildInfo :: Verbosity- -> (Verbosity -> CabalException -> IO [FilePath])+ -> (Verbosity -> CabalException -> IO [SymbolicPath Pkg File]) -- ^ 'die'' alternative. -- Since 'die'' prefixes the error message with 'errorPrefix', -- whatever is passed in here and wants to die should do the same. -- See issue #7331.- -> FilePath- -- ^ cwd -- change me to 'BuildPath Absolute PackageDir'+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -- ^ working directory -> BuildInfo -> [PPSuffixHandler] -- ^ Extra preprocessors -> [ModuleName] -- ^ Exposed modules- -> IO [FilePath]-allSourcesBuildInfo verbosity rip cwd bi pps modules = do- let searchDirs = map getSymbolicPath (hsSourceDirs bi)+ -> IO [SymbolicPath Pkg File]+allSourcesBuildInfo verbosity rip mbWorkDir bi pps modules = do+ let searchDirs = hsSourceDirs bi sources <- fmap concat $ sequenceA $- [ let file = ModuleName.toFilePath module_+ [ let file = moduleNameSymbolicPath module_ in -- NB: *Not* findFileWithExtension, because the same source -- file may show up in multiple paths due to a conditional; -- we need to package all of them. See #367.- findAllFilesCwdWithExtension cwd suffixes searchDirs file+ findAllFilesCwdWithExtension mbWorkDir suffixes searchDirs file >>= nonEmpty' (notFound module_) return | module_ <- modules ++ otherModules bi ] bootFiles <- sequenceA- [ let file = ModuleName.toFilePath module_+ [ let file = moduleNameSymbolicPath module_ fileExts = builtinHaskellBootSuffixes- in findFileCwdWithExtension cwd fileExts (map getSymbolicPath (hsSourceDirs bi)) file+ in findFileCwdWithExtension mbWorkDir fileExts (hsSourceDirs bi) file | module_ <- modules ++ otherModules bi ] @@ -542,7 +578,7 @@ suffixes = ppSuffixes pps ++ builtinHaskellSuffixes - notFound :: ModuleName -> IO [FilePath]+ notFound :: ModuleName -> IO [SymbolicPath Pkg File] notFound m = rip verbosity $ NoModuleFound m suffixes
src/Distribution/Simple/Test.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RankNTypes #-}@@ -25,8 +27,8 @@ import qualified Distribution.PackageDescription as PD import Distribution.Pretty+import Distribution.Simple.Build (addInternalBuildTools) import Distribution.Simple.Compiler-import Distribution.Simple.Flag (fromFlag) import Distribution.Simple.Hpc import Distribution.Simple.InstallDirs import qualified Distribution.Simple.LocalBuildInfo as LBI@@ -39,12 +41,12 @@ import Distribution.TestSuite import qualified Distribution.Types.LocalBuildInfo as LBI import Distribution.Types.UnqualComponentName+import Distribution.Utils.Path import Distribution.Simple.Configure (getInstalledPackagesById) import Distribution.Simple.Errors-import Distribution.Simple.Register-import Distribution.Simple.Setup (fromFlagOrDefault)-import Distribution.Simple.Setup.Common (extraCompilationArtifacts)+import Distribution.Simple.Register (internalPackageDBPath)+import Distribution.Simple.Setup.Common import Distribution.Simple.Setup.Config import Distribution.Types.ExposedModule import Distribution.Types.InstalledPackageInfo (InstalledPackageInfo (libraryDirs), exposedModules)@@ -55,7 +57,6 @@ , getDirectoryContents , removeFile )-import System.FilePath ((</>)) -- | Perform the \"@.\/setup test@\" action. test@@ -69,17 +70,19 @@ -- ^ flags sent to test -> IO () test args pkg_descr lbi0 flags = do- let verbosity = fromFlag $ testVerbosity flags+ let common = testCommonFlags flags+ verbosity = fromFlag $ setupVerbosity common+ distPref = fromFlag $ setupDistPref common+ i = LBI.interpretSymbolicPathLBI lbi -- See Note [Symbolic paths] in Distribution.Utils.Path machineTemplate = fromFlag $ testMachineLog flags- distPref = fromFlag $ testDistPref flags- testLogDir = distPref </> "test"+ testLogDir = distPref </> makeRelativePathEx "test" testNames = args pkgTests = PD.testSuites pkg_descr enabledTests = LBI.enabledTestLBIs pkg_descr lbi -- We must add the internalPkgDB to the package database stack to lookup -- the path to HPC dirs of libraries local to this package- internalPkgDB = internalPackageDBPath lbi distPref- lbi = lbi0{withPackageDB = withPackageDB lbi0 ++ [SpecificPackageDB internalPkgDB]}+ internalPkgDb = internalPackageDBPath lbi0 distPref+ lbi = lbi0{withPackageDB = withPackageDB lbi0 ++ [SpecificPackageDB internalPkgDb]} doTest :: HPCMarkupInfo@@ -87,12 +90,22 @@ , Maybe TestSuiteLog ) -> IO TestSuiteLog- doTest hpcMarkupInfo ((suite, clbi), _) =+ doTest hpcMarkupInfo ((suite, clbi), _) = do+ let lbiForTest =+ lbi+ { withPrograms =+ -- Include any build-tool-depends on build tools internal to the current package.+ addInternalBuildTools+ pkg_descr+ lbi+ (PD.testBuildInfo suite)+ (withPrograms lbi)+ } case PD.testInterface suite of PD.TestSuiteExeV10 _ _ ->- ExeV10.runTest pkg_descr lbi clbi hpcMarkupInfo flags suite+ ExeV10.runTest pkg_descr lbiForTest clbi hpcMarkupInfo flags suite PD.TestSuiteLibV09 _ _ ->- LibV09.runTest pkg_descr lbi clbi hpcMarkupInfo flags suite+ LibV09.runTest pkg_descr lbiForTest clbi hpcMarkupInfo flags suite _ -> return TestSuiteLog@@ -130,11 +143,11 @@ dieWithException verbosity $ TestNameDisabled tName | otherwise -> dieWithException verbosity $ NoSuchTest tName - createDirectoryIfMissing True testLogDir+ createDirectoryIfMissing True $ i testLogDir -- Delete ordinary files from test log directory.- getDirectoryContents testLogDir- >>= filterM doesFileExist . map (testLogDir </>)+ getDirectoryContents (i testLogDir)+ >>= filterM doesFileExist . map (i testLogDir </>) >>= traverse_ removeFile -- We configured the unit-ids of libraries we should cover in our coverage@@ -154,7 +167,7 @@ unzip $ map ( \ip ->- ( map (</> extraCompilationArtifacts) $ libraryDirs ip+ ( map ((</> coerceSymbolicPath extraCompilationArtifacts) . makeSymbolicPath) $ libraryDirs ip , map exposedName $ exposedModules ip ) )@@ -166,8 +179,8 @@ suites <- traverse (doTest hpcMarkupInfo) testsToRun let packageLog = (localPackageLog pkg_descr lbi){testSuites = suites} packageLogFile =- (</>) testLogDir $- packageLogPath machineTemplate pkg_descr lbi+ i testLogDir+ </> packageLogPath machineTemplate pkg_descr lbi allOk <- summarizePackage verbosity packageLog writeFile packageLogFile $ show packageLog
src/Distribution/Simple/Test/ExeV10.hs view
@@ -10,9 +10,9 @@ import Distribution.Compat.Environment import qualified Distribution.PackageDescription as PD-import Distribution.Simple.Build.PathsModule import Distribution.Simple.BuildPaths import Distribution.Simple.Compiler+import Distribution.Simple.Errors import Distribution.Simple.Flag import Distribution.Simple.Hpc import Distribution.Simple.InstallDirs@@ -21,6 +21,10 @@ , buildDir , depLibraryPaths )+import Distribution.Simple.Program.Db+import Distribution.Simple.Program.Find+import Distribution.Simple.Program.Run+import Distribution.Simple.Setup.Common import Distribution.Simple.Setup.Test import Distribution.Simple.Test.Log import Distribution.Simple.Utils@@ -34,20 +38,19 @@ import Distribution.Types.UnqualComponentName import Distribution.Verbosity +import Distribution.Utils.Path++import qualified Data.ByteString.Lazy as LBS+import Distribution.Simple.LocalBuildInfo (interpretSymbolicPathLBI, packageRoot) import System.Directory ( createDirectoryIfMissing , doesDirectoryExist , doesFileExist- , getCurrentDirectory , removeDirectoryRecursive )-import System.FilePath ((<.>), (</>)) import System.IO (stderr, stdout) import System.Process (createPipe) -import qualified Data.ByteString.Lazy as LBS-import Distribution.Simple.Errors- runTest :: PD.PackageDescription -> LBI.LocalBuildInfo@@ -59,13 +62,12 @@ runTest pkg_descr lbi clbi hpcMarkupInfo flags suite = do let isCoverageEnabled = LBI.testCoverage lbi way = guessWay lbi- tixDir_ = tixDir distPref way+ tixDir_ = i $ tixDir distPref way - pwd <- getCurrentDirectory existingEnv <- getEnvironment let cmd =- LBI.buildDir lbi+ i (LBI.buildDir lbi) </> testName' </> testName' <.> exeExtension (LBI.hostPlatform lbi) -- Check that the test executable exists.@@ -85,17 +87,18 @@ -- Write summary notices indicating start of test suite notice verbosity $ summarizeSuiteStart $ testName' - -- Run the test executable+ -- Run the test executable (with the appropriate environment set)+ let progDb = LBI.withPrograms lbi+ pathVar = progSearchPath progDb+ envOverrides = progOverrideEnv progDb+ newPath <- programSearchPathAsPATHVar pathVar+ overrideEnv <- fromMaybe [] <$> getEffectiveEnvironment ([("PATH", Just newPath)] ++ envOverrides) let opts = map (testOption pkg_descr lbi suite) (testOptions flags)- dataDirPath = pwd </> PD.dataDir pkg_descr- tixFile = pwd </> tixFilePath distPref way (testName')- pkgPathEnv =- (pkgPathEnvVar pkg_descr "datadir", dataDirPath)- : existingEnv- shellEnv = [("HPCTIXFILE", tixFile) | isCoverageEnabled] ++ pkgPathEnv+ tixFile = packageRoot (testCommonFlags flags) </> getSymbolicPath (tixFilePath distPref way (testName'))+ shellEnv = [("HPCTIXFILE", tixFile) | isCoverageEnabled] ++ overrideEnv ++ existingEnv -- Add (DY)LD_LIBRARY_PATH if needed shellEnv' <-@@ -191,12 +194,15 @@ return suiteLog where+ i = interpretSymbolicPathLBI lbi -- See Note [Symbolic paths] in Distribution.Utils.Path+ commonFlags = testCommonFlags flags+ testName' = unUnqualComponentName $ PD.testName suite - distPref = fromFlag $ testDistPref flags- verbosity = fromFlag $ testVerbosity flags+ distPref = fromFlag $ setupDistPref commonFlags+ verbosity = fromFlag $ setupVerbosity commonFlags details = fromFlag $ testShowDetails flags- testLogDir = distPref </> "test"+ testLogDir = distPref </> makeRelativePathEx "test" buildLog exit = let r = case exit of@@ -213,7 +219,7 @@ { testSuiteName = PD.testName suite , testLogs = l , logFile =- testLogDir+ i testLogDir </> testSuiteLogPath (fromFlag $ testHumanLog flags) pkg_descr
src/Distribution/Simple/Test/LibV09.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} @@ -18,28 +19,31 @@ import Distribution.Compat.Environment import Distribution.Compat.Internal.TempFile+import Distribution.Compat.Process (proc) import Distribution.ModuleName import qualified Distribution.PackageDescription as PD import Distribution.Pretty-import Distribution.Simple.Build.PathsModule import Distribution.Simple.BuildPaths import Distribution.Simple.Compiler-import Distribution.Simple.Flag (Flag (Flag, NoFlag), fromFlag)+import Distribution.Simple.Errors import Distribution.Simple.Hpc import Distribution.Simple.InstallDirs import qualified Distribution.Simple.LocalBuildInfo as LBI+import Distribution.Simple.Program.Db+import Distribution.Simple.Program.Find+import Distribution.Simple.Program.Run+import Distribution.Simple.Setup.Common import Distribution.Simple.Setup.Test import Distribution.Simple.Test.Log import Distribution.Simple.Utils import Distribution.System import Distribution.TestSuite import qualified Distribution.Types.LocalBuildInfo as LBI+import Distribution.Utils.Path import Distribution.Verbosity import qualified Control.Exception as CE import qualified Data.ByteString.Lazy as LBS-import Distribution.Compat.Process (proc)-import Distribution.Simple.Errors import System.Directory ( canonicalizePath , createDirectoryIfMissing@@ -50,7 +54,6 @@ , removeFile , setCurrentDirectory )-import System.FilePath ((<.>), (</>)) import System.IO (hClose, hPutStr) import qualified System.Process as Process @@ -66,13 +69,14 @@ let isCoverageEnabled = LBI.testCoverage lbi way = guessWay lbi - pwd <- getCurrentDirectory+ let mbWorkDir = LBI.mbWorkDirLBI lbi existingEnv <- getEnvironment let cmd =- LBI.buildDir lbi+ interpretSymbolicPath mbWorkDir (LBI.buildDir lbi) </> stubName suite </> stubName suite <.> exeExtension (LBI.hostPlatform lbi)+ tDir = i $ tixDir distPref way -- Check that the test executable exists. exists <- doesFileExist cmd unless exists $@@ -81,34 +85,37 @@ -- Remove old .tix files if appropriate. unless (fromFlag $ testKeepTix flags) $ do- let tDir = tixDir distPref way exists' <- doesDirectoryExist tDir when exists' $ removeDirectoryRecursive tDir -- Create directory for HPC files.- createDirectoryIfMissing True $ tixDir distPref way+ createDirectoryIfMissing True tDir -- Write summary notices indicating start of test suite notice verbosity $ summarizeSuiteStart testName' suiteLog <- CE.bracket openCabalTemp deleteIfExists $ \tempLog -> do+ -- Compute the appropriate environment for running the test suite+ let progDb = LBI.withPrograms lbi+ pathVar = progSearchPath progDb+ envOverrides = progOverrideEnv progDb+ newPath <- programSearchPathAsPATHVar pathVar+ overrideEnv <- fromMaybe [] <$> getEffectiveEnvironment ([("PATH", Just newPath)] ++ envOverrides)+ -- Run test executable let opts = map (testOption pkg_descr lbi suite) $ testOptions flags- dataDirPath = pwd </> PD.dataDir pkg_descr- tixFile = pwd </> tixFilePath distPref way testName'- pkgPathEnv =- (pkgPathEnvVar pkg_descr "datadir", dataDirPath)- : existingEnv+ tixFile = i $ tixFilePath distPref way testName' shellEnv = [("HPCTIXFILE", tixFile) | isCoverageEnabled]- ++ pkgPathEnv+ ++ overrideEnv+ ++ existingEnv -- Add (DY)LD_LIBRARY_PATH if needed shellEnv' <- if LBI.withDynExe lbi then do let (Platform _ os) = LBI.hostPlatform lbi paths <- LBI.depLibraryPaths True False lbi clbi- cpath <- canonicalizePath $ LBI.componentBuildDir lbi clbi+ cpath <- canonicalizePath $ i $ LBI.componentBuildDir lbi clbi return (addLibraryPath os (cpath : paths) shellEnv) else return shellEnv let (cmd', opts') = case testWrapper flags of@@ -143,7 +150,7 @@ -- Generate final log file name let finalLogName l =- testLogDir+ interpretSymbolicPath mbWorkDir testLogDir </> testSuiteLogPath (fromFlag $ testHumanLog flags) pkg_descr@@ -199,19 +206,21 @@ return suiteLog where+ i = LBI.interpretSymbolicPathLBI lbi+ common = testCommonFlags flags testName' = unUnqualComponentName $ PD.testName suite deleteIfExists file = do exists <- doesFileExist file when exists $ removeFile file - testLogDir = distPref </> "test"+ testLogDir = distPref </> makeRelativePathEx "test" openCabalTemp = do- (f, h) <- openTempFile testLogDir $ "cabal-test-" <.> "log"+ (f, h) <- openTempFile (i testLogDir) $ "cabal-test-" <.> "log" hClose h >> return f - distPref = fromFlag $ testDistPref flags- verbosity = fromFlag $ testVerbosity flags+ distPref = fromFlag $ setupDistPref common+ verbosity = fromFlag $ setupVerbosity common -- TODO: This is abusing the notion of a 'PathTemplate'. The result isn't -- necessarily a path.@@ -233,10 +242,6 @@ ++ [(TestSuiteNameVar, toPathTemplate $ unUnqualComponentName $ PD.testName suite)] -- Test stub -------------- | The name of the stub executable associated with a library 'TestSuite'.-stubName :: PD.TestSuite -> FilePath-stubName t = unUnqualComponentName (PD.testName t) ++ "Stub" -- | The filename of the source file for the stub executable associated with a -- library 'TestSuite'.
src/Distribution/Simple/UHC.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} @@ -50,7 +51,7 @@ import qualified Data.Map as Map (empty) import System.Directory-import System.FilePath+import System.FilePath (pathSeparator) -- ----------------------------------------------------------------------------- -- Configuring@@ -112,14 +113,15 @@ getInstalledPackages :: Verbosity -> Compiler- -> PackageDBStack+ -> Maybe (SymbolicPath CWD (Dir from))+ -> PackageDBStackX (SymbolicPath from (Dir PkgDB)) -> ProgramDb -> IO InstalledPackageIndex-getInstalledPackages verbosity comp packagedbs progdb = do+getInstalledPackages verbosity comp mbWorkDir packagedbs progdb = do let compilerid = compilerId comp systemPkgDir <- getGlobalPackageDir verbosity progdb userPkgDir <- getUserPackageDir- let pkgDirs = nub (concatMap (packageDbPaths userPkgDir systemPkgDir) packagedbs)+ let pkgDirs = nub (concatMap (packageDbPaths userPkgDir systemPkgDir mbWorkDir) packagedbs) -- putStrLn $ "pkgdirs: " ++ show pkgDirs pkgs <- liftM (map addBuiltinVersions . concat) $@@ -153,12 +155,17 @@ homeDir <- getHomeDirectory return $ homeDir </> ".cabal" </> "lib" -- TODO: determine in some other way -packageDbPaths :: FilePath -> FilePath -> PackageDB -> [FilePath]-packageDbPaths user system db =+packageDbPaths+ :: FilePath+ -> FilePath+ -> Maybe (SymbolicPath CWD (Dir from))+ -> PackageDBX (SymbolicPath from (Dir PkgDB))+ -> [FilePath]+packageDbPaths user system mbWorkDir db = case db of GlobalPackageDB -> [system] UserPackageDB -> [user]- SpecificPackageDB path -> [path]+ SpecificPackageDB path -> [interpretSymbolicPath mbWorkDir path] -- | Hack to add version numbers to UHC-built-in packages. This should sooner or -- later be fixed on the UHC side.@@ -208,7 +215,7 @@ buildLib verbosity pkg_descr lbi lib clbi = do systemPkgDir <- getGlobalPackageDir verbosity (withPrograms lbi) userPkgDir <- getUserPackageDir- let runUhcProg = runDbProgram verbosity uhcProgram (withPrograms lbi)+ let runUhcProg = runDbProgramCwd verbosity (mbWorkDirLBI lbi) uhcProgram (withPrograms lbi) let uhcArgs = -- set package name ["--pkg-build=" ++ prettyShow (packageId pkg_descr)]@@ -242,8 +249,11 @@ buildExe verbosity _pkg_descr lbi exe clbi = do systemPkgDir <- getGlobalPackageDir verbosity (withPrograms lbi) userPkgDir <- getUserPackageDir- let runUhcProg = runDbProgram verbosity uhcProgram (withPrograms lbi)- let uhcArgs =+ let mbWorkDir = mbWorkDirLBI lbi+ srcMainPath <- findFileCwd verbosity mbWorkDir (hsSourceDirs $ buildInfo exe) (modulePath exe)+ let runUhcProg = runDbProgramCwd verbosity (mbWorkDirLBI lbi) uhcProgram (withPrograms lbi)+ u = interpretSymbolicPathCWD+ uhcArgs = -- common flags lib/exe constructUHCCmdLine userPkgDir@@ -254,9 +264,9 @@ (buildDir lbi) verbosity -- output file- ++ ["--output", buildDir lbi </> prettyShow (exeName exe)]+ ++ ["--output", u $ buildDir lbi </> makeRelativePathEx (prettyShow (exeName exe))] -- main source module- ++ [modulePath exe]+ ++ [u $ srcMainPath] runUhcProg uhcArgs constructUHCCmdLine@@ -265,7 +275,7 @@ -> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo- -> FilePath+ -> SymbolicPath Pkg (Dir Build) -> Verbosity -> [String] constructUHCCmdLine user system lbi bi clbi odir verbosity =@@ -287,26 +297,28 @@ ++ ["--package=uhcbase"] ++ ["--package=" ++ prettyShow (mungedName pkgid) | (_, pkgid) <- componentPackageDeps clbi] -- search paths- ++ ["-i" ++ odir]- ++ ["-i" ++ getSymbolicPath l | l <- nub (hsSourceDirs bi)]- ++ ["-i" ++ autogenComponentModulesDir lbi clbi]- ++ ["-i" ++ autogenPackageModulesDir lbi]+ ++ ["-i" ++ u odir]+ ++ ["-i" ++ u l | l <- nub (hsSourceDirs bi)]+ ++ ["-i" ++ u (autogenComponentModulesDir lbi clbi)]+ ++ ["-i" ++ u (autogenPackageModulesDir lbi)] -- cpp options ++ ["--optP=" ++ opt | opt <- cppOptions bi] -- output path- ++ ["--odir=" ++ odir]+ ++ ["--odir=" ++ u odir] -- optimization ++ ( case withOptimization lbi of NoOptimisation -> ["-O0"] NormalOptimisation -> ["-O1"] MaximumOptimisation -> ["-O2"] )+ where+ u = interpretSymbolicPathCWD -- See Note [Symbolic paths] in Distribution.Utils.Path uhcPackageDbOptions :: FilePath -> FilePath -> PackageDBStack -> [String] uhcPackageDbOptions user system db = map (\x -> "--pkg-searchpath=" ++ x)- (concatMap (packageDbPaths user system) db)+ (concatMap (packageDbPaths user system Nothing) db) -- ----------------------------------------------------------------------------- -- Installation@@ -342,16 +354,17 @@ registerPackage :: Verbosity+ -> Maybe (SymbolicPath CWD (Dir from)) -> Compiler -> ProgramDb- -> PackageDBStack+ -> PackageDBStackS from -> InstalledPackageInfo -> IO ()-registerPackage verbosity comp progdb packageDbs installedPkgInfo = do+registerPackage verbosity mbWorkDir comp progdb packageDbs installedPkgInfo = do dbdir <- case registrationPackageDB packageDbs of GlobalPackageDB -> getGlobalPackageDir verbosity progdb UserPackageDB -> getUserPackageDir- SpecificPackageDB dir -> return dir+ SpecificPackageDB dir -> return (interpretSymbolicPath mbWorkDir dir) let pkgdir = dbdir </> uhcPackageDir (prettyShow pkgid) (prettyShow compilerid) createDirectoryIfMissingVerbose verbosity True pkgdir writeUTF8File@@ -361,5 +374,5 @@ pkgid = sourcePackageId installedPkgInfo compilerid = compilerId comp -inplacePackageDbPath :: LocalBuildInfo -> FilePath-inplacePackageDbPath lbi = buildDir lbi+inplacePackageDbPath :: LocalBuildInfo -> SymbolicPath Pkg (Dir PkgDB)+inplacePackageDbPath lbi = coerceSymbolicPath $ buildDir lbi
src/Distribution/Simple/UserHooks.hs view
@@ -32,7 +32,7 @@ , emptyUserHooks ) where -import Distribution.Compat.Prelude+import Distribution.Compat.Prelude hiding (getContents, putStr) import Prelude () import Distribution.PackageDescription
src/Distribution/Simple/Utils.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-}@@ -61,6 +62,7 @@ , rawSystemProc , rawSystemProcAction , rawSystemExitWithEnv+ , rawSystemExitWithEnvCwd , rawSystemStdout , rawSystemStdInOut , rawSystemIOWithEnv@@ -86,6 +88,7 @@ , copyFileVerbose , copyFiles , copyFileTo+ , copyFileToCwd -- * installing files , installOrdinaryFile@@ -103,7 +106,6 @@ , setFileExecutable -- * file names- , currentDir , shortRelativePath , dropExeExtension , exeExtensions@@ -112,13 +114,17 @@ , findFileEx , findFileCwd , findFirstFile+ , Suffix (..) , findFileWithExtension , findFileCwdWithExtension , findFileWithExtension'+ , findFileCwdWithExtension' , findAllFilesWithExtension , findAllFilesCwdWithExtension , findModuleFileEx+ , findModuleFileCwd , findModuleFilesEx+ , findModuleFilesCwd , getDirectoryContentsRecursive -- * environment variables@@ -133,17 +139,18 @@ , TempFileOptions (..) , defaultTempFileOptions , withTempFile+ , withTempFileCwd , withTempFileEx , withTempDirectory+ , withTempDirectoryCwd , withTempDirectoryEx+ , withTempDirectoryCwdEx , createTempDirectory -- * .cabal and .buildinfo files- , defaultPackageDesc+ , defaultPackageDescCwd , findPackageDesc- , findPackageDescCwd , tryFindPackageDesc- , tryFindPackageDescCwd , findHookedPackageDesc -- * reading and writing files safely@@ -207,6 +214,7 @@ import Distribution.Utils.Generic import Distribution.Utils.IOData (IOData (..), IODataMode (..), KnownIODataMode (..)) import qualified Distribution.Utils.IOData as IOData+import Distribution.Utils.Path import Distribution.Verbosity import Distribution.Version import Prelude ()@@ -248,6 +256,7 @@ import System.Environment ( getProgName )+import System.FilePath (takeFileName) import System.FilePath as FilePath ( getSearchPath , joinPath@@ -256,8 +265,6 @@ , splitDirectories , splitExtension , takeDirectory- , (<.>)- , (</>) ) import System.IO ( BufferMode (..)@@ -853,19 +860,28 @@ -- | Execute the given command with the given arguments, exiting -- with the same exit code if the command fails.-rawSystemExit :: Verbosity -> FilePath -> [String] -> IO ()-rawSystemExit verbosity path args =+rawSystemExit :: Verbosity -> Maybe (SymbolicPath CWD (Dir Pkg)) -> FilePath -> [String] -> IO ()+rawSystemExit verbosity mbWorkDir path args = withFrozenCallStack $ maybeExit $- rawSystemExitCode verbosity path args+ rawSystemExitCode verbosity mbWorkDir path args Nothing -- | Execute the given command with the given arguments, returning -- the command's exit code.-rawSystemExitCode :: Verbosity -> FilePath -> [String] -> IO ExitCode-rawSystemExitCode verbosity path args =+rawSystemExitCode+ :: Verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -> FilePath+ -> [String]+ -> Maybe [(String, String)]+ -> IO ExitCode+rawSystemExitCode verbosity mbWorkDir path args menv = withFrozenCallStack $ rawSystemProc verbosity $- proc path args+ (proc path args)+ { Process.cwd = fmap getSymbolicPath mbWorkDir+ , Process.env = menv+ } -- | Execute the given command with the given arguments, returning -- the command's exit code.@@ -918,12 +934,24 @@ -> [String] -> [(String, String)] -> IO ()-rawSystemExitWithEnv verbosity path args env =+rawSystemExitWithEnv verbosity =+ rawSystemExitWithEnvCwd verbosity Nothing++-- | Like 'rawSystemExitWithEnv', but setting a working directory.+rawSystemExitWithEnvCwd+ :: Verbosity+ -> Maybe (SymbolicPath CWD to)+ -> FilePath+ -> [String]+ -> [(String, String)]+ -> IO ()+rawSystemExitWithEnvCwd verbosity mbWorkDir path args env = withFrozenCallStack $ maybeExit $ rawSystemProc verbosity $ (proc path args) { Process.env = Just env+ , Process.cwd = getSymbolicPath <$> mbWorkDir } -- | Execute the given command with the given arguments, returning@@ -1187,83 +1215,75 @@ -- -- @since 3.4.0.0 findFileCwd- :: Verbosity- -> FilePath- -- ^ cwd- -> [FilePath]- -- ^ relative search location- -> FilePath+ :: forall searchDir allowAbsolute+ . Verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -- ^ working directory+ -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)]+ -- ^ search directories+ -> RelativePath searchDir File -- ^ File Name- -> IO FilePath-findFileCwd verbosity cwd searchPath fileName =+ -> IO (SymbolicPathX allowAbsolute Pkg File)+findFileCwd verbosity mbWorkDir searchPath fileName = findFirstFile- (cwd </>)+ (interpretSymbolicPath mbWorkDir) [ path </> fileName | path <- ordNub searchPath ]- >>= maybe (dieWithException verbosity $ FindFileCwd fileName) return+ >>= maybe (dieWithException verbosity $ FindFile $ getSymbolicPath fileName) return -- | Find a file by looking in a search path. The file path must match exactly. findFileEx- :: Verbosity- -> [FilePath]- -- ^ search locations- -> FilePath+ :: forall searchDir allowAbsolute+ . Verbosity+ -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)]+ -- ^ search directories+ -> RelativePath searchDir File -- ^ File Name- -> IO FilePath-findFileEx verbosity searchPath fileName =- findFirstFile- id- [ path </> fileName- | path <- ordNub searchPath- ]- >>= maybe (dieWithException verbosity $ FindFileEx fileName) return+ -> IO (SymbolicPathX allowAbsolute Pkg File)+findFileEx v = findFileCwd v Nothing -- | Find a file by looking in a search path with one of a list of possible -- file extensions. The file base name should be given and it will be tried -- with each of the extensions in each element of the search path. findFileWithExtension :: [Suffix]- -> [FilePath]- -> FilePath- -> IO (Maybe FilePath)-findFileWithExtension extensions searchPath baseName =- findFirstFile- id- [ path </> baseName <.> ext- | path <- ordNub searchPath- , Suffix ext <- ordNub extensions- ]+ -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)]+ -> RelativePath searchDir File+ -> IO (Maybe (SymbolicPathX allowAbsolute Pkg File))+findFileWithExtension =+ findFileCwdWithExtension Nothing --- | @since 3.4.0.0+-- | Find a file by looking in a search path with one of a list of possible+-- file extensions.+--+-- @since 3.4.0.0 findFileCwdWithExtension- :: FilePath+ :: forall searchDir allowAbsolute+ . Maybe (SymbolicPath CWD (Dir Pkg)) -> [Suffix]- -> [FilePath]- -> FilePath- -> IO (Maybe FilePath)+ -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)]+ -> RelativePath searchDir File+ -> IO (Maybe (SymbolicPathX allowAbsolute Pkg File)) findFileCwdWithExtension cwd extensions searchPath baseName =- findFirstFile- (cwd </>)- [ path </> baseName <.> ext- | path <- ordNub searchPath- , Suffix ext <- ordNub extensions- ]+ fmap (uncurry (</>))+ <$> findFileCwdWithExtension' cwd extensions searchPath baseName -- | @since 3.4.0.0 findAllFilesCwdWithExtension- :: FilePath- -- ^ cwd+ :: forall searchDir allowAbsolute+ . Maybe (SymbolicPath CWD (Dir Pkg))+ -- ^ working directory -> [Suffix] -- ^ extensions- -> [FilePath]+ -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)] -- ^ relative search locations- -> FilePath+ -> RelativePath searchDir File -- ^ basename- -> IO [FilePath]-findAllFilesCwdWithExtension cwd extensions searchPath basename =+ -> IO [SymbolicPathX allowAbsolute Pkg File]+findAllFilesCwdWithExtension mbWorkDir extensions searchPath basename = findAllFiles- (cwd </>)+ (interpretSymbolicPath mbWorkDir) [ path </> basename <.> ext | path <- ordNub searchPath , Suffix ext <- ordNub extensions@@ -1271,31 +1291,42 @@ findAllFilesWithExtension :: [Suffix]- -> [FilePath]- -> FilePath- -> IO [FilePath]-findAllFilesWithExtension extensions searchPath basename =- findAllFiles- id- [ path </> basename <.> ext- | path <- ordNub searchPath- , Suffix ext <- ordNub extensions- ]+ -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)]+ -> RelativePath searchDir File+ -> IO [SymbolicPathX allowAbsolute Pkg File]+findAllFilesWithExtension =+ findAllFilesCwdWithExtension Nothing -- | Like 'findFileWithExtension' but returns which element of the search path -- the file was found in, and the file path relative to that base directory. findFileWithExtension' :: [Suffix]- -> [FilePath]- -> FilePath- -> IO (Maybe (FilePath, FilePath))-findFileWithExtension' extensions searchPath baseName =+ -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)]+ -> RelativePath searchDir File+ -> IO (Maybe (SymbolicPathX allowAbsolute Pkg (Dir searchDir), RelativePath searchDir File))+findFileWithExtension' =+ findFileCwdWithExtension' Nothing++-- | Like 'findFileCwdWithExtension' but returns which element of the search path+-- the file was found in, and the file path relative to that base directory.+findFileCwdWithExtension'+ :: forall searchDir allowAbsolute+ . Maybe (SymbolicPath CWD (Dir Pkg))+ -> [Suffix]+ -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)]+ -> RelativePath searchDir File+ -> IO (Maybe (SymbolicPathX allowAbsolute Pkg (Dir searchDir), RelativePath searchDir File))+findFileCwdWithExtension' cwd extensions searchPath baseName = findFirstFile- (uncurry (</>))+ (uncurry mkPath) [ (path, baseName <.> ext) | path <- ordNub searchPath , Suffix ext <- ordNub extensions ]+ where+ mkPath :: SymbolicPathX allowAbsolute Pkg (Dir searchDir) -> RelativePath searchDir File -> FilePath+ mkPath base file =+ interpretSymbolicPath cwd (base </> file) findFirstFile :: (a -> FilePath) -> [a] -> IO (Maybe a) findFirstFile file = findFirst@@ -1314,39 +1345,79 @@ -- -- As 'findModuleFile' but for a list of module names. findModuleFilesEx- :: Verbosity- -> [FilePath]+ :: forall searchDir allowAbsolute+ . Verbosity+ -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)] -- ^ build prefix (location of objects) -> [Suffix] -- ^ search suffixes -> [ModuleName] -- ^ modules- -> IO [(FilePath, FilePath)]+ -> IO [(SymbolicPathX allowAbsolute Pkg (Dir searchDir), RelativePath searchDir File)] findModuleFilesEx verbosity searchPath extensions moduleNames = traverse (findModuleFileEx verbosity searchPath extensions) moduleNames +-- | Finds the files corresponding to a list of Haskell module names.+--+-- As 'findModuleFileCwd' but for a list of module names.+findModuleFilesCwd+ :: forall searchDir allowAbsolute+ . Verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)]+ -- ^ build prefix (location of objects)+ -> [Suffix]+ -- ^ search suffixes+ -> [ModuleName]+ -- ^ modules+ -> IO [(SymbolicPathX allowAbsolute Pkg (Dir searchDir), RelativePath searchDir File)]+findModuleFilesCwd verbosity cwd searchPath extensions moduleNames =+ traverse (findModuleFileCwd verbosity cwd searchPath extensions) moduleNames+ -- | Find the file corresponding to a Haskell module name. -- -- This is similar to 'findFileWithExtension'' but specialised to a module -- name. The function fails if the file corresponding to the module is missing. findModuleFileEx- :: Verbosity- -> [FilePath]+ :: forall searchDir allowAbsolute+ . Verbosity+ -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)] -- ^ build prefix (location of objects) -> [Suffix] -- ^ search suffixes -> ModuleName -- ^ module- -> IO (FilePath, FilePath)-findModuleFileEx verbosity searchPath extensions mod_name =- maybe notFound return- =<< findFileWithExtension'+ -> IO (SymbolicPathX allowAbsolute Pkg (Dir searchDir), RelativePath searchDir File)+findModuleFileEx verbosity =+ findModuleFileCwd verbosity Nothing++-- | Find the file corresponding to a Haskell module name.+--+-- This is similar to 'findFileCwdWithExtension'' but specialised to a module+-- name. The function fails if the file corresponding to the module is missing.+findModuleFileCwd+ :: forall searchDir allowAbsolute+ . Verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -> [SymbolicPathX allowAbsolute Pkg (Dir searchDir)]+ -- ^ build prefix (location of objects)+ -> [Suffix]+ -- ^ search suffixes+ -> ModuleName+ -- ^ module+ -> IO (SymbolicPathX allowAbsolute Pkg (Dir searchDir), RelativePath searchDir File)+findModuleFileCwd verbosity cwd searchPath extensions mod_name = do+ mbRes <-+ findFileCwdWithExtension'+ cwd extensions searchPath- (ModuleName.toFilePath mod_name)- where- notFound =- dieWithException verbosity $ FindModuleFileEx mod_name extensions searchPath+ (makeRelativePathEx $ ModuleName.toFilePath mod_name)+ case mbRes of+ Nothing ->+ dieWithException verbosity $+ FindModuleFileEx mod_name extensions (map getSymbolicPath searchPath)+ Just res -> return res -- | List all the files in a directory and all subdirectories. --@@ -1520,11 +1591,34 @@ -- | Given a relative path to a file, copy it to the given directory, preserving -- the relative path and creating the parent directories if needed.-copyFileTo :: Verbosity -> FilePath -> FilePath -> IO ()-copyFileTo verbosity dir file = withFrozenCallStack $ do- let targetFile = dir </> file+copyFileTo+ :: Verbosity+ -> FilePath+ -> FilePath+ -> IO ()+copyFileTo verbosity dir file =+ withFrozenCallStack $+ copyFileToCwd+ verbosity+ Nothing+ (makeSymbolicPath dir)+ (makeRelativePathEx file)++-- | Given a relative path to a file, copy it to the given directory, preserving+-- the relative path and creating the parent directories if needed.+copyFileToCwd+ :: Verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -> SymbolicPath Pkg (Dir target)+ -> RelativePath Pkg File+ -> IO ()+copyFileToCwd verbosity mbWorkDir dir file = withFrozenCallStack $ do+ let targetFile = i $ dir </> unsafeCoerceSymbolicPath file createDirectoryIfMissingVerbose verbosity True (takeDirectory targetFile)- installOrdinaryFile verbosity file targetFile+ installOrdinaryFile verbosity (i file) targetFile+ where+ i :: SymbolicPathX allowAbs Pkg to -> FilePath+ i = interpretSymbolicPath mbWorkDir -- | Common implementation of 'copyFiles', 'installOrdinaryFiles', -- 'installExecutableFiles' and 'installMaybeExecutableFiles'.@@ -1637,7 +1731,7 @@ defaultTempFileOptions :: TempFileOptions defaultTempFileOptions = TempFileOptions{optKeepTempFiles = False} --- | Use a temporary filename that doesn't already exist.+-- | Use a temporary filename that doesn't already exist withTempFile :: FilePath -- ^ Temp dir to create the file in@@ -1645,30 +1739,59 @@ -- ^ File name template. See 'openTempFile'. -> (FilePath -> Handle -> IO a) -> IO a-withTempFile tmpDir template action =- withTempFileEx defaultTempFileOptions tmpDir template action+withTempFile tmpDir template f = withFrozenCallStack $+ withTempFileCwd Nothing (makeSymbolicPath tmpDir) template $+ \fp h -> f (getSymbolicPath fp) h +-- | Use a temporary filename that doesn't already exist.+withTempFileCwd+ :: Maybe (SymbolicPath CWD (Dir Pkg))+ -- ^ Working directory+ -> SymbolicPath Pkg (Dir tmpDir)+ -- ^ Temp dir to create the file in+ -> String+ -- ^ File name template. See 'openTempFile'.+ -> (SymbolicPath Pkg File -> Handle -> IO a)+ -> IO a+withTempFileCwd = withFrozenCallStack $ withTempFileEx defaultTempFileOptions+ -- | A version of 'withTempFile' that additionally takes a 'TempFileOptions' -- argument. withTempFileEx- :: TempFileOptions- -> FilePath+ :: forall a tmpDir+ . TempFileOptions+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -- ^ Working directory+ -> SymbolicPath Pkg (Dir tmpDir) -- ^ Temp dir to create the file in -> String -- ^ File name template. See 'openTempFile'.- -> (FilePath -> Handle -> IO a)+ -> (SymbolicPath Pkg File -> Handle -> IO a) -> IO a-withTempFileEx opts tmpDir template action =- Exception.bracket- (openTempFile tmpDir template)- ( \(name, handle) -> do- hClose handle- unless (optKeepTempFiles opts) $- handleDoesNotExist () . removeFile $- name- )- (withLexicalCallStack (\x -> uncurry action x))+withTempFileEx opts mbWorkDir tmpDir template action =+ withFrozenCallStack $+ Exception.bracket+ (openTempFile (i tmpDir) template)+ ( \(name, handle) -> do+ hClose handle+ unless (optKeepTempFiles opts) $+ handleDoesNotExist () $+ removeFile $+ name+ )+ (withLexicalCallStack (\(fn, h) -> action (mkRelToPkg fn) h))+ where+ i = interpretSymbolicPath mbWorkDir -- See Note [Symbolic paths] in Distribution.Utils.Path+ mkRelToPkg :: FilePath -> SymbolicPath Pkg File+ mkRelToPkg fp =+ tmpDir </> makeRelativePathEx (takeFileName fp) +-- 'openTempFile' returns a path of the form @i tmpDir </> fn@, but we+-- want 'withTempFileEx' to return @tmpDir </> fn@. So we split off+-- the filename and add back the (un-interpreted) directory.+-- This assumes 'openTempFile' returns a filepath of the form+-- @inputDir </> fn@, where @fn@ does not contain any path separators.+ -- | Create and use a temporary directory. -- -- Creates a new temporary directory inside the given directory, making use@@ -1678,12 +1801,44 @@ -- -- The @tmpDir@ will be a new subdirectory of the given directory, e.g. -- @src/sdist.342@.-withTempDirectory :: Verbosity -> FilePath -> String -> (FilePath -> IO a) -> IO a-withTempDirectory verbosity targetDir template f =+withTempDirectory+ :: Verbosity+ -> FilePath+ -> String+ -> (FilePath -> IO a)+ -> IO a+withTempDirectory verb targetDir template f = withFrozenCallStack $- withTempDirectoryEx+ withTempDirectoryCwd+ verb+ Nothing+ (makeSymbolicPath targetDir)+ template+ (f . getSymbolicPath)++-- | Create and use a temporary directory.+--+-- Creates a new temporary directory inside the given directory, making use+-- of the template. The temp directory is deleted after use. For example:+--+-- > withTempDirectory verbosity "src" "sdist." $ \tmpDir -> do ...+--+-- The @tmpDir@ will be a new subdirectory of the given directory, e.g.+-- @src/sdist.342@.+withTempDirectoryCwd+ :: Verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -- ^ Working directory+ -> SymbolicPath Pkg (Dir tmpDir1)+ -> String+ -> (SymbolicPath Pkg (Dir tmpDir2) -> IO a)+ -> IO a+withTempDirectoryCwd verbosity mbWorkDir targetDir template f =+ withFrozenCallStack $+ withTempDirectoryCwdEx verbosity defaultTempFileOptions+ mbWorkDir targetDir template (withLexicalCallStack (\x -> f x))@@ -1697,15 +1852,35 @@ -> String -> (FilePath -> IO a) -> IO a-withTempDirectoryEx _verbosity opts targetDir template f =+withTempDirectoryEx verbosity opts targetDir template f = withFrozenCallStack $+ withTempDirectoryCwdEx verbosity opts Nothing (makeSymbolicPath targetDir) template $+ \fp -> f (getSymbolicPath fp)++-- | A version of 'withTempDirectoryCwd' that additionally takes a+-- 'TempFileOptions' argument.+withTempDirectoryCwdEx+ :: forall a tmpDir1 tmpDir2+ . Verbosity+ -> TempFileOptions+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -- ^ Working directory+ -> SymbolicPath Pkg (Dir tmpDir1)+ -> String+ -> (SymbolicPath Pkg (Dir tmpDir2) -> IO a)+ -> IO a+withTempDirectoryCwdEx _verbosity opts mbWorkDir targetDir template f =+ withFrozenCallStack $ Exception.bracket- (createTempDirectory targetDir template)- ( unless (optKeepTempFiles opts)- . handleDoesNotExist ()- . removeDirectoryRecursive+ (createTempDirectory (i targetDir) template)+ ( \tmpDirRelPath ->+ unless (optKeepTempFiles opts) $+ handleDoesNotExist () $+ removeDirectoryRecursive (i targetDir </> tmpDirRelPath) )- (withLexicalCallStack (\x -> f x))+ (withLexicalCallStack (\tmpDirRelPath -> f $ targetDir </> makeRelativePathEx tmpDirRelPath))+ where+ i = interpretSymbolicPath mbWorkDir -- See Note [Symbolic paths] in Distribution.Utils.Path ----------------------------------- -- Safely reading and writing files@@ -1737,12 +1912,6 @@ | otherwise = ioError e --- | The path name that represents the current directory.--- In Unix, it's @\".\"@, but this is system-specific.--- (E.g. AmigaOS uses the empty string @\"\"@ for the current directory.)-currentDir :: FilePath-currentDir = "."- shortRelativePath :: FilePath -> FilePath -> FilePath shortRelativePath from to = case dropCommonPrefix (splitDirectories from) (splitDirectories to) of@@ -1781,6 +1950,13 @@ -- Possible improvement: on Windows, read the list of extensions from the -- PATHEXT environment variable. By default PATHEXT is ".com; .exe; .bat; -- .cmd".+ --+ -- See also #10179.+ --+ -- Also we cannot actually run @.bat@ files as we do now, because of+ -- https://github.com/haskell/process/issues/140. If we detect one of those,+ -- we should record that the program is a script and run a @Process.shell@ instead+ -- of a @Process.proc@. (_, Windows) -> ["", "exe"] (_, Ghcjs) -> ["", "exe"] (Wasm32, _) -> ["", "wasm"]@@ -1792,71 +1968,61 @@ -- ------------------------------------------------------------ --- | Package description file (/pkgname/@.cabal@)-defaultPackageDesc :: Verbosity -> IO FilePath-defaultPackageDesc verbosity = tryFindPackageDesc verbosity currentDir+-- | Package description file (/pkgname/@.cabal@) in the current+-- working directory.+defaultPackageDescCwd :: Verbosity -> IO (RelativePath Pkg File)+defaultPackageDescCwd verbosity = tryFindPackageDesc verbosity Nothing -- | Find a package description file in the given directory. Looks for -- @.cabal@ files. findPackageDesc- :: FilePath- -- ^ Where to look- -> IO (Either CabalException FilePath)- -- ^ <pkgname>.cabal-findPackageDesc = findPackageDescCwd "."---- | @since 3.4.0.0-findPackageDescCwd- :: FilePath- -- ^ project root- -> FilePath- -- ^ relative directory- -> IO (Either CabalException FilePath)- -- ^ <pkgname>.cabal relative to the project root-findPackageDescCwd cwd dir =+ :: Maybe (SymbolicPath CWD (Dir Pkg))+ -- ^ package directory+ -> IO (Either CabalException (RelativePath Pkg File))+findPackageDesc mbPkgDir = do- files <- getDirectoryContents (cwd </> dir)+ let pkgDir = maybe "." getSymbolicPath mbPkgDir+ files <- getDirectoryContents pkgDir -- to make sure we do not mistake a ~/.cabal/ dir for a <pkgname>.cabal -- file we filter to exclude dirs and null base file names: cabalFiles <- filterM- (doesFileExist . snd)- [ (dir </> file, cwd </> dir </> file)+ (doesFileExist . uncurry (</>))+ [ (pkgDir, file) | file <- files , let (name, ext) = splitExtension file , not (null name) && ext == ".cabal" ]- case map fst cabalFiles of+ case map snd cabalFiles of [] -> return (Left NoDesc)- [cabalFile] -> return (Right cabalFile)+ [cabalFile] -> return (Right $ makeRelativePathEx cabalFile) multiple -> return (Left $ MultiDesc multiple) -- | Like 'findPackageDesc', but calls 'die' in case of error.-tryFindPackageDesc :: Verbosity -> FilePath -> IO FilePath+tryFindPackageDesc+ :: Verbosity+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -- ^ directory in which to look+ -> IO (RelativePath Pkg File) tryFindPackageDesc verbosity dir = either (dieWithException verbosity) return =<< findPackageDesc dir --- | Like 'findPackageDescCwd', but calls 'die' in case of error.------ @since 3.4.0.0-tryFindPackageDescCwd :: Verbosity -> FilePath -> FilePath -> IO FilePath-tryFindPackageDescCwd verbosity cwd dir =- either (dieWithException verbosity) return =<< findPackageDescCwd cwd dir- -- | Find auxiliary package information in the given directory. -- Looks for @.buildinfo@ files. findHookedPackageDesc :: Verbosity- -> FilePath+ -> Maybe (SymbolicPath CWD (Dir Pkg))+ -- ^ Working directory+ -> SymbolicPath Pkg (Dir Build) -- ^ Directory to search- -> IO (Maybe FilePath)+ -> IO (Maybe (SymbolicPath Pkg File)) -- ^ /dir/@\/@/pkgname/@.buildinfo@, if present-findHookedPackageDesc verbosity dir = do- files <- getDirectoryContents dir+findHookedPackageDesc verbosity mbWorkDir dir = do+ files <- getDirectoryContents $ interpretSymbolicPath mbWorkDir dir buildInfoFiles <- filterM- doesFileExist- [ dir </> file+ (doesFileExist . interpretSymbolicPath mbWorkDir)+ [ dir </> makeRelativePathEx file | file <- files , let (name, ext) = splitExtension file , not (null name) && ext == buildInfoExt
src/Distribution/Types/GivenComponent.hs view
@@ -3,12 +3,14 @@ module Distribution.Types.GivenComponent ( GivenComponent (..)+ , PromisedComponent (..) ) where import Distribution.Compat.Prelude import Distribution.Types.ComponentId import Distribution.Types.LibraryName+import Distribution.Types.PackageId import Distribution.Types.PackageName -- | A 'GivenComponent' represents a library depended on and explicitly@@ -27,3 +29,20 @@ instance Binary GivenComponent instance Structured GivenComponent++-- | A 'PromisedComponent' represents a promised library depended on and explicitly+-- specified by the user/client with @--promised-dependency@+--+-- It enables Cabal to know which 'ComponentId' to associate with a library+--+-- @since 3.14.0.0+data PromisedComponent = PromisedComponent+ { promisedComponentPackage :: PackageId+ , promisedComponentName :: LibraryName -- --dependency is for libraries+ -- only, not for any component+ , promisedComponentId :: ComponentId+ }+ deriving (Generic, Read, Show, Eq, Typeable)++instance Binary PromisedComponent+instance Structured PromisedComponent
src/Distribution/Types/LocalBuildConfig.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE FlexibleContexts #-}@@ -21,9 +22,9 @@ import Distribution.Compat.Prelude import Prelude () -import Distribution.Types.ComponentId import Distribution.Types.ComponentLocalBuildInfo import Distribution.Types.ComponentRequestedSpec+import Distribution.Types.GivenComponent import Distribution.Types.PackageDescription import Distribution.Types.UnitId @@ -36,9 +37,10 @@ , substPathTemplate ) import Distribution.Simple.PackageIndex-import Distribution.Simple.Program+import Distribution.Simple.Program.Db (ProgramDb) import Distribution.Simple.Setup.Config import Distribution.System+import Distribution.Utils.Path import Distribution.Compat.Graph (Graph) @@ -57,7 +59,7 @@ -- ^ The compiler we're building with , hostPlatform :: Platform -- ^ The platform we're building for- , pkgDescrFile :: Maybe FilePath+ , pkgDescrFile :: Maybe (SymbolicPath Pkg File) -- ^ the filename containing the .cabal file, if available , localPkgDescr :: PackageDescription -- ^ WARNING WARNING WARNING Be VERY careful about using@@ -99,7 +101,7 @@ -- ^ A map from component name to all matching -- components. These coincide with 'componentGraph' -- There may be more than one matching component because of backpack instantiations- , promisedPkgs :: Map (PackageName, ComponentName) ComponentId+ , promisedPkgs :: Map (PackageName, ComponentName) PromisedComponent -- ^ The packages we were promised, but aren't already installed. -- MP: Perhaps this just needs to be a Set UnitId at this stage. , installedPkgs :: InstalledPackageIndex@@ -149,6 +151,8 @@ { withVanillaLib :: Bool -- ^ Whether to build normal libs. , withProfLib :: Bool+ -- ^ Whether to build normal libs.+ , withProfLibShared :: Bool -- ^ Whether to build profiling versions of libs. , withSharedLib :: Bool -- ^ Whether to build shared versions of libs.@@ -209,6 +213,7 @@ , configGHCiLib = toFlag $ withGHCiLib , configProfExe = toFlag $ withProfExe , configProfLib = toFlag $ withProfLib+ , configProfShared = toFlag $ withProfLibShared , configProf = mempty , -- configProfDetail is for exe+lib, but overridden by configProfLibDetail -- so we specify both so we can specify independently
src/Distribution/Types/LocalBuildInfo.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DuplicateRecordFields #-}@@ -27,11 +28,12 @@ , withPackageDB , withVanillaLib , withProfLib- , withSharedLib- , withStaticLib+ , withProfLibShared , withDynExe , withFullyStaticExe , withProfExe+ , withSharedLib+ , withStaticLib , withProfLibDetail , withProfExeDetail , withOptimization@@ -55,8 +57,9 @@ , localPackage , buildDir , buildDirPBD- , configFlagsBuildDir- , cabalFilePath+ , setupFlagsBuildDir+ , distPrefLBI+ , packageRoot , progPrefix , progSuffix @@ -80,6 +83,7 @@ , neededTargetsInBuildOrder' , withNeededTargetsInBuildOrder' , testCoverage+ , buildWays -- * Functions you SHOULD NOT USE (yet), but are defined here to @@ -99,14 +103,18 @@ import Distribution.Types.ComponentId import Distribution.Types.ComponentLocalBuildInfo import Distribution.Types.ComponentRequestedSpec+import Distribution.Types.GivenComponent import qualified Distribution.Types.LocalBuildConfig as LBC import Distribution.Types.PackageDescription import Distribution.Types.PackageId import Distribution.Types.TargetInfo import Distribution.Types.UnitId +import Distribution.Utils.Path+ import Distribution.PackageDescription import Distribution.Pretty+import Distribution.Simple.BuildWay import Distribution.Simple.Compiler import Distribution.Simple.Flag import Distribution.Simple.InstallDirs hiding@@ -116,14 +124,16 @@ ) import Distribution.Simple.PackageIndex import Distribution.Simple.Program+import Distribution.Simple.Setup.Common import Distribution.Simple.Setup.Config import Distribution.System import qualified Data.Map as Map import Distribution.Compat.Graph (Graph) import qualified Distribution.Compat.Graph as Graph-import System.FilePath ((</>)) +import qualified System.FilePath as FilePath (takeDirectory)+ -- | Data cached after configuration step. See also -- 'Distribution.Simple.Setup.ConfigFlags'. data LocalBuildInfo = NewLocalBuildInfo@@ -148,10 +158,10 @@ -> InstallDirTemplates -> Compiler -> Platform- -> Maybe FilePath+ -> Maybe (SymbolicPath Pkg File) -> Graph ComponentLocalBuildInfo -> Map ComponentName [ComponentLocalBuildInfo]- -> Map (PackageName, ComponentName) ComponentId+ -> Map (PackageName, ComponentName) PromisedComponent -> InstalledPackageIndex -> PackageDescription -> ProgramDb@@ -163,6 +173,7 @@ -> Bool -> Bool -> Bool+ -> Bool -> ProfDetailLevel -> ProfDetailLevel -> OptimisationLevel@@ -195,6 +206,7 @@ , withPackageDB , withVanillaLib , withProfLib+ , withProfLibShared , withSharedLib , withStaticLib , withDynExe@@ -246,6 +258,7 @@ LBC.BuildOptions { withVanillaLib , withProfLib+ , withProfLibShared , withSharedLib , withStaticLib , withDynExe@@ -273,21 +286,32 @@ ------------------------------------------------------------------------------- -- Accessor functions -buildDir :: LocalBuildInfo -> FilePath+buildDir :: LocalBuildInfo -> SymbolicPath Pkg (Dir Build) buildDir lbi = buildDirPBD $ LBC.packageBuildDescr $ localBuildDescr lbi -buildDirPBD :: LBC.PackageBuildDescr -> FilePath+buildDirPBD :: LBC.PackageBuildDescr -> SymbolicPath Pkg (Dir Build) buildDirPBD (LBC.PackageBuildDescr{configFlags = cfg}) =- configFlagsBuildDir cfg+ setupFlagsBuildDir $ configCommonFlags cfg -configFlagsBuildDir :: ConfigFlags -> FilePath-configFlagsBuildDir cfg = fromFlag (configDistPref cfg) </> "build"+setupFlagsBuildDir :: CommonSetupFlags -> SymbolicPath Pkg (Dir Build)+setupFlagsBuildDir cfg = fromFlag (setupDistPref cfg) </> makeRelativePathEx "build" -cabalFilePath :: LocalBuildInfo -> Maybe FilePath-cabalFilePath (LocalBuildInfo{configFlags = cfg}) =- flagToMaybe (configCabalFilePath cfg)+distPrefLBI :: LocalBuildInfo -> SymbolicPath Pkg (Dir Dist)+distPrefLBI = fromFlag . setupDistPref . configCommonFlags . LBC.configFlags . LBC.packageBuildDescr . localBuildDescr +-- | The (relative or absolute) path to the package root, based on+--+-- - the working directory flag+-- - the @.cabal@ path+packageRoot :: CommonSetupFlags -> FilePath+packageRoot cfg =+ case flagToMaybe (setupCabalFilePath cfg) of+ Just cabalPath -> FilePath.takeDirectory $ interpretSymbolicPath mbWorkDir cabalPath+ Nothing -> maybe "." getSymbolicPath mbWorkDir+ where+ mbWorkDir = flagToMaybe $ setupWorkingDir cfg+ progPrefix, progSuffix :: LocalBuildInfo -> PathTemplate progPrefix (LocalBuildInfo{configFlags = cfg}) = fromFlag $ configProgPrefix cfg@@ -411,6 +435,49 @@ testCoverage :: LocalBuildInfo -> Bool testCoverage (LocalBuildInfo{exeCoverage = exes, libCoverage = libs}) = exes && libs++-- | Returns a list of ways, in the order which they should be built, and the+-- way we build executable and foreign library components.+--+-- Ideally all this info should be fixed at configure time and not dependent on+-- additional info but `LocalBuildInfo` is per package (not per component) so it's+-- currently not possible to configure components to be built in certain ways.+buildWays :: LocalBuildInfo -> (Bool -> [BuildWay], Bool -> BuildWay, BuildWay)+buildWays lbi =+ let+ -- enable-library-profiling (enable (static profiling way)) .p_o+ -- enable-shared (enabled dynamic way) .dyn_o+ -- enable-profiling-shared (enable dyanmic profilng way) .p_dyn_o+ -- enable-library-vanilla (enable vanilla way) .o+ --+ -- enable-executable-dynamic => build dynamic executables+ -- => --enable-profiling + --enable-executable-dynamic => build dynamic profiled executables+ -- => --enable-profiling => build vanilla profiled executables++ wantedLibWays is_indef =+ [ProfDynWay | withProfLibShared lbi && not is_indef]+ <> [ProfWay | withProfLib lbi]+ -- I don't see why we shouldn't build with dynamic-- indefinite components.+ <> [DynWay | withSharedLib lbi && not is_indef]+ -- MP: Ideally we should have `BuildOptions` on a per component basis, in+ -- which case this `is_indef` check could be moved to configure time.+ <> [StaticWay | withVanillaLib lbi || withStaticLib lbi]++ wantedFLibWay is_dyn_flib =+ case (is_dyn_flib, withProfExe lbi) of+ (True, True) -> ProfDynWay+ (False, True) -> ProfWay+ (True, False) -> DynWay+ (False, False) -> StaticWay++ wantedExeWay =+ case (withDynExe lbi, withProfExe lbi) of+ (True, True) -> ProfDynWay+ (True, False) -> DynWay+ (False, True) -> ProfWay+ (False, False) -> StaticWay+ in+ (wantedLibWays, wantedFLibWay, wantedExeWay) ------------------------------------------------------------------------------- -- Stub functions to prevent someone from accidentally defining them