#!/bin/bash # # A simple test suite for ccache. # # Copyright (C) 2002-2007 Andrew Tridgell # Copyright (C) 2009-2020 Joel Rosdahl and other contributors # # See doc/AUTHORS.adoc for a complete list of contributors. # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 3 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License along with # this program; if not, write to the Free Software Foundation, Inc., 51 # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # only use ansi color codes if output is to a terminal if [[ -t 1 ]]; then ansi_boldgreen='\033[1;32m' ansi_boldred='\033[1;31m' ansi_bold='\033[1m' ansi_reset='\033[1;0m' fi green() { printf "$ansi_boldgreen$*$ansi_reset\n" } red() { printf "$ansi_boldred$*$ansi_reset\n" } bold() { printf "$ansi_bold$*$ansi_reset\n" } test_failed() { echo red FAILED echo echo "Test suite: $(bold $CURRENT_SUITE)" echo "Test case: $(bold $CURRENT_TEST)" echo "Failure reason: $(red "$1")" echo echo "ccache -s:" $CCACHE -s echo echo "Test data and log file have been left in $TESTDIR / $TEST_FAILED_SYMLINK" symlink_testdir_on_failure exit 1 } find_compiler() { local name=$1 perl -e ' use File::Basename; my $cc = $ARGV[0]; $cc = basename($cc) if readlink($cc) =~ "ccache"; if ($cc =~ m!^/!) { print $cc; exit; } foreach my $dir (split(/:/, $ENV{PATH})) { $path = "$dir/$cc"; if (-x $path && readlink($path) !~ "ccache") { print $path; exit; } }' $name } generate_code() { local nlines=$1 local outfile=$2 rm -f $outfile for i in $(seq $nlines); do echo "int foo_$i(int x) { return x; }" >>$outfile done } remove_cache() { if [ -d $CCACHE_DIR ]; then chmod -R +w $CCACHE_DIR rm -rf $CCACHE_DIR fi } clear_cache() { $CCACHE -Cz >/dev/null } sed_in_place() { local expr=$1 shift for file in $*; do sed "$expr" $file >$file.sed mv $file.sed $file done } backdate() { if [[ $1 =~ ^[0-9]+$ ]]; then m=$1 shift else m=0 fi touch -t 1999010100$(printf "%02u" $m) "$@" } file_size() { wc -c $1 | awk '{print $1}' } objdump_cmd() { if $HOST_OS_APPLE; then xcrun dwarfdump -r 0 $1 elif $HOST_OS_FREEBSD; then objdump -W $1 elif $HOST_OS_WINDOWS || $HOST_OS_CYGWIN; then strings $1 # for some reason objdump only shows the basename of the file, so fall back to brute force and ignorance else objdump -g $1 fi } expect_stat() { local stat="$1" local expected_value="$2" local value="$(echo $($CCACHE -s | fgrep "$stat" | cut -c34-))" if [ "$expected_value" != "$value" ]; then test_failed "Expected \"$stat\" to be $expected_value, actual $value" fi } expect_file_exists() { if [ ! -f "$1" ]; then test_failed "Expected $1 to exist, but it's missing" fi } expect_file_missing() { if [ -f "$1" ]; then test_failed "Expected $1 to be missing, but it exists" fi } expect_equal_files() { if [ ! -e "$1" ]; then test_failed "expect_equal_files: $1 missing" fi if [ ! -e "$2" ]; then test_failed "expect_equal_files: $2 missing" fi if ! cmp -s "$1" "$2"; then test_failed "$1 and $2 differ" fi } expect_different_files() { if [ ! -e "$1" ]; then test_failed "expect_different_files: $1 missing" fi if [ ! -e "$2" ]; then test_failed "expect_different_files: $2 missing" fi if cmp -s "$1" "$2"; then test_failed "$1 and $2 are identical" fi } is_equal_object_files() { if $HOST_OS_LINUX && $COMPILER_TYPE_CLANG; then if ! which eu-elfcmp >/dev/null 2>&1; then test_failed "Please install elfutils to get eu-elfcmp" fi eu-elfcmp -q "$1" "$2" elif $HOST_OS_FREEBSD && $COMPILER_TYPE_CLANG; then elfdump -a -w "$1".dump "$1" elfdump -a -w "$2".dump "$2" # these were the elfdump fields that seemed to differ (empirically) diff -I e_shoff -I sh_size -I st_name "$1".dump "$2".dump > /dev/null else cmp -s "$1" "$2" fi } expect_equal_object_files() { is_equal_object_files "$1" "$2" if [ $? -ne 0 ]; then test_failed "Objects differ: $1 != $2" fi } expect_file_content() { local file="$1" local content="$2" if [ ! -f "$file" ]; then test_failed "$file not found" fi if [ "$(cat $file)" != "$content" ]; then test_failed "Bad content of $file.\nExpected: $content\nActual: $(cat $file)" fi } expect_file_contains() { local file="$1" local string="$2" if [ ! -f "$file" ]; then test_failed "$file not found" fi if ! grep -q "$string" "$file"; then test_failed "File $file does not contain: $string. Actual content: $(cat $file)" fi } expect_file_count() { local expected=$1 local pattern=$2 local dir=$3 local actual=`find $dir -type f -name "$pattern" | wc -l` if [ $actual -ne $expected ]; then test_failed "Found $actual (expected $expected) $pattern files in $dir" fi } # Verify that $1 is newer than (or same age as) $2. expect_file_newer_than() { local newer_file=$1 local older_file=$2 if [ "$newer_file" -ot "$older_file" ]; then test_failed "$newer_file is older than $older_file" fi } run_suite() { local suite_name=$1 CURRENT_SUITE=$suite_name cd $ABS_TESTDIR rm -rf $ABS_TESTDIR/fixture if type SUITE_${suite_name}_PROBE >/dev/null 2>&1; then mkdir $ABS_TESTDIR/probe cd $ABS_TESTDIR/probe local skip_reason="$(SUITE_${suite_name}_PROBE)" cd $ABS_TESTDIR rm -rf $ABS_TESTDIR/probe if [ -n "$skip_reason" ]; then echo "Skipped test suite $suite_name [$skip_reason]" return fi fi printf "Running test suite %s" "$(bold $suite_name)" SUITE_$suite_name echo } TEST() { CURRENT_TEST=$1 while read name; do unset $name done </dev/null 2>&1; then SUITE_${suite_name}_SETUP fi } # ============================================================================= # main program export LC_ALL=C if pwd | grep '[^A-Za-z0-9/.,=_%+-]' >/dev/null 2>&1; then cat <&2 exit 0 ;; esac case $compiler_version in *llvm*|*LLVM*) COMPILER_USES_LLVM=true ;; *MINGW*|*mingw*) COMPILER_USES_MINGW=true ;; esac case $(uname -s) in *MINGW*|*mingw*) HOST_OS_WINDOWS=true ;; *CYGWIN*|*MSYS*) HOST_OS_CYGWIN=true ;; *Darwin*) HOST_OS_APPLE=true ;; *Linux*) HOST_OS_LINUX=true ;; *FreeBSD*) HOST_OS_FREEBSD=true ;; esac if $HOST_OS_WINDOWS; then PATH_DELIM=";" else PATH_DELIM=":" fi if $HOST_OS_APPLE; then SDKROOT=$(xcrun --sdk macosx --show-sdk-path 2>/dev/null) if [ "$SDKROOT" = "" ]; then echo "Error: xcrun --show-sdk-path failure" exit 1 fi SYSROOT="-isysroot `echo \"$SDKROOT\" | sed 's/ /\\ /g'`" else SYSROOT= fi # --------------------------------------- all_suites=" base nocpp2 cpp1 multi_arch serialize_diagnostics sanitize_blacklist debug_prefix_map split_dwarf masquerading hardlink fileclone direct direct_gcc depend basedir no_compression readonly readonly_direct cleanup pch modules upgrade input_charset nvcc nvcc_direct nvcc_ldir nvcc_nocpp2 " for suite in $all_suites; do . $(dirname $0)/suites/$suite.bash done # --------------------------------------- TESTDIR=testdir.$$ TEST_FAILED_SYMLINK=testdir.failed ABS_TESTDIR=$PWD/$TESTDIR rm -rf $TESTDIR mkdir $TESTDIR START_PWD="$PWD" symlink_testdir_on_failure() { cd "$START_PWD" rm -f "$TEST_FAILED_SYMLINK" ln -s "$TESTDIR" "$TEST_FAILED_SYMLINK" } cd $TESTDIR || exit 1 compiler_bin=$(echo $COMPILER | awk '{print $1}') compiler_args=$(echo $COMPILER | awk '{$1 = ""; print}') REAL_COMPILER_BIN=$(find_compiler $compiler_bin) REAL_COMPILER="$REAL_COMPILER_BIN$compiler_args" if [ "$REAL_COMPILER" = "$COMPILER" ]; then echo "Compiler: $COMPILER" else echo "Compiler: $COMPILER ($REAL_COMPILER)" fi echo "Compiler version: $($COMPILER --version | head -n 1)" REAL_NVCC=$(find_compiler nvcc) REAL_CUOBJDUMP=$(find_compiler cuobjdump) if [ -n "$REAL_NVCC" ]; then echo "CUDA compiler: $($REAL_NVCC --version | tail -n 1) ($REAL_NVCC)" else echo "CUDA compiler: not available" fi echo VERBOSE=false [ "$1" = "-v" ] && { VERBOSE=true; shift; } suites="$*" if [ -z "$suites" ]; then suites="$all_suites" fi for suite in $suites; do run_suite $suite done cd / rm -rf $ABS_TESTDIR green PASSED exit 0