Fix some stylistic,semantic and navigational issues
[llpp.git] / Shakefile.hs
blob8b2214edb412b3bf6d479076a41f7fb1ce961236
1 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
2 {-# OPTIONS_GHC -fno-warn-missing-signatures #-}
3 import Data.List.Extra
4 import System.Exit
5 import Control.Monad
6 import Control.Concurrent.MVar
7 import Development.Shake
8 import Development.Shake.Util
9 import Development.Shake.Classes
10 import Development.Shake.FilePath
11 import System.Environment (lookupEnv)
13 newtype OcamlOrdOracle = OcamlOrdOracle String
14 deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
15 newtype OcamlOrdOracleN = OcamlOrdOracleN String
16 deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
17 newtype OcamlCmdLineOracle = OcamlCmdLineOracle String
18 deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
19 newtype OcamlCmdLineOracleN = OcamlCmdLineOracleN String
20 deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
21 newtype CCmdLineOracle = CCmdLineOracle String
22 deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
23 newtype GitDescribeOracle = GitDescribeOracle ()
24 deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
26 data Bt = Native | Bytecode
28 outdir = "build"
29 mudir = "mupdf"
30 inOutDir s = outdir </> s
31 egl = False
33 ocamlc = "ocamlc.opt"
34 ocamlopt = "ocamlopt.opt"
35 ocamldep = "ocamldep.opt"
36 ocamlflags = "-warn-error +a -w +a -g -safe-string -strict-sequence"
37 ocamlflagstbl = [("main", ("-I lablGL", "sed -f pp.sed", ["pp.sed"]))
38 ,("config", ("-I lablGL", "", []))
40 cflags = "-Wall -Werror -D_GNU_SOURCE -O\
41 \ -g -std=c99 -pedantic-errors\
42 \ -Wunused-parameter -Wsign-compare -Wshadow\
43 \ -DVISAVIS -DCSS_HACK_TO_READ_EPUBS_COMFORTABLY"
44 ++ (if egl then " -DUSE_EGL" else "")
45 cflagstbl =
46 [("link.o"
47 ,"-I " ++ mudir ++ "/include -I "
48 ++ mudir ++ "/thirdparty/freetype/include -Wextra")
50 cclib ty =
51 "-lGL -lX11 -lmupdf -lmupdfthird -lpthread -L" ++ mudir </> "build" </> ty
52 ++ " -lcrypto" ++ (if egl then " -lEGL" else "")
53 cclibNative = cclib "native"
54 cclibRelease = cclib "release"
56 getincludes :: [String] -> [String]
57 getincludes [] = []
58 getincludes ("-I":arg:tl) = arg : getincludes tl
59 getincludes (_:tl) = getincludes tl
61 isabsinc :: String -> Bool
62 isabsinc [] = False
63 isabsinc (hd:_) = hd == '+' || hd == '/'
65 fixincludes [] = []
66 fixincludes ("-I":d:tl)
67 | isabsinc d = "-I":d:fixincludes tl
68 | otherwise = "-I":inOutDir d:fixincludes tl
69 fixincludes (e:tl) = e:fixincludes tl
71 ocamlKey comp tbl key
72 | "lablGL/" `isPrefixOf` key =
73 (comp, ocamlflags ++ " -w -44 -I lablGL", [], [])
74 | otherwise = case lookup (dropExtension key) tbl of
75 Nothing -> (comp, ocamlflags, [], [])
76 Just (f, [], deps) -> (comp, ocamlflags ++ " " ++ f, [], deps)
77 Just (f, pp, deps) -> (comp, ocamlflags ++ " " ++ f, ["-pp", pp], deps)
79 cKey1 key | "lablGL/" `isPrefixOf` key = "-Wno-pointer-sign -O2"
80 | otherwise = case lookup key cflagstbl of
81 Nothing -> cflags
82 Just f -> f ++ " " ++ cflags
84 cKey Nothing key = cKey1 key
85 cKey (Just flags) key = flags ++ " " ++ cKey1 key
87 fixppfile s ("File":_:tl) = ("File \"" ++ s ++ "\","):tl
88 fixppfile _ l = l
90 fixpp :: String -> String -> String
91 fixpp r s = unlines [unwords $ fixppfile r $ words x | x <- lines s]
93 ppppe ExitSuccess _ _ = return ()
94 ppppe _ src emsg = error $ fixpp src emsg
96 needsrc key suff = do
97 let src' = key -<.> suff
98 let src = if src' == "help.ml" then inOutDir src' else src'
99 need [src]
100 return src
102 depscaml flags ppflags src = do
103 (Stdout stdout, Stderr emsg, Exit ex) <-
104 cmd ocamldep "-one-line" incs "-I" outdir ppflags src
105 ppppe ex src emsg
106 return stdout
107 where flagl = words flags
108 incs = unwords ["-I " ++ d | d <- getincludes flagl, not $ isabsinc d]
110 compilecaml comp flagl ppflags out src = do
111 let fixedflags = fixincludes flagl
112 (Stderr emsg, Exit ex) <-
113 cmd comp "-c -I" outdir fixedflags "-o" out ppflags src
114 ppppe ex src emsg
115 return ()
117 deplistE reqs =
118 [if takeDirectory1 n == outdir then n else inOutDir n | n <- reqs]
119 deplist Native (_ : (_, reqs) : _) = deplistE reqs
120 deplist Bytecode ((_, reqs) : _) = deplistE reqs
121 deplist _ _ = []
123 cmio target suffix oracle ordoracle = do
124 target %> \out -> do
125 let key = dropDirectory1 out
126 src <- needsrc key suffix
127 (comp, flags, ppflags, deps') <- oracle $ OcamlCmdLineOracle key
128 let flagl = words flags
129 let dep = out ++ "_dep"
130 need $ dep : deps'
131 ddep <- liftIO $ readFile dep
132 let deps = deplist Bytecode $ parseMakefile ddep
133 need deps
134 compilecaml comp flagl ppflags out src
135 target ++ "_dep" %> \out -> do
136 let ord = dropEnd 4 out
137 let key = dropDirectory1 ord
138 src <- needsrc key suffix
139 (_, flags, ppflags, deps') <- oracle $ OcamlCmdLineOracle key
140 mkfiledeps <- depscaml flags ppflags src
141 writeFileChanged out mkfiledeps
142 let depo = deps ++ [dep -<.> ".cmo" | dep <- deps, fit dep]
143 where
144 deps = deplist Bytecode $ parseMakefile mkfiledeps
145 fit dep = ext == ".cmi" && base /= baseout
146 where (base, ext) = splitExtension dep
147 baseout = dropExtension out
148 need (map (++ "_dep") depo ++ deps')
149 unit $ ordoracle $ OcamlOrdOracle ord
151 cmx oracle ordoracle =
152 "//*.cmx" %> \out -> do
153 let key = dropDirectory1 out
154 src <- needsrc key ".ml"
155 (comp, flags, ppflags, deps') <- oracle $ OcamlCmdLineOracleN key
156 let flagl = words flags
157 mkfiledeps <- depscaml flags ppflags src
158 need (deplist Native (parseMakefile mkfiledeps) ++ deps')
159 unit $ ordoracle $ OcamlOrdOracleN out
160 compilecaml comp flagl ppflags out src
162 binInOutDir globjs depln target =
163 inOutDir target %> \out ->
165 need (globjs ++ map inOutDir ["link.o", "main.cmx", "help.cmx"])
166 cmxs <- liftIO $ readMVar depln
167 need cmxs
168 unit $ cmd ocamlopt "-g -I lablGL -o" out
169 "unix.cmxa str.cmxa" (reverse cmxs)
170 (inOutDir "link.o") "-cclib" (cclibRelease : globjs)
172 main = do
173 depl <- newMVar ([] :: [String])
174 depln <- newMVar ([] :: [String])
175 envcflags <- lookupEnv "CFLAGS"
176 shakeArgs shakeOptions { shakeFiles = outdir
177 , shakeVerbosity = Normal
178 , shakeChange = ChangeModtimeAndDigest } $ do
179 want [inOutDir "llpp"]
181 gitDescribeOracle <- addOracle $ \(GitDescribeOracle ()) -> do
182 Stdout out <- cmd "git describe --tags --dirty"
183 return (out :: String)
185 ocamlOracle <- addOracle $ \(OcamlCmdLineOracle s) ->
186 return $ ocamlKey ocamlc ocamlflagstbl s
188 ocamlOracleN <- addOracle $ \(OcamlCmdLineOracleN s) ->
189 return $ ocamlKey ocamlopt ocamlflagstbl s
191 ocamlOrdOracle <- addOracle $ \(OcamlOrdOracle s) ->
192 unless (takeExtension s == ".cmi") $
193 liftIO $ modifyMVar_ depl $ \l -> return $ s:l
195 ocamlOrdOracleN <- addOracle $ \(OcamlOrdOracleN s) ->
196 unless (takeExtension s == ".cmi") $
197 liftIO $ modifyMVar_ depln $ \l -> return $ s:l
199 cOracle <- addOracle $ \(CCmdLineOracle s) -> return $ cKey envcflags s
201 inOutDir "help.ml" %> \out -> do
202 version <- gitDescribeOracle $ GitDescribeOracle ()
203 need ["mkhelp.sh", "KEYS"]
204 Stdout f <- cmd "/bin/sh mkhelp.sh KEYS" version
205 writeFileChanged out f
207 "//*.o" %> \out -> do
208 let key = dropDirectory1 out
209 flags <- cOracle $ CCmdLineOracle key
210 let src = key -<.> ".c"
211 let dep = out -<.> ".d"
212 unit $ cmd ocamlc "-ccopt"
213 [flags ++ " -MMD -MF " ++ dep ++ " -o " ++ out] "-c" src
214 needMakefileDependencies dep
216 let globjs = map (inOutDir . (++) "lablGL/ml_") ["gl.o", "glarray.o", "raw.o"]
217 inOutDir "llpp" %> \out -> do
218 need (globjs ++ map inOutDir ["link.o", "main.cmo", "help.cmo"])
219 cmos <- liftIO $ readMVar depl
220 need cmos
221 unit $ cmd ocamlc "-g -custom -I lablGL -o" out
222 "unix.cma str.cma" (reverse cmos)
223 (inOutDir "link.o") "-cclib" (cclibNative : globjs)
225 binInOutDir globjs depln "llpp.native"
226 binInOutDir globjs depln "llpp.murel.native"
228 cmio "//*.cmi" ".mli" ocamlOracle ocamlOrdOracle
229 cmio "//*.cmo" ".ml" ocamlOracle ocamlOrdOracle
230 cmx ocamlOracleN ocamlOrdOracleN