Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | #!/usr/bin/env bash
# SPDX-License-Identifier: BSD-3-Clause
# Copyright(c) 2015 Neil Horman. All rights reserved.
# Copyright(c) 2017 6WIND S.A.
# All rights reserved
set -e
abicheck=abi-compliance-checker
abidump=abi-dumper
default_dst=abi-check
default_target=x86_64-native-linuxapp-gcc
# trap on error
err_report() {
echo "$0: error at line $1"
}
trap 'err_report $LINENO' ERR
print_usage () {
cat <<- END_OF_HELP
$(basename $0) [options] <rev1> <rev2>
This script compares the ABI of 2 git revisions of the current
workspace. The output is a html report and a compilation log.
The objective is to make sure that applications built against
DSOs from the first revision can still run when executed using
the DSOs built from the second revision.
<rev1> and <rev2> are git commit id or tags.
Options:
-h show this help
-j <num> enable parallel compilation with <num> threads
-v show compilation logs on the console
-d <dir> change working directory (default is ${default_dst})
-t <target> the dpdk target to use (default is ${default_target})
-f overwrite existing files in destination directory
The script returns 0 on success, or the value of last failing
call of ${abicheck} (incompatible abi or the tool has run with errors).
The errors returned by ${abidump} are ignored.
END_OF_HELP
}
# log in the file, and on stdout if verbose
# $1: level string
# $2: string to be logged
log() {
echo "$1: $2"
if [ "${verbose}" != "true" ]; then
echo "$1: $2" >&3
fi
}
# launch a command and log it, taking care of surrounding spaces with quotes
cmd() {
local i s whitespace ret
s=""
whitespace="[[:space:]]"
for i in "$@"; do
if [[ $i =~ $whitespace ]]; then
i=\"$i\"
fi
if [ -z "$s" ]; then
s="$i"
else
s="$s $i"
fi
done
ret=0
log "CMD" "$s"
"$@" || ret=$?
if [ "$ret" != "0" ]; then
log "CMD" "previous command returned $ret"
fi
return $ret
}
# redirect or copy stderr/stdout to a file
# the syntax is unfamiliar, but it makes the rest of the
# code easier to read, avoiding the use of pipes
set_log_file() {
# save original stdout and stderr in fd 3 and 4
exec 3>&1
exec 4>&2
# create a new fd 5 that send to a file
exec 5> >(cat > $1)
# send stdout and stderr to fd 5
if [ "${verbose}" = "true" ]; then
exec 1> >(tee /dev/fd/5 >&3)
exec 2> >(tee /dev/fd/5 >&4)
else
exec 1>&5
exec 2>&5
fi
}
# Make sure we configure SHARED libraries
# Also turn off IGB and KNI as those require kernel headers to build
fixup_config() {
local conf=config/defconfig_$target
cmd sed -i -e"$ a\CONFIG_RTE_BUILD_SHARED_LIB=y" $conf
cmd sed -i -e"$ a\CONFIG_RTE_NEXT_ABI=n" $conf
cmd sed -i -e"$ a\CONFIG_RTE_EAL_IGB_UIO=n" $conf
cmd sed -i -e"$ a\CONFIG_RTE_LIBRTE_KNI=n" $conf
cmd sed -i -e"$ a\CONFIG_RTE_KNI_KMOD=n" $conf
}
# build dpdk for the given tag and dump abi
# $1: hash of the revision
gen_abi() {
local i
cmd git clone ${dpdkroot} ${dst}/${1}
cmd cd ${dst}/${1}
log "INFO" "Checking out version ${1} of the dpdk"
# Move to the old version of the tree
cmd git checkout ${1}
fixup_config
# Now configure the build
log "INFO" "Configuring DPDK ${1}"
cmd make config T=$target O=$target
# Checking abi compliance relies on using the dwarf information in
# the shared objects. Build with -g to include them.
log "INFO" "Building DPDK ${1}. This might take a moment"
cmd make -j$parallel O=$target V=1 EXTRA_CFLAGS="-g -Og -Wno-error" \
EXTRA_LDFLAGS="-g" || log "INFO" "The build failed"
# Move to the lib directory
cmd cd ${PWD}/$target/lib
log "INFO" "Collecting ABI information for ${1}"
for i in *.so; do
[ -e "$i" ] || break
cmd $abidump ${i} -o $dst/${1}/${i}.dump -lver ${1} || true
# hack to ignore empty SymbolsInfo section (no public ABI)
if grep -q "'SymbolInfo' => {}," $dst/${1}/${i}.dump \
2> /dev/null; then
log "INFO" "${i} has no public ABI, remove dump file"
cmd rm -f $dst/${1}/${i}.dump
fi
done
}
verbose=false
parallel=1
dst=${default_dst}
target=${default_target}
force=0
while getopts j:vd:t:fh ARG ; do
case $ARG in
j ) parallel=$OPTARG ;;
v ) verbose=true ;;
d ) dst=$OPTARG ;;
t ) target=$OPTARG ;;
f ) force=1 ;;
h ) print_usage ; exit 0 ;;
? ) print_usage ; exit 1 ;;
esac
done
shift $(($OPTIND - 1))
if [ $# != 2 ]; then
print_usage
exit 1
fi
tag1=$1
tag2=$2
# convert path to absolute
case "${dst}" in
/*) ;;
*) dst=${PWD}/${dst} ;;
esac
dpdkroot=$(readlink -e $(dirname $0)/..)
if [ -e "${dst}" -a "$force" = 0 ]; then
echo "The ${dst} directory is not empty. Remove it, use another"
echo "one (-d <dir>), or force overriding (-f)"
exit 1
fi
rm -rf ${dst}
mkdir -p ${dst}
set_log_file ${dst}/abi-check.log
log "INFO" "Logs available in ${dst}/abi-check.log"
command -v ${abicheck} || log "INFO" "Can't find ${abicheck} utility"
command -v ${abidump} || log "INFO" "Can't find ${abidump} utility"
hash1=$(git show -s --format=%h "$tag1" -- 2> /dev/null | tail -1)
hash2=$(git show -s --format=%h "$tag2" -- 2> /dev/null | tail -1)
# Make hashes available in output for non-local reference
tag1="$tag1 ($hash1)"
tag2="$tag2 ($hash2)"
if [ "$hash1" = "$hash2" ]; then
log "ERROR" "$tag1 and $tag2 are the same revisions"
exit 1
fi
cmd mkdir -p ${dst}
# dump abi for each revision
gen_abi ${hash1}
gen_abi ${hash2}
# compare the abi dumps
cmd cd ${dst}
ret=0
list=""
for i in ${hash2}/*.dump; do
name=`basename $i`
libname=${name%.dump}
if [ ! -f ${hash1}/$name ]; then
log "INFO" "$NAME does not exist in $tag1. skipping..."
continue
fi
local_ret=0
cmd $abicheck -l $libname \
-old ${hash1}/$name -new ${hash2}/$name || local_ret=$?
if [ $local_ret != 0 ]; then
log "NOTICE" "$abicheck returned $local_ret"
ret=$local_ret
list="$list $libname"
fi
done
if [ $ret != 0 ]; then
log "NOTICE" "ABI may be incompatible, check reports/logs for details."
log "NOTICE" "Incompatible list: $list"
else
log "NOTICE" "No error detected, ABI is compatible."
fi
log "INFO" "Logs are in ${dst}/abi-check.log"
log "INFO" "HTML reports are in ${dst}/compat_reports directory"
exit $ret
|