#
#  Common makefile for SCSI target mid-level and its drivers
#
#  Copyright (C) 2015 - 2018 Vladislav Bolkhovitin <vst@vlnb.net>
#  Copyright (C) 2007 - 2018 Western Digital Corporation
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation, version 2
#  of the License.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#  GNU General Public License for more details.
#
#

SHELL := /bin/bash

# Define the location to the kernel src. Can be defined here or on
# the command line during the build process. If KDIR is defined,
# we will determine an appropriate value for KVER from the kernel
# source tree. KVER can still be overridden by the user via the
# command line or by defining it in this Makefile. If KDIR and KVER
# are not defined by the user, the current running kernel version is
# used to define KVER.

ifdef KDIR
    ifndef KVER
        KVER = $(strip $(shell						\
            cat $(KDIR)/include/config/kernel.release 2>/dev/null ||	\
            make -s -C $(KDIR) kernelversion))
    endif
else
    ifndef KVER
        KVER=$(strip $(shell uname -r))
    endif

    KDIR=/lib/modules/$(KVER)/build
endif

PKG_BUILD_MODE ?= 2release

WERROR ?= n
ifneq ($(words $(strip $(WERROR))),1)
$(error WERROR must be one of: y n (got '$(WERROR)'))
endif
ifneq ($(filter y n,$(strip $(WERROR))),$(strip $(WERROR)))
$(error WERROR must be one of: y n (got '$(WERROR)'))
endif
override WERROR := $(strip $(WERROR))
export WERROR

ifeq ($(WERROR),y)
ifeq ($(filter -Werror,$(CFLAGS)),)
override CFLAGS += -Werror
endif
ifeq ($(filter -Werror,$(KCFLAGS)),)
override KCFLAGS += -Werror
endif
export CFLAGS KCFLAGS
endif

OLD_QLA_INI_DIR = qla2x00t
OLD_QLA_DIR = $(OLD_QLA_INI_DIR)/qla2x00-target

NEW_QLA_INI_DIR = qla2x00t-32gbit
NEW_QLA_DIR = $(NEW_QLA_INI_DIR)/qla2x00-target

ifeq ($(QLA_32GBIT),no)
    QLA_INI_DIR = $(OLD_QLA_INI_DIR)
    QLA_DIR = $(OLD_QLA_DIR)
else
    QLA_INI_DIR = $(NEW_QLA_INI_DIR)
    QLA_DIR = $(NEW_QLA_DIR)
endif

SCST_DIR = scst
DOC_DIR = doc
SCSTADM_DIR = scstadmin
USR_DIR = usr
SRP_DIR = srpt
SCST_LOCAL_DIR = scst_local
FCST_DIR = fcst
EMULEX_DIR = emulex
ISCSI_DIR = iscsi-scst

BUILD_DATE := $(shell date -u '+%Y/%m/%d-%H:%M:%S-%Z%:z')
GIT_COMMIT := $(shell git rev-parse --short=12 HEAD 2>/dev/null)

ifndef BUILD_NUMBER
BUILD_NUMBER := $(shell git rev-list --count HEAD 2>/dev/null || echo 0)
endif

ifndef ARCH_TYPE
ARCH_TYPE := $(shell uname -m)
endif

export KVER BUILD_DATE GIT_COMMIT BUILD_NUMBER ARCH_TYPE

RELEASE_VERSION := $(shell echo -n "$$(sed -n 's/^\#define[[:blank:]]SCST_VERSION_NAME[[:blank:]]*\"\([^-]*\).*\"/\1/p' scst/include/scst_const.h)")

ifndef REVISION
	ifneq ($(GIT_COMMIT),)
		REVISION := $(BUILD_NUMBER).$(GIT_COMMIT)
	else
		REVISION := $(BUILD_NUMBER)
	endif
endif

VERSION := $(RELEASE_VERSION).$(REVISION)
DEBIAN_REVISION := 1.1
RPMTOPDIR ?= $(shell if [ $$(id -u) = 0 ]; then echo /usr/src/packages;\
		else echo $$PWD/rpmbuilddir; fi)
DOCKER ?= docker
DOCKER_RPM_TARGET ?= rocky-10.2
DOCKER_RPM_CONTEXT ?= docker/rpm
DOCKER_RPM_DOCKERFILE ?= $(DOCKER_RPM_CONTEXT)/Dockerfile
DOCKER_RPM_IMAGE ?= scst-rpm-builder:$(DOCKER_RPM_TARGET)
DOCKER_RPM_OUTPUT ?= $(CURDIR)/docker-rpmbuilddir/$(DOCKER_RPM_TARGET)
DOCKER_RPM_BASE_IMAGE ?= $(shell bash scripts/kernel/kernel-matrix rpm-field \
		"$(DOCKER_RPM_TARGET)" base_image)
DOCKER_RPM_KERNEL_PACKAGE ?= $(shell bash scripts/kernel/kernel-matrix rpm-field \
		"$(DOCKER_RPM_TARGET)" kernel_package)
DOCKER_RPM_KERNEL_VERSION ?= $(shell bash scripts/kernel/kernel-matrix rpm-field \
		"$(DOCKER_RPM_TARGET)" kernel_version)
DOCKER_RPM_KERNEL_REPOSITORY ?= $(shell bash scripts/kernel/kernel-matrix rpm-field \
		"$(DOCKER_RPM_TARGET)" kernel_repository)
RPM_ARTIFACT_SOURCE_DIR ?= $(CURDIR)
RPM_ARTIFACT_OUTPUT_DIR ?= $(CURDIR)/rpm-artifacts
RPM_ARTIFACT_KERNEL_DEVEL_PACKAGE ?= kernel-devel
SCST_SOURCE_FILES = $(shell if [ -e scripts/source/list-source-files ]; then	\
				scripts/source/list-source-files;		\
			else						\
				echo scripts-source-files-is-missing;	\
			fi)

help:
	@printf '%s\n' \
		'Component tests (see tests/ginkgo/README.md):' \
		'  ginkgo-check                  check the framework without SCST access' \
		'  ginkgo-list                   list tests without SCST access' \
		'  ginkgo-config                 validate GINKGO_CONFIG (JSON file)' \
		'  ginkgo-test                   load built modules, then run tests (root)' \
		'  ginkgo-test-build             build and load modules, then run tests (root)' \
		'  GINKGO_LABEL                  select local, iscsi, basic, stress, scsi or io' \
		'  GINKGO_CONFIG                 component-test configuration file' \
		'' \
		'KUnit tests (see doc/KUNIT.md):' \
		'  kunit-build                   build all SCST KUnit modules' \
		'  kunit-clean                   clean test module builds; keep run reports' \
		'  kunit-list                    show base/composite labels and source suites' \
		'  kunit-run                     run already-built modules (root)' \
		'  kunit-test                    build, then run tests (root)' \
		'  KUNIT_TEST=y|n                include all suites (default: n; kunit-build sets y)' \
		'  KUNIT_LOG=y|n                 compile extra execution messages (default: n)' \
		'  KUNIT_LABEL                   base/composite labels to run (default: ALL)' \
		'  KUNIT_ARGS                    runner/list options; run also accepts module paths' \
		'' \
		'Build variables:' \
		'  WERROR=y|n                    treat warnings as errors (default: n)' \
		'' \
		'Build and maintenance targets:' \
		'  tags                          make tags' \
		'  cov-build                     make coverity build' \
		'  shellcheck                    check Bash scripts' \
		'  analyzer-policy               show shared analyzer input policy (no analysis)' \
		'  ANALYZER                      policy to show (default: common)' \
		'  ANALYZER_FORMAT=text|json     policy output format (default: text)' \
		'  sparse, smatch                analyze configured modules through Kbuild' \
		'  coccicheck                    run kernel Coccinelle report rules' \
		'  cppcheck                      analyze fresh kernel and userspace build contexts' \
		'  checkpatch                    check C source/header style, including KUnit' \
		'  scs_lint                      check SCST code style rules (doc/scs.md)' \
		'  DIFFBR=commit                 compare with one commit; select relevant inputs' \
		'  lint-test                     test shared analyzer tooling (no modules)' \
		'  all                           make all' \
		'  clean                         clean files' \
		'  extraclean                    clean + clean dependencies' \
		'  install                       install' \
		'  uninstall                     uninstall' \
		'  scst                          make scst only' \
		'  scst_clean                    scst: clean' \
		'  scst_extraclean               scst: clean + clean dependencies' \
		'  scst_install                  scst: install' \
		'  scst_uninstall                scst: uninstall' \
		'  docs                          make docs' \
		'  docs_clean                    docs: clean' \
		'  docs_extraclean               docs: clean + clean dependencies' \
		'  scstadm                       make scstadmin' \
		'  scstadm_clean                 scstadmin: clean' \
		'  scstadm_extraclean            scstadmin: clean + clean dependencies' \
		'  scstadm_install               scstadmin: install' \
		'  scstadm_uninstall             scstadmin: uninstall' \
		'  qla                           make QLA target driver' \
		'  qla_clean                     qla target: clean' \
		'  qla_extraclean                qla target: clean + clean dependencies' \
		'  qla_install                   qla target: install' \
		'  qla_uninstall                 qla target: uninstall' \
		'  iscsi                         make iSCSI target' \
		'  iscsi_clean                   ISCSI target: clean' \
		'  iscsi_extraclean              ISCSI target: clean + clean dependencies' \
		'  iscsi_install                 ISCSI target: install' \
		'  iscsi_uninstall               ISCSI target: uninstall' \
		'  emulex                        make Emulex target' \
		'  emulex_clean                  Emulex target: clean' \
		'  emulex_extraclean             Emulex target: clean + clean dependencies' \
		'  emulex_install                Emulex target: install' \
		'  emulex_uninstall              Emulex target: uninstall' \
		'  srpt                          make SRP target' \
		'  srpt_clean                    srp target: clean' \
		'  srpt_extraclean               srp target: clean + clean dependencies' \
		'  srpt_install                  srp target: install' \
		'  srpt_uninstall                srp target: uninstall' \
		'  fcst                          make FCoE target' \
		'  fcst_clean                    FCoE target: clean' \
		'  fcst_extraclean               FCoE target: clean + clean dependencies' \
		'  fcst_install                  FCoE target: install' \
		'  fcst_uninstall                FCoE target: uninstall' \
		'  scst_local                    make scst_local target' \
		'  scst_local_clean              scst_local target: clean' \
		'  scst_local_extraclean         scst_local target: clean + clean dependencies' \
		'  scst_local_install            scst_local target: install' \
		'  scst_local_uninstall          scst_local target: uninstall' \
		'  usr                           make user space targets' \
		'  usr_clean                     usr target: clean' \
		'  usr_extraclean                usr target: clean + clean dependencies' \
		'  usr_install                   usr target: install' \
		'  usr_uninstall                 usr target: uninstall' \
		'  scst-rpm                      make SCST RPM packages' \
		'  scst-dkms-rpm                 make SCST DKMS RPM packages' \
		'  scstadm-rpm                   make scstadmin RPM packages' \
		'  rpm                           make both SCST and scstadmin RPM packages' \
		'  rpm-dkms                      make both SCST DKMS and scstadmin RPM packages' \
		'  rpm-artifacts                 build verified RPM artifacts' \
		'  docker-rpm-image              build the RPM builder Docker image' \
		'  docker-rpm                    build RPM packages in Docker' \
		'  dpkg                          make SCST dpkg packages' \
		'  2perf                         changes debug state to full performance' \
		'  2release                      changes debug state to release' \
		'  2debug                        changes debug state to full debug' \
		'' \
		'Installation and module execution may require root.'

# Resolve the config relative to the caller, before entering tests/ginkgo.
export GINKGO_CONFIG

ginkgo-test-build: export SCST_TEST_KDIR := $(abspath $(KDIR))

ginkgo-check ginkgo-list ginkgo-config ginkgo-test ginkgo-test-build:
	@case "$$GINKGO_CONFIG" in ""|/*) ;; \
		*) GINKGO_CONFIG="$$PWD/$$GINKGO_CONFIG" ;; esac; \
	$(MAKE) -C tests/ginkgo $(patsubst ginkgo-%,%,$@) GINKGO_CONFIG="$$GINKGO_CONFIG"

tags:
	find . -type f -name "*.[ch]" | ctags --c-kinds=+p --fields=+iaS --extra=+q -e -L-

cov-build:
	for d in $(SCST_DIR) $(ISCSI_DIR) $(OLD_QLA_DIR) $(NEW_QLA_DIR)    \
		$(SRP_DIR) $(SCST_LOCAL_DIR) $(FCST_DIR) $(USR_DIR)	   \
		$(SCSTADM_DIR); do					   \
		BUILD_2X_MODULE=y CONFIG_SCSI_QLA_FC=y			   \
		CONFIG_SCSI_QLA2XXX_TARGET=y $(MAKE) -j$$(nproc) -C "$$d" || \
			exit $$?;					   \
	done

shellcheck:
	scripts/source/run-shellcheck

.PHONY: analyzer-policy
analyzer-policy:
	@$(PYTHON) -B scripts/analyzer_policy.py show "$(or $(ANALYZER),common)" --format="$(or $(ANALYZER_FORMAT),text)"

.PHONY: sparse smatch lint-kbuild
sparse smatch: export SCST_LINT_KDIR := $(KDIR)
sparse smatch:
	+@$(PYTHON) -B scripts/sparse_smatch/smp.py $@

.PHONY: coccicheck
coccicheck: export SCST_LINT_KDIR := $(KDIR)
coccicheck:
	+@$(PYTHON) -B scripts/coccinelle/coccicheck.py

.PHONY: checkpatch
checkpatch: export SCST_LINT_KDIR := $(KDIR)
checkpatch:
	@$(PYTHON) -B scripts/style/checkpatch.py

.PHONY: scs_lint scs-lint-test
scs_lint:
	@scripts/scs_lint/run_scs_lint.sh

scs-lint-test:
	@uv run --no-project scripts/scs_lint/test_scs_lint.py

.PHONY: cppcheck lint-userspace
cppcheck: export SCST_LINT_KDIR := $(KDIR)
cppcheck: export SCST_LINT_CC := $(CC)
cppcheck:
	+@$(PYTHON) -B scripts/cppcheck/cppcheck.py

lint-userspace:
	+$(MAKE) -C scst/src ../include/scst_itf_ver.h
	+$(MAKE) -C $(ISCSI_DIR) progs
	+$(MAKE) -C usr/fileio
	+$(MAKE) -C usr/stpgd
	+$(MAKE) -C usr/events

# Preserve dependency order. The newer QLogic base is compiled for its target
# module, but only sources selected by analyzer policy reach the checker.
lint-kbuild:
	+$(MAKE) -C $(SCST_DIR)
	+$(MAKE) -C $(ISCSI_DIR) mods
	+$(MAKE) -C $(NEW_QLA_DIR) BUILD_2X_MODULE=y
	+$(MAKE) -C $(SRP_DIR)
	+$(MAKE) -C $(SCST_LOCAL_DIR)
	+$(MAKE) -C $(FCST_DIR)

.PHONY: lint-test
lint-test:
	PYTHONDONTWRITEBYTECODE=1 $(PYTHON) -m unittest discover -s scripts/tests -v

all clean extraclean install uninstall:
	if [ $@ = extraclean ]; then rm -f TAGS tags cscope.out; fi
	for d in $(SCST_DIR) $(ISCSI_DIR) $(QLA_DIR) $(SRP_DIR)	     \
		$(SCST_LOCAL_DIR) $(FCST_DIR) $(USR_DIR) $(SCSTADM_DIR); do \
		$(MAKE) -j$$(nproc) -C "$$d" $@ || exit $$?;	    \
	done

scst:
	cd $(SCST_DIR) && $(MAKE) all

scst_clean:
	cd $(SCST_DIR) && $(MAKE) clean

scst_extraclean:
	cd $(SCST_DIR) && $(MAKE) extraclean

scst_install:
	cd $(SCST_DIR) && $(MAKE) install

scst_uninstall:
	cd $(SCST_DIR) && $(MAKE) uninstall

docs:
	cd $(DOC_DIR) && $(MAKE) all

docs_clean:
	cd $(DOC_DIR) && $(MAKE) clean

docs_extraclean:
	cd $(DOC_DIR) && $(MAKE) extraclean

scstadm:
	cd $(SCSTADM_DIR) && $(MAKE) all

scstadm_clean:
	cd $(SCSTADM_DIR) && $(MAKE) clean

scstadm_extraclean:
	cd $(SCSTADM_DIR) && $(MAKE) extraclean

scstadm_install:
	cd $(SCSTADM_DIR) && $(MAKE) install

scstadm_uninstall:
	cd $(SCSTADM_DIR) && $(MAKE) uninstall

qla:
	cd $(QLA_DIR) && $(MAKE) all

qla_clean:
	cd $(QLA_DIR) && $(MAKE) clean

qla_extraclean:
	cd $(QLA_DIR) && $(MAKE) extraclean

qla_install:
	cd $(QLA_DIR) && $(MAKE) install

qla_uninstall:
	cd $(QLA_DIR) && $(MAKE) uninstall

iscsi:
	cd $(ISCSI_DIR) && $(MAKE) all

iscsi_clean:
	cd $(ISCSI_DIR) && $(MAKE) clean

iscsi_extraclean:
	cd $(ISCSI_DIR) && $(MAKE) extraclean

iscsi_install:
	cd $(ISCSI_DIR) && $(MAKE) install

iscsi_uninstall:
	cd $(ISCSI_DIR) && $(MAKE) uninstall

emulex:
	cd $(EMULEX_DIR) && $(MAKE) all

emulex_clean:
	cd $(EMULEX_DIR) && $(MAKE) clean

emulex_extraclean:
	cd $(EMULEX_DIR) && $(MAKE) extraclean

emulex_install:
	cd $(EMULEX_DIR) && $(MAKE) install

emulex_uninstall:
	cd $(EMULEX_DIR) && $(MAKE) uninstall

srpt:
	cd $(SRP_DIR) && $(MAKE) all

srpt_clean:
	cd $(SRP_DIR) && $(MAKE) clean

srpt_extraclean:
	cd $(SRP_DIR) && $(MAKE) extraclean

srpt_install:
	cd $(SRP_DIR) && $(MAKE) install

srpt_uninstall:
	cd $(SRP_DIR) && $(MAKE) uninstall

fcst:
	cd $(FCST_DIR) && $(MAKE) all

fcst_clean:
	cd $(FCST_DIR) && $(MAKE) clean

fcst_extraclean:
	cd $(FCST_DIR) && $(MAKE) extraclean

fcst_install:
	cd $(FCST_DIR) && $(MAKE) install

fcst_uninstall:
	cd $(FCST_DIR) && $(MAKE) uninstall

scst_local:
	cd $(SCST_LOCAL_DIR) && $(MAKE) all

scst_local_clean:
	cd $(SCST_LOCAL_DIR) && $(MAKE) clean

scst_local_extraclean:
	cd $(SCST_LOCAL_DIR) && $(MAKE) extraclean

scst_local_install:
	cd $(SCST_LOCAL_DIR) && $(MAKE) install

scst_local_uninstall:
	cd $(SCST_LOCAL_DIR) && $(MAKE) uninstall

usr:
	cd $(USR_DIR) && $(MAKE)

usr_clean:
	cd $(USR_DIR) && $(MAKE) clean

usr_extraclean:
	cd $(USR_DIR) && $(MAKE) extraclean

usr_install:
	cd $(USR_DIR) && $(MAKE) install

usr_uninstall:
	cd $(USR_DIR) && $(MAKE) uninstall

# Make an SCST source code archive. $(1) is the tar compression option, $(2)
# is the tar filename compression suffix, $(3) is the version and $(4) is the
# source file filter.
make-scst-dist =							\
	[ -n "$(1)" ] && [ -n "$(2)" ] && [ -n "$(3)" ] &&		\
	[ -n "$(4)" ] &&						\
	name=scst &&							\
	mkdir "$${name}-$(3)" &&					\
	{								\
	  {								\
	    scripts/source/list-source-files | grep -v '/\.gitignore' &&	\
	    if [ -e debian/changelog ]; then echo debian/changelog; fi;	\
	    if [ -e debian/compat ]; then echo debian/compat; fi;	\
	  } |								\
	  $(4) |							\
	  tar -T- -cf- |						\
	  tar -C "$${name}-$(3)" -xf-;					\
	} &&								\
	rm -f "$${name}-$(3).tar.$(2)" &&				\
	tar -c$(1) -f "$${name}-$(3).tar.$(2)" "$${name}-$(3)" &&	\
	rm -rf "$${name}-$(3)"

scst-dist-gzip: scst-$(VERSION).tar.bz2

scst-$(VERSION).tar.bz2: $(SCST_SOURCE_FILES)
	$(call make-scst-dist,j,bz2,$(VERSION),grep -E '^debian/|^doc/|^fcst/|^iscsi-scst/|^Makefile|^qla2x00t(|-32gbit)/|^scripts/|^scst.spec|^scst/|^scst_local/|^srpt/|^usr/|^scstadmin/')

scst-rpm:
	name=scst &&							\
	rpmtopdir=$(RPMTOPDIR) &&					\
	$(MAKE) scst-dist-gzip &&					\
	for d in BUILD RPMS SOURCES SPECS SRPMS; do			\
	  mkdir -p $${rpmtopdir}/$$d;					\
	done &&								\
	cp scst-$(VERSION).tar.bz2 $${rpmtopdir}/SOURCES &&		\
	sed -e "s/@rpm_version@/$(VERSION)/g"				\
	    -e "s|@depmod@|$(shell which depmod)|g"			\
		<$${name}.spec.in >$${name}.spec &&			\
	MAKE="$(MAKE)" rpmbuild --define="%_topdir $${rpmtopdir}"	\
	    $(if $(KVER),--define="%kversion $(KVER)")			\
	    $(if $(KDIR),--define="%kdir $(KDIR)")			\
	    --define="%pkg_build_mode $(PKG_BUILD_MODE)"		\
	    -ba $${name}.spec &&					\
	rm -f scst-$(VERSION).tar.bz2

scst-dkms-rpm:
	name=scst-dkms &&						\
	rpmtopdir=$(RPMTOPDIR) &&					\
	$(MAKE) scst-dist-gzip &&					\
	for d in BUILD RPMS SOURCES SPECS SRPMS; do			\
	  mkdir -p $${rpmtopdir}/$$d;					\
	done &&								\
	cp scst-$(VERSION).tar.bz2 $${rpmtopdir}/SOURCES &&		\
	sed "s/@rpm_version@/$(VERSION)/g"				\
		<$${name}.spec.in >$${name}.spec &&			\
	MAKE="$(MAKE)" rpmbuild --define="%_topdir $${rpmtopdir}"	\
	    $(if $(KVER),--define="%kversion $(KVER)")			\
	    $(if $(KDIR),--define="%kdir $(KDIR)")			\
	    --define="%pkg_build_mode $(PKG_BUILD_MODE)"		\
	    -ba $${name}.spec &&					\
	rm -f scst-$(VERSION).tar.bz2

scstadm-rpm:
	$(MAKE) -C scstadmin rpm

rpm:
	$(MAKE) scst-rpm
	$(MAKE) scstadm-rpm
	@if [ "$$(id -u)" != 0 ]; then			\
	    echo;					\
	    echo "The following RPMs have been built:";	\
	    find -name '*.rpm';				\
	fi

rpm-dkms:
	$(MAKE) scst-dkms-rpm
	$(MAKE) scstadm-rpm
	@if [ "$$(id -u)" != 0 ]; then			\
	    echo;					\
	    echo "The following RPMs have been built:";	\
	    find -name '*.rpm';				\
	fi

rpm-artifacts:
	mkdir -p "$(RPM_ARTIFACT_OUTPUT_DIR)"
	RPM_ARTIFACT_SOURCE_DIR="$(RPM_ARTIFACT_SOURCE_DIR)" \
	RPM_ARTIFACT_OUTPUT_DIR="$(RPM_ARTIFACT_OUTPUT_DIR)" \
	RPM_ARTIFACT_KERNEL_DEVEL_PACKAGE="$(RPM_ARTIFACT_KERNEL_DEVEL_PACKAGE)" \
		bash "$(CURDIR)/scripts/release/build-rpm-artifacts"

docker-rpm-image:
	test -n "$(DOCKER_RPM_BASE_IMAGE)"
	test -n "$(DOCKER_RPM_KERNEL_PACKAGE)"
	test -n "$(DOCKER_RPM_KERNEL_VERSION)"
	$(DOCKER) build --file "$(DOCKER_RPM_DOCKERFILE)" \
		--build-arg "BASE_IMAGE=$(DOCKER_RPM_BASE_IMAGE)" \
		--build-arg "KERNEL_PACKAGE=$(DOCKER_RPM_KERNEL_PACKAGE)" \
		--build-arg "KERNEL_VERSION=$(DOCKER_RPM_KERNEL_VERSION)" \
		--build-arg \
			"KERNEL_REPOSITORY=$(DOCKER_RPM_KERNEL_REPOSITORY)" \
		--tag "$(DOCKER_RPM_IMAGE)" "$(DOCKER_RPM_CONTEXT)"

docker-rpm: docker-rpm-image
	mkdir -p "$(DOCKER_RPM_OUTPUT)"
	git_common_dir="$$(git rev-parse --path-format=absolute \
		--git-common-dir)" && \
	$(DOCKER) run --rm \
		--user "$$(id -u):$$(id -g)" \
		--env HOME=/tmp \
		--env WERROR="$(WERROR)" \
		--mount "type=bind,source=$(CURDIR),target=/source,readonly" \
		--mount "type=bind,source=$${git_common_dir},target=$${git_common_dir},readonly" \
		--mount "type=bind,source=$(DOCKER_RPM_OUTPUT),target=/output" \
		"$(DOCKER_RPM_IMAGE)" \
		make -C /source rpm-artifacts \
			RPM_ARTIFACT_SOURCE_DIR=/source \
			RPM_ARTIFACT_OUTPUT_DIR=/output \
			RPM_ARTIFACT_KERNEL_DEVEL_PACKAGE="$(DOCKER_RPM_KERNEL_PACKAGE)-devel"

debian/changelog: debian/changelog.in
	sed 's/%{scst_version}/$(VERSION)-$(DEBIAN_REVISION)/'		\
	  <debian/changelog.in >debian/changelog

debian/compat:
	version=$$(dpkg-query -W --showformat='$${Version}\n' debhelper) && \
	printf '%s\n' "$${version%%.*}" >$@

../scst_$(VERSION).orig.tar.gz: debian/changelog debian/compat Makefile	\
		$(SCST_SOURCE_FILES)
	$(call make-scst-dist,z,gz,$(VERSION),cat) &&			\
	mv "scst-$(VERSION).tar.gz" "$@"

../scst_$(VERSION).orig.tar.xz: debian/changelog debian/compat Makefile	\
		$(SCST_SOURCE_FILES)
	$(call make-scst-dist,J,xz,$(VERSION),cat) &&			\
	mv "scst-$(VERSION).tar.xz" "$@"

dpkg: ../scst_$(VERSION).orig.tar.gz
	@[ -n "$$DEBEMAIL" ] || export DEBEMAIL=bvanassche@acm.org &&	\
	[ -n "$$DEBFULLNAME" ] || export DEBFULLNAME="Bart Van Assche" &&\
	echo "KDIR=$(KDIR)" &&						\
	echo "KVER=$(KVER)" &&						\
	sed 's/%{scst_version}/$(VERSION)/'				\
	  <debian/scst.dkms.in >debian/scst.dkms &&			\
	sed 's/%{KVER}/$(KVER)/'					\
	  <debian/scst.preinst.in >debian/scst.preinst &&		\
	sed 's/%{KVER}/$(KVER)/'					\
	  <debian/scst.postinst.in >debian/scst.postinst &&		\
	output_files=(							\
		../*_$(VERSION)-$(DEBIAN_REVISION)_*.deb		\
		../*_$(VERSION)-$(DEBIAN_REVISION)_*.ddeb		\
		../scst_$(VERSION)-$(DEBIAN_REVISION).debian.tar.[gx]z	\
		../scst_$(VERSION)-$(DEBIAN_REVISION).dsc		\
		../scst_$(VERSION)-$(DEBIAN_REVISION)_amd64.build	\
		../scst_$(VERSION)-$(DEBIAN_REVISION)_amd64.buildinfo	\
		../scst_$(VERSION)-$(DEBIAN_REVISION)_amd64.changes	\
	) &&								\
	rm -f "$${output_files[@]}" &&					\
	buildopts=(-uc -us) &&						\
	if dpkg-buildpackage --help 2>&1 | grep -q -- '-ui'; then	\
	  buildopts+=(-ui);						\
	fi &&								\
	if dpkg-buildpackage --help 2>&1 |				\
	   grep -q -- '--jobs\[=<number>|auto\]'; then			\
	  buildopts+=(-jauto);						\
	else								\
	  buildopts+=(-j4);						\
	fi &&								\
	DEB_CC_SET="$(CC)" DEB_KVER_SET=$(KVER) DEB_KDIR_SET=$(KDIR) \
	   DEB_QLA_DIR_SET=$(QLA_DIR) DEB_QLA_INI_DIR_SET=$(QLA_INI_DIR) \
	   DEB_PKG_BUILD_MODE=$(PKG_BUILD_MODE) DEB_WERROR_SET="$(WERROR)" \
	   debuild "$${buildopts[@]}" --lintian-opts --profile debian && \
	mkdir -p dpkg &&						\
	for f in "$${output_files[@]}" ../scst_$(VERSION).orig.tar.[gx]z; do\
		mv $$f dpkg || true;					\
	done &&								\
	echo "Output files:" &&						\
	ls -l dpkg

release-archive:
	$(MAKE) 2release
	scripts/release/generate-release-archive scst "$(RELEASE_VERSION)"
	md5sum ../scst-$(RELEASE_VERSION).tar.bz2	\
	  > ../scst-$(RELEASE_VERSION).tar.bz2.md5sum
	$(MAKE) 2debug

multiple-release-archives:
	$(MAKE) 2release
	for m in $$(find -name Makefile |			\
		    xargs grep -l '^release-archive:' |		\
		    grep -v '^\./Makefile');			\
	do							\
	    (cd $$(dirname $$m) && $(MAKE) release-archive)	\
	done
	$(MAKE) 2debug

2perf:
	cd $(SCST_DIR) && $(MAKE) $@

2release:
	cd $(SCST_DIR) && $(MAKE) $@

2debug:
	cd $(SCST_DIR) && $(MAKE) $@

.PHONY: help tags cov-build shellcheck all clean extraclean install uninstall \
	ginkgo-check ginkgo-list ginkgo-config ginkgo-test ginkgo-test-build \
	scst scst_clean scst_extraclean scst_install scst_uninstall \
	docs docs_clean docs_extraclean \
	scstadm scstadm_clean scstadm_extraclean scstadm_install scstadm_uninstall \
	qla qla_clean qla_extraclean qla_install qla_uninstall \
	iscsi iscsi_clean iscsi_extraclean iscsi_install iscsi_uninstall \
	emulex emulex_clean emulex_extraclean emulex_install emulex_uninstall \
	srpt srpt_clean srpt_extraclean srpt_install srpt_uninstall \
	fcst fcst_clean fcst_extraclean fcst_install fcst_uninstall \
	scst_local scst_local_clean scst_local_extraclean scst_local_install scst_local_uninstall \
	usr usr_clean usr_extraclean usr_install usr_uninstall \
	scst-rpm scst-dkms-rpm scstadm-rpm rpm rpm-dkms rpm-artifacts \
	docker-rpm-image docker-rpm dpkg \
	2perf 2release 2debug

include scst/src/kunit/select.mk

PYTHON ?= python3

.PHONY: kunit-build kunit-clean kunit-run kunit-test

kunit-clean: scst-kunit-clean-files
	@for target in $(SCST_KUNIT_COMPONENTS); do \
		$(MAKE) -C "$$target" clean || exit $$?; \
	done

kunit-build:
	@rm -f .kunit-modules .kunit-modules.tmp
	@echo "Building all SCST KUnit tests"
	@for target in $(SCST_KUNIT_COMPONENTS); do \
		$(MAKE) -C "$$target" kunit-build KUNIT_TEST=y || exit $$?; \
	done
	@for module in $(SCST_KUNIT_MODULES); do \
		test -f "$$module" || { echo "Missing built module: $$module"; exit 2; }; \
	done
	@printf '%s\n' $(SCST_KUNIT_MODULES) > .kunit-modules.tmp
	@mv .kunit-modules.tmp .kunit-modules

# Build and run sequentially even under make -j.
kunit-test:
	@$(MAKE) kunit-build
	@$(MAKE) kunit-run

kunit-run:
	@$(PYTHON) scripts/kunit/run.py --labels "$(KUNIT_LABEL)" $(KUNIT_ARGS)
