test-release.sh: Defer test errors until the end
[oota-llvm.git] / utils / release / test-release.sh
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
15 if [ `uname -s` = "FreeBSD" ]; then
16     MAKE=gmake
17 else
18     MAKE=make
19 fi
20
21 # Base SVN URL for the sources.
22 Base_url="http://llvm.org/svn/llvm-project"
23
24 Release=""
25 Release_no_dot=""
26 RC=""
27 Triple=""
28 use_gzip="no"
29 do_checkout="yes"
30 do_debug="no"
31 do_asserts="no"
32 do_compare="yes"
33 do_rt="yes"
34 do_libs="yes"
35 do_test_suite="yes"
36 BuildDir="`pwd`"
37 use_autoconf="no"
38 ExtraConfigureFlags=""
39 ExportBranch=""
40
41 function usage() {
42     echo "usage: `basename $0` -release X.Y.Z -rc NUM [OPTIONS]"
43     echo ""
44     echo " -release X.Y.Z       The release version to test."
45     echo " -rc NUM              The pre-release candidate number."
46     echo " -final               The final release candidate."
47     echo " -triple TRIPLE       The target triple for this machine."
48     echo " -j NUM               Number of compile jobs to run. [default: 3]"
49     echo " -build-dir DIR       Directory to perform testing in. [default: pwd]"
50     echo " -no-checkout         Don't checkout the sources from SVN."
51     echo " -test-debug          Test the debug build. [default: no]"
52     echo " -test-asserts        Test with asserts on. [default: no]"
53     echo " -no-compare-files    Don't test that phase 2 and 3 files are identical."
54     echo " -use-gzip            Use gzip instead of xz."
55     echo " -configure-flags FLAGS  Extra flags to pass to the configure step."
56     echo " -use-autoconf        Use autoconf instead of cmake"
57     echo " -svn-path DIR        Use the specified DIR instead of a release."
58     echo "                      For example -svn-path trunk or -svn-path branches/release_37"
59     echo " -no-rt               Disable check-out & build Compiler-RT"
60     echo " -no-libs             Disable check-out & build libcxx/libcxxabi/libunwind"
61     echo " -no-test-suite       Disable check-out & build test-suite"
62 }
63
64 if [ `uname -s` = "Darwin" ]; then
65   # compiler-rt doesn't yet build with CMake on Darwin.
66   use_autoconf="yes"
67 fi
68
69 while [ $# -gt 0 ]; do
70     case $1 in
71         -release | --release )
72             shift
73             Release="$1"
74             Release_no_dot="`echo $1 | sed -e 's,\.,,g'`"
75             ;;
76         -rc | --rc | -RC | --RC )
77             shift
78             RC="rc$1"
79             ;;
80         -final | --final )
81             RC=final
82             ;;
83         -svn-path | --svn-path )
84             shift
85             Release="test"
86             Release_no_dot="test"
87             ExportBranch="$1"
88             RC="`echo $ExportBranch | sed -e 's,/,_,g'`"
89             echo "WARNING: Using the branch $ExportBranch instead of a release tag"
90             echo "         This is intended to aid new packagers in trialing "
91             echo "         builds without requiring a tag to be created first"
92             ;;
93         -triple | --triple )
94             shift
95             Triple="$1"
96             ;;
97         -configure-flags | --configure-flags )
98             shift
99             ExtraConfigureFlags="$1"
100             ;;
101         -j* )
102             NumJobs="`echo $1 | sed -e 's,-j\([0-9]*\),\1,g'`"
103             if [ -z "$NumJobs" ]; then
104                 shift
105                 NumJobs="$1"
106             fi
107             ;;
108         -build-dir | --build-dir | -builddir | --builddir )
109             shift
110             BuildDir="$1"
111             ;;
112         -no-checkout | --no-checkout )
113             do_checkout="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         -use-autoconf | --use-autoconf )
128             use_autoconf="yes"
129             ;;
130         -no-rt )
131             do_rt="no"
132             ;;
133         -no-libs )
134             do_libs="no"
135             ;;
136         -no-test-suite )
137             do_test_suite="no"
138             ;;
139         -help | --help | -h | --h | -\? )
140             usage
141             exit 0
142             ;;
143         * )
144             echo "unknown option: $1"
145             usage
146             exit 1
147             ;;
148     esac
149     shift
150 done
151
152 # Check required arguments.
153 if [ -z "$Release" ]; then
154     echo "error: no release number specified"
155     exit 1
156 fi
157 if [ -z "$RC" ]; then
158     echo "error: no release candidate number specified"
159     exit 1
160 fi
161 if [ -z "$ExportBranch" ]; then
162     ExportBranch="tags/RELEASE_$Release_no_dot/$RC"
163 fi
164 if [ -z "$Triple" ]; then
165     echo "error: no target triple specified"
166     exit 1
167 fi
168
169 # Figure out how many make processes to run.
170 if [ -z "$NumJobs" ]; then
171     NumJobs=`sysctl -n hw.activecpu 2> /dev/null || true`
172 fi
173 if [ -z "$NumJobs" ]; then
174     NumJobs=`sysctl -n hw.ncpu 2> /dev/null || true`
175 fi
176 if [ -z "$NumJobs" ]; then
177     NumJobs=`grep -c processor /proc/cpuinfo 2> /dev/null || true`
178 fi
179 if [ -z "$NumJobs" ]; then
180     NumJobs=3
181 fi
182
183 # Projects list
184 projects="llvm cfe clang-tools-extra"
185 if [ $do_rt = "yes" ]; then
186   projects="$projects compiler-rt"
187 fi
188 if [ $do_libs = "yes" ]; then
189   projects="$projects libcxx libcxxabi libunwind"
190 fi
191 if [ $do_test_suite = "yes" ]; then
192   projects="$projects test-suite"
193 fi
194
195 # Go to the build directory (may be different from CWD)
196 BuildDir=$BuildDir/$RC
197 mkdir -p $BuildDir
198 cd $BuildDir
199
200 # Location of log files.
201 LogDir=$BuildDir/logs
202 mkdir -p $LogDir
203
204 # Final package name.
205 Package=clang+llvm-$Release
206 if [ $RC != "final" ]; then
207   Package=$Package-$RC
208 fi
209 Package=$Package-$Triple
210
211 # Errors to be highlighted at the end are written to this file.
212 echo -n > $LogDir/deferred_errors.log
213
214 function deferred_error() {
215   Phase="$1"
216   Flavor="$2"
217   Msg="$3"
218   echo "[${Flavor} Phase${Phase}] ${Msg}" | tee -a $LogDir/deferred_errors.log
219 }
220
221 # Make sure that a required program is available
222 function check_program_exists() {
223   local program="$1"
224   if ! type -P $program > /dev/null 2>&1 ; then
225     echo "program '$1' not found !"
226     exit 1
227   fi
228 }
229
230 if [ `uname -s` != "Darwin" ]; then
231   check_program_exists 'chrpath'
232   check_program_exists 'file'
233   check_program_exists 'objdump'
234 fi
235
236 # Make sure that the URLs are valid.
237 function check_valid_urls() {
238     for proj in $projects ; do
239         echo "# Validating $proj SVN URL"
240
241         if ! svn ls $Base_url/$proj/$ExportBranch > /dev/null 2>&1 ; then
242             echo "$proj does not have a $ExportBranch branch/tag!"
243             exit 1
244         fi
245     done
246 }
247
248 # Export sources to the build directory.
249 function export_sources() {
250     check_valid_urls
251
252     for proj in $projects ; do
253         if [ -d $proj.src ]; then
254           echo "# Reusing $proj $Release-$RC sources"
255           continue
256         fi
257         echo "# Exporting $proj $Release-$RC sources"
258         if ! svn export -q $Base_url/$proj/$ExportBranch $proj.src ; then
259             echo "error: failed to export $proj project"
260             exit 1
261         fi
262     done
263
264     echo "# Creating symlinks"
265     cd $BuildDir/llvm.src/tools
266     if [ ! -h clang ]; then
267         ln -s ../../cfe.src clang
268     fi
269     cd $BuildDir/llvm.src/tools/clang/tools
270     if [ ! -h clang-tools-extra ]; then
271         ln -s ../../../../clang-tools-extra.src extra
272     fi
273     cd $BuildDir/llvm.src/projects
274     if [ -d $BuildDir/test-suite.src ] && [ ! -h test-suite ]; then
275         ln -s ../../test-suite.src test-suite
276     fi
277     if [ -d $BuildDir/compiler-rt.src ] && [ ! -h compiler-rt ]; then
278         ln -s ../../compiler-rt.src compiler-rt
279     fi
280     if [ -d $BuildDir/libcxx.src ] && [ ! -h libcxx ]; then
281         ln -s ../../libcxx.src libcxx
282     fi
283     if [ -d $BuildDir/libcxxabi.src ] && [ ! -h libcxxabi ]; then
284         ln -s ../../libcxxabi.src libcxxabi
285     fi
286     if [ -d $BuildDir/libunwind.src ] && [ ! -h libunwind ]; then
287         ln -s ../../libunwind.src libunwind
288     fi
289
290     cd $BuildDir
291 }
292
293 function configure_llvmCore() {
294     Phase="$1"
295     Flavor="$2"
296     ObjDir="$3"
297
298     case $Flavor in
299         Release )
300             BuildType="Release"
301             Assertions="OFF"
302             ConfigureFlags="--enable-optimized --disable-assertions"
303             ;;
304         Release+Asserts )
305             BuildType="Release"
306             Assertions="ON"
307             ConfigureFlags="--enable-optimized --enable-assertions"
308             ;;
309         Debug )
310             BuildType="Debug"
311             Assertions="ON"
312             ConfigureFlags="--disable-optimized --enable-assertions"
313             ;;
314         * )
315             echo "# Invalid flavor '$Flavor'"
316             echo ""
317             return
318             ;;
319     esac
320
321     echo "# Using C compiler: $c_compiler"
322     echo "# Using C++ compiler: $cxx_compiler"
323
324     cd $ObjDir
325     echo "# Configuring llvm $Release-$RC $Flavor"
326
327     if [ "$use_autoconf" = "yes" ]; then
328         echo "#" env CC="$c_compiler" CXX="$cxx_compiler" \
329             $BuildDir/llvm.src/configure \
330             $ConfigureFlags --disable-timestamps $ExtraConfigureFlags \
331             2>&1 | tee $LogDir/llvm.configure-Phase$Phase-$Flavor.log
332         env CC="$c_compiler" CXX="$cxx_compiler" \
333             $BuildDir/llvm.src/configure \
334             $ConfigureFlags --disable-timestamps $ExtraConfigureFlags \
335             2>&1 | tee $LogDir/llvm.configure-Phase$Phase-$Flavor.log
336     else
337         echo "#" env CC="$c_compiler" CXX="$cxx_compiler" \
338             cmake -G "Unix Makefiles" \
339             -DCMAKE_BUILD_TYPE=$BuildType -DLLVM_ENABLE_ASSERTIONS=$Assertions \
340             -DLLVM_ENABLE_TIMESTAMPS=OFF -DLLVM_CONFIGTIME="(timestamp not enabled)" \
341             $ExtraConfigureFlags $BuildDir/llvm.src \
342             2>&1 | tee $LogDir/llvm.configure-Phase$Phase-$Flavor.log
343         env CC="$c_compiler" CXX="$cxx_compiler" \
344             cmake -G "Unix Makefiles" \
345             -DCMAKE_BUILD_TYPE=$BuildType -DLLVM_ENABLE_ASSERTIONS=$Assertions \
346             -DLLVM_ENABLE_TIMESTAMPS=OFF -DLLVM_CONFIGTIME="(timestamp not enabled)" \
347             $ExtraConfigureFlags $BuildDir/llvm.src \
348             2>&1 | tee $LogDir/llvm.configure-Phase$Phase-$Flavor.log
349     fi
350
351     cd $BuildDir
352 }
353
354 function build_llvmCore() {
355     Phase="$1"
356     Flavor="$2"
357     ObjDir="$3"
358     DestDir="$4"
359
360     cd $ObjDir
361     echo "# Compiling llvm $Release-$RC $Flavor"
362     echo "# ${MAKE} -j $NumJobs VERBOSE=1"
363     ${MAKE} -j $NumJobs VERBOSE=1 \
364         2>&1 | tee $LogDir/llvm.make-Phase$Phase-$Flavor.log
365
366     echo "# Installing llvm $Release-$RC $Flavor"
367     echo "# ${MAKE} install"
368     ${MAKE} install \
369         DESTDIR="${DestDir}" \
370         2>&1 | tee $LogDir/llvm.install-Phase$Phase-$Flavor.log
371     cd $BuildDir
372 }
373
374 function test_llvmCore() {
375     Phase="$1"
376     Flavor="$2"
377     ObjDir="$3"
378
379     cd $ObjDir
380     if ! ( ${MAKE} -j $NumJobs -k check-all \
381         2>&1 | tee $LogDir/llvm.check-Phase$Phase-$Flavor.log ) ; then
382       deferred_error $Phase $Flavor "check-all failed"
383     fi
384
385     if [ "$use_autoconf" = "yes" ]; then
386         # In the cmake build, unit tests are run as part of check-all.
387         if ! ( ${MAKE} -k unittests 2>&1 | \
388             tee $LogDir/llvm.unittests-Phase$Phase-$Flavor.log ) ; then
389           deferred_error $Phase $Flavor "unittests failed"
390         fi
391     fi
392
393     cd $BuildDir
394 }
395
396 # Clean RPATH. Libtool adds the build directory to the search path, which is
397 # not necessary --- and even harmful --- for the binary packages we release.
398 function clean_RPATH() {
399   if [ `uname -s` = "Darwin" ]; then
400     return
401   fi
402   local InstallPath="$1"
403   for Candidate in `find $InstallPath/{bin,lib} -type f`; do
404     if file $Candidate | grep ELF | egrep 'executable|shared object' > /dev/null 2>&1 ; then
405       if rpath=`objdump -x $Candidate | grep 'RPATH'` ; then
406         rpath=`echo $rpath | sed -e's/^ *RPATH *//'`
407         if [ -n "$rpath" ]; then
408           newrpath=`echo $rpath | sed -e's/.*\(\$ORIGIN[^:]*\).*/\1/'`
409           chrpath -r $newrpath $Candidate 2>&1 > /dev/null 2>&1
410         fi
411       fi
412     fi
413   done
414 }
415
416 # Create a package of the release binaries.
417 function package_release() {
418     cwd=`pwd`
419     cd $BuildDir/Phase3/Release
420     mv llvmCore-$Release-$RC.install/usr/local $Package
421     if [ "$use_gzip" = "yes" ]; then
422       tar cfz $BuildDir/$Package.tar.gz $Package
423     else
424       tar cfJ $BuildDir/$Package.tar.xz $Package
425     fi
426     mv $Package llvmCore-$Release-$RC.install/usr/local
427     cd $cwd
428 }
429
430 # Exit if any command fails
431 # Note: pipefail is necessary for running build commands through
432 # a pipe (i.e. it changes the output of ``false | tee /dev/null ; echo $?``)
433 set -e
434 set -o pipefail
435
436 if [ "$do_checkout" = "yes" ]; then
437     export_sources
438 fi
439
440 (
441 Flavors="Release"
442 if [ "$do_debug" = "yes" ]; then
443     Flavors="Debug $Flavors"
444 fi
445 if [ "$do_asserts" = "yes" ]; then
446     Flavors="$Flavors Release+Asserts"
447 fi
448
449 for Flavor in $Flavors ; do
450     echo ""
451     echo ""
452     echo "********************************************************************************"
453     echo "  Release:     $Release-$RC"
454     echo "  Build:       $Flavor"
455     echo "  System Info: "
456     echo "    `uname -a`"
457     echo "********************************************************************************"
458     echo ""
459
460     c_compiler="$CC"
461     cxx_compiler="$CXX"
462
463     llvmCore_phase1_objdir=$BuildDir/Phase1/$Flavor/llvmCore-$Release-$RC.obj
464     llvmCore_phase1_destdir=$BuildDir/Phase1/$Flavor/llvmCore-$Release-$RC.install
465
466     llvmCore_phase2_objdir=$BuildDir/Phase2/$Flavor/llvmCore-$Release-$RC.obj
467     llvmCore_phase2_destdir=$BuildDir/Phase2/$Flavor/llvmCore-$Release-$RC.install
468
469     llvmCore_phase3_objdir=$BuildDir/Phase3/$Flavor/llvmCore-$Release-$RC.obj
470     llvmCore_phase3_destdir=$BuildDir/Phase3/$Flavor/llvmCore-$Release-$RC.install
471
472     rm -rf $llvmCore_phase1_objdir
473     rm -rf $llvmCore_phase1_destdir
474
475     rm -rf $llvmCore_phase2_objdir
476     rm -rf $llvmCore_phase2_destdir
477
478     rm -rf $llvmCore_phase3_objdir
479     rm -rf $llvmCore_phase3_destdir
480
481     mkdir -p $llvmCore_phase1_objdir
482     mkdir -p $llvmCore_phase1_destdir
483
484     mkdir -p $llvmCore_phase2_objdir
485     mkdir -p $llvmCore_phase2_destdir
486
487     mkdir -p $llvmCore_phase3_objdir
488     mkdir -p $llvmCore_phase3_destdir
489
490     ############################################################################
491     # Phase 1: Build llvmCore and clang
492     echo "# Phase 1: Building llvmCore"
493     configure_llvmCore 1 $Flavor $llvmCore_phase1_objdir
494     build_llvmCore 1 $Flavor \
495         $llvmCore_phase1_objdir $llvmCore_phase1_destdir
496     clean_RPATH $llvmCore_phase1_destdir/usr/local
497
498     ########################################################################
499     # Phase 2: Build llvmCore with newly built clang from phase 1.
500     c_compiler=$llvmCore_phase1_destdir/usr/local/bin/clang
501     cxx_compiler=$llvmCore_phase1_destdir/usr/local/bin/clang++
502     echo "# Phase 2: Building llvmCore"
503     configure_llvmCore 2 $Flavor $llvmCore_phase2_objdir
504     build_llvmCore 2 $Flavor \
505         $llvmCore_phase2_objdir $llvmCore_phase2_destdir
506     clean_RPATH $llvmCore_phase2_destdir/usr/local
507
508     ########################################################################
509     # Phase 3: Build llvmCore with newly built clang from phase 2.
510     c_compiler=$llvmCore_phase2_destdir/usr/local/bin/clang
511     cxx_compiler=$llvmCore_phase2_destdir/usr/local/bin/clang++
512     echo "# Phase 3: Building llvmCore"
513     configure_llvmCore 3 $Flavor $llvmCore_phase3_objdir
514     build_llvmCore 3 $Flavor \
515         $llvmCore_phase3_objdir $llvmCore_phase3_destdir
516     clean_RPATH $llvmCore_phase3_destdir/usr/local
517
518     ########################################################################
519     # Testing: Test phase 3
520     echo "# Testing - built with clang"
521     test_llvmCore 3 $Flavor $llvmCore_phase3_objdir
522
523     ########################################################################
524     # Compare .o files between Phase2 and Phase3 and report which ones
525     # differ.
526     if [ "$do_compare" = "yes" ]; then
527         echo
528         echo "# Comparing Phase 2 and Phase 3 files"
529         for p2 in `find $llvmCore_phase2_objdir -name '*.o'` ; do
530             p3=`echo $p2 | sed -e 's,Phase2,Phase3,'`
531             # Substitute 'Phase2' for 'Phase3' in the Phase 2 object file in
532             # case there are build paths in the debug info. On some systems,
533             # sed adds a newline to the output, so pass $p3 through sed too.
534             if ! cmp -s <(sed -e 's,Phase2,Phase3,g' $p2) <(sed -e '' $p3) \
535                     16 16 ; then
536                 echo "file `basename $p2` differs between phase 2 and phase 3"
537             fi
538         done
539     fi
540 done
541 ) 2>&1 | tee $LogDir/testing.$Release-$RC.log
542
543 package_release
544
545 set +e
546
547 # Woo hoo!
548 echo "### Testing Finished ###"
549 if [ "$use_gzip" = "yes" ]; then
550   echo "### Package: $Package.tar.gz"
551 else
552   echo "### Package: $Package.tar.xz"
553 fi
554 echo "### Logs: $LogDir"
555
556 echo "### Errors:"
557 if [ -s "$LogDir/deferred_errors.log" ]; then
558   cat "$LogDir/deferred_errors.log"
559   exit 1
560 else
561   echo "None."
562 fi
563
564 exit 0