325 lines · bash
1#!/bin/bash2# SPDX-License-Identifier: GPL-2.03# kselftest_deps.sh4#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 mm"16echo -e "\tkselftest_deps.sh [-p] aarch64-linux-gnu-gcc"17echo -e "\tkselftest_deps.sh [-p] aarch64-linux-gnu-gcc mm\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 131 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" ]; then41 echo -e "\tPlease run $0 in"42 echo -e "\ttools/testing/selftests directory ..."43 exit 144fi45 46print_targets=047 48while getopts "p" arg; do49 case $arg in50 p)51 print_targets=152 shift;;53 esac54done55 56if [ $# -eq 0 ]57then58 usage59fi60 61# Compiler62CC=$163 64tmp_file=$(mktemp).c65trap "rm -f $tmp_file.o $tmp_file $tmp_file.bin" EXIT66#echo $tmp_file67 68pass=$(mktemp).out69trap "rm -f $pass" EXIT70#echo $pass71 72fail=$(mktemp).out73trap "rm -f $fail" EXIT74#echo $fail75 76# Generate tmp source fire for compile test77cat << "EOF" > $tmp_file78int main()79{80}81EOF82 83# Save results84total_cnt=085fail_trgts=()86fail_libs=()87fail_cnt=088pass_trgts=()89pass_libs=()90pass_cnt=091 92# Get all TARGETS from selftests Makefile93targets=$(grep -E "^TARGETS +|^TARGETS =" Makefile | cut -d "=" -f2)94 95# Initially, in LDLIBS related lines, the dep checker needs96# to ignore lines containing the following strings:97filter="\$(VAR_LDLIBS)\|pkg-config\|PKG_CONFIG\|IOURING_EXTRA_LIBS"98 99# Single test case100if [ $# -eq 2 ]101then102 test=$2/Makefile103 104 l1_test $test105 l2_test $test106 l3_test $test107 l4_test $test108 l5_test $test109 110 print_results $1 $2111 exit $?112fi113 114# Level 1: LDLIBS set static.115#116# Find all LDLIBS set statically for all executables built by a Makefile117# 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 2127# Some tests have multiple valid LDLIBS lines for individual sub-tests128# that need dependency checks. Find them and append them to the tests129# e.g: mm/Makefile:$(OUTPUT)/userfaultfd: LDLIBS += -lpthread130# 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 3138# memfd and others use pkg-config to find mount and fuse libs139# respectively and save it in VAR_LDLIBS. If pkg-config doesn't find140# any, VAR_LDLIBS set to default.141# Use the default value and filter out pkg-config for dependency check.142# e.g:143# memfd/Makefile144# VAR_LDLIBS := $(shell pkg-config fuse --libs 2>/dev/null)145 146l3_tests=$(grep -r --include=Makefile "^VAR_LDLIBS" | \147 grep -v "pkg-config\|PKG_CONFIG" | awk -F: '{print $1}' | uniq)148 149# Level 4150# some tests may fall back to default using `|| echo -l<libname>`151# if pkg-config doesn't find the libs, instead of using VAR_LDLIBS152# as per level 3 checks.153# e.g:154# netfilter/Makefile155# LDLIBS += $(shell $(HOSTPKG_CONFIG) --libs libmnl 2>/dev/null || echo -lmnl)156l4_tests=$(grep -r --include=Makefile "^LDLIBS" | \157 grep "pkg-config\|PKG_CONFIG" | awk -F: '{print $1}' | uniq)158 159# Level 5160# some tests may use IOURING_EXTRA_LIBS to add extra libs to LDLIBS,161# which in turn may be defined in a sub-Makefile162# e.g.:163# mm/Makefile164# $(OUTPUT)/gup_longterm: LDLIBS += $(IOURING_EXTRA_LIBS)165l5_tests=$(grep -r --include=Makefile "LDLIBS +=.*\$(IOURING_EXTRA_LIBS)" | \166 awk -F: '{print $1}' | uniq)167 168#echo l1_tests $l1_tests169#echo l2_tests $l2_tests170#echo l3_tests $l3_tests171#echo l4_tests $l4_tests172#echo l5_tests $l5_tests173 174all_tests175print_results $1 $2176 177exit $?178}179# end main()180 181all_tests()182{183 for test in $l1_tests; do184 l1_test $test185 done186 187 for test in $l2_tests; do188 l2_test $test189 done190 191 for test in $l3_tests; do192 l3_test $test193 done194 195 for test in $l4_tests; do196 l4_test $test197 done198 199 for test in $l5_tests; do200 l5_test $test201 done202}203 204# Use same parsing used for l1_tests and pick libraries this time.205l1_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_libs213}214 215# Use same parsing used for l2_tests and pick libraries this time.216l2_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_libs224}225 226l3_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_libs233}234 235l4_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_libs242}243 244l5_test()245{246 tests=$(find $(dirname "$test") -type f -name "*.mk")247 [[ -z "${tests// }" ]] && return248 test_libs=$(grep "^IOURING_EXTRA_LIBS +\?=" $tests | \249 cut -d "=" -f 2)250 251 check_libs $test $test_libs252}253 254check_libs()255{256 257if [[ ! -z "${test_libs// }" ]]258then259 260 #echo $test_libs261 262 for lib in $test_libs; do263 264 let total_cnt+=1265 $CC -o $tmp_file.bin $lib $tmp_file > /dev/null 2>&1266 if [ $? -ne 0 ]; then267 echo "FAIL: $test dependency check: $lib" >> $fail268 let fail_cnt+=1269 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 else274 echo "PASS: $test dependency check passed $lib" >> $pass275 let pass_cnt+=1276 pass_libs+="$lib "277 pass_trgts+="$(echo "$test" | cut -d "/" -f1) "278 fi279 280 done281fi282}283 284print_results()285{286 echo -e "========================================================";287 echo -e "Kselftest Dependency Check for [$0 $1 $2] results..."288 289 if [ $print_targets -ne 0 ]290 then291 echo -e "Suggested Selftest Targets for your configuration:"292 echo -e "$targets";293 fi294 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 ]; then302 echo -e "--------------------------------------------------------";303 cat $pass304 echo -e "--------------------------------------------------------";305 echo -e "Targets passed build dependency check on system:"306 echo -e "$(echo "$pass_trgts" | xargs -n1 | sort -u | xargs)"307 fi308 309 if [ $fail_cnt -ne 0 ]; then310 echo -e "--------------------------------------------------------";311 cat $fail312 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 fi319 320 echo -e "--------------------------------------------------------";321 echo -e "========================================================";322}323 324main "$@"325