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