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 10 usage() 11 { 12 13 echo -e "Usage: $0 -[p] <compiler> [test_name]\n" 14 echo -e "\tkselftest_deps.sh [-p] gcc" 15 echo -e "\tkselftest_deps.sh [-p] gcc mm" 16 echo -e "\tkselftest_deps.sh [-p] aarch64-linux-gnu-gcc" 17 echo -e "\tkselftest_deps.sh [-p] aarch64-linux-gnu-gcc mm\n" 18 echo "- Should be run in selftests directory in the kernel repo." 19 echo "- Checks if Kselftests can be built/cross-built on a system." 20 echo "- Parses all test/sub-test Makefile to find library dependencies." 21 echo "- Runs compile test on a trivial C file with LDLIBS specified" 22 echo " in the test Makefiles to identify missing library dependencies." 23 echo "- Prints suggested target list for a system filtering out tests" 24 echo " failed the build dependency check from the TARGETS in Selftests" 25 echo " main Makefile when optional -p is specified." 26 echo "- Prints pass/fail dependency check for each tests/sub-test." 27 echo "- Prints pass/fail targets and libraries." 28 echo "- Default: runs dependency checks on all tests." 29 echo "- Optional: test name can be specified to check dependencies for it." 30 exit 1 31 32 } 33 34 # Start main() 35 main() 36 { 37 38 base_dir=`pwd` 39 # Make sure we're in the selftests top-level directory. 40 if [ $(basename "$base_dir") != "selftests" ]; then 41 echo -e "\tPlease run $0 in" 42 echo -e "\ttools/testing/selftests directory ..." 43 exit 1 44 fi 45 46 print_targets=0 47 48 while getopts "p" arg; do 49 case $arg in 50 p) 51 print_targets=1 52 shift;; 53 esac 54 done 55 56 if [ $# -eq 0 ] 57 then 58 usage 59 fi 60 61 # Compiler 62 CC=$1 63 64 tmp_file=$(mktemp).c 65 trap "rm -f $tmp_file.o $tmp_file $tmp_file.bin" EXIT 66 #echo $tmp_file 67 68 pass=$(mktemp).out 69 trap "rm -f $pass" EXIT 70 #echo $pass 71 72 fail=$(mktemp).out 73 trap "rm -f $fail" EXIT 74 #echo $fail 75 76 # Generate tmp source fire for compile test 77 cat << "EOF" > $tmp_file 78 int main() 79 { 80 } 81 EOF 82 83 # Save results 84 total_cnt=0 85 fail_trgts=() 86 fail_libs=() 87 fail_cnt=0 88 pass_trgts=() 89 pass_libs=() 90 pass_cnt=0 91 92 # Get all TARGETS from selftests Makefile 93 targets=$(grep -E "^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: 97 filter="\$(VAR_LDLIBS)\|pkg-config\|PKG_CONFIG\|IOURING_EXTRA_LIBS" 98 99 # Single test case 100 if [ $# -eq 2 ] 101 then 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 $? 112 fi 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 121 l1_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: mm/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 134 l2_tests=$(grep -r --include=Makefile ": LDLIBS" | \ 135 grep -v "$filter" | awk -F: '{print $1}' | uniq) 136 137 # Level 3 138 # 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 # memfd/Makefile 144 # VAR_LDLIBS := $(shell pkg-config fuse --libs 2>/dev/null) 145 146 l3_tests=$(grep -r --include=Makefile "^VAR_LDLIBS" | \ 147 grep -v "pkg-config\|PKG_CONFIG" | awk -F: '{print $1}' | uniq) 148 149 # Level 4 150 # some tests may fall back to default using `|| echo -l<libname>` 151 # if pkg-config doesn't find the libs, instead of using VAR_LDLIBS 152 # as per level 3 checks. 153 # e.g: 154 # netfilter/Makefile 155 # LDLIBS += $(shell $(HOSTPKG_CONFIG) --libs libmnl 2>/dev/null || echo -lmnl) 156 l4_tests=$(grep -r --include=Makefile "^LDLIBS" | \ 157 grep "pkg-config\|PKG_CONFIG" | awk -F: '{print $1}' | uniq) 158 159 # Level 5 160 # some tests may use IOURING_EXTRA_LIBS to add extra libs to LDLIBS, 161 # which in turn may be defined in a sub-Makefile 162 # e.g.: 163 # mm/Makefile 164 # $(OUTPUT)/gup_longterm: LDLIBS += $(IOURING_EXTRA_LIBS) 165 l5_tests=$(grep -r --include=Makefile "LDLIBS +=.*\$(IOURING_EXTRA_LIBS)" | \ 166 awk -F: '{print $1}' | uniq) 167 168 #echo l1_tests $l1_tests 169 #echo l2_tests $l2_tests 170 #echo l3_tests $l3_tests 171 #echo l4_tests $l4_tests 172 #echo l5_tests $l5_tests 173 174 all_tests 175 print_results $1 $2 176 177 exit $? 178 } 179 # end main() 180 181 all_tests() 182 { 183 for test in $l1_tests; do 184 l1_test $test 185 done 186 187 for test in $l2_tests; do 188 l2_test $test 189 done 190 191 for test in $l3_tests; do 192 l3_test $test 193 done 194 195 for test in $l4_tests; do 196 l4_test $test 197 done 198 199 for test in $l5_tests; do 200 l5_test $test 201 done 202 } 203 204 # Use same parsing used for l1_tests and pick libraries this time. 205 l1_test() 206 { 207 test_libs=$(grep --include=Makefile "^LDLIBS" $test | \ 208 grep -v "$filter" | \ 209 sed -e 's/\:/ /' | \ 210 sed -e 's/+/ /' | cut -d "=" -f 2) 211 212 check_libs $test $test_libs 213 } 214 215 # Use same parsing used for l2_tests and pick libraries this time. 216 l2_test() 217 { 218 test_libs=$(grep --include=Makefile ": LDLIBS" $test | \ 219 grep -v "$filter" | \ 220 sed -e 's/\:/ /' | sed -e 's/+/ /' | \ 221 cut -d "=" -f 2) 222 223 check_libs $test $test_libs 224 } 225 226 l3_test() 227 { 228 test_libs=$(grep --include=Makefile "^VAR_LDLIBS" $test | \ 229 grep -v "pkg-config" | sed -e 's/\:/ /' | 230 sed -e 's/+/ /' | cut -d "=" -f 2) 231 232 check_libs $test $test_libs 233 } 234 235 l4_test() 236 { 237 test_libs=$(grep --include=Makefile "^VAR_LDLIBS\|^LDLIBS" $test | \ 238 grep "\(pkg-config\|PKG_CONFIG\).*|| echo " | \ 239 sed -e 's/.*|| echo //' | sed -e 's/)$//') 240 241 check_libs $test $test_libs 242 } 243 244 l5_test() 245 { 246 tests=$(find $(dirname "$test") -type f -name "*.mk") 247 [[ -z "${tests// }" ]] && return 248 test_libs=$(grep "^IOURING_EXTRA_LIBS +\?=" $tests | \ 249 cut -d "=" -f 2) 250 251 check_libs $test $test_libs 252 } 253 254 check_libs() 255 { 256 257 if [[ ! -z "${test_libs// }" ]] 258 then 259 260 #echo $test_libs 261 262 for lib in $test_libs; do 263 264 let total_cnt+=1 265 $CC -o $tmp_file.bin $lib $tmp_file > /dev/null 2>&1 266 if [ $? -ne 0 ]; then 267 echo "FAIL: $test dependency check: $lib" >> $fail 268 let fail_cnt+=1 269 fail_libs+="$lib " 270 fail_target=$(echo "$test" | cut -d "/" -f1) 271 fail_trgts+="$fail_target " 272 targets=$(echo "$targets" | grep -v "$fail_target") 273 else 274 echo "PASS: $test dependency check passed $lib" >> $pass 275 let pass_cnt+=1 276 pass_libs+="$lib " 277 pass_trgts+="$(echo "$test" | cut -d "/" -f1) " 278 fi 279 280 done 281 fi 282 } 283 284 print_results() 285 { 286 echo -e "========================================================"; 287 echo -e "Kselftest Dependency Check for [$0 $1 $2] results..." 288 289 if [ $print_targets -ne 0 ] 290 then 291 echo -e "Suggested Selftest Targets for your configuration:" 292 echo -e "$targets"; 293 fi 294 295 echo -e "========================================================"; 296 echo -e "Checked tests defining LDLIBS dependencies" 297 echo -e "--------------------------------------------------------"; 298 echo -e "Total tests with Dependencies:" 299 echo -e "$total_cnt Pass: $pass_cnt Fail: $fail_cnt"; 300 301 if [ $pass_cnt -ne 0 ]; then 302 echo -e "--------------------------------------------------------"; 303 cat $pass 304 echo -e "--------------------------------------------------------"; 305 echo -e "Targets passed build dependency check on system:" 306 echo -e "$(echo "$pass_trgts" | xargs -n1 | sort -u | xargs)" 307 fi 308 309 if [ $fail_cnt -ne 0 ]; then 310 echo -e "--------------------------------------------------------"; 311 cat $fail 312 echo -e "--------------------------------------------------------"; 313 echo -e "Targets failed build dependency check on system:" 314 echo -e "$(echo "$fail_trgts" | xargs -n1 | sort -u | xargs)" 315 echo -e "--------------------------------------------------------"; 316 echo -e "Missing libraries system" 317 echo -e "$(echo "$fail_libs" | xargs -n1 | sort -u | xargs)" 318 fi 319 320 echo -e "--------------------------------------------------------"; 321 echo -e "========================================================"; 322 } 323 324 main "$@"
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.