1#!/usr/bin/env bash
2#===-- test-release.sh - Test the LLVM release candidates ------------------===#
3#
4# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5# See https://llvm.org/LICENSE.txt for license information.
6# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7#
8#===------------------------------------------------------------------------===#
9#
10# Download, build, and test the release candidate for an LLVM release.
11#
12#===------------------------------------------------------------------------===#
13
14System=`uname -s`
15if [ "$System" = "FreeBSD" ]; then
16    MAKE=gmake
17else
18    MAKE=make
19fi
20generator="Unix Makefiles"
21
22# Base SVN URL for the sources.
23Base_url="http://llvm.org/svn/llvm-project"
24
25Release=""
26Release_no_dot=""
27RC=""
28Triple=""
29use_gzip="no"
30do_checkout="yes"
31do_debug="no"
32do_asserts="no"
33do_compare="yes"
34do_rt="yes"
35do_libs="yes"
36do_libcxxabi="yes"
37do_libunwind="yes"
38do_test_suite="yes"
39do_openmp="yes"
40do_lld="yes"
41do_lldb="no"
42do_polly="yes"
43do_mlir="yes"
44do_flang="no"
45BuildDir="`pwd`"
46ExtraConfigureFlags=""
47ExportBranch=""
48git_ref=""
49
50function usage() {
51    echo "usage: `basename $0` -release X.Y.Z -rc NUM [OPTIONS]"
52    echo ""
53    echo " -release X.Y.Z       The release version to test."
54    echo " -rc NUM              The pre-release candidate number."
55    echo " -final               The final release candidate."
56    echo " -triple TRIPLE       The target triple for this machine."
57    echo " -j NUM               Number of compile jobs to run. [default: 3]"
58    echo " -build-dir DIR       Directory to perform testing in. [default: pwd]"
59    echo " -no-checkout         Don't checkout the sources from SVN."
60    echo " -test-debug          Test the debug build. [default: no]"
61    echo " -test-asserts        Test with asserts on. [default: no]"
62    echo " -no-compare-files    Don't test that phase 2 and 3 files are identical."
63    echo " -use-gzip            Use gzip instead of xz."
64    echo " -use-ninja           Use ninja instead of make/gmake."
65    echo " -configure-flags FLAGS  Extra flags to pass to the configure step."
66    echo " -git-ref sha         Use the specified git ref for testing instead of a release."
67    echo " -no-rt               Disable check-out & build Compiler-RT"
68    echo " -no-libs             Disable check-out & build libcxx/libcxxabi/libunwind"
69    echo " -no-libcxxabi        Disable check-out & build libcxxabi"
70    echo " -no-libunwind        Disable check-out & build libunwind"
71    echo " -no-test-suite       Disable check-out & build test-suite"
72    echo " -no-openmp           Disable check-out & build libomp"
73    echo " -no-lld              Disable check-out & build lld"
74    echo " -lldb                Enable check-out & build lldb"
75    echo " -no-lldb             Disable check-out & build lldb (default)"
76    echo " -no-polly            Disable check-out & build Polly"
77    echo " -no-mlir             Disable check-out & build MLIR"
78}
79
80while [ $# -gt 0 ]; do
81    case $1 in
82        -release | --release )
83            shift
84            Release="$1"
85            Release_no_dot="`echo $1 | sed -e 's,\.,,g'`"
86            ;;
87        -rc | --rc | -RC | --RC )
88            shift
89            RC="rc$1"
90            ;;
91        -final | --final )
92            RC=final
93            ;;
94        -git-ref | --git-ref )
95            shift
96            Release="test"
97            Release_no_dot="test"
98            ExportBranch="$1"
99            RC="`echo $ExportBranch | sed -e 's,/,_,g'`"
100            git_ref="$1"
101            echo "WARNING: Using the ref $git_ref instead of a release tag"
102            echo "         This is intended to aid new packagers in trialing "
103            echo "         builds without requiring a tag to be created first"
104            ;;
105        -triple | --triple )
106            shift
107            Triple="$1"
108            ;;
109        -configure-flags | --configure-flags )
110            shift
111            ExtraConfigureFlags="$1"
112            ;;
113        -j* )
114            NumJobs="`echo $1 | sed -e 's,-j\([0-9]*\),\1,g'`"
115            if [ -z "$NumJobs" ]; then
116                shift
117                NumJobs="$1"
118            fi
119            ;;
120        -use-ninja )
121            MAKE=ninja
122            generator=Ninja
123            ;;
124        -build-dir | --build-dir | -builddir | --builddir )
125            shift
126            BuildDir="$1"
127            ;;
128        -no-checkout | --no-checkout )
129            do_checkout="no"
130            ;;
131        -test-debug | --test-debug )
132            do_debug="yes"
133            ;;
134        -test-asserts | --test-asserts )
135            do_asserts="yes"
136            ;;
137        -no-compare-files | --no-compare-files )
138            do_compare="no"
139            ;;
140        -use-gzip | --use-gzip )
141            use_gzip="yes"
142            ;;
143        -no-rt )
144            do_rt="no"
145            ;;
146        -no-libs )
147            do_libs="no"
148            ;;
149        -no-libcxxabi )
150            do_libcxxabi="no"
151            ;;
152        -no-libunwind )
153            do_libunwind="no"
154            ;;
155        -no-test-suite )
156            do_test_suite="no"
157            ;;
158        -no-openmp )
159            do_openmp="no"
160            ;;
161        -no-lld )
162            do_lld="no"
163            ;;
164        -lldb )
165            do_lldb="yes"
166            ;;
167        -no-lldb )
168            do_lldb="no"
169            ;;
170        -no-polly )
171            do_polly="no"
172            ;;
173        -no-mlir )
174            do_mlir="no"
175            ;;
176        -flang )
177            do_flang="yes"
178            ;;
179        -help | --help | -h | --h | -\? )
180            usage
181            exit 0
182            ;;
183        * )
184            echo "unknown option: $1"
185            usage
186            exit 1
187            ;;
188    esac
189    shift
190done
191
192# Check required arguments.
193if [ -z "$Release" ]; then
194    echo "error: no release number specified"
195    exit 1
196fi
197if [ -z "$RC" ]; then
198    echo "error: no release candidate number specified"
199    exit 1
200fi
201if [ -z "$ExportBranch" ]; then
202    ExportBranch="tags/RELEASE_$Release_no_dot/$RC"
203fi
204if [ -z "$Triple" ]; then
205    echo "error: no target triple specified"
206    exit 1
207fi
208
209if [ "$Release" != "test" ]; then
210  if [ -n "$git_ref" ]; then
211    echo "error: can't specify both -release and -git-ref"
212    exit 1
213  fi
214  git_ref=llvmorg-$Release
215  if [ "$RC" != "final" ]; then
216    git_ref="$git_ref-$RC"
217  fi
218fi
219
220# Figure out how many make processes to run.
221if [ -z "$NumJobs" ]; then
222    NumJobs=`sysctl -n hw.activecpu 2> /dev/null || true`
223fi
224if [ -z "$NumJobs" ]; then
225    NumJobs=`sysctl -n hw.ncpu 2> /dev/null || true`
226fi
227if [ -z "$NumJobs" ]; then
228    NumJobs=`grep -c processor /proc/cpuinfo 2> /dev/null || true`
229fi
230if [ -z "$NumJobs" ]; then
231    NumJobs=3
232fi
233
234# Projects list
235projects="llvm clang clang-tools-extra"
236if [ $do_rt = "yes" ]; then
237  projects="$projects compiler-rt"
238fi
239if [ $do_libs = "yes" ]; then
240  projects="$projects libcxx"
241  if [ $do_libcxxabi = "yes" ]; then
242    projects="$projects libcxxabi"
243  fi
244  if [ $do_libunwind = "yes" ]; then
245    projects="$projects libunwind"
246  fi
247fi
248case $do_test_suite in
249  yes|export-only)
250    projects="$projects test-suite"
251    ;;
252esac
253if [ $do_openmp = "yes" ]; then
254  projects="$projects openmp"
255fi
256if [ $do_lld = "yes" ]; then
257  projects="$projects lld"
258fi
259if [ $do_lldb = "yes" ]; then
260  projects="$projects lldb"
261fi
262if [ $do_polly = "yes" ]; then
263  projects="$projects polly"
264fi
265if [ $do_mlir = "yes" ]; then
266  projects="$projects mlir"
267fi
268if [ $do_flang = "yes" ]; then
269  projects="$projects flang"
270fi
271
272# Go to the build directory (may be different from CWD)
273BuildDir=$BuildDir/$RC
274mkdir -p $BuildDir
275cd $BuildDir
276
277# Location of log files.
278LogDir=$BuildDir/logs
279mkdir -p $LogDir
280
281# Final package name.
282Package=clang+llvm-$Release
283if [ $RC != "final" ]; then
284  Package=$Package-$RC
285fi
286Package=$Package-$Triple
287
288# Errors to be highlighted at the end are written to this file.
289echo -n > $LogDir/deferred_errors.log
290
291function deferred_error() {
292  Phase="$1"
293  Flavor="$2"
294  Msg="$3"
295  echo "[${Flavor} Phase${Phase}] ${Msg}" | tee -a $LogDir/deferred_errors.log
296}
297
298# Make sure that a required program is available
299function check_program_exists() {
300  local program="$1"
301  if ! type -P $program > /dev/null 2>&1 ; then
302    echo "program '$1' not found !"
303    exit 1
304  fi
305}
306
307if [ "$System" != "Darwin" -a "$System" != "SunOS" ]; then
308  check_program_exists 'chrpath'
309fi
310
311if [ "$System" != "Darwin" ]; then
312  check_program_exists 'file'
313  check_program_exists 'objdump'
314fi
315
316check_program_exists ${MAKE}
317
318# Export sources to the build directory.
319function export_sources() {
320  SrcDir=$BuildDir/llvm-project
321  mkdir -p $SrcDir
322  echo "# Using git ref: $git_ref"
323
324  # GitHub allows you to download a tarball of any commit using the URL:
325  # https://github.com/$organization/$repo/archive/$ref.tar.gz
326  curl -L https://github.com/llvm/llvm-project/archive/$git_ref.tar.gz | \
327    tar -C $SrcDir --strip-components=1 -xzf -
328
329  if [ "$do_test_suite" = "yes" ]; then
330    TestSuiteSrcDir=$BuildDir/llvm-test-suite
331    mkdir -p $TestSuiteSrcDir
332
333    # We can only use named refs, like branches and tags, that exist in
334    # both the llvm-project and test-suite repos if we want to run the
335    # test suite.
336    # If the test-suite fails to download assume we are using a ref that
337    # doesn't exist in the test suite and disable it.
338    set +e
339    curl -L https://github.com/llvm/test-suite/archive/$git_ref.tar.gz | \
340      tar -C $TestSuiteSrcDir --strip-components=1 -xzf -
341    if [ $? -ne -0 ]; then
342      echo "$git_ref not found in test-suite repo, test-suite disabled."
343      do_test_suite="no"
344    fi
345    set -e
346  fi
347
348  cd $BuildDir
349}
350
351function configure_llvmCore() {
352    Phase="$1"
353    Flavor="$2"
354    ObjDir="$3"
355
356    case $Flavor in
357        Release )
358            BuildType="Release"
359            Assertions="OFF"
360            ;;
361        Release+Asserts )
362            BuildType="Release"
363            Assertions="ON"
364            ;;
365        Debug )
366            BuildType="Debug"
367            Assertions="ON"
368            ;;
369        * )
370            echo "# Invalid flavor '$Flavor'"
371            echo ""
372            return
373            ;;
374    esac
375
376    project_list=${projects// /;}
377    echo "# Using C compiler: $c_compiler"
378    echo "# Using C++ compiler: $cxx_compiler"
379
380    cd $ObjDir
381    echo "# Configuring llvm $Release-$RC $Flavor"
382
383    echo "#" env CC="$c_compiler" CXX="$cxx_compiler" \
384        cmake -G "$generator" \
385        -DCMAKE_BUILD_TYPE=$BuildType -DLLVM_ENABLE_ASSERTIONS=$Assertions \
386        -DLLVM_ENABLE_PROJECTS="$project_list" \
387        $ExtraConfigureFlags $BuildDir/llvm-project/llvm \
388        2>&1 | tee $LogDir/llvm.configure-Phase$Phase-$Flavor.log
389    env CC="$c_compiler" CXX="$cxx_compiler" \
390        cmake -G "$generator" \
391        -DCMAKE_BUILD_TYPE=$BuildType -DLLVM_ENABLE_ASSERTIONS=$Assertions \
392        -DLLVM_ENABLE_PROJECTS="$project_list" \
393        $ExtraConfigureFlags $BuildDir/llvm-project/llvm \
394        2>&1 | tee $LogDir/llvm.configure-Phase$Phase-$Flavor.log
395
396    cd $BuildDir
397}
398
399function build_llvmCore() {
400    Phase="$1"
401    Flavor="$2"
402    ObjDir="$3"
403    DestDir="$4"
404
405    Verbose="VERBOSE=1"
406    if [ ${MAKE} = 'ninja' ]; then
407      Verbose="-v"
408    fi
409
410    cd $ObjDir
411    echo "# Compiling llvm $Release-$RC $Flavor"
412    echo "# ${MAKE} -j $NumJobs $Verbose"
413    ${MAKE} -j $NumJobs $Verbose \
414        2>&1 | tee $LogDir/llvm.make-Phase$Phase-$Flavor.log
415
416    echo "# Installing llvm $Release-$RC $Flavor"
417    echo "# ${MAKE} install"
418    DESTDIR="${DestDir}" ${MAKE} install \
419        2>&1 | tee $LogDir/llvm.install-Phase$Phase-$Flavor.log
420    cd $BuildDir
421}
422
423function test_llvmCore() {
424    Phase="$1"
425    Flavor="$2"
426    ObjDir="$3"
427
428    KeepGoing="-k"
429    if [ ${MAKE} = 'ninja' ]; then
430      # Ninja doesn't have a documented "keep-going-forever" mode, we need to
431      # set a limit on how many jobs can fail before we give up.
432      KeepGoing="-k 100"
433    fi
434
435    cd $ObjDir
436    if ! ( ${MAKE} -j $NumJobs $KeepGoing check-all \
437        2>&1 | tee $LogDir/llvm.check-Phase$Phase-$Flavor.log ) ; then
438      deferred_error $Phase $Flavor "check-all failed"
439    fi
440
441    if [ $do_test_suite = 'yes' ]; then
442      cd $TestSuiteBuildDir
443      env CC="$c_compiler" CXX="$cxx_compiler" \
444          cmake $TestSuiteSrcDir -G "$generator" -DTEST_SUITE_LIT=$Lit
445
446      if ! ( ${MAKE} -j $NumJobs $KeepGoing check \
447          2>&1 | tee $LogDir/llvm.check-Phase$Phase-$Flavor.log ) ; then
448        deferred_error $Phase $Flavor "test suite failed"
449      fi
450    fi
451    cd $BuildDir
452}
453
454# Clean RPATH. Libtool adds the build directory to the search path, which is
455# not necessary --- and even harmful --- for the binary packages we release.
456function clean_RPATH() {
457  if [ "$System" = "Darwin" -o "$System" = "SunOS" ]; then
458    return
459  fi
460  local InstallPath="$1"
461  for Candidate in `find $InstallPath/{bin,lib} -type f`; do
462    if file $Candidate | grep ELF | egrep 'executable|shared object' > /dev/null 2>&1 ; then
463      if rpath=`objdump -x $Candidate | grep 'RPATH'` ; then
464        rpath=`echo $rpath | sed -e's/^ *RPATH *//'`
465        if [ -n "$rpath" ]; then
466          newrpath=`echo $rpath | sed -e's/.*\(\$ORIGIN[^:]*\).*/\1/'`
467          chrpath -r $newrpath $Candidate 2>&1 > /dev/null 2>&1
468        fi
469      fi
470    fi
471  done
472}
473
474# Create a package of the release binaries.
475function package_release() {
476    cwd=`pwd`
477    cd $BuildDir/Phase3/Release
478    mv llvmCore-$Release-$RC.install/usr/local $Package
479    if [ "$use_gzip" = "yes" ]; then
480      tar cf - $Package | gzip -9c > $BuildDir/$Package.tar.gz
481    else
482      tar cf - $Package | xz -9ce > $BuildDir/$Package.tar.xz
483    fi
484    mv $Package llvmCore-$Release-$RC.install/usr/local
485    cd $cwd
486}
487
488# Exit if any command fails
489# Note: pipefail is necessary for running build commands through
490# a pipe (i.e. it changes the output of ``false | tee /dev/null ; echo $?``)
491set -e
492set -o pipefail
493
494# Turn off core dumps, as some test cases can easily fill up even the largest
495# file systems.
496ulimit -c 0
497
498if [ "$do_checkout" = "yes" ]; then
499    export_sources
500fi
501
502# Setup the test-suite.  Do this early so we can catch failures before
503# we do the full 3 stage build.
504if [ $do_test_suite = "yes" ]; then
505  venv=virtualenv
506  if ! type -P 'virtualenv' > /dev/null 2>&1 ; then
507    check_program_exists 'python3'
508    venv="python3 -m venv"
509  fi
510
511  SandboxDir="$BuildDir/sandbox"
512  Lit=$SandboxDir/bin/lit
513  TestSuiteBuildDir="$BuildDir/test-suite-build"
514  TestSuiteSrcDir="$BuildDir/llvm-test-suite"
515
516  ${venv} $SandboxDir
517  $SandboxDir/bin/python $BuildDir/llvm-project/llvm/utils/lit/setup.py install
518  mkdir -p $TestSuiteBuildDir
519fi
520
521(
522Flavors="Release"
523if [ "$do_debug" = "yes" ]; then
524    Flavors="Debug $Flavors"
525fi
526if [ "$do_asserts" = "yes" ]; then
527    Flavors="$Flavors Release+Asserts"
528fi
529
530for Flavor in $Flavors ; do
531    echo ""
532    echo ""
533    echo "********************************************************************************"
534    echo "  Release:     $Release-$RC"
535    echo "  Build:       $Flavor"
536    echo "  System Info: "
537    echo "    `uname -a`"
538    echo "********************************************************************************"
539    echo ""
540
541    c_compiler="$CC"
542    cxx_compiler="$CXX"
543    llvmCore_phase1_objdir=$BuildDir/Phase1/$Flavor/llvmCore-$Release-$RC.obj
544    llvmCore_phase1_destdir=$BuildDir/Phase1/$Flavor/llvmCore-$Release-$RC.install
545
546    llvmCore_phase2_objdir=$BuildDir/Phase2/$Flavor/llvmCore-$Release-$RC.obj
547    llvmCore_phase2_destdir=$BuildDir/Phase2/$Flavor/llvmCore-$Release-$RC.install
548
549    llvmCore_phase3_objdir=$BuildDir/Phase3/$Flavor/llvmCore-$Release-$RC.obj
550    llvmCore_phase3_destdir=$BuildDir/Phase3/$Flavor/llvmCore-$Release-$RC.install
551
552    rm -rf $llvmCore_phase1_objdir
553    rm -rf $llvmCore_phase1_destdir
554
555    rm -rf $llvmCore_phase2_objdir
556    rm -rf $llvmCore_phase2_destdir
557
558    rm -rf $llvmCore_phase3_objdir
559    rm -rf $llvmCore_phase3_destdir
560
561    mkdir -p $llvmCore_phase1_objdir
562    mkdir -p $llvmCore_phase1_destdir
563
564    mkdir -p $llvmCore_phase2_objdir
565    mkdir -p $llvmCore_phase2_destdir
566
567    mkdir -p $llvmCore_phase3_objdir
568    mkdir -p $llvmCore_phase3_destdir
569
570    ############################################################################
571    # Phase 1: Build llvmCore and clang
572    echo "# Phase 1: Building llvmCore"
573    configure_llvmCore 1 $Flavor $llvmCore_phase1_objdir
574    build_llvmCore 1 $Flavor \
575        $llvmCore_phase1_objdir $llvmCore_phase1_destdir
576    clean_RPATH $llvmCore_phase1_destdir/usr/local
577
578    ########################################################################
579    # Phase 2: Build llvmCore with newly built clang from phase 1.
580    c_compiler=$llvmCore_phase1_destdir/usr/local/bin/clang
581    cxx_compiler=$llvmCore_phase1_destdir/usr/local/bin/clang++
582    echo "# Phase 2: Building llvmCore"
583    configure_llvmCore 2 $Flavor $llvmCore_phase2_objdir
584    build_llvmCore 2 $Flavor \
585        $llvmCore_phase2_objdir $llvmCore_phase2_destdir
586    clean_RPATH $llvmCore_phase2_destdir/usr/local
587
588    ########################################################################
589    # Phase 3: Build llvmCore with newly built clang from phase 2.
590    c_compiler=$llvmCore_phase2_destdir/usr/local/bin/clang
591    cxx_compiler=$llvmCore_phase2_destdir/usr/local/bin/clang++
592    echo "# Phase 3: Building llvmCore"
593    configure_llvmCore 3 $Flavor $llvmCore_phase3_objdir
594    build_llvmCore 3 $Flavor \
595        $llvmCore_phase3_objdir $llvmCore_phase3_destdir
596    clean_RPATH $llvmCore_phase3_destdir/usr/local
597
598    ########################################################################
599    # Testing: Test phase 3
600    c_compiler=$llvmCore_phase3_destdir/usr/local/bin/clang
601    cxx_compiler=$llvmCore_phase3_destdir/usr/local/bin/clang++
602    echo "# Testing - built with clang"
603    test_llvmCore 3 $Flavor $llvmCore_phase3_objdir
604
605    ########################################################################
606    # Compare .o files between Phase2 and Phase3 and report which ones
607    # differ.
608    if [ "$do_compare" = "yes" ]; then
609        echo
610        echo "# Comparing Phase 2 and Phase 3 files"
611        for p2 in `find $llvmCore_phase2_objdir -name '*.o'` ; do
612            p3=`echo $p2 | sed -e 's,Phase2,Phase3,'`
613            # Substitute 'Phase2' for 'Phase3' in the Phase 2 object file in
614            # case there are build paths in the debug info. Do the same sub-
615            # stitution on both files in case the string occurrs naturally.
616            if ! cmp -s \
617                <(env LC_CTYPE=C sed -e 's,Phase1,Phase2,g' -e 's,Phase2,Phase3,g' $p2) \
618                <(env LC_CTYPE=C sed -e 's,Phase1,Phase2,g' -e 's,Phase2,Phase3,g' $p3) \
619                16 16; then
620                echo "file `basename $p2` differs between phase 2 and phase 3"
621            fi
622        done
623    fi
624done
625
626) 2>&1 | tee $LogDir/testing.$Release-$RC.log
627
628if [ "$use_gzip" = "yes" ]; then
629  echo "# Packaging the release as $Package.tar.gz"
630else
631  echo "# Packaging the release as $Package.tar.xz"
632fi
633package_release
634
635set +e
636
637# Woo hoo!
638echo "### Testing Finished ###"
639echo "### Logs: $LogDir"
640
641echo "### Errors:"
642if [ -s "$LogDir/deferred_errors.log" ]; then
643  cat "$LogDir/deferred_errors.log"
644  exit 1
645else
646  echo "None."
647fi
648
649exit 0
650