diff --git a/.gitignore b/.gitignore
index 8d3af5046734428d34e5a8385c4a58257f53ead3..fb6069a0ef93fcdd9d594f09b2af180719e41e85 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,3 +36,4 @@ lib*.pc
 /pgsql.sln.cache
 /Debug/
 /Release/
+/tmp_install/
diff --git a/GNUmakefile.in b/GNUmakefile.in
index 69e08249c1daede9254c4c74a07fb4414fc653a4..361897a80b55f96c9c32cbee5410c8ae32fc3db2 100644
--- a/GNUmakefile.in
+++ b/GNUmakefile.in
@@ -47,6 +47,7 @@ $(call recurse,distprep,doc src config contrib)
 # it's not built by default
 $(call recurse,clean,doc contrib src config)
 clean:
+	rm -rf tmp_install/
 # Garbage from autoconf:
 	@rm -rf autom4te.cache/
 
diff --git a/contrib/earthdistance/Makefile b/contrib/earthdistance/Makefile
index 93dcbe3a31c5ee5caaee2905288af9ce6157a3a4..cde1ae630fe138abb137c4b4597dc0d4b1965715 100644
--- a/contrib/earthdistance/Makefile
+++ b/contrib/earthdistance/Makefile
@@ -7,7 +7,7 @@ DATA = earthdistance--1.0.sql earthdistance--unpackaged--1.0.sql
 PGFILEDESC = "earthdistance - calculate distances on the surface of the Earth"
 
 REGRESS = earthdistance
-REGRESS_OPTS = --extra-install=contrib/cube
+EXTRA_INSTALL = contrib/cube
 
 LDFLAGS_SL += $(filter -lm, $(LIBS))
 
diff --git a/contrib/test_decoding/Makefile b/contrib/test_decoding/Makefile
index 438be44afcca4a86cd75740b7587c35502b59cda..613e9c387b7ac71d4f0b86e985eca69e543ec802 100644
--- a/contrib/test_decoding/Makefile
+++ b/contrib/test_decoding/Makefile
@@ -39,35 +39,33 @@ submake-test_decoding:
 
 REGRESSCHECKS=ddl rewrite toast permissions decoding_in_xact decoding_into_rel binary prepared
 
-regresscheck: all | submake-regress submake-test_decoding
+regresscheck: all | submake-regress submake-test_decoding temp-install
 	$(MKDIR_P) regression_output
 	$(pg_regress_check) \
 	    --temp-config $(top_srcdir)/contrib/test_decoding/logical.conf \
-	    --temp-install=./tmp_check \
-	    --extra-install=contrib/test_decoding \
+	    --temp-instance=./tmp_check \
 	    --outputdir=./regression_output \
 	    $(REGRESSCHECKS)
 
-regresscheck-install-force: | submake-regress submake-test_decoding
+regresscheck-install-force: | submake-regress submake-test_decoding temp-install
 	$(pg_regress_installcheck) \
-	    --extra-install=contrib/test_decoding \
 	    $(REGRESSCHECKS)
 
 ISOLATIONCHECKS=mxact delayed_startup ondisk_startup concurrent_ddl_dml
 
-isolationcheck: all | submake-isolation submake-test_decoding
+isolationcheck: all | submake-isolation submake-test_decoding temp-install
 	$(MKDIR_P) isolation_output
 	$(pg_isolation_regress_check) \
 	    --temp-config $(top_srcdir)/contrib/test_decoding/logical.conf \
-	    --extra-install=contrib/test_decoding \
 	    --outputdir=./isolation_output \
 	    $(ISOLATIONCHECKS)
 
-isolationcheck-install-force: all | submake-isolation submake-test_decoding
+isolationcheck-install-force: all | submake-isolation submake-test_decoding temp-install
 	$(pg_isolation_regress_installcheck) \
-	    --extra-install=contrib/test_decoding \
 	    $(ISOLATIONCHECKS)
 
 PHONY: submake-test_decoding submake-regress check \
 	regresscheck regresscheck-install-force \
 	isolationcheck isolationcheck-install-force
+
+temp-install: EXTRA_INSTALL=contrib/test_decoding
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index 4b06fc2d96247750b6fd6ce32f3118e6d8370b69..d9dd7effbbd142955bf25933367d226fb3dae1e8 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -43,6 +43,7 @@ MAJORVERSION = @PG_MAJORVERSION@
 # (PGXS VPATH support is handled separately in pgxs.mk)
 ifndef PGXS
 vpath_build = @vpath_build@
+abs_top_builddir = @abs_top_builddir@
 abs_top_srcdir = @abs_top_srcdir@
 
 ifneq ($(vpath_build),yes)
@@ -301,6 +302,17 @@ BZIP2	= bzip2
 
 # Testing
 
+check: temp-install
+
+.PHONY: temp-install
+temp-install:
+ifeq ($(MAKELEVEL),0)
+	rm -rf '$(abs_top_builddir)'/tmp_install
+	$(MKDIR_P) '$(abs_top_builddir)'/tmp_install/log
+	$(MAKE) -C '$(top_builddir)' DESTDIR='$(abs_top_builddir)'/tmp_install install >'$(abs_top_builddir)'/tmp_install/log/install.log 2>&1
+endif
+	for extra in $(EXTRA_INSTALL); do $(MAKE) -C '$(top_builddir)'/$$extra DESTDIR='$(abs_top_builddir)'/tmp_install install >>'$(abs_top_builddir)'/tmp_install/log/install.log 2>&1 || exit; done
+
 PROVE = @PROVE@
 PG_PROVE_FLAGS = -I $(top_srcdir)/src/test/perl/
 PROVE_FLAGS = --verbose
@@ -315,6 +327,10 @@ define ld_library_path_var
 $(if $(filter $(PORTNAME),darwin),DYLD_LIBRARY_PATH,$(if $(filter $(PORTNAME),aix),LIBPATH,LD_LIBRARY_PATH))
 endef
 
+define with_temp_install
+PATH="$(abs_top_builddir)/tmp_install$(bindir):$$PATH" $(call add_to_path,$(ld_library_path_var),$(abs_top_builddir)/tmp_install$(libdir))
+endef
+
 ifeq ($(enable_tap_tests),yes)
 
 define prove_installcheck
@@ -322,9 +338,7 @@ cd $(srcdir) && TESTDIR='$(CURDIR)' PATH="$(bindir):$$PATH" PGPORT='6$(DEF_PGPOR
 endef
 
 define prove_check
-$(MKDIR_P) tmp_check/log
-$(MAKE) -C $(top_builddir) DESTDIR='$(CURDIR)'/tmp_check/install install >'$(CURDIR)'/tmp_check/log/install.log 2>&1
-cd $(srcdir) && TESTDIR='$(CURDIR)' PATH="$(CURDIR)/tmp_check/install$(bindir):$$PATH" $(call add_to_path,$(ld_library_path_var),$(CURDIR)/tmp_check/install$(libdir)) top_builddir='$(CURDIR)/$(top_builddir)' PGPORT='6$(DEF_PGPORT)' $(PROVE) $(PG_PROVE_FLAGS) $(PROVE_FLAGS) t/*.pl
+cd $(srcdir) && TESTDIR='$(CURDIR)' $(with_temp_install) PGPORT='6$(DEF_PGPORT)' top_builddir='$(CURDIR)/$(top_builddir)' $(PROVE) $(PG_PROVE_FLAGS) $(PROVE_FLAGS) t/*.pl
 endef
 
 else
@@ -495,13 +509,13 @@ endif
 
 pg_regress_locale_flags = $(if $(ENCODING),--encoding=$(ENCODING)) $(NOLOCALE)
 
-pg_regress_check = $(top_builddir)/src/test/regress/pg_regress --inputdir=$(srcdir) --temp-install=./tmp_check --top-builddir=$(top_builddir) $(pg_regress_locale_flags) $(EXTRA_REGRESS_OPTS)
-pg_regress_installcheck = $(top_builddir)/src/test/regress/pg_regress --inputdir=$(srcdir) --psqldir='$(PSQLDIR)' $(pg_regress_locale_flags) $(EXTRA_REGRESS_OPTS)
+pg_regress_check = $(with_temp_install) $(top_builddir)/src/test/regress/pg_regress --inputdir=$(srcdir) --temp-instance=./tmp_check --bindir= $(pg_regress_locale_flags) $(EXTRA_REGRESS_OPTS)
+pg_regress_installcheck = $(top_builddir)/src/test/regress/pg_regress --inputdir=$(srcdir) --bindir='$(bindir)' $(pg_regress_locale_flags) $(EXTRA_REGRESS_OPTS)
 
 pg_regress_clean_files = results/ regression.diffs regression.out tmp_check/ log/
 
-pg_isolation_regress_check = $(top_builddir)/src/test/isolation/pg_isolation_regress --inputdir=$(srcdir) --temp-install=./tmp_check --top-builddir=$(top_builddir) $(pg_regress_locale_flags) $(EXTRA_REGRESS_OPTS)
-pg_isolation_regress_installcheck = $(top_builddir)/src/test/isolation/pg_isolation_regress --inputdir=$(srcdir) --top-builddir=$(top_builddir) $(pg_regress_locale_flags) $(EXTRA_REGRESS_OPTS)
+pg_isolation_regress_check = $(with_temp_install) $(top_builddir)/src/test/isolation/pg_isolation_regress --inputdir=$(srcdir) --temp-instance=./tmp_check --bindir= $(pg_regress_locale_flags) $(EXTRA_REGRESS_OPTS)
+pg_isolation_regress_installcheck = $(top_builddir)/src/test/isolation/pg_isolation_regress --inputdir=$(srcdir) $(pg_regress_locale_flags) $(EXTRA_REGRESS_OPTS)
 
 ##########################################################################
 #
@@ -683,7 +697,7 @@ endif
 define _create_recursive_target
 .PHONY: $(1)-$(2)-recurse
 $(1): $(1)-$(2)-recurse
-$(1)-$(2)-recurse:
+$(1)-$(2)-recurse: $(if $(filter check, $(3)), temp-install)
 	$$(MAKE) -C $(2) $(3)
 endef
 # Note that the use of $$ on the last line above is important; we want
diff --git a/src/bin/pg_upgrade/test.sh b/src/bin/pg_upgrade/test.sh
index 0903f30b11972857223f96cf9d06da28ae1d8f0f..fef64dfb5f87a9f101bcf9251cdb4fda1c53717c 100644
--- a/src/bin/pg_upgrade/test.sh
+++ b/src/bin/pg_upgrade/test.sh
@@ -86,7 +86,7 @@ if [ "$1" = '--install' ]; then
 	# use psql from the proper installation directory, which might
 	# be outdated or missing. But don't override anything else that's
 	# already in EXTRA_REGRESS_OPTS.
-	EXTRA_REGRESS_OPTS="$EXTRA_REGRESS_OPTS --psqldir='$bindir'"
+	EXTRA_REGRESS_OPTS="$EXTRA_REGRESS_OPTS --bindir='$bindir'"
 	export EXTRA_REGRESS_OPTS
 fi
 
diff --git a/src/interfaces/ecpg/test/Makefile b/src/interfaces/ecpg/test/Makefile
index 387729bda34429fc087a748879c358c1a4c54ecc..a4ac02107c801e5e33266291b23cf79bca18f3aa 100644
--- a/src/interfaces/ecpg/test/Makefile
+++ b/src/interfaces/ecpg/test/Makefile
@@ -11,14 +11,10 @@ override CPPFLAGS := \
 	'-I$(top_builddir)/src/port' \
 	'-I$(top_srcdir)/src/test/regress' \
 	'-DHOST_TUPLE="$(host_tuple)"' \
-	'-DMAKEPROG="$(MAKE)"' \
 	'-DSHELLPROG="$(SHELL)"' \
 	'-DDLSUFFIX="$(DLSUFFIX)"' \
 	$(CPPFLAGS)
 
-# where to find psql for testing an existing installation
-PSQLDIR = $(bindir)
-
 # default encoding for regression tests
 ENCODING = SQL_ASCII
 
@@ -82,11 +78,11 @@ endif
 REGRESS_OPTS = --dbname=regress1,connectdb --create-role=connectuser,connectdb $(EXTRA_REGRESS_OPTS)
 
 check: all
-	./pg_regress $(REGRESS_OPTS) --top-builddir=$(top_builddir) --temp-install=./tmp_check $(pg_regress_locale_flags) $(THREAD) --schedule=$(srcdir)/ecpg_schedule
+	$(with_temp_install) ./pg_regress $(REGRESS_OPTS) --temp-instance=./tmp_check --bindir= $(pg_regress_locale_flags) $(THREAD) --schedule=$(srcdir)/ecpg_schedule
 
 # the same options, but with --listen-on-tcp
 checktcp: all
-	./pg_regress $(REGRESS_OPTS) --top-builddir=$(top_builddir) --temp-install=./tmp_check $(pg_regress_locale_flags) $(THREAD) --schedule=$(srcdir)/ecpg_schedule_tcp --host=localhost
+	$(with_temp_install) ./pg_regress $(REGRESS_OPTS) --temp-instance=./tmp_check --bindir= $(pg_regress_locale_flags) $(THREAD) --schedule=$(srcdir)/ecpg_schedule_tcp --host=localhost
 
 installcheck: all
-	./pg_regress $(REGRESS_OPTS) --psqldir='$(PSQLDIR)' --top-builddir=$(top_builddir) $(pg_regress_locale_flags) $(THREAD) --schedule=$(srcdir)/ecpg_schedule
+	./pg_regress $(REGRESS_OPTS) --bindir='$(bindir)' $(pg_regress_locale_flags) $(THREAD) --schedule=$(srcdir)/ecpg_schedule
diff --git a/src/makefiles/pgxs.mk b/src/makefiles/pgxs.mk
index 24ddba9294bf614111c2a26266d78ea8ada89aa3..ea17b1c1858624d196776cf2a65913d4776137b7 100644
--- a/src/makefiles/pgxs.mk
+++ b/src/makefiles/pgxs.mk
@@ -258,9 +258,6 @@ else
   REGRESS_OPTS += --dbname=$(CONTRIB_TESTDB)
 endif
 
-# where to find psql for running the tests
-PSQLDIR = $(bindir)
-
 # When doing a VPATH build, must copy over the data files so that the
 # driver script can find them.  We have to use an absolute path for
 # the targets, because otherwise make will try to locate the missing
@@ -295,7 +292,9 @@ check:
 	@echo 'Do "$(MAKE) install", then "$(MAKE) installcheck" instead.'
 else
 check: all submake $(REGRESS_PREP)
-	$(pg_regress_check) --extra-install=$(subdir) $(REGRESS_OPTS) $(REGRESS)
+	$(pg_regress_check) $(REGRESS_OPTS) $(REGRESS)
+
+temp-install: EXTRA_INSTALL=$(subdir)
 endif
 endif # REGRESS
 
diff --git a/src/pl/plperl/GNUmakefile b/src/pl/plperl/GNUmakefile
index a04a2d3456d1d8bf735c7daea79e1404928feb30..2b698477c263383f416e77df27be321165fff921 100644
--- a/src/pl/plperl/GNUmakefile
+++ b/src/pl/plperl/GNUmakefile
@@ -69,8 +69,6 @@ ifeq ($(shell $(PERL) -V:usemultiplicity), usemultiplicity='define';)
 	REGRESS += plperl_plperlu
 endif
 endif
-# where to find psql for running the tests
-PSQLDIR = $(bindir)
 
 # where to find xsubpp for building XS.
 XSUBPPDIR = $(shell $(PERL) -e 'use List::Util qw(first); print first { -r "$$_/ExtUtils/xsubpp" } @INC')
diff --git a/src/pl/plpython/Makefile b/src/pl/plpython/Makefile
index 430aa8912704e237a758c504307059dd5cdfb039..c58e56b40087089b6f92e9df0a2296238a354bed 100644
--- a/src/pl/plpython/Makefile
+++ b/src/pl/plpython/Makefile
@@ -115,9 +115,6 @@ REGRESS = \
 
 REGRESS_PLPYTHON3_MANGLE := $(REGRESS)
 
-# where to find psql for running the tests
-PSQLDIR = $(bindir)
-
 include $(top_srcdir)/src/Makefile.shlib
 
 all: all-lib
diff --git a/src/pl/tcl/Makefile b/src/pl/tcl/Makefile
index 7ea00267c0309225eb5fa27316fe311e6845021a..851e3c063f5ce7ff5b4d7b8a0c329159f5231c16 100644
--- a/src/pl/tcl/Makefile
+++ b/src/pl/tcl/Makefile
@@ -45,8 +45,6 @@ DATA = pltcl.control pltcl--1.0.sql pltcl--unpackaged--1.0.sql \
 
 REGRESS_OPTS = --dbname=$(PL_TESTDB) --load-extension=pltcl
 REGRESS = pltcl_setup pltcl_queries
-# where to find psql for running the tests
-PSQLDIR = $(bindir)
 
 # Tcl on win32 ships with import libraries only for Microsoft Visual C++,
 # which are not compatible with mingw gcc. Therefore we need to build a
diff --git a/src/test/isolation/Makefile b/src/test/isolation/Makefile
index a88257a562c996cb8b8a1c338a34cb19f3667f33..4577509137e4511f53827ffd17e985ce1a55866f 100644
--- a/src/test/isolation/Makefile
+++ b/src/test/isolation/Makefile
@@ -9,9 +9,6 @@ subdir = src/test/isolation
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-# where to find psql for testing an existing installation
-PSQLDIR = $(bindir)
-
 override CPPFLAGS := -I$(srcdir) -I$(libpq_srcdir) -I$(srcdir)/../regress $(CPPFLAGS)
 
 OBJS =  specparse.o isolationtester.o $(WIN32RES)
@@ -55,17 +52,17 @@ maintainer-clean: distclean
 	rm -f specparse.c specscanner.c
 
 installcheck: all
-	./pg_isolation_regress --psqldir='$(PSQLDIR)' $(EXTRA_REGRESS_OPTS) --inputdir=$(srcdir) --schedule=$(srcdir)/isolation_schedule
+	./pg_isolation_regress --bindir='$(bindir)' $(EXTRA_REGRESS_OPTS) --inputdir=$(srcdir) --schedule=$(srcdir)/isolation_schedule
 
 check: all
-	./pg_isolation_regress --temp-install=./tmp_check --inputdir=$(srcdir) --top-builddir=$(top_builddir) $(EXTRA_REGRESS_OPTS) --schedule=$(srcdir)/isolation_schedule
+	$(with_temp_install) ./pg_isolation_regress --temp-instance=./tmp_check --inputdir=$(srcdir) --bindir= $(EXTRA_REGRESS_OPTS) --schedule=$(srcdir)/isolation_schedule
 
 # Versions of the check tests that include the prepared_transactions test
 # It only makes sense to run these if set up to use prepared transactions,
 # via TEMP_CONFIG for the check case, or via the postgresql.conf for the
 # installcheck case.
-installcheck-prepared-txns: all
-	./pg_isolation_regress --psqldir='$(PSQLDIR)' $(EXTRA_REGRESS_OPTS) --inputdir=$(srcdir) --schedule=$(srcdir)/isolation_schedule prepared-transactions
+installcheck-prepared-txns: all temp-install
+	./pg_isolation_regress --bindir='$(bindir)' $(EXTRA_REGRESS_OPTS) --inputdir=$(srcdir) --schedule=$(srcdir)/isolation_schedule prepared-transactions
 
-check-prepared-txns: all
-	./pg_isolation_regress --temp-install=./tmp_check $(EXTRA_REGRESS_OPTS) --inputdir=$(srcdir) --top-builddir=$(top_builddir) --schedule=$(srcdir)/isolation_schedule prepared-transactions
+check-prepared-txns: all temp-install
+	./pg_isolation_regress --temp-instance=./tmp_check $(EXTRA_REGRESS_OPTS) --inputdir=$(srcdir) --schedule=$(srcdir)/isolation_schedule prepared-transactions
diff --git a/src/test/regress/GNUmakefile b/src/test/regress/GNUmakefile
index 110eb8080de859f474a35f11ca398f9955b8207b..4d6849e34e535a0b48c6e219e5228d042a056db8 100644
--- a/src/test/regress/GNUmakefile
+++ b/src/test/regress/GNUmakefile
@@ -23,9 +23,6 @@ ifdef TEMP_CONFIG
 TEMP_CONF += --temp-config=$(TEMP_CONFIG)
 endif
 
-# where to find psql for testing an existing installation
-PSQLDIR = $(bindir)
-
 # maximum simultaneous connections for parallel tests
 MAXCONNOPT =
 ifdef MAX_CONNECTIONS
@@ -34,7 +31,6 @@ endif
 
 # stuff to pass into build of pg_regress
 EXTRADEFS = '-DHOST_TUPLE="$(host_tuple)"' \
-	'-DMAKEPROG="$(MAKE)"' \
 	'-DSHELLPROG="$(SHELL)"' \
 	'-DDLSUFFIX="$(DLSUFFIX)"'
 
diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c
index 098acf68762869970e3d64326360e2cfc0fada00..2df5c1b5d6a727f7592b4d7613b6b1ad8ca959d6 100644
--- a/src/test/regress/pg_regress.c
+++ b/src/test/regress/pg_regress.c
@@ -45,25 +45,10 @@ typedef struct _resultmap
 } _resultmap;
 
 /*
- * Values obtained from pg_config_paths.h and Makefile.  The PG installation
- * paths are only used in temp_install mode: we use these strings to find
- * out where "make install" will put stuff under the temp_install directory.
- * In non-temp_install mode, the only thing we need is the location of psql,
- * which we expect to find in psqldir, or in the PATH if psqldir isn't given.
- *
- * XXX Because pg_regress is not installed in bindir, we can't support
- * this for relocatable trees as it is.  --psqldir would need to be
- * specified in those cases.
+ * Values obtained from Makefile.
  */
-char	   *bindir = PGBINDIR;
-char	   *libdir = LIBDIR;
-char	   *datadir = PGSHAREDIR;
 char	   *host_platform = HOST_TUPLE;
 
-#ifndef WIN32_ONLY_COMPILER
-static char *makeprog = MAKEPROG;
-#endif
-
 #ifndef WIN32					/* not used in WIN32 case */
 static char *shellprog = SHELLPROG;
 #endif
@@ -86,7 +71,7 @@ _stringlist *dblist = NULL;
 bool		debug = false;
 char	   *inputdir = ".";
 char	   *outputdir = ".";
-char	   *psqldir = PGBINDIR;
+char	   *bindir = PGBINDIR;
 char	   *launcher = NULL;
 static _stringlist *loadlanguage = NULL;
 static _stringlist *loadextension = NULL;
@@ -94,9 +79,8 @@ static int	max_connections = 0;
 static char *encoding = NULL;
 static _stringlist *schedulelist = NULL;
 static _stringlist *extra_tests = NULL;
-static char *temp_install = NULL;
+static char *temp_instance = NULL;
 static char *temp_config = NULL;
-static char *top_builddir = NULL;
 static bool nolocale = false;
 static bool use_existing = false;
 static char *hostname = NULL;
@@ -105,7 +89,6 @@ static bool port_specified_by_user = false;
 static char *dlpath = PKGLIBDIR;
 static char *user = NULL;
 static _stringlist *extraroles = NULL;
-static _stringlist *extra_install = NULL;
 static char *config_auth_datadir = NULL;
 
 /* internal variables */
@@ -282,8 +265,10 @@ stop_postmaster(void)
 		fflush(stderr);
 
 		snprintf(buf, sizeof(buf),
-				 "\"%s/pg_ctl\" stop -D \"%s/data\" -s -m fast",
-				 bindir, temp_install);
+				 "\"%s%spg_ctl\" stop -D \"%s/data\" -s -m fast",
+				 bindir ? bindir : "",
+				 bindir ? "/" : "",
+				 temp_instance);
 		r = system(buf);
 		if (r != 0)
 		{
@@ -730,27 +715,6 @@ doputenv(const char *var, const char *val)
 	putenv(s);
 }
 
-/*
- * Set the environment variable "pathname", prepending "addval" to its
- * old value (if any).
- */
-static void
-add_to_path(const char *pathname, char separator, const char *addval)
-{
-	char	   *oldval = getenv(pathname);
-	char	   *newval;
-
-	if (!oldval || !oldval[0])
-	{
-		/* no previous value */
-		newval = psprintf("%s=%s", pathname, addval);
-	}
-	else
-		newval = psprintf("%s=%s%c%s", pathname, addval, separator, oldval);
-
-	putenv(newval);
-}
-
 /*
  * Prepare environment variables for running regression tests
  */
@@ -825,7 +789,7 @@ initialize_environment(void)
 		putenv(new_pgoptions);
 	}
 
-	if (temp_install)
+	if (temp_instance)
 	{
 		/*
 		 * Clear out any environment vars that might cause psql to connect to
@@ -863,49 +827,6 @@ initialize_environment(void)
 			sprintf(s, "%d", port);
 			doputenv("PGPORT", s);
 		}
-
-		/*
-		 * GNU make stores some flags in the MAKEFLAGS environment variable to
-		 * pass arguments to its own children.  If we are invoked by make,
-		 * that causes the make invoked by us to think its part of the make
-		 * task invoking us, and so it tries to communicate with the toplevel
-		 * make.  Which fails.
-		 *
-		 * Unset the variable to protect against such problems.  We also reset
-		 * MAKELEVEL to be certain the child doesn't notice the make above us.
-		 */
-		unsetenv("MAKEFLAGS");
-		unsetenv("MAKELEVEL");
-
-		/*
-		 * Adjust path variables to point into the temp-install tree
-		 */
-		bindir = psprintf("%s/install/%s", temp_install, bindir);
-
-		libdir = psprintf("%s/install/%s", temp_install, libdir);
-
-		datadir = psprintf("%s/install/%s", temp_install, datadir);
-
-		/* psql will be installed into temp-install bindir */
-		psqldir = bindir;
-
-		/*
-		 * Set up shared library paths to include the temp install.
-		 *
-		 * LD_LIBRARY_PATH covers many platforms.  DYLD_LIBRARY_PATH works on
-		 * Darwin, and maybe other Mach-based systems.  LIBPATH is for AIX.
-		 * Windows needs shared libraries in PATH (only those linked into
-		 * executables, not dlopen'ed ones). Feel free to account for others
-		 * as well.
-		 */
-		add_to_path("LD_LIBRARY_PATH", ':', libdir);
-		add_to_path("DYLD_LIBRARY_PATH", ':', libdir);
-		add_to_path("LIBPATH", ':', libdir);
-#if defined(WIN32)
-		add_to_path("PATH", ';', libdir);
-#elif defined(__CYGWIN__)
-		add_to_path("PATH", ':', libdir);
-#endif
 	}
 	else
 	{
@@ -1158,8 +1079,8 @@ psql_command(const char *database, const char *query,...)
 	/* And now we can build and execute the shell command */
 	snprintf(psql_cmd, sizeof(psql_cmd),
 			 "\"%s%spsql\" -X -c \"%s\" \"%s\"",
-			 psqldir ? psqldir : "",
-			 psqldir ? "/" : "",
+			 bindir ? bindir : "",
+			 bindir ? "/" : "",
 			 query_escaped,
 			 database);
 
@@ -2051,21 +1972,18 @@ help(void)
 	printf(_("  --outputdir=DIR           place output files in DIR (default \".\")\n"));
 	printf(_("  --schedule=FILE           use test ordering schedule from FILE\n"));
 	printf(_("                            (can be used multiple times to concatenate)\n"));
-	printf(_("  --temp-install=DIR        create a temporary installation in DIR\n"));
-	printf(_("  --use-existing            use an existing installation\n"));
+	printf(_("  --temp-instance=DIR       create a temporary instance in DIR\n"));
+	printf(_("  --use-existing            use an existing installation\n")); // XXX
 	printf(_("\n"));
-	printf(_("Options for \"temp-install\" mode:\n"));
-	printf(_("  --extra-install=DIR       additional directory to install (e.g., contrib)\n"));
+	printf(_("Options for \"temp-instance\" mode:\n"));
 	printf(_("  --no-locale               use C locale\n"));
 	printf(_("  --port=PORT               start postmaster on PORT\n"));
 	printf(_("  --temp-config=FILE        append contents of FILE to temporary config\n"));
-	printf(_("  --top-builddir=DIR        (relative) path to top level build directory\n"));
 	printf(_("\n"));
 	printf(_("Options for using an existing installation:\n"));
 	printf(_("  --host=HOST               use postmaster running on HOST\n"));
 	printf(_("  --port=PORT               use postmaster running at PORT\n"));
 	printf(_("  --user=USER               connect as USER\n"));
-	printf(_("  --psqldir=DIR             use psql in DIR (default: configured bindir)\n"));
 	printf(_("\n"));
 	printf(_("The exit status is 0 if all tests passed, 1 if some tests failed, and 2\n"));
 	printf(_("if the tests could not be run for some reason.\n"));
@@ -2087,20 +2005,18 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
 		{"encoding", required_argument, NULL, 6},
 		{"outputdir", required_argument, NULL, 7},
 		{"schedule", required_argument, NULL, 8},
-		{"temp-install", required_argument, NULL, 9},
+		{"temp-instance", required_argument, NULL, 9},
 		{"no-locale", no_argument, NULL, 10},
-		{"top-builddir", required_argument, NULL, 11},
 		{"host", required_argument, NULL, 13},
 		{"port", required_argument, NULL, 14},
 		{"user", required_argument, NULL, 15},
-		{"psqldir", required_argument, NULL, 16},
+		{"bindir", required_argument, NULL, 16},
 		{"dlpath", required_argument, NULL, 17},
 		{"create-role", required_argument, NULL, 18},
 		{"temp-config", required_argument, NULL, 19},
 		{"use-existing", no_argument, NULL, 20},
 		{"launcher", required_argument, NULL, 21},
 		{"load-extension", required_argument, NULL, 22},
-		{"extra-install", required_argument, NULL, 23},
 		{"config-auth", required_argument, NULL, 24},
 		{NULL, 0, NULL, 0}
 	};
@@ -2172,14 +2088,11 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
 				add_stringlist_item(&schedulelist, optarg);
 				break;
 			case 9:
-				temp_install = make_absolute_path(optarg);
+				temp_instance = make_absolute_path(optarg);
 				break;
 			case 10:
 				nolocale = true;
 				break;
-			case 11:
-				top_builddir = strdup(optarg);
-				break;
 			case 13:
 				hostname = strdup(optarg);
 				break;
@@ -2191,9 +2104,11 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
 				user = strdup(optarg);
 				break;
 			case 16:
-				/* "--psqldir=" should mean to use PATH */
+				/* "--bindir=" means to use PATH */
 				if (strlen(optarg))
-					psqldir = strdup(optarg);
+					bindir = strdup(optarg);
+				else
+					bindir = NULL;
 				break;
 			case 17:
 				dlpath = strdup(optarg);
@@ -2213,9 +2128,6 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
 			case 22:
 				add_stringlist_item(&loadextension, optarg);
 				break;
-			case 23:
-				add_stringlist_item(&extra_install, optarg);
-				break;
 			case 24:
 				config_auth_datadir = pstrdup(optarg);
 				break;
@@ -2244,7 +2156,7 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
 		exit(0);
 	}
 
-	if (temp_install && !port_specified_by_user)
+	if (temp_instance && !port_specified_by_user)
 
 		/*
 		 * To reduce chances of interference with parallel installations, use
@@ -2270,83 +2182,45 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
 	unlimit_core_size();
 #endif
 
-	if (temp_install)
+	if (temp_instance)
 	{
 		FILE	   *pg_conf;
-		_stringlist *sl;
 
 		/*
-		 * Prepare the temp installation
+		 * Prepare the temp instance
 		 */
-		if (!top_builddir)
-		{
-			fprintf(stderr, _("--top-builddir must be specified when using --temp-install\n"));
-			exit(2);
-		}
 
-		if (directory_exists(temp_install))
+		if (directory_exists(temp_instance))
 		{
-			header(_("removing existing temp installation"));
-			if (!rmtree(temp_install, true))
+			header(_("removing existing temp instance"));
+			if (!rmtree(temp_instance, true))
 			{
-				fprintf(stderr, _("\n%s: could not remove temp installation \"%s\"\n"),
-						progname, temp_install);
+				fprintf(stderr, _("\n%s: could not remove temp instance \"%s\"\n"),
+						progname, temp_instance);
 				exit(2);
 			}
 		}
 
-		header(_("creating temporary installation"));
+		header(_("creating temporary instance"));
 
-		/* make the temp install top directory */
-		make_directory(temp_install);
+		/* make the temp instance top directory */
+		make_directory(temp_instance);
 
 		/* and a directory for log files */
-		snprintf(buf, sizeof(buf), "%s/log", outputdir);
+		snprintf(buf, sizeof(buf), "%s/log", temp_instance);
 		if (!directory_exists(buf))
 			make_directory(buf);
 
-		/* "make install" */
-#ifndef WIN32_ONLY_COMPILER
-		snprintf(buf, sizeof(buf),
-				 "\"%s\" -C \"%s\" DESTDIR=\"%s/install\" install > \"%s/log/install.log\" 2>&1",
-				 makeprog, top_builddir, temp_install, outputdir);
-#else
-		snprintf(buf, sizeof(buf),
-				 "perl \"%s/src/tools/msvc/install.pl\" \"%s/install\" >\"%s/log/install.log\" 2>&1",
-				 top_builddir, temp_install, outputdir);
-#endif
-		if (system(buf))
-		{
-			fprintf(stderr, _("\n%s: installation failed\nExamine %s/log/install.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
-			exit(2);
-		}
-
-		for (sl = extra_install; sl != NULL; sl = sl->next)
-		{
-#ifndef WIN32_ONLY_COMPILER
-			snprintf(buf, sizeof(buf),
-					 "\"%s\" -C \"%s/%s\" DESTDIR=\"%s/install\" install >> \"%s/log/install.log\" 2>&1",
-				   makeprog, top_builddir, sl->str, temp_install, outputdir);
-#else
-			fprintf(stderr, _("\n%s: --extra-install option not supported on this platform\n"), progname);
-			exit(2);
-#endif
-
-			if (system(buf))
-			{
-				fprintf(stderr, _("\n%s: installation failed\nExamine %s/log/install.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
-				exit(2);
-			}
-		}
-
 		/* initdb */
 		header(_("initializing database system"));
 		snprintf(buf, sizeof(buf),
-				 "\"%s/initdb\" -D \"%s/data\" -L \"%s\" --noclean --nosync%s%s > \"%s/log/initdb.log\" 2>&1",
-				 bindir, temp_install, datadir,
+				 "\"%s%sinitdb\" -D \"%s/data\" --noclean --nosync%s%s > \"%s/log/initdb.log\" 2>&1",
+				 bindir ? bindir : "",
+				 bindir ? "/" : "",
+				 temp_instance,
 				 debug ? " --debug" : "",
 				 nolocale ? " --no-locale" : "",
-				 outputdir);
+				 temp_instance);
 		if (system(buf))
 		{
 			fprintf(stderr, _("\n%s: initdb failed\nExamine %s/log/initdb.log for the reason.\nCommand was: %s\n"), progname, outputdir, buf);
@@ -2361,7 +2235,7 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
 		 * failures, don't set max_prepared_transactions any higher than
 		 * actually needed by the prepared_xacts regression test.)
 		 */
-		snprintf(buf, sizeof(buf), "%s/data/postgresql.conf", temp_install);
+		snprintf(buf, sizeof(buf), "%s/data/postgresql.conf", temp_instance);
 		pg_conf = fopen(buf, "a");
 		if (pg_conf == NULL)
 		{
@@ -2399,7 +2273,7 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
 		 * Since we successfully used the same buffer for the much-longer
 		 * "initdb" command, this can't truncate.
 		 */
-		snprintf(buf, sizeof(buf), "%s/data", temp_install);
+		snprintf(buf, sizeof(buf), "%s/data", temp_instance);
 		config_sspi_auth(buf);
 #elif !defined(HAVE_UNIX_SOCKETS)
 #error Platform has no means to secure the test installation.
@@ -2409,8 +2283,10 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
 		 * Check if there is a postmaster running already.
 		 */
 		snprintf(buf2, sizeof(buf2),
-				 "\"%s/psql\" -X postgres <%s 2>%s",
-				 bindir, DEVNULL, DEVNULL);
+				 "\"%s%spsql\" -X postgres <%s 2>%s",
+				 bindir ? bindir : "",
+				 bindir ? "/" : "",
+				 DEVNULL, DEVNULL);
 
 		for (i = 0; i < 16; i++)
 		{
@@ -2441,12 +2317,14 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
 		 */
 		header(_("starting postmaster"));
 		snprintf(buf, sizeof(buf),
-				 "\"%s/postgres\" -D \"%s/data\" -F%s "
+				 "\"%s%spostgres\" -D \"%s/data\" -F%s "
 				 "-c \"listen_addresses=%s\" -k \"%s\" "
 				 "> \"%s/log/postmaster.log\" 2>&1",
-				 bindir, temp_install, debug ? " -d 5" : "",
+				 bindir ? bindir : "",
+				 bindir ? "/" : "",
+				 temp_instance, debug ? " -d 5" : "",
 				 hostname ? hostname : "", sockdir ? sockdir : "",
-				 outputdir);
+				 temp_instance);
 		postmaster_pid = spawn_process(buf);
 		if (postmaster_pid == INVALID_PID)
 		{
@@ -2560,23 +2438,23 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
 	/*
 	 * Shut down temp installation's postmaster
 	 */
-	if (temp_install)
+	if (temp_instance)
 	{
 		header(_("shutting down postmaster"));
 		stop_postmaster();
 	}
 
 	/*
-	 * If there were no errors, remove the temp installation immediately to
-	 * conserve disk space.  (If there were errors, we leave the installation
+	 * If there were no errors, remove the temp instance immediately to
+	 * conserve disk space.  (If there were errors, we leave the instance
 	 * in place for possible manual investigation.)
 	 */
-	if (temp_install && fail_count == 0 && fail_ignore_count == 0)
+	if (temp_instance && fail_count == 0 && fail_ignore_count == 0)
 	{
-		header(_("removing temporary installation"));
-		if (!rmtree(temp_install, true))
-			fprintf(stderr, _("\n%s: could not remove temp installation \"%s\"\n"),
-					progname, temp_install);
+		header(_("removing temporary instance"));
+		if (!rmtree(temp_instance, true))
+			fprintf(stderr, _("\n%s: could not remove temp instance \"%s\"\n"),
+					progname, temp_instance);
 	}
 
 	fclose(logfile);
diff --git a/src/test/regress/pg_regress.h b/src/test/regress/pg_regress.h
index a7af7a56febc076fed6cde31dcfe201fa6d597f7..0fc9db701353d557e15d52c8e2f6edb83d6de2f9 100644
--- a/src/test/regress/pg_regress.h
+++ b/src/test/regress/pg_regress.h
@@ -43,12 +43,6 @@ extern char *inputdir;
 extern char *outputdir;
 extern char *launcher;
 
-/*
- * This should not be global but every module should be able to read command
- * line parameters.
- */
-extern char *psqldir;
-
 extern const char *basic_diff_opts;
 extern const char *pretty_diff_opts;
 
diff --git a/src/test/regress/pg_regress_main.c b/src/test/regress/pg_regress_main.c
index a4039655cc3070c080cef76d383262eadf92f89d..860431b24a453817bc030583689448406050427e 100644
--- a/src/test/regress/pg_regress_main.c
+++ b/src/test/regress/pg_regress_main.c
@@ -65,8 +65,8 @@ psql_start_test(const char *testname,
 
 	snprintf(psql_cmd + offset, sizeof(psql_cmd) - offset,
 			 "\"%s%spsql\" -X -a -q -d \"%s\" < \"%s\" > \"%s\" 2>&1",
-			 psqldir ? psqldir : "",
-			 psqldir ? "/" : "",
+			 bindir ? bindir : "",
+			 bindir ? "/" : "",
 			 dblist->str,
 			 infile,
 			 outfile);
diff --git a/src/tools/msvc/vcregress.pl b/src/tools/msvc/vcregress.pl
index c3143ac665b536de8897d4f2ccf58562729fa25c..0153f054f5205b3276491d16bf120355e2dcb6b5 100644
--- a/src/tools/msvc/vcregress.pl
+++ b/src/tools/msvc/vcregress.pl
@@ -16,6 +16,7 @@ my $startdir = getcwd();
 chdir "../../.." if (-d "../../../src/tools/msvc");
 
 my $topdir = getcwd();
+my $tmp_installdir = "$topdir/tmp_install";
 
 require 'src/tools/msvc/config_default.pl';
 require 'src/tools/msvc/config.pl' if (-f 'src/tools/msvc/config.pl');
@@ -95,7 +96,7 @@ sub installcheck
 	my @args = (
 		"../../../$Config/pg_regress/pg_regress",
 		"--dlpath=.",
-		"--psqldir=../../../$Config/psql",
+		"--bindir=../../../$Config/psql",
 		"--schedule=${schedule}_schedule",
 		"--encoding=SQL_ASCII",
 		"--no-locale");
@@ -107,15 +108,19 @@ sub installcheck
 
 sub check
 {
+	chdir $startdir;
+
+	InstallTemp();
+	chdir "${topdir}/src/test/regress";
+
 	my @args = (
-		"../../../$Config/pg_regress/pg_regress",
+		"${tmp_installdir}/bin/pg_regress",
 		"--dlpath=.",
-		"--psqldir=../../../$Config/psql",
+		"--bindir=${tmp_installdir}/bin",
 		"--schedule=${schedule}_schedule",
 		"--encoding=SQL_ASCII",
 		"--no-locale",
-		"--temp-install=./tmp_check",
-		"--top-builddir=\"$topdir\"");
+		"--temp-instance=./tmp_check");
 	push(@args, $maxconn)     if $maxconn;
 	push(@args, $temp_config) if $temp_config;
 	system(@args);
@@ -129,18 +134,20 @@ sub ecpgcheck
 	system("msbuild ecpg_regression.proj /p:config=$Config");
 	my $status = $? >> 8;
 	exit $status if $status;
+	InstallTemp();
 	chdir "$topdir/src/interfaces/ecpg/test";
+
+	$ENV{PATH} = "${tmp_installdir}/bin;${tmp_installdir}/lib;$ENV{PATH}";
 	$schedule = "ecpg";
 	my @args = (
-		"../../../../$Config/pg_regress_ecpg/pg_regress_ecpg",
-		"--psqldir=../../../$Config/psql",
+		"${tmp_installdir}/bin/pg_regress_ecpg",
+		"--bindir=",
 		"--dbname=regress1,connectdb",
 		"--create-role=connectuser,connectdb",
 		"--schedule=${schedule}_schedule",
 		"--encoding=SQL_ASCII",
 		"--no-locale",
-		"--temp-install=./tmp_chk",
-		"--top-builddir=\"$topdir\"");
+		"--temp-instance=./tmp_chk");
 	push(@args, $maxconn) if $maxconn;
 	system(@args);
 	$status = $? >> 8;
@@ -149,12 +156,14 @@ sub ecpgcheck
 
 sub isolationcheck
 {
-	chdir "../isolation";
-	copy("../../../$Config/isolationtester/isolationtester.exe",
-		"../../../$Config/pg_isolation_regress");
+	chdir $startdir;
+
+	InstallTemp();
+	chdir "${topdir}/src/test/isolation";
+
 	my @args = (
-		"../../../$Config/pg_isolation_regress/pg_isolation_regress",
-		"--psqldir=../../../$Config/psql",
+		"${tmp_installdir}/bin/pg_isolation_regress",
+		"--bindir=${tmp_installdir}/bin",
 		"--inputdir=.",
 		"--schedule=./isolation_schedule");
 	push(@args, $maxconn) if $maxconn;
@@ -165,7 +174,10 @@ sub isolationcheck
 
 sub plcheck
 {
-	chdir "../../pl";
+	chdir $startdir;
+
+	InstallTemp();
+	chdir "${topdir}/src/pl";
 
 	foreach my $pl (glob("*"))
 	{
@@ -202,8 +214,8 @@ sub plcheck
 		  "============================================================\n";
 		print "Checking $lang\n";
 		my @args = (
-			"../../../$Config/pg_regress/pg_regress",
-			"--psqldir=../../../$Config/psql",
+			"${tmp_installdir}/bin/pg_regress",
+			"--bindir=${tmp_installdir}/bin",
 			"--dbname=pl_regression", @lang_args, @tests);
 		system(@args);
 		my $status = $? >> 8;
@@ -233,8 +245,8 @@ sub subdircheck
 	my @tests = fetchTests();
 	my @opts  = fetchRegressOpts();
 	my @args  = (
-		"$topdir/$Config/pg_regress/pg_regress",
-		"--psqldir=$topdir/$Config/psql",
+		"${tmp_installdir}/bin/pg_regress",
+		"--bindir=${tmp_installdir}/bin",
 		"--dbname=contrib_regression", @opts, @tests);
 	system(@args);
 	my $status = $? >> 8;
@@ -273,8 +285,8 @@ sub modulescheck
 sub standard_initdb
 {
 	return (
-		system('initdb', '-N') == 0 and system(
-			"$topdir/$Config/pg_regress/pg_regress", '--config-auth',
+		system("${tmp_installdir}/bin/initdb", '-N') == 0 and system(
+			"${tmp_installdir}/bin/pg_regress", '--config-auth',
 			$ENV{PGDATA}) == 0);
 }
 
@@ -293,14 +305,13 @@ sub upgradecheck
 	$ENV{PGPORT} ||= 50432;
 	my $tmp_root = "$topdir/src/bin/pg_upgrade/tmp_check";
 	(mkdir $tmp_root || die $!) unless -d $tmp_root;
-	my $tmp_install = "$tmp_root/install";
-	print "Setting up temp install\n\n";
-	Install($tmp_install, "all", $config);
+
+	InstallTemp();
 
 	# Install does a chdir, so change back after that
 	chdir $cwd;
 	my ($bindir, $libdir, $oldsrc, $newsrc) =
-	  ("$tmp_install/bin", "$tmp_install/lib", $topdir, $topdir);
+	  ("$tmp_installdir/bin", "$tmp_installdir/lib", $topdir, $topdir);
 	$ENV{PATH} = "$bindir;$ENV{PATH}";
 	my $data = "$tmp_root/data";
 	$ENV{PGDATA} = "$data.old";
@@ -435,6 +446,12 @@ sub GetTests
 	return "";
 }
 
+sub InstallTemp
+{
+	print "Setting up temp install\n\n";
+	Install("$tmp_installdir", "all", $config);
+}
+
 sub usage
 {
 	print STDERR