xref: /spdk/configure (revision b4ba6cdf0ad14da86fe0ca1b53f6a3f7b09560de)
1#!/usr/bin/env bash
2#  SPDX-License-Identifier: BSD-3-Clause
3#  Copyright (C) 2017 Intel Corporation
4#  All rights reserved.
5#  Copyright (c) 2022 Dell Inc, or its subsidiaries.
6#
7
8set -e
9
10trap 'echo -e "\n\nConfiguration failed\n\n" >&2' ERR
11
12rootdir=$(readlink -f $(dirname $0))
13source "$rootdir/scripts/common.sh"
14
15function usage() {
16	echo "'configure' configures SPDK to compile on supported platforms."
17	echo ""
18	echo "Usage: ./configure [OPTION]..."
19	echo ""
20	echo "Defaults for the options are specified in brackets."
21	echo ""
22	echo "General:"
23	echo " -h, --help                Display this help and exit"
24	echo ""
25	echo " --prefix=path             Configure installation prefix (default: /usr/local)"
26	echo " --target-arch=arch        Target build architecture. Must be a valid GNU arch. Default: native"
27	echo ""
28	echo " --cross-prefix=prefix     Prefix for cross compilation (default: none)"
29	echo "                           example: aarch64-linux-gnu"
30	echo " --libdir=path             Configure installation path for the libraries (default: \$prefix/lib)"
31	echo " --max-lcores=VAL          DPDK configuration. VAL defines maximum number of lcores supported"
32	echo "                           by EAL, or enables autodetection if set to 'detect'. When 'detect'"
33	echo "                           is specified, DPDK will detect number of cores in the system during"
34	echo "                           compilation, and will set maximum number of lcores to this value"
35	echo " --enable-debug            Configure for debug builds"
36	echo " --enable-werror           Treat compiler warnings as errors"
37	echo " --enable-asan             Enable address sanitizer"
38	echo " --enable-ubsan            Enable undefined behavior sanitizer"
39	echo " --enable-coverage         Enable code coverage tracking"
40	echo " --enable-lto              Enable link-time optimization"
41	echo " --enable-pgo-capture[=PATH]      Enable generation of profile guided optimization data"
42	echo " --enable-pgo-use[=PATH]   Use previously captured profile guided optimization data"
43	echo " --enable-cet              Enable Intel Control-flow Enforcement Technology (CET)"
44	echo " --disable-tests           Disable building of functional tests"
45	echo " --disable-unit-tests      Disable building of unit tests"
46	echo " --disable-examples        Disable building of examples"
47	echo " --disable-apps            Disable building of apps"
48	echo ""
49	echo "Specifying Dependencies:"
50	echo "--with-DEPENDENCY[=path]   Use the given dependency. Optionally, provide the"
51	echo "                           path."
52	echo "--without-DEPENDENCY       Do not link to the given dependency. This may"
53	echo "                           disable features and components."
54	echo ""
55	echo "Valid dependencies are listed below."
56	echo " --with-dpdk[=DIR]         Build against a custom dpdk version. By default, the dpdk"
57	echo " --without-dpdk            submodule in spdk tree will be used."
58	echo "                           example: /usr/share/dpdk/x86_64-default-linuxapp-gcc"
59	echo " --with-env=DIR            Use an alternate environment implementation instead of DPDK."
60	echo "                           Implies --without-dpdk."
61	echo " --with-idxd               Build the IDXD library and accel framework plug-in module."
62	echo " --without-idxd            Disabled while experimental. Only built for x86 when enabled."
63	echo " --with-crypto             Build isa-l-crypto and vbdev crypto module. No path required."
64	echo " --without-crypto          Disable isa-l-crypto and vbdev crypto module."
65	echo " --with-fio[=DIR]          Build fio_plugin."
66	echo " --without-fio             default: /usr/src/fio"
67	echo " --with-xnvme              Build xNVMe bdev module."
68	echo " --without-xnvme           No path required."
69	echo " --with-vhost              Build vhost target. Enabled by default."
70	echo " --without-vhost           No path required."
71	echo " --with-virtio             Build vhost initiator and virtio-pci bdev modules."
72	echo " --without-virtio          No path required."
73	echo " --with-vfio-user[=DIR]    Build custom vfio-user transport for NVMf target and vfio-user target."
74	echo "                           vfio-user initiator is always built-in in Linux."
75	echo "                           example: /usr/src/libvfio-user"
76	echo " --without-vfio-user       No path required."
77	echo " --with-vbdev-compress     Build vbdev compression module and dependencies."
78	echo " --without-vbdev-compress  No path required."
79	echo " --with-dpdk-compressdev   Build accel DPDK compression module and dependencies."
80	echo " --without-dpdk-compressdev No path required."
81	echo " --with-rbd                Build Ceph RBD bdev module."
82	echo " --without-rbd             No path required."
83	echo " --with-ublk               Build ublk library."
84	echo " --without-ublk            No path required."
85	echo " --with-rdma[=DIR]         Build RDMA transport for NVMf target and initiator."
86	echo " --without-rdma            Accepts optional RDMA provider name. Can be \"verbs\" or \"mlx5_dv\"."
87	echo "                           If no provider specified, \"verbs\" provider is used by default."
88	echo " --with-fc[=DIR]           Build FC transport for NVMf target."
89	echo " --without-fc              If an argument is provided, it is considered a directory containing"
90	echo "                           libufc.a and fc_lld.h. Otherwise the regular system paths will"
91	echo "                           be searched."
92	echo " --with-daos[=DIR]         Build DAOS bdev module."
93	echo " --without-daos            No path required."
94	echo " --with-shared             Build spdk shared libraries."
95	echo " --without-shared          No path required."
96	echo " --with-iscsi-initiator    Build with iscsi bdev module."
97	echo " --without-iscsi-initiator No path required."
98	echo " --with-vtune=DIR          Required to profile I/O under Intel VTune Profiler."
99	echo "                           example: /opt/intel/oneapi/vtune/version"
100	echo " --without-vtune           Support for Intel VTune Profiler will not be provided."
101	echo " --with-ocf[=DIR]          Build OCF library and bdev module."
102	echo " --without-ocf             If argument is directory, interpret it as root of OCF repo"
103	echo "                           If argument is file, interpret it as compiled OCF lib"
104	echo "                           If no argument is specified, OCF git submodule is used by default"
105	echo "                           example: /usr/src/ocf/"
106	echo " --with-uring[=DIR]        Build I/O uring bdev or socket module."
107	echo " --without-uring           If an argument is provided, it is considered a directory containing"
108	echo "                           liburing.a and io_uring.h. Otherwise the regular system paths will"
109	echo "                           be searched."
110	echo " --without-uring-zns       Build I/O uring module without ZNS (zoned namespaces) support."
111	echo " --with-openssl[=DIR]      Build OPENSSL with custom path. Otherwise the regular system paths will"
112	echo "                           be searched."
113	echo " --with-fuse               Build FUSE components for mounting a blobfs filesystem."
114	echo " --without-fuse            No path required."
115	echo " --with-nvme-cuse          Build NVMe driver with support for CUSE-based character devices."
116	echo " --without-nvme-cuse       No path required."
117	echo " --with-raid5f             Build with bdev_raid module RAID5f support."
118	echo " --without-raid5f          No path required."
119	echo " --with-wpdk=DIR           Build using WPDK to provide support for Windows (experimental)."
120	echo " --without-wpdk            The argument must be a directory containing lib and include."
121	echo " --with-usdt               Build with userspace DTrace probes enabled."
122	echo " --without-usdt            No path required."
123	echo " --with-fuzzer             Build with LLVM fuzzing enabled."
124	echo "                           Path to clang_rt.fuzzer_no_main library required."
125	echo "                           Requires setting CC and CXX to clang."
126	echo "                           (Typically /usr/lib/llvm-VER/lib/clang/VER/lib/linux/libclang_rt.fuzzer_no_main-ARCH.a)"
127	echo " --with-sma                Generate Storage Management Agent's protobuf interface"
128	echo " --without-sma             No path required."
129	echo " --with-avahi              Build with Avahi mDNS discovery client service enabled in bdev-nvme module."
130	echo " --without-avahi           No path required."
131	echo " --with-golang             Build with components written in Go"
132	echo " --without-golang          No path required."
133	echo ""
134	echo "Environment variables:"
135	echo ""
136	echo "CC                         C compiler"
137	echo "CFLAGS                     C compiler flags"
138	echo "CXX                        C++ compiler"
139	echo "CXXFLAGS                   C++ compiler flags"
140	echo "LD                         Linker"
141	echo "LDFLAGS                    Linker flags"
142	echo "DESTDIR                    Destination for 'make install'"
143	echo ""
144}
145
146# Load default values
147# Convert config to sourceable configuration file
148sed -r 's/CONFIG_([[:alnum:]_]+)=(.*)/CONFIG[\1]=\2/g' $rootdir/CONFIG > $rootdir/CONFIG.sh
149declare -A CONFIG
150source $rootdir/CONFIG.sh
151rm $rootdir/CONFIG.sh
152
153# Try to expand literal ~ that might have been passed as an option via --long-opt=~/dir.
154set -- "${@//\~/~}"
155
156for i in "$@"; do
157	case "$i" in
158		--cross-prefix=*)
159			CONFIG[CROSS_PREFIX]="${i#*=}"
160			;;
161		--enable-lto)
162			CONFIG[LTO]=y
163			;;
164		--disable-lto)
165			CONFIG[LTO]=n
166			;;
167	esac
168done
169
170# Detect the compiler toolchain
171$rootdir/scripts/detect_cc.sh --cc="$CC" --cxx="$CXX" --lto="${CONFIG[LTO]}" --ld="$LD" --cross-prefix="${CONFIG[CROSS_PREFIX]}" > $rootdir/mk/cc.mk
172
173mapfile -t cc < <(grep "=" "$rootdir/mk/cc.mk")
174source <(printf '%q\n' "${cc[@]}")
175CC=$DEFAULT_CC
176
177arch=$($CC -dumpmachine)
178sys_name=$(uname -s)
179
180if [[ $arch == *mingw* ]] || [[ $arch == *windows* ]]; then
181	sys_name=Windows
182fi
183
184if [[ $sys_name != "Linux" ]]; then
185	# Vhost, rte_vhost library and virtio are only supported on Linux.
186	CONFIG[VHOST]="n"
187	CONFIG[VIRTIO]="n"
188	CONFIG[NVME_CUSE]="n"
189	echo "Notice: Vhost, rte_vhost library, virtio, and fuse"
190	echo "are only supported on Linux. Turning off default feature."
191fi
192
193function check_dir() {
194	arg="$1"
195	dir="${arg#*=}"
196	if [ ! -d "$dir" ]; then
197		echo "$arg: directory not found"
198		exit 1
199	fi
200}
201
202# On x86_64 'clang -dumpmachine' produces x86_64-pc-linux-gnu
203# whereas the dpdk might be built with gcc and its libs lie in
204# x86_64-linux-gnu. Let's find the right libdir for dpdk libs.
205function find_dpdk_arch_libdir() {
206	local dpdk_libdir="$1/lib"
207
208	# Use libdir with 'lib' or 'lib64'
209	if [[ ! -d "$dpdk_libdir" ]]; then
210		dpdk_libdir+="64"
211	fi
212
213	# Checking first what we have with $arch, then clang
214	# variant of arch.
215	arches=("$arch" "$(echo $arch | sed 's/-pc//g')")
216	for a in "${arches[@]}"; do
217		local libdir_arch="$dpdk_libdir/$a"
218		if [[ -d "$libdir_arch" ]]; then
219			echo "$libdir_arch"
220			return
221		fi
222	done
223
224	# Fallback to the libdir without arch component
225	echo "$dpdk_libdir"
226}
227
228function check_IPSec_mb() {
229	local mode=$1
230	local dpdk_libdir=$2
231	local dpdk_incdir=$3
232	local have_ipsec_mb=n
233
234	if [[ $mode = "pkg-config" ]]; then
235		local dpdk_libs
236
237		# Request libdpdk pkg-config settings to figure out if the IPSec_MB is used
238		# as a dependency.
239		# Due to some reason pkg-config shows -lIPSec_MB only with --static option
240		dpdk_libs=$(PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$dpdk_libdir/pkgconfig" pkg-config --libs --static libdpdk)
241		if echo "$dpdk_libs" | grep "\-lIPSec_MB" > /dev/null 2>&1; then
242			have_ipsec_mb=y
243		fi
244	elif [[ $mode = "build-config" ]]; then
245		# Use dpdk build config header to check if the IPSec_MB was used.
246		if grep -F "define RTE_CRYPTO_IPSEC_MB 1" "$dpdk_incdir/rte_build_config.h" > /dev/null 2>&1; then
247			have_ipsec_mb=y
248		fi
249	else
250		echo "ERROR: Invalid IPSec_MB checking mode $mode."
251		echo "ERROR: Only \"pkg-config\" and \"build-config\" available."
252		exit 1
253	fi
254	if [[ $have_ipsec_mb = "n" ]]; then
255		CONFIG[IPSEC_MB]=n
256		return
257	fi
258
259	# Since we don't know the library path where the IPSec_MB is located
260	# let's find it out with the ldd utility. This can be a standard location
261	# or a custom build.
262	local librte_crypto_ipsec_mb="$dpdk_libdir/librte_crypto_ipsec_mb.so"
263	if [[ -f "$librte_crypto_ipsec_mb" ]]; then
264		local ipsec_mb_libdir
265
266		ipsec_mb_libdir=$(ldd "$librte_crypto_ipsec_mb" | grep "libIPSec_MB.so" \
267			| sed -e 's/\s*libIPSec_MB.so.*=>\s//' -e 's/\/libIPSec_MB.so.*$//')
268		if [[ -d $ipsec_mb_libdir ]]; then
269			CONFIG[IPSEC_MB]=y
270			CONFIG[IPSEC_MB_DIR]="$ipsec_mb_libdir"
271		elif [[ $ipsec_mb_libdir = "not found" ]]; then
272			# ldconfig cache is broken, old build with refs to non-existing libs, etc.
273			echo "ERROR: Invalid IPSec_MB installation. Library is not found and/or ldconfig cache is broken!"
274			exit 1
275		else
276			# Failed to check for IPSec_MB lib path. Let's just assume it is lives
277			# in one of the standard locations (/usr/lib, etc.).
278			CONFIG[IPSEC_MB]=y
279		fi
280	else
281		# pkg-config says there is IPSec_mb and dpdk lib does not have it. Let's just
282		# assume it is installed in the system in one of the standard locations.
283		CONFIG[IPSEC_MB]=y
284	fi
285}
286
287for i in "$@"; do
288	case "$i" in
289		-h | --help)
290			usage
291			exit 0
292			;;
293		--cross-prefix=*) ;&
294		--enable-lto) ;&
295		--disable-lto)
296			# Options handled before detecting CC.
297			;;
298		--prefix=*)
299			CONFIG[PREFIX]="${i#*=}"
300			;;
301		--target-arch=*)
302			CONFIG[ARCH]="${i#*=}"
303			;;
304		--libdir=*)
305			CONFIG[LIBDIR]="${i#*=}"
306			;;
307		--enable-debug)
308			CONFIG[DEBUG]=y
309			;;
310		--disable-debug)
311			CONFIG[DEBUG]=n
312			;;
313		--enable-asan)
314			CONFIG[ASAN]=y
315			;;
316		--disable-asan)
317			CONFIG[ASAN]=n
318			;;
319		--enable-ubsan)
320			CONFIG[UBSAN]=y
321			;;
322		--disable-ubsan)
323			CONFIG[UBSAN]=n
324			;;
325		--enable-tsan)
326			CONFIG[TSAN]=y
327			;;
328		--disable-tsan)
329			CONFIG[TSAN]=n
330			;;
331		--enable-coverage)
332			CONFIG[COVERAGE]=y
333			;;
334		--disable-coverage)
335			CONFIG[COVERAGE]=n
336			;;
337		--enable-pgo-capture)
338			CONFIG[PGO_CAPTURE]=y
339			;;
340		--enable-pgo-capture=*)
341			CONFIG[PGO_CAPTURE]=y
342			CONFIG[PGO_DIR]="${i#*=}"
343			;;
344		--disable-pgo-capture)
345			CONFIG[PGO_CAPTURE]=n
346			;;
347		--enable-pgo-use)
348			CONFIG[PGO_USE]=y
349			;;
350		--enable-pgo-use=*)
351			CONFIG[PGO_USE]=y
352			CONFIG[PGO_DIR]="${i#*=}"
353			;;
354		--disable-pgo-use)
355			CONFIG[PGO_USE]=n
356			;;
357		--enable-tests)
358			CONFIG[TESTS]=y
359			;;
360		--disable-tests)
361			CONFIG[TESTS]=n
362			;;
363		--enable-unit-tests)
364			CONFIG[UNIT_TESTS]=y
365			;;
366		--disable-unit-tests)
367			CONFIG[UNIT_TESTS]=n
368			;;
369		--enable-examples)
370			CONFIG[EXAMPLES]=y
371			;;
372		--disable-examples)
373			CONFIG[EXAMPLES]=n
374			;;
375		--enable-apps)
376			CONFIG[APPS]=y
377			;;
378		--disable-apps)
379			CONFIG[APPS]=N
380			;;
381		--enable-werror)
382			CONFIG[WERROR]=y
383			;;
384		--disable-werror)
385			CONFIG[WERROR]=n
386			;;
387		--enable-cet)
388			CONFIG[CET]=y
389			;;
390		--disable-cet)
391			CONFIG[CET]=n
392			;;
393		--with-dpdk)
394			# Can we use pkg-config?
395			if command -v "pkg-config" > /dev/null 2>&1 && pkg-config --exists libdpdk; then
396				dpdk_libdir=$(pkg-config --variable=libdir libdpdk)
397				dpdk_libdir=$(readlink -f $dpdk_libdir)
398				dpdk_incdir=$(pkg-config --variable=includedir libdpdk)
399				echo "Using DPDK lib dir $dpdk_libdir"
400				CONFIG[DPDK_LIB_DIR]=$dpdk_libdir
401				CONFIG[DPDK_INC_DIR]=$dpdk_incdir
402				CONFIG[DPDK_PKG_CONFIG]=y
403				CFLAGS="${CFLAGS:+$CFLAGS }$(pkg-config --cflags libdpdk)"
404				check_IPSec_mb "pkg-config" "$dpdk_libdir" "$dpdk_incdir"
405			else
406				echo "libdpdk.pc not found, aborting"
407				exit 1
408			fi
409			;;
410		--with-dpdk=*)
411			check_dir "$i"
412			dpdk_dir=$(readlink -f ${i#*=})
413			dpdk_libdir=$(find_dpdk_arch_libdir $dpdk_dir)
414			dpdk_incdir="$dpdk_dir/include"
415
416			# Can we use pkg-config?
417			if command -v "pkg-config" > /dev/null 2>&1 && PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$dpdk_libdir/pkgconfig" pkg-config --exists libdpdk; then
418				echo "Using $dpdk_libdir/pkgconfig for additional libs..."
419				sysroot_dir=$(PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$dpdk_libdir/pkgconfig" pkg-config --variable=pc_sysrootdir libdpdk)
420				dpdk_libdir=$(PKG_CONFIG_SYSROOT_DIR='' PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$dpdk_libdir/pkgconfig" pkg-config --variable=libdir libdpdk)
421				dpdk_libdir=$(readlink -f "${sysroot_dir}$dpdk_libdir")
422				if ! echo $dpdk_libdir | grep $dpdk_dir > /dev/null 2>&1; then
423					echo "ERROR: pkg-config reported DPDK libdir $dpdk_libdir is out of the directory specified with --with-dpdk="
424					echo "ERROR: do you have another DPDK installed in the system?"
425					exit 1
426				fi
427				CFLAGS="${CFLAGS:+$CFLAGS }$(PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$dpdk_libdir/pkgconfig" pkg-config --cflags libdpdk)"
428				dpdk_incdir="${sysroot_dir}$(PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$dpdk_libdir/pkgconfig" pkg-config --variable=includedir libdpdk)"
429				check_IPSec_mb "pkg-config" "$dpdk_libdir" "$dpdk_incdir"
430			else
431				echo "Using $dpdk_incdir/rte_build_config.h for additional libs..."
432
433				check_IPSec_mb "build-config" "$dpdk_libdir" "$dpdk_incdir"
434			fi
435			echo "DPDK libraries: $dpdk_libdir"
436			echo "DPDK includes: $dpdk_incdir"
437			CONFIG[DPDK_DIR]=$dpdk_dir
438			CONFIG[DPDK_LIB_DIR]="$dpdk_libdir"
439			CONFIG[DPDK_INC_DIR]="$dpdk_incdir"
440			CONFIG[DPDK_PKG_CONFIG]=n
441			;;
442		--without-dpdk)
443			CONFIG[DPDK_DIR]=
444			;;
445		--with-wpdk=*)
446			check_dir "$i"
447			CONFIG[WPDK_DIR]=$(readlink -f ${i#*=})
448			;;
449		--without-wpdk)
450			CONFIG[WPDK_DIR]=
451			;;
452		--with-env=*)
453			CONFIG[ENV]="${i#*=}"
454			;;
455		--with-ublk)
456			CONFIG[UBLK]=y
457			;;
458		--without-ublk)
459			CONFIG[UBLK]=n
460			;;
461		--with-rbd)
462			CONFIG[RBD]=y
463			;;
464		--without-rbd)
465			CONFIG[RBD]=n
466			;;
467		--with-rdma=*)
468			CONFIG[RDMA]=y
469			CONFIG[RDMA_PROV]=${i#*=}
470			;;
471		--with-rdma)
472			CONFIG[RDMA]=y
473			CONFIG[RDMA_PROV]="verbs"
474			;;
475		--without-rdma)
476			CONFIG[RDMA]=n
477			;;
478		--with-fc=*)
479			CONFIG[FC]=y
480			CONFIG[FC_PATH]=$(readlink -f ${i#*=})
481			;;
482		--with-fc)
483			CONFIG[FC]=y
484			CONFIG[FC_PATH]=
485			;;
486		--without-fc)
487			CONFIG[FC]=n
488			CONFIG[FC_PATH]=
489			;;
490		--with-daos)
491			CONFIG[DAOS]=y
492			CONFIG[DAOS_DIR]=""
493			;;
494		--with-daos=*)
495			CONFIG[DAOS]=y
496			check_dir "$i"
497			CONFIG[DAOS_DIR]=$(readlink -f ${i#*=})
498			;;
499		--without-daos)
500			CONFIG[DAOS]=n
501			;;
502		--with-shared)
503			CONFIG[SHARED]=y
504			;;
505		--without-shared)
506			CONFIG[SHARED]=n
507			;;
508		--with-iscsi-initiator)
509			CONFIG[ISCSI_INITIATOR]=y
510			;;
511		--without-iscsi-initiator)
512			CONFIG[ISCSI_INITIATOR]=n
513			;;
514		--with-crypto)
515			CONFIG[CRYPTO]=y
516			;;
517		--without-crypto)
518			CONFIG[CRYPTO]=n
519			;;
520		--with-vhost)
521			CONFIG[VHOST]=y
522			;;
523		--without-vhost)
524			CONFIG[VHOST]=n
525			;;
526		--with-virtio)
527			CONFIG[VIRTIO]=y
528			;;
529		--without-virtio)
530			CONFIG[VIRTIO]=n
531			;;
532		--with-vfio-user)
533			CONFIG[VFIO_USER]=y
534			CONFIG[VFIO_USER_DIR]=""
535			;;
536		--with-vfio-user=*)
537			CONFIG[VFIO_USER]=y
538			check_dir "$i"
539			CONFIG[VFIO_USER_DIR]=$(readlink -f ${i#*=})
540			;;
541		--without-vfio-user)
542			CONFIG[VFIO_USER]=n
543			;;
544		--with-vbdev-compress)
545			CONFIG[VBDEV_COMPRESS]=y
546			;;
547		--without-vbdev-compress)
548			CONFIG[VBDEV_COMPRESS]=n
549			;;
550		--with-dpdk-compressdev)
551			CONFIG[DPDK_COMPRESSDEV]=y
552			;;
553		--without-dpdk-compressdev)
554			CONFIG[DPDK_COMPRESSDEV]=n
555			;;
556		--with-xnvme)
557			CONFIG[XNVME]=y
558			;;
559		--without-xnvme)
560			CONFIG[XNVME]=n
561			;;
562		--with-fio) ;&
563		--with-fio=*)
564			if [[ ${i#*=} != "$i" ]]; then
565				CONFIG[FIO_SOURCE_DIR]=${i#*=}
566			fi
567			check_dir "--with-fio=${CONFIG[FIO_SOURCE_DIR]}"
568			CONFIG[FIO_SOURCE_DIR]=$(readlink -f "${CONFIG[FIO_SOURCE_DIR]}")
569			CONFIG[FIO_PLUGIN]=y
570			;;
571		--without-fio)
572			CONFIG[FIO_PLUGIN]=n
573			;;
574		--with-vtune=*)
575			check_dir "$i"
576			CONFIG[VTUNE_DIR]="${i#*=}"
577			CONFIG[VTUNE]=y
578			;;
579		--without-vtune)
580			CONFIG[VTUNE_DIR]=
581			CONFIG[VTUNE]=n
582			;;
583		--with-ocf)
584			CONFIG[OCF]=y
585			CONFIG[OCF_PATH]=$(readlink -f "$rootdir/ocf")
586			;;
587		--with-ocf=*)
588			CONFIG[OCF]=y
589			CONFIG[OCF_PATH]=$(readlink -f ${i#*=})
590			;;
591		--without-ocf)
592			CONFIG[OCF]=n
593			CONFIG[OCF_PATH]=
594			;;
595		--with-uring=*)
596			CONFIG[URING]=y
597			CONFIG[URING_PATH]=$(readlink -f ${i#*=})
598			;;
599		--with-uring)
600			CONFIG[URING]=y
601			CONFIG[URING_ZNS]=y
602			CONFIG[URING_PATH]=
603			;;
604		--without-uring)
605			CONFIG[URING]=n
606			CONFIG[URING_PATH]=
607			;;
608		--without-uring-zns)
609			CONFIG[URING_ZNS]=n
610			;;
611		--with-openssl=*)
612			check_dir "$i"
613			CONFIG[OPENSSL_PATH]=$(readlink -f ${i#*=})
614			;;
615		--with-fuse)
616			CONFIG[FUSE]=y
617			;;
618		--without-fuse)
619			CONFIG[FUSE]=n
620			;;
621		--with-nvme-cuse)
622			CONFIG[NVME_CUSE]=y
623			;;
624		--without-nvme-cuse)
625			CONFIG[NVME_CUSE]=n
626			;;
627		--with-raid5f)
628			CONFIG[RAID5F]=y
629			;;
630		--without-raid5f)
631			CONFIG[RAID5F]=n
632			;;
633		--with-idxd)
634			CONFIG[IDXD]=y
635			CONFIG[IDXD_KERNEL]=n
636			;;
637		--without-idxd)
638			CONFIG[IDXD]=n
639			;;
640		--with-usdt)
641			CONFIG[USDT]=y
642			;;
643		--without-usdt)
644			CONFIG[USDT]=n
645			;;
646		--with-fuzzer)
647			echo "Must specify fuzzer library path with --with-fuzzer"
648			usage
649			exit 1
650			;;
651		--with-fuzzer=*)
652			CONFIG[FUZZER]=y
653			CONFIG[FUZZER_LIB]=$(readlink -f ${i#*=})
654			;;
655		--without-fuzzer)
656			CONFIG[FUZZER]=n
657			CONFIG[FUZZER_LIB]=
658			;;
659		--with-sma)
660			CONFIG[SMA]=y
661			;;
662		--without-sma)
663			CONFIG[SMA]=n
664			;;
665		--with-avahi)
666			CONFIG[AVAHI]=y
667			;;
668		--without-avahi)
669			CONFIG[AVAHI]=n
670			;;
671		--with-golang)
672			CONFIG[GOLANG]=y
673			;;
674		--without-golang)
675			CONFIG[GOLANG]=n
676			;;
677		--max-lcores='')
678			echo "Must specify max number of lcores for --max-lcores"
679			usage
680			exit 1
681			;;
682		--max-lcores=*)
683			CONFIG[MAX_LCORES]="${i#*=}"
684			CONFIG["MAX_LCORES"]=${CONFIG["MAX_LCORES"],,}
685			;;
686		--)
687			break
688			;;
689		*)
690			echo "Unrecognized option $i"
691			usage
692			exit 1
693			;;
694	esac
695done
696
697if [[ $arch == x86_64* ]]; then
698	BUILD_CMD=($CC -o /dev/null -x c $CPPFLAGS $CFLAGS $LDFLAGS "-march=native")
699else
700	BUILD_CMD=($CC -o /dev/null -x c $CPPFLAGS $CFLAGS $LDFLAGS)
701fi
702BUILD_CMD+=(-I/usr/local/include -L/usr/local/lib)
703BUILD_CMD+=("-fuse-ld=$LD_TYPE")
704
705if [[ "${CONFIG[VFIO_USER]}" = "y" ]]; then
706	if ! echo -e '#include <json-c/json.h>' \
707		| "${BUILD_CMD[@]}" -E - 2> /dev/null; then
708		echo "ERROR: --with-vfio-user requires json-c-devel"
709		echo "Please install then re-run this script"
710		exit 1
711	fi
712	if ! echo -e '#include <cmocka.h>' \
713		| "${BUILD_CMD[@]}" -E - 2> /dev/null; then
714		echo "ERROR: --with-vfio-user requires libcmocka-devel"
715		echo "Please install then re-run this script"
716		exit 1
717	fi
718fi
719
720# IDXD uses Intel specific instructions.
721if [[ "${CONFIG[IDXD]}" = "y" ]]; then
722	if [ $(uname -s) == "FreeBSD" ]; then
723		intel="hw.model: Intel"
724		cpu_vendor=$(sysctl -a | grep hw.model | cut -c 1-15)
725	else
726		intel="GenuineIntel"
727		cpu_vendor=$(grep -i 'vendor' /proc/cpuinfo --max-count=1)
728	fi
729	if [[ "$cpu_vendor" != *"$intel"* ]]; then
730		echo "ERROR: IDXD cannot be used due to CPU incompatibility."
731		exit 1
732	fi
733	if [ -e /usr/include/accel-config/libaccel_config.h ]; then
734		CONFIG[IDXD_KERNEL]=y
735	fi
736
737fi
738
739if [ -z "${CONFIG[ENV]}" ]; then
740	CONFIG[ENV]=$rootdir/lib/env_dpdk
741	echo "Using default SPDK env in ${CONFIG[ENV]}"
742	if [[ -z "${CONFIG[DPDK_DIR]}" && "${CONFIG[DPDK_PKG_CONFIG]}" == n ]]; then
743		if [ ! -f "$rootdir"/dpdk/config/meson.build ]; then
744			echo "DPDK not found; please specify --with-dpdk=<path> or run:"
745			echo
746			echo "  git submodule update --init"
747			exit 1
748		else
749			CONFIG[DPDK_DIR]="${rootdir}/dpdk/build"
750			# Default ipsec libs
751			if [[ "${CONFIG[CRYPTO]}" = "y" ]] && [[ $arch = x86_64* ]]; then
752				CONFIG[IPSEC_MB]=y
753				CONFIG[IPSEC_MB_DIR]="${rootdir}/intel-ipsec-mb/lib"
754			fi
755			echo "Using default DPDK in ${CONFIG[DPDK_DIR]}"
756		fi
757	fi
758else
759	if [[ -n "${CONFIG[DPDK_DIR]}" || "${CONFIG[DPDK_PKG_CONFIG]}" == y ]]; then
760		echo "--with-env and --with-dpdk are mutually exclusive."
761		exit 1
762	fi
763
764	if [ "${CONFIG[VHOST]}" = "y" ]; then
765		echo "Vhost is only supported when using the default DPDK environment. Disabling it."
766	fi
767	# Always disable vhost, but only print the error message if the user explicitly turned it on.
768	CONFIG[VHOST]="n"
769	if [ "${CONFIG[VIRTIO]}" = "y" ]; then
770		echo "Virtio is only supported when using the default DPDK environment. Disabling it."
771	fi
772	# Always disable virtio, but only print the error message if the user explicitly turned it on.
773	CONFIG[VIRTIO]="n"
774fi
775
776if [[ "${CONFIG[DPDK_PKG_CONFIG]}" == y ]]; then
777	if [[ "${CONFIG[SHARED]}" == n ]]; then
778		# dpdk-devel doesn't provide static libs
779		echo "Build against packaged DPDK requested, enabling shared libraries"
780		CONFIG[SHARED]=y
781	fi
782fi
783
784if [[ $sys_name == "Windows" ]]; then
785	if [ -z "${CONFIG[WPDK_DIR]}" ]; then
786		if [ ! -f "$rootdir"/wpdk/Makefile ]; then
787			echo "WPDK not found; please specify --with-wpdk=<path>. See https://wpdk.github.io."
788			exit 1
789		else
790			CONFIG[WPDK_DIR]="${rootdir}/wpdk/build"
791			echo "Using default WPDK in ${CONFIG[WPDK_DIR]}"
792		fi
793	fi
794else
795	if [ -n "${CONFIG[WPDK_DIR]}" ]; then
796		echo "ERROR: --with-wpdk is only supported for Windows"
797		exit 1
798	fi
799fi
800
801if [ "${CONFIG[VTUNE]}" = "y" ]; then
802	if [ -z "${CONFIG[VTUNE_DIR]}" ]; then
803		echo "When VTune is enabled, you must specify the VTune directory using --with-vtune=path"
804		exit 1
805	fi
806fi
807
808if [[ "${CONFIG[ASAN]}" = "y" && "${CONFIG[TSAN]}" = "y" ]]; then
809	echo "ERROR: ASAN and TSAN cannot be enabled at the same time."
810	exit 1
811fi
812
813if [[ "${CONFIG[FIO_PLUGIN]}" = "y" && "${CONFIG[EXAMPLES]}" = "n" ]]; then
814	echo "ERROR: --with-fio and --disable-examples are mutually exclusive."
815	exit 1
816fi
817
818if [[ $sys_name == "FreeBSD" ]]; then
819	# FreeBSD doesn't support all configurations
820	if [[ "${CONFIG[COVERAGE]}" == "y" ]]; then
821		echo "ERROR: CONFIG_COVERAGE not available on FreeBSD"
822		exit 1
823	fi
824fi
825
826if [[ $sys_name == "Linux" ]]; then
827	if pkg-config libbsd; then
828		CONFIG[HAVE_LIBBSD]=y
829	fi
830fi
831
832if pkg-config libarchive; then
833	CONFIG[HAVE_LIBARCHIVE]=y
834fi
835
836if [[ $sys_name != "Linux" ]]; then
837	if [[ "${CONFIG[VHOST]}" == "y" ]]; then
838		echo "Vhost is only supported on Linux."
839		exit 1
840	fi
841	if [[ "${CONFIG[VIRTIO]}" == "y" ]]; then
842		echo "Virtio is only supported on Linux."
843		exit 1
844	fi
845fi
846
847if [ "${CONFIG[RDMA]}" = "y" ]; then
848	if [[ ! "${CONFIG[RDMA_PROV]}" == "verbs" ]] && [[ ! "${CONFIG[RDMA_PROV]}" == "mlx5_dv" ]]; then
849		echo "Invalid RDMA provider specified, must be \"verbs\" or \"mlx5_dv\""
850		exit 1
851	fi
852
853	if ! echo -e '#include <infiniband/verbs.h>\n#include <rdma/rdma_verbs.h>\n' \
854		'int main(void) { return 0; }\n' \
855		| "${BUILD_CMD[@]}" -libverbs -lrdmacm - 2> /dev/null; then
856		echo "--with-rdma requires libverbs and librdmacm."
857		echo "Please install then re-run this script."
858		exit 1
859	fi
860
861	if echo -e '#include <infiniband/verbs.h>\n' \
862		'int main(void) { return !!IBV_WR_SEND_WITH_INV; }\n' \
863		| "${BUILD_CMD[@]}" -c - 2> /dev/null; then
864		CONFIG[RDMA_SEND_WITH_INVAL]="y"
865	else
866		CONFIG[RDMA_SEND_WITH_INVAL]="n"
867		echo "
868*******************************************************************************
869WARNING: The Infiniband Verbs opcode Send With Invalidate is either not
870supported or is not functional with the current version of libibverbs installed
871on this system. Please upgrade to at least version 1.1.
872
873Beginning with Linux kernel 4.14, the kernel NVMe-oF initiator leverages Send
874With Invalidate RDMA operations to improve performance. Failing to use the
875Send With Invalidate operation on the NVMe-oF target side results in full
876functionality, but greatly reduced performance. The SPDK NVMe-oF target will
877be unable to leverage that operation using the currently installed version
878of libibverbs, so Linux kernel NVMe-oF initiators based on kernels greater
879than or equal to 4.14 will see significantly reduced performance.
880*******************************************************************************"
881	fi
882
883	if echo -e '#include <rdma/rdma_cma.h>\n' \
884		'int main(void) { return !!RDMA_OPTION_ID_ACK_TIMEOUT; }\n' \
885		| "${BUILD_CMD[@]}" -c - 2> /dev/null; then
886		CONFIG[RDMA_SET_ACK_TIMEOUT]="y"
887	else
888		CONFIG[RDMA_SET_ACK_TIMEOUT]="n"
889		echo "RDMA_OPTION_ID_ACK_TIMEOUT is not supported"
890	fi
891
892	if echo -e '#include <rdma/rdma_cma.h>\n' \
893		'int main(void) { return !!RDMA_OPTION_ID_TOS; }\n' \
894		| "${BUILD_CMD[@]}" -c - 2> /dev/null; then
895		CONFIG[RDMA_SET_TOS]="y"
896	else
897		CONFIG[RDMA_SET_TOS]="n"
898		echo "RDMA_OPTION_ID_TOS is not supported"
899	fi
900
901	if [ "${CONFIG[RDMA_PROV]}" == "mlx5_dv" ]; then
902		MLX5_DV_BUILD_BUILD_CMD="
903		#include <infiniband/mlx5dv.h>\n
904		#include <rdma/rdma_cma.h>\n
905		int main(void) { return rdma_establish(NULL) ||\n
906		!!IBV_QP_INIT_ATTR_SEND_OPS_FLAGS || !!MLX5_OPCODE_RDMA_WRITE"
907		if [ "${CONFIG[CRYPTO]}" = "y" ]; then
908			MLX5_DV_BUILD_BUILD_CMD+="|| !!MLX5DV_CRYPTO_ENGINES_CAP_AES_XTS_SINGLE_BLOCK"
909		fi
910		MLX5_DV_BUILD_BUILD_CMD+=";}"
911		if ! echo -e $MLX5_DV_BUILD_BUILD_CMD | "${BUILD_CMD[@]}" -lmlx5 -I${rootdir}/include -c -; then
912			echo "mlx5_dv provider is not supported"
913			exit 1
914		fi
915	fi
916
917	echo "Using '${CONFIG[RDMA_PROV]}' RDMA provider"
918fi
919
920if [[ "${CONFIG[FC]}" = "y" ]]; then
921	if [[ -n "${CONFIG[FC_PATH]}" ]]; then
922		check_dir "${CONFIG[FC_PATH]}"
923	fi
924fi
925
926function dpdk_version() {
927	# Check DPDK version to determine if mlx5_pci driver is supported
928	local dpdk_ver="none"
929	if [[ "${CONFIG[DPDK_DIR]}" == "$rootdir/dpdk/build" ]]; then
930		# DPDK_DIR points at our submodule so ./build may not exist yet. Use
931		# absolute path to lookup the version.
932		dpdk_ver=$(< "$rootdir/dpdk/VERSION")
933	elif [[ -f "${CONFIG[DPDK_DIR]}"/../VERSION ]]; then
934		dpdk_ver=$(< "${CONFIG[DPDK_DIR]}"/../VERSION)
935	fi
936	echo $dpdk_ver
937}
938
939function mlx5_build() {
940	# Check if libmlx5 exists to enable mlx5_pci compress/crypto PMD
941	if ! echo -e '#include <spdk/stdinc.h>\n' \
942		'#include <infiniband/mlx5dv.h>\n' \
943		'#include <infiniband/verbs.h>\n' \
944		'int main(void) { return 0; }\n' \
945		| "${BUILD_CMD[@]}" -lmlx5 -libverbs -I${rootdir}/include -c - 2> /dev/null; then
946		return 1
947	fi
948	return 0
949}
950
951if [[ "${CONFIG[VBDEV_COMPRESS]}" = "y" ]]; then
952	if ! echo -e '#include <libpmem.h>\nint main(void) { return 0; }\n' \
953		| "${BUILD_CMD[@]}" -lpmem - 2> /dev/null; then
954		echo "--with-vbdev-compress requires libpmem."
955		echo "Please install then re-run this script."
956		exit 1
957	fi
958	# Try to enable mlx5 compress
959	CONFIG[VBDEV_COMPRESS_MLX5]="y"
960
961	# Check if libmlx5 exists to enable mlx5_pci compress PMD
962	if ! mlx5_build; then
963		echo "libmlx5 is not found, so disabling DPDK mlx5_pci compress PMD"
964		CONFIG[VBDEV_COMPRESS_MLX5]="n"
965	else
966		if [[ "${CONFIG[DPDK_PKG_CONFIG]}" = "y" ]]; then
967			# Check if librte_compress_mlx5 exists in DPDK package
968			if [ ! -f "${CONFIG[DPDK_LIB_DIR]}"/librte_compress_mlx5.so ]; then
969				echo "librte_compress_mlx5 is not found, so disabling DPDK mlx5_pci compress PMD"
970				CONFIG[VBDEV_COMPRESS_MLX5]="n"
971			fi
972		else
973			# Check DPDK version to determine if mlx5_pci driver is supported
974			dpdk_ver=$(dpdk_version)
975			if [[ $dpdk_ver = "none" ]]; then
976				echo "Cannot get DPDK version, so disabling DPDK mlx5_pci compress PMD"
977				CONFIG[VBDEV_COMPRESS_MLX5]="n"
978			elif [[ -n $dpdk_ver ]] && lt "$dpdk_ver" 21.02.0; then
979				# mlx5_pci for compress is supported by DPDK >- 21.02.0
980				echo "DPDK version ${dpdk_ver} doesn't support mlx5_pci compress PMD"
981				CONFIG[VBDEV_COMPRESS_MLX5]="n"
982			elif [[ -n ${CONFIG[DPDK_LIB_DIR]} ]] && [ ! -f "${CONFIG[DPDK_LIB_DIR]}"/librte_compress_mlx5.so ]; then
983				# This is only checked when --with-dpdk or --with-dpdk=* is used
984				echo "librte_compress_mlx5 is not found, so disabling DPDK mlx5_pci compress PMD"
985				CONFIG[VBDEV_COMPRESS_MLX5]="n"
986			fi
987		fi
988	fi
989fi
990
991if [[ "${CONFIG[CRYPTO]}" = "y" ]]; then
992	# Try to enable mlx5 crypto
993	CONFIG[CRYPTO_MLX5]="y"
994
995	# Check if libmlx5 exists to enable mlx5_pci compress PMD
996	if ! mlx5_build; then
997		echo "libmlx5 is not found, so disabling DPDK mlx5_pci crypto PMD"
998		CONFIG[CRYPTO_MLX5]="n"
999	else
1000		if [[ "${CONFIG[DPDK_PKG_CONFIG]}" = "y" ]]; then
1001			# Check if librte_crypto_mlx5 exists in DPDK package
1002			if [ ! -f "${CONFIG[DPDK_LIB_DIR]}"/librte_crypto_mlx5.so ]; then
1003				echo "librte_crypto_mlx5 is not found, so disabling DPDK mlx5_pci crypto PMD"
1004				CONFIG[CRYPTO_MLX5]="n"
1005			fi
1006		else
1007			# Check DPDK version to determine if mlx5_pci driver is supported
1008			dpdk_ver=$(dpdk_version)
1009			if [[ $dpdk_ver = "none" ]]; then
1010				echo "Cannot get DPDK version, so disabling DPDK mlx5_pci crypto PMD"
1011				CONFIG[CRYPTO_MLX5]="n"
1012			elif [[ -n $dpdk_ver ]] && lt "$dpdk_ver" 21.11.0; then
1013				# mlx5_pci for crypto is supported by DPDK >- 21.11.0
1014				echo "DPDK version ${dpdk_ver} doesn't support mlx5_pci crypto PMD"
1015				CONFIG[CRYPTO_MLX5]="n"
1016			elif [[ -n ${CONFIG[DPDK_LIB_DIR]} ]] && [ ! -f "${CONFIG[DPDK_LIB_DIR]}"/librte_crypto_mlx5.so ]; then
1017				# This is only checked when --with-dpdk or --with-dpdk=* is used
1018				echo "librte_crypto_mlx5 is not found, so disabling DPDK mlx5_pci crypto PMD"
1019				CONFIG[CRYPTO_MLX5]="n"
1020			fi
1021		fi
1022	fi
1023fi
1024
1025if [[ "${CONFIG[NVME_CUSE]}" = "y" ]]; then
1026	if ! echo -e '#define FUSE_USE_VERSION 31\n#include <fuse3/cuse_lowlevel.h>\n#include <fuse3/fuse_lowlevel.h>\n#include <fuse3/fuse_opt.h>\nint main(void) { return 0; }\n' \
1027		| "${BUILD_CMD[@]}" -lfuse3 -D_FILE_OFFSET_BITS=64 - 2> /dev/null; then
1028		echo "--with-nvme-cuse requires libfuse3."
1029		echo "Please install then re-run this script."
1030		exit 1
1031	fi
1032fi
1033
1034if [[ "${CONFIG[RBD]}" = "y" ]]; then
1035	if ! echo -e '#include <rbd/librbd.h>\n#include <rados/librados.h>\n' \
1036		'int main(void) { return 0; }\n' \
1037		| "${BUILD_CMD[@]}" -lrados -lrbd - 2> /dev/null; then
1038		echo "--with-rbd requires librados and librbd."
1039		echo "Please install then re-run this script."
1040		exit 1
1041	fi
1042fi
1043
1044if [[ "${CONFIG[UBLK]}" = "y" ]]; then
1045	if ! echo -e '#include <linux/ublk_cmd.h>\n#include <liburing.h>\n' \
1046		'int main(void) { return 0; }\n' \
1047		| "${BUILD_CMD[@]}" -luring - 2> /dev/null; then
1048		echo "--with-ublk requires liburing and ublk_drv."
1049		echo "Please install then re-run this script."
1050		exit 1
1051	fi
1052fi
1053
1054if [[ "${CONFIG[ISCSI_INITIATOR]}" = "y" ]]; then
1055	# Fedora installs libiscsi to /usr/lib64/iscsi for some reason.
1056	if ! echo -e '#include <iscsi/iscsi.h>\n#include <iscsi/scsi-lowlevel.h>\n' \
1057		'#if LIBISCSI_API_VERSION < 20150621\n' \
1058		'#error\n' \
1059		'#endif\n' \
1060		'int main(void) { return 0; }\n' \
1061		| "${BUILD_CMD[@]}" -L/usr/lib64/iscsi -liscsi - 2> /dev/null; then
1062		echo "--with-iscsi-initiator requires libiscsi with"
1063		echo "LIBISCSI_API_VERSION >= 20150621."
1064		echo "Please install then re-run this script."
1065		exit 1
1066	fi
1067fi
1068
1069if [[ "${CONFIG[DAOS]}" = "y" ]]; then
1070	daos_build_cmd=("${BUILD_CMD[@]}")
1071	if [[ -n "${CONFIG[DAOS_DIR]}" ]]; then
1072		daos_build_cmd+=(-I"${CONFIG[DAOS_DIR]}"/include -L"${CONFIG[DAOS_DIR]}"/lib64)
1073	fi
1074	if ! echo -e '#include <daos.h>\n#include <daos_fs.h>\n' \
1075		'int main(void) { return 0; }\n' \
1076		| "${daos_build_cmd[@]}" -lgurt -ldaos -ldaos_common -ldfs - 2> /dev/null; then
1077		echo "--with-daos requires libdaos, libdaos_common, libdfs and libgurt"
1078		echo "Please install then re-run this script."
1079		exit 1
1080	fi
1081fi
1082
1083if [[ "${CONFIG[ASAN]}" = "y" ]]; then
1084	if ! echo -e 'int main(void) { return 0; }\n' \
1085		| "${BUILD_CMD[@]}" -fsanitize=address - 2> /dev/null; then
1086		echo "--enable-asan requires libasan."
1087		echo "Please install then re-run this script."
1088		exit 1
1089	fi
1090fi
1091
1092if [[ "${CONFIG[UBSAN]}" = "y" ]]; then
1093	if ! echo -e 'int main(void) { return 0; }\n' \
1094		| "${BUILD_CMD[@]}" -fsanitize=undefined - 2> /dev/null; then
1095		echo "--enable-ubsan requires libubsan."
1096		echo "Please install then re-run this script."
1097		echo "If installed, please check that the GCC version is at least 6.4"
1098		echo "and synchronize CC accordingly."
1099		exit 1
1100	fi
1101fi
1102
1103if [[ "${CONFIG[TSAN]}" = "y" ]]; then
1104	if ! echo -e 'int main(void) { return 0; }\n' \
1105		| "${BUILD_CMD[@]}" -fsanitize=thread - 2> /dev/null; then
1106		echo "--enable-tsan requires libtsan."
1107		echo "Please install then re-run this script."
1108		exit 1
1109	fi
1110fi
1111
1112if echo -e '#include <stdlib.h>\nint main(void) { arc4random(); return 0; }\n' \
1113	| "${BUILD_CMD[@]}" - 2> /dev/null; then
1114	CONFIG[HAVE_ARC4RANDOM]="y"
1115fi
1116
1117if echo -e '#include <uuid/uuid.h>\nint main(void) { uuid_generate_sha1(NULL, NULL, NULL, 0); return 0; }\n' \
1118	| "${BUILD_CMD[@]}" - -luuid 2> /dev/null; then
1119	CONFIG[HAVE_UUID_GENERATE_SHA1]="y"
1120fi
1121
1122if echo -e '#include <execinfo.h>' | "${BUILD_CMD[@]}" -c - 2> /dev/null; then
1123	CONFIG[HAVE_EXECINFO_H]=y
1124fi
1125
1126if echo -e '#include <keyutils.h>\nint main(void) { request_key(0, 0, 0, -1); return 0; }' \
1127	| "${BUILD_CMD[@]}" - -lkeyutils 2> /dev/null; then
1128	CONFIG[HAVE_KEYUTILS]=y
1129fi
1130
1131if [[ "${CONFIG[OCF]}" = "y" ]]; then
1132	# If OCF_PATH is a file, assume it is a library and use it to compile with
1133	if [ -f ${CONFIG[OCF_PATH]} ]; then
1134		CONFIG[CUSTOMOCF]=y
1135	else
1136		CONFIG[CUSTOMOCF]=n
1137	fi
1138fi
1139
1140if [[ "${CONFIG[PGO_CAPTURE]}" = "y" && "${CONFIG[PGO_USE]}" = "y" ]]; then
1141	echo "ERROR: --enable-pgo-capture and --enable-pgo-use are mutually exclusive."
1142	exit 1
1143elif [[ "${CONFIG[PGO_CAPTURE]}" = "y" || "${CONFI[PGO_USE]}" = "y" ]]; then
1144	if [[ -z "${CONFIG[PGO_DIR]}" ]]; then
1145		CONFIG[PGO_DIR]=$(realpath $rootdir/build/pgo)
1146	fi
1147fi
1148
1149if [[ "${CONFIG[PGO_USE]}" = "y" ]]; then
1150	if [[ "$CC_TYPE" = "clang" ]]; then
1151		# For clang we need to run an extra step on gathered profiling data.
1152		echo "Generating suitable profile data"
1153		llvm-profdata merge -output=${CONFIG[PGO_DIR]}/default.profdata ${CONFIG[PGO_DIR]}
1154	fi
1155fi
1156
1157if [[ "${CONFIG[URING]}" = "y" || "${CONFIG[XNVME]}" = "y" ]]; then
1158	if [[ -n "${CONFIG[URING_PATH]}" ]]; then
1159		check_dir "${CONFIG[URING_PATH]}"
1160	elif ! echo -e '#include <liburing.h>\nint main(void) { return 0; }\n' \
1161		| "${BUILD_CMD[@]}" -luring - 2> /dev/null; then
1162		echo "--with-uring requires liburing."
1163		echo "Please build and install then re-run this script."
1164		exit 1
1165	fi
1166	# Support for Zoned devices is enabled by default for Uring bdev. Check appropriate support in kernel.
1167	if [[ "${CONFIG[URING_ZNS]}" = "y" ]]; then
1168		if ! echo -e '#include<linux/blkzoned.h>\nint main(void) { return BLK_ZONE_REP_CAPACITY; }\n' \
1169			| "${BUILD_CMD[@]}" -c - 2> /dev/null; then
1170			echo "Disabling Zoned NS support in Uring! Requires blkzoned.h from kernel >= linux-5.9."
1171			CONFIG[URING_ZNS]=n
1172		fi
1173	fi
1174fi
1175
1176if [[ "${CONFIG[FUSE]}" = "y" ]]; then
1177	if [[ ! -d /usr/include/fuse3 ]] && [[ ! -d /usr/local/include/fuse3 ]]; then
1178		echo "--with-fuse requires libfuse3."
1179		echo "Please install then re-run this script."
1180		exit 1
1181	fi
1182fi
1183
1184if [ "${CONFIG[CET]}" = "y" ]; then
1185	if ! echo -e 'int main(void) { return 0; }\n' | "${BUILD_CMD[@]}" -fcf-protection - 2> /dev/null; then
1186		echo "--enable-cet requires compiler/linker that supports CET."
1187		echo "Please install then re-run this script."
1188		exit 1
1189	fi
1190fi
1191
1192if [[ "${CONFIG[FUZZER]}" = "y" && "$CC_TYPE" != "clang" ]]; then
1193	echo "--with-fuzzer requires setting CC and CXX to clang."
1194	exit 1
1195fi
1196
1197if [[ $arch == x86_64* ]] || [[ $arch == aarch64* ]]; then
1198	CONFIG[ISAL]=y
1199	# make sure the submodule is initialized
1200	if [ ! -f "$rootdir"/isa-l/autogen.sh ]; then
1201		echo "ISA-L is required but was not found, please init the submodule with:"
1202		echo "  git submodule update --init"
1203		echo "and then re-run this script."
1204		exit 1
1205	fi
1206	# for x86 only, check the nasm version for ISA-L and IPSEC
1207	if [[ $arch == x86_64* ]]; then
1208		ver=$(nasm -v 2> /dev/null | awk '{print $3}' | awk -Fr '{print $1}')
1209		if lt "$ver" 2.14; then
1210			CONFIG[ISAL]=n
1211			# IPSEC has nasm requirement and DPDK crypto relies on IPSEC
1212			CONFIG[IPSEC_MB]=n
1213			echo "WARNING: ISA-L & DPDK crypto cannot be used as nasm ver must be 2.14 or newer."
1214		fi
1215	fi
1216	# check gas version on aarch64
1217	if [[ $arch == aarch64* ]]; then
1218		ver=$(as --version 2> /dev/null | awk '/GNU assembler/{print $NF}')
1219		if lt "$ver" 2.24; then
1220			# ISA-L, compression & crypto require gas version 2.24 or newer.
1221			CONFIG[ISAL]=n
1222			echo "Notice: ISA-L, compression & crypto require GAS version 2.24 or newer. Turning off default ISA-L and crypto features."
1223		elif lt "$ver" 2.34; then
1224			#For gas v2.24~v2.34, sve2 instructions are not supported. To workaround it, sve2 optimization should be disabled
1225			ISAL_CRYPTO_OPTS+=("--disable-sve2")
1226		fi
1227	fi
1228else
1229	# for PPC
1230	CONFIG[ISAL]=n
1231	echo "WARNING: ISA-L cannot be used due to architecture incompatibility."
1232fi
1233
1234# now either configure ISA-L or disable unavailable features
1235if [[ "${CONFIG[ISAL]}" = "y" ]]; then
1236	cd $rootdir/isa-l
1237	ISAL_LOG=$rootdir/.spdk-isal.log
1238	if [[ -n "${CONFIG[CROSS_PREFIX]}" ]]; then
1239		ISAL_OPTS=("--host=${CONFIG[CROSS_PREFIX]}")
1240	else
1241		ISAL_OPTS=()
1242	fi
1243	if [[ "${CONFIG[SHARED]}" = "y" ]]; then
1244		ISAL_OPTS+=("--enable-shared=yes")
1245	else
1246		ISAL_OPTS+=("--enable-shared=no")
1247	fi
1248	ISAL_OPTS+=("--prefix=${CONFIG[PREFIX]}")
1249	echo -n "Configuring ISA-L (logfile: $ISAL_LOG)..."
1250	./autogen.sh &> $ISAL_LOG
1251	./configure CFLAGS="-fPIC -g -O2 -fuse-ld=$LD_TYPE -Wno-unused-command-line-argument" "${ISAL_OPTS[@]}" --enable-shared=no >> $ISAL_LOG 2>&1
1252	echo "done."
1253	cd $rootdir
1254else
1255	echo "Without ISA-L, there is no software support for crypto or compression,"
1256	echo "so these features will be disabled."
1257	CONFIG[CRYPTO]=n
1258	CONFIG[VBDEV_COMPRESS]=n
1259	CONFIG[DPDK_COMPRESSDEV]=n
1260fi
1261
1262# ISA-L-crypto complements ISA-L functionality, it is only enabled together with ISA-L
1263if [[ "${CONFIG[ISAL]}" = "y" ]]; then
1264	if [ ! -f "$rootdir"/isa-l-crypto/autogen.sh ]; then
1265		echo "ISA-L-crypto is required but was not found, please init the submodule with:"
1266		echo "  git submodule update --init"
1267		echo "and then re-run this script."
1268		exit 1
1269	fi
1270
1271	cd $rootdir/isa-l-crypto
1272	ISAL_CRYPTO_LOG=$rootdir/.spdk-isal-crypto.log
1273	if [[ -n "${CONFIG[CROSS_PREFIX]}" ]]; then
1274		ISAL_CRYPTO_OPTS+=("--host=${CONFIG[CROSS_PREFIX]}")
1275	fi
1276	if [[ "${CONFIG[SHARED]}" = "y" ]]; then
1277		ISAL_CRYPTO_OPTS+=("--enable-shared=yes")
1278	else
1279		ISAL_CRYPTO_OPTS+=("--enable-shared=no")
1280	fi
1281	ISAL_CRYPTO_OPTS+=("--prefix=${CONFIG[PREFIX]}")
1282	echo -n "Configuring ISA-L-crypto (logfile: $ISAL_CRYPTO_LOG)..."
1283	./autogen.sh &> $ISAL_CRYPTO_LOG
1284	./configure CFLAGS="-fPIC -g -O2 -fuse-ld=$LD_TYPE -Wno-unused-command-line-argument" "${ISAL_CRYPTO_OPTS[@]}" >> $ISAL_CRYPTO_LOG 2>&1
1285	echo "done."
1286	cd $rootdir
1287	CONFIG[ISAL_CRYPTO]=y
1288else
1289	CONFIG[ISAL_CRYPTO]=n
1290fi
1291
1292if [[ "${CONFIG[SMA]}" = "y" ]]; then
1293	if ! python3 -c 'import grpc; import grpc_tools' 2> /dev/null; then
1294		echo "--with-sma requires grpcio and grpcio-tools python packages."
1295		echo "Please install then re-run this script."
1296		exit 1
1297	fi
1298fi
1299
1300if [[ "${CONFIG[AVAHI]}" = "y" ]]; then
1301	if ! echo -e '#include <avahi-client/client.h>\n#include <avahi-common/malloc.h>\n' \
1302		'int main(void) { return 0; }\n' \
1303		| "${BUILD_CMD[@]}" -lavahi-client -lavahi-common - 2> /dev/null; then
1304		echo "--with-avahi requires libavahi-client and libavahi-common."
1305		echo "Please install then re-run this script."
1306		exit 1
1307	fi
1308fi
1309
1310if [[ "${CONFIG[GOLANG]}" = "y" ]]; then
1311	if ! go version 2> /dev/null; then
1312		echo "--with-golang requires Go installation."
1313		echo "Please install then re-run this script."
1314		exit 1
1315	fi
1316fi
1317
1318if [[ -n ${CONFIG[MAX_LCORES]} ]]; then
1319	if [[ ! ${CONFIG[MAX_LCORES]} =~ ^([1-9][0-9]*|detect)$ ]] || ((CONFIG[MAX_LCORES] > 1024)); then
1320		echo "ERROR: Max number of lcores must be a decimal number in range [1..1024] or 'detect' (given: ${CONFIG[MAX_LCORES]})"
1321		exit 1
1322	fi
1323fi
1324
1325# For ARM Neoverse-N1 platform, debug build needs gcc version newer than 8.4
1326if [[ "${CONFIG[DEBUG]}" = "y" && $arch = aarch64* && "$CC_TYPE" = "gcc" ]]; then
1327	GCC_VERSION=$($CC -dumpfullversion)
1328	PART_NUM=$(grep -i -m 1 "CPU part" /proc/cpuinfo | awk '{print $4}')
1329
1330	if [[ "$(printf '%s\n' "8.4.0" "$GCC_VERSION" | sort -V | head -n1)" != "8.4.0" ]]; then
1331		if [[ $PART_NUM = 0xd0c ]]; then
1332			echo "WARNING: For ARM Neoverse-N1 platform, debug build needs GCC version newer than 8.4."
1333			echo "         Will work around this by using armv8.2-a+crypto as target architecture for now."
1334			CONFIG[ARCH]=armv8.2-a+crypto
1335		elif [[ $PART_NUM = 0x0b2 ]]; then
1336			echo "WARNING: For ARM octeontx2 platform, debug build needs GCC version newer than 8.4."
1337			echo "         Will work around this by using armv8.2-a+crypto as target architecture for now."
1338			CONFIG[ARCH]=armv8.2-a+crypto
1339		fi
1340	fi
1341fi
1342
1343# We are now ready to generate final configuration. But first do sanity
1344# check to see if all keys in CONFIG array have its reflection in CONFIG file.
1345if (($(grep -cE "^\s*CONFIG_[[:alnum:]_]+=" "$rootdir/CONFIG") != ${#CONFIG[@]})); then
1346	echo ""
1347	echo "BUG: Some configuration options are not present in CONFIG file. Please update this file."
1348	echo "Missing options in CONFIG (+) file and in current config (-): "
1349	diff -u --label "CONFIG file" --label "CONFIG[@]" \
1350		<(sed -r -e '/^[[:space:]]*$/d; /^[[:space:]]*#.*/d; s/(CONFIG_[[:alnum:]_]+)=.*/\1/g' CONFIG | sort) \
1351		<(printf "CONFIG_%s\n" "${!CONFIG[@]}" | sort)
1352	exit 1
1353fi
1354
1355echo -n "Creating mk/config.mk..."
1356cp -f $rootdir/CONFIG $rootdir/mk/config.mk
1357ARGS=$(echo "$@" | sed 's/ /\\ /g')
1358sed -i.bak -r "s#__CONFIGURE_OPTIONS__#${ARGS}#g" $rootdir/mk/config.mk
1359for key in "${!CONFIG[@]}"; do
1360	sed -i.bak -r "s#[[:space:]]*CONFIG_${key}=.*#CONFIG_${key}\?=${CONFIG[$key]}#g" $rootdir/mk/config.mk
1361done
1362# On FreeBSD sed -i 'SUFFIX' - SUFFIX is mandatory. So no way but to delete the backed file.
1363rm -f $rootdir/mk/config.mk.bak
1364echo "done."
1365
1366# Environment variables
1367echo -n "Creating mk/cc.flags.mk..."
1368rm -f $rootdir/mk/cc.flags.mk
1369[ -n "$CFLAGS" ] && echo "CFLAGS?=$CFLAGS" > $rootdir/mk/cc.flags.mk
1370[ -n "$CXXFLAGS" ] && echo "CXXFLAGS?=$CXXFLAGS" >> $rootdir/mk/cc.flags.mk
1371[ -n "$LDFLAGS" ] && echo "LDFLAGS?=$LDFLAGS" >> $rootdir/mk/cc.flags.mk
1372[ -n "$DESTDIR" ] && echo "DESTDIR?=$DESTDIR" >> $rootdir/mk/cc.flags.mk
1373echo "done."
1374
1375# Create .sh with build config for easy sourcing|lookup during the tests.
1376for conf in "${!CONFIG[@]}"; do
1377	echo "CONFIG_$conf=${CONFIG[$conf]}"
1378done > "$rootdir/test/common/build_config.sh"
1379
1380if [[ $sys_name == "FreeBSD" ]]; then
1381	echo "Type 'gmake' to build."
1382else
1383	echo "Type 'make' to build."
1384fi
1385
1386exit 0
1387