-- stop hard-coding dpkg_datadir
> to avoid changing all pathname concatenation I changed dpkg_datadir to
> «$(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))». But given that
> I think we might still need to substitute other things I've left this
> one out for now.

A rebased and slightly less intrusive version is attached.

-- scripts/mk/buildopts.mk: small optimisations
> I've left this one out as it is kind of an API change. I think it

The tradition in Make APIs is to condider that "undefined" and "empty"
are equivalent.  I dislike this tradition, but it is widely accepted
and there were precedents in scripts/mk/*.mk.

> might perhaps make more sense to fallback to setting it to 1 if it's
> missing, but I need to ponder about possible consequences/fallout, etc.

In case you decide to keep an undefined (or empty :-) value by
default, I suggest to add a commented example:
# $(MAKE) $(addprefix -j,$(DEB_BUILD_OPTION_PARALLEL))
# SPHINXDOC += $(addprefix -j,$(DEB_BUILD_OPTION_PARALLEL))
$(addprefix) avoids an explicit test, which is exactly the purpose of
DEB_BUILD_OPTION_PARALLEL as far as I understand.

-- scripts/mk: reduce the number of subprocesses
> I've left this one out for now. I'm not entirely satisfied with the
> sed usage here. If we keep using sed, then I think it needs to be set
> via a SED variable, substituted from the value found at configure
> time. But then, I've been pondering whether we can have better export

That is right only for packages using autoconf, but even then, how do
you get $(SED) from debian/rules?

Even autoconf-generated ./configure scripts assume that a minimal 'sed'
is available, so I think we can do the same when building a Debian
package.

> formats, that might make the sed usage not necessary. I started with a
> make-eval export mode for buildflags, but perhaps it would be better a
> more generic formatting mode where the caller can specify how the
> output should look like, akin «dpkg-query --showformat». Will ponder
> about this.

For me, the main problem is not whether COMMAND=dpkg-buildflags or
COMMAND=dpkg-buildflags|sed, but Make itself.
$(shell COMMAND) replaces line terminators with spaces, and then
removes duplicate spaces.

If we want to invoke COMMAND at most once for all variables, its ouput
should contain multiple Make assignments.  Make assignments are
usually separated by line terminators, which are unavailable, so I
have embedded each assignment in its own $(eval).
In other words, I have used balanced parenthesis as separators.
This seems a sensible compromise for build flags.

The ideal solution would set Make variables with raw values,
but I see no simple way.

One could define ad-hoc variables like

  space := $(undefined) $(undefined)
  define new_line :=


  endef

that the output of COMMAND can $$(embed), but then you also need
$(equal), $(colon), $(openparenthesis) and so on :-)

A temporary file intended for inclusion by debian/rules solves most
escaping problems, but adds complexity.

-- scripts/mk: protect against repeated inclusion
> dedicated variable instead of reusing the existing ones, in case the

Fixed in the attached commit.

-- scripts/mk: improve details in documentation
> I've left this one out for now. The version information was added on
> purpose to help people know when each interface or file was added, so

Fixed in the attached commit (sorry, I thought that we were not
supporting anything before oldoldstable).

Thanks for the answers.
>From 043f2cd6b8c445a2f0667260a2e4fabbe2e2488b Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <nico...@debian.org>
Date: Mon, 29 Jul 2019 14:38:32 +0200
Subject: [PATCH 1/6] scripts/mk: stop hard-coding dpkg_datadir

The Makefile snippets include each other from their common directory,
but the path differ during tests and after installation.  Instead of
rewriting the file with a hardcoded path, compute it within Make.
---
 build-aux/subst.am       |  6 ------
 scripts/mk/Makefile.am   | 16 ----------------
 scripts/mk/buildtools.mk |  2 +-
 scripts/mk/default.mk    |  2 +-
 4 files changed, 2 insertions(+), 24 deletions(-)

diff --git a/build-aux/subst.am b/build-aux/subst.am
index 74a40bf0b..4cd4bdca8 100644
--- a/build-aux/subst.am
+++ b/build-aux/subst.am
@@ -38,9 +38,3 @@ SUFFIXES += .pl
 	@test -d `dirname $@` || $(MKDIR_P) `dirname $@`
 	$(do_perl_subst) <$< >$@
 	$(AM_V_at) chmod +x $@
-
-# Makefile support.
-
-do_make_subst = $(AM_V_GEN) $(SED) \
-	-e "s:dpkg_datadir[[:space:]]*=[[:space:]]*[^[:space:]]*:dpkg_datadir = $(pkgdatadir):" \
-	# EOL
diff --git a/scripts/mk/Makefile.am b/scripts/mk/Makefile.am
index a82e409d6..0c635bf00 100644
--- a/scripts/mk/Makefile.am
+++ b/scripts/mk/Makefile.am
@@ -9,19 +9,3 @@ dist_pkgdata_DATA = \
 	pkg-info.mk \
 	vendor.mk \
 	# EOL
-
-SUFFIXES =
-
-include $(top_srcdir)/build-aux/subst.am
-
-# Ideally we'd use '$(SED) -i', but unfortunately that's not portable.
-install-data-hook:
-	$(do_make_subst) <$(DESTDIR)$(pkgdatadir)/default.mk \
-	                 >$(DESTDIR)$(pkgdatadir)/default.mk.new
-	mv $(DESTDIR)$(pkgdatadir)/default.mk.new \
-	   $(DESTDIR)$(pkgdatadir)/default.mk
-
-	$(do_make_subst) <$(DESTDIR)$(pkgdatadir)/buildtools.mk \
-	                 >$(DESTDIR)$(pkgdatadir)/buildtools.mk.new
-	mv $(DESTDIR)$(pkgdatadir)/buildtools.mk.new \
-	   $(DESTDIR)$(pkgdatadir)/buildtools.mk
diff --git a/scripts/mk/buildtools.mk b/scripts/mk/buildtools.mk
index ea5082935..02c16ec92 100644
--- a/scripts/mk/buildtools.mk
+++ b/scripts/mk/buildtools.mk
@@ -26,7 +26,7 @@
 # The variables are not exported by default. This can be changed by
 # defining DPKG_EXPORT_BUILDTOOLS.
 
-dpkg_datadir = $(srcdir)/mk
+dpkg_datadir ?= $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
 include $(dpkg_datadir)/architecture.mk
 
 # We set the TOOL_FOR_BUILD variables to the specified value, and the TOOL
diff --git a/scripts/mk/default.mk b/scripts/mk/default.mk
index 3916a0c24..095128470 100644
--- a/scripts/mk/default.mk
+++ b/scripts/mk/default.mk
@@ -1,7 +1,7 @@
 # This Makefile fragment (since dpkg 1.16.1) includes all the Makefile
 # fragments that define variables that can be useful within debian/rules.
 
-dpkg_datadir = $(srcdir)/mk
+dpkg_datadir := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
 include $(dpkg_datadir)/architecture.mk
 include $(dpkg_datadir)/buildflags.mk
 include $(dpkg_datadir)/buildopts.mk
-- 
2.30.2

>From 34fcdfa1c614e4a53b9e69a47d2aff68aeaf6e5f Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <nico...@debian.org>
Date: Thu, 11 Feb 2021 16:09:48 +0100
Subject: [PATCH 2/6] scripts/t: use loops instead of repetitions, check
 exports and overrides

Replace copied lines with Make loops.

Add tests: architecture variable override, buildflags set and export,
buildtool override and export.
---
 scripts/t/mk/architecture.mk | 57 +++++++++++++-------------------
 scripts/t/mk/buildflags.mk   | 38 +++++++++++++++-------
 scripts/t/mk/buildtools.mk   | 63 +++++++++++++++++-------------------
 3 files changed, 79 insertions(+), 79 deletions(-)

diff --git a/scripts/t/mk/architecture.mk b/scripts/t/mk/architecture.mk
index 2ac0222ca..a938a6d6c 100644
--- a/scripts/t/mk/architecture.mk
+++ b/scripts/t/mk/architecture.mk
@@ -1,36 +1,25 @@
+DEB_BUILD_ARCH := overridden
+
 include $(srcdir)/mk/architecture.mk
 
-test:
-	test "$(DEB_BUILD_ARCH)" = "$(TEST_DEB_BUILD_ARCH)"
-	test "$(DEB_BUILD_ARCH_ABI)" = "$(TEST_DEB_BUILD_ARCH_ABI)"
-	test "$(DEB_BUILD_ARCH_BITS)" = "$(TEST_DEB_BUILD_ARCH_BITS)"
-	test "$(DEB_BUILD_ARCH_CPU)" = "$(TEST_DEB_BUILD_ARCH_CPU)"
-	test "$(DEB_BUILD_ARCH_ENDIAN)" = "$(TEST_DEB_BUILD_ARCH_ENDIAN)"
-	test "$(DEB_BUILD_ARCH_LIBC)" = "$(TEST_DEB_BUILD_ARCH_LIBC)"
-	test "$(DEB_BUILD_ARCH_OS)" = "$(TEST_DEB_BUILD_ARCH_OS)"
-	test "$(DEB_BUILD_GNU_CPU)" = "$(TEST_DEB_BUILD_GNU_CPU)"
-	test "$(DEB_BUILD_GNU_SYSTEM)" = "$(TEST_DEB_BUILD_GNU_SYSTEM)"
-	test "$(DEB_BUILD_GNU_TYPE)" = "$(TEST_DEB_BUILD_GNU_TYPE)"
-	test "$(DEB_BUILD_MULTIARCH)" = "$(TEST_DEB_BUILD_MULTIARCH)"
-	test "$(DEB_HOST_ARCH)" = "$(TEST_DEB_HOST_ARCH)"
-	test "$(DEB_HOST_ARCH_ABI)" = "$(TEST_DEB_HOST_ARCH_ABI)"
-	test "$(DEB_HOST_ARCH_BITS)" = "$(TEST_DEB_HOST_ARCH_BITS)"
-	test "$(DEB_HOST_ARCH_CPU)" = "$(TEST_DEB_HOST_ARCH_CPU)"
-	test "$(DEB_HOST_ARCH_ENDIAN)" = "$(TEST_DEB_HOST_ARCH_ENDIAN)"
-	test "$(DEB_HOST_ARCH_LIBC)" = "$(TEST_DEB_HOST_ARCH_LIBC)"
-	test "$(DEB_HOST_ARCH_OS)" = "$(TEST_DEB_HOST_ARCH_OS)"
-	test "$(DEB_HOST_GNU_CPU)" = "$(TEST_DEB_HOST_GNU_CPU)"
-	test "$(DEB_HOST_GNU_SYSTEM)" = "$(TEST_DEB_HOST_GNU_SYSTEM)"
-	test "$(DEB_HOST_GNU_TYPE)" = "$(TEST_DEB_HOST_GNU_TYPE)"
-	test "$(DEB_HOST_MULTIARCH)" = "$(TEST_DEB_HOST_MULTIARCH)"
-	test "$(DEB_TARGET_ARCH)" = "$(TEST_DEB_TARGET_ARCH)"
-	test "$(DEB_TARGET_ARCH_ABI)" = "$(TEST_DEB_TARGET_ARCH_ABI)"
-	test "$(DEB_TARGET_ARCH_BITS)" = "$(TEST_DEB_TARGET_ARCH_BITS)"
-	test "$(DEB_TARGET_ARCH_CPU)" = "$(TEST_DEB_TARGET_ARCH_CPU)"
-	test "$(DEB_TARGET_ARCH_ENDIAN)" = "$(TEST_DEB_TARGET_ARCH_ENDIAN)"
-	test "$(DEB_TARGET_ARCH_LIBC)" = "$(TEST_DEB_TARGET_ARCH_LIBC)"
-	test "$(DEB_TARGET_ARCH_OS)" = "$(TEST_DEB_TARGET_ARCH_OS)"
-	test "$(DEB_TARGET_GNU_CPU)" = "$(TEST_DEB_TARGET_GNU_CPU)"
-	test "$(DEB_TARGET_GNU_SYSTEM)" = "$(TEST_DEB_TARGET_GNU_SYSTEM)"
-	test "$(DEB_TARGET_GNU_TYPE)" = "$(TEST_DEB_TARGET_GNU_TYPE)"
-	test "$(DEB_TARGET_MULTIARCH)" = "$(TEST_DEB_TARGET_MULTIARCH)"
+vars := $(foreach machine,BUILD HOST TARGET,$(foreach var,\
+  ARCH \
+  ARCH_ABI \
+  ARCH_BITS \
+  ARCH_CPU \
+  ARCH_ENDIAN \
+  ARCH_LIBC \
+  ARCH_OS \
+  GNU_CPU \
+  GNU_SYSTEM \
+  GNU_TYPE \
+  MULTIARCH \
+  ,DEB_$(machine)_$(var)))
+
+test: $(vars)
+DEB_BUILD_ARCH:
+	test '$($@)' = overridden
+	test "$${$@}" = overridden
+$(filter-out DEB_BUILD_ARCH,$(vars)):
+	test '$($@)' = '$(TEST_$@)'
+	test "$${$@}" = '$(TEST_$@)'
diff --git a/scripts/t/mk/buildflags.mk b/scripts/t/mk/buildflags.mk
index 542bced43..83b583597 100644
--- a/scripts/t/mk/buildflags.mk
+++ b/scripts/t/mk/buildflags.mk
@@ -1,16 +1,30 @@
 DEB_CPPFLAGS_MAINT_APPEND = -DTEST_MK=test
+DEB_CXXFLAGS_MAINT_SET := set
+DPKG_EXPORT_BUILDFLAGS := 1
 
 include $(srcdir)/mk/buildflags.mk
 
-test:
-	test "$(ASFLAGS)" = "$(TEST_ASFLAGS)"
-	test "$(CFLAGS)" = "$(TEST_CFLAGS)"
-	test "$(CPPFLAGS)" = "$(TEST_CPPFLAGS) -DTEST_MK=test"
-	test "$(CXXFLAGS)" = "$(TEST_CXXFLAGS)"
-	test "$(DFLAGS)" = "$(TEST_DFLAGS)"
-	test "$(FCFLAGS)" = "$(TEST_FCFLAGS)"
-	test "$(FFLAGS)" = "$(TEST_FFLAGS)"
-	test "$(GCJFLAGS)" = "$(TEST_GCJFLAGS)"
-	test "$(LDFLAGS)" = "$(TEST_LDFLAGS)"
-	test "$(OBJCFLAGS)" = "$(TEST_OBJCFLAGS)"
-	test "$(OBJCXXFLAGS)" = "$(TEST_OBJCXXFLAGS)"
+vars := \
+  ASFLAGS \
+  CFLAGS \
+  CPPFLAGS \
+  CXXFLAGS \
+  DFLAGS \
+  FCFLAGS \
+  FFLAGS \
+  GCJFLAGS \
+  LDFLAGS \
+  OBJCFLAGS \
+  OBJCXXFLAGS \
+  # EOL
+
+test: $(vars)
+CPPFLAGS:
+	test '$($@)' = '$(TEST_$@) -DTEST_MK=test'
+	test "$${$@}" = '$(TEST_$@) -DTEST_MK=test'
+CXXFLAGS:
+	test '$($@)' = set
+	test "$${$@}" = set
+$(filter-out CPPFLAGS CXXFLAGS,$(vars)):
+	test '$($@)' = '$(TEST_$@)'
+	test "$${$@}" = '$(TEST_$@)'
diff --git a/scripts/t/mk/buildtools.mk b/scripts/t/mk/buildtools.mk
index 0077791b5..2fe049818 100644
--- a/scripts/t/mk/buildtools.mk
+++ b/scripts/t/mk/buildtools.mk
@@ -1,35 +1,32 @@
+AR := overridden
+DPKG_EXPORT_BUILDTOOLS := 1
+
 include $(srcdir)/mk/buildtools.mk
 
-test:
-	test "$(AS)" = "$(TEST_AS)"
-	test "$(AS_FOR_BUILD)" = "$(TEST_AS_FOR_BUILD)"
-	test "$(CC)" = "$(TEST_CC)"
-	test "$(CC_FOR_BUILD)" = "$(TEST_CC_FOR_BUILD)"
-	test "$(CXX)" = "$(TEST_CXX)"
-	test "$(CXX_FOR_BUILD)" = "$(TEST_CXX_FOR_BUILD)"
-	test "$(OBJC)" = "$(TEST_OBJC)"
-	test "$(OBJC_FOR_BUILD)" = "$(TEST_OBJC_FOR_BUILD)"
-	test "$(OBJCXX)" = "$(TEST_OBJCXX)"
-	test "$(OBJCXX_FOR_BUILD)" = "$(TEST_OBJCXX_FOR_BUILD)"
-	test "$(GCJ)" = "$(TEST_GCJ)"
-	test "$(GCJ_FOR_BUILD)" = "$(TEST_GCJ_FOR_BUILD)"
-	test "$(F77)" = "$(TEST_F77)"
-	test "$(F77_FOR_BUILD)" = "$(TEST_F77_FOR_BUILD)"
-	test "$(FC)" = "$(TEST_FC)"
-	test "$(FC_FOR_BUILD)" = "$(TEST_FC_FOR_BUILD)"
-	test "$(LD)" = "$(TEST_LD)"
-	test "$(LD_FOR_BUILD)" = "$(TEST_LD_FOR_BUILD)"
-	test "$(STRIP)" = "$(TEST_STRIP)"
-	test "$(STRIP_FOR_BUILD)" = "$(TEST_STRIP_FOR_BUILD)"
-	test "$(OBJCOPY)" = "$(TEST_OBJCOPY)"
-	test "$(OBJCOPY_FOR_BUILD)" = "$(TEST_OBJCOPY_FOR_BUILD)"
-	test "$(OBJDUMP)" = "$(TEST_OBJDUMP)"
-	test "$(OBJDUMP_FOR_BUILD)" = "$(TEST_OBJDUMP_FOR_BUILD)"
-	test "$(NM)" = "$(TEST_NM)"
-	test "$(NM_FOR_BUILD)" = "$(TEST_NM_FOR_BUILD)"
-	test "$(AR)" = "$(TEST_AR)"
-	test "$(AR_FOR_BUILD)" = "$(TEST_AR_FOR_BUILD)"
-	test "$(RANLIB)" = "$(TEST_RANLIB)"
-	test "$(RANLIB_FOR_BUILD)" = "$(TEST_RANLIB_FOR_BUILD)"
-	test "$(PKG_CONFIG)" = "$(TEST_PKG_CONFIG)"
-	test "$(PKG_CONFIG_FOR_BUILD)" = "$(TEST_PKG_CONFIG_FOR_BUILD)"
+vars := $(foreach tool,\
+  AR \
+  AS \
+  CC \
+  CPP \
+  CXX \
+  F77 \
+  FC \
+  GCJ \
+  LD \
+  NM \
+  OBJC \
+  OBJCOPY \
+  OBJCXX \
+  OBJDUMP \
+  PKG_CONFIG \
+  RANLIB \
+  STRIP \
+  ,$(tool) $(tool)_FOR_BUILD)
+
+test: $(vars)
+AR AR_FOR_BUILD:
+	test '$($@)' = overridden
+	test "$${$@}" = overridden
+$(filter-out AR AR_FOR_BUILD,$(vars)):
+	test '$($@)' = '$(TEST_$@)'
+	test "$${$@}" = '$(TEST_$@)'
-- 
2.30.2

>From 6d30c2cd83e81b74de2740da1670caf60de29923 Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <nico...@debian.org>
Date: Mon, 1 Nov 2021 10:08:08 +0100
Subject: [PATCH 3/6] scripts/mk/buildopts.mk: small optimisations

Assign DEB_BUILD_OPTION_PARALLEL with := so that the value is computed
only once instead of every time the variable is used.
The maintainer is not supposed to modify DEB_BUILD_OPTIONS.

Always define DEB_BUILD_OPTION_PARALLEL, even if empty when
DEB_BUILD_OPTIONS does not contain parallel=%.
The distinction between DEB_BUILD_OPTIONS= and
DEB_BUILD_OPTIONS=parallel= does probably not deserve a test.
---
 scripts/mk/buildopts.mk | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/scripts/mk/buildopts.mk b/scripts/mk/buildopts.mk
index c95777719..420b6359c 100644
--- a/scripts/mk/buildopts.mk
+++ b/scripts/mk/buildopts.mk
@@ -5,6 +5,5 @@
 #
 #   DEB_BUILD_OPTION_PARALLEL: the argument for the parallel=N option.
 
-ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
-  DEB_BUILD_OPTION_PARALLEL = $(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
-endif
+DEB_BUILD_OPTION_PARALLEL := $(patsubst parallel=%,%,\
+                               $(filter parallel=%,$(DEB_BUILD_OPTIONS)))
-- 
2.30.2

>From ee2850385c228af1c6e7aaab4294dfc72d3c7ee6 Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <nico...@debian.org>
Date: Thu, 11 Feb 2021 16:26:50 +0100
Subject: [PATCH 4/6] scripts/mk: reduce the number of subprocesses

architecture.mk and buildflags.mk spawn less subshells, improving the
overall speed (the tests run twice faster according to bash time
builtin).

pkg-info.mk uses the same trick than buildflags.mk in order to spawn
at most one subshell. The performance gain is visible, but minor
because there are way less variables.
---
 scripts/mk/architecture.mk | 18 +++++++++++-----
 scripts/mk/buildflags.mk   | 23 ++++++++++++++------
 scripts/mk/pkg-info.mk     | 44 +++++++++++++++++++++++++++++++-------
 3 files changed, 66 insertions(+), 19 deletions(-)

diff --git a/scripts/mk/architecture.mk b/scripts/mk/architecture.mk
index 2aa115822..198e5e145 100644
--- a/scripts/mk/architecture.mk
+++ b/scripts/mk/architecture.mk
@@ -2,10 +2,18 @@
 # DEB_BUILD_* variables that dpkg-architecture can return. Existing values
 # of those variables are preserved as per policy.
 
-dpkg_lazy_eval ?= $$(or $$(value DPKG_CACHE_$(1)),$$(eval DPKG_CACHE_$(1) := $$(shell $(2)))$$(value DPKG_CACHE_$(1)))
-
-dpkg_architecture_setvar = export $(1) ?= $(call dpkg_lazy_eval,$(1),dpkg-architecture -q$(1))
-
+dpkg-architecture_vars := \
 $(foreach machine,BUILD HOST TARGET,\
   $(foreach var,ARCH ARCH_ABI ARCH_LIBC ARCH_OS ARCH_CPU ARCH_BITS ARCH_ENDIAN GNU_CPU GNU_SYSTEM GNU_TYPE MULTIARCH,\
-    $(eval $(call dpkg_architecture_setvar,DEB_$(machine)_$(var)))))
+    DEB_$(machine)_$(var)))
+
+# Spare a subprocess in the frequent case where dpkg-buildpackage
+# has already exported all variables.
+ifneq (,$(filter undefined,$(foreach v,$(dpkg-architecture_vars),$(origin $(v)))))
+
+  # ?= preserves overriddes from debian/rules or its command line.
+  $(foreach v,$(subst =,?=,$(shell dpkg-architecture)),$(eval $(v)))
+
+endif
+
+export $(dpkg-architecture_vars)
diff --git a/scripts/mk/buildflags.mk b/scripts/mk/buildflags.mk
index 9cef0c0c4..868581a7f 100644
--- a/scripts/mk/buildflags.mk
+++ b/scripts/mk/buildflags.mk
@@ -18,11 +18,13 @@
 # This list is kept in sync with the default set of flags returned
 # by dpkg-buildflags.
 
-dpkg_lazy_eval ?= $$(or $$(value DPKG_CACHE_$(1)),$$(eval DPKG_CACHE_$(1) := $$(shell $(2)))$$(value DPKG_CACHE_$(1)))
-
 DPKG_BUILDFLAGS_LIST = ASFLAGS CFLAGS CPPFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS \
                        GCJFLAGS DFLAGS FFLAGS FCFLAGS LDFLAGS
 
+# Accumulate the parameters for dpkg-buildflags, in case it is ever
+# called.
+
+DPKG_BUILDFLAGS_EXPORT_ENVVAR :=
 define dpkg_buildflags_export_envvar
   ifdef $(1)
     DPKG_BUILDFLAGS_EXPORT_ENVVAR += $(1)="$$(value $(1))"
@@ -36,11 +38,20 @@ $(foreach flag,$(DPKG_BUILDFLAGS_LIST),\
   $(foreach operation,SET STRIP APPEND PREPEND,\
     $(eval $(call dpkg_buildflags_export_envvar,DEB_$(flag)_MAINT_$(operation)))))
 
-dpkg_buildflags_setvar = $(1) = $(call dpkg_lazy_eval,$(1),$(DPKG_BUILDFLAGS_EXPORT_ENVVAR) dpkg-buildflags --get $(1))
-
-$(foreach flag,$(DPKG_BUILDFLAGS_LIST),\
-  $(eval $(call dpkg_buildflags_setvar,$(flag))))
+# This variable is only expanded on demand, and we ensure that it
+# happens at most once..
+dpkg-buildflags_run = $(eval $(shell \
+  $(DPKG_BUILDFLAGS_EXPORT_ENVVAR) dpkg-buildflags \
+  | sed 's/^\([^=]*\)\(.*\)/$$(eval \1:\2)/'))
 
 ifdef DPKG_EXPORT_BUILDFLAGS
+  # We must compute all values right now.
+  $(dpkg-buildflags_run)
   export $(DPKG_BUILDFLAGS_LIST)
+else
+  # Only run a subprocess when a variable is actually used,
+  # but then replace each recursive definition with a non-recursive one
+  # (and of course return the asked value).
+  $(foreach var,$(DPKG_BUILDFLAGS_LIST),\
+    $(eval $(var)=$$(dpkg-buildflags_run)$$($(var))))
 endif
diff --git a/scripts/mk/pkg-info.mk b/scripts/mk/pkg-info.mk
index bccde2317..27e16c50c 100644
--- a/scripts/mk/pkg-info.mk
+++ b/scripts/mk/pkg-info.mk
@@ -12,16 +12,44 @@
 #   SOURCE_DATE_EPOCH: source release date as seconds since the epoch, as
 #     specified by <https://reproducible-builds.org/specs/source-date-epoch/>
 #     (since dpkg 1.18.8).
+#     If it is undefined, the date of the latest changelog entry is used.
+#     In both cases, the value is exported.
 
-dpkg_late_eval ?= $(or $(value DPKG_CACHE_$(1)),$(eval DPKG_CACHE_$(1) := $(shell $(2)))$(value DPKG_CACHE_$(1)))
 
-DEB_SOURCE = $(call dpkg_late_eval,DEB_SOURCE,dpkg-parsechangelog -SSource)
-DEB_VERSION = $(call dpkg_late_eval,DEB_VERSION,dpkg-parsechangelog -SVersion)
-DEB_VERSION_EPOCH_UPSTREAM = $(call dpkg_late_eval,DEB_VERSION_EPOCH_UPSTREAM,echo '$(DEB_VERSION)' | sed -e 's/-[^-]*$$//')
-DEB_VERSION_UPSTREAM_REVISION = $(call dpkg_late_eval,DEB_VERSION_UPSTREAM_REVISION,echo '$(DEB_VERSION)' | sed -e 's/^[0-9]*://')
-DEB_VERSION_UPSTREAM = $(call dpkg_late_eval,DEB_VERSION_UPSTREAM,echo '$(DEB_VERSION_EPOCH_UPSTREAM)' | sed -e 's/^[0-9]*://')
-DEB_DISTRIBUTION = $(call dpkg_late_eval,DEB_DISTRIBUTION,dpkg-parsechangelog -SDistribution)
+# This variable is only expanded on demand, and we ensure that it
+# happens at most once..
+dpkg-parsechangelog_run = $(eval $(shell dpkg-parsechangelog \
+                                   | sed -n '$(dpkg-parsechangelog_sed)'))
 
-SOURCE_DATE_EPOCH ?= $(call dpkg_late_eval,SOURCE_DATE_EPOCH,dpkg-parsechangelog -STimestamp)
+dpkg-parsechangelog_sed := \
+  s/^Source: \(.*\)/\
+    $$(eval DEB_SOURCE                    := \1)/p;\
+  s/^Version: \([0-9]*:\)\?\(.*\)\(-[^-]*\)$$/\
+    $$(eval DEB_VERSION                   := \1\2\3)\
+    $$(eval DEB_VERSION_EPOCH_UPSTREAM    := \1\2)\
+    $$(eval DEB_VERSION_UPSTREAM_REVISION := \2\3)\
+    $$(eval DEB_VERSION_UPSTREAM          := \2)/p;\
+  s/^Distribution: \(.*\)/\
+    $$(eval DEB_DISTRIBUTION              := \1)/p
+
+ifdef SOURCE_DATE_EPOCH
+  # Only parse the changelog if a variable is actually used,
+  # but then replace each recursive definition with a non-recursive one
+  # (and of course return the asked value).
+  $(foreach var,\
+    DEB_SOURCE \
+    DEB_VERSION \
+    DEB_VERSION_EPOCH_UPSTREAM \
+    DEB_VERSION_UPSTREAM_REVISION \
+    DEB_VERSION_UPSTREAM \
+    DEB_DISTRIBUTION \
+    ,$(eval $(var) = $$(dpkg-parsechangelog_run)$$($(var))))
+else
+  # We must run a subshell in order to compute SOURCE_DATE_EPOCH,
+  # so we may as well set all variables.
+  dpkg-parsechangelog_sed += \
+    ;s/^Timestamp: \(.*\)/$$(eval SOURCE_DATE_EPOCH:=\1)/p
+  $(dpkg-parsechangelog_run)
+endif
 
 export SOURCE_DATE_EPOCH
-- 
2.30.2

>From 6a094cdd65da5b9e113ce71f6dd4a063d50f4d09 Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <nico...@debian.org>
Date: Sun, 13 Feb 2022 14:17:20 +0100
Subject: [PATCH 5/6] scripts/mk: protect against repeated inclusion

For example, buildtools.mk implicitly includes architecture.mk.
---
 scripts/mk/architecture.mk | 5 +++++
 scripts/mk/buildflags.mk   | 6 ++++++
 scripts/mk/buildopts.mk    | 5 +++++
 scripts/mk/buildtools.mk   | 5 +++++
 scripts/mk/pkg-info.mk     | 6 ++++++
 scripts/mk/vendor.mk       | 5 +++++
 6 files changed, 32 insertions(+)

diff --git a/scripts/mk/architecture.mk b/scripts/mk/architecture.mk
index 198e5e145..963293e05 100644
--- a/scripts/mk/architecture.mk
+++ b/scripts/mk/architecture.mk
@@ -2,6 +2,9 @@
 # DEB_BUILD_* variables that dpkg-architecture can return. Existing values
 # of those variables are preserved as per policy.
 
+ifndef dpkg_architecture_mk_already_included
+dpkg_architecture_mk_already_included :=
+
 dpkg-architecture_vars := \
 $(foreach machine,BUILD HOST TARGET,\
   $(foreach var,ARCH ARCH_ABI ARCH_LIBC ARCH_OS ARCH_CPU ARCH_BITS ARCH_ENDIAN GNU_CPU GNU_SYSTEM GNU_TYPE MULTIARCH,\
@@ -17,3 +20,5 @@ ifneq (,$(filter undefined,$(foreach v,$(dpkg-architecture_vars),$(origin $(v)))
 endif
 
 export $(dpkg-architecture_vars)
+
+endif
diff --git a/scripts/mk/buildflags.mk b/scripts/mk/buildflags.mk
index 868581a7f..34a66fd01 100644
--- a/scripts/mk/buildflags.mk
+++ b/scripts/mk/buildflags.mk
@@ -15,6 +15,10 @@
 # You can also export them in the environment by setting
 # DPKG_EXPORT_BUILDFLAGS to a non-empty value.
 #
+
+ifndef dpkg_buildflags_mk_already_included
+dpkg_buildflags_mk_already_included :=
+
 # This list is kept in sync with the default set of flags returned
 # by dpkg-buildflags.
 
@@ -55,3 +59,5 @@ else
   $(foreach var,$(DPKG_BUILDFLAGS_LIST),\
     $(eval $(var)=$$(dpkg-buildflags_run)$$($(var))))
 endif
+
+endif
diff --git a/scripts/mk/buildopts.mk b/scripts/mk/buildopts.mk
index 420b6359c..c087ad3a4 100644
--- a/scripts/mk/buildopts.mk
+++ b/scripts/mk/buildopts.mk
@@ -5,5 +5,10 @@
 #
 #   DEB_BUILD_OPTION_PARALLEL: the argument for the parallel=N option.
 
+ifndef dpkg_buildopts_mk_already_included
+dpkg_buildopts_mk_already_included :=
+
 DEB_BUILD_OPTION_PARALLEL := $(patsubst parallel=%,%,\
                                $(filter parallel=%,$(DEB_BUILD_OPTIONS)))
+
+endif
diff --git a/scripts/mk/buildtools.mk b/scripts/mk/buildtools.mk
index 02c16ec92..ac9809c36 100644
--- a/scripts/mk/buildtools.mk
+++ b/scripts/mk/buildtools.mk
@@ -26,6 +26,9 @@
 # The variables are not exported by default. This can be changed by
 # defining DPKG_EXPORT_BUILDTOOLS.
 
+ifndef dpkg_buildtool_mk_already_included
+dpkg_buildtool_mk_already_included :=
+
 dpkg_datadir ?= $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
 include $(dpkg_datadir)/architecture.mk
 
@@ -76,3 +79,5 @@ $(eval $(call dpkg_buildtool_setvar,AR,ar))
 $(eval $(call dpkg_buildtool_setvar,RANLIB,ranlib))
 $(eval $(call dpkg_buildtool_setvar,PKG_CONFIG,pkg-config))
 $(eval $(call dpkg_buildtool_setvar,QMAKE,qmake))
+
+endif
diff --git a/scripts/mk/pkg-info.mk b/scripts/mk/pkg-info.mk
index 27e16c50c..21ed26b36 100644
--- a/scripts/mk/pkg-info.mk
+++ b/scripts/mk/pkg-info.mk
@@ -15,6 +15,8 @@
 #     If it is undefined, the date of the latest changelog entry is used.
 #     In both cases, the value is exported.
 
+ifndef dpkg_pkg_info_mk_already_included
+dpkg_pkg_info_mk_already_included :=
 
 # This variable is only expanded on demand, and we ensure that it
 # happens at most once..
@@ -33,6 +35,8 @@ dpkg-parsechangelog_sed := \
     $$(eval DEB_DISTRIBUTION              := \1)/p
 
 ifdef SOURCE_DATE_EPOCH
+  # dpkg-buildpackage exports SOURCE_DATE_EPOCH.
+
   # Only parse the changelog if a variable is actually used,
   # but then replace each recursive definition with a non-recursive one
   # (and of course return the asked value).
@@ -53,3 +57,5 @@ else
 endif
 
 export SOURCE_DATE_EPOCH
+
+endif
diff --git a/scripts/mk/vendor.mk b/scripts/mk/vendor.mk
index f7c61bf6f..d6050d965 100644
--- a/scripts/mk/vendor.mk
+++ b/scripts/mk/vendor.mk
@@ -32,6 +32,9 @@
 #     ...
 #   endif
 
+ifndef dpkg_vendor_mk_already_included
+dpkg_vendor_mk_already_included :=
+
 dpkg_late_eval ?= $(or $(value DPKG_CACHE_$(1)),$(eval DPKG_CACHE_$(1) := $(shell $(2)))$(value DPKG_CACHE_$(1)))
 
 DEB_VENDOR = $(call dpkg_late_eval,DEB_VENDOR,dpkg-vendor --query Vendor)
@@ -41,3 +44,5 @@ dpkg_vendor_derives_from_v0 = dpkg-vendor --derives-from $(1) && echo yes || ech
 dpkg_vendor_derives_from_v1 = $(shell $(dpkg_vendor_derives_from_v0))
 
 dpkg_vendor_derives_from ?= $(dpkg_vendor_derives_from_v0)
+
+endif
-- 
2.30.2

>From 3ac84880e2a57590f66598f6987f7c4c1646988d Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <nico...@debian.org>
Date: Sun, 13 Feb 2022 13:41:26 +0100
Subject: [PATCH 6/6] scripts/mk: improve details in documentation

architecture.mk: give more details
Mention default.mk as an alternative in included scripts.
Improve consistency accross Makefile snippets.
---
 scripts/mk/architecture.mk | 15 ++++++++++++---
 scripts/mk/buildflags.mk   | 11 +++++++++--
 scripts/mk/buildopts.mk    |  7 +++----
 scripts/mk/buildtools.mk   |  5 +++--
 scripts/mk/default.mk      |  4 ++--
 scripts/mk/pkg-info.mk     |  5 +++--
 scripts/mk/vendor.mk       |  5 +++--
 7 files changed, 35 insertions(+), 17 deletions(-)

diff --git a/scripts/mk/architecture.mk b/scripts/mk/architecture.mk
index 963293e05..5bf017844 100644
--- a/scripts/mk/architecture.mk
+++ b/scripts/mk/architecture.mk
@@ -1,6 +1,15 @@
-# This Makefile frament (since dpkg 1.16.1) defines all the DEB_HOST_* and
-# DEB_BUILD_* variables that dpkg-architecture can return. Existing values
-# of those variables are preserved as per policy.
+# debian/rules helper defining dpkg-architecture(1) variables.
+# (since dpkg 1.16.1)
+# Include this (or default.mk) if using DEB_{HOST,BUILD,TARGET}_*.
+#
+# These variables are usually computed by dpkg-buildpackage and simply
+# inherited by debian/rules, but need a definition when debian/rules
+# is invoked directly.
+#
+# Each variable may be overridden by the end user (on the debian/rules
+# command line) or by the maintainer (within debian/rules).
+#
+# All values are unconditionally exported.
 
 ifndef dpkg_architecture_mk_already_included
 dpkg_architecture_mk_already_included :=
diff --git a/scripts/mk/buildflags.mk b/scripts/mk/buildflags.mk
index 34a66fd01..a51778467 100644
--- a/scripts/mk/buildflags.mk
+++ b/scripts/mk/buildflags.mk
@@ -1,4 +1,6 @@
-# This Makefile fragment (since dpkg 1.16.1) defines the following variables:
+# debian/rules helper defining the dpkg-buildflags(1) variables.
+# (since dpkg 1.16.1)
+# Include this (or default.mk) if using:
 #
 #   ASFLAGS: flags for the assembler (since 1.21.0).
 #   CFLAGS: flags for the C compiler.
@@ -13,8 +15,13 @@
 #   LDFLAGS: flags for the linker.
 #
 # You can also export them in the environment by setting
-# DPKG_EXPORT_BUILDFLAGS to a non-empty value.
+# DPKG_EXPORT_BUILDFLAGS.
 #
+# These variables are computed by dpkg-buildflags(1) and should not be
+# directly overridden.  The following setting are exported to
+# dpkg-buildflags.
+#   DEB_BUILD_{OPTIONS,MAINT_OPTIONS,PATH}
+#   DEB_*_MAINT_{APPEND,PREPEND,SET,STRIP}
 
 ifndef dpkg_buildflags_mk_already_included
 dpkg_buildflags_mk_already_included :=
diff --git a/scripts/mk/buildopts.mk b/scripts/mk/buildopts.mk
index c087ad3a4..042bf814a 100644
--- a/scripts/mk/buildopts.mk
+++ b/scripts/mk/buildopts.mk
@@ -1,7 +1,6 @@
-# This Makefile fragment (since dpkg 1.20.1) parses option arguments from
-# DEB_BUILD_OPTIONS, and exposes these as variables.
-#
-# Defines the following variables:
+# debian/rules helper extracting some arguments from DEB_BUILD_OPTIONS.
+# (since dpkg 1.20.1)
+# Include this (or default.mk) if using:
 #
 #   DEB_BUILD_OPTION_PARALLEL: the argument for the parallel=N option.
 
diff --git a/scripts/mk/buildtools.mk b/scripts/mk/buildtools.mk
index ac9809c36..859b21043 100644
--- a/scripts/mk/buildtools.mk
+++ b/scripts/mk/buildtools.mk
@@ -1,5 +1,6 @@
-# This Makefile fragment (since dpkg 1.19.0) defines the following variables
-# for host tools:
+# debian/rules helper defining some host and build tools
+# (since dpkg 1.19.0)
+# Include this if using:
 #
 #   AS: assembler (since dpkg 1.19.1).
 #   CPP: C preprocessor.
diff --git a/scripts/mk/default.mk b/scripts/mk/default.mk
index 095128470..0a0b52171 100644
--- a/scripts/mk/default.mk
+++ b/scripts/mk/default.mk
@@ -1,5 +1,5 @@
-# This Makefile fragment (since dpkg 1.16.1) includes all the Makefile
-# fragments that define variables that can be useful within debian/rules.
+# debian/rules helper including a selection of more specific helpers.
+# (since dpkg 1.16.1)
 
 dpkg_datadir := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
 include $(dpkg_datadir)/architecture.mk
diff --git a/scripts/mk/pkg-info.mk b/scripts/mk/pkg-info.mk
index 21ed26b36..abc27379d 100644
--- a/scripts/mk/pkg-info.mk
+++ b/scripts/mk/pkg-info.mk
@@ -1,5 +1,6 @@
-# This Makefile fragment (since dpkg 1.16.1) defines the following package
-# information variables:
+# debian/rules helper defining some dpkg-parsechangelog(1) variables.
+# (since 1.16.1)
+# Include this (or default.mk) if using:
 #
 #   DEB_SOURCE: source package name.
 #   DEB_VERSION: package's full version (epoch + upstream vers. + revision).
diff --git a/scripts/mk/vendor.mk b/scripts/mk/vendor.mk
index d6050d965..8669620ea 100644
--- a/scripts/mk/vendor.mk
+++ b/scripts/mk/vendor.mk
@@ -1,5 +1,6 @@
-# This Makefile fragment (since dpkg 1.16.1) defines the following
-# vendor-related variables:
+# debian/rules helper defining some dpkg-vendor(1) variables.
+# (since dpkg 1.16.1)
+# Include this (or default.mk) if using:
 #
 #   DEB_VENDOR: output of «dpkg-vendor --query Vendor».
 #   DEB_PARENT_VENDOR: output of «dpkg-vendor --query Parent» (can be empty).
-- 
2.30.2

Reply via email to