-
Notifications
You must be signed in to change notification settings - Fork 0
/
Shakefile.hs
230 lines (200 loc) · 7.93 KB
/
Shakefile.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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
import Data.List.Extra
import System.Exit
import Control.Monad
import Control.Concurrent.MVar
import Development.Shake
import Development.Shake.Util
import Development.Shake.Classes
import Development.Shake.FilePath
import System.Environment (lookupEnv)
newtype OcamlOrdOracle = OcamlOrdOracle String
deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
newtype OcamlOrdOracleN = OcamlOrdOracleN String
deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
newtype OcamlCmdLineOracle = OcamlCmdLineOracle String
deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
newtype OcamlCmdLineOracleN = OcamlCmdLineOracleN String
deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
newtype CCmdLineOracle = CCmdLineOracle String
deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
newtype GitDescribeOracle = GitDescribeOracle ()
deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
outdir = "build"
mudir = "mupdf"
inOutDir s = outdir </> s
egl = False
ocamlc = "ocamlc.opt"
ocamlopt = "ocamlopt.opt"
ocamldep = "ocamldep.opt"
ocamlflags = "-warn-error +a -w +a -g -safe-string -strict-sequence"
ocamlflagstbl = [("main", ("-I lablGL", "sed -f pp.sed", ["pp.sed"]))
,("config", ("-I lablGL", "", []))
]
cflags = "-Wall -Werror -D_GNU_SOURCE -O\
\ -g -std=c99 -pedantic-errors\
\ -Wunused-parameter -Wsign-compare -Wshadow\
\ -DVISAVIS -DCSS_HACK_TO_READ_EPUBS_COMFORTABLY"
++ (if egl then " -DUSE_EGL" else "")
cflagstbl =
[("link.o"
,"-I " ++ mudir ++ "/include -I "
++ mudir ++ "/thirdparty/freetype/include -Wextra")
]
cclib ty =
"-lGL -lX11 -lmupdf -lmupdfthird -lpthread -L" ++ mudir </> "build" </> ty
++ " -lcrypto" ++ (if egl then " -lEGL" else "")
cclib_native = cclib "native"
cclib_release = cclib "release"
getincludes :: [String] -> [String]
getincludes [] = []
getincludes ("-I":arg:tl) = arg : getincludes tl
getincludes (_:tl) = getincludes tl
isabsinc :: String -> Bool
isabsinc [] = False
isabsinc (hd:_) = hd == '+' || hd == '/'
fixincludes [] = []
fixincludes ("-I":d:tl)
| isabsinc d = "-I":d:fixincludes tl
| otherwise = "-I":inOutDir d:fixincludes tl
fixincludes (e:tl) = e:fixincludes tl
ocamlKey comp tbl key
| "lablGL/" `isPrefixOf` key =
(comp, ocamlflags ++ " -w -44 -I lablGL", [], [])
| otherwise = case lookup (dropExtension key) tbl of
Nothing -> (comp, ocamlflags, [], [])
Just (f, [], deps) -> (comp, ocamlflags ++ " " ++ f, [], deps)
Just (f, pp, deps) -> (comp, ocamlflags ++ " " ++ f, ["-pp", pp], deps)
cKey1 key | "lablGL/" `isPrefixOf` key = "-Wno-pointer-sign -O2"
| otherwise = case lookup key cflagstbl of
Nothing -> cflags
Just f -> f ++ " " ++ cflags
cKey Nothing key = cKey1 key
cKey (Just flags) key = flags ++ " " ++ cKey1 key
fixppfile s ("File":_:tl) = ("File \"" ++ s ++ "\","):tl
fixppfile _ l = l
fixpp :: String -> String -> String
fixpp r s = unlines [unwords $ fixppfile r $ words x | x <- lines s]
ppppe ExitSuccess _ _ = return ()
ppppe _ src emsg = error $ fixpp src emsg
needsrc key suff = do
let src' = key -<.> suff
let src = if src' == "help.ml" then inOutDir src' else src'
need [src]
return src
depscaml flags ppflags src = do
(Stdout stdout, Stderr emsg, Exit ex) <-
cmd ocamldep "-one-line" incs "-I" outdir ppflags src
ppppe ex src emsg
return stdout
where flagl = words flags
incs = unwords ["-I " ++ d | d <- getincludes flagl, not $ isabsinc d]
compilecaml comp flagl ppflags out src = do
let fixedflags = fixincludes flagl
(Stderr emsg, Exit ex) <-
cmd comp "-c -I" outdir fixedflags "-o" out ppflags src
ppppe ex src emsg
return ()
cmio target suffix oracle ordoracle = do
target %> \out -> do
let key = dropDirectory1 out
src <- needsrc key suffix
(comp, flags, ppflags, deps') <- oracle $ OcamlCmdLineOracle key
let flagl = words flags
let dep = out ++ "_dep"
need $ dep : deps'
ddep <- liftIO $ readFile dep
let deps = deplist $ parseMakefile ddep
need deps
compilecaml comp flagl ppflags out src
target ++ "_dep" %> \out -> do
let ord = dropEnd 4 out
let key = dropDirectory1 ord
src <- needsrc key suffix
(_, flags, ppflags, deps') <- oracle $ OcamlCmdLineOracle key
mkfiledeps <- depscaml flags ppflags src
writeFileChanged out mkfiledeps
let depo = deps ++ [dep -<.> ".cmo" | dep <- deps, fit dep]
where
deps = deplist $ parseMakefile mkfiledeps
fit dep = ext == ".cmi" && base /= baseout
where (base, ext) = splitExtension dep
baseout = dropExtension out
need ((map (++ "_dep") depo) ++ deps')
unit $ ordoracle $ OcamlOrdOracle ord
where
deplist [] = []
deplist ((_, reqs) : _) =
[if takeDirectory1 n == outdir then n else inOutDir n | n <- reqs]
cmx oracle ordoracle =
"//*.cmx" %> \out -> do
let key = dropDirectory1 out
src <- needsrc key ".ml"
(comp, flags, ppflags, deps') <- oracle $ OcamlCmdLineOracleN key
let flagl = words flags
mkfiledeps <- depscaml flags ppflags src
need ((deplist $ parseMakefile mkfiledeps) ++ deps')
unit $ ordoracle $ OcamlOrdOracleN out
compilecaml comp flagl ppflags out src
where
deplist (_ : (_, reqs) : _) =
[if takeDirectory1 n == outdir then n else inOutDir n | n <- reqs]
deplist _ = []
binInOutDir globjs depln target =
inOutDir target %> \out ->
do
need (globjs ++ map inOutDir ["link.o", "main.cmx", "help.cmx"])
cmxs <- liftIO $ readMVar depln
need cmxs
unit $ cmd ocamlopt "-g -I lablGL -o" out
"unix.cmxa str.cmxa" (reverse cmxs)
(inOutDir "link.o") "-cclib" (cclib_release : globjs)
main = do
depl <- newMVar ([] :: [String])
depln <- newMVar ([] :: [String])
envcflags <- lookupEnv "CFLAGS"
shakeArgs shakeOptions { shakeFiles = outdir
, shakeVerbosity = Normal
, shakeChange = ChangeModtimeAndDigest } $ do
want [inOutDir "llpp"]
gitDescribeOracle <- addOracle $ \(GitDescribeOracle ()) -> do
Stdout out <- cmd "git describe --tags --dirty"
return (out :: String)
ocamlOracle <- addOracle $ \(OcamlCmdLineOracle s) ->
return $ ocamlKey ocamlc ocamlflagstbl s
ocamlOracleN <- addOracle $ \(OcamlCmdLineOracleN s) ->
return $ ocamlKey ocamlopt ocamlflagstbl s
ocamlOrdOracle <- addOracle $ \(OcamlOrdOracle s) ->
unless (takeExtension s == ".cmi") $
liftIO $ modifyMVar_ depl $ \l -> return $ s:l
ocamlOrdOracleN <- addOracle $ \(OcamlOrdOracleN s) ->
unless (takeExtension s == ".cmi") $
liftIO $ modifyMVar_ depln $ \l -> return $ s:l
cOracle <- addOracle $ \(CCmdLineOracle s) -> return $ cKey envcflags s
inOutDir "help.ml" %> \out -> do
version <- gitDescribeOracle $ GitDescribeOracle ()
need ["mkhelp.sh", "KEYS"]
Stdout f <- cmd "/bin/sh mkhelp.sh KEYS" version
writeFileChanged out f
"//*.o" %> \out -> do
let key = dropDirectory1 out
flags <- cOracle $ CCmdLineOracle key
let src = key -<.> ".c"
let dep = out -<.> ".d"
unit $ cmd ocamlc "-ccopt"
[flags ++ " -MMD -MF " ++ dep ++ " -o " ++ out] "-c" src
needMakefileDependencies dep
let globjs = map (inOutDir . (++) "lablGL/ml_") ["gl.o", "glarray.o", "raw.o"]
inOutDir "llpp" %> \out -> do
need (globjs ++ map inOutDir ["link.o", "main.cmo", "help.cmo"])
cmos <- liftIO $ readMVar depl
need cmos
unit $ cmd ocamlc "-g -custom -I lablGL -o" out
"unix.cma str.cma" (reverse cmos)
(inOutDir "link.o") "-cclib" (cclib_native : globjs)
binInOutDir globjs depln "llpp.native"
binInOutDir globjs depln "llpp.murel.native"
cmio "//*.cmi" ".mli" ocamlOracle ocamlOrdOracle
cmio "//*.cmo" ".ml" ocamlOracle ocamlOrdOracle
cmx ocamlOracleN ocamlOrdOracleN