1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3# kselftest_deps.sh 4# 5# Checks for kselftest build dependencies on the build system. 6# Copyright (c) 2020 Shuah Khan <skhan@linuxfoundation.org> 7# 8# 9 10usage() 11{ 12 13echo -e "Usage: $0 -[p] <compiler> [test_name]\n" 14echo -e "\tkselftest_deps.sh [-p] gcc" 15echo -e "\tkselftest_deps.sh [-p] gcc vm" 16echo -e "\tkselftest_deps.sh [-p] aarch64-linux-gnu-gcc" 17echo -e "\tkselftest_deps.sh [-p] aarch64-linux-gnu-gcc vm\n" 18echo "- Should be run in selftests directory in the kernel repo." 19echo "- Checks if Kselftests can be built/cross-built on a system." 20echo "- Parses all test/sub-test Makefile to find library dependencies." 21echo "- Runs compile test on a trivial C file with LDLIBS specified" 22echo " in the test Makefiles to identify missing library dependencies." 23echo "- Prints suggested target list for a system filtering out tests" 24echo " failed the build dependency check from the TARGETS in Selftests" 25echo " main Makefile when optional -p is specified." 26echo "- Prints pass/fail dependency check for each tests/sub-test." 27echo "- Prints pass/fail targets and libraries." 28echo "- Default: runs dependency checks on all tests." 29echo "- Optional test name can be specified to check dependencies for it." 30exit 1 31 32} 33 34# Start main() 35main() 36{ 37 38base_dir=`pwd` 39# Make sure we're in the selftests top-level directory. 40if [ $(basename "$base_dir") != "selftests" ]; then 41 echo -e "\tPlease run $0 in" 42 echo -e "\ttools/testing/selftests directory ..." 43 exit 1 44fi 45 46print_targets=0 47 48while getopts "p" arg; do 49 case $arg in 50 p) 51 print_targets=1 52 shift;; 53 esac 54done 55 56if [ $# -eq 0 ] 57then 58 usage 59fi 60 61# Compiler 62CC=$1 63 64tmp_file=$(mktemp).c 65trap "rm -f $tmp_file.o $tmp_file $tmp_file.bin" EXIT 66#echo $tmp_file 67 68pass=$(mktemp).out 69trap "rm -f $pass" EXIT 70#echo $pass 71 72fail=$(mktemp).out 73trap "rm -f $fail" EXIT 74#echo $fail 75 76# Generate tmp source fire for compile test 77cat << "EOF" > $tmp_file 78int main() 79{ 80} 81EOF 82 83# Save results 84total_cnt=0 85fail_trgts=() 86fail_libs=() 87fail_cnt=0 88pass_trgts=() 89pass_libs=() 90pass_cnt=0 91 92# Get all TARGETS from selftests Makefile 93targets=$(egrep "^TARGETS +|^TARGETS =" Makefile | cut -d "=" -f2) 94 95# Single test case 96if [ $# -eq 2 ] 97then 98 test=$2/Makefile 99 100 l1_test $test 101 l2_test $test 102 l3_test $test 103 104 print_results $1 $2 105 exit $? 106fi 107 108# Level 1: LDLIBS set static. 109# 110# Find all LDLIBS set statically for all executables built by a Makefile 111# and filter out VAR_LDLIBS to discard the following: 112# gpio/Makefile:LDLIBS += $(VAR_LDLIBS) 113# Append space at the end of the list to append more tests. 114 115l1_tests=$(grep -r --include=Makefile "^LDLIBS" | \ 116 grep -v "VAR_LDLIBS" | awk -F: '{print $1}') 117 118# Level 2: LDLIBS set dynamically. 119# 120# Level 2 121# Some tests have multiple valid LDLIBS lines for individual sub-tests 122# that need dependency checks. Find them and append them to the tests 123# e.g: vm/Makefile:$(OUTPUT)/userfaultfd: LDLIBS += -lpthread 124# Filter out VAR_LDLIBS to discard the following: 125# memfd/Makefile:$(OUTPUT)/fuse_mnt: LDLIBS += $(VAR_LDLIBS) 126# Append space at the end of the list to append more tests. 127 128l2_tests=$(grep -r --include=Makefile ": LDLIBS" | \ 129 grep -v "VAR_LDLIBS" | awk -F: '{print $1}') 130 131# Level 3 132# gpio, memfd and others use pkg-config to find mount and fuse libs 133# respectively and save it in VAR_LDLIBS. If pkg-config doesn't find 134# any, VAR_LDLIBS set to default. 135# Use the default value and filter out pkg-config for dependency check. 136# e.g: 137# gpio/Makefile 138# VAR_LDLIBS := $(shell pkg-config --libs mount) 2>/dev/null) 139# memfd/Makefile 140# VAR_LDLIBS := $(shell pkg-config fuse --libs 2>/dev/null) 141 142l3_tests=$(grep -r --include=Makefile "^VAR_LDLIBS" | \ 143 grep -v "pkg-config" | awk -F: '{print $1}') 144 145#echo $l1_tests 146#echo $l2_1_tests 147#echo $l3_tests 148 149all_tests 150print_results $1 $2 151 152exit $? 153} 154# end main() 155 156all_tests() 157{ 158 for test in $l1_tests; do 159 l1_test $test 160 done 161 162 for test in $l2_tests; do 163 l2_test $test 164 done 165 166 for test in $l3_tests; do 167 l3_test $test 168 done 169} 170 171# Use same parsing used for l1_tests and pick libraries this time. 172l1_test() 173{ 174 test_libs=$(grep --include=Makefile "^LDLIBS" $test | \ 175 grep -v "VAR_LDLIBS" | \ 176 sed -e 's/\:/ /' | \ 177 sed -e 's/+/ /' | cut -d "=" -f 2) 178 179 check_libs $test $test_libs 180} 181 182# Use same parsing used for l2__tests and pick libraries this time. 183l2_test() 184{ 185 test_libs=$(grep --include=Makefile ": LDLIBS" $test | \ 186 grep -v "VAR_LDLIBS" | \ 187 sed -e 's/\:/ /' | sed -e 's/+/ /' | \ 188 cut -d "=" -f 2) 189 190 check_libs $test $test_libs 191} 192 193l3_test() 194{ 195 test_libs=$(grep --include=Makefile "^VAR_LDLIBS" $test | \ 196 grep -v "pkg-config" | sed -e 's/\:/ /' | 197 sed -e 's/+/ /' | cut -d "=" -f 2) 198 199 check_libs $test $test_libs 200} 201 202check_libs() 203{ 204 205if [[ ! -z "${test_libs// }" ]] 206then 207 208 #echo $test_libs 209 210 for lib in $test_libs; do 211 212 let total_cnt+=1 213 $CC -o $tmp_file.bin $lib $tmp_file > /dev/null 2>&1 214 if [ $? -ne 0 ]; then 215 echo "FAIL: $test dependency check: $lib" >> $fail 216 let fail_cnt+=1 217 fail_libs+="$lib " 218 fail_target=$(echo "$test" | cut -d "/" -f1) 219 fail_trgts+="$fail_target " 220 targets=$(echo "$targets" | grep -v "$fail_target") 221 else 222 echo "PASS: $test dependency check passed $lib" >> $pass 223 let pass_cnt+=1 224 pass_libs+="$lib " 225 pass_trgts+="$(echo "$test" | cut -d "/" -f1) " 226 fi 227 228 done 229fi 230} 231 232print_results() 233{ 234 echo -e "========================================================"; 235 echo -e "Kselftest Dependency Check for [$0 $1 $2] results..." 236 237 if [ $print_targets -ne 0 ] 238 then 239 echo -e "Suggested Selftest Targets for your configuration:" 240 echo -e "$targets"; 241 fi 242 243 echo -e "========================================================"; 244 echo -e "Checked tests defining LDLIBS dependencies" 245 echo -e "--------------------------------------------------------"; 246 echo -e "Total tests with Dependencies:" 247 echo -e "$total_cnt Pass: $pass_cnt Fail: $fail_cnt"; 248 249 if [ $pass_cnt -ne 0 ]; then 250 echo -e "--------------------------------------------------------"; 251 cat $pass 252 echo -e "--------------------------------------------------------"; 253 echo -e "Targets passed build dependency check on system:" 254 echo -e "$(echo "$pass_trgts" | xargs -n1 | sort -u | xargs)" 255 fi 256 257 if [ $fail_cnt -ne 0 ]; then 258 echo -e "--------------------------------------------------------"; 259 cat $fail 260 echo -e "--------------------------------------------------------"; 261 echo -e "Targets failed build dependency check on system:" 262 echo -e "$(echo "$fail_trgts" | xargs -n1 | sort -u | xargs)" 263 echo -e "--------------------------------------------------------"; 264 echo -e "Missing libraries system" 265 echo -e "$(echo "$fail_libs" | xargs -n1 | sort -u | xargs)" 266 fi 267 268 echo -e "--------------------------------------------------------"; 269 echo -e "========================================================"; 270} 271 272main "$@" 273