Fix inotify for certain filenames
[llpp.git] / build.sh
blob6d4a6d0e3b15f64280f0ed1c2b9b456cffcb7f76
1 #!/bin/sh
2 set -eu
4 test "$(uname)" = Darwin && {
5 darwin=true
6 wsi="wsi/osx"
7 } || {
8 darwin=false
9 wsi="wsi/x11"
12 now() { echo "print_float @@ Unix.gettimeofday ()" | ocaml unix.cma -stdin; }
14 tstart=$(now)
15 vecho() { ${vecho-:} "$*"; }
16 command -v md5sum >/dev/null && alias sum=md5sum || true
17 test -z "${debugdeps-}" \
18 && digest() { sum $* 2>/dev/null | while read h _; do printf "$h"; done; } \
19 || digest() { sum $* 2>/dev/null; }
21 partmsg() {
22 test $? -eq 0 && msg="ok" || msg="ko"
23 echo "$msg $(echo "scale=3; ($(now) - $tstart)/1" | bc -l) sec"
26 die() {
27 echo "$*" >&2
28 exit 111
31 trap 'partmsg' EXIT
33 test $(ocamlc -version | { IFS=. read a b _; echo $a$b; }) -lt 406 && {
34 die OCaml version 4.06+ is required
37 test -n "${1-}" || die "usage: $0 build-directory"
39 outd="$1"
40 srcd="$(dirname $0)"
41 mudir=$srcd/mupdf
42 muinc="-I $mudir/include -I $mudir/thirdparty/freetype/include"
44 isfresh() {
45 test -e "$1" && test -r "$1.past" && {
46 . "$1.past"
47 test "$k" = "$2"
51 test "${USER-}" = "malc" && {
52 keycmd="cd $mudir && git describe --tags --dirty"
53 isfresh "$outd/mupdf" "$(eval $keycmd)" || (
54 mkdir -p $outd
55 make -C "$mudir" CC='ccache gcc' build=native -j4 libs && :>$outd/mupdf
56 echo "k=$(eval $keycmd)" >$outd/mupdf.past
57 ) && vecho "fresh mupdf"
60 oflags() {
61 case "${1#$outd/}" in
62 main.cmo|utils.cmo|config.cmo|parser.cmo|wsi.cmi|$wsi/wsi.cmo)
63 f="-g -strict-sequence -strict-formats -warn-error a";;
64 *) f="-g";;
65 esac
66 echo "$incs $f"
69 cflags() {
70 case "${1#$outd/}" in
71 link.o)
72 f="-g -std=c99 -O2 $muinc -Wall -Werror -pedantic-errors"
73 f="$f -D_GNU_SOURCE"
74 $darwin && echo "$f -D__COCOA__" || echo $f;;
75 keysym2ucs.o) echo "-DKeySym=long";;
76 */ml_gl.o) echo "-g -Wno-pointer-sign -O2";;
77 *) echo "-g -O2";;
78 esac
81 mflags() { echo "-I $(ocamlc -where) -g -O2"; }
83 bocaml1() {
84 :>$o.depl
85 ocamlc -depend -bytecode -one-line $(echo $incs) $s | {
86 read _ _ depl
87 depl=$(eval echo $depl)
88 for d in $depl; do
89 bocaml ${d#$srcd/} $((n+1))
90 test $d = "build/help.cmo" \
91 && dd=$outd/help.cmo || dd=$outd/${d#$srcd/}
92 printf "$dd " >>$o.depl
93 done
95 cmd="ocamlc $(oflags $o) -c -o $o $s"
96 keycmd="digest $s $(cat $o.depl)"
97 grep -q "$o" $outd/ordered || {
98 echo "$o" >>"$outd/ordered"
99 isfresh "$o" "$cmd$(eval $keycmd)" || {
100 printf "%*.s%s -> %s\n" $n '' "${s#$srcd/}" "${o#$outd/}"
101 eval "$cmd" || die "$cmd failed"
102 echo "k='$cmd$(eval $keycmd)'" >"$o.past"
103 } && vecho "fresh '$o'"
107 bocaml() (
108 o="$1"
109 n="$2"
110 wocmi="${o%.cmi}"
111 test ${wocmi%help.cmo} != $wocmi && {
112 s=$outd/help.ml
113 o=$outd/help.cmo
114 } || {
115 test "$o" = "$wocmi" && s=$srcd/${o%.cmo}.ml || s=$srcd/$wocmi.mli
116 o=$outd/$o
118 incs="-I $srcd/lablGL -I $srcd/$wsi -I $srcd"
119 incs="$incs -I $outd/lablGL -I $outd/$wsi -I $outd"
120 bocaml1 "$s" "$o"
123 bocamlc() {
124 o=$outd/$1
125 s=$srcd/${1%.o}.c
126 cmd="ocamlc -ccopt \"$(cflags $o) -MMD -MF $o.dep -MT_ -o $o\" $s"
127 test -r $o.dep && read _ d <$o.dep || d=
128 keycmd='digest $o $d'
129 isfresh "$o" "$cmd$(eval $keycmd)" || {
130 printf "%s -> %s\n" "${s#$srcd/}" "${o#$outd/}"
131 eval "$cmd" || die "$cmd failed"
132 read _ d <$o.dep
133 echo "k='$cmd$(eval $keycmd)'" >"$o.past"
134 } && vecho "fresh $o"
137 bobjc() {
138 o=$outd/$1
139 s=$srcd/${1%.o}.m
140 cmd="$mcomp $(mflags $o) -MMD -MF $o.dep -MT_ -c -o $o $s"
141 test -r $o.dep && read _ d <$o.dep || d=
142 keycmd='digest $o $d'
143 isfresh "$o" "$cmd$(eval $keycmd)" || {
144 printf "%s -> %s\n" "${s#$srcd/}" "${o#$outd/}"
145 eval "$cmd"
146 read _ d <$o.dep
147 echo "k='$cmd$(eval $keycmd)'" >"$o.past"
148 } && vecho "fresh $o"
151 mkdir -p $outd/$wsi
152 mkdir -p $outd/lablGL
153 :>$outd/ordered
155 mkhelp() {
156 ocaml str.cma -stdin $srcd/KEYS <<EOF
157 let fixup = let open Str in
158 let dash = regexp {|\([^ ]*\) +- +\(.*\)|}
159 and head = regexp {|-----\(.*\)-----|} in fun s ->
160 String.escaped s |> global_replace dash {|\1\t\2|}
161 |> global_replace head {|\xc2\xb7\1|};;
162 let rec iter ic = match input_line ic with
163 | s -> Printf.printf "\"%s\";\\n" @@ fixup s; iter ic
164 | exception End_of_file -> ();;
165 Printf.printf "let keys = [\\n";
166 iter @@ open_in Sys.argv.(1);;
167 Printf.printf "] and version = \"$ver\";;"
171 ver=$(cd $srcd && git describe --tags --dirty) || ver=unknown
172 cmd="mkhelp >$outd/help.ml"
173 keycmd="digest $srcd/KEYS; echo $ver"
174 isfresh "$outd/help.ml" '$cmd$(eval $keycmd)' || {
175 eval $cmd
176 echo "k='$cmd$(eval $keycmd)'" >"$outd/help.ml.past"
177 } && vecho "fresh $outd/help.ml"
179 case "${2-}" in
180 man)
181 md=$outd/man
182 mkdir -p $md
183 for m in llpp llppac llpphtml; do
184 man=$srcd/man/$m.man
185 xml=$md/$m.xml
186 out=$md/$m.1
187 keycmd="digest $xml $man"
188 conf="$srcd/man/asciidoc.conf"
189 cmd="asciidoc -d manpage -b docbook -f $conf -o '$xml' '$man'"
190 isfresh "$xml" "$cmd$(eval $keycmd)" || {
191 eval $cmd
192 echo "k='$cmd$(eval $keycmd)'" >"$md/$m.past"
193 } && vecho "fresh manual xmls"
194 keycmd="digest $out $xml"
195 cmd="xmlto man -o $md $xml"
196 isfresh "$out" "$cmd$(eval $keycmd)" || {
197 eval $cmd
198 echo "k='$cmd$(eval $keycmd)'" >"$out.past"
199 } && vecho "fresh manual pages"
200 done
201 shift;;
202 *) ;;
203 esac
205 # following is disgusting (from "generalize everything" perspective),
206 # but generic method of derviving .ml's location from .mli's is not
207 # immediately obvious
208 for m in lablGL/glMisc.cmo lablGL/glTex.cmo $wsi/wsi.cmo main.cmo; do
209 bocaml $m 0
210 done
211 cobjs=
212 for m in keysym2ucs.o link.o; do
213 bocamlc $m
214 cobjs="$cobjs $outd/$m"
215 done
217 libs="str.cma unix.cma"
218 clibs="-L$mudir/build/native -lmupdf -lmupdfthird -lpthread"
219 if $darwin; then
220 mcomp=$(ocamlc -config | grep bytecomp_c_co | { read _ c; echo $c; })
221 clibs="$clibs -framework Cocoa -framework OpenGL"
222 bobjc main_osx.o
223 cobjs="$cobjs $outd/main_osx.o"
224 else
225 clibs="$clibs -lGL -lX11"
228 globjs=
229 for f in ml_gl ml_glarray ml_raw; do
230 bocamlc lablGL/$f.o
231 globjs="$globjs $outd/lablGL/$f.o"
232 done
234 ord=$(echo $(grep -v \.cmi $outd/ordered))
235 cmd="ocamlc -custom $libs -o $outd/llpp $cobjs $ord"
236 cmd="$cmd $globjs -cclib \"$clibs\""
237 keycmd="digest $outd/llpp $cobjs $ord"
238 isfresh "$outd/llpp" "$cmd$(eval $keycmd)" || {
239 echo linking $outd/llpp
240 eval $cmd || die "$cmd failed"
241 echo "k='$cmd$(eval $keycmd)'" >"$outd/llpp.past"
242 } && vecho "fresh llpp"
244 if $darwin; then
245 out="$outd/llpp.app/Contents/Info.plist"
246 keycmd="digest $out $srcd/misc/Info.plist.sh"
247 isfresh $out "$(eval $keycmd)" || {
248 shortver=$(echo $ver | { IFS='-' read s _; echo ${s#v}; })
249 d=$(dirname $out)
250 test -d "$d" || mkdir -p "$d"
251 . $srcd/misc/Info.plist.sh >"$out"
252 echo "k=$(eval $keycmd)" >"$out.past"
253 } && vecho "fresh plist"
255 out=$outd/llpp.app/Contents/MacOS/llpp
256 keycmd="digest $out $outd/llpp"
257 isfresh $out "$(eval $keycmd)" || {
258 d=$(dirname $out)
259 mkdir -p "$d"
260 cp $outd/llpp $out
261 echo "k=$(eval $keycmd)" >"$out.past"
262 } && vecho "fresh bundle"