Use cmd_
[llpp.git] / Shakefile.hs
blob29c963dd5eef502c88036d533a33e0760c31e580
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
108 deplistE reqs =
109 [if takeDirectory1 n == outdir then n else inOutDir n | n <- reqs]
110 deplist Native (_ : (_, reqs) : _) = deplistE reqs
111 deplist Bytecode ((_, reqs) : _) = deplistE reqs
112 deplist _ _ = []
114 cmio target suffix oracle ordoracle = do
115 target %> \out -> do
116 let key = dropDirectory1 out
117 src <- needsrc key suffix
118 (comp, flags) <- oracle $ OcamlCmdLineOracle key
119 let flagl = words flags
120 let dep = out ++ "_dep"
121 need $ [dep]
122 ddep <- liftIO $ readFile dep
123 let deps = deplist Bytecode $ parseMakefile ddep
124 need deps
125 compilecaml comp flagl out src
126 target ++ "_dep" %> \out -> do
127 let ord = dropEnd 4 out
128 let key = dropDirectory1 ord
129 src <- needsrc key suffix
130 (_, flags) <- oracle $ OcamlCmdLineOracle key
131 mkfiledeps <- depscaml flags src
132 writeFileChanged out mkfiledeps
133 let depo = deps ++ [dep -<.> ".cmo" | dep <- deps, fit dep]
134 where
135 deps = deplist Bytecode $ parseMakefile mkfiledeps
136 fit dep = ext == ".cmi" && base /= baseout
137 where (base, ext) = splitExtension dep
138 baseout = dropExtension out
139 need (map (++ "_dep") depo)
140 unit $ ordoracle $ OcamlOrdOracle ord
142 cmx oracle ordoracle =
143 "//*.cmx" %> \out -> do
144 let key = dropDirectory1 out
145 src <- needsrc key ".ml"
146 (comp, flags) <- oracle $ OcamlCmdLineOracleN key
147 let flagl = words flags
148 mkfiledeps <- depscaml flags src
149 need (deplist Native (parseMakefile mkfiledeps))
150 unit $ ordoracle $ OcamlOrdOracleN out
151 compilecaml comp flagl out src
153 binInOutDir ty globjs depln target =
154 inOutDir target %> \out ->
156 need [inOutDir "help.cmx"]
157 need $ mulibs ty ++ globjs ++ map inOutDir ["link.o", "main.cmx"]
158 cmxs <- liftIO $ readMVar depln
159 need cmxs
160 unit $ cmd ocamlopt "-g -I lablGL -o" out
161 "unix.cmxa str.cmxa" (reverse cmxs)
162 (inOutDir "link.o") "-cclib"
163 ((if ty == "native" then cclibNative else cclibRelease) : globjs)
165 main = do
166 depl <- newMVar ([] :: [String])
167 depln <- newMVar ([] :: [String])
168 envcflags <- lookupEnv "CFLAGS"
169 shakeArgs shakeOptions { shakeFiles = outdir
170 , shakeVerbosity = Normal
171 , shakeChange = ChangeModtimeAndDigest } $ do
172 want [inOutDir "llpp"]
174 gitDescribeOracle <- addOracle $ \(GitDescribeOracle ()) -> do
175 Stdout out <- cmd "git describe --tags --dirty"
176 return (out :: String)
178 ocamlOracle <- addOracle $ \(OcamlCmdLineOracle s) ->
179 return $ ocamlKey ocamlc ocamlflagstbl s
181 ocamlOracleN <- addOracle $ \(OcamlCmdLineOracleN s) ->
182 return $ ocamlKey ocamlopt ocamlflagstbl s
184 ocamlOrdOracle <- addOracle $ \(OcamlOrdOracle s) ->
185 unless (takeExtension s == ".cmi") $
186 liftIO $ modifyMVar_ depl $ \l -> return $ s:l
188 ocamlOrdOracleN <- addOracle $ \(OcamlOrdOracleN s) ->
189 unless (takeExtension s == ".cmi") $
190 liftIO $ modifyMVar_ depln $ \l -> return $ s:l
192 cOracle <- addOracle $ \(CCmdLineOracle s) -> return $ cKey envcflags s
194 inOutDir "help.ml" %> \out -> do
195 version <- gitDescribeOracle $ GitDescribeOracle ()
196 need ["mkhelp.sh", "KEYS"]
197 Stdout f <- cmd "/bin/sh mkhelp.sh KEYS" version
198 writeFileChanged out f
200 "//*.o" %> \out -> do
201 let key = dropDirectory1 out
202 flags <- cOracle $ CCmdLineOracle key
203 let src = key -<.> ".c"
204 let dep = out -<.> ".d"
205 unit $ cmd ocamlc "-ccopt"
206 [flags ++ " -MMD -MF " ++ dep ++ " -o " ++ out] "-c" src
207 needMakefileDependencies dep
209 let globjs = map (inOutDir . (++) "lablGL/ml_") ["gl.o", "glarray.o", "raw.o"]
211 let mulib ty name = do
212 -- perhaps alwaysrerun is in order here?
213 mudir </> "build" </> ty </> name %> \_ -> do
214 unit $ cmd (Cwd "mupdf") ("make build=" ++ ty) "libs"
216 mulib "release" "libmupdf.a"
217 mulib "release" "libmupdfthird.a"
218 mulib "native" "libmupdf.a"
219 mulib "native" "libmupdfthird.a"
221 inOutDir "llpp" %> \out -> do
222 need [inOutDir "help.cmo"]
223 need $ mulibs "native" ++ globjs ++ map inOutDir ["link.o", "main.cmo"]
224 cmos <- liftIO $ readMVar depl
225 need cmos
226 unit $ cmd ocamlc "-g -custom -I lablGL -o" out
227 "unix.cma str.cma" (reverse cmos)
228 (inOutDir "link.o") "-cclib" (cclibNative : globjs)
230 binInOutDir "native" globjs depln "llpp.native"
231 binInOutDir "release" globjs depln "llpp.murel.native"
233 cmio "//*.cmi" ".mli" ocamlOracle ocamlOrdOracle
234 cmio "//*.cmo" ".ml" ocamlOracle ocamlOrdOracle
235 cmx ocamlOracleN ocamlOrdOracleN