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=$(grep -E "^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# 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# memfd/Makefile 138# VAR_LDLIBS := $(shell pkg-config fuse --libs 2>/dev/null) 139 140l3_tests=$(grep -r --include=Makefile "^VAR_LDLIBS" | \ 141 grep -v "pkg-config" | awk -F: '{print $1}') 142 143#echo $l1_tests 144#echo $l2_1_tests 145#echo $l3_tests 146 147all_tests 148print_results $1 $2 149 150exit $? 151} 152# end main() 153 154all_tests() 155{ 156 for test in $l1_tests; do 157 l1_test $test 158 done 159 160 for test in $l2_tests; do 161 l2_test $test 162 done 163 164 for test in $l3_tests; do 165 l3_test $test 166 done 167} 168 169# Use same parsing used for l1_tests and pick libraries this time. 170l1_test() 171{ 172 test_libs=$(grep --include=Makefile "^LDLIBS" $test | \ 173 grep -v "VAR_LDLIBS" | \ 174 sed -e 's/\:/ /' | \ 175 sed -e 's/+/ /' | cut -d "=" -f 2) 176 177 check_libs $test $test_libs 178} 179 180# Use same parsing used for l2__tests and pick libraries this time. 181l2_test() 182{ 183 test_libs=$(grep --include=Makefile ": LDLIBS" $test | \ 184 grep -v "VAR_LDLIBS" | \ 185 sed -e 's/\:/ /' | sed -e 's/+/ /' | \ 186 cut -d "=" -f 2) 187 188 check_libs $test $test_libs 189} 190 191l3_test() 192{ 193 test_libs=$(grep --include=Makefile "^VAR_LDLIBS" $test | \ 194 grep -v "pkg-config" | sed -e 's/\:/ /' | 195 sed -e 's/+/ /' | cut -d "=" -f 2) 196 197 check_libs $test $test_libs 198} 199 200check_libs() 201{ 202 203if [[ ! -z "${test_libs// }" ]] 204then 205 206 #echo $test_libs 207 208 for lib in $test_libs; do 209 210 let total_cnt+=1 211 $CC -o $tmp_file.bin $lib $tmp_file > /dev/null 2>&1 212 if [ $? -ne 0 ]; then 213 echo "FAIL: $test dependency check: $lib" >> $fail 214 let fail_cnt+=1 215 fail_libs+="$lib " 216 fail_target=$(echo "$test" | cut -d "/" -f1) 217 fail_trgts+="$fail_target " 218 targets=$(echo "$targets" | grep -v "$fail_target") 219 else 220 echo "PASS: $test dependency check passed $lib" >> $pass 221 let pass_cnt+=1 222 pass_libs+="$lib " 223 pass_trgts+="$(echo "$test" | cut -d "/" -f1) " 224 fi 225 226 done 227fi 228} 229 230print_results() 231{ 232 echo -e "========================================================"; 233 echo -e "Kselftest Dependency Check for [$0 $1 $2] results..." 234 235 if [ $print_targets -ne 0 ] 236 then 237 echo -e "Suggested Selftest Targets for your configuration:" 238 echo -e "$targets"; 239 fi 240 241 echo -e "========================================================"; 242 echo -e "Checked tests defining LDLIBS dependencies" 243 echo -e "--------------------------------------------------------"; 244 echo -e "Total tests with Dependencies:" 245 echo -e "$total_cnt Pass: $pass_cnt Fail: $fail_cnt"; 246 247 if [ $pass_cnt -ne 0 ]; then 248 echo -e "--------------------------------------------------------"; 249 cat $pass 250 echo -e "--------------------------------------------------------"; 251 echo -e "Targets passed build dependency check on system:" 252 echo -e "$(echo "$pass_trgts" | xargs -n1 | sort -u | xargs)" 253 fi 254 255 if [ $fail_cnt -ne 0 ]; then 256 echo -e "--------------------------------------------------------"; 257 cat $fail 258 echo -e "--------------------------------------------------------"; 259 echo -e "Targets failed build dependency check on system:" 260 echo -e "$(echo "$fail_trgts" | xargs -n1 | sort -u | xargs)" 261 echo -e "--------------------------------------------------------"; 262 echo -e "Missing libraries system" 263 echo -e "$(echo "$fail_libs" | xargs -n1 | sort -u | xargs)" 264 fi 265 266 echo -e "--------------------------------------------------------"; 267 echo -e "========================================================"; 268} 269 270main "$@" 271