Wasn't the best idea
[llpp.git] / Build.hs
blob88292ca40654771161e70ba3514d5fa18933e646
1 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
2 {-# OPTIONS_GHC -fno-warn-missing-signatures #-}
3 import Data.List
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.Config ()
10 import Development.Shake.Classes
11 import Development.Shake.FilePath
13 newtype OcamlOrdOracle = OcamlOrdOracle String
14 deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
15 newtype OcamlCmdLineOracle = OcamlCmdLineOracle String
16 deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
17 newtype CCmdLineOracle = CCmdLineOracle String
18 deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
19 newtype GitDescribeOracle = GitDescribeOracle ()
20 deriving (Show,Typeable,Eq,Hashable,Binary,NFData)
21 data CM = CMO | CMI
23 outdir = "build"
24 mudir = "/home/malc/x/rcs/git/mupdf"
25 inOutDir s = outdir </> s
27 ocamlc = "ocamlc.opt"
28 ocamldep = "ocamldep.opt"
29 ocamlflags = "-warn-error +a -w +a -g -safe-string"
30 ocamlflagstbl = [("main.cmo", ("-I lablGL", "sed -f pp.sed"))
31 ,("config.cmo", ("-I lablGL", ""))
33 cflags = "-Wall -Werror -D_GNU_SOURCE -O\
34 \ -g -std=c99 -pedantic-errors\
35 \ -Wunused-parameter -Wsign-compare -Wshadow"
36 cflagstbl =
37 [("link.o"
38 ,"-I " ++ mudir ++ "/include -I "
39 ++ mudir ++ "/thirdparty/freetype/include -Wextra")
41 cclib = "-lGL -lX11 -lmupdf -lz -lfreetype -ljpeg \
42 \-ljbig2dec -lopenjpeg -lmujs \
43 \-lpthread -L" ++ mudir ++ "/build/native -lcrypto"
45 getincludes :: [String] -> [String]
46 getincludes [] = []
47 getincludes ("-I":arg:tl) = arg : getincludes tl
48 getincludes (_:tl) = getincludes tl
50 isabsinc :: String -> Bool
51 isabsinc [] = False
52 isabsinc (hd:_) = hd == '+' || hd == '/'
54 fixincludes [] = []
55 fixincludes ("-I":d:tl)
56 | isabsinc d = "-I":d:fixincludes tl
57 | otherwise = "-I":inOutDir d:fixincludes tl
58 fixincludes (e:tl) = e:fixincludes tl
60 ocamlKey key | "lablGL/" `isPrefixOf` key = (ocamlc, "-I lablGL", [])
61 | otherwise = case lookup key ocamlflagstbl of
62 Nothing -> (ocamlc, ocamlflags, [])
63 Just (f, []) -> (ocamlc, ocamlflags ++ " " ++ f, [])
64 Just (f, pp) -> (ocamlc, ocamlflags ++ " " ++ f, ["-pp", pp])
66 cKey key | "lablGL/" `isPrefixOf` key = "-Wno-pointer-sign -O2"
67 | otherwise = case lookup key cflagstbl of
68 Nothing -> cflags
69 Just f -> f ++ " " ++ cflags
71 fixppfile :: String -> [String] -> [String]
72 fixppfile s ("File":_:tl) = ("File \"" ++ s ++ "\","):tl
73 fixppfile _ l = l
75 fixpp :: String -> String -> String
76 fixpp r s = unlines [unwords $ fixppfile r $ words x | x <- lines s]
78 cm' t oracle ordoracle =
79 target `op` \out -> do
80 let key = dropDirectory1 out
81 let src' = key -<.> suffix
82 let src = if src' == "help.ml" then inOutDir src' else src'
83 need [src]
84 (comp, flags, ppflags) <- oracle $ OcamlCmdLineOracle key
85 let flagl = words flags
86 let incs = unwords ["-I " ++ d | d <- getincludes flagl
87 , not $ isabsinc d]
88 (Stdout stdout, Stderr emsg, Exit ex) <-
89 cmd ocamldep "-one-line" incs ppflags src
90 ppppe ex src emsg
91 let depo = deps ++ [dep -<.> ".cmo" | dep <- deps, fit dep]
92 where
93 deps = deplist $ parseMakefile stdout
94 fit dep = ext == ".cmi" && base /= baseout
95 where (base, ext) = splitExtension dep
96 baseout = dropExtension out
97 need depo
98 let fixedflags = fixincludes flagl
99 (Stderr emsg2, Exit ex2) <-
100 cmd comp "-c -I" outdir fixedflags "-o" out ppflags src
101 ppppe ex2 src emsg2
102 unit $ ordoracle $ OcamlOrdOracle out
103 return ()
104 where (target, suffix, op) = case t of
105 CMO -> ("//*.cmo", ".ml", (%>))
106 CMI -> ("//*.cmi", ".mli", (%>))
107 deplist [] = []
108 deplist ((_, reqs) : _) =
109 [if takeDirectory1 n == outdir then n else inOutDir n | n <- reqs]
110 ppppe ExitSuccess _ _ = return ()
111 ppppe _ src emsg = error $ fixpp src emsg
113 main = do
114 depl <- newMVar ([] :: [String])
115 shakeArgs shakeOptions { shakeFiles = outdir
116 , shakeVerbosity = Normal
117 , shakeChange = ChangeModtimeAndDigest } $ do
118 want ["build/llpp"]
120 gitDescribeOracle <- addOracle $ \(GitDescribeOracle ()) -> do
121 Stdout out <- cmd "git describe --tags --dirty"
122 return (out :: String)
124 ocamlOracle <- addOracle $ \(OcamlCmdLineOracle s) ->
125 return $ ocamlKey s
127 ocamlOrdOracle <- addOracle $ \(OcamlOrdOracle s) -> do
128 unless (takeExtension s == ".cmi") $
129 liftIO $ modifyMVar_ depl $ \l -> return $ s:l
131 cOracle <- addOracle $ \(CCmdLineOracle s) -> return $ cKey s
133 inOutDir "help.ml" %> \out -> do
134 version <- gitDescribeOracle $ GitDescribeOracle ()
135 need ["mkhelp.sh", "KEYS"]
136 Stdout f <- cmd "/bin/sh mkhelp.sh KEYS" version
137 writeFileChanged out f
139 "//*.o" %> \out -> do
140 let key = dropDirectory1 out
141 flags <- cOracle $ CCmdLineOracle key
142 let src = key -<.> ".c"
143 let dep = out -<.> ".d"
144 unit $ cmd ocamlc "-ccopt"
145 [flags ++ " -MMD -MF " ++ dep ++ " -o " ++ out] "-c" src
146 needMakefileDependencies dep
148 inOutDir "llpp" %> \out -> do
149 let objs = map (inOutDir . (++) "lablGL/ml_") ["gl.o", "glarray.o", "raw.o"]
150 need (objs ++ map inOutDir ["link.o", "main.cmo", "help.cmo"])
151 cmos <- liftIO $ readMVar depl
152 unit $ cmd ocamlc "-g -custom -I lablGL -o " out
153 "unix.cma str.cma" (reverse cmos)
154 (inOutDir "link.o") "-cclib" (cclib : objs)
156 cm' CMI ocamlOracle ocamlOrdOracle
157 cm' CMO ocamlOracle ocamlOrdOracle