diff --git a/src/backend/Makefile b/src/backend/Makefile
index 4a28267..d0f99a6 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -131,19 +131,20 @@ postgres.o: $(OBJS)
 # match the dependencies shown in the subdirectory makefiles!
 
 parser/gram.h: parser/gram.y
-	$(MAKE) -C parser gram.h
+	$(MAKE) -C parser gram.h gram.c
 
 storage/lmgr/lwlocknames.h: storage/lmgr/generate-lwlocknames.pl storage/lmgr/lwlocknames.txt
-	$(MAKE) -C storage/lmgr lwlocknames.h
+	$(MAKE) -C storage/lmgr lwlocknames.h lwlocknames.c
 
 utils/errcodes.h: utils/generate-errcodes.pl utils/errcodes.txt
 	$(MAKE) -C utils errcodes.h
 
 # see explanation in parser/Makefile
-utils/fmgrprotos.h: utils/fmgroids.h ;
+utils/fmgrprotos.h: utils/fmgroids.h
+	touch $@
 
 utils/fmgroids.h: utils/Gen_fmgrtab.pl catalog/Catalog.pm $(top_srcdir)/src/include/catalog/pg_proc.h
-	$(MAKE) -C utils $(notdir $@)
+	$(MAKE) -C utils fmgroids.h fmgrprotos.h
 
 utils/probes.h: utils/probes.d
 	$(MAKE) -C utils probes.h
@@ -218,7 +219,7 @@ distprep:
 	$(MAKE) -C bootstrap	bootparse.c bootscanner.c
 	$(MAKE) -C catalog	schemapg.h postgres.bki postgres.description postgres.shdescription
 	$(MAKE) -C replication	repl_gram.c repl_scanner.c syncrep_gram.c syncrep_scanner.c
-	$(MAKE) -C storage/lmgr	lwlocknames.h
+	$(MAKE) -C storage/lmgr	lwlocknames.h lwlocknames.c
 	$(MAKE) -C utils	fmgrtab.c fmgroids.h fmgrprotos.h errcodes.h
 	$(MAKE) -C utils/misc	guc-file.c
 	$(MAKE) -C utils/sort	qsort_tuple.c
diff --git a/src/backend/parser/Makefile b/src/backend/parser/Makefile
index 4b97f83..304f90e 100644
--- a/src/backend/parser/Makefile
+++ b/src/backend/parser/Makefile
@@ -24,11 +24,14 @@ include $(top_srcdir)/src/backend/common.mk
 # There is no correct way to write a rule that generates two files.
 # Rules with two targets don't have that meaning, they are merely
 # shorthand for two otherwise separate rules.  To be safe for parallel
-# make, we must chain the dependencies like this.  The semicolon is
-# important, otherwise make will choose the built-in rule for
-# gram.y=>gram.c.
-
-gram.h: gram.c ;
+# make, we must chain the dependencies like this.  Furthermore, the
+# "touch" step is essential, because it ensures that gram.h is seen as
+# newer than (or at least no older than) gram.c.  Without that, make is
+# likely to try to rebuild both files at inopportune times, causing
+# havoc in parallel or VPATH builds.
+
+gram.h: gram.c
+	touch $@
 
 gram.c: BISONFLAGS += -d
 gram.c: BISON_CHECK_CMD = $(PERL) $(srcdir)/check_keywords.pl $< $(top_srcdir)/src/include/parser/kwlist.h
diff --git a/src/backend/storage/lmgr/Makefile b/src/backend/storage/lmgr/Makefile
index e1b787e..d97f672 100644
--- a/src/backend/storage/lmgr/Makefile
+++ b/src/backend/storage/lmgr/Makefile
@@ -26,7 +26,8 @@ s_lock_test: s_lock.c $(top_builddir)/src/port/libpgport.a
 		$(TASPATH) -L $(top_builddir)/src/port -lpgport -o s_lock_test
 
 # see explanation in ../../parser/Makefile
-lwlocknames.c: lwlocknames.h ;
+lwlocknames.c: lwlocknames.h
+	touch $@
 
 lwlocknames.h: $(top_srcdir)/src/backend/storage/lmgr/lwlocknames.txt generate-lwlocknames.pl
 	$(PERL) $(srcdir)/generate-lwlocknames.pl $<
diff --git a/src/backend/utils/Makefile b/src/backend/utils/Makefile
index efb8b53..0809cd8 100644
--- a/src/backend/utils/Makefile
+++ b/src/backend/utils/Makefile
@@ -21,8 +21,11 @@ all: errcodes.h fmgroids.h fmgrprotos.h probes.h
 $(SUBDIRS:%=%-recursive): fmgroids.h fmgrprotos.h
 
 # see explanation in ../parser/Makefile
-fmgrprotos.h: fmgroids.h ;
-fmgroids.h: fmgrtab.c ;
+fmgrprotos.h: fmgroids.h
+	touch $@
+
+fmgroids.h: fmgrtab.c
+	touch $@
 
 fmgrtab.c: Gen_fmgrtab.pl $(catalogdir)/Catalog.pm $(top_srcdir)/src/include/catalog/pg_proc.h
 	$(PERL) -I $(catalogdir) $< -I $(top_srcdir)/src/include/ $(top_srcdir)/src/include/catalog/pg_proc.h
diff --git a/src/bin/psql/Makefile b/src/bin/psql/Makefile
index c8eb2f9..58f7aa8 100644
--- a/src/bin/psql/Makefile
+++ b/src/bin/psql/Makefile
@@ -35,7 +35,11 @@ psql: $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
 
 help.o: sql_help.h
 
-sql_help.c: sql_help.h ;
+# sql_help.c is built by create_help.pl, but make sure it's newer than
+# sql_help.h (see comments in src/backend/parser/Makefile)
+sql_help.c: sql_help.h
+	touch $@
+
 sql_help.h: create_help.pl $(wildcard $(REFDOCDIR)/*.sgml)
 	$(PERL) $< $(REFDOCDIR) $*
 
@@ -43,7 +47,7 @@ psqlscanslash.c: FLEXFLAGS = -Cfe -p -p
 psqlscanslash.c: FLEX_NO_BACKUP=yes
 psqlscanslash.c: FLEX_FIX_WARNING=yes
 
-distprep: sql_help.h psqlscanslash.c
+distprep: sql_help.h sql_help.c psqlscanslash.c
 
 install: all installdirs
 	$(INSTALL_PROGRAM) psql$(X) '$(DESTDIR)$(bindir)/psql$(X)'
diff --git a/src/pl/plpgsql/src/Makefile b/src/pl/plpgsql/src/Makefile
index fc60618..dd17092 100644
--- a/src/pl/plpgsql/src/Makefile
+++ b/src/pl/plpgsql/src/Makefile
@@ -63,7 +63,9 @@ uninstall-headers:
 pl_gram.o pl_handler.o pl_comp.o pl_exec.o pl_funcs.o pl_scanner.o: plpgsql.h pl_gram.h plerrcodes.h
 
 # See notes in src/backend/parser/Makefile about the following two rules
-pl_gram.h: pl_gram.c ;
+pl_gram.h: pl_gram.c
+	touch $@
+
 pl_gram.c: BISONFLAGS += -d
 
 # generate plerrcodes.h from src/backend/utils/errcodes.txt
