Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100755 525 lines (468 sloc) 16.745 kb
22b433a @fperrin Don't assume that bash is in /bin
fperrin authored
1 #!/usr/bin/env bash
2
3 set -u
4 set -e
fccc685 Initial open-source release
MLstate authored
5
6 # README BEFORE EDITING THIS FILE!
7 #
8 # This is supposed to be a portable script (Linux, Mac, and even Windows).
9 # Due to Windows limitations, avoid complex pipes (you can pipe to an
10 # executable, but not to a `while' loop).
11 # Don't refer to absolute directories ("/tmp" is not a good idea).
12 # And don't do tricky low level hacks.
13
14 CONFIG_SH=config.sh
15 if [ -n "${NO_CONFIG_SH:-}" ]; then
16 CONFIG_SH=$0
17 else
18 if [ ! -e $CONFIG_SH ]; then
19 echo "Error: config.sh not found. Please run ./configure"
20 exit 1
21 fi
22 . $CONFIG_SH
23 fi
24
25 export MLSTATELIBS=$PREFIX
26
27
28 print_help () {
29 cat <<EOF
30 bld: the MLstate build system
31 Usage: bld [options] [special-targets] [targets] [-- exec-parameters]
32
33 Options:
34 -dir <dir> set the installation directory (default: \$MLSTATELIBS)
35 -help this help
36 -release enables release mode, disables debug and asserts
37 -nocompile don't check compilation of libs and tools, only install what we can
38 -bytecode try to only use bytecode
39 -private UNDOCUMENTED
40
41 Special targets:
42 clean removes compiled files
43 [un]install-libs automatically [un]install libs from "build_libs"
44 [un]install-tools automatically [un]install tools from "build_tools"
45 [un]install [un]install both libs and tools
46 libs=lib1[,lib2,...] subset of libs to install
47 tools=tool1[,tool2,...] subset of tools to install
48
49 Targets:
50 <target> compiles targets from file <target>.itarget
51 <libname>.doc builds library documentation in <libname>.docdir
52 <target>.exe finds <target>.ml, builds and copies the native exe
53 <target>.<ext> compiles target with ocamlbuild (see below)
54
55 Quick reference on special ocamlbuild targets:
56 <source file> <target>
57 %.<any_src> %.byte, %.native byte/native program
58 %.mllib %.cma, %.cmxa byte/native library
59 %.mltop %.top custom toplevel
60 %.odocl %.docdir ocamldoc documentation
61 %.itarget %.otarget (virtual) set of targets
62
63 Environment variables:
64 \$MLSTATELIBS prefix where everything should be installed
65 \$BLD_NOTIFY if "1", you'll be notified when bld finished
66 (by means of "notify-send")
67
68 Other options are passed to ocamlbuild, which runs the generated binary if "--"
69 is used.
70
71 bld works from the contents of files "build_libs", "build_tools" and "build_rules*.ml".
72 See the README in libqml for syntax and more information.
73 EOF
74 }
75
76 # try to find the appropriate directory
77 RELDIR=""
78 while [ "$PWD" != "/" ] && [ ! -f build_libs ]; do
79 RELDIR="$(basename "$PWD")/$RELDIR"
80 cd ..
81 done
82 if [ "$PWD" = "/" ]; then
83 echo "bld error: can't find 'build_libs' in the current directory or any of its parents"
84 exit 1
85 fi
86 if [ "$RELDIR" != "" ]; then echo "Working from $PWD, results in $PWD/_build/$RELDIR"; fi
87
88 . platform_helper.sh
89
90 msg () {
91 echo "$*"
92 }
93 warn () {
94 echo "warning: $*"
95 }
96
97 # Portability :
98 # Under cygwin, only tested in bytecode
99 # Under windows, use cygwin version (=>ENFORCE_WINDOWS="YES")
100 # ENFORCE_WINDOWS , if set => compile ocaml with ms compiler compatibility
101
102 WINDOWS=${WINDOWS:-"$IS_WINDOWS"}
103
104 if [ $(uname) = "windows32" ]; then
105 tmp=tmp # mktemp is awkward on Windows
106 else
107 tmp=$(mktemp -t tmp.XXXXXX)
108 trap "rm -f $tmp" EXIT
109 fi
110
111 : ${BLDDIR:="$MLSTATELIBS"/share/opa/bld}
112
113 : ${CONFIG_ML:=config.ml}
114 if [ ! -e $CONFIG_ML ]; then
115 echo "Error: config.ml not found. Please run ./configure"
116 exit 1
117 fi
118
119 filter_target(){
120 if [ "$WINDOWS" = 1 ]; then
121 grep -v '^\(#\|$\)' "$@" | sed s/\\.o$/\\.obj/g | sed -e "s/\\.o /\\.obj /g"
122 else
123 grep -v '^\(#\|$\)' "$@"
124 fi
125 }
126
127 export PPDEBUGDIR=$PWD/utils
128
129 COMMANDLINE="$*"
130 STARTTIME=$(date +%s)
131 UNINSTALL_LIBS="false"
132 UNINSTALL_TOOLS="false"
133 INSTALL_LIBS="false"
134 INSTALL_TOOLS="false"
135 TOOLS=""
136 LIBS=""
137 BYTECODE="false"
138 CLEAN="false"
139 INSTALL_CMD="install -m 0644"
140 INSTALL_BIN="install -m 0755"
141 COMPILE="true"
142 DEBUG="true"
143 NOCOMPILE="false"
144 ARGS=""
145 RENAME=""
146 INSTALLDIR="$MLSTATELIBS"
147 BUILD_DIR="_build"
148 BUILD_LIBS="build_libs"
149 BUILD_TOOLS="build_tools"
150
151 init_install_libs() (
152 if [ -z "$LIBS" ]; then
153 grep "^ *internal" $BUILD_LIBS > $tmp
154 while read x lib y; do echo $lib; done < $tmp
155 else
156 echo $LIBS
157 fi
158 )
159 init_install_tools() (
160 if [ -z "$TOOLS" ]; then
161 grep "^ *internal" $BUILD_TOOLS | filter_target > $tmp
162 while read x tool y; do echo $tool; done < $tmp
163 else
164 echo $TOOLS
165 fi
166 )
167
168 R=''
169 while [ $# -gt 0 ]; do
170 case $1 in
171 clean)
172 CLEAN="true";;
173 install-libs)
174 INSTALL_LIBS="true"
175 LIBS=$(init_install_libs);;
176 install-tools)
177 INSTALL_TOOLS="true"
178 TOOLS=$(init_install_tools);;
179 install)
180 INSTALL_LIBS="true"; INSTALL_TOOLS="true"
181 LIBS=$(init_install_libs)
182 TOOLS=$(init_install_tools);;
183 uninstall-libs)
184 UNINSTALL_LIBS="true"
185 LIBS=$(init_install_libs);;
186 uninstall-tools)
187 UNINSTALL_TOOLS="true"
188 TOOLS=$(init_install_tools);;
189 uninstall)
190 UNINSTALL_LIBS="true"; UNINSTALL_TOOLS="true"
191 LIBS=$(init_install_libs)
192 TOOLS=$(init_install_tools);;
193 libs=*)
194 LIBS="$(echo $1 | sed 's/^libs=//' | sed 's/,/ /g')";;
195 tools=*)
196 TOOLS="$(echo $1 | sed 's/^tools=//' | sed 's/,/ /g')";;
197 -private)
198 BUILD_LIBS="build_libs*"
199 BUILD_TOOLS="build_tools*"
200 ;;
201 -release)
202 ARGS="$ARGS -tag release -tag noassert"
203 DEBUG="false";;
204 -nocompile)
205 NOCOMPILE="true";;
206 -bytecode)
207 BYTECODE="true";;
208 -dir)
209 if [ -z "$2" ]; then echo "Error: option $1 requires an argument"; exit 1; fi
210 shift; INSTALLDIR="$1";;
211 -build-dir)
212 shift; BUILD_DIR="$1"; ARGS="$ARGS -build-dir $1";;
213 -help|--help)
214 print_help; exit 0;;
215 --)
216 ARGS="$ARGS $@"; break;;
217 *)
218 TARGET="${RELDIR}$1"
219 if [ -f "$TARGET.itarget" ]; then A="$TARGET.otarget"
220 elif echo $TARGET | grep -q '.exe$'; then
221 N=$(find */ -name $(basename "$TARGET" .exe).ml | grep -v $BUILD_DIR)
222 if [ -z "$N" ]; then echo "Target not found: $TARGET"; exit 1; fi
223 if [ -n "$(echo $N | (read a b; echo $b))" ]; then
224 echo "Multiple targets found: $TARGET"; exit 1;
225 fi
226 if [ "$BYTECODE" = "true" ]; then
227 A="$(dirname "$N")/$(basename "$N" .ml).byte"; else
228 A="$(dirname "$N")/$(basename "$N" .ml).native"
229 fi
230 R="$A"
231 elif echo $TARGET | grep -q '.doc$'; then
232 A="${TARGET}dir/index.html"
233 else
234 A="$TARGET"
235 fi
236 ARGS="$ARGS $A"
237 RENAME="$RENAME $R";;
238 esac
239 shift
240 done
241
242 INSTALL_LIBS_DIR=$INSTALLDIR/lib/opa/ocaml/opa
243
244 if [ "$CLEAN" = "true" ]; then
245 rm -rf $BUILD_DIR/* || warn "could not complete clean"
246 fi
247
248 if [ "$DEBUG" = "true" ]; then ARGS="-tag debug $ARGS"; fi
249
250 shopt -s nullglob
251 # causes non-matching patterns to be discarded from the line instead of left as-is
252 # useful for install commands
253
254 #########
255 # myocamlbuild generation
256 #########
257
258 MYOCAMLBUILD=$BUILD_DIR/myocamlbuild.ml
259
260 mkdir -p $BUILD_DIR
261
262 libexportfiles() {
263 sed 's%^\([^#/]\+\)/\([^/]\+\)$%\1 \2%; t OK; d; :OK' $1 | \
264 while read dir module; do
265 # Get the real capitalisation of the source file
266 f=$(find -L $dir -maxdepth 1 -iname $module.ml)
267 # If the source file doesn't exist (generated ?), lowercase first letter
268 if [ -z "$f" ]; then f=$dir/$(echo ${module:0:1} | tr '[:upper:]' '[:lower:]')${module:1}.ml; fi
269 echo $f
270 done
271 }
272
273 if [ ! -f $MYOCAMLBUILD ] ||
274 [ $MYOCAMLBUILD -ot $BLDDIR/myocamlbuild_prefix.ml ] ||
275 [ $MYOCAMLBUILD -ot $BLDDIR/myocamlbuild_suffix.ml ] ||
276 [ $MYOCAMLBUILD -ot $CONFIG_ML ] ||
277 [ $MYOCAMLBUILD -ot $CONFIG_SH ] ||
278 [ $MYOCAMLBUILD -ot $0 ] ||
279 [ -n "$(find -L . -maxdepth 1 -newer $MYOCAMLBUILD -and \
280 \( -name build_rules\*.ml -or -name build_tools\* -or -name build_libs\* \) )" ]
281 then
282 {
283 echo "(* ****************************************************************************** *)"
284 echo "(* File generated by bld: DO NOT EDIT. *)"
285 echo "(* See build_libs*, build_tools* and build_rules*.ml instead. *)"
286 echo "(* ****************************************************************************** *)"
287 echo
288 echo "#1 \"$CONFIG_ML\""
289 cat $CONFIG_ML
290 echo "#1 \"$BLDDIR/myocamlbuild_prefix.ml\""
291 cat $BLDDIR/myocamlbuild_prefix.ml
292 for i in $BUILD_TOOLS; do
293 echo "#1 \"$i\""
294 if [ "$BYTECODE" = "true" ]; then sed "s/\.native/.byte/g" $i | filter_target> $tmp
295 else cat $i | filter_target> $tmp
296 fi
297 awk '/^external/ { print "set_tool ~internal:false \""$2"\" \""$3"\";" }
298 /^internal/ { print "set_tool ~internal:true \""$2"\" \""$3"\";" }' $tmp
299 done
300 for i in $BUILD_LIBS; do
301 echo "#1 \"$i\""
302 awk '/^external/ { print "mlstate_lib ~dir:\"lib/opa/static\" \""$2"\";" }
303 /^internal/ { print "internal_lib", $3 ? "~dir:\""$3"\"" : "", "\""$2"\";" }' $i
304 done
305 for i in build_rules*.ml; do
306 echo "#1 \"$i\""
307 cat $i
308 echo ";"
309 done
310 echo "#1 \"$BLDDIR/myocamlbuild_suffix.ml\""
311 cat $BLDDIR/myocamlbuild_suffix.ml
312 } > $MYOCAMLBUILD
313 fi
314
315
316 if [ ! -f $BUILD_DIR/myocamlbuild ] ||
317 [ $BUILD_DIR/myocamlbuild -ot $MYOCAMLBUILD ]
318 then
319 D=$PWD
320 [ $IS_WINDOWS ] && unset OCAMLLIB # prevent windows installation to bypass cygwin one
321 wh=$($OCAMLBUILD -where)
322 # Why CYGWIN : because flexdll is not working with Cygwin, so no dynamic loading can occur
323 if [ "$BYTECODE" = "true" ]; then
324 echo Compiling myself to bytecode using $wh
325 cp $CONFIG_ML ${CONFIG_ML}i $BUILD_DIR
326 cd $BUILD_DIR
327 ocamlc -w y -I "$wh" unix.cma ocamlbuildlib.cma config.ml myocamlbuild.ml "$wh"/ocamlbuild.cmo -o myocamlbuild
328 else
329 echo Compiling myself using $wh
330 rm -f _build/config.*
331 cp $CONFIG_ML ${CONFIG_ML}i $BUILD_DIR
332 cd $BUILD_DIR
333 $OCAMLOPT -c config.mli
334 $OCAMLOPT -c config.ml
335 $OCAMLOPT -w y -I "$wh" unix.cmxa ocamlbuildlib.cmxa config.cmx myocamlbuild.ml "$wh"/ocamlbuild.cmx -o myocamlbuild
336 fi
337 cd $D
338 fi
339
340 #########
341 # functions handling libs
342 #########
343
344 lib_files () {
345 local lib=$1; shift
346 local dir=$1; shift
347 local pfx=$1; shift
348 [ $# -eq 0 ]
349 FILES="$lib.$EXT_LIB $lib.cmxa"
350 if [ "$BYTECODE" = "true" ]; then FILES="$lib.cma"; fi
351 for i in $pfx/$dir/*.cmi; do
352 local module=$(basename "$i" .cmi)
353 if grep -qi '^\([^#].* \)\? *'$dir/$module'\( \|$\)' $lib.mllib; then
354 FILES="$FILES $dir/$module.cmi"
355 fi
356 done
357 echo $FILES
358 }
359
360 install_lib () {
361 local lib=$1; shift
362 local srcdir=${1:-$lib}
363 [ $# -le 1 ]
364 FILES=$(lib_files $lib $srcdir $BUILD_DIR)
365 echo "$lib >> $FILES"
366 echo -n -e "Installing into $INSTALL_LIBS_DIR\r"
367 for i in $FILES; do
368 echo "Installing $i"
369 if [ -e "$INSTALL_LIBS_DIR/$(basename $i)" ]; then
370 if diff $BUILD_DIR/$i $INSTALL_LIBS_DIR/$(basename $i); then
371 echo "Trying to install $i to $INSTALL_LIBS_DIR/$(basename $i), which is already there. Skipping."
372 else
373 echo "Error: would install file $i from lib $lib, which conflicts with"
374 echo "an already installed file ($INSTALL_LIBS_DIR/$(basename $i))"
375 exit 1
376 fi
377 else
378 $INSTALL_CMD $BUILD_DIR/$i $INSTALL_LIBS_DIR
379 fi
380 done
381 }
382
383 #########
384 # Setup notification
385 #########
386
387 # $1: delay in seconds, '92' for instance
388 # stdout: '1m32s', for instance
389 pretty_time() {
390 local seconds=$(($1%60))
391 local minutes=$(($1/60%60))
392 local hours=$(($1/3600%24))
393 local days=$(($1/(3600*24)))
394 local once=false
395 { [ $days -ne 0 ] || $once; } && printf "%ddays " $days && once=true
396 { [ $hours -ne 0 ] || $once; } && printf "%dh" $hours && once=true
397 { [ $minutes -ne 0 ] || $once; } && printf "%dm" $minutes && once=true
398 { [ $seconds -ne 0 ] || $once; } && printf "%ds" $seconds && once=true
399 }
400
401 notify_success () {
402 if [ $IS_MAC ] && which growlnotify &> /dev/null; then
403 growlnotify -t "$1" -m "$2"
404 elif [ $IS_LINUX ] && which notify-send &> /dev/null; then
405 notify-send -t 4000 "$1" "$2"
406 fi
407 }
408
409 notify_error () {
410 if [ $IS_MAC ] && which growlnotify &> /dev/null; then
411 growlnotify -t "$1" -m "$2"
412 elif [ $IS_LINUX ] && which notify-send &> /dev/null; then
413 notify-send -t 4000 -c ERROR "$1" "$2"
414 fi
415 }
416
417 notify_exit () {
418 local status=$?
419 local delay=$(($(date +%s) - $STARTTIME))
420 if [ $status -ne 0 ]; then
421 notify_error "[!] build unsucessful [!]" "bld $COMMANDLINE failed in $(pretty_time $delay)" || beep || true
422 else
423 notify_success "build finished" "bld $COMMANDLINE finished in $(pretty_time $delay)" || beep || true
424 fi
425 }
426 if [ "${BLD_NOTIFY:-""}" = 1 ]; then
427 trap notify_exit 0
428 fi
429
430 #########
431 # Processing targets
432 #########
433
434 if [ "$UNINSTALL_LIBS" = "true" ]; then
435 rm -f $INSTALL_LIBS_DIR/*.{cmi,cma,cmxa,a}
436 fi
437
438
439 if [ "$UNINSTALL_TOOLS" = "true" ]; then
440 grep "^internal" $BUILD_TOOLS | filter_target > $tmp
441 while read x tool file dir ; do
442 if [ -z "$dir" ]; then dir="bin"; fi
443 rm -f $INSTALLDIR/$dir/$tool
444 done < $tmp
445 fi
446
447 TARGETSFILE=bld_target.itarget
448 if [ "$NOCOMPILE" = "false" ]; then
449 echo "# file generated by bld, DO NOT EDIT" >$TARGETSFILE
450 ARGS="${TARGETSFILE%.itarget}.otarget $ARGS"
451 for i in $LIBS; do
452 echo $i.cma >>$TARGETSFILE
453 echo $i.cmxa >>$TARGETSFILE
454 done
455
456 for i in $TOOLS; do
457 FILE=$(cat $BUILD_TOOLS | filter_target | grep "^internal *$i\( \|$\)" | (read _ tool file dir; echo $file))
458 if [ "$BYTECODE" = "true" ]; then FILE=${FILE/%.native/.byte}; FILE=${FILE/%.cmxs/.cma}; fi
459 if [ -z "$FILE" ]; then
460 cat $BUILD_TOOLS | filter_target
461 echo "Tool not found: $i. Make sure it is declared in your $BUILD_TOOLS file"; exit 1
462 else
463 echo $FILE >>$TARGETSFILE
464 fi
465 done
466 fi
467
468 if [ -n "$ARGS" ]; then
469 msg "bld: ocamlbuild $ARGS"
470 $BUILD_DIR/myocamlbuild -no-plugin -j 6 $ARGS
471 fi
472
473 if [ -n "$RENAME" ]; then
474 for i in $RENAME; do
475 DST=$(dirname $i)/$(basename "$(basename "$i" .native)" .byte).exe
476 cp $BUILD_DIR/$i $BUILD_DIR/$DST
477 if [ ! -f $DST ]; then
478 ln -sf $BUILD_DIR/$DST .
479 else
480 warn "Not linking $BUILD_DIR/$DST: file exists in current directory"
481 fi
482 done
483 fi
484
485 if [ "$INSTALL_LIBS" = "true" ]; then
486 # First remove all that we are going to install, so that we can check for collisions
487 if [ "$UNINSTALL_LIBS" != "true" ]; then
488 for lib in $LIBS; do
489 grep "^internal *$lib\\( \\|$\\)" $BUILD_LIBS > $tmp
490 read x lib srcdir < $tmp;
491 if [ -z "$srcdir" ]; then srcdir=$lib; fi
492 FILES=$(lib_files $lib $srcdir $BUILD_DIR)
493 for i in $FILES; do
494 rm -f $INSTALL_LIBS_DIR/$(basename "$i")
495 done
496 done
497 fi
498
499 # Installs the internal libs found in the "build_libs*" file
500 mkdir -p $INSTALL_LIBS_DIR
501 for i in $LIBS; do
502 grep "^internal *$i\\( \\|$\\)" $BUILD_LIBS > $tmp
503 read x lib srcdir < $tmp;
504 install_lib $lib $srcdir || warn "$lib not found, not installing"
505 done
506 fi
507
508 if [ "$INSTALL_TOOLS" = "true" ]; then
509 # Installs the internal tools found in the "build_tools*" file
510 for i in $TOOLS; do
511 cat $BUILD_TOOLS | filter_target | grep "^ *internal *$i\\( \\|$\\)" > $tmp
512 read x tool file dir < $tmp
513 if [ "$BYTECODE" = "true" ]; then file=${file/%.native/.byte}; fi
514 inst="$INSTALL_CMD"
515 if [ -z "$dir" ]; then dir="bin"; inst="$INSTALL_BIN"; fi
516 echo -n -e "Installing into $INSTALLDIR/$dir\r"
517 mkdir -p $INSTALLDIR/$dir
518 if [ -e $BUILD_DIR/$file ]; then
519 $inst $BUILD_DIR/$file $INSTALLDIR/$dir/$tool || warn "Error installing $tool"
520 else
521 warn "$tool not found, not installing"
522 fi
523 done
524 fi
Something went wrong with that request. Please try again.