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