]> gitweb.factorcode.org Git - factor.git/blob - build-support/factor.sh
8b11038cab6723718e5feadb556b9afff951faac
[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                 [ -z "$CC" ] && CC=clang
96                 [ -z "$CXX" ] && CXX=clang++
97             else
98                 [ -z "$CC" ] && CC=gcc
99                 [ -z "$CXX" ] && CXX=g++
100             fi
101         ;;
102         *)
103             [ -z "$CC" ] && CC=gcc
104             [ -z "$CXX" ] && CXX=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     $CC -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 CXX=$CXX
298     $ECHO MAKE=$MAKE
299     $ECHO COPY=$COPY
300     $ECHO DELETE=$DELETE
301 }
302
303 check_os_arch_word() {
304     if ! [[ -n $OS && -n $ARCH && -n $WORD ]] ; then
305         $ECHO "OS: $OS"
306         $ECHO "ARCH: $ARCH"
307         $ECHO "WORD: $WORD"
308         $ECHO "OS, ARCH, or WORD is empty.  Please report this."
309
310         $ECHO $MAKE_TARGET
311         exit_script 5
312     fi
313 }
314
315 set_build_info() {
316     check_os_arch_word
317     if [[ $OS == linux && $ARCH == ppc ]] ; then
318         MAKE_IMAGE_TARGET=linux-ppc.32
319         MAKE_TARGET=linux-ppc-32
320     elif [[ $OS == windows && $ARCH == x86 && $WORD == 64 ]] ; then
321         MAKE_IMAGE_TARGET=windows-x86.64
322         MAKE_TARGET=windows-x86-64
323     elif [[ $OS == windows && $ARCH == x86 && $WORD == 32 ]] ; then
324         MAKE_IMAGE_TARGET=windows-x86.32
325         MAKE_TARGET=windows-x86-32
326     elif [[ $ARCH == x86 && $WORD == 64 ]] ; then
327         MAKE_IMAGE_TARGET=unix-x86.64
328         MAKE_TARGET=$OS-x86-64
329     elif [[ $ARCH == x86 && $WORD == 32 ]] ; then
330         MAKE_IMAGE_TARGET=unix-x86.32
331         MAKE_TARGET=$OS-x86-32
332     else
333         MAKE_IMAGE_TARGET=$ARCH.$WORD
334         MAKE_TARGET=$OS-$ARCH-$WORD
335     fi
336     BOOT_IMAGE=boot.$MAKE_IMAGE_TARGET.image
337 }
338
339 parse_build_info() {
340     ensure_program_installed cut
341     $ECHO "Parsing make target from command line: $1"
342     OS=`echo $1 | cut -d '-' -f 1`
343     ARCH=`echo $1 | cut -d '-' -f 2`
344     WORD=`echo $1 | cut -d '-' -f 3`
345     
346     if [[ $OS == linux && $ARCH == ppc ]] ; then WORD=32; fi
347     if [[ $OS == linux && $ARCH == arm ]] ; then WORD=32; fi
348     if [[ $OS == macosx && $ARCH == ppc ]] ; then WORD=32; fi
349
350     $ECHO "OS=$OS"
351     $ECHO "ARCH=$ARCH"
352     $ECHO "WORD=$WORD"
353 }
354
355 find_build_info() {
356     find_os
357     find_architecture
358     set_gcc
359     find_word_size
360     set_factor_binary
361     set_factor_library
362     set_factor_image
363     set_build_info
364     set_downloader
365     set_make
366     echo_build_info
367 }
368
369 invoke_git() {
370     git $*
371     check_ret git
372 }
373
374 git_clone() {
375     $ECHO "Downloading the git repository from factorcode.org..."
376     invoke_git clone $GIT_URL
377 }
378
379 update_script_name() {
380     $ECHO `dirname $0`/_update.sh
381 }
382
383 update_script() {
384     update_script=`update_script_name`
385     bash_path=`which bash`
386     $ECHO "#!$bash_path" >"$update_script"
387     $ECHO "git pull \"$GIT_URL\" master" >>"$update_script"
388     $ECHO "if [[ \$? -eq 0 ]]; then exec \"$0\" $SCRIPT_ARGS; else echo \"git pull failed\"; exit 2; fi" \
389         >>"$update_script"
390     $ECHO "exit 0" >>"$update_script"
391
392     chmod 755 "$update_script"
393     exec "$update_script"
394 }
395
396 update_script_changed() {
397     invoke_git diff --stat `invoke_git merge-base HEAD FETCH_HEAD` FETCH_HEAD | grep 'build-support.factor\.sh' >/dev/null 
398 }
399
400 git_fetch_factorcode() {
401     $ECHO "Fetching the git repository from factorcode.org..."
402
403     rm -f `update_script_name`
404     invoke_git fetch "$GIT_URL" master
405
406     if update_script_changed; then
407         $ECHO "Updating and restarting the factor.sh script..."
408         update_script
409     else
410         $ECHO "Updating the working tree..."
411         invoke_git pull "$GIT_URL" master
412     fi
413 }
414
415 cd_factor() {
416     cd factor
417     check_ret cd
418 }
419
420 set_copy() {
421     case $OS in
422         windows) COPY=cp;;
423         *) COPY=cp;;
424     esac
425 }
426
427 set_delete() {
428     case $OS in
429         windows) DELETE=rm;;
430         *) DELETE=rm;;
431     esac
432 }
433
434 backup_factor() {
435     $ECHO "Backing up factor..."
436     $COPY $FACTOR_BINARY $FACTOR_BINARY.bak
437     $COPY $FACTOR_LIBRARY $FACTOR_LIBRARY.bak
438     $COPY $BOOT_IMAGE $BOOT_IMAGE.bak
439     $COPY $FACTOR_IMAGE $FACTOR_IMAGE.bak
440     $ECHO "Done with backup."
441 }
442
443 check_makefile_exists() {
444     if [[ ! -e "GNUmakefile" ]] ; then
445         $ECHO ""
446         $ECHO "***GNUmakefile not found***"
447         $ECHO "You are likely in the wrong directory."
448         $ECHO "Run this script from your factor directory:"
449         $ECHO "     ./build-support/factor.sh"
450         exit_script 6
451     fi
452 }
453
454 invoke_make() {
455     check_makefile_exists
456     $MAKE $MAKE_OPTS $*
457     check_ret $MAKE
458 }
459
460 make_clean() {
461     invoke_make clean
462 }
463
464 make_factor() {
465     invoke_make NO_UI=$NO_UI $MAKE_TARGET -j5
466 }
467
468 make_clean_factor() {
469     make_clean
470     make_factor
471 }
472
473 update_boot_images() {
474     $ECHO "Deleting old images..."
475     $DELETE checksums.txt* > /dev/null 2>&1
476     # delete boot images with one or two characters after the dot
477     $DELETE $BOOT_IMAGE.{?,??} > /dev/null 2>&1
478     $DELETE temp/staging.*.image > /dev/null 2>&1
479     if [[ -f $BOOT_IMAGE ]] ; then
480         get_url http://downloads.factorcode.org/images/latest/checksums.txt
481         factorcode_md5=`cat checksums.txt|grep $BOOT_IMAGE|cut -f2 -d' '`
482         set_md5sum
483         disk_md5=`$MD5SUM $BOOT_IMAGE|cut -f1 -d' '`
484         $ECHO "Factorcode md5: $factorcode_md5";
485         $ECHO "Disk md5: $disk_md5";
486         if [[ "$factorcode_md5" == "$disk_md5" ]] ; then
487             $ECHO "Your disk boot image matches the one on factorcode.org."
488         else
489             $DELETE $BOOT_IMAGE > /dev/null 2>&1
490             get_boot_image;
491         fi
492     else
493         get_boot_image
494     fi
495 }
496
497 get_boot_image() {
498     $ECHO "Downloading boot image $BOOT_IMAGE."
499     get_url http://downloads.factorcode.org/images/latest/$BOOT_IMAGE
500 }
501
502 get_url() {
503     if [[ -z $DOWNLOADER ]] ; then
504         set_downloader;
505     fi
506     $ECHO $DOWNLOADER $1 ;
507     $DOWNLOADER $1
508     check_ret $DOWNLOADER
509 }
510
511 get_config_info() {
512     find_build_info
513     check_installed_programs
514     check_libraries
515 }
516
517 copy_fresh_image() {
518     $ECHO "Copying $FACTOR_IMAGE to $FACTOR_IMAGE_FRESH..."
519     $COPY $FACTOR_IMAGE $FACTOR_IMAGE_FRESH
520 }
521
522 bootstrap() {
523     ./$FACTOR_BINARY -i=$BOOT_IMAGE
524     copy_fresh_image
525 }
526
527 install() {
528     check_factor_exists
529     get_config_info
530     git_clone
531     cd_factor
532     make_factor
533     get_boot_image
534     bootstrap
535 }
536
537 update() {
538     get_config_info
539     check_git_branch
540     git_fetch_factorcode
541     backup_factor
542     make_clean_factor
543 }
544
545 download_and_bootstrap() {
546     update_boot_images
547     bootstrap
548 }
549
550 net_bootstrap_no_pull() {
551     get_config_info
552     make_clean_factor
553     download_and_bootstrap
554 }
555
556 refresh_image() {
557     ./$FACTOR_BINARY -script -e="USING: vocabs.loader vocabs.refresh system memory ; refresh-all save 0 exit"
558     check_ret factor
559 }
560
561 make_boot_image() {
562     ./$FACTOR_BINARY -script -e="\"$MAKE_IMAGE_TARGET\" USING: system bootstrap.image memory ; make-image save 0 exit"
563     check_ret factor
564 }
565
566 install_deps_apt_get() {
567     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
568     check_ret sudo
569 }
570
571 install_deps_pacman() {
572     sudo pacman --noconfirm -S gcc clang make rlwrap git wget pango glibc gtk2 gtk3 gtkglext gtk-engines gdk-pixbuf2 libx11 screen tmux
573     check_ret sudo
574 }
575
576 install_deps_macosx() {
577     test_program_installed git
578     if [[ $? -ne 1 ]] ; then
579         ensure_program_installed yes
580         $ECHO "git not found."
581         $ECHO "This script requires either git-core or port."
582         $ECHO "If it fails, install git-core or port and try again."
583         ensure_program_installed port
584         $ECHO "Installing git-core with port...this will take awhile."
585         yes | sudo port install git-core
586     fi
587 }
588
589 usage() {
590     $ECHO "usage: $0 command [optional-target]"
591     $ECHO "  install - git clone, compile, bootstrap"
592     $ECHO "  deps-apt-get - install required packages for Factor on Linux using apt-get"
593     $ECHO "  deps-pacman - install required packages for Factor on Linux using pacman"
594     $ECHO "  deps-macosx - install git on MacOSX using port"
595     $ECHO "  self-update - git pull, make local boot image, bootstrap"
596     $ECHO "  quick-update - git pull, refresh-all, save"
597     $ECHO "  update - git pull, download a boot image, recompile, bootstrap"
598     $ECHO "  bootstrap - bootstrap with an existing boot image"
599     $ECHO "  net-bootstrap - download a boot image, bootstrap"
600     $ECHO "  make-target - find and print the os-arch-cpu string"
601     $ECHO "  report - print the build variables"
602     $ECHO ""
603     $ECHO "If you are behind a firewall, invoke as:"
604     $ECHO "env GIT_PROTOCOL=http $0 <command>"
605     $ECHO ""
606     $ECHO "Example for overriding the default target:"
607     $ECHO "    $0 update macosx-x86-32"
608 }
609
610 MAKE_TARGET=unknown
611
612 # -n is nonzero length, -z is zero length
613 if [[ -n "$2" ]] ; then
614     parse_build_info $2
615 fi
616
617 set_copy
618 set_delete
619
620 case "$1" in
621     install) install ;;
622     deps-apt-get) install_deps_apt_get ;;
623     deps-pacman) install_deps_pacman ;;
624     deps-macosx) install_deps_macosx ;;
625     self-update) update; make_boot_image; bootstrap;;
626     quick-update) update; refresh_image ;;
627     update) update; download_and_bootstrap ;;
628     bootstrap) get_config_info; bootstrap ;;
629     net-bootstrap) net_bootstrap_no_pull ;;
630     make-target) FIND_MAKE_TARGET=true; ECHO=false; find_build_info; exit_script ;;
631     report) find_build_info ;;
632     *) usage ;;
633 esac