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