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=""
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/tools/clang/tools
214    if [ ! -h clang-tools-extra ]; then
215        ln -s ../../../../clang-tools-extra.src extra
216    fi
217    cd $BuildDir/llvm.src/projects
218    if [ ! -h test-suite ]; then
219        ln -s ../../test-suite.src test-suite
220    fi
221    if [ ! -h compiler-rt ]; then
222        ln -s ../../compiler-rt.src compiler-rt
223    fi
224    if [ ! -h libcxx ]; then
225        ln -s ../../libcxx.src libcxx
226    fi
227    cd $BuildDir
228}
229
230function configure_llvmCore() {
231    Phase="$1"
232    Flavor="$2"
233    ObjDir="$3"
234    InstallDir="$4"
235
236    case $Flavor in
237        Release | Release-64 )
238            Optimized="yes"
239            Assertions="no"
240            ;;
241        Release+Asserts )
242            Optimized="yes"
243            Assertions="yes"
244            ;;
245        Debug )
246            Optimized="no"
247            Assertions="yes"
248            ;;
249        * )
250            echo "# Invalid flavor '$Flavor'"
251            echo ""
252            return
253            ;;
254    esac
255
256    echo "# Using C compiler: $c_compiler"
257    echo "# Using C++ compiler: $cxx_compiler"
258
259    cd $ObjDir
260    echo "# Configuring llvm $Release-$RC $Flavor"
261    echo "# $BuildDir/llvm.src/configure --prefix=$InstallDir \
262        --enable-optimized=$Optimized \
263        --enable-assertions=$Assertions"
264    env CC="$c_compiler" CXX="$cxx_compiler" \
265    $BuildDir/llvm.src/configure --prefix=$InstallDir \
266        --enable-optimized=$Optimized \
267        --enable-assertions=$Assertions \
268        --disable-timestamps \
269        2>&1 | tee $LogDir/llvm.configure-Phase$Phase-$Flavor.log
270    cd $BuildDir
271}
272
273function build_llvmCore() {
274    Phase="$1"
275    Flavor="$2"
276    ObjDir="$3"
277    ExtraOpts=""
278
279    if [ "$Flavor" = "Release-64" ]; then
280        ExtraOpts="EXTRA_OPTIONS=-m64"
281    fi
282
283    cd $ObjDir
284    echo "# Compiling llvm $Release-$RC $Flavor"
285    echo "# ${MAKE} -j $NumJobs VERBOSE=1 $ExtraOpts"
286    ${MAKE} -j $NumJobs VERBOSE=1 $ExtraOpts \
287        2>&1 | tee $LogDir/llvm.make-Phase$Phase-$Flavor.log
288
289    echo "# Installing llvm $Release-$RC $Flavor"
290    echo "# ${MAKE} install"
291    ${MAKE} install \
292        2>&1 | tee $LogDir/llvm.install-Phase$Phase-$Flavor.log
293    cd $BuildDir
294}
295
296function build_dragonegg() {
297    Phase="$1"
298    Flavor="$2"
299    LLVMInstallDir="$3"
300    DragonEggObjDir="$4"
301    LLVM_CONFIG=$LLVMInstallDir/bin/llvm-config
302    TOP_DIR=$BuildDir/dragonegg.src
303
304    echo "# Targeted compiler: $gcc_compiler"
305
306    cd $DragonEggObjDir
307    echo "# Compiling phase $Phase dragonegg $Release-$RC $Flavor"
308    echo -n "# CXX=$cxx_compiler TOP_DIR=$TOP_DIR GCC=$gcc_compiler "
309    echo -n "LLVM_CONFIG=$LLVM_CONFIG ${MAKE} -f $TOP_DIR/Makefile "
310    echo "-j $NumJobs VERBOSE=1"
311    CXX="$cxx_compiler" TOP_DIR="$TOP_DIR" GCC="$gcc_compiler" \
312    LLVM_CONFIG="$LLVM_CONFIG" ${MAKE} -f $TOP_DIR/Makefile \
313        -j $NumJobs VERBOSE=1 \
314            2>&1 | tee $LogDir/dragonegg-Phase$Phase-$Flavor.log
315    cd $BuildDir
316}
317
318function test_llvmCore() {
319    Phase="$1"
320    Flavor="$2"
321    ObjDir="$3"
322
323    cd $ObjDir
324    ${MAKE} -k check-all \
325        2>&1 | tee $LogDir/llvm.check-Phase$Phase-$Flavor.log
326    ${MAKE} -k unittests \
327        2>&1 | tee $LogDir/llvm.unittests-Phase$Phase-$Flavor.log
328    cd $BuildDir
329}
330
331set -e                          # Exit if any command fails
332
333if [ "$do_checkout" = "yes" ]; then
334    export_sources
335fi
336
337(
338Flavors="Release"
339if [ "$do_debug" = "yes" ]; then
340    Flavors="Debug $Flavors"
341fi
342if [ "$do_asserts" = "yes" ]; then
343    Flavors="$Flavors Release+Asserts"
344fi
345if [ "$do_64bit" = "yes" ]; then
346    Flavors="$Flavors Release-64"
347fi
348
349for Flavor in $Flavors ; do
350    echo ""
351    echo ""
352    echo "********************************************************************************"
353    echo "  Release:     $Release-$RC"
354    echo "  Build:       $Flavor"
355    echo "  System Info: "
356    echo "    `uname -a`"
357    echo "********************************************************************************"
358    echo ""
359
360    c_compiler="$CC"
361    cxx_compiler="$CXX"
362
363    llvmCore_phase1_objdir=$BuildDir/Phase1/$Flavor/llvmCore-$Release-$RC.obj
364    llvmCore_phase1_installdir=$BuildDir/Phase1/$Flavor/llvmCore-$Release-$RC.install
365    dragonegg_phase1_objdir=$BuildDir/Phase1/$Flavor/DragonEgg-$Release-$RC.obj
366
367    llvmCore_phase2_objdir=$BuildDir/Phase2/$Flavor/llvmCore-$Release-$RC.obj
368    llvmCore_phase2_installdir=$BuildDir/Phase2/$Flavor/llvmCore-$Release-$RC.install
369    llvmCore_de_phase2_objdir=$BuildDir/Phase2/$Flavor/llvmCore-DragonEgg-$Release-$RC.obj
370    llvmCore_de_phase2_installdir=$BuildDir/Phase2/$Flavor/llvmCore-DragonEgg-$Release-$RC.install
371    dragonegg_phase2_objdir=$BuildDir/Phase2/$Flavor/DragonEgg-$Release-$RC.obj
372
373    llvmCore_phase3_objdir=$BuildDir/Phase3/$Flavor/llvmCore-$Release-$RC.obj
374    llvmCore_phase3_installdir=$BuildDir/Phase3/$Flavor/llvmCore-$Release-$RC.install
375    llvmCore_de_phase3_objdir=$BuildDir/Phase3/$Flavor/llvmCore-DragonEgg-$Release-$RC.obj
376    llvmCore_de_phase3_installdir=$BuildDir/Phase3/$Flavor/llvmCore-DragonEgg-$Release-$RC.install
377    dragonegg_phase3_objdir=$BuildDir/Phase3/$Flavor/DragonEgg-$Release-$RC.obj
378
379    rm -rf $llvmCore_phase1_objdir
380    rm -rf $llvmCore_phase1_installdir
381    rm -rf $dragonegg_phase1_objdir
382
383    rm -rf $llvmCore_phase2_objdir
384    rm -rf $llvmCore_phase2_installdir
385    rm -rf $llvmCore_de_phase2_objdir
386    rm -rf $llvmCore_de_phase2_installdir
387    rm -rf $dragonegg_phase2_objdir
388
389    rm -rf $llvmCore_phase3_objdir
390    rm -rf $llvmCore_phase3_installdir
391    rm -rf $llvmCore_de_phase3_objdir
392    rm -rf $llvmCore_de_phase3_installdir
393    rm -rf $dragonegg_phase3_objdir
394
395    mkdir -p $llvmCore_phase1_objdir
396    mkdir -p $llvmCore_phase1_installdir
397    mkdir -p $dragonegg_phase1_objdir
398
399    mkdir -p $llvmCore_phase2_objdir
400    mkdir -p $llvmCore_phase2_installdir
401    mkdir -p $llvmCore_de_phase2_objdir
402    mkdir -p $llvmCore_de_phase2_installdir
403    mkdir -p $dragonegg_phase2_objdir
404
405    mkdir -p $llvmCore_phase3_objdir
406    mkdir -p $llvmCore_phase3_installdir
407    mkdir -p $llvmCore_de_phase3_objdir
408    mkdir -p $llvmCore_de_phase3_installdir
409    mkdir -p $dragonegg_phase3_objdir
410
411    ############################################################################
412    # Phase 1: Build llvmCore and clang
413    echo "# Phase 1: Building llvmCore"
414    configure_llvmCore 1 $Flavor \
415        $llvmCore_phase1_objdir $llvmCore_phase1_installdir
416    build_llvmCore 1 $Flavor \
417        $llvmCore_phase1_objdir
418
419    # Test clang
420    if [ "$do_clang" = "yes" ]; then
421        ########################################################################
422        # Phase 2: Build llvmCore with newly built clang from phase 1.
423        c_compiler=$llvmCore_phase1_installdir/bin/clang
424        cxx_compiler=$llvmCore_phase1_installdir/bin/clang++
425        echo "# Phase 2: Building llvmCore"
426        configure_llvmCore 2 $Flavor \
427            $llvmCore_phase2_objdir $llvmCore_phase2_installdir
428        build_llvmCore 2 $Flavor \
429            $llvmCore_phase2_objdir
430
431        ########################################################################
432        # Phase 3: Build llvmCore with newly built clang from phase 2.
433        c_compiler=$llvmCore_phase2_installdir/bin/clang
434        cxx_compiler=$llvmCore_phase2_installdir/bin/clang++
435        echo "# Phase 3: Building llvmCore"
436        configure_llvmCore 3 $Flavor \
437            $llvmCore_phase3_objdir $llvmCore_phase3_installdir
438        build_llvmCore 3 $Flavor \
439            $llvmCore_phase3_objdir
440
441        ########################################################################
442        # Testing: Test phase 3
443        echo "# Testing - built with clang"
444        test_llvmCore 3 $Flavor $llvmCore_phase3_objdir
445
446        ########################################################################
447        # Compare .o files between Phase2 and Phase3 and report which ones
448        # differ.
449        if [ "$do_compare" = "yes" ]; then
450            echo
451            echo "# Comparing Phase 2 and Phase 3 files"
452            for o in `find $llvmCore_phase2_objdir -name '*.o'` ; do
453                p3=`echo $o | sed -e 's,Phase2,Phase3,'`
454                if ! cmp --ignore-initial=16 $o $p3 > /dev/null 2>&1 ; then
455                    echo "file `basename $o` differs between phase 2 and phase 3"
456                fi
457            done
458        fi
459    fi
460
461    # Test dragonegg
462    if [ "$do_dragonegg" = "yes" ]; then
463        # Build dragonegg using the targeted gcc.  This isn't necessary, but
464        # helps avoid using broken versions of gcc (which are legion), tests
465        # that the targeted gcc is basically sane and is consistent with the
466        # later phases in which the targeted gcc + dragonegg are used.
467        c_compiler="$gcc_compiler"
468        cxx_compiler="$gxx_compiler"
469        build_dragonegg 1 $Flavor $llvmCore_phase1_installdir $dragonegg_phase1_objdir
470
471        ########################################################################
472        # Phase 2: Build llvmCore with newly built dragonegg from phase 1.
473        c_compiler="$gcc_compiler -fplugin=$dragonegg_phase1_objdir/dragonegg.so"
474        cxx_compiler="$gxx_compiler -fplugin=$dragonegg_phase1_objdir/dragonegg.so"
475        echo "# Phase 2: Building llvmCore with dragonegg"
476        configure_llvmCore 2 $Flavor \
477            $llvmCore_de_phase2_objdir $llvmCore_de_phase2_installdir
478        build_llvmCore 2 $Flavor \
479            $llvmCore_de_phase2_objdir
480        build_dragonegg 2 $Flavor $llvmCore_de_phase2_installdir $dragonegg_phase2_objdir
481
482        ########################################################################
483        # Phase 3: Build llvmCore with newly built dragonegg from phase 2.
484        c_compiler="$gcc_compiler -fplugin=$dragonegg_phase2_objdir/dragonegg.so"
485        cxx_compiler="$gxx_compiler -fplugin=$dragonegg_phase2_objdir/dragonegg.so"
486        echo "# Phase 3: Building llvmCore with dragonegg"
487        configure_llvmCore 3 $Flavor \
488            $llvmCore_de_phase3_objdir $llvmCore_de_phase3_installdir
489        build_llvmCore 3 $Flavor \
490            $llvmCore_de_phase3_objdir
491        build_dragonegg 3 $Flavor $llvmCore_de_phase3_installdir $dragonegg_phase3_objdir
492
493        ########################################################################
494        # Testing: Test phase 3
495        c_compiler="$gcc_compiler -fplugin=$dragonegg_phase3_objdir/dragonegg.so"
496        cxx_compiler="$gxx_compiler -fplugin=$dragonegg_phase3_objdir/dragonegg.so"
497        echo "# Testing - built with dragonegg"
498        test_llvmCore 3 $Flavor $llvmCore_de_phase3_objdir
499
500        ########################################################################
501        # Compare .o files between Phase2 and Phase3 and report which ones differ.
502        echo
503        echo "# Comparing Phase 2 and Phase 3 files"
504        for o in `find $llvmCore_de_phase2_objdir -name '*.o'` \
505          `find $dragonegg_phase2_objdir -name '*.o'` ; do
506            p3=`echo $o | sed -e 's,Phase2,Phase3,'`
507            if ! cmp --ignore-initial=16 $o $p3 > /dev/null 2>&1 ; then
508                echo "file `basename $o` differs between dragonegg phase 2 and phase 3"
509            fi
510        done
511    fi
512
513    # Otherwise just test the core.
514    if [ "$do_clang" != "yes" -a "$do_dragonegg" != "yes" ]; then
515        echo "# Testing - built with system compiler"
516        test_llvmCore 1 $Flavor $llvmCore_phase1_objdir
517    fi
518done
519) 2>&1 | tee $LogDir/testing.$Release-$RC.log
520
521set +e
522
523# Woo hoo!
524echo "### Testing Finished ###"
525echo "### Logs: $LogDir"
526exit 0
527