xref: /spdk/configure (revision cc6920a4763d4b9a43aa40583c8397d8f14fa100)
1#!/usr/bin/env bash
2
3set -e
4
5trap 'echo -e "\n\nConfiguration failed\n\n" >&2' ERR
6
7rootdir=$(readlink -f $(dirname $0))
8source "$rootdir/scripts/common.sh"
9
10function usage() {
11	echo "'configure' configures SPDK to compile on supported platforms."
12	echo ""
13	echo "Usage: ./configure [OPTION]..."
14	echo ""
15	echo "Defaults for the options are specified in brackets."
16	echo ""
17	echo "General:"
18	echo " -h, --help                Display this help and exit"
19	echo ""
20	echo " --prefix=path             Configure installation prefix (default: /usr/local)"
21	echo " --target-arch=arch        Target build architecture. Must be a valid GNU arch. Default: native"
22	echo ""
23	echo " --cross-prefix=prefix     Prefix for cross compilation (default: none)"
24	echo "                           example: aarch64-linux-gnu"
25	echo ""
26	echo " --enable-debug            Configure for debug builds"
27	echo " --enable-werror           Treat compiler warnings as errors"
28	echo " --enable-asan             Enable address sanitizer"
29	echo " --enable-ubsan            Enable undefined behavior sanitizer"
30	echo " --enable-coverage         Enable code coverage tracking"
31	echo " --enable-lto              Enable link-time optimization"
32	echo " --enable-pgo-capture      Enable generation of profile guided optimization data"
33	echo " --enable-pgo-use          Use previously captured profile guided optimization data"
34	echo " --enable-cet              Enable Intel Control-flow Enforcement Technology (CET)"
35	echo " --disable-tests           Disable building of functional tests"
36	echo " --disable-unit-tests      Disable building of unit tests"
37	echo " --disable-examples        Disable building of examples"
38	echo " --disable-apps            Disable building of apps"
39	echo ""
40	echo "Specifying Dependencies:"
41	echo "--with-DEPENDENCY[=path]   Use the given dependency. Optionally, provide the"
42	echo "                           path."
43	echo "--without-DEPENDENCY       Do not link to the given dependency. This may"
44	echo "                           disable features and components."
45	echo ""
46	echo "Valid dependencies are listed below."
47	echo " dpdk                      Build against a custom dpdk version. By default, the dpdk"
48	echo "                           submodule in spdk tree will be used."
49	echo "                           example: /usr/share/dpdk/x86_64-default-linuxapp-gcc"
50	echo " env                       Use an alternate environment implementation instead of DPDK."
51	echo "                           Implies --without-dpdk."
52	echo " idxd                      Build the IDXD library and accel framework plug-in module."
53	echo "                           Disabled while experimental. Only built for x86 when enabled."
54	echo " crypto                    Build vbdev crypto module."
55	echo "                           No path required."
56	echo " fio                       Build fio_plugin."
57	echo "                           default: /usr/src/fio"
58	echo " vhost                     Build vhost target. Enabled by default."
59	echo "                           No path required."
60	echo " virtio                    Build vhost initiator and virtio-pci bdev modules."
61	echo "                           No path required."
62	echo " vfio-user                 Build custom vfio-user transport for NVMf target and NVMe initiator."
63	echo "                           example: /usr/src/libvfio-user"
64	echo " pmdk                      Build persistent memory bdev."
65	echo "                           example: /usr/share/pmdk"
66	echo " reduce                    Build vbdev compression module."
67	echo "                           No path required."
68	echo " rbd                       Build Ceph RBD bdev module."
69	echo "                           No path required."
70	echo " rdma                      Build RDMA transport for NVMf target and initiator."
71	echo "                           Accepts optional RDMA provider name. Can be \"verbs\" or \"mlx5_dv\"."
72	echo "                           If no provider specified, \"verbs\" provider is used by default."
73	echo " fc                        Build FC transport for NVMf target."
74	echo "                           If an argument is provided, it is considered a directory containing"
75	echo "                           libufc.a and fc_lld.h. Otherwise the regular system paths will"
76	echo "                           be searched."
77	echo " shared                    Build spdk shared libraries."
78	echo "                           No path required."
79	echo " iscsi-initiator           Build with iscsi bdev module."
80	echo "                           No path required."
81	echo " vtune                     Required to profile I/O under Intel VTune Amplifier XE."
82	echo "                           example: /opt/intel/vtune_amplifier_xe_version"
83	echo " ocf                       Build OCF library and bdev module."
84	echo "                           If argument is directory, interpret it as root of OCF repo"
85	echo "                           If argument is file, interpret it as compiled OCF lib"
86	echo "                           If no argument is specified, OCF git submodule is used by default"
87	echo "                           example: /usr/src/ocf/"
88	echo " isal                      Build with ISA-L. Enabled by default on x86 and aarch64 architectures."
89	echo "                           No path required."
90	echo " uring                     Build I/O uring bdev or socket module."
91	echo "                           If an argument is provided, it is considered a directory containing"
92	echo "                           liburing.a and io_uring.h. Otherwise the regular system paths will"
93	echo "                           be searched."
94	echo " fuse                      Build FUSE components for mounting a blobfs filesystem."
95	echo "                           No path required."
96	echo " nvme-cuse                 Build NVMe driver with support for CUSE-based character devices."
97	echo "                           No path required."
98	echo " raid5                     Build with bdev_raid module RAID5 support."
99	echo "                           No path required."
100	echo " wpdk                      Build using WPDK to provide support for Windows (experimental)."
101	echo "                           The argument must be a directory containing lib and include."
102	echo " usdt                      Build with userspace DTrace probes enabled."
103	echo "                           No path required."
104	echo ""
105	echo "Environment variables:"
106	echo ""
107	echo "CC                         C compiler"
108	echo "CFLAGS                     C compiler flags"
109	echo "CXX                        C++ compiler"
110	echo "CXXFLAGS                   C++ compiler flags"
111	echo "LD                         Linker"
112	echo "LDFLAGS                    Linker flags"
113	echo "DESTDIR                    Destination for 'make install'"
114	echo ""
115}
116
117# Load default values
118# Convert config to sourceable configuration file
119sed -r 's/CONFIG_([[:alnum:]_]+)=(.*)/CONFIG[\1]=\2/g' $rootdir/CONFIG > $rootdir/CONFIG.sh
120declare -A CONFIG
121source $rootdir/CONFIG.sh
122rm $rootdir/CONFIG.sh
123
124for i in "$@"; do
125	case "$i" in
126		--cross-prefix=*)
127			CONFIG[CROSS_PREFIX]="${i#*=}"
128			;;
129		--enable-lto)
130			CONFIG[LTO]=y
131			;;
132		--disable-lto)
133			CONFIG[LTO]=n
134			;;
135	esac
136done
137
138# Detect the compiler toolchain
139$rootdir/scripts/detect_cc.sh --cc="$CC" --cxx="$CXX" --lto="${CONFIG[LTO]}" --ld="$LD" --cross-prefix="${CONFIG[CROSS_PREFIX]}" > $rootdir/mk/cc.mk
140
141CC=$(grep "DEFAULT_CC=" "$rootdir/mk/cc.mk" | sed s/DEFAULT_CC=//)
142CC_TYPE=$(grep "CC_TYPE=" "$rootdir/mk/cc.mk" | cut -d "=" -f 2)
143
144arch=$($CC -dumpmachine)
145sys_name=$(uname -s)
146
147if [[ $arch == *mingw* ]] || [[ $arch == *windows* ]]; then
148	sys_name=Windows
149fi
150
151# Sanitize default configuration. All parameters set by user explicit should fail
152# Force no ISA-L if non-x86 or non-aarch64 architecture
153if [[ "${CONFIG[ISAL]}" = "y" ]]; then
154	if [[ $arch != x86_64* ]] && [[ $arch != aarch64* ]]; then
155		CONFIG[ISAL]=n
156		echo "Notice: ISA-L not supported for ${arch}. Turning off default feature."
157	fi
158fi
159
160if [[ $sys_name != "Linux" ]]; then
161	# Vhost, rte_vhost library and virtio are only supported on Linux.
162	CONFIG[VHOST]="n"
163	CONFIG[VIRTIO]="n"
164	echo "Notice: Vhost, rte_vhost library and virtio are only supported on Linux. Turning off default feature."
165fi
166
167#check nasm only on x86
168if [[ $arch == x86_64* ]]; then
169	ver=$(nasm -v 2> /dev/null | awk '{print $3}' | awk -Fr '{print $1}')
170	if lt "$ver" 2.14; then
171		# ISA-L, compression & crypto require NASM version 2.14 or newer.
172		CONFIG[ISAL]=n
173		CONFIG[CRYPTO]=n
174		CONFIG[IPSEC_MB]=n
175		CONFIG[REDUCE]=n
176		HAVE_NASM=n
177		echo "Notice: ISA-L, compression & crypto require NASM version 2.14 or newer. Turning off default ISA-L and crypto features."
178	else
179		HAVE_NASM=y
180	fi
181fi
182
183function check_dir() {
184	arg="$1"
185	dir="${arg#*=}"
186	if [ ! -d "$dir" ]; then
187		echo "$arg: directory not found"
188		exit 1
189	fi
190}
191
192for i in "$@"; do
193	case "$i" in
194		-h | --help)
195			usage
196			exit 0
197			;;
198		--cross-prefix=*) ;&
199		--enable-lto) ;&
200		--disable-lto)
201			# Options handled before detecting CC.
202			;;
203		--prefix=*)
204			CONFIG[PREFIX]="${i#*=}"
205			;;
206		--target-arch=*)
207			CONFIG[ARCH]="${i#*=}"
208			;;
209		--enable-debug)
210			CONFIG[DEBUG]=y
211			;;
212		--disable-debug)
213			CONFIG[DEBUG]=n
214			;;
215		--enable-asan)
216			CONFIG[ASAN]=y
217			;;
218		--disable-asan)
219			CONFIG[ASAN]=n
220			;;
221		--enable-ubsan)
222			CONFIG[UBSAN]=y
223			;;
224		--disable-ubsan)
225			CONFIG[UBSAN]=n
226			;;
227		--enable-tsan)
228			CONFIG[TSAN]=y
229			;;
230		--disable-tsan)
231			CONFIG[TSAN]=n
232			;;
233		--enable-coverage)
234			CONFIG[COVERAGE]=y
235			;;
236		--disable-coverage)
237			CONFIG[COVERAGE]=n
238			;;
239		--enable-pgo-capture)
240			CONFIG[PGO_CAPTURE]=y
241			;;
242		--disable-pgo-capture)
243			CONFIG[PGO_CAPTURE]=n
244			;;
245		--enable-pgo-use)
246			CONFIG[PGO_USE]=y
247			;;
248		--disable-pgo-use)
249			CONFIG[PGO_USE]=n
250			;;
251		--enable-tests)
252			CONFIG[TESTS]=y
253			;;
254		--disable-tests)
255			CONFIG[TESTS]=n
256			;;
257		--enable-unit-tests)
258			CONFIG[UNIT_TESTS]=y
259			;;
260		--disable-unit-tests)
261			CONFIG[UNIT_TESTS]=n
262			;;
263		--enable-examples)
264			CONFIG[EXAMPLES]=y
265			;;
266		--disable-examples)
267			CONFIG[EXAMPLES]=n
268			;;
269		--enable-apps)
270			CONFIG[APPS]=y
271			;;
272		--disable-apps)
273			CONFIG[APPS]=N
274			;;
275		--enable-werror)
276			CONFIG[WERROR]=y
277			;;
278		--disable-werror)
279			CONFIG[WERROR]=n
280			;;
281		--enable-cet)
282			CONFIG[CET]=y
283			;;
284		--disable-cet)
285			CONFIG[CET]=n
286			;;
287		--with-dpdk)
288			if pkg-config --exists libdpdk; then
289				CONFIG[DPDK_LIB_DIR]=$(pkg-config --variable=libdir libdpdk)
290				CONFIG[DPDK_INC_DIR]=$(pkg-config --variable=includedir libdpdk)
291				CONFIG[DPDK_PKG_CONFIG]=y
292				CFLAGS="${CFLAGS:+$CFLAGS }$(pkg-config --cflags libdpdk)"
293			else
294				echo "libdpdk.pc not found, aborting"
295				exit 1
296			fi
297			;;
298		--with-dpdk=*)
299			check_dir "$i"
300			CONFIG[DPDK_DIR]=$(readlink -f ${i#*=})
301			;;
302		--without-dpdk)
303			CONFIG[DPDK_DIR]=
304			;;
305		--with-wpdk=*)
306			check_dir "$i"
307			CONFIG[WPDK_DIR]=$(readlink -f ${i#*=})
308			;;
309		--with-env=*)
310			CONFIG[ENV]="${i#*=}"
311			;;
312		--with-rbd)
313			CONFIG[RBD]=y
314			;;
315		--without-rbd)
316			CONFIG[RBD]=n
317			;;
318		--with-rdma=*)
319			CONFIG[RDMA]=y
320			CONFIG[RDMA_PROV]=${i#*=}
321			;;
322		--with-rdma)
323			CONFIG[RDMA]=y
324			CONFIG[RDMA_PROV]="verbs"
325			;;
326		--without-rdma)
327			CONFIG[RDMA]=n
328			;;
329		--with-fc=*)
330			CONFIG[FC]=y
331			CONFIG[FC_PATH]=$(readlink -f ${i#*=})
332			;;
333		--with-fc)
334			CONFIG[FC]=y
335			CONFIG[FC_PATH]=
336			;;
337		--without-fc)
338			CONFIG[FC]=n
339			CONFIG[FC_PATH]=
340			;;
341		--with-shared)
342			CONFIG[SHARED]=y
343			;;
344		--without-shared)
345			CONFIG[SHARED]=n
346			;;
347		--with-iscsi-initiator)
348			CONFIG[ISCSI_INITIATOR]=y
349			;;
350		--without-iscsi-initiator)
351			CONFIG[ISCSI_INITIATOR]=n
352			;;
353		--with-crypto)
354			CONFIG[CRYPTO]=y
355			;;
356		--without-crypto)
357			CONFIG[CRYPTO]=n
358			;;
359		--with-vhost)
360			CONFIG[VHOST]=y
361			;;
362		--without-vhost)
363			CONFIG[VHOST]=n
364			;;
365		--with-virtio)
366			CONFIG[VIRTIO]=y
367			;;
368		--without-virtio)
369			CONFIG[VIRTIO]=n
370			;;
371		--with-vfio-user)
372			CONFIG[VFIO_USER]=y
373			CONFIG[VFIO_USER_DIR]=""
374			;;
375		--with-vfio-user=*)
376			CONFIG[VFIO_USER]=y
377			check_dir "$i"
378			CONFIG[VFIO_USER_DIR]=$(readlink -f ${i#*=})
379			;;
380		--without-vfio-user)
381			CONFIG[VFIO_USER]=n
382			;;
383		--with-pmdk)
384			CONFIG[PMDK]=y
385			CONFIG[PMDK_DIR]=""
386			;;
387		--with-pmdk=*)
388			CONFIG[PMDK]=y
389			check_dir "$i"
390			CONFIG[PMDK_DIR]=$(readlink -f ${i#*=})
391			;;
392		--without-pmdk)
393			CONFIG[PMDK]=n
394			;;
395		--with-reduce)
396			CONFIG[REDUCE]=y
397			;;
398		--without-reduce)
399			CONFIG[REDUCE]=n
400			;;
401		--with-fio) ;&
402		--with-fio=*)
403			if [[ ${i#*=} != "$i" ]]; then
404				CONFIG[FIO_SOURCE_DIR]=$(readlink -f "${i#*=}")
405			fi
406			check_dir "--with-fio=${CONFIG[FIO_SOURCE_DIR]}"
407			CONFIG[FIO_PLUGIN]=y
408			;;
409		--without-fio)
410			CONFIG[FIO_PLUGIN]=n
411			;;
412		--with-vtune=*)
413			check_dir "$i"
414			CONFIG[VTUNE_DIR]="${i#*=}"
415			CONFIG[VTUNE]=y
416			;;
417		--without-vtune)
418			CONFIG[VTUNE_DIR]=
419			CONFIG[VTUNE]=n
420			;;
421		--with-ocf)
422			CONFIG[OCF]=y
423			CONFIG[OCF_PATH]=$(readlink -f "./ocf")
424			;;
425		--with-ocf=*)
426			CONFIG[OCF]=y
427			CONFIG[OCF_PATH]=$(readlink -f ${i#*=})
428			;;
429		--without-ocf)
430			CONFIG[OCF]=n
431			CONFIG[OCF_PATH]=
432			;;
433		--with-isal)
434			CONFIG[ISAL]=y
435			;;
436		--without-isal)
437			CONFIG[ISAL]=n
438			;;
439		--with-uring=*)
440			CONFIG[URING]=y
441			CONFIG[URING_PATH]=$(readlink -f ${i#*=})
442			;;
443		--with-uring)
444			CONFIG[URING]=y
445			CONFIG[URING_PATH]=
446			;;
447		--without-uring)
448			CONFIG[URING]=n
449			CONFIG[URING_PATH]=
450			;;
451		--with-fuse)
452			CONFIG[FUSE]=y
453			;;
454		--without-fuse)
455			CONFIG[FUSE]=n
456			;;
457		--with-nvme-cuse)
458			CONFIG[NVME_CUSE]=y
459			;;
460		--without-nvme-cuse)
461			CONFIG[NVME_CUSE]=n
462			;;
463		--with-raid5)
464			CONFIG[RAID5]=y
465			;;
466		--without-raid5)
467			CONFIG[RAID5]=n
468			;;
469		--with-idxd)
470			CONFIG[IDXD]=y
471			CONFIG[IDXD_KERNEL]=n
472			;;
473		--without-idxd)
474			CONFIG[IDXD]=n
475			;;
476		--with-usdt)
477			CONFIG[USDT]=y
478			;;
479		--without-usdt)
480			CONFIG[USDT]=n
481			;;
482		--)
483			break
484			;;
485		*)
486			echo "Unrecognized option $i"
487			usage
488			exit 1
489			;;
490	esac
491done
492
493if [[ $arch == x86_64* ]]; then
494	BUILD_CMD=("$CC" -o /dev/null -x c $CPPFLAGS $CFLAGS $LDFLAGS "-march=native")
495else
496	BUILD_CMD=("$CC" -o /dev/null -x c $CPPFLAGS $CFLAGS $LDFLAGS)
497fi
498BUILD_CMD+=(-I/usr/local/include -L/usr/local/lib)
499
500if [[ "${CONFIG[VFIO_USER]}" = "y" ]]; then
501
502	if ! bash -c "command -v cmake3 cmake" > /dev/null; then
503		echo "ERROR: --with-vfio-user requires cmake"
504		echo "Please install then re-run this script"
505		exit 1
506	fi
507	if [[ ! -d /usr/include/json-c ]] && [[ ! -d /usr/local/include/json-c ]]; then
508		echo "ERROR: --with-vfio-user requires json-c-devel"
509		echo "Please install then re-run this script"
510		exit 1
511	fi
512	if [[ ! -e /usr/include/cmocka.h ]] && [[ ! -e /usr/local/include/cmocka.h ]]; then
513		echo "ERROR: --with-vfio-user requires libcmocka-devel"
514		echo "Please install then re-run this script"
515		exit 1
516	fi
517fi
518
519# IDXD uses Intel specific instructions.
520if [[ "${CONFIG[IDXD]}" = "y" ]]; then
521	if [ $(uname -s) == "FreeBSD" ]; then
522		intel="hw.model: Intel"
523		cpu_vendor=$(sysctl -a | grep hw.model | cut -c 1-15)
524	else
525		intel="GenuineIntel"
526		cpu_vendor=$(grep -i 'vendor' /proc/cpuinfo --max-count=1)
527	fi
528	if [[ "$cpu_vendor" != *"$intel"* ]]; then
529		echo "ERROR: IDXD cannot be used due to CPU incompatibility."
530		exit 1
531	fi
532	if [ -e /usr/include/accel-config/libaccel_config.h ]; then
533		CONFIG[IDXD_KERNEL]=y
534	fi
535
536fi
537
538# Detect architecture and force no ISA-L if non-x86 or non-aarch64 architecture
539if [[ "${CONFIG[ISAL]}" = "y" ]]; then
540	if [[ $arch != x86_64* ]] && [[ $arch != aarch64* ]]; then
541		echo "ERROR: ISA-L cannot be used due to CPU incompatibility."
542		exit 1
543	fi
544fi
545
546if [[ "${CONFIG[ISAL]}" = "n" ]] && [[ "${CONFIG[REDUCE]}" = "y" ]]; then
547	echo "ERROR Conflicting options: --with-reduce is not compatible with --without-isal."
548	exit 1
549fi
550
551if [ -z "${CONFIG[ENV]}" ]; then
552	CONFIG[ENV]=$rootdir/lib/env_dpdk
553	echo "Using default SPDK env in ${CONFIG[ENV]}"
554	if [[ -z "${CONFIG[DPDK_DIR]}" && "${CONFIG[DPDK_PKG_CONFIG]}" == n ]]; then
555		if [ ! -f "$rootdir"/dpdk/config/meson.build ]; then
556			echo "DPDK not found; please specify --with-dpdk=<path> or run:"
557			echo
558			echo "  git submodule update --init"
559			exit 1
560		else
561			CONFIG[DPDK_DIR]="${rootdir}/dpdk/build"
562			echo "Using default DPDK in ${CONFIG[DPDK_DIR]}"
563		fi
564	fi
565else
566	if [[ -n "${CONFIG[DPDK_DIR]}" || "${CONFIG[DPDK_PKG_CONFIG]}" == y ]]; then
567		echo "--with-env and --with-dpdk are mutually exclusive."
568		exit 1
569	fi
570
571	if [ "${CONFIG[VHOST]}" = "y" ]; then
572		echo "Vhost is only supported when using the default DPDK environment. Disabling it."
573	fi
574	# Always disable vhost, but only print the error message if the user explicitly turned it on.
575	CONFIG[VHOST]="n"
576	if [ "${CONFIG[VIRTIO]}" = "y" ]; then
577		echo "Virtio is only supported when using the default DPDK environment. Disabling it."
578	fi
579	# Always disable virtio, but only print the error message if the user explicitly turned it on.
580	CONFIG[VIRTIO]="n"
581fi
582
583if [[ "${CONFIG[DPDK_PKG_CONFIG]}" == y ]]; then
584	if [[ "${CONFIG[SHARED]}" == n ]]; then
585		# dpdk-devel doesn't provide static libs
586		echo "Build against packaged DPDK requested, enabling shared libraries"
587		CONFIG[SHARED]=y
588	fi
589fi
590
591if [[ $sys_name == "Windows" ]]; then
592	if [ -z "${CONFIG[WPDK_DIR]}" ]; then
593		if [ ! -f "$rootdir"/wpdk/Makefile ]; then
594			echo "WPDK not found; please specify --with-wpdk=<path>. See https://wpdk.github.io."
595			exit 1
596		else
597			CONFIG[WPDK_DIR]="${rootdir}/wpdk/build"
598			echo "Using default WPDK in ${CONFIG[WPDK_DIR]}"
599		fi
600	fi
601else
602	if [ -n "${CONFIG[WPDK_DIR]}" ]; then
603		echo "ERROR: --with-wpdk is only supported for Windows"
604		exit 1
605	fi
606fi
607
608if [ "${CONFIG[VTUNE]}" = "y" ]; then
609	if [ -z "${CONFIG[VTUNE_DIR]}" ]; then
610		echo "When VTune is enabled, you must specify the VTune directory using --with-vtune=path"
611		exit 1
612	fi
613fi
614
615if [[ "${CONFIG[ASAN]}" = "y" && "${CONFIG[TSAN]}" = "y" ]]; then
616	echo "ERROR: ASAN and TSAN cannot be enabled at the same time."
617	exit 1
618fi
619
620if [[ $sys_name == "FreeBSD" ]]; then
621	# FreeBSD doesn't support all configurations
622	if [[ "${CONFIG[COVERAGE]}" == "y" ]]; then
623		echo "ERROR: CONFIG_COVERAGE not available on FreeBSD"
624		exit 1
625	fi
626fi
627
628if [[ $sys_name != "Linux" ]]; then
629	if [[ "${CONFIG[VHOST]}" == "y" ]]; then
630		echo "Vhost is only supported on Linux."
631		exit 1
632	fi
633	if [[ "${CONFIG[VIRTIO]}" == "y" ]]; then
634		echo "Virtio is only supported on Linux."
635		exit 1
636	fi
637fi
638
639if [ "${CONFIG[RDMA]}" = "y" ]; then
640	if [[ ! "${CONFIG[RDMA_PROV]}" == "verbs" ]] && [[ ! "${CONFIG[RDMA_PROV]}" == "mlx5_dv" ]]; then
641		echo "Invalid RDMA provider specified, must be \"verbs\" or \"mlx5_dv\""
642		exit 1
643	fi
644
645	if ! echo -e '#include <infiniband/verbs.h>\n#include <rdma/rdma_verbs.h>\n' \
646		'int main(void) { return 0; }\n' \
647		| "${BUILD_CMD[@]}" -libverbs -lrdmacm - 2> /dev/null; then
648		echo "--with-rdma requires libverbs and librdmacm."
649		echo "Please install then re-run this script."
650		exit 1
651	fi
652
653	if echo -e '#include <infiniband/verbs.h>\n' \
654		'int main(void) { return !!IBV_WR_SEND_WITH_INV; }\n' \
655		| "${BUILD_CMD[@]}" -c - 2> /dev/null; then
656		CONFIG[RDMA_SEND_WITH_INVAL]="y"
657	else
658		CONFIG[RDMA_SEND_WITH_INVAL]="n"
659		echo "
660*******************************************************************************
661WARNING: The Infiniband Verbs opcode Send With Invalidate is either not
662supported or is not functional with the current version of libibverbs installed
663on this system. Please upgrade to at least version 1.1.
664
665Beginning with Linux kernel 4.14, the kernel NVMe-oF initiator leverages Send
666With Invalidate RDMA operations to improve performance. Failing to use the
667Send With Invalidate operation on the NVMe-oF target side results in full
668functionality, but greatly reduced performance. The SPDK NVMe-oF target will
669be unable to leverage that operation using the currently installed version
670of libibverbs, so Linux kernel NVMe-oF initiators based on kernels greater
671than or equal to 4.14 will see significantly reduced performance.
672*******************************************************************************"
673	fi
674
675	if echo -e '#include <rdma/rdma_cma.h>\n' \
676		'int main(void) { return !!RDMA_OPTION_ID_ACK_TIMEOUT; }\n' \
677		| "${BUILD_CMD[@]}" -c - 2> /dev/null; then
678		CONFIG[RDMA_SET_ACK_TIMEOUT]="y"
679	else
680		CONFIG[RDMA_SET_ACK_TIMEOUT]="n"
681		echo "RDMA_OPTION_ID_ACK_TIMEOUT is not supported"
682	fi
683
684	if [ "${CONFIG[RDMA_PROV]}" == "mlx5_dv" ]; then
685		if ! echo -e '#include <spdk/stdinc.h>\n' \
686			'#include <infiniband/mlx5dv.h>\n' \
687			'#include <rdma/rdma_cma.h>\n' \
688			'int main(void) { return rdma_establish(NULL) || ' \
689			'!!IBV_QP_INIT_ATTR_SEND_OPS_FLAGS || !!MLX5_OPCODE_RDMA_WRITE; }\n' \
690			| "${BUILD_CMD[@]}" -lmlx5 -I${rootdir}/include -c - 2> /dev/null; then
691			echo "mlx5_dv provider is not supported"
692			exit 1
693		fi
694	fi
695
696	echo "Using '${CONFIG[RDMA_PROV]}' RDMA provider"
697fi
698
699if [[ "${CONFIG[FC]}" = "y" ]]; then
700	if [[ -n "${CONFIG[FC_PATH]}" ]]; then
701		if [ ! -d "${CONFIG[FC_PATH]}" ]; then
702			echo "${CONFIG[FC_PATH]}: directory not found"
703			exit 1
704		fi
705	fi
706fi
707
708if [[ "${CONFIG[ISAL]}" = "y" ]] || [[ "${CONFIG[CRYPTO]}" = "y" ]]; then
709	if [[ "${HAVE_NASM}" = "n" ]] && [[ $arch == x86_64* ]]; then
710		echo "ERROR: ISA-L, compression & crypto require NASM version 2.14 or newer."
711		echo "Please install or upgrade them re-run this script."
712		exit 1
713	else
714		if [[ "${CONFIG[CRYPTO]}" = "y" ]]; then
715			CONFIG[IPSEC_MB]=y
716		fi
717	fi
718fi
719
720if [[ "${CONFIG[PMDK]}" = "y" ]]; then
721	if ! echo -e '#include <libpmemblk.h>\nint main(void) { return 0; }\n' \
722		| "${BUILD_CMD[@]}" -lpmemblk - 2> /dev/null; then
723		echo "--with-pmdk requires libpmemblk."
724		echo "Please install then re-run this script."
725		exit 1
726	fi
727fi
728
729if [[ "${CONFIG[REDUCE]}" = "y" ]]; then
730	if ! echo -e '#include <libpmem.h>\nint main(void) { return 0; }\n' \
731		| "${BUILD_CMD[@]}" -lpmem - 2> /dev/null; then
732		echo "--with-reduce requires libpmem."
733		echo "Please install then re-run this script."
734		exit 1
735	fi
736
737	CONFIG[REDUCE_MLX5]="y"
738	# Check if libmlx5 exists to enable mlx5_pci compress PMD
739	if ! echo -e '#include <spdk/stdinc.h>\n' \
740		'#include <infiniband/mlx5dv.h>\n' \
741		'#include <infiniband/verbs.h>\n' \
742		'int main(void) { return 0; }\n' \
743		| "${BUILD_CMD[@]}" -lmlx5 -I${rootdir}/include -c - 2> /dev/null; then
744		echo "libmlx5 is not found, so disabling DPDK mlx5_pci compress PMD"
745		CONFIG[REDUCE_MLX5]="n"
746	fi
747
748	if [[ "${CONFIG[DPDK_PKG_CONFIG]}" = "y" ]]; then
749		# Check if librte_compress_mlx5 exists in DPDK package
750		if [ ! -f "${CONFIG[DPDK_LIB_DIR]}"/librte_compress_mlx5.so ]; then
751			echo "librte_compress_mlx5 is not found, so disabling DPDK mlx5_pci compress PMD"
752			CONFIG[REDUCE_MLX5]="n"
753		fi
754	else
755		# Check DPDK version to determine if mlx5_pci driver is supported
756		dpdk_ver=""
757		if [[ "${CONFIG[DPDK_DIR]}" == "$rootdir/dpdk/build" ]]; then
758			# DPDK_DIR points at our submodule so ./build may not exist yet. Use
759			# absolute path to lookup the version.
760			dpdk_ver=$(< "$rootdir/dpdk/VERSION")
761		elif [[ -f "${CONFIG[DPDK_DIR]}"/../VERSION ]]; then
762			dpdk_ver=$(< "${CONFIG[DPDK_DIR]}"/../VERSION)
763		else
764			echo "Cannot get DPDK version, so disabling DPDK mlx5_pci compress PMD"
765			CONFIG[REDUCE_MLX5]="n"
766		fi
767		# mlx5_pci is supported by DPDK >- 21.02.0
768		if [[ -n $dpdk_ver ]] && lt "$dpdk_ver" 21.02.0; then
769			echo "DPDK version ${dpdk_ver} doesn't support mlx5_pci compress PMD"
770			CONFIG[REDUCE_MLX5]="n"
771		fi
772	fi
773fi
774
775if [[ "${CONFIG[NVME_CUSE]}" = "y" ]]; then
776	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' \
777		| "${BUILD_CMD[@]}" -lfuse3 -D_FILE_OFFSET_BITS=64 - 2> /dev/null; then
778		echo "--with-cuse requires libfuse3."
779		echo "Please install then re-run this script."
780		exit 1
781	fi
782fi
783
784if [[ "${CONFIG[RBD]}" = "y" ]]; then
785	if ! echo -e '#include <rbd/librbd.h>\n#include <rados/librados.h>\n' \
786		'int main(void) { return 0; }\n' \
787		| "${BUILD_CMD[@]}" -lrados -lrbd - 2> /dev/null; then
788		echo "--with-rbd requires librados and librbd."
789		echo "Please install then re-run this script."
790		exit 1
791	fi
792fi
793
794if [[ "${CONFIG[ISCSI_INITIATOR]}" = "y" ]]; then
795	# Fedora installs libiscsi to /usr/lib64/iscsi for some reason.
796	if ! echo -e '#include <iscsi/iscsi.h>\n#include <iscsi/scsi-lowlevel.h>\n' \
797		'#if LIBISCSI_API_VERSION < 20150621\n' \
798		'#error\n' \
799		'#endif\n' \
800		'int main(void) { return 0; }\n' \
801		| "${BUILD_CMD[@]}" -L/usr/lib64/iscsi -liscsi - 2> /dev/null; then
802		echo "--with-iscsi-initiator requires libiscsi with"
803		echo "LIBISCSI_API_VERSION >= 20150621."
804		echo "Please install then re-run this script."
805		exit 1
806	fi
807fi
808
809if [[ "${CONFIG[ASAN]}" = "y" ]]; then
810	if ! echo -e 'int main(void) { return 0; }\n' \
811		| "${BUILD_CMD[@]}" -fsanitize=address - 2> /dev/null; then
812		echo "--enable-asan requires libasan."
813		echo "Please install then re-run this script."
814		exit 1
815	fi
816fi
817
818if [[ "${CONFIG[UBSAN]}" = "y" ]]; then
819	if ! echo -e 'int main(void) { return 0; }\n' \
820		| "${BUILD_CMD[@]}" -fsanitize=undefined - 2> /dev/null; then
821		echo "--enable-ubsan requires libubsan."
822		echo "Please install then re-run this script."
823		echo "If installed, please check that the GCC version is at least 6.4"
824		echo "and synchronize CC accordingly."
825		exit 1
826	fi
827fi
828
829if [[ "${CONFIG[TSAN]}" = "y" ]]; then
830	if ! echo -e 'int main(void) { return 0; }\n' \
831		| "${BUILD_CMD[@]}" -fsanitize=thread - 2> /dev/null; then
832		echo "--enable-tsan requires libtsan."
833		echo "Please install then re-run this script."
834		exit 1
835	fi
836fi
837
838if [[ "${CONFIG[OCF]}" = "y" ]]; then
839	# If OCF_PATH is a file, assume it is a library and use it to compile with
840	if [ -f ${CONFIG[OCF_PATH]} ]; then
841		CONFIG[CUSTOMOCF]=y
842	else
843		CONFIG[CUSTOMOCF]=n
844	fi
845fi
846
847if [[ "${CONFIG[PGO_CAPTURE]}" = "y" && "${CONFIG[PGO_USE]}" = "y" ]]; then
848	echo "ERROR: --enable-pgo-capture and --enable-pgo-use are mutually exclusive."
849	exit 1
850elif [[ "${CONFIG[PGO_USE]}" = "y" ]]; then
851	if [[ "$CC_TYPE" = "clang" ]]; then
852		# For clang we need to run an extra step on gathered profiling data.
853		echo "Generating suitable profile data"
854		llvm-profdata merge -output=build/pgo/default.profdata build/pgo
855	fi
856fi
857
858if [[ "${CONFIG[URING]}" = "y" ]]; then
859	if [[ -n "${CONFIG[URING_PATH]}" ]]; then
860		if [ ! -d "${CONFIG[URING_PATH]}" ]; then
861			echo "${CONFIG[URING_PATH]}: directory not found"
862			exit 1
863		fi
864	elif ! echo -e '#include <liburing.h>\nint main(void) { return 0; }\n' \
865		| "${BUILD_CMD[@]}" -luring - 2> /dev/null; then
866		echo "--with-uring requires liburing."
867		echo "Please build and install then re-run this script."
868		exit 1
869	fi
870fi
871
872if [[ "${CONFIG[FUSE]}" = "y" ]]; then
873	if [[ ! -d /usr/include/fuse3 ]] && [[ ! -d /usr/local/include/fuse3 ]]; then
874		echo "--with-fuse requires libfuse3."
875		echo "Please install then re-run this script."
876		exit 1
877	fi
878fi
879
880if [ "${CONFIG[CET]}" = "y" ]; then
881	if ! echo -e 'int main(void) { return 0; }\n' | "${BUILD_CMD[@]}" -fcf-protection - 2> /dev/null; then
882		echo "--enable-cet requires compiler/linker that supports CET."
883		echo "Please install then re-run this script."
884		exit 1
885	fi
886fi
887
888if [[ "${CONFIG[ISAL]}" = "y" ]]; then
889	if [ ! -f "$rootdir"/isa-l/autogen.sh ]; then
890		echo "ISA-L was not found; To install ISA-L run:"
891		echo "  git submodule update --init"
892		exit 1
893	fi
894
895	cd $rootdir/isa-l
896	ISAL_LOG=$rootdir/isa-l/spdk-isal.log
897	if [[ -n "${CONFIG[CROSS_PREFIX]}" ]]; then
898		ISAL_OPTS=("--host=${CONFIG[CROSS_PREFIX]}")
899	else
900		ISAL_OPTS=()
901	fi
902	echo -n "Configuring ISA-L (logfile: $ISAL_LOG)..."
903	./autogen.sh &> $ISAL_LOG
904	./configure CFLAGS="-fPIC -g -O2" "${ISAL_OPTS[@]}" --enable-shared=no >> $ISAL_LOG 2>&1
905	echo "done."
906	cd $rootdir
907fi
908
909# For ARM Neoverse-N1 platform, debug build needs gcc version newer than 8.4
910if [[ "${CONFIG[DEBUG]}" = "y" && $arch = aarch64* && "$CC_TYPE" = "gcc" ]]; then
911	GCC_VERSION=$($CC -dumpfullversion)
912	PART_NUM=$(grep -i -m 1 "CPU part" /proc/cpuinfo | awk '{print $4}')
913
914	if [[ "$(printf '%s\n' "8.4.0" "$GCC_VERSION" | sort -V | head -n1)" != "8.4.0" ]]; then
915		if [[ $PART_NUM = 0xd0c ]]; then
916			echo "WARNING: For ARM Neoverse-N1 platform, debug build needs GCC version newer than 8.4."
917			echo "         Will work around this by using armv8.2-a+crypto as target architecture for now."
918			CONFIG[ARCH]=armv8.2-a+crypto
919		fi
920	fi
921fi
922
923# We are now ready to generate final configuration. But first do sanity
924# check to see if all keys in CONFIG array have its reflection in CONFIG file.
925if (($(grep -cE "^\s*CONFIG_[[:alnum:]_]+=" "$rootdir/CONFIG") != ${#CONFIG[@]})); then
926	echo ""
927	echo "BUG: Some configuration options are not present in CONFIG file. Please update this file."
928	echo "Missing options in CONFIG (+) file and in current config (-): "
929	diff -u --label "CONFIG file" --label "CONFIG[@]" \
930		<(sed -r -e '/^[[:space:]]*$/d; /^[[:space:]]*#.*/d; s/(CONFIG_[[:alnum:]_]+)=.*/\1/g' CONFIG | sort) \
931		<(printf "CONFIG_%s\n" "${!CONFIG[@]}" | sort)
932	exit 1
933fi
934
935echo -n "Creating mk/config.mk..."
936cp -f $rootdir/CONFIG $rootdir/mk/config.mk
937for key in "${!CONFIG[@]}"; do
938	sed -i.bak -r "s#[[:space:]]*CONFIG_${key}=.*#CONFIG_${key}\?=${CONFIG[$key]}#g" $rootdir/mk/config.mk
939done
940# On FreeBSD sed -i 'SUFFIX' - SUFFIX is mandatory. So no way but to delete the backed file.
941rm -f $rootdir/mk/config.mk.bak
942echo "done."
943
944# Environment variables
945echo -n "Creating mk/cc.flags.mk..."
946rm -f $rootdir/mk/cc.flags.mk
947[ -n "$CFLAGS" ] && echo "CFLAGS?=$CFLAGS" > $rootdir/mk/cc.flags.mk
948[ -n "$CXXFLAGS" ] && echo "CXXFLAGS?=$CXXFLAGS" >> $rootdir/mk/cc.flags.mk
949[ -n "$LDFLAGS" ] && echo "LDFLAGS?=$LDFLAGS" >> $rootdir/mk/cc.flags.mk
950[ -n "$DESTDIR" ] && echo "DESTDIR?=$DESTDIR" >> $rootdir/mk/cc.flags.mk
951echo "done."
952
953# Create .sh with build config for easy sourcing|lookup during the tests.
954for conf in "${!CONFIG[@]}"; do
955	echo "CONFIG_$conf=${CONFIG[$conf]}"
956done > "$rootdir/test/common/build_config.sh"
957
958if [[ $sys_name == "FreeBSD" ]]; then
959	echo "Type 'gmake' to build."
960else
961	echo "Type 'make' to build."
962fi
963
964exit 0
965