forked from ekmett/rounded
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathSetup.hs
211 lines (175 loc) · 7.46 KB
/
Setup.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
module Main (main) where
import Distribution.Simple
import Distribution.Simple.Program
import Distribution.Simple.Program.Builtin
import Distribution.Simple.Program.Db
import Distribution.Simple.Program.Ar
import Distribution.Simple.Program.Find
import Distribution.Simple.LocalBuildInfo
import Distribution.Simple.Setup
import Distribution.PackageDescription hiding (Flag)
import Distribution.Verbosity
import System.IO
import System.Process
import System.FilePath
import System.Directory
import System.Exit
import Control.Applicative
import Control.Monad
import Data.List
import Data.Monoid
import Data.Maybe
-----------------------------------------------------------------
-- Horrible mess of semi-general code
--
-- Not particularly thread safe, but the whole notion of a current directory isn't either
inDirectory :: FilePath -> IO r -> IO r
inDirectory dir action = do
old <- getCurrentDirectory
setCurrentDirectory dir
res <- action
setCurrentDirectory old
return res
mpfrRoot = "deps/mpfr"
getMpfrDist = do
canonicalizePath "./deps/mpfr"
pathsWithSuffix :: String -> FilePath -> IO [FilePath]
pathsWithSuffix suffix path = do
files <- getDirectoryContents path
return $ map (path </>) (filter (suffix `isSuffixOf`) files)
-- TODO: support Windows nicely
runOrBomb :: FilePath -> [String] -> IO ()
runOrBomb cmd args = do
(c, out, err) <- readProcessWithExitCode cmd args ""
case c of
ExitSuccess -> return ()
ExitFailure e -> do
hPutStrLn stderr $ "Command \"" ++ unwords (cmd:args) ++ "\" failed with exit code: " ++ show e
hPutStrLn stdout $ out
hPutStrLn stderr $ err
exitWith $ ExitFailure e
getConfigDist :: ConfigFlags -> IO FilePath
getConfigDist flags = do
let Flag relDistDir = Flag defaultDistPref `mappend` configDistPref flags
canonicalizePath relDistDir
getBuildDist :: BuildFlags -> IO FilePath
getBuildDist flags = do
let Flag relDistDir = Flag defaultDistPref `mappend` buildDistPref flags
canonicalizePath relDistDir
createDirectory' dir = do
exists <- doesDirectoryExist $ dir
unless exists $ createDirectory dir -- let's hope nobody creates the directory first!
configureMpfr :: FilePath -> IO ()
configureMpfr distDir =
inDirectory mpfrRoot $ do
putStrLn $ "--> Configuring MPFR..."
runOrBomb "sh" ["configure", "--with-gmp=/usr/local", "--prefix=" ++ distDir]
makeMpfr :: FilePath -> IO ()
makeMpfr distDir =
inDirectory mpfrRoot $ do
putStrLn $ "--> Building MPFR..."
runOrBomb "make" ["-j4"]
runOrBomb "make" ["install"]
mpfrHooks :: UserHooks
mpfrHooks = autoconfUserHooks
{ preConf = mpfrPreConf
, postConf = mpfrPostConf
, confHook = mpfrConfHook
, preBuild = mpfrPreBuild
, buildHook = mpfrBuildHook
, postBuild = mpfrPostBuild
, postClean = mpfrPostClean
-- , sDistHook = mpfrSDist
}
where
mpfrConfHook (pkg, pbi) flags = do
--distDir <- getConfigDist flags
mpfrDist <- getMpfrDist
lbi <- confHook autoconfUserHooks (pkg, pbi) flags
let lpd = localPkgDescr lbi
lib = fromJust (library lpd)
libbi = libBuildInfo lib
libbi' = libbi { extraLibDirs = (mpfrDist </> "lib") : extraLibDirs libbi }
lib' = lib { libBuildInfo = libbi' }
lpd' = lpd { library = Just lib' }
return lbi { localPkgDescr = lpd' }
-- We need to create the "include" directory at some point, but we're doing it this early to make cabal
-- shut up about it not being present.
mpfrPreConf args flags = do
distDir <- getConfigDist flags
mpfrDist <- getMpfrDist
createDirectory' $ mpfrDist </> "include"
createDirectory' $ mpfrDist </> "lib"
createDirectory' $ distDir </> "tmp"
createDirectory' $ distDir </> "tmp_p"
return emptyHookedBuildInfo
mpfrPostConf args flags pkg_descr lbi = do
postConf simpleUserHooks args flags pkg_descr lbi
distDir <- getConfigDist flags
mpfrDist <- getMpfrDist
configureMpfr mpfrDist
mpfrPreBuild args flags = do
preBuild simpleUserHooks args flags
distDir <- getBuildDist flags
mpfrDist <- getMpfrDist
makeMpfr mpfrDist
let modified = emptyBuildInfo { extraLibs = ["mpfrPIC"]
, extraLibDirs = [distDir </> "libtmp"]
, includeDirs = [mpfrDist </> "include"]
}
return (Just modified, snd emptyHookedBuildInfo)
mpfrBuildHook pkg_descr lbi hooks flags = do
distDir <- getBuildDist flags
mpfrDist <- getMpfrDist
(ar, _) <- requireProgram silent arProgram defaultProgramDb
let lbi' = lbi { withPrograms = updateProgram ar (withPrograms lbi) }
putStrLn $ "Determining MPFR constants..."
programExists <- doesFileExist $ mpfrDist </> "mkMpfrDerivedConstants"
unless programExists $ do
Just gcc <- programFindLocation gccProgram normal defaultProgramSearchPath
runOrBomb gcc ["cbits/mkMpfrDerivedConstants.c", "-I" ++ mpfrDist </> "include", "-o", mpfrDist </> "mkMpfrDerivedConstants"]
headerExists <- doesFileExist $ mpfrDist </> "include" </> "MpfrDerivedConstants.h"
unless headerExists $ do
header <- readProcess (mpfrDist </> "mkMpfrDerivedConstants") [] ""
writeFile (mpfrDist </> "include" </> "MpfrDerivedConstants.h") header
createDirectory' $ distDir </> "libtmp"
picObjects <- pathsWithSuffix ".o" $ mpfrRoot </> "src" </> ".libs"
createArLibArchive silent lbi' (distDir </> "libtmp" </> "libmpfrPIC.a") picObjects
runOrBomb "ranlib" [distDir </> "libtmp" </> "libmpfrPIC.a"]
buildHook simpleUserHooks pkg_descr lbi' hooks flags
mpfrPostBuild args flags pkg_descr lbi = do
distDir <- getBuildDist flags
mpfrDist <- getMpfrDist
(ar, _) <- requireProgram silent arProgram defaultProgramDb
-- (ranlib, _) <- requireProgram silent ranlibProgram defaultProgramDb
let lbi' = lbi { withPrograms = updateProgram ar (withPrograms lbi) }
putStrLn "Mangling static library..."
inDirectory (distDir </> "tmp") $ do
runOrBomb "ar" ["-x", distDir </> "build" </> "libHShaskell-mpfr-0.1.a"]
runOrBomb "ar" ["-x", mpfrDist </> "lib" </> "libmpfr.a"]
objects <- pathsWithSuffix ".o" $ distDir </> "tmp"
--forM_ objects $ \o -> do
-- runOrBomb "mv" [o, o <.> "tmp"]
-- runOrBomb "objcopy" ["--redefine-syms=haskell-mpfr.rename", o <.> "tmp", o]
createArLibArchive silent lbi' (distDir </> "build" </> "libHShaskell-mpfr-0.1.a") objects
runOrBomb "ranlib" [distDir </> "build" </> "libHShaskell-mpfr-0.1.a"]
profExists <- doesFileExist $ distDir </> "build" </> "libHShaskell-mpfr-0.1_p.a"
when profExists $ do
putStrLn "Mangling static library (prof)..."
inDirectory (distDir </> "tmp_p") $ do
runOrBomb "ar" ["-x", distDir </> "build" </> "libHShaskell-mpfr-0.1_p.a"]
runOrBomb "ar" ["-x", mpfrDist </> "lib" </> "libmpfr.a"]
objects <- pathsWithSuffix "o" $ distDir </> "tmp_p"
--forM_ objects $ \o -> do
-- runOrBomb "mv" [o, o <.> "tmp_p"]
-- runOrBomb "objcopy" ["--redefine-syms=haskell-mpfr.rename", o <.> "tmp_p", o]
createArLibArchive silent lbi' (distDir </> "build" </> "libHShaskell-mpfr-0.1_p.a") objects
runOrBomb "ranlib" [distDir </> "build" </> "libHShaskell-mpfr-0.1_p.a"]
postBuild simpleUserHooks args flags pkg_descr lbi
mpfrPostClean args flags pkg_descr _ = do
inDirectory mpfrRoot (readProcessWithExitCode "make" ["distclean"] "")
return ()
{- mpfrSDist pkg_descr mlbi hooks flags = do
-}
main :: IO ()
main = defaultMainWithHooks mpfrHooks