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