]> gitweb.factorcode.org Git - factor.git/blob - build-support/factor.sh
d3d1a3ec3289546d711d8ab08e65b959962d81e6
[factor.git] / build-support / factor.sh
1 #!/usr/bin/env bash
2
3 # Programs returning != 0 will not cause script to exit
4 set +e
5
6 # Case insensitive string comparison
7 shopt -s nocaseglob
8 #shopt -s nocasematch
9
10 ECHO=echo
11 OS=
12 ARCH=
13 WORD=
14 NO_UI=${NO_UI-}
15 GIT_PROTOCOL=${GIT_PROTOCOL:="git"}
16 GIT_URL=${GIT_URL:=$GIT_PROTOCOL"://factorcode.org/git/factor.git"}
17 SCRIPT_ARGS="$*"
18
19 test_program_installed() {
20     if ! [[ -n `type -p $1` ]] ; then
21         return 0;
22     fi
23     return 1;
24 }
25
26 exit_script() {
27     if [[ $FIND_MAKE_TARGET = true ]] ; then
28         # Must be echo not $ECHO
29         echo $MAKE_TARGET;
30     fi
31     exit $1
32 }
33
34 ensure_program_installed() {
35     installed=0;
36     for i in $* ;
37     do
38         $ECHO -n "Checking for $i..."
39         test_program_installed $i
40         if [[ $? -eq 0 ]]; then
41             $ECHO -n "not "
42         else
43             installed=$(( $installed + 1 ))
44         fi
45         $ECHO "found!"
46     done
47     if [[ $installed -eq 0 ]] ; then
48         $ECHO -n "Install "
49         if [[ $# -eq 1 ]] ; then
50             $ECHO -n $1
51         else
52             $ECHO -n "any of [ $* ]"
53         fi
54         $ECHO " and try again."
55         if [[ $OS == macosx ]] ; then
56             $ECHO "If you have Xcode 4.3 or higher installed, you must install the"
57             $ECHO "Command Line Tools from Xcode Preferences > Downloads in order"
58             $ECHO "to build Factor."
59         fi
60         exit_script 1;
61     fi
62 }
63
64 check_ret() {
65     RET=$?
66     if [[ $RET -ne 0 ]] ; then
67        $ECHO $1 failed
68        exit_script 2
69     fi
70 }
71
72 set_downloader() {
73     test_program_installed wget curl
74     if [[ $? -ne 0 ]] ; then
75         DOWNLOADER=wget
76     else
77         DOWNLOADER="curl -f -O"
78     fi
79 }
80
81 set_md5sum() {
82     test_program_installed md5sum
83     if [[ $? -ne 0 ]] ; then
84         MD5SUM=md5sum
85     else
86         MD5SUM="md5 -r"
87     fi
88 }
89
90 set_gcc() {
91     case $OS in
92         macosx)
93             xcode_major=`xcodebuild -version | sed -E -ne 's/^Xcode ([0-9]+).*$/\1/p'`
94             if [[ $xcode_major -ge 4 ]]; then
95                 CC=clang
96                 CPP=clang++
97             else
98                 CC=gcc
99                 CPP=g++
100             fi
101         ;;
102         *)
103             CC=gcc
104             CPP=g++
105         ;;
106     esac
107 }
108
109 set_make() {
110     MAKE='make'
111 }
112
113 check_git_branch() {
114     BRANCH=`git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,'`
115     if [ "$BRANCH" != "master" ] ; then
116         $ECHO "git branch is $BRANCH, not master"
117         exit_script 3
118     fi
119 }
120
121 check_installed_programs() {
122     ensure_program_installed chmod
123     ensure_program_installed uname
124     ensure_program_installed git
125     ensure_program_installed wget curl
126     ensure_program_installed clang gcc
127     ensure_program_installed clang++ g++ cl
128     ensure_program_installed make gmake
129     ensure_program_installed md5sum md5
130     ensure_program_installed cut
131 }
132
133 check_library_exists() {
134     GCC_TEST=factor-library-test.c
135     GCC_OUT=factor-library-test.out
136     $ECHO -n "Checking for library $1..."
137     $ECHO "int main(){return 0;}" > $GCC_TEST
138     $CC $GCC_TEST -o $GCC_OUT -l $1 2>&-
139     if [[ $? -ne 0 ]] ; then
140         $ECHO "not found!"
141         $ECHO "***Factor will compile NO_UI=1"
142         NO_UI=1
143     else
144         $ECHO "found."
145     fi
146     $DELETE -f $GCC_TEST
147     check_ret $DELETE
148     $DELETE -f $GCC_OUT
149     check_ret $DELETE
150 }
151
152 check_X11_libraries() {
153     if [ -z "$NO_UI" ]; then
154         check_library_exists GL
155         check_library_exists X11
156         check_library_exists pango-1.0
157     fi
158 }
159
160 check_gtk_libraries() {
161     if [ -z "$NO_UI" ]; then
162         check_library_exists gobject-2.0
163         check_library_exists gtk-x11-2.0
164         check_library_exists gdk-x11-2.0
165         check_library_exists gdk_pixbuf-2.0
166         check_library_exists gtkglext-x11-1.0
167         check_library_exists atk-1.0
168         check_library_exists gio-2.0
169         check_library_exists gdkglext-x11-1.0
170         check_library_exists pango-1.0
171     fi
172 }
173
174
175 check_libraries() {
176     case $OS in
177             linux) check_X11_libraries
178                    check_gtk_libraries;;
179             unix) check_gtk_libraries;;
180     esac
181 }
182
183 check_factor_exists() {
184     if [[ -d "factor" ]] ; then
185         $ECHO "A directory called 'factor' already exists."
186         $ECHO "Rename or delete it and try again."
187         exit_script 4
188     fi
189 }
190
191 find_os() {
192     if [[ -n $OS ]] ; then return; fi
193     $ECHO "Finding OS..."
194     uname_s=`uname -s`
195     check_ret uname
196     case $uname_s in
197         CYGWIN_NT-5.2-WOW64) OS=windows;;
198         *CYGWIN_NT*) OS=windows;;
199         *CYGWIN*) OS=windows;;
200         MINGW32*) OS=windows;;
201         *darwin*) OS=macosx;;
202         *Darwin*) OS=macosx;;
203         *linux*) OS=linux;;
204         *Linux*) OS=linux;;
205     esac
206 }
207
208 find_architecture() {
209     if [[ -n $ARCH ]] ; then return; fi
210     $ECHO "Finding ARCH..."
211     uname_m=`uname -m`
212     check_ret uname
213     case $uname_m in
214        i386) ARCH=x86;;
215        i686) ARCH=x86;;
216        i86pc) ARCH=x86;;
217        amd64) ARCH=x86;;
218        ppc64) ARCH=ppc;;
219        *86) ARCH=x86;;
220        *86_64) ARCH=x86;;
221        "Power Macintosh") ARCH=ppc;;
222     esac
223 }
224
225 write_test_program() {
226     #! Must be 'echo'
227     echo "#include <stdio.h>" > $C_WORD.c
228     echo "int main(){printf(\"%ld\", (long)(8*sizeof(void*))); return 0; }" >> $C_WORD.c
229 }
230
231 c_find_word_size() {
232     $ECHO "Finding WORD..."
233     C_WORD=factor-word-size
234     write_test_program
235     gcc -o $C_WORD $C_WORD.c
236     WORD=$(./$C_WORD)
237     check_ret $C_WORD
238     $DELETE -f $C_WORD*
239 }
240
241 intel_macosx_word_size() {
242     ensure_program_installed sysctl
243     $ECHO -n "Testing if your Intel Mac supports 64bit binaries..."
244     sysctl machdep.cpu.extfeatures | grep EM64T >/dev/null
245     if [[ $? -eq 0 ]] ; then
246         WORD=64
247         $ECHO "yes!"
248     else
249         WORD=32
250         $ECHO "no."
251     fi
252 }
253
254 find_word_size() {
255     if [[ -n $WORD ]] ; then return; fi
256     if [[ $OS == macosx && $ARCH == x86 ]] ; then
257         intel_macosx_word_size
258     else
259         c_find_word_size
260     fi
261 }
262
263 set_factor_binary() {
264     case $OS in
265         windows) FACTOR_BINARY=factor.com;;
266         *) FACTOR_BINARY=factor;;
267     esac
268 }
269
270 set_factor_library() {
271     case $OS in
272         windows) FACTOR_LIBRARY=factor.dll;;
273         macosx) FACTOR_LIBRARY=libfactor.dylib;;
274         *) FACTOR_LIBRARY=libfactor.a;;
275     esac
276 }
277
278 set_factor_image() {
279     FACTOR_IMAGE=factor.image
280     FACTOR_IMAGE_FRESH=factor.image.fresh
281 }
282
283 echo_build_info() {
284     $ECHO OS=$OS
285     $ECHO ARCH=$ARCH
286     $ECHO WORD=$WORD
287     $ECHO FACTOR_BINARY=$FACTOR_BINARY
288     $ECHO FACTOR_LIBRARY=$FACTOR_LIBRARY
289     $ECHO FACTOR_IMAGE=$FACTOR_IMAGE
290     $ECHO MAKE_TARGET=$MAKE_TARGET
291     $ECHO BOOT_IMAGE=$BOOT_IMAGE
292     $ECHO MAKE_IMAGE_TARGET=$MAKE_IMAGE_TARGET
293     $ECHO GIT_PROTOCOL=$GIT_PROTOCOL
294     $ECHO GIT_URL=$GIT_URL
295     $ECHO DOWNLOADER=$DOWNLOADER
296     $ECHO CC=$CC
297     $ECHO MAKE=$MAKE
298     $ECHO COPY=$COPY
299     $ECHO DELETE=$DELETE
300 }
301
302 check_os_arch_word() {
303     if ! [[ -n $OS && -n $ARCH && -n $WORD ]] ; then
304         $ECHO "OS: $OS"
305         $ECHO "ARCH: $ARCH"
306         $ECHO "WORD: $WORD"
307         $ECHO "OS, ARCH, or WORD is empty.  Please report this."
308
309         $ECHO $MAKE_TARGET
310         exit_script 5
311     fi
312 }
313
314 set_build_info() {
315     check_os_arch_word
316     if [[ $OS == linux && $ARCH == ppc ]] ; then
317         MAKE_IMAGE_TARGET=linux-ppc.32
318         MAKE_TARGET=linux-ppc-32
319     elif [[ $OS == windows && $ARCH == x86 && $WORD == 64 ]] ; then
320         MAKE_IMAGE_TARGET=windows-x86.64
321         MAKE_TARGET=windows-x86-64
322     elif [[ $OS == windows && $ARCH == x86 && $WORD == 32 ]] ; then
323         MAKE_IMAGE_TARGET=windows-x86.32
324         MAKE_TARGET=windows-x86-32
325     elif [[ $ARCH == x86 && $WORD == 64 ]] ; then
326         MAKE_IMAGE_TARGET=unix-x86.64
327         MAKE_TARGET=$OS-x86-64
328     elif [[ $ARCH == x86 && $WORD == 32 ]] ; then
329         MAKE_IMAGE_TARGET=unix-x86.32
330         MAKE_TARGET=$OS-x86-32
331     else
332         MAKE_IMAGE_TARGET=$ARCH.$WORD
333         MAKE_TARGET=$OS-$ARCH-$WORD
334     fi
335     BOOT_IMAGE=boot.$MAKE_IMAGE_TARGET.image
336 }
337
338 parse_build_info() {
339     ensure_program_installed cut
340     $ECHO "Parsing make target from command line: $1"
341     OS=`echo $1 | cut -d '-' -f 1`
342     ARCH=`echo $1 | cut -d '-' -f 2`
343     WORD=`echo $1 | cut -d '-' -f 3`
344     
345     if [[ $OS == linux && $ARCH == ppc ]] ; then WORD=32; fi
346     if [[ $OS == linux && $ARCH == arm ]] ; then WORD=32; fi
347     if [[ $OS == macosx && $ARCH == ppc ]] ; then WORD=32; fi
348     
349     $ECHO "OS=$OS"
350     $ECHO "ARCH=$ARCH"
351     $ECHO "WORD=$WORD"
352 }
353
354 find_build_info() {
355     find_os
356     find_architecture
357     find_word_size
358     set_factor_binary
359     set_factor_library
360     set_factor_image
361     set_build_info
362     set_downloader
363     set_gcc
364     set_make
365     echo_build_info
366 }
367
368 invoke_git() {
369     git $*
370     check_ret git
371 }
372
373 git_clone() {
374     $ECHO "Downloading the git repository from factorcode.org..."
375     invoke_git clone $GIT_URL
376 }
377
378 update_script_name() {
379     $ECHO `dirname $0`/_update.sh
380 }
381
382 update_script() {
383     update_script=`update_script_name`
384     bash_path=`which bash`
385     $ECHO "#!$bash_path" >"$update_script"
386     $ECHO "git pull \"$GIT_URL\" master" >>"$update_script"
387     $ECHO "if [[ \$? -eq 0 ]]; then exec \"$0\" $SCRIPT_ARGS; else echo \"git pull failed\"; exit 2; fi" \
388         >>"$update_script"
389     $ECHO "exit 0" >>"$update_script"
390
391     chmod 755 "$update_script"
392     exec "$update_script"
393 }
394
395 update_script_changed() {
396     invoke_git diff --stat `invoke_git merge-base HEAD FETCH_HEAD` FETCH_HEAD | grep 'build-support.factor\.sh' >/dev/null 
397 }
398
399 git_fetch_factorcode() {
400     $ECHO "Fetching the git repository from factorcode.org..."
401
402     rm -f `update_script_name`
403     invoke_git fetch "$GIT_URL" master
404
405     if update_script_changed; then
406         $ECHO "Updating and restarting the factor.sh script..."
407         update_script
408     else
409         $ECHO "Updating the working tree..."
410         invoke_git pull "$GIT_URL" master
411     fi
412 }
413
414 cd_factor() {
415     cd factor
416     check_ret cd
417 }
418
419 set_copy() {
420     case $OS in
421         windows) COPY=cp;;
422         *) COPY=cp;;
423     esac
424 }
425
426 set_delete() {
427     case $OS in
428         windows) DELETE=rm;;
429         *) DELETE=rm;;
430     esac
431 }
432
433 backup_factor() {
434     $ECHO "Backing up factor..."
435     $COPY $FACTOR_BINARY $FACTOR_BINARY.bak
436     $COPY $FACTOR_LIBRARY $FACTOR_LIBRARY.bak
437     $COPY $BOOT_IMAGE $BOOT_IMAGE.bak
438     $COPY $FACTOR_IMAGE $FACTOR_IMAGE.bak
439     $ECHO "Done with backup."
440 }
441
442 check_makefile_exists() {
443     if [[ ! -e "GNUmakefile" ]] ; then
444         $ECHO ""
445         $ECHO "***GNUmakefile not found***"
446         $ECHO "You are likely in the wrong directory."
447         $ECHO "Run this script from your factor directory:"
448         $ECHO "     ./build-support/factor.sh"
449         exit_script 6
450     fi
451 }
452
453 invoke_make() {
454     check_makefile_exists
455     $MAKE $MAKE_OPTS $*
456     check_ret $MAKE
457 }
458
459 make_clean() {
460     invoke_make clean
461 }
462
463 make_factor() {
464     invoke_make NO_UI=$NO_UI $MAKE_TARGET -j5
465 }
466
467 make_clean_factor() {
468     make_clean
469     make_factor
470 }
471
472 update_boot_images() {
473     $ECHO "Deleting old images..."
474     $DELETE checksums.txt* > /dev/null 2>&1
475     # delete boot images with one or two characters after the dot
476     $DELETE $BOOT_IMAGE.{?,??} > /dev/null 2>&1
477     $DELETE temp/staging.*.image > /dev/null 2>&1
478     if [[ -f $BOOT_IMAGE ]] ; then
479         get_url http://downloads.factorcode.org/images/latest/checksums.txt
480         factorcode_md5=`cat checksums.txt|grep $BOOT_IMAGE|cut -f2 -d' '`
481         set_md5sum
482         disk_md5=`$MD5SUM $BOOT_IMAGE|cut -f1 -d' '`
483         $ECHO "Factorcode md5: $factorcode_md5";
484         $ECHO "Disk md5: $disk_md5";
485         if [[ "$factorcode_md5" == "$disk_md5" ]] ; then
486             $ECHO "Your disk boot image matches the one on factorcode.org."
487         else
488             $DELETE $BOOT_IMAGE > /dev/null 2>&1
489             get_boot_image;
490         fi
491     else
492         get_boot_image
493     fi
494 }
495
496 get_boot_image() {
497     $ECHO "Downloading boot image $BOOT_IMAGE."
498     get_url http://downloads.factorcode.org/images/latest/$BOOT_IMAGE
499 }
500
501 get_url() {
502     if [[ -z $DOWNLOADER ]] ; then
503         set_downloader;
504     fi
505     $ECHO $DOWNLOADER $1 ;
506     $DOWNLOADER $1
507     check_ret $DOWNLOADER
508 }
509
510 get_config_info() {
511     find_build_info
512     check_installed_programs
513     check_libraries
514 }
515
516 copy_fresh_image() {
517     $ECHO "Copying $FACTOR_IMAGE to $FACTOR_IMAGE_FRESH..."
518     $COPY $FACTOR_IMAGE $FACTOR_IMAGE_FRESH
519 }
520
521 bootstrap() {
522     ./$FACTOR_BINARY -i=$BOOT_IMAGE
523     copy_fresh_image
524 }
525
526 install() {
527     check_factor_exists
528     get_config_info
529     git_clone
530     cd_factor
531     make_factor
532     get_boot_image
533     bootstrap
534 }
535
536 update() {
537     get_config_info
538     check_git_branch
539     git_fetch_factorcode
540     backup_factor
541     make_clean_factor
542 }
543
544 download_and_bootstrap() {
545     update_boot_images
546     bootstrap
547 }
548
549 net_bootstrap_no_pull() {
550     get_config_info
551     make_clean_factor
552     download_and_bootstrap
553 }
554
555 refresh_image() {
556     ./$FACTOR_BINARY -script -e="USING: vocabs.loader vocabs.refresh system memory ; refresh-all save 0 exit"
557     check_ret factor
558 }
559
560 make_boot_image() {
561     ./$FACTOR_BINARY -script -e="\"$MAKE_IMAGE_TARGET\" USING: system bootstrap.image memory ; make-image save 0 exit"
562     check_ret factor
563 }
564
565 install_deps_apt_get() {
566     sudo apt-get --yes install libc6-dev libpango1.0-dev libx11-dev xorg-dev libgtk2.0-dev gtk2-engines-pixbuf libgtkglext1-dev wget git git-doc rlwrap clang gcc make screen tmux libssl-dev
567     check_ret sudo
568 }
569
570 install_deps_pacman() {
571     sudo pacman --noconfirm -S gcc clang make rlwrap git wget pango glibc gtk2 gtk3 gtkglext gtk-engines gdk-pixbuf2 libx11 screen tmux
572     check_ret sudo
573 }
574
575 install_deps_macosx() {
576     test_program_installed git
577     if [[ $? -ne 1 ]] ; then
578         ensure_program_installed yes
579         $ECHO "git not found."
580         $ECHO "This script requires either git-core or port."
581         $ECHO "If it fails, install git-core or port and try again."
582         ensure_program_installed port
583         $ECHO "Installing git-core with port...this will take awhile."
584         yes | sudo port install git-core
585     fi
586 }
587
588 usage() {
589     $ECHO "usage: $0 command [optional-target]"
590     $ECHO "  install - git clone, compile, bootstrap"
591     $ECHO "  deps-apt-get - install required packages for Factor on Linux using apt-get"
592     $ECHO "  deps-pacman - install required packages for Factor on Linux using pacman"
593     $ECHO "  deps-macosx - install git on MacOSX using port"
594     $ECHO "  self-update - git pull, make local boot image, bootstrap"
595     $ECHO "  quick-update - git pull, refresh-all, save"
596     $ECHO "  update - git pull, download a boot image, recompile, bootstrap"
597     $ECHO "  bootstrap - bootstrap with an existing boot image"
598     $ECHO "  net-bootstrap - download a boot image, bootstrap"
599     $ECHO "  make-target - find and print the os-arch-cpu string"
600     $ECHO "  report - print the build variables"
601     $ECHO ""
602     $ECHO "If you are behind a firewall, invoke as:"
603     $ECHO "env GIT_PROTOCOL=http $0 <command>"
604     $ECHO ""
605     $ECHO "Example for overriding the default target:"
606     $ECHO "    $0 update macosx-x86-32"
607 }
608
609 MAKE_TARGET=unknown
610
611 # -n is nonzero length, -z is zero length
612 if [[ -n "$2" ]] ; then
613     parse_build_info $2
614 fi
615
616 set_copy
617 set_delete
618
619 case "$1" in
620     install) install ;;
621     deps-apt-get) install_deps_apt_get ;;
622     deps-pacman) install_deps_pacman ;;
623     deps-macosx) install_deps_macosx ;;
624     self-update) update; make_boot_image; bootstrap;;
625     quick-update) update; refresh_image ;;
626     update) update; download_and_bootstrap ;;
627     bootstrap) get_config_info; bootstrap ;;
628     net-bootstrap) net_bootstrap_no_pull ;;
629     make-target) FIND_MAKE_TARGET=true; ECHO=false; find_build_info; exit_script ;;
630     report) find_build_info ;;
631     *) usage ;;
632 esac