Package: dpkg-dev
Version: 1.19.7
Followup-For: Bug #872381

Hello.

The attachments are commits based on the current git head (f0c3cccf).

2/ adds tests for the Make snippets.
The current implementation passes these new tests.

3/ implements the suggestion as a git commit.
It also passes all tests, slightly faster.

How can I help?
Thanks.
>From 55c1f85f2f371b94aa36db098cf5408213a8295c Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <nicolas.bouleng...@free.fr>
Date: Mon, 29 Jul 2019 14:38:32 +0200
Subject: [PATCH 1/3] scripts/mk: simplify Makefile.am with sed --in-place
 option

---
 scripts/mk/Makefile.am | 18 ++++--------------
 1 file changed, 4 insertions(+), 14 deletions(-)

diff --git a/scripts/mk/Makefile.am b/scripts/mk/Makefile.am
index 54a41e712..e2d1f7a43 100644
--- a/scripts/mk/Makefile.am
+++ b/scripts/mk/Makefile.am
@@ -8,18 +8,8 @@ dist_pkgdata_DATA = \
 	pkg-info.mk \
 	vendor.mk
 
-do_path_subst = $(AM_V_GEN) sed \
-	-e "s:dpkg_datadir[[:space:]]*=[[:space:]]*[^[:space:]]*:dpkg_datadir = $(pkgdatadir):"
-
 install-data-hook:
-	mv $(DESTDIR)$(pkgdatadir)/default.mk \
-	   $(DESTDIR)$(pkgdatadir)/default.mk.tmp
-	$(do_path_subst) <$(DESTDIR)$(pkgdatadir)/default.mk.tmp \
-	                 >$(DESTDIR)$(pkgdatadir)/default.mk
-	rm -f $(DESTDIR)$(pkgdatadir)/default.mk.tmp
-
-	mv $(DESTDIR)$(pkgdatadir)/buildtools.mk \
-	   $(DESTDIR)$(pkgdatadir)/buildtools.mk.tmp
-	$(do_path_subst) <$(DESTDIR)$(pkgdatadir)/buildtools.mk.tmp \
-	                 >$(DESTDIR)$(pkgdatadir)/buildtools.mk
-	rm -f $(DESTDIR)$(pkgdatadir)/buildtools.mk.tmp
+	$(AM_V_GEN) sed --in-place \
+	  's:dpkg_datadir[[:space:]]*=[[:space:]]*[^[:space:]]*:dpkg_datadir = $(pkgdatadir):' \
+	  $(DESTDIR)$(pkgdatadir)/buildtools.mk \
+	  $(DESTDIR)$(pkgdatadir)/default.mk
-- 
2.20.1

>From c9363d090298601494e3a551a98e7fdaad73abbf Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <nicolas.bouleng...@free.fr>
Date: Mon, 29 Jul 2019 18:34:13 +0200
Subject: [PATCH 2/3] scripts/mk: extend and simplify tests

Use less hash traversals, deal with key/values pairs instead of
iterating on keys and search each value.
There is no need to unexport build tools, tests happen in a separate process.
Test SOURCE_DATE_EPOCH, from environemnt or d/changelog.
Use Make loops instead of similar lines.
Check that values may be overridden.
Check that values are (or can be) exported, even if overridden.
---
 scripts/t/mk.t               | 35 ++++++++++++--------
 scripts/t/mk/architecture.mk | 57 +++++++++++++-------------------
 scripts/t/mk/buildflags.mk   | 33 +++++++++++++------
 scripts/t/mk/buildtools.mk   | 63 +++++++++++++++++-------------------
 scripts/t/mk/pkg-info.mk     |  2 ++
 5 files changed, 100 insertions(+), 90 deletions(-)

diff --git a/scripts/t/mk.t b/scripts/t/mk.t
index 98c7e5083..a46512b88 100644
--- a/scripts/t/mk.t
+++ b/scripts/t/mk.t
@@ -16,7 +16,7 @@
 use strict;
 use warnings;
 
-use Test::More tests => 8;
+use Test::More tests => 9;
 use Test::Dpkg qw(:paths);
 
 use File::Spec::Functions qw(rel2abs);
@@ -69,16 +69,23 @@ sub cmd_get_vars {
 
 my %arch = cmd_get_vars($ENV{PERL}, "$srcdir/dpkg-architecture.pl", '-f');
 
-delete $ENV{$_} foreach keys %arch;
-$ENV{"TEST_$_"} = $arch{$_} foreach keys %arch;
+while (my ($k, $v) = each %arch) {
+    delete $ENV{$k};
+    $ENV{"TEST_$k"} = $v;
+}
 test_makefile('architecture.mk');
-$ENV{$_} = $arch{$_} foreach keys %arch;
+
+while (my ($k, $v) = each %arch) {
+    $ENV{$k} = $v;
+}
 test_makefile('architecture.mk');
 
 my %buildflag = cmd_get_vars($ENV{PERL}, "$srcdir/dpkg-buildflags.pl");
 
-delete $ENV{$_} foreach keys %buildflag;
-$ENV{"TEST_$_"} = $buildflag{$_} foreach keys %buildflag;
+while (my ($k, $v) = each %buildflag) {
+    delete $ENV{$k};
+    $ENV{"TEST_$k"} = $v;
+}
 test_makefile('buildflags.mk');
 
 my %buildtools = (
@@ -101,19 +108,21 @@ my %buildtools = (
     PKG_CONFIG => 'pkg-config',
 );
 
-foreach my $tool (keys %buildtools) {
+while (my ($tool, $default) = each %buildtools) {
     delete $ENV{$tool};
-    $ENV{"TEST_$tool"} = "$ENV{DEB_HOST_GNU_TYPE}-$buildtools{$tool}";
+    $ENV{"TEST_$tool"} = "$ENV{DEB_HOST_GNU_TYPE}-$default";
     delete $ENV{"${tool}_FOR_BUILD"};
-    $ENV{"TEST_${tool}_FOR_BUILD"} = "$ENV{DEB_BUILD_GNU_TYPE}-$buildtools{$tool}";
+    $ENV{"TEST_${tool}_FOR_BUILD"} = "$ENV{DEB_BUILD_GNU_TYPE}-$default";
 }
 test_makefile('buildtools.mk');
 
-foreach my $tool (keys %buildtools) {
-    delete $ENV{${tool}};
-    delete $ENV{"${tool}_FOR_BUILD"};
-}
+delete $ENV{SOURCE_DATE_EPOCH};
+$ENV{TEST_SOURCE_DATE_EPOCH} = `date +%s -d "Tue, 04 Aug 2015 16:13:50 +0200"`;
+chomp $ENV{TEST_SOURCE_DATE_EPOCH};
+test_makefile('pkg-info.mk');
 
+$ENV{SOURCE_DATE_EPOCH} = 100;
+$ENV{TEST_SOURCE_DATE_EPOCH} = 100;
 test_makefile('pkg-info.mk');
 
 test_makefile('vendor.mk');
diff --git a/scripts/t/mk/architecture.mk b/scripts/t/mk/architecture.mk
index 2ac0222ca..939835be3 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 feed5e31b..95b5cbf46 100644
--- a/scripts/t/mk/buildflags.mk
+++ b/scripts/t/mk/buildflags.mk
@@ -1,14 +1,27 @@
 DEB_CPPFLAGS_MAINT_APPEND = -DTEST_MK=test
+DEB_CXXFLAGS_MAINT_SET := set
+DPKG_EXPORT_BUILDFLAGS := 1
 
 include $(srcdir)/mk/buildflags.mk
 
-test:
-	test "$(CFLAGS)" = "$(TEST_CFLAGS)"
-	test "$(CPPFLAGS)" = "$(TEST_CPPFLAGS) -DTEST_MK=test"
-	test "$(CXXFLAGS)" = "$(TEST_CXXFLAGS)"
-	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 := \
+  CFLAGS \
+  CPPFLAGS \
+  CXXFLAGS \
+  FCFLAGS \
+  FFLAGS \
+  GCJFLAGS \
+  LDFLAGS \
+  OBJCFLAGS \
+  OBJCXXFLAGS
+
+test: $(vars)
+CPPFLAGS:
+	test '$(CPPFLAGS)' = '$(TEST_CPPFLAGS) -DTEST_MK=test'
+	test "$${CPPFLAGS}" = '$(TEST_CPPFLAGS) -DTEST_MK=test'
+CXXFLAGS:
+	test '$(CXXFLAGS)' = set
+	test "$${CXXFLAGS}" = 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..ec9ddc115 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_$@)'
diff --git a/scripts/t/mk/pkg-info.mk b/scripts/t/mk/pkg-info.mk
index 22a2bf44f..c0e3287b5 100644
--- a/scripts/t/mk/pkg-info.mk
+++ b/scripts/t/mk/pkg-info.mk
@@ -7,3 +7,5 @@ test:
 	test "$(DEB_VERSION_UPSTREAM_REVISION)" = "2:3.4-5-6"
 	test "$(DEB_VERSION_UPSTREAM)" = "2:3.4-5"
 	test "$(DEB_DISTRIBUTION)" = "suite"
+	test '$(SOURCE_DATE_EPOCH)' = '$(TEST_SOURCE_DATE_EPOCH)'
+	test "$${SOURCE_DATE_EPOCH}" = '$(TEST_SOURCE_DATE_EPOCH)'
-- 
2.20.1

>From 1f4ac9b6d6fd480b4a2e5e768b7b207e146e0480 Mon Sep 17 00:00:00 2001
From: Nicolas Boulenguez <nicolas.bouleng...@free.fr>
Date: Mon, 29 Jul 2019 19:03:16 +0200
Subject: [PATCH 3/3] scripts/mk: improve subproceses

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.

In buildtools.mk, remove the test 'ifdef $(1)', since $(1) is affected
by previous stanza.
---
 debian/changelog           |  3 +++
 scripts/mk/architecture.mk | 12 +++++------
 scripts/mk/buildflags.mk   | 26 ++++++++++++++++-------
 scripts/mk/buildtools.mk   | 21 +++++++++++--------
 scripts/mk/pkg-info.mk     | 43 +++++++++++++++++++++++++++++++-------
 5 files changed, 75 insertions(+), 30 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index d556ed5bb..048248889 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -2,6 +2,9 @@ dpkg (1.20.0) UNRELEASED; urgency=medium
 
   *
 
+  [ Nicolas Boulenguez <nico...@debian.org> ]
+  * scripts/mk: spawn each subcommand at most once for efficiency.
+
  -- Guillem Jover <guil...@debian.org>  Fri, 07 Jun 2019 18:00:53 +0200
 
 dpkg (1.19.7) unstable; urgency=medium
diff --git a/scripts/mk/architecture.mk b/scripts/mk/architecture.mk
index 0af96019d..d02f59d0d 100644
--- a/scripts/mk/architecture.mk
+++ b/scripts/mk/architecture.mk
@@ -2,10 +2,10 @@
 # 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))
-
-$(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)))))
+# According to dpkg-architecture(1), the variables must always be
+# exported, so we need at least a subprocess.
+# Attempt to set all variables with the minimal number of external subprocesses.
+# This also avoids maintaining a copy of the variable list here.
+# Each = is replaced with ?= in order to export existing overridden values.
+$(eval $(shell dpkg-architecture | sed 's/\([^=]*\)\(.*\)/$$(eval export \1?\2)/'))
diff --git a/scripts/mk/buildflags.mk b/scripts/mk/buildflags.mk
index bb496e108..dcfd969a0 100644
--- a/scripts/mk/buildflags.mk
+++ b/scripts/mk/buildflags.mk
@@ -12,15 +12,18 @@
 #
 # You can also export them in the environment by setting
 # DPKG_EXPORT_BUILDFLAGS to a non-empty value.
-#
+
+
 # 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 = CFLAGS CPPFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS \
                        GCJFLAGS 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))"
@@ -33,11 +36,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/buildtools.mk b/scripts/mk/buildtools.mk
index c3b44bb8a..a95b0a69c 100644
--- a/scripts/mk/buildtools.mk
+++ b/scripts/mk/buildtools.mk
@@ -23,27 +23,30 @@
 #
 # The variables are not exported by default. This can be changed by
 # defining DPKG_EXPORT_BUILDTOOLS.
+#
+# If TOOL is undefined or contains the Make built-in value,
+# it is assigned the Debian default prefixed with the host triplet.
+#
+# If TOOL_FOR_BUILD is undefined,
+# it is assigned the value of TOOL for native builds,
+# or the Debian default prefixed with the build triplet for cross builds.
+
 
 dpkg_datadir = $(srcdir)/mk
 include $(dpkg_datadir)/architecture.mk
 
-# We set the TOOL_FOR_BUILD variables to the specified value, and the TOOL
-# variables (for the host) to the their triplet-prefixed form iff they are
-# not defined or contain the make built-in defaults. On native builds if
-# TOOL is defined and TOOL_FOR_BUILD is not, we fallback to use TOOL.
 define dpkg_buildtool_setvar
 ifeq ($(origin $(1)),default)
 $(1) = $(DEB_HOST_GNU_TYPE)-$(2)
-endif
+else
 $(1) ?= $(DEB_HOST_GNU_TYPE)-$(2)
+endif
 
-# On native build fallback to use TOOL if that's defined.
 ifeq ($(DEB_BUILD_GNU_TYPE),$(DEB_HOST_GNU_TYPE))
-ifdef $(1)
 $(1)_FOR_BUILD ?= $$($(1))
-endif
-endif
+else
 $(1)_FOR_BUILD ?= $(DEB_BUILD_GNU_TYPE)-$(2)
+endif
 
 ifdef DPKG_EXPORT_BUILDTOOLS
 export $(1)
diff --git a/scripts/mk/pkg-info.mk b/scripts/mk/pkg-info.mk
index 15322cedd..2a4b49bec 100644
--- a/scripts/mk/pkg-info.mk
+++ b/scripts/mk/pkg-info.mk
@@ -9,16 +9,43 @@
 #
 # SOURCE_DATE_EPOCH: the source release date as seconds since the epoch, as
 #   specified by <https://reproducible-builds.org/specs/source-date-epoch/>
+# 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.20.1

Reply via email to