1#!/usr/bin/env bash 2# SPDX-License-Identifier: BSD-3-Clause 3# Copyright (C) 2022 Intel Corporation. 4# All rights reserved. 5 6source "$rootdir/test/common/autotest_common.sh" 7source "$rootdir/scripts/common.sh" 8 9_ocf_precompile() { 10 # We compile OCF sources ourselves 11 # They don't need to be checked with scanbuild and code coverage is not applicable 12 # So we precompile OCF now for further use as standalone static library 13 "$rootdir/configure" $(echo $config_params | sed 's/--enable-coverage//g') 14 $MAKE $MAKEFLAGS include/spdk/config.h 15 CC=gcc CCAR=ar $MAKE $MAKEFLAGS -C "$rootdir/lib/env_ocf" exportlib O="$rootdir/ocf.a" 16 # Set config to use precompiled library 17 config_params="$config_params --with-ocf=/$rootdir/ocf.a" 18 # need to reconfigure to avoid clearing ocf related files on future make clean. 19 "$rootdir/configure" $config_params 20} 21 22# Find matching llvm fuzzer library and clang compiler version 23_llvm_precompile() { 24 [[ $(clang --version) =~ "version "(([0-9]+).([0-9]+).([0-9]+)) ]] 25 clang_version=${BASH_REMATCH[1]} 26 clang_num=${BASH_REMATCH[2]} 27 28 export CC=clang-$clang_num 29 export CXX=clang++-$clang_num 30 31 fuzzer_libs=(/usr/lib*/clang/"$clang_version"/lib/linux/libclang_rt.fuzzer_no_main-x86_64.a) 32 fuzzer_lib=${fuzzer_libs[0]} 33 [[ -e $fuzzer_lib ]] 34 35 config_params="$config_params --with-fuzzer=$fuzzer_lib" 36 # need to reconfigure to avoid clearing llvm related files on future make clean. 37 "$rootdir/configure" $config_params 38} 39 40_build_native_dpdk() { 41 local external_dpdk_dir 42 local external_dpdk_base_dir 43 local compiler_version 44 local compiler 45 local dpdk_kmods 46 local repo='dpdk' 47 48 compiler=${CC:-gcc} 49 50 # Export CC to be absolutely sure it's set. 51 # If CC was not set and we defaulted to "gcc" then we need to do the export 52 # so that "meson build" command a few lines below is aware of which compiler 53 # to use. 54 export CC="$compiler" 55 56 if [[ $compiler != *clang* && $compiler != *gcc* ]]; then 57 echo "Unsupported compiler detected ($compiler), failing the test" >&2 58 return 1 59 fi 60 61 if [[ $SPDK_TEST_NATIVE_DPDK != 'main' ]]; then 62 repo='dpdk-stable' 63 fi 64 65 compiler_version=$("$compiler" -dumpversion) 66 compiler_version=${compiler_version%%.*} 67 external_dpdk_dir="$SPDK_RUN_EXTERNAL_DPDK" 68 external_dpdk_base_dir="$(dirname $external_dpdk_dir)" 69 70 if [[ ! -d "$external_dpdk_base_dir" ]]; then 71 sudo mkdir -p "$external_dpdk_base_dir" 72 sudo chown -R $(whoami) "$external_dpdk_base_dir"/.. 73 fi 74 orgdir=$PWD 75 76 rm -rf "$external_dpdk_base_dir" 77 git clone --branch $SPDK_TEST_NATIVE_DPDK --depth 1 http://dpdk.org/git/${repo} "$external_dpdk_base_dir" 78 git -C "$external_dpdk_base_dir" log --oneline -n 5 79 80 dpdk_cflags="-fPIC -g -fcommon" 81 dpdk_ldflags="" 82 dpdk_ver=$(< "$external_dpdk_base_dir/VERSION") 83 84 if [[ $compiler == *gcc* && $compiler_version -ge 5 ]]; then 85 dpdk_cflags+=" -Werror" 86 fi 87 88 if [[ $compiler == *gcc* && $compiler_version -ge 10 ]]; then 89 dpdk_cflags+=" -Wno-stringop-overflow" 90 fi 91 92 # the drivers we use 93 # net/i40e driver is not really needed by us, but it's built as a workaround 94 # for DPDK issue: https://bugs.dpdk.org/show_bug.cgi?id=576 95 DPDK_DRIVERS=("bus" "bus/pci" "bus/vdev" "mempool/ring" "net/i40e" "net/i40e/base") 96 97 local mlx5_libs_added="n" 98 if [[ "$SPDK_TEST_CRYPTO" -eq 1 || "$SPDK_TEST_SMA" -eq 1 ]]; then 99 intel_ipsec_mb_ver=v0.54 100 intel_ipsec_mb_drv=crypto/aesni_mb 101 intel_ipsec_lib="" 102 if ge "$dpdk_ver" 21.11.0; then 103 # Minimum supported version of intel-ipsec-mb, for DPDK >= 21.11, is 1.0. 104 # Source of the aesni_mb driver was moved to ipsec_mb. .{h,so,a} were moved 105 # to ./lib. 106 # https://github.com/dpdk/dpdk/commit/918fd2f1466b0e3b21a033df7012a77a83665582. 107 intel_ipsec_mb_ver=v1.0 108 intel_ipsec_mb_drv=crypto/ipsec_mb 109 intel_ipsec_lib=lib 110 fi 111 git clone --branch "$intel_ipsec_mb_ver" --depth 1 https://github.com/intel/intel-ipsec-mb.git "$external_dpdk_base_dir/intel-ipsec-mb" 112 cd "$external_dpdk_base_dir/intel-ipsec-mb" 113 $MAKE $MAKEFLAGS all SHARED=y EXTRA_CFLAGS=-fPIC 114 DPDK_DRIVERS+=("crypto") 115 DPDK_DRIVERS+=("$intel_ipsec_mb_drv") 116 DPDK_DRIVERS+=("crypto/qat") 117 DPDK_DRIVERS+=("compress/qat") 118 DPDK_DRIVERS+=("common/qat") 119 # 21.11.0 is version of DPDK with stable support for mlx5 crypto. 120 if ge "$dpdk_ver" 21.11.0; then 121 # SPDK enables CRYPTO_MLX in case supported version of DPDK is detected 122 # so make sure proper libs are built. 123 DPDK_DRIVERS+=("bus/auxiliary") 124 DPDK_DRIVERS+=("common/mlx5") 125 DPDK_DRIVERS+=("common/mlx5/linux") 126 DPDK_DRIVERS+=("crypto/mlx5") 127 mlx5_libs_added="y" 128 fi 129 dpdk_cflags+=" -I$external_dpdk_base_dir/intel-ipsec-mb/$intel_ipsec_lib" 130 dpdk_ldflags+=" -L$external_dpdk_base_dir/intel-ipsec-mb/$intel_ipsec_lib" 131 export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$external_dpdk_base_dir/intel-ipsec-mb/$intel_ipsec_lib" 132 fi 133 134 if [[ "$SPDK_TEST_VBDEV_COMPRESS" -eq 1 ]]; then 135 isal_dir="$external_dpdk_base_dir/isa-l" 136 git clone --branch v2.29.0 --depth 1 https://github.com/intel/isa-l.git "$isal_dir" 137 138 cd $isal_dir 139 ./autogen.sh 140 ./configure CFLAGS="-fPIC -g -O2" --enable-shared=yes --prefix="$isal_dir/build" 141 ln -s $PWD/include $PWD/isa-l 142 $MAKE $MAKEFLAGS all 143 $MAKE install 144 DPDK_DRIVERS+=("compress") 145 DPDK_DRIVERS+=("compress/isal") 146 DPDK_DRIVERS+=("compress/qat") 147 DPDK_DRIVERS+=("common/qat") 148 if ge "$dpdk_ver" 21.02.0; then 149 # SPDK enables REDUCE_MLX in case supported version of DPDK is detected 150 # so make sure proper libs are built. 151 if test $mlx5_libs_added = "n"; then 152 DPDK_DRIVERS+=("bus/auxiliary") 153 DPDK_DRIVERS+=("common/mlx5") 154 DPDK_DRIVERS+=("common/mlx5/linux") 155 fi 156 DPDK_DRIVERS+=("compress/mlx5") 157 fi 158 export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$isal_dir/build/lib/pkgconfig" 159 export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$isal_dir/build/lib" 160 fi 161 162 cd $external_dpdk_base_dir 163 if [ "$(uname -s)" = "Linux" ]; then 164 if lt $dpdk_ver 21.11.0; then 165 patch -p1 < "$rootdir/test/common/config/pkgdep/patches/dpdk/20.11/dpdk_pci.patch" 166 patch -p1 < "$rootdir/test/common/config/pkgdep/patches/dpdk/20.11/dpdk_qat.patch" 167 else 168 patch -p1 < "$rootdir/test/common/config/pkgdep/patches/dpdk/21.11+/dpdk_qat.patch" 169 170 if lt $dpdk_ver 23.03.0; then 171 # Commit https://review.spdk.io/gerrit/c/spdk/dpdk/+/16828 is required for DPDK <23.03.0 172 patch -p1 < "$rootdir/test/common/config/pkgdep/patches/dpdk/21.11+/dpdk_rte_thash_gfni.patch" 173 fi 174 175 # Commit https://review.spdk.io/gerrit/c/spdk/dpdk/+/16134 is required for DPDK 22.11+ 176 if ge $dpdk_ver 22.11.0; then 177 patch -p1 < "$rootdir/test/common/config/pkgdep/patches/dpdk/22.11+/dpdk_ipsec_mb.patch" 178 fi 179 fi 180 fi 181 182 dpdk_kmods="false" 183 if [ "$(uname -s)" = "FreeBSD" ]; then 184 dpdk_kmods="true" 185 fi 186 187 meson build-tmp --prefix="$external_dpdk_dir" --libdir lib \ 188 -Denable_docs=false -Denable_kmods="$dpdk_kmods" -Dtests=false \ 189 -Dc_link_args="$dpdk_ldflags" -Dc_args="$dpdk_cflags" \ 190 -Dmachine=native -Denable_drivers=$(printf "%s," "${DPDK_DRIVERS[@]}") 191 ninja -C "$external_dpdk_base_dir/build-tmp" $MAKEFLAGS 192 ninja -C "$external_dpdk_base_dir/build-tmp" $MAKEFLAGS install 193 194 # Save this path. In tests are run using autorun.sh then autotest.sh 195 # script will be unaware of LD_LIBRARY_PATH and will fail tests. 196 echo "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH" > /tmp/spdk-ld-path 197 198 cd "$orgdir" 199} 200 201check_dpdk_pci_api() { 202 local dpdk_dir 203 204 if [[ -n "$SPDK_TEST_NATIVE_DPDK" ]]; then 205 dpdk_dir=$(dirname "$SPDK_RUN_EXTERNAL_DPDK") 206 fi 207 208 "$rootdir/scripts/env_dpdk/check_dpdk_pci_api.sh" check "$dpdk_dir" 209} 210 211make_fail_cleanup() { 212 if [ -d $out/scan-build-tmp ]; then 213 scanoutput=$(ls -1 $out/scan-build-tmp/) 214 mv $out/scan-build-tmp/$scanoutput $out/scan-build 215 rm -rf $out/scan-build-tmp 216 chmod -R a+rX $out/scan-build 217 fi 218 false 219} 220 221_scanbuild_make() { 222 pass=true 223 "$rootdir/configure" $config_params --without-shared 224 $scanbuild $MAKE $MAKEFLAGS > $out/build_output.txt && rm -rf $out/scan-build-tmp || make_fail_cleanup 225 xtrace_disable 226 227 rm -f $out/*files.txt 228 for ent in $(find app examples lib module test -type f | grep -vF ".h"); do 229 if [[ $ent == lib/env_ocf* ]]; then continue; fi 230 if file -bi $ent | grep -q 'text/x-c'; then 231 echo $ent | sed 's/\.cp\{0,2\}$//g' >> $out/all_c_files.txt 232 fi 233 done 234 xtrace_restore 235 236 grep -E "CC|CXX" $out/build_output.txt | sed 's/\s\s\(CC\|CXX\)\s//g' | sed 's/\.o//g' > $out/built_c_files.txt 237 cat $rootdir/test/common/skipped_build_files.txt >> $out/built_c_files.txt 238 239 sort -o $out/all_c_files.txt $out/all_c_files.txt 240 sort -o $out/built_c_files.txt $out/built_c_files.txt 241 # from comm manual: 242 # -2 suppress column 2 (lines unique to FILE2) 243 # -3 suppress column 3 (lines that appear in both files) 244 # comm may exit 1 if no lines were printed (undocumented, unreliable) 245 comm -2 -3 $out/all_c_files.txt $out/built_c_files.txt > $out/unbuilt_c_files.txt || true 246 247 if [ $(wc -l < $out/unbuilt_c_files.txt) -ge 1 ]; then 248 echo "missing files" 249 cat <<- ERROR 250 The following C files were not built. Either scanbuild CI job needs to 251 be updated with proper flags to build these files, or exceptions need 252 to be added to test/common/skipped_build_files.txt 253 254 $(<"$out/unbuilt_c_files.txt") 255 ERROR 256 pass=false 257 fi 258 259 $pass 260} 261 262porcelain_check() { 263 if [ $(git status --porcelain --ignore-submodules | wc -l) -ne 0 ]; then 264 echo "Generated files missing from .gitignore:" 265 git status --porcelain --ignore-submodules 266 exit 1 267 fi 268} 269 270# Check that header file dependencies are working correctly by 271# capturing a binary's stat data before and after touching a 272# header file and re-making. 273header_dependency_check() { 274 STAT1=$(stat $SPDK_BIN_DIR/spdk_tgt) 275 sleep 1 276 touch "$rootdir/lib/nvme/nvme_internal.h" 277 $MAKE $MAKEFLAGS 278 STAT2=$(stat $SPDK_BIN_DIR/spdk_tgt) 279 280 if [ "$STAT1" == "$STAT2" ]; then 281 echo "Header dependency check failed" 282 false 283 fi 284} 285 286test_make_install() { 287 $MAKE $MAKEFLAGS install DESTDIR="$SPDK_WORKSPACE" prefix=/usr 288} 289 290test_make_uninstall() { 291 # Create empty file to check if it is not deleted by target uninstall 292 touch "$SPDK_WORKSPACE/usr/lib/sample_xyz.a" 293 $MAKE $MAKEFLAGS uninstall DESTDIR="$SPDK_WORKSPACE" prefix=/usr 294 if [[ $(find "$SPDK_WORKSPACE/usr" -maxdepth 1 -mindepth 1 | wc -l) -ne 2 ]] || [[ $(find "$SPDK_WORKSPACE/usr/lib/" -maxdepth 1 -mindepth 1 | wc -l) -ne 1 ]]; then 295 ls -lR "$SPDK_WORKSPACE" 296 echo "Make uninstall failed" 297 exit 1 298 fi 299} 300 301_build_doc() { 302 local doxygenv 303 doxygenv=$(doxygen --version) 304 305 $MAKE -C "$rootdir"/doc --no-print-directory $MAKEFLAGS &> "$out"/doxygen.log 306 if [ -s "$out"/doxygen.log ]; then 307 if [[ "$doxygenv" == "1.8.20" ]]; then 308 # Doxygen 1.8.20 produces false positives, see: 309 # https://github.com/doxygen/doxygen/issues/7948 310 grep -vE '\\ilinebr' 311 elif [[ "$doxygenv" == "1.9.5" ]]; then 312 # Doxygen 1.9.5 produces false positives, see: 313 # https://github.com/doxygen/doxygen/issues/9552 and 314 # https://github.com/doxygen/doxygen/issues/9678 315 grep -vE '\\ifile|@param' 316 fi < "$out/doxygen.log" && echo "Doxygen errors found!" && return 1 317 318 echo "Doxygen $doxygenv detected. No warnings except false positives, continuing the test" 319 fi 320 if hash pdflatex 2> /dev/null; then 321 $MAKE -C "$rootdir"/doc/output/latex --no-print-directory $MAKEFLAGS &>> "$out"/doxygen.log 322 fi 323 mkdir -p "$out"/doc 324 # Copy and remove files to avoid mv: failed to preserve ownership error 325 cp -r --preserve=mode "$rootdir"/doc/output/html "$out"/doc 326 rm -rf "$rootdir"/doc/output/html 327 if [ -f "$rootdir"/doc/output/latex/refman.pdf ]; then 328 mv "$rootdir"/doc/output/latex/refman.pdf "$out"/doc/spdk.pdf 329 fi 330 $MAKE -C "$rootdir"/doc --no-print-directory $MAKEFLAGS clean &>> "$out"/doxygen.log 331 if [ -s "$out"/doxygen.log ]; then 332 # Save the log as an artifact in case we are working with potentially broken version 333 eq "$doxygenv" 1.8.20 || rm "$out"/doxygen.log 334 fi 335 rm -rf "$rootdir"/doc/output 336} 337 338check_format() { 339 run_test "autobuild_check_format" "$rootdir/scripts/check_format.sh" 340} 341 342check_so_deps() { 343 run_test "autobuild_check_so_deps" "$rootdir/test/make/check_so_deps.sh" "$spdk_conf" 344} 345 346external_code() { 347 run_test "autobuild_external_code" "$rootdir/test/external_code/test_make.sh" "$rootdir" 348} 349 350dpdk_pci_api() { 351 run_test "autobuild_check_dpdk_pci_api" check_dpdk_pci_api 352} 353 354build_files() { 355 "$rootdir/configure" $config_params --without-shared 356 $MAKE $MAKEFLAGS 357 run_test "autobuild_generated_files_check" porcelain_check 358 run_test "autobuild_header_dependency_check" header_dependency_check 359 run_test "autobuild_make_install" test_make_install 360 run_test "autobuild_make_uninstall" test_make_uninstall 361} 362 363build_doc() { 364 "$rootdir/configure" $config_params --without-shared 365 run_test "autobuild_build_doc" _build_doc 366} 367 368autobuild_test_suite_tiny() { 369 check_format 370 check_so_deps 371 dpdk_pci_api 372} 373 374autobuild_test_suite_ext() { 375 external_code 376} 377 378autobuild_test_suite_full() { 379 autobuild_test_suite_tiny 380 autobuild_test_suite_ext 381 build_files 382 build_doc 383} 384 385_autobuild_test_suite() { 386 case "$SPDK_TEST_AUTOBUILD" in 387 tiny) autobuild_test_suite_tiny ;; 388 ext) autobuild_test_suite_ext ;; 389 full) autobuild_test_suite_full ;; 390 esac 391} 392 393_unittest_build() { 394 "$rootdir/configure" $config_params --without-shared 395 $MAKE $MAKEFLAGS 396} 397 398autobuild_test_suite() { 399 run_test "autobuild" _autobuild_test_suite 400} 401 402unittest_build() { 403 run_test "unittest_build" _unittest_build 404} 405 406scanbuild_make() { 407 run_test "scanbuild_make" _scanbuild_make 408} 409 410ocf_precompile() { 411 run_test "autobuild_ocf_precompile" _ocf_precompile 412} 413 414llvm_precompile() { 415 run_test "autobuild_llvm_precompile" _llvm_precompile 416} 417 418build_native_dpdk() { 419 run_test "build_native_dpdk" _build_native_dpdk 420} 421 422out=$output_dir 423SPDK_WORKSPACE=$(mktemp -dt "spdk_$(date +%s).XXXXXX") 424 425if [[ -n $EXTERNAL_MAKE_HUGEMEM ]]; then 426 export EXTERNAL_MAKE_HUGEMEM 427fi 428 429if [ -n "$SPDK_TEST_NATIVE_DPDK" ]; then 430 scanbuild_exclude=" --exclude $(dirname $SPDK_RUN_EXTERNAL_DPDK)" 431else 432 scanbuild_exclude="--exclude $rootdir/dpdk/" 433fi 434# We exclude /tmp as it's used by xnvme's liburing subproject for storing 435# temporary .c files which are picked up as buggy by the scanbuild. 436scanbuild_exclude+=" --exclude $rootdir/xnvme --exclude /tmp" 437 438scanbuild="scan-build -o $output_dir/scan-build-tmp $scanbuild_exclude --status-bugs" 439config_params=$(get_config_params) 440 441spdk_conf=${spdk_conf:-"$1"} 442 443if [[ ! -f $spdk_conf ]]; then 444 echo "ERROR: SPDK test configuration not specified" 445 return 1 446fi 447