on ebbae35 help sign in
Idris-dev/Setup.hs
259 lines 11 kB history raw
1{-# LANGUAGE CPP #-}
2import Control.Monad
3import Data.IORef
4import Control.Exception (SomeException, catch)
6import Distribution.Simple
7import Distribution.Simple.BuildPaths (autogenModulesDir)
8import Distribution.Simple.InstallDirs as I
9import Distribution.Simple.LocalBuildInfo as L
10import qualified Distribution.Simple.Setup as S
11import qualified Distribution.Simple.Program as P
12import Distribution.Simple.Utils (createDirectoryIfMissingVerbose, rewriteFile)
13import Distribution.PackageDescription
14import Distribution.Text
16import System.Environment
17import System.Exit
18import System.FilePath ((</>), splitDirectories,isAbsolute)
19import System.Directory
20import qualified System.FilePath.Posix as Px
21import System.Process
23-- After Idris is built, we need to check and install the prelude and other libs
25-- -----------------------------------------------------------------------------
26-- Idris Command Path
28-- make on mingw32 exepects unix style separators
29#ifdef mingw32_HOST_OS
30(<//>) = (Px.</>)
31idrisCmd local = Px.joinPath $ splitDirectories $ ".." <//> ".." <//> buildDir local <//> "idris" <//> "idris"
32#else
33idrisCmd local = ".." </> ".." </> buildDir local </> "idris" </> "idris"
34#endif
36-- -----------------------------------------------------------------------------
37-- Make Commands
39-- use GNU make on FreeBSD
40#if defined(freebsd_HOST_OS) || defined(dragonfly_HOST_OS)
41mymake = "gmake"
42#else
43mymake = "make"
44#endif
45make verbosity =
46 P.runProgramInvocation verbosity . P.simpleProgramInvocation mymake
48-- -----------------------------------------------------------------------------
49-- Flags
51usesGMP :: S.ConfigFlags -> Bool
52usesGMP flags =
53 case lookup (FlagName "gmp") (S.configConfigurationsFlags flags) of
54 Just True -> True
55 Just False -> False
56 Nothing -> True
58execOnly :: S.ConfigFlags -> Bool
59execOnly flags =
60 case lookup (FlagName "execonly") (S.configConfigurationsFlags flags) of
61 Just True -> True
62 Just False -> False
63 Nothing -> False
65isRelease :: S.ConfigFlags -> Bool
66isRelease flags =
67 case lookup (FlagName "release") (S.configConfigurationsFlags flags) of
68 Just True -> True
69 Just False -> False
70 Nothing -> False
72isFreestanding :: S.ConfigFlags -> Bool
73isFreestanding flags =
74 case lookup (FlagName "freestanding") (S.configConfigurationsFlags flags) of
75 Just True -> True
76 Just False -> False
77 Nothing -> False
78-- -----------------------------------------------------------------------------
79-- Clean
81idrisClean _ flags _ _ = do
82 cleanStdLib
83 where
84 verbosity = S.fromFlag $ S.cleanVerbosity flags
86 cleanStdLib = do
87 makeClean "libs"
89 makeClean dir = make verbosity [ "-C", dir, "clean", "IDRIS=idris" ]
92-- -----------------------------------------------------------------------------
93-- Configure
95gitHash :: IO String
96gitHash = do h <- Control.Exception.catch (readProcess "git" ["rev-parse", "--short", "HEAD"] "")
97 (\e -> let e' = (e :: SomeException) in return "PRE")
98 return $ takeWhile (/= '\n') h
100-- Put the Git hash into a module for use in the program
101-- For release builds, just put the empty string in the module
102generateVersionModule verbosity dir release = do
103 hash <- gitHash
104 let versionModulePath = dir </> "Version_idris" Px.<.> "hs"
105 putStrLn $ "Generating " ++ versionModulePath ++
106 if release then " for release" else (" for prerelease " ++ hash)
107 createDirectoryIfMissingVerbose verbosity True dir
108 rewriteFile versionModulePath (versionModuleContents hash)
110 where versionModuleContents h = "module Version_idris where\n\n" ++
111 "gitHash :: String\n" ++
112 if release
113 then "gitHash = \"\"\n"
114 else "gitHash = \"git:" ++ h ++ "\"\n"
116-- Generate a module that contains the lib path for a freestanding Idris
117generateTargetModule verbosity dir targetDir = do
118 absPath <- return $ isAbsolute targetDir
119 let targetModulePath = dir </> "Target_idris" Px.<.> "hs"
120 putStrLn $ "Generating " ++ targetModulePath
121 createDirectoryIfMissingVerbose verbosity True dir
122 rewriteFile targetModulePath (versionModuleContents absPath targetDir)
123 where versionModuleContents absolute td = "module Target_idris where\n\n" ++
124 "import System.FilePath\n" ++
125 "import System.Environment\n" ++
126 "getDataDir :: IO String\n" ++
127 if absolute
128 then "getDataDir = return \"" ++ td ++ "\"\n"
129 else "getDataDir = do \n" ++
130 " expath <- getExecutablePath\n" ++
131 " execDir <- return $ dropFileName expath\n" ++
132 " return $ execDir ++ \"" ++ td ++ "\"\n"
133 ++ "getDataFileName :: FilePath -> IO FilePath\n"
134 ++ "getDataFileName name = do\n"
135 ++ " dir <- getDataDir\n"
136 ++ " return (dir ++ \"/\" ++ name)"
138-- a module that has info about existence and location of a bundled toolchain
139generateToolchainModule verbosity srcDir toolDir = do
140 let commonContent = "module Tools_idris where\n\n"
141 let toolContent = case toolDir of
142 Just dir -> "hasBundledToolchain = True\n" ++
143 "getToolchainDir = \"" ++ dir ++ "\"\n"
144 Nothing -> "hasBundledToolchain = False\n" ++
145 "getToolchainDir = \"\""
146 let toolPath = srcDir </> "Tools_idris" Px.<.> "hs"
147 createDirectoryIfMissingVerbose verbosity True srcDir
148 rewriteFile toolPath (commonContent ++ toolContent)
150idrisConfigure _ flags _ local = do
151 configureRTS
152 generateVersionModule verbosity (autogenModulesDir local) (isRelease (configFlags local))
153 if (isFreestanding $ configFlags local)
154 then (do
155 toolDir <- lookupEnv "IDRIS_TOOLCHAIN_DIR"
156 generateToolchainModule verbosity (autogenModulesDir local) toolDir
157 targetDir <- lookupEnv "IDRIS_LIB_DIR"
158 case targetDir of
159 Just d -> generateTargetModule verbosity (autogenModulesDir local) d
160 Nothing -> error $ "Trying to build freestanding without a target directory."
161 ++ " Set it by defining IDRIS_LIB_DIR.")
162 else
163 generateToolchainModule verbosity (autogenModulesDir local) Nothing
164 where
165 verbosity = S.fromFlag $ S.configVerbosity flags
166 version = pkgVersion . package $ localPkgDescr local
168 -- This is a hack. I don't know how to tell cabal that a data file needs
169 -- installing but shouldn't be in the distribution. And it won't make the
170 -- distribution if it's not there, so instead I just delete
171 -- the file after configure.
172 configureRTS = make verbosity ["-C", "rts", "clean"]
174idrisPreSDist args flags = do
175 let dir = S.fromFlag (S.sDistDirectory flags)
176 let verb = S.fromFlag (S.sDistVerbosity flags)
177 generateVersionModule verb ("src") True
178 generateTargetModule verb "src" "./libs"
179 generateToolchainModule verb "src" Nothing
180 preSDist simpleUserHooks args flags
182idrisPostSDist args flags desc lbi = do
183 Control.Exception.catch (do let file = "src" </> "Version_idris" Px.<.> "hs"
184 let targetFile = "src" </> "Target_idris" Px.<.> "hs"
185 putStrLn $ "Removing generated modules:\n "
186 ++ file ++ "\n" ++ targetFile
187 removeFile file
188 removeFile targetFile)
189 (\e -> let e' = (e :: SomeException) in return ())
190 postSDist simpleUserHooks args flags desc lbi
192-- -----------------------------------------------------------------------------
193-- Build
195getVersion :: Args -> S.BuildFlags -> IO HookedBuildInfo
196getVersion args flags = do
197 hash <- gitHash
198 let buildinfo = (emptyBuildInfo { cppOptions = ["-DVERSION="++hash] }) :: BuildInfo
199 return (Just buildinfo, [])
201idrisBuild _ flags _ local = unless (execOnly (configFlags local)) $ do
202 buildStdLib
203 buildRTS
204 where
205 verbosity = S.fromFlag $ S.buildVerbosity flags
207 buildStdLib = do
208 putStrLn "Building libraries..."
209 makeBuild "libs"
210 where
211 makeBuild dir = make verbosity [ "-C", dir, "build" , "IDRIS=" ++ idrisCmd local]
213 buildRTS = make verbosity (["-C", "rts", "build"] ++
214 gmpflag (usesGMP (configFlags local)))
216 gmpflag False = []
217 gmpflag True = ["GMP=-DIDRIS_GMP"]
221-- -----------------------------------------------------------------------------
222-- Copy/Install
224idrisInstall verbosity copy pkg local = unless (execOnly (configFlags local)) $ do
225 installStdLib
226 installRTS
227 where
228 target = datadir $ L.absoluteInstallDirs pkg local copy
230 installStdLib = do
231 putStrLn $ "Installing libraries in " ++ target
232 makeInstall "libs" target
234 installRTS = do
235 let target' = target </> "rts"
236 putStrLn $ "Installing run time system in " ++ target'
237 makeInstall "rts" target'
239 makeInstall src target =
240 make verbosity [ "-C", src, "install" , "TARGET=" ++ target, "IDRIS=" ++ idrisCmd local]
242-- -----------------------------------------------------------------------------
243-- Main
245-- Install libraries during both copy and install
246-- See https://github.com/haskell/cabal/issues/709
247main = defaultMainWithHooks $ simpleUserHooks
248 { postClean = idrisClean
249 , postConf = idrisConfigure
250 , postBuild = idrisBuild
251 , postCopy = \_ flags pkg local ->
252 idrisInstall (S.fromFlag $ S.copyVerbosity flags)
253 (S.fromFlag $ S.copyDest flags) pkg local
254 , postInst = \_ flags pkg local ->
255 idrisInstall (S.fromFlag $ S.installVerbosity flags)
256 NoCopyDest pkg local
257 , preSDist = idrisPreSDist --do { putStrLn (show args) ; putStrLn (show flags) ; return emptyHookedBuildInfo }
258 , postSDist = idrisPostSDist
259 }