module Distribution.Simple (
module Distribution.Package,
module Distribution.Version,
module Distribution.License,
module Distribution.Simple.Compiler,
module Language.Haskell.Extension,
defaultMain, defaultMainNoRead, defaultMainArgs,
UserHooks(..), Args,
defaultMainWithHooks, defaultMainWithHooksArgs,
simpleUserHooks, defaultUserHooks, emptyUserHooks,
defaultHookedPackageDesc
#ifdef DEBUG
,simpleHunitTests
#endif
) where
import Distribution.Simple.Compiler
import Distribution.Package
import Distribution.PackageDescription
import Distribution.Simple.Program(Program(..), ProgramConfiguration,
defaultProgramConfiguration, addKnownProgram,
pfesetupProgram, rawSystemProgramConf)
import Distribution.Simple.PreProcess (knownSuffixHandlers,
removePreprocessedPackage,
preprocessSources, PPSuffixHandler)
import Distribution.Simple.Setup
import Distribution.Simple.Build ( build, makefile )
import Distribution.Simple.SrcDist ( sdist )
import Distribution.Simple.Register ( register, unregister,
writeInstalledConfig,
removeRegScripts
)
import Distribution.Simple.Configure(getPersistBuildConfig,
maybeGetPersistBuildConfig,
checkPersistBuildConfig,
configure, writePersistBuildConfig)
import Distribution.Simple.LocalBuildInfo ( LocalBuildInfo(..), distPref, srcPref)
import Distribution.Simple.Install (install)
import Distribution.Simple.Haddock (haddock, hscolour)
import Distribution.Simple.Utils (die, currentDir, moduleToFilePath,
defaultPackageDesc, defaultHookedPackageDesc)
import Distribution.Simple.Utils (rawSystemPathExit, notice, info)
import Distribution.Verbosity
import Language.Haskell.Extension
import System.Environment(getArgs)
import System.Directory(removeFile, doesFileExist, doesDirectoryExist)
import Distribution.License
import Control.Monad (when, unless)
import Data.List (intersperse, unionBy)
import System.IO.Error (try)
import Distribution.GetOpt
import Distribution.Compat.Directory(removeDirectoryRecursive)
import System.FilePath((</>))
#ifdef DEBUG
import Test.HUnit (Test)
import Distribution.Version hiding (hunitTests)
#else
import Distribution.Version
#endif
type Args = [String]
data UserHooks = UserHooks
{
runTests :: Args -> Bool -> PackageDescription -> LocalBuildInfo -> IO (),
readDesc :: IO (Maybe PackageDescription),
hookedPreProcessors :: [ PPSuffixHandler ],
hookedPrograms :: [Program],
preConf :: Args -> ConfigFlags -> IO HookedBuildInfo,
confHook :: ( Either GenericPackageDescription PackageDescription
, HookedBuildInfo)
-> ConfigFlags -> IO LocalBuildInfo,
postConf :: Args -> ConfigFlags -> PackageDescription -> LocalBuildInfo -> IO (),
preBuild :: Args -> BuildFlags -> IO HookedBuildInfo,
buildHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> BuildFlags -> IO (),
postBuild :: Args -> BuildFlags -> PackageDescription -> LocalBuildInfo -> IO (),
preMakefile :: Args -> MakefileFlags -> IO HookedBuildInfo,
makefileHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> MakefileFlags -> IO (),
postMakefile :: Args -> MakefileFlags -> PackageDescription -> LocalBuildInfo -> IO (),
preClean :: Args -> CleanFlags -> IO HookedBuildInfo,
cleanHook :: PackageDescription -> Maybe LocalBuildInfo -> UserHooks -> CleanFlags -> IO (),
postClean :: Args -> CleanFlags -> PackageDescription -> Maybe LocalBuildInfo -> IO (),
preCopy :: Args -> CopyFlags -> IO HookedBuildInfo,
copyHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> CopyFlags -> IO (),
postCopy :: Args -> CopyFlags -> PackageDescription -> LocalBuildInfo -> IO (),
preInst :: Args -> InstallFlags -> IO HookedBuildInfo,
instHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> InstallFlags -> IO (),
postInst :: Args -> InstallFlags -> PackageDescription -> LocalBuildInfo -> IO (),
preSDist :: Args -> SDistFlags -> IO HookedBuildInfo,
sDistHook :: PackageDescription -> Maybe LocalBuildInfo -> UserHooks -> SDistFlags -> IO (),
postSDist :: Args -> SDistFlags -> PackageDescription -> Maybe LocalBuildInfo -> IO (),
preReg :: Args -> RegisterFlags -> IO HookedBuildInfo,
regHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> RegisterFlags -> IO (),
postReg :: Args -> RegisterFlags -> PackageDescription -> LocalBuildInfo -> IO (),
preUnreg :: Args -> RegisterFlags -> IO HookedBuildInfo,
unregHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> RegisterFlags -> IO (),
postUnreg :: Args -> RegisterFlags -> PackageDescription -> LocalBuildInfo -> IO (),
preHscolour :: Args -> HscolourFlags -> IO HookedBuildInfo,
hscolourHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> HscolourFlags -> IO (),
postHscolour :: Args -> HscolourFlags -> PackageDescription -> LocalBuildInfo -> IO (),
preHaddock :: Args -> HaddockFlags -> IO HookedBuildInfo,
haddockHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> HaddockFlags -> IO (),
postHaddock :: Args -> HaddockFlags -> PackageDescription -> LocalBuildInfo -> IO (),
prePFE :: Args -> PFEFlags -> IO HookedBuildInfo,
pfeHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> PFEFlags -> IO (),
postPFE :: Args -> PFEFlags -> PackageDescription -> LocalBuildInfo -> IO ()
}
defaultMain :: IO ()
defaultMain = defaultMain__ Nothing Nothing Nothing
defaultMainArgs :: [String] -> IO ()
defaultMainArgs args = defaultMain__ (Just args) Nothing Nothing
defaultMainWithHooks :: UserHooks -> IO ()
defaultMainWithHooks hooks = defaultMain__ Nothing (Just hooks) Nothing
defaultMainWithHooksArgs :: UserHooks -> [String] -> IO ()
defaultMainWithHooksArgs hooks args
= defaultMain__ (Just args) (Just hooks) Nothing
defaultMainNoRead :: PackageDescription -> IO ()
defaultMainNoRead pkg_descr = defaultMain__ Nothing Nothing (Just pkg_descr)
defaultMain__ :: Maybe [String]
-> Maybe UserHooks
-> Maybe PackageDescription
-> IO ()
defaultMain__ margs mhooks mdescr = do
args <- maybe getArgs return margs
let hooks = maybe simpleUserHooks id mhooks
let prog_conf = allPrograms hooks
(action, args') <- parseGlobalArgs prog_conf args
defaultMainWorker mdescr action args' hooks prog_conf
allPrograms :: UserHooks
-> ProgramConfiguration
allPrograms h = foldl (flip addKnownProgram)
defaultProgramConfiguration
(hookedPrograms h)
allSuffixHandlers :: UserHooks
-> [PPSuffixHandler]
allSuffixHandlers hooks
= overridesPP (hookedPreProcessors hooks) knownSuffixHandlers
where
overridesPP :: [PPSuffixHandler] -> [PPSuffixHandler] -> [PPSuffixHandler]
overridesPP = unionBy (\x y -> fst x == fst y)
defaultMainWorker :: (Maybe PackageDescription)
-> Action
-> [String]
-> UserHooks
-> ProgramConfiguration
-> IO ()
defaultMainWorker mdescr action all_args hooks prog_conf
= do case action of
ConfigCmd flags -> do
(flags', optFns, args) <-
parseConfigureArgs prog_conf flags all_args [scratchDirOpt]
pbi <- preConf hooks args flags'
(mb_pd_file, pkg_descr0) <- confPkgDescr flags'
let epkg_descr = (pkg_descr0, pbi)
localbuildinfo0 <- confHook hooks epkg_descr flags'
let localbuildinfo = localbuildinfo0{ pkgDescrFile = mb_pd_file }
writePersistBuildConfig (foldr id localbuildinfo optFns)
let pkg_descr = localPkgDescr localbuildinfo
postConf hooks args flags' pkg_descr localbuildinfo
where
confPkgDescr :: ConfigFlags
-> IO (Maybe FilePath,
Either GenericPackageDescription
PackageDescription)
confPkgDescr cfgflags =
case mdescr of
Just ppd -> return (Nothing, Right ppd)
Nothing -> do
mdescr' <- readDesc hooks
case mdescr' of
Just descr -> return (Nothing, Right descr)
Nothing -> do
pdfile <- defaultPackageDesc (configVerbose cfgflags)
ppd <- readPackageDescription (configVerbose cfgflags) pdfile
return (Just pdfile, Left ppd)
BuildCmd -> do
lbi <- getBuildConfigIfUpToDate
res@(flags, _, _) <-
parseBuildArgs prog_conf
(emptyBuildFlags (withPrograms lbi)) all_args []
command (\_ _ -> return res) buildVerbose
preBuild buildHook postBuild
(return lbi { withPrograms = buildPrograms flags })
MakefileCmd ->
command (parseMakefileArgs emptyMakefileFlags) makefileVerbose
preMakefile makefileHook postMakefile
getBuildConfigIfUpToDate
HscolourCmd ->
command (parseHscolourArgs emptyHscolourFlags) hscolourVerbose
preHscolour hscolourHook postHscolour
getBuildConfigIfUpToDate
HaddockCmd ->
command (parseHaddockArgs emptyHaddockFlags) haddockVerbose
preHaddock haddockHook postHaddock
getBuildConfigIfUpToDate
ProgramaticaCmd -> do
command parseProgramaticaArgs pfeVerbose
prePFE pfeHook postPFE
getBuildConfigIfUpToDate
CleanCmd -> do
(flags, _, args) <- parseCleanArgs emptyCleanFlags all_args []
pbi <- preClean hooks args flags
mlbi <- maybeGetPersistBuildConfig
pdfile <- defaultPackageDesc (cleanVerbose flags)
ppd <- readPackageDescription (cleanVerbose flags) pdfile
let pkg_descr0 = flattenPackageDescription ppd
let pkg_descr = updatePackageDescription pbi pkg_descr0
cleanHook hooks pkg_descr mlbi hooks flags
postClean hooks args flags pkg_descr mlbi
CopyCmd mprefix -> do
command (parseCopyArgs (emptyCopyFlags mprefix)) copyVerbose
preCopy copyHook postCopy
getBuildConfigIfUpToDate
InstallCmd -> do
command (parseInstallArgs emptyInstallFlags) installVerbose
preInst instHook postInst
getBuildConfigIfUpToDate
SDistCmd -> do
(flags, _, args) <- parseSDistArgs all_args []
pbi <- preSDist hooks args flags
mlbi <- maybeGetPersistBuildConfig
pdfile <- defaultPackageDesc (sDistVerbose flags)
ppd <- readPackageDescription (sDistVerbose flags) pdfile
let pkg_descr0 = flattenPackageDescription ppd
let pkg_descr = updatePackageDescription pbi pkg_descr0
sDistHook hooks pkg_descr mlbi hooks flags
postSDist hooks args flags pkg_descr mlbi
TestCmd -> do
(_verbosity,_, args) <- parseTestArgs all_args []
localbuildinfo <- getBuildConfigIfUpToDate
let pkg_descr = localPkgDescr localbuildinfo
runTests hooks args False pkg_descr localbuildinfo
RegisterCmd -> do
command (parseRegisterArgs emptyRegisterFlags) regVerbose
preReg regHook postReg
getBuildConfigIfUpToDate
UnregisterCmd -> do
command (parseUnregisterArgs emptyRegisterFlags) regVerbose
preUnreg unregHook postUnreg
getBuildConfigIfUpToDate
HelpCmd -> return ()
where
command parse_args _get_verbosity
pre_hook cmd_hook post_hook
get_build_config = do
(flags, _, args) <- parse_args all_args []
pbi <- pre_hook hooks args flags
localbuildinfo <- get_build_config
let pkg_descr0 = localPkgDescr localbuildinfo
let pkg_descr = updatePackageDescription pbi pkg_descr0
cmd_hook hooks pkg_descr localbuildinfo hooks flags
post_hook hooks args flags pkg_descr localbuildinfo
getModulePaths :: LocalBuildInfo -> BuildInfo -> [String] -> IO [FilePath]
getModulePaths lbi bi =
fmap concat .
mapM (flip (moduleToFilePath (buildDir lbi : hsSourceDirs bi)) ["hs", "lhs"])
getBuildConfigIfUpToDate :: IO LocalBuildInfo
getBuildConfigIfUpToDate = do
lbi <- getPersistBuildConfig
case pkgDescrFile lbi of
Nothing -> return ()
Just pkg_descr_file -> checkPersistBuildConfig pkg_descr_file
return lbi
pfe :: PackageDescription -> LocalBuildInfo -> UserHooks -> PFEFlags -> IO ()
pfe pkg_descr _lbi hooks (PFEFlags verbosity) = do
let pps = allSuffixHandlers hooks
unless (hasLibs pkg_descr) $
die "no libraries found in this project"
withLib pkg_descr () $ \lib -> do
lbi <- getPersistBuildConfig
let bi = libBuildInfo lib
let mods = exposedModules lib ++ otherModules (libBuildInfo lib)
preprocessSources pkg_descr lbi False verbosity pps
inFiles <- getModulePaths lbi bi mods
let verbFlags = if verbosity >= deafening then ["-v"] else []
rawSystemProgramConf verbosity pfesetupProgram (withPrograms lbi)
("noplogic" : "cpp" : verbFlags ++ inFiles)
clean :: PackageDescription -> Maybe LocalBuildInfo -> UserHooks -> CleanFlags -> IO ()
clean pkg_descr maybeLbi _ (CleanFlags saveConfigure verbosity) = do
notice verbosity "cleaning..."
maybeConfig <- if saveConfigure then maybeGetPersistBuildConfig
else return Nothing
try $ removeDirectoryRecursive distPref
removeRegScripts
mapM_ removeFileOrDirectory (extraTmpFiles pkg_descr)
case maybeLbi of
Nothing -> return ()
Just lbi -> do
case compilerFlavor (compiler lbi) of
JHC -> cleanJHCExtras lbi
_ -> return ()
maybe (return ()) writePersistBuildConfig maybeConfig
where
cleanJHCExtras lbi = do
try $ removeFile (buildDir lbi </> "jhc-pkg.conf")
removePreprocessedPackage pkg_descr currentDir ["ho"]
removeFileOrDirectory :: FilePath -> IO ()
removeFileOrDirectory fname = do
isDir <- doesDirectoryExist fname
isFile <- doesFileExist fname
if isDir then removeDirectoryRecursive fname
else if isFile then removeFile fname
else return ()
no_extra_flags :: [String] -> IO ()
no_extra_flags [] = return ()
no_extra_flags extra_flags =
die $ concat
$ intersperse "\n" ("Unrecognised flags:" : map (' ' :) extra_flags)
scratchDirOpt :: OptDescr (LocalBuildInfo -> LocalBuildInfo)
scratchDirOpt = Option "b" ["scratchdir"] (reqDirArg setScratchDir)
"directory to receive the built package [dist/scratch]"
where setScratchDir dir lbi = lbi { scratchDir = dir }
emptyUserHooks :: UserHooks
emptyUserHooks
= UserHooks
{
runTests = ru,
readDesc = return Nothing,
hookedPreProcessors = [],
hookedPrograms = [],
preConf = rn,
confHook = (\_ _ -> return (error "No local build info generated during configure. Over-ride empty configure hook.")),
postConf = ru,
preBuild = rn,
buildHook = ru,
postBuild = ru,
preMakefile = rn,
makefileHook = ru,
postMakefile = ru,
preClean = rn,
cleanHook = ru,
postClean = ru,
preCopy = rn,
copyHook = ru,
postCopy = ru,
preInst = rn,
instHook = ru,
postInst = ru,
preSDist = rn,
sDistHook = ru,
postSDist = ru,
preReg = rn,
regHook = ru,
postReg = ru,
preUnreg = rn,
unregHook = ru,
postUnreg = ru,
prePFE = rn,
pfeHook = ru,
postPFE = ru,
preHscolour = rn,
hscolourHook = ru,
postHscolour = ru,
preHaddock = rn,
haddockHook = ru,
postHaddock = ru
}
where rn args _ = no_extra_flags args >> return emptyHookedBuildInfo
ru _ _ _ _ = return ()
simpleUserHooks :: UserHooks
simpleUserHooks =
emptyUserHooks {
confHook = configure,
buildHook = defaultBuildHook,
makefileHook = defaultMakefileHook,
copyHook = \desc lbi _ f -> install desc lbi f,
instHook = defaultInstallHook,
sDistHook = \p l h f -> sdist p l f srcPref distPref (allSuffixHandlers h),
pfeHook = pfe,
cleanHook = clean,
hscolourHook = defaultHscolourHook,
haddockHook = defaultHaddockHook,
regHook = defaultRegHook,
unregHook = \p l _ f -> unregister p l f
}
defaultUserHooks :: UserHooks
defaultUserHooks = autoconfUserHooks
autoconfUserHooks :: UserHooks
autoconfUserHooks
= simpleUserHooks
{
postConf = defaultPostConf,
preBuild = readHook buildVerbose,
preMakefile = readHook makefileVerbose,
preClean = readHook cleanVerbose,
preCopy = readHook copyVerbose,
preInst = readHook installVerbose,
preHscolour = readHook hscolourVerbose,
preHaddock = readHook haddockVerbose,
preReg = readHook regVerbose,
preUnreg = readHook regVerbose
}
where defaultPostConf :: Args -> ConfigFlags -> PackageDescription -> LocalBuildInfo -> IO ()
defaultPostConf args flags _ _
= do let verbosity = configVerbose flags
no_extra_flags args
confExists <- doesFileExist "configure"
when confExists $
rawSystemPathExit verbosity "sh" $
"configure" : configureArgs flags
readHook :: (a -> Verbosity) -> Args -> a -> IO HookedBuildInfo
readHook get_verbosity a flags = do
no_extra_flags a
maybe_infoFile <- defaultHookedPackageDesc
case maybe_infoFile of
Nothing -> return emptyHookedBuildInfo
Just infoFile -> do
let verbosity = get_verbosity flags
info verbosity $ "Reading parameters from " ++ infoFile
readHookedBuildInfo verbosity infoFile
defaultInstallHook :: PackageDescription -> LocalBuildInfo
-> UserHooks -> InstallFlags -> IO ()
defaultInstallHook pkg_descr localbuildinfo _ (InstallFlags uInstFlag verbosity) = do
install pkg_descr localbuildinfo (CopyFlags NoCopyDest verbosity)
when (hasLibs pkg_descr) $
register pkg_descr localbuildinfo
emptyRegisterFlags{ regPackageDB=uInstFlag, regVerbose=verbosity }
defaultBuildHook :: PackageDescription -> LocalBuildInfo
-> UserHooks -> BuildFlags -> IO ()
defaultBuildHook pkg_descr localbuildinfo hooks flags = do
build pkg_descr localbuildinfo flags (allSuffixHandlers hooks)
when (hasLibs pkg_descr) $
writeInstalledConfig pkg_descr localbuildinfo False Nothing
defaultMakefileHook :: PackageDescription -> LocalBuildInfo
-> UserHooks -> MakefileFlags -> IO ()
defaultMakefileHook pkg_descr localbuildinfo hooks flags = do
makefile pkg_descr localbuildinfo flags (allSuffixHandlers hooks)
when (hasLibs pkg_descr) $
writeInstalledConfig pkg_descr localbuildinfo False Nothing
defaultRegHook :: PackageDescription -> LocalBuildInfo
-> UserHooks -> RegisterFlags -> IO ()
defaultRegHook pkg_descr localbuildinfo _ flags =
if hasLibs pkg_descr
then register pkg_descr localbuildinfo flags
else setupMessage (regVerbose flags)
"Package contains no library to register:"
pkg_descr
defaultHaddockHook :: PackageDescription -> LocalBuildInfo
-> UserHooks -> HaddockFlags -> IO ()
defaultHaddockHook pkg_descr localbuildinfo hooks flags = do
haddock pkg_descr localbuildinfo (allSuffixHandlers hooks) flags
defaultHscolourHook :: PackageDescription -> LocalBuildInfo
-> UserHooks -> HscolourFlags -> IO ()
defaultHscolourHook pkg_descr localbuildinfo hooks flags =
hscolour pkg_descr localbuildinfo (allSuffixHandlers hooks) flags
#ifdef DEBUG
simpleHunitTests :: [Test]
simpleHunitTests = []
#endif