Sync with upstream
[llpp/slowscroll.git] / Shakefile.hs
blob15b5d1c85c60091aa0f8950de7166a4950cbe55a
1 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
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 data Bt = Native | Bytecode
27 outdir = "build"
28 mudir = "mupdf"
29 mulibs ty = [mudir </> "build" </> ty </> "libmupdf.a"
30 ,mudir </> "build" </> ty </> "libmupdfthird.a"]
31 inOutDir s = outdir </> s
32 egl = False
34 ocamlc = "ocamlc.opt"
35 ocamlopt = "ocamlopt.opt"
36 ocamldep = "ocamldep.opt"
37 ocamlflags = "-warn-error +a -w +a -g -safe-string -strict-sequence"
38 ocamlflagstbl = [("main", "-I lablGL")
39 ,("config", "-I lablGL")]
40 cflags = "-Wall -Werror -D_GNU_SOURCE -O\
41 \ -g -std=c99 -pedantic-errors\
42 \ -Wunused-parameter -Wsign-compare -Wshadow"
43 ++ (if egl then " -DUSE_EGL" else "")
44 cflagstbl =
45 [("link.o"
46 ,"-I " ++ mudir ++ "/include -I "
47 ++ mudir ++ "/thirdparty/freetype/include -Wextra")
49 cclib ty =
50 "-lGL -lX11 -lmupdf -lmupdfthird -lpthread -L" ++ mudir </> "build" </> ty
51 ++ " -lcrypto" ++ (if egl then " -lEGL" else "")
52 cclibNative = cclib "native"
53 cclibRelease = cclib "release"
55 getincludes :: [String] -> [String]
56 getincludes [] = []
57 getincludes ("-I":arg:tl) = arg : getincludes tl
58 getincludes (_:tl) = getincludes tl
60 isabsinc :: String -> Bool
61 isabsinc [] = False
62 isabsinc (hd:_) = hd == '+' || hd == '/'
64 fixincludes [] = []
65 fixincludes ("-I":d:tl)
66 | isabsinc d = "-I":d:fixincludes tl
67 | otherwise = "-I":inOutDir d:fixincludes tl
68 fixincludes (e:tl) = e:fixincludes tl
70 ocamlKey comp tbl key
71 | "lablGL/" `isPrefixOf` key = (comp, ocamlflags ++ " -w -44 -I lablGL")
72 | otherwise = case lookup (dropExtension key) tbl of
73 Nothing -> (comp, ocamlflags)
74 Just f -> (comp, ocamlflags ++ " " ++ f)
76 cKey1 key | "lablGL/" `isPrefixOf` key = "-Wno-pointer-sign -O2"
77 | otherwise = case lookup key cflagstbl of
78 Nothing -> cflags
79 Just f -> f ++ " " ++ cflags
81 cKey Nothing key = cKey1 key
82 cKey (Just flags) key = flags ++ " " ++ cKey1 key
84 needsrc key suff = do
85 let src' = key -<.> suff
86 let src = if src' == "help.ml" then inOutDir src' else src'
87 need [src]
88 return src
90 depscaml flags src = do
91 (Stdout stdout) <- cmd ocamldep "-one-line" incs "-I" outdir src
92 return stdout
93 where flagl = words flags
94 incs = unwords ["-I " ++ d | d <- getincludes flagl, not $ isabsinc d]
96 compilecaml comp flagl out src = do
97 let fixedflags = fixincludes flagl
98 () <- cmd comp "-c -I" outdir fixedflags "-o" out src
99 return ()
101 deplistE reqs =
102 [if takeDirectory1 n == outdir then n else inOutDir n | n <- reqs]
103 deplist Native (_ : (_, reqs) : _) = deplistE reqs
104 deplist Bytecode ((_, reqs) : _) = deplistE reqs
105 deplist _ _ = []
107 cmio target suffix oracle ordoracle = do
108 target %> \out -> do
109 let key = dropDirectory1 out
110 src <- needsrc key suffix
111 (comp, flags) <- oracle $ OcamlCmdLineOracle key
112 let flagl = words flags
113 let dep = out ++ "_dep"
114 need $ [dep]
115 ddep <- liftIO $ readFile dep
116 let deps = deplist Bytecode $ parseMakefile ddep
117 need deps
118 compilecaml comp flagl out src
119 target ++ "_dep" %> \out -> do
120 let ord = dropEnd 4 out
121 let key = dropDirectory1 ord
122 src <- needsrc key suffix
123 (_, flags) <- oracle $ OcamlCmdLineOracle key
124 mkfiledeps <- depscaml flags src
125 writeFileChanged out mkfiledeps
126 let depo = deps ++ [dep -<.> ".cmo" | dep <- deps, fit dep]
127 where
128 deps = deplist Bytecode $ parseMakefile mkfiledeps
129 fit dep = ext == ".cmi" && base /= baseout
130 where (base, ext) = splitExtension dep
131 baseout = dropExtension out
132 need (map (++ "_dep") depo)
133 unit $ ordoracle $ OcamlOrdOracle ord
135 cmx oracle ordoracle =
136 "//*.cmx" %> \out -> do
137 let key = dropDirectory1 out
138 src <- needsrc key ".ml"
139 (comp, flags) <- oracle $ OcamlCmdLineOracleN key
140 let flagl = words flags
141 mkfiledeps <- depscaml flags src
142 need (deplist Native (parseMakefile mkfiledeps))
143 unit $ ordoracle $ OcamlOrdOracleN out
144 compilecaml comp flagl out src
146 binInOutDir ty globjs depln target =
147 inOutDir target %> \out ->
149 need [inOutDir "help.cmx"]
150 need $ mulibs ty ++ globjs ++ map inOutDir ["link.o", "main.cmx"]
151 cmxs <- liftIO $ readMVar depln
152 need cmxs
153 unit $ cmd ocamlopt "-g -I lablGL -o" out
154 "unix.cmxa str.cmxa" (reverse cmxs)
155 (inOutDir "link.o") "-cclib" (cclibRelease : globjs)
157 main = do
158 depl <- newMVar ([] :: [String])
159 depln <- newMVar ([] :: [String])
160 envcflags <- lookupEnv "CFLAGS"
161 shakeArgs shakeOptions { shakeFiles = outdir
162 , shakeVerbosity = Normal
163 , shakeChange = ChangeModtimeAndDigest } $ do
164 want [inOutDir "llpp"]
166 gitDescribeOracle <- addOracle $ \(GitDescribeOracle ()) -> do
167 Stdout out <- cmd "git describe --tags --dirty"
168 return (out :: String)
170 ocamlOracle <- addOracle $ \(OcamlCmdLineOracle s) ->
171 return $ ocamlKey ocamlc ocamlflagstbl s
173 ocamlOracleN <- addOracle $ \(OcamlCmdLineOracleN s) ->
174 return $ ocamlKey ocamlopt ocamlflagstbl s
176 ocamlOrdOracle <- addOracle $ \(OcamlOrdOracle s) ->
177 unless (takeExtension s == ".cmi") $
178 liftIO $ modifyMVar_ depl $ \l -> return $ s:l
180 ocamlOrdOracleN <- addOracle $ \(OcamlOrdOracleN s) ->
181 unless (takeExtension s == ".cmi") $
182 liftIO $ modifyMVar_ depln $ \l -> return $ s:l
184 cOracle <- addOracle $ \(CCmdLineOracle s) -> return $ cKey envcflags s
186 inOutDir "help.ml" %> \out -> do
187 version <- gitDescribeOracle $ GitDescribeOracle ()
188 need ["mkhelp.sh", "KEYS"]
189 Stdout f <- cmd "/bin/sh mkhelp.sh KEYS" version
190 writeFileChanged out f
192 "//*.o" %> \out -> do
193 let key = dropDirectory1 out
194 flags <- cOracle $ CCmdLineOracle key
195 let src = key -<.> ".c"
196 let dep = out -<.> ".d"
197 unit $ cmd ocamlc "-ccopt"
198 [flags ++ " -MMD -MF " ++ dep ++ " -o " ++ out] "-c" src
199 needMakefileDependencies dep
201 let globjs = map (inOutDir . (++) "lablGL/ml_") ["gl.o", "glarray.o", "raw.o"]
203 let mulib ty name = do
204 -- perhaps alwaysrerun is in order here?
205 mudir </> "build" </> ty </> name %> \_ -> do
206 unit $ cmd (Cwd "mupdf") ("make build=" ++ ty) "libs"
208 mulib "release" "libmupdf.a"
209 mulib "release" "libmupdfthird.a"
210 mulib "native" "libmupdf.a"
211 mulib "native" "libmupdfthird.a"
213 inOutDir "llpp" %> \out -> do
214 need [inOutDir "help.cmo"]
215 need $ mulibs "native" ++ globjs ++ map inOutDir ["link.o", "main.cmo"]
216 cmos <- liftIO $ readMVar depl
217 need cmos
218 unit $ cmd ocamlc "-g -custom -I lablGL -o" out
219 "unix.cma str.cma" (reverse cmos)
220 (inOutDir "link.o") "-cclib" (cclibNative : globjs)
222 binInOutDir "native" globjs depln "llpp.native"
223 binInOutDir "release" globjs depln "llpp.murel.native"
225 cmio "//*.cmi" ".mli" ocamlOracle ocamlOrdOracle
226 cmio "//*.cmo" ".ml" ocamlOracle ocamlOrdOracle
227 cmx ocamlOracleN ocamlOrdOracleN