mirror of
https://github.com/ilyakooo0/Idris-dev.git
synced 2024-09-11 08:55:23 +03:00
328 lines
12 KiB
Haskell
328 lines
12 KiB
Haskell
{-# LANGUAGE CPP #-}
|
|
|
|
#if !defined(MIN_VERSION_Cabal)
|
|
# define MIN_VERSION_Cabal(x,y,z) 0
|
|
#endif
|
|
|
|
import Control.Monad
|
|
import Data.IORef
|
|
import Control.Exception (SomeException, catch)
|
|
|
|
import Distribution.Simple
|
|
import Distribution.Simple.BuildPaths
|
|
import Distribution.Simple.InstallDirs as I
|
|
import Distribution.Simple.LocalBuildInfo as L
|
|
import qualified Distribution.Simple.Setup as S
|
|
import qualified Distribution.Simple.Program as P
|
|
import Distribution.Simple.Utils
|
|
import Distribution.Compiler
|
|
import Distribution.PackageDescription
|
|
import Distribution.Text
|
|
import Distribution.Verbosity
|
|
|
|
import System.Environment
|
|
import System.Exit
|
|
import System.FilePath ((</>), splitDirectories,isAbsolute)
|
|
import System.Directory
|
|
import qualified System.FilePath.Posix as Px
|
|
import System.Process
|
|
|
|
#if (MIN_VERSION_Cabal(2,0,0))
|
|
import Distribution.Types.UnqualComponentName
|
|
#endif
|
|
|
|
|
|
-- After Idris is built, we need to check and install the prelude and other libs
|
|
|
|
-- -----------------------------------------------------------------------------
|
|
-- Idris Command Path
|
|
|
|
-- make on mingw32 exepects unix style separators
|
|
#ifdef mingw32_HOST_OS
|
|
(<//>) = (Px.</>)
|
|
idrisCmd local = Px.joinPath $ splitDirectories $ ".." <//> ".." <//> buildDir local <//> "idris" <//> "idris"
|
|
#else
|
|
idrisCmd local = ".." </> ".." </> buildDir local </> "idris" </> "idris"
|
|
#endif
|
|
|
|
-- -----------------------------------------------------------------------------
|
|
-- Make Commands
|
|
|
|
-- use GNU make on FreeBSD
|
|
#if defined(freebsd_HOST_OS) || defined(dragonfly_HOST_OS)\
|
|
|| defined(openbsd_HOST_OS) || defined(netbsd_HOST_OS)
|
|
mymake = "gmake"
|
|
#else
|
|
mymake = "make"
|
|
#endif
|
|
make verbosity =
|
|
P.runProgramInvocation verbosity . P.simpleProgramInvocation mymake
|
|
|
|
#ifdef mingw32_HOST_OS
|
|
windres verbosity = P.runProgramInvocation verbosity . P.simpleProgramInvocation "windres"
|
|
#endif
|
|
-- -----------------------------------------------------------------------------
|
|
-- Flags
|
|
|
|
usesGMP :: S.ConfigFlags -> Bool
|
|
usesGMP flags =
|
|
case lookupFlagAssignment (mkFlagName "gmp") (S.configConfigurationsFlags flags) of
|
|
Just True -> True
|
|
Just False -> False
|
|
Nothing -> False
|
|
|
|
execOnly :: S.ConfigFlags -> Bool
|
|
execOnly flags =
|
|
case lookupFlagAssignment (mkFlagName "execonly") (S.configConfigurationsFlags flags) of
|
|
Just True -> True
|
|
Just False -> False
|
|
Nothing -> False
|
|
|
|
isRelease :: S.ConfigFlags -> Bool
|
|
isRelease flags =
|
|
case lookupFlagAssignment (mkFlagName "release") (S.configConfigurationsFlags flags) of
|
|
Just True -> True
|
|
Just False -> False
|
|
Nothing -> False
|
|
|
|
isFreestanding :: S.ConfigFlags -> Bool
|
|
isFreestanding flags =
|
|
case lookupFlagAssignment (mkFlagName "freestanding") (S.configConfigurationsFlags flags) of
|
|
Just True -> True
|
|
Just False -> False
|
|
Nothing -> False
|
|
|
|
#if !(MIN_VERSION_Cabal(2,0,0))
|
|
mkFlagName :: String -> FlagName
|
|
mkFlagName = FlagName
|
|
#endif
|
|
|
|
#if !(MIN_VERSION_Cabal(2,2,0))
|
|
lookupFlagAssignment :: FlagName -> FlagAssignment -> Maybe Bool
|
|
lookupFlagAssignment = lookup
|
|
#endif
|
|
|
|
-- -----------------------------------------------------------------------------
|
|
-- Clean
|
|
|
|
idrisClean _ flags _ _ = cleanStdLib
|
|
where
|
|
verbosity = S.fromFlag $ S.cleanVerbosity flags
|
|
|
|
cleanStdLib = makeClean "libs"
|
|
|
|
makeClean dir = make verbosity [ "-C", dir, "clean", "IDRIS=idris" ]
|
|
|
|
-- -----------------------------------------------------------------------------
|
|
-- Configure
|
|
|
|
gitHash :: IO String
|
|
gitHash = do h <- Control.Exception.catch (readProcess "git" ["rev-parse", "--short", "HEAD"] "")
|
|
(\e -> let e' = (e :: SomeException) in return "PRE")
|
|
return $ takeWhile (/= '\n') h
|
|
|
|
-- Generate a module that contains extra library directories passed
|
|
-- via command-line to cabal
|
|
generateBuildFlagsModule :: Verbosity -> FilePath -> [String] -> IO ()
|
|
generateBuildFlagsModule verbosity dir libdirs = do
|
|
let buildFlagsModulePath = dir </> "BuildFlags_idris" Px.<.> "hs"
|
|
putStrLn $ "Generating " ++ buildFlagsModulePath
|
|
createDirectoryIfMissingVerbose verbosity True dir
|
|
rewriteFileEx verbosity buildFlagsModulePath contents
|
|
where contents = "module BuildFlags_idris where \n\n" ++
|
|
"extraLibDirs :: [String]\n" ++
|
|
"extraLibDirs = " ++ show libdirs
|
|
|
|
-- Put the Git hash into a module for use in the program
|
|
-- For release builds, just put the empty string in the module
|
|
generateVersionModule verbosity dir release = do
|
|
hash <- gitHash
|
|
let versionModulePath = dir </> "Version_idris" Px.<.> "hs"
|
|
putStrLn $ "Generating " ++ versionModulePath ++
|
|
if release then " for release" else " for prerelease " ++ hash
|
|
createDirectoryIfMissingVerbose verbosity True dir
|
|
rewriteFileEx verbosity versionModulePath (versionModuleContents hash)
|
|
|
|
where versionModuleContents h = "module Version_idris where\n\n" ++
|
|
"gitHash :: String\n" ++
|
|
if release
|
|
then "gitHash = \"\"\n"
|
|
else "gitHash = \"git:" ++ h ++ "\"\n"
|
|
|
|
-- Generate a module that contains the lib path for a freestanding Idris
|
|
generateTargetModule verbosity dir targetDir = do
|
|
let absPath = isAbsolute targetDir
|
|
let targetModulePath = dir </> "Target_idris" Px.<.> "hs"
|
|
putStrLn $ "Generating " ++ targetModulePath
|
|
createDirectoryIfMissingVerbose verbosity True dir
|
|
rewriteFileEx verbosity targetModulePath (versionModuleContents absPath targetDir)
|
|
where versionModuleContents absolute td = "module Target_idris where\n\n" ++
|
|
"import System.FilePath\n" ++
|
|
"import System.Environment\n" ++
|
|
"getDataDir :: IO String\n" ++
|
|
if absolute
|
|
then "getDataDir = return \"" ++ td ++ "\"\n"
|
|
else "getDataDir = do \n" ++
|
|
" expath <- getExecutablePath\n" ++
|
|
" execDir <- return $ dropFileName expath\n" ++
|
|
" return $ execDir ++ \"" ++ td ++ "\"\n"
|
|
++ "getDataFileName :: FilePath -> IO FilePath\n"
|
|
++ "getDataFileName name = do\n"
|
|
++ " dir <- getDataDir\n"
|
|
++ " return (dir ++ \"/\" ++ name)"
|
|
|
|
-- a module that has info about existence and location of a bundled toolchain
|
|
generateToolchainModule verbosity srcDir toolDir = do
|
|
let commonContent = "module Tools_idris where\n\n"
|
|
let toolContent = case toolDir of
|
|
Just dir -> "hasBundledToolchain = True\n" ++
|
|
"getToolchainDir = \"" ++ dir ++ "\"\n"
|
|
Nothing -> "hasBundledToolchain = False\n" ++
|
|
"getToolchainDir = \"\""
|
|
let toolPath = srcDir </> "Tools_idris" Px.<.> "hs"
|
|
createDirectoryIfMissingVerbose verbosity True srcDir
|
|
rewriteFileEx verbosity toolPath (commonContent ++ toolContent)
|
|
|
|
idrisConfigure _ flags pkgdesc local = do
|
|
configureRTS
|
|
withLibLBI pkgdesc local $ \lib libcfg -> do
|
|
let libAutogenDir = autogenComponentModulesDir local libcfg
|
|
let libDirs = extraLibDirs $ libBuildInfo lib
|
|
generateBuildFlagsModule verbosity libAutogenDir libDirs
|
|
generateVersionModule verbosity libAutogenDir (isRelease (configFlags local))
|
|
if isFreestanding $ configFlags local
|
|
then do
|
|
toolDir <- lookupEnv "IDRIS_TOOLCHAIN_DIR"
|
|
generateToolchainModule verbosity libAutogenDir toolDir
|
|
targetDir <- lookupEnv "IDRIS_LIB_DIR"
|
|
case targetDir of
|
|
Just d -> generateTargetModule verbosity libAutogenDir d
|
|
Nothing -> error $ "Trying to build freestanding without a target directory."
|
|
++ " Set it by defining IDRIS_LIB_DIR."
|
|
else
|
|
generateToolchainModule verbosity libAutogenDir Nothing
|
|
where
|
|
verbosity = S.fromFlag $ S.configVerbosity flags
|
|
version = pkgVersion . package $ localPkgDescr local
|
|
|
|
-- This is a hack. I don't know how to tell cabal that a data file needs
|
|
-- installing but shouldn't be in the distribution. And it won't make the
|
|
-- distribution if it's not there, so instead I just delete
|
|
-- the file after configure.
|
|
configureRTS = make verbosity ["-C", "rts", "clean"]
|
|
|
|
#if !(MIN_VERSION_Cabal(2,0,0))
|
|
autogenComponentModulesDir lbi _ = autogenModulesDir lbi
|
|
#endif
|
|
|
|
#if !(MIN_VERSION_Cabal(2,0,0))
|
|
rewriteFileEx :: Verbosity -> FilePath -> String -> IO ()
|
|
rewriteFileEx _ = rewriteFile
|
|
#endif
|
|
|
|
-- -----------------------------------------------------------------------------
|
|
-- Build
|
|
|
|
getVersion :: Args -> S.BuildFlags -> IO HookedBuildInfo
|
|
getVersion args flags = do
|
|
hash <- gitHash
|
|
let buildinfo = (emptyBuildInfo { cppOptions = ["-DVERSION="++hash] }) :: BuildInfo
|
|
return (Just buildinfo, [])
|
|
|
|
|
|
#if !(MIN_VERSION_Cabal(2,0,0))
|
|
mkUnqualComponentName = id
|
|
#endif
|
|
|
|
idrisPreBuild args flags = do
|
|
#ifdef mingw32_HOST_OS
|
|
createDirectoryIfMissingVerbose verbosity True dir
|
|
windres verbosity ["icons/idris_icon.rc","-o", dir++"/idris_icon.o"]
|
|
return (Nothing, [(mkUnqualComponentName "idris", emptyBuildInfo { ldOptions = [dir ++ "/idris_icon.o"] })])
|
|
where
|
|
verbosity = S.fromFlag $ S.buildVerbosity flags
|
|
dir = S.fromFlagOrDefault "dist" $ S.buildDistPref flags
|
|
#else
|
|
return (Nothing, [])
|
|
#endif
|
|
|
|
idrisBuild _ flags _ local
|
|
= if (execOnly (configFlags local)) then buildRTS
|
|
else do buildStdLib
|
|
buildRTS
|
|
where
|
|
verbosity = S.fromFlag $ S.buildVerbosity flags
|
|
|
|
buildStdLib = do
|
|
putStrLn "Building libraries..."
|
|
makeBuild "libs"
|
|
where
|
|
makeBuild dir = make verbosity [ "-C", dir, "build" , "IDRIS=" ++ idrisCmd local]
|
|
|
|
buildRTS = make verbosity (["-C", "rts", "build"] ++
|
|
gmpflag (usesGMP (configFlags local)))
|
|
|
|
gmpflag False = []
|
|
gmpflag True = ["GMP=-DIDRIS_GMP"]
|
|
|
|
-- -----------------------------------------------------------------------------
|
|
-- Copy/Install
|
|
|
|
idrisInstall verbosity copy pkg local
|
|
= if (execOnly (configFlags local)) then installRTS
|
|
else do installStdLib
|
|
installRTS
|
|
installManPage
|
|
where
|
|
target = datadir $ L.absoluteInstallDirs pkg local copy
|
|
|
|
installStdLib = do
|
|
let target' = target -- </> "libs"
|
|
putStrLn $ "Installing libraries in " ++ target'
|
|
makeInstall "libs" target'
|
|
|
|
installRTS = do
|
|
let target' = target </> "rts"
|
|
putStrLn $ "Installing run time system in " ++ target'
|
|
makeInstall "rts" target'
|
|
|
|
installManPage = do
|
|
let mandest = mandir (L.absoluteInstallDirs pkg local copy) ++ "/man1"
|
|
notice verbosity $ unwords ["Copying man page to", mandest]
|
|
installOrdinaryFiles verbosity mandest [("man", "idris.1")]
|
|
|
|
makeInstall src target =
|
|
make verbosity [ "-C", src, "install" , "TARGET=" ++ target, "IDRIS=" ++ idrisCmd local]
|
|
|
|
-- -----------------------------------------------------------------------------
|
|
-- Test
|
|
|
|
-- There are two "dataDir" in cabal, and they don't relate to each other.
|
|
-- When fetching modules, idris uses the second path (in the pkg record),
|
|
-- which by default is the root folder of the project.
|
|
-- We want it to be the install directory where we put the idris libraries.
|
|
fixPkg pkg target = pkg { dataDir = target }
|
|
|
|
idrisTestHook args pkg local hooks flags = do
|
|
let target = datadir $ L.absoluteInstallDirs pkg local NoCopyDest
|
|
testHook simpleUserHooks args (fixPkg pkg target) local hooks flags
|
|
|
|
-- -----------------------------------------------------------------------------
|
|
-- Main
|
|
|
|
-- Install libraries during both copy and install
|
|
-- See https://github.com/haskell/cabal/issues/709
|
|
main = defaultMainWithHooks $ simpleUserHooks
|
|
{ postClean = idrisClean
|
|
, postConf = idrisConfigure
|
|
, preBuild = idrisPreBuild
|
|
, postBuild = idrisBuild
|
|
, postCopy = \_ flags pkg local ->
|
|
idrisInstall (S.fromFlag $ S.copyVerbosity flags)
|
|
(S.fromFlag $ S.copyDest flags) pkg local
|
|
, postInst = \_ flags pkg local ->
|
|
idrisInstall (S.fromFlag $ S.installVerbosity flags)
|
|
NoCopyDest pkg local
|
|
, testHook = idrisTestHook
|
|
}
|