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