From 19e231bbdaef792dce22100012b504e2fb72f971 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter_e@gmx.net>
Date: Fri, 12 Nov 2010 22:15:16 +0200
Subject: [PATCH] Improved parallel make support

Replace for loops in makefiles with proper dependencies.  Parallel
make can now span across directories.  Also, make -k and make -q work
properly.

GNU make 3.80 or newer is now required.
---
 GNUmakefile.in                                | 56 +++++--------------
 contrib/Makefile                              | 12 +---
 contrib/dblink/Makefile                       |  1 +
 doc/src/sgml/installation.sgml                |  5 +-
 src/Makefile                                  | 47 +++++-----------
 src/Makefile.global.in                        | 47 +++++++++++++++-
 src/Makefile.shlib                            | 11 ++--
 src/backend/Makefile                          |  4 +-
 src/backend/common.mk                         |  6 +-
 .../replication/libpqwalreceiver/Makefile     |  3 +-
 .../utils/mb/conversion_procs/Makefile        |  6 +-
 src/bin/Makefile                              |  3 +-
 src/bin/initdb/Makefile                       |  4 +-
 src/bin/pg_config/Makefile                    |  4 +-
 src/bin/pg_controldata/Makefile               |  4 +-
 src/bin/pg_ctl/Makefile                       |  4 +-
 src/bin/pg_dump/Makefile                      |  8 +--
 src/bin/pg_resetxlog/Makefile                 |  4 +-
 src/bin/psql/Makefile                         |  4 +-
 src/bin/scripts/Makefile                      | 20 +++----
 src/interfaces/Makefile                       |  3 +-
 src/interfaces/ecpg/Makefile                  | 16 ++----
 src/interfaces/ecpg/compatlib/Makefile        |  9 +++
 src/interfaces/ecpg/ecpglib/Makefile          |  9 ++-
 src/interfaces/ecpg/preproc/Makefile          |  7 ++-
 src/pl/Makefile                               | 10 +---
 src/test/regress/GNUmakefile                  | 16 +++---
 src/timezone/Makefile                         |  4 +-
 src/tools/findoidjoins/Makefile               |  4 +-
 src/tools/fsync/Makefile                      |  4 +-
 30 files changed, 156 insertions(+), 179 deletions(-)

diff --git a/GNUmakefile.in b/GNUmakefile.in
index ed42170a9b5..8ccbdcc49fb 100644
--- a/GNUmakefile.in
+++ b/GNUmakefile.in
@@ -8,57 +8,39 @@ subdir =
 top_builddir = .
 include $(top_builddir)/src/Makefile.global
 
+$(call recurse,all install,src config)
+
 all:
-	$(MAKE) -C src all
-	$(MAKE) -C config all
-	@echo "All of PostgreSQL successfully made. Ready to install."
+	+@echo "All of PostgreSQL successfully made. Ready to install."
 
 docs:
 	$(MAKE) -C doc all
 
+$(call recurse,world,doc src config contrib,all)
 world:
-	$(MAKE) -C doc all
-	$(MAKE) -C src all
-	$(MAKE) -C config all
-	$(MAKE) -C contrib all
-	@echo "PostgreSQL, contrib, and documentation successfully made. Ready to install."
+	+@echo "PostgreSQL, contrib, and documentation successfully made. Ready to install."
 
 html man:
 	$(MAKE) -C doc $@
 
 install:
-	$(MAKE) -C src $@
-	$(MAKE) -C config $@
-	@echo "PostgreSQL installation complete."
+	+@echo "PostgreSQL installation complete."
 
 install-docs:
 	$(MAKE) -C doc install
 
+$(call recurse,install-world,doc src config contrib,install)
 install-world:
-	$(MAKE) -C doc install
-	$(MAKE) -C src install
-	$(MAKE) -C config install
-	$(MAKE) -C contrib install
-	@echo "PostgreSQL, contrib, and documentation installation complete."
+	+@echo "PostgreSQL, contrib, and documentation installation complete."
 
-installdirs uninstall coverage:
-	$(MAKE) -C doc $@
-	$(MAKE) -C src $@
-	$(MAKE) -C config $@
+$(call recurse,installdirs uninstall coverage,doc src config)
 
-distprep:
-	$(MAKE) -C doc $@
-	$(MAKE) -C src $@
-	$(MAKE) -C config $@
-	$(MAKE) -C contrib $@
+$(call recurse,distprep,doc src config contrib)
 
 # clean, distclean, etc should apply to contrib too, even though
 # it's not built by default
+$(call recurse,clean,doc contrib src config)
 clean:
-	$(MAKE) -C doc $@
-	$(MAKE) -C contrib $@
-	$(MAKE) -C src $@
-	$(MAKE) -C config $@
 # Garbage from autoconf:
 	@rm -rf autom4te.cache/
 
@@ -78,11 +60,7 @@ check: all
 check installcheck installcheck-parallel:
 	$(MAKE) -C src/test $@
 
-installcheck-world:
-	$(MAKE) -C src/test installcheck
-	$(MAKE) -C src/pl installcheck
-	$(MAKE) -C src/interfaces/ecpg installcheck
-	$(MAKE) -C contrib installcheck
+$(call recurse,installcheck-world,src/test src/pl src/interfaces/ecpg contrib,installcheck)
 
 GNUmakefile: GNUmakefile.in $(top_builddir)/config.status
 	./config.status $@
@@ -143,12 +121,4 @@ distcheck: dist
 	rm -rf $(distdir) $(dummy)
 	@echo "Distribution integrity checks out."
 
-.PHONY: dist distdir distcheck docs install-docs
-
-
-# Temporary measure to explore whether we can start requiring GNU make
-# 3.80.  That version also happens to be the version where the
-# .VARIABLES variable was introduced, so this is a simple check.
-ifndef .VARIABLES
-$(warning warning: GNU make 3.80 or newer might become required soon. You are using version $(MAKE_VERSION).)
-endif
+.PHONY: dist distdir distcheck docs install-docs world install-world installcheck-world
diff --git a/contrib/Makefile b/contrib/Makefile
index b7773255341..e1f2a84cde3 100644
--- a/contrib/Makefile
+++ b/contrib/Makefile
@@ -63,14 +63,4 @@ endif
 #		start-scripts	\ (does not have a makefile)
 
 
-all install installdirs uninstall distprep clean distclean maintainer-clean:
-	@for dir in $(SUBDIRS); do \
-		$(MAKE) -C $$dir $@ || exit; \
-	done
-
-# We'd like check operations to run all the subtests before failing.
-check installcheck:
-	@CHECKERR=0; for dir in $(SUBDIRS); do \
-		$(MAKE) -C $$dir $@ || CHECKERR=$$?; \
-	done; \
-	exit $$CHECKERR
+$(recurse)
diff --git a/contrib/dblink/Makefile b/contrib/dblink/Makefile
index 148961e6c94..cc59128cb2a 100644
--- a/contrib/dblink/Makefile
+++ b/contrib/dblink/Makefile
@@ -4,6 +4,7 @@ MODULE_big = dblink
 PG_CPPFLAGS = -I$(libpq_srcdir)
 OBJS	= dblink.o
 SHLIB_LINK = $(libpq)
+SHLIB_PREREQS = submake-libpq
 
 DATA_built = dblink.sql 
 DATA = uninstall_dblink.sql 
diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index d471e6da00e..0eeaa25af9a 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -68,8 +68,8 @@ su - postgres
        <primary>make</primary>
       </indexterm>
 
-      <acronym>GNU</> <application>make</> is required; other
-      <application>make</> programs will <emphasis>not</> work.
+      <acronym>GNU</> <application>make</> version 3.80 or newer is required; other
+      <application>make</> programs or older <acronym>GNU</> <application>make</> versions will <emphasis>not</> work.
       <acronym>GNU</> <application>make</> is often installed under
       the name <filename>gmake</filename>; this document will always
       refer to it by that name. (On some systems
@@ -79,7 +79,6 @@ su - postgres
 <screen>
 <userinput>gmake --version</userinput>
 </screen>
-      It is recommended to use version 3.79.1 or later.
      </para>
     </listitem>
 
diff --git a/src/Makefile b/src/Makefile
index 0e1e43197a4..0d4a6ee65b9 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -12,20 +12,21 @@ subdir = src
 top_builddir = ..
 include Makefile.global
 
+SUBDIRS = \
+	port \
+	timezone \
+	backend \
+	backend/utils/mb/conversion_procs \
+	backend/snowball \
+	include \
+	interfaces \
+	backend/replication/libpqwalreceiver \
+	bin \
+	pl \
+	makefiles \
+	test/regress
 
-all install installdirs uninstall distprep:
-	$(MAKE) -C port $@
-	$(MAKE) -C timezone $@
-	$(MAKE) -C backend $@
-	$(MAKE) -C backend/utils/mb/conversion_procs $@
-	$(MAKE) -C backend/snowball $@
-	$(MAKE) -C include $@
-	$(MAKE) -C interfaces $@
-	$(MAKE) -C backend/replication/libpqwalreceiver $@
-	$(MAKE) -C bin $@
-	$(MAKE) -C pl $@
-	$(MAKE) -C makefiles $@
-	$(MAKE) -C test/regress $@
+$(recurse)
 
 install: install-local
 
@@ -46,31 +47,11 @@ uninstall-local:
 	rm -f $(addprefix '$(DESTDIR)$(pgxsdir)/$(subdir)'/, Makefile.global Makefile.port Makefile.shlib nls-global.mk)
 
 clean:
-	$(MAKE) -C port $@
-	$(MAKE) -C timezone $@
-	$(MAKE) -C backend $@
-	$(MAKE) -C backend/snowball $@
-	$(MAKE) -C include $@
-	$(MAKE) -C interfaces $@
-	$(MAKE) -C backend/replication/libpqwalreceiver $@
-	$(MAKE) -C bin $@
-	$(MAKE) -C pl $@
-	$(MAKE) -C makefiles $@
 	$(MAKE) -C test $@
 	$(MAKE) -C tutorial NO_PGXS=1 $@
 	$(MAKE) -C test/thread $@
 
 distclean maintainer-clean:
-	$(MAKE) -C port $@
-	$(MAKE) -C timezone $@
-	$(MAKE) -C backend $@
-	$(MAKE) -C backend/snowball $@
-	$(MAKE) -C include $@
-	$(MAKE) -C interfaces $@
-	$(MAKE) -C backend/replication/libpqwalreceiver $@
-	$(MAKE) -C bin $@
-	$(MAKE) -C pl $@
-	$(MAKE) -C makefiles $@
 	$(MAKE) -C test $@
 	$(MAKE) -C tutorial NO_PGXS=1 $@
 	$(MAKE) -C test/thread $@
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index 5d308453ced..d290116f8cd 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -18,7 +18,9 @@
 #
 # Meta configuration
 
-.PHONY: all install install-strip installdirs uninstall clean distclean maintainer-clean distprep check installcheck maintainer-check coverage html man installcheck-parallel world install-world installcheck-world
+standard_targets = all install installdirs uninstall distprep clean distclean maintainer-clean coverage check installcheck
+
+.PHONY: $(standard_targets) install-strip maintainer-check html man installcheck-parallel
 
 # make `all' the default target
 all:
@@ -538,6 +540,48 @@ install-strip:
 	    install
 
 
+##########################################################################
+#
+# Recursive make support
+# ----------------------
+# Instead of recursing through subdirectories with a for loop or
+# repeated $(MAKE) -C whatever calls, this is a little smarter: it
+# allows parallel make across directories and lets make -k and -q work
+# correctly.
+
+# This function is only for internal use below.  It should be called
+# with $(eval).  It will set up a target so that it recurses into
+# subdirectories.
+# $1: target name, e.g., all
+# $2: list of subdirs
+# $3: target to run in subdir, usually same as $1
+define _create_recursive_target
+.PHONY: $(patsubst %,$(1)-%-recursive,$(2))
+$(1): $(patsubst %,$(1)-%-recursive,$(2))
+$(2:%=$(1)-%-recursive):
+	$$(MAKE) -C $$(patsubst $(1)-%-recursive,%,$$@) $(3)
+endef
+# Note that the use of $$ on the last line above is important; we want
+# those variables/functions to be evaluated when the rule is run, not
+# when the $(eval) is run to create the rule.  In the case of
+# $$(MAKE), this is necessary to get make -q working.
+
+# Call this function in a makefile.  In the normal case it doesn't
+# need any arguments.
+# $1: targets to make recursive (defaults to list of standard targets)
+# $2: list of subdirs (defaults to SUBDIRS variable)
+# $3: target to run in subdir (defaults to $1)
+recurse = $(foreach target,$(if $1,$1,$(standard_targets)),$(eval $(call _create_recursive_target,$(target),$(if $2,$2,$(SUBDIRS)),$(if $3,$3,$(target)))))
+
+# We need the $(eval) function and order-only prerequisites, which are
+# available in GNU make 3.80.  That also happens to be the version
+# where the .VARIABLES variable was introduced, so this is a simple
+# check.
+ifndef .VARIABLES
+$(error GNU make 3.80 or newer is required.  You are using version $(MAKE_VERSION))
+endif
+
+
 ##########################################################################
 #
 # Automatic dependency generation
@@ -640,7 +684,6 @@ lcov.info: $(gcda_files)
 	$(GCOV) -b -f -p -o . $(GCOVFLAGS) $*.c >$*.c.gcov.out
 
 coverage: $(gcda_files:.gcda=.c.gcov) lcov.info
-	$(if $(SUBDIRS),for dir in $(SUBDIRS); do $(MAKE) -C $$dir coverage || exit; done)
 
 .PHONY: coverage-html
 coverage-html: coverage
diff --git a/src/Makefile.shlib b/src/Makefile.shlib
index 3e5387fb717..b6dea47f905 100644
--- a/src/Makefile.shlib
+++ b/src/Makefile.shlib
@@ -22,6 +22,7 @@
 # OBJS                  List of object files to include in library
 # SHLIB_LINK            If shared library relies on other libraries,
 #                       additional stuff to put in its link command
+# SHLIB_PREREQS         Order-only prerequisites for library build target
 # SHLIB_EXPORTS         (optional) Name of file containing list of symbols to
 #                       export, in the format "function_name  number"
 #
@@ -340,7 +341,7 @@ all-static-lib: $(stlib)
 all-shared-lib: $(shlib)
 
 ifndef haslibarule
-$(stlib): $(OBJS)
+$(stlib): $(OBJS) | $(SHLIB_PREREQS)
 	$(LINK.static) $@ $^
 	$(RANLIB) $@
 endif #haslibarule
@@ -351,7 +352,7 @@ ifeq (,$(filter cygwin win32,$(PORTNAME)))
 ifneq ($(PORTNAME), aix)
 
 # Normal case
-$(shlib): $(OBJS)
+$(shlib): $(OBJS) | $(SHLIB_PREREQS)
 	$(LINK.shared) -o $@ $(OBJS) $(LDFLAGS) $(LDFLAGS_SL) $(SHLIB_LINK)
 ifdef shlib_major
 # If we're using major and minor versions, then make a symlink to major-version-only.
@@ -382,7 +383,7 @@ endif
 else # PORTNAME == aix
 
 # AIX case
-$(shlib) $(stlib): $(OBJS)
+$(shlib) $(stlib): $(OBJS) | $(SHLIB_PREREQS)
 	$(LINK.static) $(stlib) $^
 	$(RANLIB) $(stlib)
 	$(MKLDEXPORT) $(stlib) >$(exports_file)
@@ -408,10 +409,10 @@ else
 DLL_DEFFILE = lib$(NAME)dll.def
 endif
 
-$(shlib): $(OBJS) $(DLL_DEFFILE)
+$(shlib): $(OBJS) $(DLL_DEFFILE) | $(SHLIB_PREREQS)
 	$(DLLWRAP) -o $@ --dllname $(shlib) $(DLLWRAP_FLAGS) --def $(DLL_DEFFILE) $(OBJS) $(LDFLAGS) $(LDFLAGS_SL) $(SHLIB_LINK)
 
-$(stlib): $(shlib) $(DLL_DEFFILE)
+$(stlib): $(shlib) $(DLL_DEFFILE) | $(SHLIB_PREREQS)
 	$(DLLTOOL) --dllname $(shlib) $(DLLTOOL_LIBFLAGS) --def $(DLL_DEFFILE) --output-lib $@
 
 endif # PORTNAME == cygwin || PORTNAME == win32
diff --git a/src/backend/Makefile b/src/backend/Makefile
index bed086c6f79..9a0f2e21e56 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -122,7 +122,9 @@ submake-schemapg:
 
 .PHONY: submake-schemapg
 
-catalog/schemapg.h: submake-schemapg
+catalog/schemapg.h: | submake-schemapg
+
+$(top_builddir)/src/port/libpgport_srv.a: | submake-libpgport
 
 
 # The postgres.o target is needed by the rule in Makefile.global that
diff --git a/src/backend/common.mk b/src/backend/common.mk
index 5ba8822b4f7..4e0a5da3334 100644
--- a/src/backend/common.mk
+++ b/src/backend/common.mk
@@ -34,15 +34,13 @@ objfiles.txt: Makefile $(SUBDIROBJS) $(OBJS)
 expand_subsys = $(foreach file,$(1),$(if $(filter %/objfiles.txt,$(file)),$(patsubst ../../src/backend/%,%,$(addprefix $(top_builddir)/,$(shell cat $(file)))),$(file)))
 
 # Parallel make trickery
-$(SUBDIROBJS): $(SUBDIRS:%=%-recursive) ;
+$(SUBDIROBJS): | $(SUBDIRS:%=%-recursive) ;
 
 .PHONY: $(SUBDIRS:%=%-recursive)
 $(SUBDIRS:%=%-recursive):
 	$(MAKE) -C $(subst -recursive,,$@) all
 
+$(call recurse,clean)
 clean: clean-local
 clean-local:
-ifdef SUBDIRS
-	for dir in $(SUBDIRS); do $(MAKE) -C $$dir clean || exit; done
-endif
 	rm -f $(subsysfilename) $(OBJS)
diff --git a/src/backend/replication/libpqwalreceiver/Makefile b/src/backend/replication/libpqwalreceiver/Makefile
index c310b3ba48f..774adaa24d4 100644
--- a/src/backend/replication/libpqwalreceiver/Makefile
+++ b/src/backend/replication/libpqwalreceiver/Makefile
@@ -16,9 +16,10 @@ override CPPFLAGS := -I$(srcdir) -I$(libpq_srcdir) $(CPPFLAGS)
 
 OBJS = libpqwalreceiver.o
 SHLIB_LINK = $(libpq)
+SHLIB_PREREQS = submake-libpq
 NAME = libpqwalreceiver
 
-all: submake-libpq all-shared-lib
+all: all-shared-lib
 
 include $(top_srcdir)/src/Makefile.shlib
 
diff --git a/src/backend/utils/mb/conversion_procs/Makefile b/src/backend/utils/mb/conversion_procs/Makefile
index 3cdc45708e3..0848d963356 100644
--- a/src/backend/utils/mb/conversion_procs/Makefile
+++ b/src/backend/utils/mb/conversion_procs/Makefile
@@ -26,6 +26,8 @@ SUBDIRS = \
 	utf8_and_sjis utf8_and_win utf8_and_uhc \
 	utf8_and_euc2004 utf8_and_sjis2004 euc2004_sjis2004
 
+$(recurse)
+
 # conversion_name source_encoding destination_encoding function object
 CONVERSIONS = \
 		ascii_to_mic	SQL_ASCII MULE_INTERNAL ascii_to_mic ascii_and_mic \
@@ -162,7 +164,6 @@ CONVERSIONS = \
 		shift_jis_2004_to_euc_jis_2004 SHIFT_JIS_2004 EUC_JIS_2004 shift_jis_2004_to_euc_jis_2004 euc2004_sjis2004
 
 all: $(SQLSCRIPT)
-	@for dir in $(SUBDIRS); do $(MAKE) -C $$dir $@ || exit; done
 
 $(SQLSCRIPT): Makefile
 ifeq ($(enable_shared), yes)
@@ -205,15 +206,12 @@ $(REGRESSION_SCRIPT): Makefile
 
 install: $(SQLSCRIPT) installdirs
 	$(INSTALL_DATA) $(SQLSCRIPT) '$(DESTDIR)$(datadir)'
-	@for dir in $(SUBDIRS); do $(MAKE) -C $$dir $@ || exit; done
 
 installdirs:
 	$(MKDIR_P) '$(DESTDIR)$(datadir)' '$(DESTDIR)$(pkglibdir)'
 
 uninstall:
 	rm -f '$(DESTDIR)$(datadir)/$(SQLSCRIPT)'
-	@for dir in $(SUBDIRS); do $(MAKE) -C $$dir $@ || exit; done
 
 clean distclean maintainer-clean:
 	rm -f $(SQLSCRIPT)
-	@for dir in $(SUBDIRS); do $(MAKE) -C $$dir $@ || exit; done
diff --git a/src/bin/Makefile b/src/bin/Makefile
index 63b32e4598b..c81b6654817 100644
--- a/src/bin/Makefile
+++ b/src/bin/Makefile
@@ -19,5 +19,4 @@ ifeq ($(PORTNAME), win32)
 SUBDIRS+=pgevent
 endif
 
-all install installdirs uninstall distprep clean distclean maintainer-clean:
-	@for dir in $(SUBDIRS); do $(MAKE) -C $$dir $@ || exit; done
+$(recurse)
diff --git a/src/bin/initdb/Makefile b/src/bin/initdb/Makefile
index 99c8b1bca40..903fbc10970 100644
--- a/src/bin/initdb/Makefile
+++ b/src/bin/initdb/Makefile
@@ -20,9 +20,9 @@ override CPPFLAGS := -DFRONTEND -I$(libpq_srcdir) $(CPPFLAGS)
 
 OBJS=	initdb.o encnames.o pqsignal.o $(WIN32RES)
 
-all: submake-libpgport initdb
+all: initdb
 
-initdb: $(OBJS)
+initdb: $(OBJS) | submake-libpgport
 	$(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
 # We used to pull in all of libpq to get encnames and pqsignal, but that
diff --git a/src/bin/pg_config/Makefile b/src/bin/pg_config/Makefile
index 732144dde6c..c7e5a023744 100644
--- a/src/bin/pg_config/Makefile
+++ b/src/bin/pg_config/Makefile
@@ -31,9 +31,9 @@ override CPPFLAGS += -DVAL_LDFLAGS_EX="\"$(LDFLAGS_EX)\""
 override CPPFLAGS += -DVAL_LDFLAGS_SL="\"$(LDFLAGS_SL)\""
 override CPPFLAGS += -DVAL_LIBS="\"$(LIBS)\""
 
-all: submake-libpgport pg_config
+all: pg_config
 
-pg_config: $(OBJS)
+pg_config: $(OBJS) | submake-libpgport
 	$(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
 install: all installdirs
diff --git a/src/bin/pg_controldata/Makefile b/src/bin/pg_controldata/Makefile
index bcdf741fdc5..180c5ebfe8d 100644
--- a/src/bin/pg_controldata/Makefile
+++ b/src/bin/pg_controldata/Makefile
@@ -17,9 +17,9 @@ include $(top_builddir)/src/Makefile.global
 
 OBJS= pg_controldata.o pg_crc.o $(WIN32RES)
 
-all: submake-libpgport pg_controldata
+all: pg_controldata
 
-pg_controldata: $(OBJS)
+pg_controldata: $(OBJS) | submake-libpgport
 	$(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
 pg_crc.c: $(top_srcdir)/src/backend/utils/hash/pg_crc.c
diff --git a/src/bin/pg_ctl/Makefile b/src/bin/pg_ctl/Makefile
index 0d49509724e..992799c2155 100644
--- a/src/bin/pg_ctl/Makefile
+++ b/src/bin/pg_ctl/Makefile
@@ -20,9 +20,9 @@ override CPPFLAGS := -DDEF_PGPORT=$(DEF_PGPORT) -I$(libpq_srcdir) $(CPPFLAGS)
 
 OBJS=	pg_ctl.o $(WIN32RES)
 
-all: submake-libpq submake-libpgport pg_ctl
+all: pg_ctl
 
-pg_ctl: $(OBJS) $(libpq_builddir)/libpq.a
+pg_ctl: $(OBJS) | submake-libpq submake-libpgport
 	$(CC) $(CFLAGS) $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
 install: all installdirs
diff --git a/src/bin/pg_dump/Makefile b/src/bin/pg_dump/Makefile
index f4c716ee2fc..0367466f845 100644
--- a/src/bin/pg_dump/Makefile
+++ b/src/bin/pg_dump/Makefile
@@ -27,15 +27,15 @@ KEYWRDOBJS = keywords.o kwlookup.o
 kwlookup.c: % : $(top_srcdir)/src/backend/parser/%
 	rm -f $@ && $(LN_S) $< .
 
-all: submake-libpq submake-libpgport pg_dump pg_restore pg_dumpall
+all: pg_dump pg_restore pg_dumpall
 
-pg_dump: pg_dump.o common.o pg_dump_sort.o $(OBJS) $(KEYWRDOBJS) $(libpq_builddir)/libpq.a 
+pg_dump: pg_dump.o common.o pg_dump_sort.o $(OBJS) $(KEYWRDOBJS) | submake-libpq submake-libpgport
 	$(CC) $(CFLAGS) pg_dump.o common.o pg_dump_sort.o $(KEYWRDOBJS) $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
-pg_restore: pg_restore.o $(OBJS) $(KEYWRDOBJS) $(libpq_builddir)/libpq.a
+pg_restore: pg_restore.o $(OBJS) $(KEYWRDOBJS) | submake-libpq submake-libpgport
 	$(CC) $(CFLAGS) pg_restore.o $(KEYWRDOBJS) $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
-pg_dumpall: pg_dumpall.o dumputils.o $(KEYWRDOBJS) $(libpq_builddir)/libpq.a
+pg_dumpall: pg_dumpall.o dumputils.o $(KEYWRDOBJS) | submake-libpq submake-libpgport
 	$(CC) $(CFLAGS) pg_dumpall.o dumputils.o $(KEYWRDOBJS) $(WIN32RES) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
 install: all installdirs
diff --git a/src/bin/pg_resetxlog/Makefile b/src/bin/pg_resetxlog/Makefile
index 67ba562949f..ad56a115033 100644
--- a/src/bin/pg_resetxlog/Makefile
+++ b/src/bin/pg_resetxlog/Makefile
@@ -17,9 +17,9 @@ include $(top_builddir)/src/Makefile.global
 
 OBJS= pg_resetxlog.o pg_crc.o $(WIN32RES)
 
-all: submake-libpgport pg_resetxlog
+all: pg_resetxlog
 
-pg_resetxlog: $(OBJS)
+pg_resetxlog: $(OBJS) | submake-libpgport
 	$(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
 pg_crc.c: $(top_srcdir)/src/backend/utils/hash/pg_crc.c
diff --git a/src/bin/psql/Makefile b/src/bin/psql/Makefile
index 9e1c3cd6f77..a30c6684240 100644
--- a/src/bin/psql/Makefile
+++ b/src/bin/psql/Makefile
@@ -29,9 +29,9 @@ OBJS=	command.o common.o help.o input.o stringutils.o mainloop.o copy.o \
 FLEXFLAGS = -Cfe
 
 
-all: submake-libpq submake-libpgport psql
+all: psql
 
-psql: $(OBJS) $(libpq_builddir)/libpq.a
+psql: $(OBJS) | submake-libpq submake-libpgport
 	$(CC) $(CFLAGS) $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
 help.o: sql_help.h
diff --git a/src/bin/scripts/Makefile b/src/bin/scripts/Makefile
index 4248f3bedd9..d0b0c1c20e0 100644
--- a/src/bin/scripts/Makefile
+++ b/src/bin/scripts/Makefile
@@ -20,20 +20,20 @@ PROGRAMS = createdb createlang createuser dropdb droplang dropuser clusterdb vac
 
 override CPPFLAGS := -I$(top_srcdir)/src/bin/pg_dump -I$(top_srcdir)/src/bin/psql -I$(libpq_srcdir) $(CPPFLAGS)
 
-all: submake-libpq $(PROGRAMS)
+all: $(PROGRAMS)
 
 %: %.o $(WIN32RES)
 	$(CC) $(CFLAGS) $^ $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
-createdb: createdb.o common.o dumputils.o kwlookup.o keywords.o
-createlang: createlang.o common.o print.o mbprint.o
-createuser: createuser.o common.o dumputils.o kwlookup.o keywords.o
-dropdb: dropdb.o common.o dumputils.o kwlookup.o keywords.o
-droplang: droplang.o common.o print.o mbprint.o
-dropuser: dropuser.o common.o dumputils.o kwlookup.o keywords.o
-clusterdb: clusterdb.o common.o dumputils.o kwlookup.o keywords.o
-vacuumdb: vacuumdb.o common.o
-reindexdb: reindexdb.o common.o dumputils.o kwlookup.o keywords.o
+createdb: createdb.o common.o dumputils.o kwlookup.o keywords.o | submake-libpq
+createlang: createlang.o common.o print.o mbprint.o | submake-libpq
+createuser: createuser.o common.o dumputils.o kwlookup.o keywords.o | submake-libpq
+dropdb: dropdb.o common.o dumputils.o kwlookup.o keywords.o | submake-libpq
+droplang: droplang.o common.o print.o mbprint.o | submake-libpq
+dropuser: dropuser.o common.o dumputils.o kwlookup.o keywords.o | submake-libpq
+clusterdb: clusterdb.o common.o dumputils.o kwlookup.o keywords.o | submake-libpq
+vacuumdb: vacuumdb.o common.o | submake-libpq
+reindexdb: reindexdb.o common.o dumputils.o kwlookup.o keywords.o | submake-libpq
 
 dumputils.c keywords.c: % : $(top_srcdir)/src/bin/pg_dump/%
 	rm -f $@ && $(LN_S) $< .
diff --git a/src/interfaces/Makefile b/src/interfaces/Makefile
index f208a28919b..2c034bc7923 100644
--- a/src/interfaces/Makefile
+++ b/src/interfaces/Makefile
@@ -14,5 +14,4 @@ include $(top_builddir)/src/Makefile.global
 
 SUBDIRS = libpq ecpg
 
-all install installdirs uninstall distprep clean distclean maintainer-clean:
-	@for dir in $(SUBDIRS); do $(MAKE) -C $$dir $@ || exit; done
+$(recurse)
diff --git a/src/interfaces/ecpg/Makefile b/src/interfaces/ecpg/Makefile
index 71bfff672d7..d955ceed1c9 100644
--- a/src/interfaces/ecpg/Makefile
+++ b/src/interfaces/ecpg/Makefile
@@ -2,19 +2,13 @@ subdir = src/interfaces/ecpg
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-all install installdirs uninstall distprep:
-	$(MAKE) -C include $@
-	$(MAKE) -C pgtypeslib $@
-	$(MAKE) -C ecpglib $@
-	$(MAKE) -C compatlib $@
-	$(MAKE) -C preproc $@
+SUBDIRS = include pgtypeslib ecpglib compatlib preproc
+
+$(recurse)
+
+all-compatlib-recursive: all-ecpglib-recursive
 
 clean distclean maintainer-clean:
-	$(MAKE) -C include $@
-	$(MAKE) -C pgtypeslib $@
-	$(MAKE) -C ecpglib $@
-	$(MAKE) -C compatlib $@
-	$(MAKE) -C preproc $@
 	$(MAKE) -C test clean
 
 check checktcp installcheck: all
diff --git a/src/interfaces/ecpg/compatlib/Makefile b/src/interfaces/ecpg/compatlib/Makefile
index d211b7d20a7..eb9a76ae74b 100644
--- a/src/interfaces/ecpg/compatlib/Makefile
+++ b/src/interfaces/ecpg/compatlib/Makefile
@@ -23,6 +23,7 @@ override CFLAGS += $(PTHREAD_CFLAGS)
 
 SHLIB_LINK = -L../ecpglib -lecpg -L../pgtypeslib -lpgtypes $(libpq) \
 	$(filter -lintl -lm, $(LIBS)) $(PTHREAD_LIBS)
+SHLIB_PREREQS = submake-ecpglib submake-pgtypeslib
 
 SHLIB_EXPORTS = exports.txt
 
@@ -33,6 +34,14 @@ OBJS= informix.o $(filter snprintf.o, $(LIBOBJS))
 
 all: all-lib
 
+.PHONY: submake-ecpglib submake-pgtypeslib
+
+submake-ecpglib:
+	$(MAKE) -C $(top_builddir)/src/interfaces/ecpg/ecpglib all
+
+submake-pgtypeslib:
+	$(MAKE) -C $(top_builddir)/src/interfaces/ecpg/pgtypeslib all
+
 # Shared library stuff
 include $(top_srcdir)/src/Makefile.shlib
 
diff --git a/src/interfaces/ecpg/ecpglib/Makefile b/src/interfaces/ecpg/ecpglib/Makefile
index 7d134acd7f3..9a29d150c7e 100644
--- a/src/interfaces/ecpg/ecpglib/Makefile
+++ b/src/interfaces/ecpg/ecpglib/Makefile
@@ -34,6 +34,7 @@ OBJS += thread.o
 endif
 
 SHLIB_LINK = -L../pgtypeslib -lpgtypes $(libpq) $(filter -lintl -lm, $(LIBS)) $(PTHREAD_LIBS)
+SHLIB_PREREQS = submake-libpq submake-pgtypeslib
 
 SHLIB_EXPORTS = exports.txt
 
@@ -42,12 +43,10 @@ ifeq ($(PORTNAME), win32)
 SHLIB_LINK += -lshfolder
 endif
 
-all: libpq pgtypeslib all-lib
+all: all-lib
 
-libpq:
-	$(MAKE) -C $(top_builddir)/src/interfaces/libpq all
-
-pgtypeslib:
+.PHONY: submake-pgtypeslib
+submake-pgtypeslib:
 	$(MAKE) -C $(top_builddir)/src/interfaces/ecpg/pgtypeslib all
 
 # Shared library stuff
diff --git a/src/interfaces/ecpg/preproc/Makefile b/src/interfaces/ecpg/preproc/Makefile
index 8978eeb241f..e8a6916faa8 100644
--- a/src/interfaces/ecpg/preproc/Makefile
+++ b/src/interfaces/ecpg/preproc/Makefile
@@ -30,11 +30,14 @@ OBJS=	preproc.o type.o ecpg.o output.o parser.o \
 	keywords.o c_keywords.o ecpg_keywords.o kwlookup.o ../ecpglib/typename.o descriptor.o variable.o \
 	$(WIN32RES)
 
-all: submake-libpgport ecpg
+all: ecpg
 
-ecpg: $(OBJS)
+ecpg: $(OBJS) | submake-libpgport
 	$(CC) $(CFLAGS) $(LDFLAGS) $(LDFLAGS_EX) $^ $(LIBS) $(PTHREAD_LIBS) -o $@$(X)
 
+../ecpglib/typename.o: ../ecpglib/typename.c
+	$(MAKE) -C $(dir $@) $(notdir $@)
+
 # pgc is compiled as part of preproc
 preproc.o: pgc.c
 
diff --git a/src/pl/Makefile b/src/pl/Makefile
index c625c0de508..ef630fe8d2e 100644
--- a/src/pl/Makefile
+++ b/src/pl/Makefile
@@ -26,12 +26,4 @@ ifeq ($(with_tcl), yes)
 SUBDIRS += tcl
 endif
 
-all install installdirs uninstall distprep clean distclean maintainer-clean:
-	@for dir in $(SUBDIRS); do $(MAKE) -C $$dir $@ || exit; done
-
-# We'd like check operations to run all the subtests before failing.
-check installcheck:
-	@CHECKERR=0; for dir in $(SUBDIRS); do \
-		$(MAKE) -C $$dir $@ || CHECKERR=$$?; \
-	done; \
-	exit $$CHECKERR
+$(recurse)
diff --git a/src/test/regress/GNUmakefile b/src/test/regress/GNUmakefile
index b2b5b16153c..0755304820c 100644
--- a/src/test/regress/GNUmakefile
+++ b/src/test/regress/GNUmakefile
@@ -50,9 +50,9 @@ EXTRADEFS = '-DHOST_TUPLE="$(host_tuple)"' \
 
 # Build regression test driver
 
-all: submake-libpgport pg_regress$(X)
+all: pg_regress$(X)
 
-pg_regress$(X): pg_regress.o pg_regress_main.o
+pg_regress$(X): pg_regress.o pg_regress_main.o | submake-libpgport
 	$(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@
 
 # dependencies ensure that path changes propagate
@@ -131,8 +131,6 @@ $(top_builddir)/contrib/dummy_seclabel/dummy_seclabel$(DLSUFFIX): $(top_builddir
 
 # Tablespace setup
 
-all: tablespace-setup
-
 .PHONY: tablespace-setup
 tablespace-setup:
 	rm -rf ./testtablespace
@@ -145,13 +143,13 @@ tablespace-setup:
 
 pg_regress_call = ./pg_regress --inputdir=$(srcdir) --dlpath=. --multibyte=$(MULTIBYTE) $(NOLOCALE)
 
-check: all
+check: all tablespace-setup
 	$(pg_regress_call) --temp-install=./tmp_check --top-builddir=$(top_builddir) --schedule=$(srcdir)/parallel_schedule $(MAXCONNOPT) $(TEMP_CONF)
 
-installcheck: all
+installcheck: all tablespace-setup
 	$(pg_regress_call) --psqldir=$(PSQLDIR) --schedule=$(srcdir)/serial_schedule
 
-installcheck-parallel: all
+installcheck-parallel: all tablespace-setup
 	$(pg_regress_call) --psqldir=$(PSQLDIR) --schedule=$(srcdir)/parallel_schedule $(MAXCONNOPT)
 
 standbycheck: all
@@ -163,10 +161,10 @@ runcheck: check
 runtest: installcheck
 runtest-parallel: installcheck-parallel
 
-bigtest: all
+bigtest: all tablespace-setup
 	$(pg_regress_call) --psqldir=$(PSQLDIR) --schedule=$(srcdir)/serial_schedule numeric_big 
 
-bigcheck: all
+bigcheck: all tablespace-setup
 	$(pg_regress_call) --temp-install=./tmp_check --top-builddir=$(top_builddir) --schedule=$(srcdir)/parallel_schedule $(MAXCONNOPT) numeric_big
 
 
diff --git a/src/timezone/Makefile b/src/timezone/Makefile
index a20ddb043af..2cecaec5e63 100644
--- a/src/timezone/Makefile
+++ b/src/timezone/Makefile
@@ -35,7 +35,7 @@ endif
 include $(top_srcdir)/src/backend/common.mk
 
 ifeq (,$(with_system_tzdata))
-all: submake-libpgport zic
+all: zic
 endif
 
 # We could do this test in the action section:
@@ -46,7 +46,7 @@ ifeq (,$(ZIC))
 ZIC= ./zic
 endif
 
-zic: $(ZICOBJS)
+zic: $(ZICOBJS) | submake-libpgport
 	$(CC) $(CFLAGS) $(ZICOBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
 install: all installdirs
diff --git a/src/tools/findoidjoins/Makefile b/src/tools/findoidjoins/Makefile
index db3c8f9a9df..ac9f4801243 100644
--- a/src/tools/findoidjoins/Makefile
+++ b/src/tools/findoidjoins/Makefile
@@ -16,9 +16,9 @@ override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS)
 
 OBJS= findoidjoins.o
 
-all: submake-libpq submake-libpgport findoidjoins
+all: findoidjoins
 
-findoidjoins: findoidjoins.o $(libpq_builddir)/libpq.a
+findoidjoins: findoidjoins.o | submake-libpq submake-libpgport
 	$(CC) $(CFLAGS) findoidjoins.o $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
 clean distclean maintainer-clean:
diff --git a/src/tools/fsync/Makefile b/src/tools/fsync/Makefile
index b0fd13b6926..252c087898b 100644
--- a/src/tools/fsync/Makefile
+++ b/src/tools/fsync/Makefile
@@ -16,9 +16,9 @@ override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS)
 
 OBJS= test_fsync.o
 
-all: submake-libpq submake-libpgport test_fsync
+all: test_fsync
 
-test_fsync: test_fsync.o $(libpq_builddir)/libpq.a
+test_fsync: test_fsync.o | submake-libpq submake-libpgport
 	$(CC) $(CFLAGS) test_fsync.o $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
 clean distclean maintainer-clean:
-- 
GitLab