1#!/usr/bin/env bash
2#===-- test-release.sh - Test the LLVM release candidates ------------------===#
3#
4#                     The LLVM Compiler Infrastructure
5#
6# This file is distributed under the University of Illinois Open Source
7# License.
8#
9#===------------------------------------------------------------------------===#
10#
11# Download, build, and test the release candidate for an LLVM release.
12#
13#===------------------------------------------------------------------------===#
14
15if [ `uname -s` = "FreeBSD" ]; then
16    MAKE=gmake
17else
18    MAKE=make
19fi
20
21projects="llvm cfe dragonegg compiler-rt libcxx test-suite clang-tools-extra"
22
23# Base SVN URL for the sources.
24Base_url="http://llvm.org/svn/llvm-project"
25
26Release=""
27Release_no_dot=""
28RC=""
29Triple=""
30use_gzip="no"
31do_checkout="yes"
32do_ada="no"
33do_clang="yes"
34do_dragonegg="no"
35do_fortran="no"
36do_objc="yes"
37do_64bit="yes"
38do_debug="no"
39do_asserts="no"
40do_compare="yes"
41BuildDir="`pwd`"
42
43function usage() {
44    echo "usage: `basename $0` -release X.Y -rc NUM [OPTIONS]"
45    echo ""
46    echo " -release X.Y      The release number to test."
47    echo " -rc NUM           The pre-release candidate number."
48    echo " -final            The final release candidate."
49    echo " -triple TRIPLE    The target triple for this machine."
50    echo " -j NUM            Number of compile jobs to run. [default: 3]"
51    echo " -build-dir DIR    Directory to perform testing in. [default: pwd]"
52    echo " -no-checkout      Don't checkout the sources from SVN."
53    echo " -no-64bit         Don't test the 64-bit version. [default: yes]"
54    echo " -enable-ada       Build Ada. [default: disable]"
55    echo " -disable-clang    Do not test clang. [default: enable]"
56    echo " -enable-dragonegg Test dragonegg. [default: disable]"
57    echo " -enable-fortran   Enable Fortran build. [default: disable]"
58    echo " -disable-objc     Disable ObjC build. [default: enable]"
59    echo " -test-debug       Test the debug build. [default: no]"
60    echo " -test-asserts     Test with asserts on. [default: no]"
61    echo " -no-compare-files Don't test that phase 2 and 3 files are identical."
62    echo " -use-gzip         Use gzip instead of xz."
63}
64
65while [ $# -gt 0 ]; do
66    case $1 in
67        -release | --release )
68            shift
69            Release="$1"
70            Release_no_dot="`echo $1 | sed -e 's,\.,,'`"
71            ;;
72        -rc | --rc | -RC | --RC )
73            shift
74            RC="rc$1"
75            ;;
76        -final | --final )
77            RC=final
78            ;;
79        -triple | --triple )
80            shift
81            Triple="$1"
82            ;;
83        -j* )
84            NumJobs="`echo $1 | sed -e 's,-j\([0-9]*\),\1,g'`"
85            if [ -z "$NumJobs" ]; then
86                shift
87                NumJobs="$1"
88            fi
89            ;;
90        -build-dir | --build-dir | -builddir | --builddir )
91            shift
92            BuildDir="$1"
93            ;;
94        -no-checkout | --no-checkout )
95            do_checkout="no"
96            ;;
97        -no-64bit | --no-64bit )
98            do_64bit="no"
99            ;;
100        -enable-ada | --enable-ada )
101            do_ada="yes"
102            ;;
103        -disable-clang | --disable-clang )
104            do_clang="no"
105            ;;
106        -enable-dragonegg | --enable-dragonegg )
107            do_dragonegg="yes"
108            ;;
109        -enable-fortran | --enable-fortran )
110            do_fortran="yes"
111            ;;
112        -disable-objc | --disable-objc )
113            do_objc="no"
114            ;;
115        -test-debug | --test-debug )
116            do_debug="yes"
117            ;;
118        -test-asserts | --test-asserts )
119            do_asserts="yes"
120            ;;
121        -no-compare-files | --no-compare-files )
122            do_compare="no"
123            ;;
124        -use-gzip | --use-gzip )
125            use_gzip="yes"
126            ;;
127        -help | --help | -h | --h | -\? )
128            usage
129            exit 0
130            ;;
131        * )
132            echo "unknown option: $1"
133            usage
134            exit 1
135            ;;
136    esac
137    shift
138done
139
140# Check required arguments.
141if [ -z "$Release" ]; then
142    echo "error: no release number specified"
143    exit 1
144fi
145if [ -z "$RC" ]; then
146    echo "error: no release candidate number specified"
147    exit 1
148fi
149if [ -z "$Triple" ]; then
150    echo "error: no target triple specified"
151    exit 1
152fi
153
154# Figure out how many make processes to run.
155if [ -z "$NumJobs" ]; then
156    NumJobs=`sysctl -n hw.activecpu 2> /dev/null || true`
157fi
158if [ -z "$NumJobs" ]; then
159    NumJobs=`sysctl -n hw.ncpu 2> /dev/null || true`
160fi
161if [ -z "$NumJobs" ]; then
162    NumJobs=`grep -c processor /proc/cpuinfo 2> /dev/null || true`
163fi
164if [ -z "$NumJobs" ]; then
165    NumJobs=3
166fi
167
168# Go to the build directory (may be different from CWD)
169BuildDir=$BuildDir/$RC
170mkdir -p $BuildDir
171cd $BuildDir
172
173# Location of log files.
174LogDir=$BuildDir/logs
175mkdir -p $LogDir
176
177# Final package name.
178Package=clang+llvm-$Release
179if [ $RC != "final" ]; then
180  Package=$Package-$RC
181fi
182Package=$Package-$Triple
183
184# Find compilers.
185if [ "$do_dragonegg" = "yes" ]; then
186    gcc_compiler="$GCC"
187    if [ -z "$gcc_compiler" ]; then
188        gcc_compiler="`which gcc`"
189        if [ -z "$gcc_compiler" ]; then
190            echo "error: cannot find gcc to use with dragonegg"
191            exit 1
192        fi
193    fi
194
195    gxx_compiler="$GXX"
196    if [ -z "$gxx_compiler" ]; then
197        gxx_compiler="`which g++`"
198        if [ -z "$gxx_compiler" ]; then
199            echo "error: cannot find g++ to use with dragonegg"
200            exit 1
201        fi
202    fi
203fi
204
205# Make sure that a required program is available
206function check_program_exists() {
207  local program="$1"
208  if ! type -P $program > /dev/null 2>&1 ; then
209    echo "program '$1' not found !"
210    exit 1
211  fi
212}
213
214if [ `uname -s` != "Darwin" ]; then
215  check_program_exists 'chrpath'
216  check_program_exists 'file'
217  check_program_exists 'objdump'
218fi
219
220# Make sure that the URLs are valid.
221function check_valid_urls() {
222    for proj in $projects ; do
223        echo "# Validating $proj SVN URL"
224
225        if ! svn ls $Base_url/$proj/tags/RELEASE_$Release_no_dot/$RC > /dev/null 2>&1 ; then
226            echo "$proj $Release release candidate $RC doesn't exist!"
227            exit 1
228        fi
229    done
230}
231
232# Export sources to the build directory.
233function export_sources() {
234    check_valid_urls
235
236    for proj in $projects ; do
237        echo "# Exporting $proj $Release-$RC sources"
238        if ! svn export -q $Base_url/$proj/tags/RELEASE_$Release_no_dot/$RC $proj.src ; then
239            echo "error: failed to export $proj project"
240            exit 1
241        fi
242    done
243
244    echo "# Creating symlinks"
245    cd $BuildDir/llvm.src/tools
246    if [ ! -h clang ]; then
247        ln -s ../../cfe.src clang
248    fi
249    cd $BuildDir/llvm.src/tools/clang/tools
250    if [ ! -h clang-tools-extra ]; then
251        ln -s ../../../../clang-tools-extra.src extra
252    fi
253    cd $BuildDir/llvm.src/projects
254    if [ ! -h test-suite ]; then
255        ln -s ../../test-suite.src test-suite
256    fi
257    if [ ! -h compiler-rt ]; then
258        ln -s ../../compiler-rt.src compiler-rt
259    fi
260    if [ ! -h libcxx ]; then
261        ln -s ../../libcxx.src libcxx
262    fi
263    cd $BuildDir
264}
265
266function configure_llvmCore() {
267    Phase="$1"
268    Flavor="$2"
269    ObjDir="$3"
270    InstallDir="$4"
271
272    case $Flavor in
273        Release | Release-64 )
274            Optimized="yes"
275            Assertions="no"
276            ;;
277        Release+Asserts )
278            Optimized="yes"
279            Assertions="yes"
280            ;;
281        Debug )
282            Optimized="no"
283            Assertions="yes"
284            ;;
285        * )
286            echo "# Invalid flavor '$Flavor'"
287            echo ""
288            return
289            ;;
290    esac
291
292    echo "# Using C compiler: $c_compiler"
293    echo "# Using C++ compiler: $cxx_compiler"
294
295    cd $ObjDir
296    echo "# Configuring llvm $Release-$RC $Flavor"
297    echo "# $BuildDir/llvm.src/configure --prefix=$InstallDir \
298        --enable-optimized=$Optimized \
299        --enable-assertions=$Assertions"
300    env CC="$c_compiler" CXX="$cxx_compiler" \
301    $BuildDir/llvm.src/configure --prefix=$InstallDir \
302        --enable-optimized=$Optimized \
303        --enable-assertions=$Assertions \
304        --disable-timestamps \
305        2>&1 | tee $LogDir/llvm.configure-Phase$Phase-$Flavor.log
306    cd $BuildDir
307}
308
309function build_llvmCore() {
310    Phase="$1"
311    Flavor="$2"
312    ObjDir="$3"
313    ExtraOpts=""
314
315    if [ "$Flavor" = "Release-64" ]; then
316        ExtraOpts="EXTRA_OPTIONS=-m64"
317    fi
318
319    cd $ObjDir
320    echo "# Compiling llvm $Release-$RC $Flavor"
321    echo "# ${MAKE} -j $NumJobs VERBOSE=1 $ExtraOpts"
322    ${MAKE} -j $NumJobs VERBOSE=1 $ExtraOpts \
323        2>&1 | tee $LogDir/llvm.make-Phase$Phase-$Flavor.log
324
325    echo "# Installing llvm $Release-$RC $Flavor"
326    echo "# ${MAKE} install"
327    ${MAKE} install \
328        2>&1 | tee $LogDir/llvm.install-Phase$Phase-$Flavor.log
329    cd $BuildDir
330}
331
332function build_dragonegg() {
333    Phase="$1"
334    Flavor="$2"
335    LLVMInstallDir="$3"
336    DragonEggObjDir="$4"
337    LLVM_CONFIG=$LLVMInstallDir/bin/llvm-config
338    TOP_DIR=$BuildDir/dragonegg.src
339
340    echo "# Targeted compiler: $gcc_compiler"
341
342    cd $DragonEggObjDir
343    echo "# Compiling phase $Phase dragonegg $Release-$RC $Flavor"
344    echo -n "# CXX=$cxx_compiler TOP_DIR=$TOP_DIR GCC=$gcc_compiler "
345    echo -n "LLVM_CONFIG=$LLVM_CONFIG ${MAKE} -f $TOP_DIR/Makefile "
346    echo "-j $NumJobs VERBOSE=1"
347    CXX="$cxx_compiler" TOP_DIR="$TOP_DIR" GCC="$gcc_compiler" \
348    LLVM_CONFIG="$LLVM_CONFIG" ${MAKE} -f $TOP_DIR/Makefile \
349        -j $NumJobs VERBOSE=1 \
350            2>&1 | tee $LogDir/dragonegg-Phase$Phase-$Flavor.log
351    cd $BuildDir
352}
353
354function test_llvmCore() {
355    Phase="$1"
356    Flavor="$2"
357    ObjDir="$3"
358
359    cd $ObjDir
360    ${MAKE} -k check-all \
361        2>&1 | tee $LogDir/llvm.check-Phase$Phase-$Flavor.log
362    ${MAKE} -k unittests \
363        2>&1 | tee $LogDir/llvm.unittests-Phase$Phase-$Flavor.log
364    cd $BuildDir
365}
366
367# Clean RPATH. Libtool adds the build directory to the search path, which is
368# not necessary --- and even harmful --- for the binary packages we release.
369function clean_RPATH() {
370  if [ `uname -s` = "Darwin" ]; then
371    return
372  fi
373  local InstallPath="$1"
374  for Candidate in `find $InstallPath/{bin,lib} -type f`; do
375    if file $Candidate | grep ELF | egrep 'executable|shared object' > /dev/null 2>&1 ; then
376      rpath=`objdump -x $Candidate | grep 'RPATH' | sed -e's/^ *RPATH *//'`
377      if [ -n "$rpath" ]; then
378        newrpath=`echo $rpath | sed -e's/.*\(\$ORIGIN[^:]*\).*/\1/'`
379        chrpath -r $newrpath $Candidate 2>&1 > /dev/null 2>&1
380      fi
381    fi
382  done
383}
384
385# Create a package of the release binaries.
386function package_release() {
387    cwd=`pwd`
388    cd $BuildDir/Phase3/Release
389    mv llvmCore-$Release-$RC.install $Package
390    if [ "$use_gzip" = "yes" ]; then
391      tar cfz $BuildDir/$Package.tar.gz $Package
392    else
393      tar cfJ $BuildDir/$Package.tar.xz $Package
394    fi
395    mv $Package llvmCore-$Release-$RC.install
396    cd $cwd
397}
398
399set -e                          # Exit if any command fails
400
401if [ "$do_checkout" = "yes" ]; then
402    export_sources
403fi
404
405(
406Flavors="Release"
407if [ "$do_debug" = "yes" ]; then
408    Flavors="Debug $Flavors"
409fi
410if [ "$do_asserts" = "yes" ]; then
411    Flavors="$Flavors Release+Asserts"
412fi
413if [ "$do_64bit" = "yes" ]; then
414    Flavors="$Flavors Release-64"
415fi
416
417for Flavor in $Flavors ; do
418    echo ""
419    echo ""
420    echo "********************************************************************************"
421    echo "  Release:     $Release-$RC"
422    echo "  Build:       $Flavor"
423    echo "  System Info: "
424    echo "    `uname -a`"
425    echo "********************************************************************************"
426    echo ""
427
428    c_compiler="$CC"
429    cxx_compiler="$CXX"
430
431    llvmCore_phase1_objdir=$BuildDir/Phase1/$Flavor/llvmCore-$Release-$RC.obj
432    llvmCore_phase1_installdir=$BuildDir/Phase1/$Flavor/llvmCore-$Release-$RC.install
433    dragonegg_phase1_objdir=$BuildDir/Phase1/$Flavor/DragonEgg-$Release-$RC.obj
434
435    llvmCore_phase2_objdir=$BuildDir/Phase2/$Flavor/llvmCore-$Release-$RC.obj
436    llvmCore_phase2_installdir=$BuildDir/Phase2/$Flavor/llvmCore-$Release-$RC.install
437    llvmCore_de_phase2_objdir=$BuildDir/Phase2/$Flavor/llvmCore-DragonEgg-$Release-$RC.obj
438    llvmCore_de_phase2_installdir=$BuildDir/Phase2/$Flavor/llvmCore-DragonEgg-$Release-$RC.install
439    dragonegg_phase2_objdir=$BuildDir/Phase2/$Flavor/DragonEgg-$Release-$RC.obj
440
441    llvmCore_phase3_objdir=$BuildDir/Phase3/$Flavor/llvmCore-$Release-$RC.obj
442    llvmCore_phase3_installdir=$BuildDir/Phase3/$Flavor/llvmCore-$Release-$RC.install
443    llvmCore_de_phase3_objdir=$BuildDir/Phase3/$Flavor/llvmCore-DragonEgg-$Release-$RC.obj
444    llvmCore_de_phase3_installdir=$BuildDir/Phase3/$Flavor/llvmCore-DragonEgg-$Release-$RC.install
445    dragonegg_phase3_objdir=$BuildDir/Phase3/$Flavor/DragonEgg-$Release-$RC.obj
446
447    rm -rf $llvmCore_phase1_objdir
448    rm -rf $llvmCore_phase1_installdir
449    rm -rf $dragonegg_phase1_objdir
450
451    rm -rf $llvmCore_phase2_objdir
452    rm -rf $llvmCore_phase2_installdir
453    rm -rf $llvmCore_de_phase2_objdir
454    rm -rf $llvmCore_de_phase2_installdir
455    rm -rf $dragonegg_phase2_objdir
456
457    rm -rf $llvmCore_phase3_objdir
458    rm -rf $llvmCore_phase3_installdir
459    rm -rf $llvmCore_de_phase3_objdir
460    rm -rf $llvmCore_de_phase3_installdir
461    rm -rf $dragonegg_phase3_objdir
462
463    mkdir -p $llvmCore_phase1_objdir
464    mkdir -p $llvmCore_phase1_installdir
465    mkdir -p $dragonegg_phase1_objdir
466
467    mkdir -p $llvmCore_phase2_objdir
468    mkdir -p $llvmCore_phase2_installdir
469    mkdir -p $llvmCore_de_phase2_objdir
470    mkdir -p $llvmCore_de_phase2_installdir
471    mkdir -p $dragonegg_phase2_objdir
472
473    mkdir -p $llvmCore_phase3_objdir
474    mkdir -p $llvmCore_phase3_installdir
475    mkdir -p $llvmCore_de_phase3_objdir
476    mkdir -p $llvmCore_de_phase3_installdir
477    mkdir -p $dragonegg_phase3_objdir
478
479    ############################################################################
480    # Phase 1: Build llvmCore and clang
481    echo "# Phase 1: Building llvmCore"
482    configure_llvmCore 1 $Flavor \
483        $llvmCore_phase1_objdir $llvmCore_phase1_installdir
484    build_llvmCore 1 $Flavor \
485        $llvmCore_phase1_objdir
486    clean_RPATH $llvmCore_phase1_installdir
487
488    # Test clang
489    if [ "$do_clang" = "yes" ]; then
490        ########################################################################
491        # Phase 2: Build llvmCore with newly built clang from phase 1.
492        c_compiler=$llvmCore_phase1_installdir/bin/clang
493        cxx_compiler=$llvmCore_phase1_installdir/bin/clang++
494        echo "# Phase 2: Building llvmCore"
495        configure_llvmCore 2 $Flavor \
496            $llvmCore_phase2_objdir $llvmCore_phase2_installdir
497        build_llvmCore 2 $Flavor \
498            $llvmCore_phase2_objdir
499        clean_RPATH $llvmCore_phase2_installdir
500
501        ########################################################################
502        # Phase 3: Build llvmCore with newly built clang from phase 2.
503        c_compiler=$llvmCore_phase2_installdir/bin/clang
504        cxx_compiler=$llvmCore_phase2_installdir/bin/clang++
505        echo "# Phase 3: Building llvmCore"
506        configure_llvmCore 3 $Flavor \
507            $llvmCore_phase3_objdir $llvmCore_phase3_installdir
508        build_llvmCore 3 $Flavor \
509            $llvmCore_phase3_objdir
510        clean_RPATH $llvmCore_phase3_installdir
511
512        ########################################################################
513        # Testing: Test phase 3
514        echo "# Testing - built with clang"
515        test_llvmCore 3 $Flavor $llvmCore_phase3_objdir
516
517        ########################################################################
518        # Compare .o files between Phase2 and Phase3 and report which ones
519        # differ.
520        if [ "$do_compare" = "yes" ]; then
521            echo
522            echo "# Comparing Phase 2 and Phase 3 files"
523            for o in `find $llvmCore_phase2_objdir -name '*.o'` ; do
524                p3=`echo $o | sed -e 's,Phase2,Phase3,'`
525                if ! cmp --ignore-initial=16 $o $p3 > /dev/null 2>&1 ; then
526                    echo "file `basename $o` differs between phase 2 and phase 3"
527                fi
528            done
529        fi
530    fi
531
532    # Test dragonegg
533    if [ "$do_dragonegg" = "yes" ]; then
534        # Build dragonegg using the targeted gcc.  This isn't necessary, but
535        # helps avoid using broken versions of gcc (which are legion), tests
536        # that the targeted gcc is basically sane and is consistent with the
537        # later phases in which the targeted gcc + dragonegg are used.
538        c_compiler="$gcc_compiler"
539        cxx_compiler="$gxx_compiler"
540        build_dragonegg 1 $Flavor $llvmCore_phase1_installdir $dragonegg_phase1_objdir
541
542        ########################################################################
543        # Phase 2: Build llvmCore with newly built dragonegg from phase 1.
544        c_compiler="$gcc_compiler -fplugin=$dragonegg_phase1_objdir/dragonegg.so"
545        cxx_compiler="$gxx_compiler -fplugin=$dragonegg_phase1_objdir/dragonegg.so"
546        echo "# Phase 2: Building llvmCore with dragonegg"
547        configure_llvmCore 2 $Flavor \
548            $llvmCore_de_phase2_objdir $llvmCore_de_phase2_installdir
549        build_llvmCore 2 $Flavor \
550            $llvmCore_de_phase2_objdir
551        build_dragonegg 2 $Flavor $llvmCore_de_phase2_installdir $dragonegg_phase2_objdir
552        clean_RPATH $llvmCore_de_phase2_installdir
553
554        ########################################################################
555        # Phase 3: Build llvmCore with newly built dragonegg from phase 2.
556        c_compiler="$gcc_compiler -fplugin=$dragonegg_phase2_objdir/dragonegg.so"
557        cxx_compiler="$gxx_compiler -fplugin=$dragonegg_phase2_objdir/dragonegg.so"
558        echo "# Phase 3: Building llvmCore with dragonegg"
559        configure_llvmCore 3 $Flavor \
560            $llvmCore_de_phase3_objdir $llvmCore_de_phase3_installdir
561        build_llvmCore 3 $Flavor \
562            $llvmCore_de_phase3_objdir
563        build_dragonegg 3 $Flavor $llvmCore_de_phase3_installdir $dragonegg_phase3_objdir
564        clean_RPATH $llvmCore_de_phase3_installdir
565
566        ########################################################################
567        # Testing: Test phase 3
568        c_compiler="$gcc_compiler -fplugin=$dragonegg_phase3_objdir/dragonegg.so"
569        cxx_compiler="$gxx_compiler -fplugin=$dragonegg_phase3_objdir/dragonegg.so"
570        echo "# Testing - built with dragonegg"
571        test_llvmCore 3 $Flavor $llvmCore_de_phase3_objdir
572
573        ########################################################################
574        # Compare .o files between Phase2 and Phase3 and report which ones differ.
575        echo
576        echo "# Comparing Phase 2 and Phase 3 files"
577        for o in `find $llvmCore_de_phase2_objdir -name '*.o'` \
578          `find $dragonegg_phase2_objdir -name '*.o'` ; do
579            p3=`echo $o | sed -e 's,Phase2,Phase3,'`
580            if ! cmp --ignore-initial=16 $o $p3 > /dev/null 2>&1 ; then
581                echo "file `basename $o` differs between dragonegg phase 2 and phase 3"
582            fi
583        done
584    fi
585
586    # Otherwise just test the core.
587    if [ "$do_clang" != "yes" -a "$do_dragonegg" != "yes" ]; then
588        echo "# Testing - built with system compiler"
589        test_llvmCore 1 $Flavor $llvmCore_phase1_objdir
590    fi
591done
592) 2>&1 | tee $LogDir/testing.$Release-$RC.log
593
594package_release
595
596set +e
597
598# Woo hoo!
599echo "### Testing Finished ###"
600if [ "$use_gzip" = "yes" ]; then
601  echo "### Package: $Package.tar.gz"
602else
603  echo "### Package: $Package.tar.xz"
604fi
605echo "### Logs: $LogDir"
606exit 0
607