#!/usr/bin/make -f

include /usr/share/dpkg/architecture.mk
include /usr/share/dpkg/pkg-info.mk
include /usr/share/dpkg/buildtools.mk


export DEB_BUILD_MAINT_OPTIONS = hardening=+all

builtins := /usr/share/nodejs/node

# source equivalent of nodejs -e 'console.log(process.versions.modules)'
ABI = $(shell awk '/^#define NODE_MODULE_VERSION [0-9]+/ {print $$3}' src/node_version.h)

# archs
ARCHS := amd64 arm64 armel armhf i386 mips64el mips64r6el loong64 ppc64 ppc64el riscv64 s390x

# branch
BRANCH := $(word 1, $(subst .,$(space), $(DEB_UPSTREAM_VERSION)))

LANG=C
export LANG
DEB_CONFIGURE_NORMAL_ARGS =
DEB_CONFIGURE_EXTRA_FLAGS = \
--verbose \
--without-npm \
--without-corepack \
--shared \
--shared-zlib \
--shared-cares \
--shared-ngtcp2 \
--shared-nghttp3 \
--shared-nghttp2 \
--shared-brotli \
--shared-libuv \
--shared-simdjson \
--shared-builtin-undici/undici-path=/usr/share/nodejs/undici/undici-fetch.js \
--shared-builtin-acorn-path=/usr/share/nodejs/acorn/dist/acorn.js \
--shared-builtin-acorn_walk-path=/usr/share/nodejs/acorn-walk/dist/walk.js \
--shared-builtin-cjs_module_lexer/lexer-path=/usr/share/nodejs/cjs-module-lexer/lexer.js \
--shared-builtin-cjs_module_lexer/dist/lexer-path=/usr/share/nodejs/cjs-module-lexer/dist/lexer.js \
--shared-builtin-minimatch-path=/usr/share/nodejs/minimatch/dist/cjs/index.bundle.js \
--shared-openssl \
--openssl-use-def-ca-store \
--with-intl=system-icu \
--prefix=/usr \
--arch-triplet=$(DEB_HOST_MULTIARCH) \
--node-relative-path="lib/$(DEB_HOST_MULTIARCH)/nodejs:share/nodejs" \
--dest-os=linux

ifneq ($(filter pkg.nodejs.nobuiltin,$(DEB_BUILD_PROFILES)),)
	DEB_CONFIGURE_EXTRA_FLAGS += --node-builtin-modules-path=$(builtins)
endif

# map HOST ARCH AND OS, and if unknown let upstream guess

destCpu =
destCpu := $(or $(destCpu),$(if $(filter i386,$(DEB_HOST_ARCH)),ia32))
destCpu := $(or $(destCpu),$(if $(filter x32,$(DEB_HOST_ARCH)),x32))
destCpu := $(or $(destCpu),$(if $(filter hurd-i386,$(DEB_HOST_ARCH)),ia32))
destCpu := $(or $(destCpu),$(if $(filter amd64,$(DEB_HOST_ARCH)),x64))
destCpu := $(or $(destCpu),$(if $(filter armel,$(DEB_HOST_ARCH)),arm))
destCpu := $(or $(destCpu),$(if $(filter armhf,$(DEB_HOST_ARCH)),arm))
destCpu := $(or $(destCpu),$(if $(filter aarch64,$(DEB_HOST_ARCH)),arm64))
destCpu := $(or $(destCpu),$(if $(filter mips64el,$(DEB_HOST_ARCH)),mips64el))
destCpu := $(or $(destCpu),$(if $(filter mips64r6el,$(DEB_HOST_ARCH)),mips64el))
destCpu := $(or $(destCpu),$(if $(filter loong64,$(DEB_HOST_ARCH)),loong64))
destCpu := $(or $(destCpu),$(if $(filter powerpc,$(DEB_HOST_ARCH)),ppc))
destCpu := $(or $(destCpu),$(if $(filter ppc64,$(DEB_HOST_ARCH)),ppc64))
destCpu := $(or $(destCpu),$(if $(filter riscv64,$(DEB_HOST_ARCH)),riscv64))
destCpu := $(or $(destCpu),$(if $(filter s390x,$(DEB_HOST_ARCH)),s390x))

ifneq (, $(destCpu))
DEB_CONFIGURE_EXTRA_FLAGS += --dest-cpu=$(destCpu)
endif

# mips32r1 or greater, detected at runtime
ifeq (mips64el, $(DEB_HOST_ARCH))
DEB_CONFIGURE_EXTRA_FLAGS += --with-mips-arch-variant=rx --with-mips-fpu-mode=fp64
CFLAGS += -gsplit-dwarf
CPPFLAGS += -gsplit-dwarf
endif
ifeq (mips64r6el, $(DEB_HOST_ARCH))
DEB_CONFIGURE_EXTRA_FLAGS += --with-mips-arch-variant=rx --with-mips-fpu-mode=fp64
CFLAGS += -gsplit-dwarf
CPPFLAGS += -gsplit-dwarf
endif

ifeq (armel, $(DEB_HOST_ARCH))
DEB_CONFIGURE_EXTRA_FLAGS += --with-arm-float-abi=softfp
ifeq ($(shell dpkg-vendor --is ubuntu && echo true),true)
# Ubuntu targets armv7+ with VFP and thumb2 support by default for armel
DEB_CONFIGURE_EXTRA_FLAGS += --with-arm-fpu=vfpv3
else
# debian armel version
# v8 supports armv6k (must be set explicitely) + vfpv2 (selected by default)
# armv6k is only not available on ARM1136JF-S r0p2, and available on r1p0.
DEB_CONFIGURE_EXTRA_FLAGS += --with-arm-fpu=vfpv2 --with-arm-version=6
CFLAGS += -march=armv6k -mfpu=vfpv2
CPPFLAGS += -march=armv6k -mfpu=vfpv2
endif
endif

ifeq (armhf, $(DEB_HOST_ARCH))
DEB_CONFIGURE_EXTRA_FLAGS += --with-arm-float-abi=hard
ifeq ($(shell dpkg-vendor --derives-from raspbian && echo true),true)
# enable vfp, disable armv7
DEB_CONFIGURE_EXTRA_FLAGS += --with-arm-fpu=vfp
else
# enable armv7 vfpv3-d16
DEB_CONFIGURE_EXTRA_FLAGS += --with-arm-fpu=vfpv3-d16
endif
endif

DEB_DESTDIR = $(CURDIR)/debian/tmp
DEB_MAKE_CLEAN_TARGET = clean
DEB_MAKE_BUILD_TARGET = build

#  relax regression tests when targeted experimental suite
skipTests =
# tests require undici >= 6.5.0
skipTests := $(skipTests),parallel/test-eventsource
# tests using npm
skipTests := $(skipTests),parallel/test-npm-install
skipTests := $(skipTests),parallel/test-npm-version
skipTests := $(skipTests),parallel/test-release-npm
# tests using network
skipTests := $(skipTests),parallel/test-dns
skipTests := $(skipTests),parallel/test-net-connect-immediate-finish
skipTests := $(skipTests),parallel/test-net-better-error-messages-port-hostname
skipTests := $(skipTests),parallel/test-https-connect-address-family
skipTests := $(skipTests),parallel/test-tls-connect-address-family
skipTests := $(skipTests),parallel/test-dns-cancel-reverse-lookup
skipTests := $(skipTests),parallel/test-dns-resolveany-bad-ancount
# bad test
skipTests := $(skipTests),parallel/test-child-process-stdio-overlapped
# requires corepack
skipTests := $(skipTests),parallel/test-corepack-yarn-install
skipTests := $(skipTests),parallel/test-corepack-version
# fail on buildd
skipTests := $(skipTests),sequential/test-force-repl
skipTests := $(skipTests),sequential/test-performance
# flaky on buildd https://github.com/nodejs/node/issues/39655
skipTests := $(skipTests),parallel/test-cluster-primary-error
skipTests := $(skipTests),parallel/test-cluster-primary-kill
# hangs https://github.com/nodejs/node/issues/44898
skipTests := $(skipTests),sequential/test-watch-mode
skipTests := $(skipTests),sequential/test-watch-mode-inspect
# CVE-2024-22017 shared libuv cannot guarantee io_uring is disabled
skipTests := $(skipTests),parallel/test-process-uid-gid
skipTests := $(skipTests),parallel/test-process-initgroups
skipTests := $(skipTests),parallel/test-process-setgroups
skipTests := $(skipTests),parallel/test-process-euid-egid
# sea requires postject
skipTests := $(skipTests),parallel/test-single-executable-application
# loading of openssl for tests make this test fail
skipTests := $(skipTests),parallel/test-strace-openat-openssl

export HOME = $(CURDIR)/tmp
export FLAKY_TESTS = dontcare
export CI_JS_SUITES = message parallel sequential
export NODE_TEST_DIR = $(CURDIR)/tmp
export NODE_TEST_NO_INTERNET = 1
# needed for tests to avoid "ee key too small" errors
export OPENSSL_CONF = $(CURDIR)/debian/openssl.cnf
# keep in mind ./debian/rules check is also invoked by adt-run, see debian/tests/
exp-relax-check := $(if $(shell dpkg-parsechangelog | grep -x 'Distribution: \(experimental\|UNRELEASED\)'),-i)
DEB_MAKE_CHECK_TARGET = $(exp-relax-check) test-ci-js
export CI_SKIP_TESTS = $(skipTests)
TEST_CI_ARGS = --arch=$(destCpu) --timeout=3000

# override Node.js path when running under adt-run (no build directory present)
ifeq (,$(wildcard $(CURDIR)/out))
TEST_CI_ARGS += --shell=/usr/bin/node
else
TEST_CI_ARGS += --shell=out/Release/node
endif
export TEST_CI_ARGS

# build -fPIC
CFLAGS += -fPIC
CPPFLAGS += -fPIC

ifeq ($(DEB_HOST_ARCH_BITS),32)
CFLAGS += -g1
CPPFLAGS += -g1
DH_FLAGS += --max-parallel=1
export JOBS = 1
else
CFLAGS += -g
CPPFLAGS += -g
endif


# hardening gyp
CXXFLAGS += $(CPPFLAGS)

export CPPFLAGS
export CXXFLAGS
export CFLAGS
export LDFLAGS

export PYTHON = python3

%:
	dh $@ $(DH_FLAGS)

# properly clean files from build, test, python
execute_after_dh_auto_clean:
	rm -f node_trace.1.log
	rm -f icu_config.gypi
	rm -rf test/addons/doc-*
	rm -f test/addons/.buildstamp
	rm -f test/addons/.docbuildstamp
	rm -rf test/addons/*/build
	rm -f config.gypi
	rm -f config.mk
	rm -f config.status
	rm -f test/fixtures/hello.txt
	rm -rf $(NODE_TEST_DIR)
	find . -name "*.pyc" -delete
	rm -rf out
	rm -rf node_modules
	rm -f debian/libnode$(ABI).install
	rm -f debian/libnode-dev.links
	rm -f debian/nodejs.install
	rm -f debian/nodejs.bash-completion
	rm -rf deps/openssl/

# remove *.json files from documentation
execute_after_dh_installdocs:
	find debian/nodejs-doc/usr/share/doc/nodejs-doc -name *.json -delete || true

override_dh_auto_configure:
# gyp    | debian
# -------+-------
# target | host
# host   | build

ifneq ($(DEB_BUILD_ARCH),$(DEB_HOST_ARCH))
	CC=$(CC) CXX=$(CXX) PKG_CONFIG=$(PKG_CONFIG) CC_host=$(CC_FOR_BUILD) CXX_host=$(CXX_FOR_BUILD) ./configure --cross-compiling $(DEB_CONFIGURE_EXTRA_FLAGS)
else
	./configure $(DEB_CONFIGURE_EXTRA_FLAGS)
endif

execute_before_dh_auto_build-arch:
	mkdir -p deps/openssl/ && touch deps/openssl/nodejs-openssl.cnf
	pkver=`dpkg-query --showformat='$${source:Upstream-Version}' --show node-acorn | sed -E 's/^([0-9]+\.[0-9]+\.[0-9]+).*/\1/g'`; \
	sed -i -e "s/[0-9]\+\.[0-9]\+\.[0-9]\+/$${pkver}/" src/acorn_version.h
	pkver=`dpkg-query --showformat='$${source:Upstream-Version}' --show node-cjs-module-lexer | sed -E 's/^([0-9]+\.[0-9]+\.[0-9]+).*/\1/g'`; \
	sed -i -e "s/[0-9]\+\.[0-9]\+\.[0-9]\+/$${pkver}/" src/cjs_module_lexer_version.h
	pkver=`dpkg-query --showformat='$${source:Upstream-Version}' --show node-undici | sed -E 's/^([0-9]+\.[0-9]+\.[0-9]+).*/\1/g'`; \
	sed -i -e "s/[0-9]\+\.[0-9]\+\.[0-9]\+/$${pkver}/" src/undici_version.h

execute_after_dh_auto_build-arch:
ifeq ($(filter nodoc,$(DEB_BUILD_PROFILES)),)
	./out/Release/node --completion-bash > ./debian/nodejs.bash-completion
endif

override_dh_auto_build-indep:
	mkdir -p node_modules
	ln -sf /usr/share/nodejs/marked node_modules/
	ln -sf /usr/share/nodejs/acorn node_modules/
	ln -sf /usr/share/nodejs/js-yaml node_modules/
	ln -sf /usr/share/nodejs/cjs-module-lexer node_modules/
	ln -sf /usr/share/nodejs/minimatch node_modules/
	$(MAKE) doc-only

override_dh_auto_test-indep:
	# skip tests

override_dh_auto_test-arch:
ifeq ($(filter nocheck,$(DEB_BUILD_PROFILES)),)
	mkdir -p $(NODE_TEST_DIR)
	$(MAKE) $(DEB_MAKE_CHECK_TARGET)
	rm -rf $(NODE_TEST_DIR)
endif

override_dh_auto_install-indep:
	# skip install all

override_dh_auto_install-arch:
	dh_auto_install

override_dh_install-arch:
	sed 's/@DEB_HOST_MULTIARCH@/$(DEB_HOST_MULTIARCH)/g' debian/libnode.install.in > debian/libnode$(ABI).install
	sed -e 's/@DEB_HOST_MULTIARCH@/$(DEB_HOST_MULTIARCH)/g' -e 's/@ABI@/$(ABI)/g' debian/libnode-dev.links.in > debian/libnode-dev.links
	cp debian/nodejs.install.in debian/nodejs.install
ifneq ($(filter pkg.nodejs.nobuiltin,$(DEB_BUILD_PROFILES)),)
	echo "./lib $(builtins)/" >> debian/nodejs.install
	deps_files="$(shell $(PYTHON) -c "import ast; d = ast.literal_eval(open('node.gyp').read()); print(' '.join(d['variables']['deps_files'][:-1]));")"; \
	for src in $$deps_files; do \
		dst=`dirname $$src`; \
		echo "./$$src $(builtins)/$$dst" >> debian/nodejs.install; \
	done
endif
	dh_install

override_dh_dwz:
	# Double up the limit of debug information entries
	# Also, ignore failures (on 32-bit archs it might fail)
	-dh_dwz -- --max-die-limit 100000000

override_dh_gencontrol:
	dh_gencontrol -- \
	 -V"types:Node=$(shell jq --raw-output .version <types-node/package.json)~$(DEB_VERSION)"

execute_after_dh_fixperms-arch:
	find $(CURDIR)/debian/nodejs/usr/share/nodejs/@types/node -type f -exec chmod a-x '{}' \;
