Update for shake 0.16
[llpp/slowscroll.git] / Shakefile.hs
blobd25590c51fdad5ecd984fb8ad57e03f107645f4f
1 {-# LANGUAGE GeneralizedNewtypeDeriving, TypeFamilies #-}
2 {-# OPTIONS_GHC -fno-warn-missing-signatures #-}
3 import Data.List.Extra
4 import Control.Monad
5 import Control.Concurrent.MVar
6 import Development.Shake
7 import Development.Shake.Util
8 import Development.Shake.Classes
9 import Development.Shake.FilePath
10 import System.Environment (lookupEnv)
12 newtype OcamlOrdOracle = OcamlOrdOracle String
13 deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
14 newtype OcamlOrdOracleN = OcamlOrdOracleN String
15 deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
16 newtype OcamlCmdLineOracle = OcamlCmdLineOracle String
17 deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
18 newtype OcamlCmdLineOracleN = OcamlCmdLineOracleN String
19 deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
20 newtype CCmdLineOracle = CCmdLineOracle String
21 deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
22 newtype GitDescribeOracle = GitDescribeOracle ()
23 deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
25 type instance RuleResult GitDescribeOracle = String
26 type instance RuleResult OcamlCmdLineOracle = (String, String)
27 type instance RuleResult OcamlCmdLineOracleN = (String, String)
28 type instance RuleResult OcamlOrdOracle = ()
29 type instance RuleResult OcamlOrdOracleN = ()
30 type instance RuleResult CCmdLineOracle = String
32 data Bt = Native | Bytecode
34 outdir = "build"
35 mudir = "mupdf"
36 mulibs ty = [mudir </> "build" </> ty </> "libmupdf.a"
37 ,mudir </> "build" </> ty </> "libmupdfthird.a"]
38 inOutDir s = outdir </> s
39 egl = False
41 ocamlc = "ocamlc.opt"
42 ocamlopt = "ocamlopt.opt"
43 ocamldep = "ocamldep.opt"
44 ocamlflags = "-warn-error +a -w +a -g -safe-string -strict-sequence"
45 ocamlflagstbl = [("main", "-I lablGL -I wsi/x11")
46 ,("wsi/x11/wsi", "-I wsi/x11")
47 ,("config", "-I lablGL -I wsi/x11")]
48 cflags = "-Wall -Werror -D_GNU_SOURCE -O\
49 \ -g -std=c99 -pedantic-errors\
50 \ -Wunused-parameter -Wsign-compare -Wshadow"
51 ++ (if egl then " -DUSE_EGL" else "")
52 cflagstbl =
53 [("link.o"
54 ,"-I " ++ mudir ++ "/include -I "
55 ++ mudir ++ "/thirdparty/freetype/include -Wextra")
57 cclib ty =
58 "-lGL -lX11 -lmupdf -lmupdfthird -lpthread -L" ++ mudir </> "build" </> ty
59 ++ " -lcrypto" ++ (if egl then " -lEGL" else "")
60 cclibNative = cclib "native"
61 cclibRelease = cclib "release"
63 getincludes :: [String] -> [String]
64 getincludes [] = []
65 getincludes ("-I":arg:tl) = arg : getincludes tl
66 getincludes (_:tl) = getincludes tl
68 isabsinc :: String -> Bool
69 isabsinc [] = False
70 isabsinc (hd:_) = hd == '+' || hd == '/'
72 fixincludes [] = []
73 fixincludes ("-I":d:tl)
74 | isabsinc d = "-I":d:fixincludes tl
75 | otherwise = "-I":inOutDir d:fixincludes tl
76 fixincludes (e:tl) = e:fixincludes tl
78 ocamlKey comp tbl key
79 | "lablGL/" `isPrefixOf` key = (comp, ocamlflags ++ " -w -44 -I lablGL")
80 | otherwise = case lookup (dropExtension key) tbl of
81 Nothing -> (comp, ocamlflags)
82 Just f -> (comp, ocamlflags ++ " " ++ f)
84 cKey1 key | "lablGL/" `isPrefixOf` key = "-Wno-pointer-sign -O2"
85 | otherwise = case lookup key cflagstbl of
86 Nothing -> cflags
87 Just f -> f ++ " " ++ cflags
89 cKey Nothing key = cKey1 key
90 cKey (Just flags) key = flags ++ " " ++ cKey1 key
92 needsrc key suff = do
93 let src' = key -<.> suff
94 let src = if src' == "help.ml" then inOutDir src' else src'
95 need [src]
96 return src
98 depscaml flags src = do
99 (Stdout stdout) <- cmd ocamldep "-one-line" incs "-I" outdir src
100 return stdout
101 where flagl = words flags
102 incs = unwords ["-I " ++ d | d <- getincludes flagl, not $ isabsinc d]
104 compilecaml comp flagl out src = do
105 let fixedflags = fixincludes flagl
106 () <- cmd comp "-c -I" outdir fixedflags "-o" out src
107 return ()
109 deplistE reqs =
110 [if takeDirectory1 n == outdir then n else inOutDir n | n <- reqs]
111 deplist Native (_ : (_, reqs) : _) = deplistE reqs
112 deplist Bytecode ((_, reqs) : _) = deplistE reqs
113 deplist _ _ = []
115 cmio target suffix oracle ordoracle = do
116 target %> \out -> do
117 let key = dropDirectory1 out
118 src <- needsrc key suffix
119 (comp, flags) <- oracle $ OcamlCmdLineOracle key
120 let flagl = words flags
121 let dep = out ++ "_dep"
122 need $ [dep]
123 ddep <- liftIO $ readFile dep
124 let deps = deplist Bytecode $ parseMakefile ddep
125 need deps
126 compilecaml comp flagl out src
127 target ++ "_dep" %> \out -> do
128 let ord = dropEnd 4 out
129 let key = dropDirectory1 ord
130 src <- needsrc key suffix
131 (_, flags) <- oracle $ OcamlCmdLineOracle key
132 mkfiledeps <- depscaml flags src
133 writeFileChanged out mkfiledeps
134 let depo = deps ++ [dep -<.> ".cmo" | dep <- deps, fit dep]
135 where
136 deps = deplist Bytecode $ parseMakefile mkfiledeps
137 fit dep = ext == ".cmi" && base /= baseout
138 where (base, ext) = splitExtension dep
139 baseout = dropExtension out
140 need (map (++ "_dep") depo)
141 unit $ ordoracle $ OcamlOrdOracle ord
143 cmx oracle ordoracle =
144 "//*.cmx" %> \out -> do
145 let key = dropDirectory1 out
146 src <- needsrc key ".ml"
147 (comp, flags) <- oracle $ OcamlCmdLineOracleN key
148 let flagl = words flags
149 mkfiledeps <- depscaml flags src
150 need (deplist Native (parseMakefile mkfiledeps))
151 unit $ ordoracle $ OcamlOrdOracleN out
152 compilecaml comp flagl out src
154 binInOutDir ty globjs depln target =
155 inOutDir target %> \out ->
157 need [inOutDir "help.cmx"]
158 need $ mulibs ty ++ globjs ++ map inOutDir ["link.o", "main.cmx"]
159 cmxs <- liftIO $ readMVar depln
160 need cmxs
161 unit $ cmd ocamlopt "-g -I lablGL -o" out
162 "unix.cmxa str.cmxa" (reverse cmxs)
163 (inOutDir "link.o") "-cclib"
164 ((if ty == "native" then cclibNative else cclibRelease) : globjs)
166 main = do
167 depl <- newMVar ([] :: [String])
168 depln <- newMVar ([] :: [String])
169 envcflags <- lookupEnv "CFLAGS"
170 shakeArgs shakeOptions { shakeFiles = outdir
171 , shakeVerbosity = Normal
172 , shakeChange = ChangeModtimeAndDigest } $ do
173 want [inOutDir "llpp"]
175 gitDescribeOracle <- addOracle $ \(GitDescribeOracle ()) -> do
176 Stdout out <- cmd "git describe --tags --dirty"
177 return (out :: String)
179 ocamlOracle <- addOracle $ \(OcamlCmdLineOracle s) ->
180 return $ ocamlKey ocamlc ocamlflagstbl s
182 ocamlOracleN <- addOracle $ \(OcamlCmdLineOracleN s) ->
183 return $ ocamlKey ocamlopt ocamlflagstbl s
185 ocamlOrdOracle <- addOracle $ \(OcamlOrdOracle s) ->
186 unless (takeExtension s == ".cmi") $
187 liftIO $ modifyMVar_ depl $ \l -> return $ s:l
189 ocamlOrdOracleN <- addOracle $ \(OcamlOrdOracleN s) ->
190 unless (takeExtension s == ".cmi") $
191 liftIO $ modifyMVar_ depln $ \l -> return $ s:l
193 cOracle <- addOracle $ \(CCmdLineOracle s) -> return $ cKey envcflags s
195 inOutDir "help.ml" %> \out -> do
196 version <- gitDescribeOracle $ GitDescribeOracle ()
197 need ["mkhelp.sh", "KEYS"]
198 Stdout f <- cmd "/bin/sh mkhelp.sh KEYS" version
199 writeFileChanged out f
201 "//*.o" %> \out -> do
202 let key = dropDirectory1 out
203 flags <- cOracle $ CCmdLineOracle key
204 let src = key -<.> ".c"
205 let dep = out -<.> ".d"
206 unit $ cmd ocamlc "-ccopt"
207 [flags ++ " -MMD -MF " ++ dep ++ " -o " ++ out] "-c" src
208 needMakefileDependencies dep
210 let globjs = map (inOutDir . (++) "lablGL/ml_") ["gl.o", "glarray.o", "raw.o"]
212 let mulib ty name = do
213 -- perhaps alwaysrerun is in order here?
214 mudir </> "build" </> ty </> name %> \_ -> do
215 unit $ cmd (Cwd "mupdf") ("make build=" ++ ty) "libs"
217 mulib "release" "libmupdf.a"
218 mulib "release" "libmupdfthird.a"
219 mulib "native" "libmupdf.a"
220 mulib "native" "libmupdfthird.a"
222 inOutDir "llpp" %> \out -> do
223 need [inOutDir "help.cmo"]
224 need $ mulibs "native" ++ globjs ++ map inOutDir ["link.o", "main.cmo"]
225 cmos <- liftIO $ readMVar depl
226 need cmos
227 unit $ cmd ocamlc "-g -custom -I lablGL -o" out
228 "unix.cma str.cma" (reverse cmos)
229 (inOutDir "link.o") "-cclib" (cclibNative : globjs)
231 binInOutDir "native" globjs depln "llpp.native"
232 binInOutDir "release" globjs depln "llpp.murel.native"
234 cmio "//*.cmi" ".mli" ocamlOracle ocamlOrdOracle
235 cmio "//*.cmo" ".ml" ocamlOracle ocamlOrdOracle
236 cmx ocamlOracleN ocamlOrdOracleN