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# Initially, in LDLIBS related lines, the dep checker needs 96# to ignore lines containing the following strings: 97filter="\$(VAR_LDLIBS)\|pkg-config\|PKG_CONFIG\|IOURING_EXTRA_LIBS" 98 99# Single test case 100if [ $# -eq 2 ] 101then 102 test=$2/Makefile 103 104 l1_test $test 105 l2_test $test 106 l3_test $test 107 l4_test $test 108 l5_test $test 109 110 print_results $1 $2 111 exit $? 112fi 113 114# Level 1: LDLIBS set static. 115# 116# Find all LDLIBS set statically for all executables built by a Makefile 117# and filter out VAR_LDLIBS to discard the following: 118# gpio/Makefile:LDLIBS += $(VAR_LDLIBS) 119# Append space at the end of the list to append more tests. 120 121l1_tests=$(grep -r --include=Makefile "^LDLIBS" | \ 122 grep -v "$filter" | awk -F: '{print $1}' | uniq) 123 124# Level 2: LDLIBS set dynamically. 125# 126# Level 2 127# Some tests have multiple valid LDLIBS lines for individual sub-tests 128# that need dependency checks. Find them and append them to the tests 129# e.g: vm/Makefile:$(OUTPUT)/userfaultfd: LDLIBS += -lpthread 130# Filter out VAR_LDLIBS to discard the following: 131# memfd/Makefile:$(OUTPUT)/fuse_mnt: LDLIBS += $(VAR_LDLIBS) 132# Append space at the end of the list to append more tests. 133 134l2_tests=$(grep -r --include=Makefile ": LDLIBS" | \ 135 grep -v "$filter" | awk -F: '{print $1}' | uniq) 136 137# Level 3 138# gpio, memfd and others use pkg-config to find mount and fuse libs 139# respectively and save it in VAR_LDLIBS. If pkg-config doesn't find 140# any, VAR_LDLIBS set to default. 141# Use the default value and filter out pkg-config for dependency check. 142# e.g: 143# gpio/Makefile 144# VAR_LDLIBS := $(shell pkg-config --libs mount) 2>/dev/null) 145# memfd/Makefile 146# VAR_LDLIBS := $(shell pkg-config fuse --libs 2>/dev/null) 147 148l3_tests=$(grep -r --include=Makefile "^VAR_LDLIBS" | \ 149 grep -v "pkg-config\|PKG_CONFIG" | awk -F: '{print $1}' | uniq) 150 151# Level 4 152# some tests may fall back to default using `|| echo -l<libname>` 153# if pkg-config doesn't find the libs, instead of using VAR_LDLIBS 154# as per level 3 checks. 155# e.g: 156# netfilter/Makefile 157# LDLIBS += $(shell $(HOSTPKG_CONFIG) --libs libmnl 2>/dev/null || echo -lmnl) 158l4_tests=$(grep -r --include=Makefile "^LDLIBS" | \ 159 grep "pkg-config\|PKG_CONFIG" | awk -F: '{print $1}' | uniq) 160 161# Level 5 162# some tests may use IOURING_EXTRA_LIBS to add extra libs to LDLIBS, 163# which in turn may be defined in a sub-Makefile 164# e.g.: 165# mm/Makefile 166# $(OUTPUT)/gup_longterm: LDLIBS += $(IOURING_EXTRA_LIBS) 167l5_tests=$(grep -r --include=Makefile "LDLIBS +=.*\$(IOURING_EXTRA_LIBS)" | \ 168 awk -F: '{print $1}' | uniq) 169 170#echo l1_tests $l1_tests 171#echo l2_tests $l2_tests 172#echo l3_tests $l3_tests 173#echo l4_tests $l4_tests 174#echo l5_tests $l5_tests 175 176all_tests 177print_results $1 $2 178 179exit $? 180} 181# end main() 182 183all_tests() 184{ 185 for test in $l1_tests; do 186 l1_test $test 187 done 188 189 for test in $l2_tests; do 190 l2_test $test 191 done 192 193 for test in $l3_tests; do 194 l3_test $test 195 done 196 197 for test in $l4_tests; do 198 l4_test $test 199 done 200 201 for test in $l5_tests; do 202 l5_test $test 203 done 204} 205 206# Use same parsing used for l1_tests and pick libraries this time. 207l1_test() 208{ 209 test_libs=$(grep --include=Makefile "^LDLIBS" $test | \ 210 grep -v "$filter" | \ 211 sed -e 's/\:/ /' | \ 212 sed -e 's/+/ /' | cut -d "=" -f 2) 213 214 check_libs $test $test_libs 215} 216 217# Use same parsing used for l2_tests and pick libraries this time. 218l2_test() 219{ 220 test_libs=$(grep --include=Makefile ": LDLIBS" $test | \ 221 grep -v "$filter" | \ 222 sed -e 's/\:/ /' | sed -e 's/+/ /' | \ 223 cut -d "=" -f 2) 224 225 check_libs $test $test_libs 226} 227 228l3_test() 229{ 230 test_libs=$(grep --include=Makefile "^VAR_LDLIBS" $test | \ 231 grep -v "pkg-config" | sed -e 's/\:/ /' | 232 sed -e 's/+/ /' | cut -d "=" -f 2) 233 234 check_libs $test $test_libs 235} 236 237l4_test() 238{ 239 test_libs=$(grep --include=Makefile "^VAR_LDLIBS\|^LDLIBS" $test | \ 240 grep "\(pkg-config\|PKG_CONFIG\).*|| echo " | \ 241 sed -e 's/.*|| echo //' | sed -e 's/)$//') 242 243 check_libs $test $test_libs 244} 245 246l5_test() 247{ 248 tests=$(find $(dirname "$test") -type f -name "*.mk") 249 test_libs=$(grep "^IOURING_EXTRA_LIBS +\?=" $tests | \ 250 cut -d "=" -f 2) 251 252 check_libs $test $test_libs 253} 254 255check_libs() 256{ 257 258if [[ ! -z "${test_libs// }" ]] 259then 260 261 #echo $test_libs 262 263 for lib in $test_libs; do 264 265 let total_cnt+=1 266 $CC -o $tmp_file.bin $lib $tmp_file > /dev/null 2>&1 267 if [ $? -ne 0 ]; then 268 echo "FAIL: $test dependency check: $lib" >> $fail 269 let fail_cnt+=1 270 fail_libs+="$lib " 271 fail_target=$(echo "$test" | cut -d "/" -f1) 272 fail_trgts+="$fail_target " 273 targets=$(echo "$targets" | grep -v "$fail_target") 274 else 275 echo "PASS: $test dependency check passed $lib" >> $pass 276 let pass_cnt+=1 277 pass_libs+="$lib " 278 pass_trgts+="$(echo "$test" | cut -d "/" -f1) " 279 fi 280 281 done 282fi 283} 284 285print_results() 286{ 287 echo -e "========================================================"; 288 echo -e "Kselftest Dependency Check for [$0 $1 $2] results..." 289 290 if [ $print_targets -ne 0 ] 291 then 292 echo -e "Suggested Selftest Targets for your configuration:" 293 echo -e "$targets"; 294 fi 295 296 echo -e "========================================================"; 297 echo -e "Checked tests defining LDLIBS dependencies" 298 echo -e "--------------------------------------------------------"; 299 echo -e "Total tests with Dependencies:" 300 echo -e "$total_cnt Pass: $pass_cnt Fail: $fail_cnt"; 301 302 if [ $pass_cnt -ne 0 ]; then 303 echo -e "--------------------------------------------------------"; 304 cat $pass 305 echo -e "--------------------------------------------------------"; 306 echo -e "Targets passed build dependency check on system:" 307 echo -e "$(echo "$pass_trgts" | xargs -n1 | sort -u | xargs)" 308 fi 309 310 if [ $fail_cnt -ne 0 ]; then 311 echo -e "--------------------------------------------------------"; 312 cat $fail 313 echo -e "--------------------------------------------------------"; 314 echo -e "Targets failed build dependency check on system:" 315 echo -e "$(echo "$fail_trgts" | xargs -n1 | sort -u | xargs)" 316 echo -e "--------------------------------------------------------"; 317 echo -e "Missing libraries system" 318 echo -e "$(echo "$fail_libs" | xargs -n1 | sort -u | xargs)" 319 fi 320 321 echo -e "--------------------------------------------------------"; 322 echo -e "========================================================"; 323} 324 325main "$@" 326