on f0a67ff help sign in
Idris-dev/Setup.hs
286 lines 12 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, notice, installOrdinaryFiles)
13import Distribution.Compiler
14import Distribution.PackageDescription
15import Distribution.Text
17import System.Environment
18import System.Exit
19import System.FilePath ((</>), splitDirectories,isAbsolute)
20import System.Directory
21import qualified System.FilePath.Posix as Px
22import System.Process
24-- After Idris is built, we need to check and install the prelude and other libs
26-- -----------------------------------------------------------------------------
27-- Idris Command Path
29-- make on mingw32 exepects unix style separators
30#ifdef mingw32_HOST_OS
31(<//>) = (Px.</>)
32idrisCmd local = Px.joinPath $ splitDirectories $ ".." <//> ".." <//> buildDir local <//> "idris" <//> "idris"
33#else
34idrisCmd local = ".." </> ".." </> buildDir local </> "idris" </> "idris"
35#endif
37-- -----------------------------------------------------------------------------
38-- Make Commands
40-- use GNU make on FreeBSD
41#if defined(freebsd_HOST_OS) || defined(dragonfly_HOST_OS)\
42 || defined(openbsd_HOST_OS) || defined(netbsd_HOST_OS)
43mymake = "gmake"
44#else
45mymake = "make"
46#endif
47make verbosity =
48 P.runProgramInvocation verbosity . P.simpleProgramInvocation mymake
50#ifdef mingw32_HOST_OS
51windres verbosity = P.runProgramInvocation verbosity . P.simpleProgramInvocation "windres"
52#endif
53-- -----------------------------------------------------------------------------
54-- Flags
56usesGMP :: S.ConfigFlags -> Bool
57usesGMP flags =
58 case lookup (FlagName "gmp") (S.configConfigurationsFlags flags) of
59 Just True -> True
60 Just False -> False
61 Nothing -> False
63execOnly :: S.ConfigFlags -> Bool
64execOnly flags =
65 case lookup (FlagName "execonly") (S.configConfigurationsFlags flags) of
66 Just True -> True
67 Just False -> False
68 Nothing -> False
70isRelease :: S.ConfigFlags -> Bool
71isRelease flags =
72 case lookup (FlagName "release") (S.configConfigurationsFlags flags) of
73 Just True -> True
74 Just False -> False
75 Nothing -> False
77isFreestanding :: S.ConfigFlags -> Bool
78isFreestanding flags =
79 case lookup (FlagName "freestanding") (S.configConfigurationsFlags flags) of
80 Just True -> True
81 Just False -> False
82 Nothing -> False
83-- -----------------------------------------------------------------------------
84-- Clean
86idrisClean _ flags _ _ = do
87 cleanStdLib
88 where
89 verbosity = S.fromFlag $ S.cleanVerbosity flags
91 cleanStdLib = do
92 makeClean "libs"
94 makeClean dir = make verbosity [ "-C", dir, "clean", "IDRIS=idris" ]
97-- -----------------------------------------------------------------------------
98-- Configure
100gitHash :: IO String
101gitHash = do h <- Control.Exception.catch (readProcess "git" ["rev-parse", "--short", "HEAD"] "")
102 (\e -> let e' = (e :: SomeException) in return "PRE")
103 return $ takeWhile (/= '\n') h
105-- Put the Git hash into a module for use in the program
106-- For release builds, just put the empty string in the module
107generateVersionModule verbosity dir release = do
108 hash <- gitHash
109 let versionModulePath = dir </> "Version_idris" Px.<.> "hs"
110 putStrLn $ "Generating " ++ versionModulePath ++
111 if release then " for release" else (" for prerelease " ++ hash)
112 createDirectoryIfMissingVerbose verbosity True dir
113 rewriteFile versionModulePath (versionModuleContents hash)
115 where versionModuleContents h = "module Version_idris where\n\n" ++
116 "gitHash :: String\n" ++
117 if release
118 then "gitHash = \"\"\n"
119 else "gitHash = \"git:" ++ h ++ "\"\n"
121-- Generate a module that contains the lib path for a freestanding Idris
122generateTargetModule verbosity dir targetDir = do
123 absPath <- return $ isAbsolute targetDir
124 let targetModulePath = dir </> "Target_idris" Px.<.> "hs"
125 putStrLn $ "Generating " ++ targetModulePath
126 createDirectoryIfMissingVerbose verbosity True dir
127 rewriteFile targetModulePath (versionModuleContents absPath targetDir)
128 where versionModuleContents absolute td = "module Target_idris where\n\n" ++
129 "import System.FilePath\n" ++
130 "import System.Environment\n" ++
131 "getDataDir :: IO String\n" ++
132 if absolute
133 then "getDataDir = return \"" ++ td ++ "\"\n"
134 else "getDataDir = do \n" ++
135 " expath <- getExecutablePath\n" ++
136 " execDir <- return $ dropFileName expath\n" ++
137 " return $ execDir ++ \"" ++ td ++ "\"\n"
138 ++ "getDataFileName :: FilePath -> IO FilePath\n"
139 ++ "getDataFileName name = do\n"
140 ++ " dir <- getDataDir\n"
141 ++ " return (dir ++ \"/\" ++ name)"
143-- a module that has info about existence and location of a bundled toolchain
144generateToolchainModule verbosity srcDir toolDir = do
145 let commonContent = "module Tools_idris where\n\n"
146 let toolContent = case toolDir of
147 Just dir -> "hasBundledToolchain = True\n" ++
148 "getToolchainDir = \"" ++ dir ++ "\"\n"
149 Nothing -> "hasBundledToolchain = False\n" ++
150 "getToolchainDir = \"\""
151 let toolPath = srcDir </> "Tools_idris" Px.<.> "hs"
152 createDirectoryIfMissingVerbose verbosity True srcDir
153 rewriteFile toolPath (commonContent ++ toolContent)
155idrisConfigure _ flags _ local = do
156 configureRTS
157 generateVersionModule verbosity (autogenModulesDir local) (isRelease (configFlags local))
158 if (isFreestanding $ configFlags local)
159 then (do
160 toolDir <- lookupEnv "IDRIS_TOOLCHAIN_DIR"
161 generateToolchainModule verbosity (autogenModulesDir local) toolDir
162 targetDir <- lookupEnv "IDRIS_LIB_DIR"
163 case targetDir of
164 Just d -> generateTargetModule verbosity (autogenModulesDir local) d
165 Nothing -> error $ "Trying to build freestanding without a target directory."
166 ++ " Set it by defining IDRIS_LIB_DIR.")
167 else
168 generateToolchainModule verbosity (autogenModulesDir local) Nothing
169 where
170 verbosity = S.fromFlag $ S.configVerbosity flags
171 version = pkgVersion . package $ localPkgDescr local
173 -- This is a hack. I don't know how to tell cabal that a data file needs
174 -- installing but shouldn't be in the distribution. And it won't make the
175 -- distribution if it's not there, so instead I just delete
176 -- the file after configure.
177 configureRTS = make verbosity ["-C", "rts", "clean"]
179idrisPreSDist args flags = do
180 let dir = S.fromFlag (S.sDistDirectory flags)
181 let verb = S.fromFlag (S.sDistVerbosity flags)
182 generateVersionModule verb ("src") True
183 generateTargetModule verb "src" "./libs"
184 generateToolchainModule verb "src" Nothing
185 preSDist simpleUserHooks args flags
187idrisPostSDist args flags desc lbi = do
188 Control.Exception.catch (do let file = "src" </> "Version_idris" Px.<.> "hs"
189 let targetFile = "src" </> "Target_idris" Px.<.> "hs"
190 putStrLn $ "Removing generated modules:\n "
191 ++ file ++ "\n" ++ targetFile
192 removeFile file
193 removeFile targetFile)
194 (\e -> let e' = (e :: SomeException) in return ())
195 postSDist simpleUserHooks args flags desc lbi
197-- -----------------------------------------------------------------------------
198-- Build
200getVersion :: Args -> S.BuildFlags -> IO HookedBuildInfo
201getVersion args flags = do
202 hash <- gitHash
203 let buildinfo = (emptyBuildInfo { cppOptions = ["-DVERSION="++hash] }) :: BuildInfo
204 return (Just buildinfo, [])
208idrisPreBuild args flags = do
209#ifdef mingw32_HOST_OS
210 createDirectoryIfMissingVerbose verbosity True dir
211 windres verbosity ["icons/idris_icon.rc","-o", dir++"idris_icon.o"]
212 return (Nothing, [("idris", emptyBuildInfo { ldOptions = [dir ++ "idris_icon.o"] })])
213 where
214 verbosity = S.fromFlag $ S.buildVerbosity flags
215 dir = S.fromFlagOrDefault "dist" $ S.buildDistPref flags
216#else
217 return (Nothing, [])
218#endif
220idrisBuild _ flags _ local = unless (execOnly (configFlags local)) $ do
221 buildStdLib
222 buildRTS
223 where
224 verbosity = S.fromFlag $ S.buildVerbosity flags
226 buildStdLib = do
227 putStrLn "Building libraries..."
228 makeBuild "libs"
229 where
230 makeBuild dir = make verbosity [ "-C", dir, "build" , "IDRIS=" ++ idrisCmd local]
232 buildRTS = make verbosity (["-C", "rts", "build"] ++
233 gmpflag (usesGMP (configFlags local)))
235 gmpflag False = []
236 gmpflag True = ["GMP=-DIDRIS_GMP"]
240-- -----------------------------------------------------------------------------
241-- Copy/Install
243idrisInstall verbosity copy pkg local = unless (execOnly (configFlags local)) $ do
244 installStdLib
245 installRTS
246 installManPage
247 where
248 target = datadir $ L.absoluteInstallDirs pkg local copy
250 installStdLib = do
251 putStrLn $ "Installing libraries in " ++ target
252 makeInstall "libs" target
254 installRTS = do
255 let target' = target </> "rts"
256 putStrLn $ "Installing run time system in " ++ target'
257 makeInstall "rts" target'
259 installManPage = do
260 let mandest = (mandir $ L.absoluteInstallDirs pkg local copy) ++ "/man1"
261 notice verbosity $ unwords ["Copying man page to", mandest]
262 installOrdinaryFiles verbosity mandest [("man", "idris.1")]
265 makeInstall src target =
266 make verbosity [ "-C", src, "install" , "TARGET=" ++ target, "IDRIS=" ++ idrisCmd local]
268-- -----------------------------------------------------------------------------
269-- Main
271-- Install libraries during both copy and install
272-- See https://github.com/haskell/cabal/issues/709
273main = defaultMainWithHooks $ simpleUserHooks
274 { postClean = idrisClean
275 , postConf = idrisConfigure
276 , preBuild = idrisPreBuild
277 , postBuild = idrisBuild
278 , postCopy = \_ flags pkg local ->
279 idrisInstall (S.fromFlag $ S.copyVerbosity flags)
280 (S.fromFlag $ S.copyDest flags) pkg local
281 , postInst = \_ flags pkg local ->
282 idrisInstall (S.fromFlag $ S.installVerbosity flags)
283 NoCopyDest pkg local
284 , preSDist = idrisPreSDist --do { putStrLn (show args) ; putStrLn (show flags) ; return emptyHookedBuildInfo }
285 , postSDist = idrisPostSDist
286 }