diff --git a/GNUmakefile.in b/GNUmakefile.in
index f3c5fe587e9f14ab0e10eec77d27a08bd4a5c7a4..79b0da42a84543046477fc254e997213ba844aec 100644
--- a/GNUmakefile.in
+++ b/GNUmakefile.in
@@ -60,8 +60,7 @@ check: all
 check installcheck installcheck-parallel:
 	$(MAKE) -C src/test $@
 
-# TODO: add contrib
-$(call recurse,check-world,src/test src/pl src/interfaces/ecpg,check)
+$(call recurse,check-world,src/test src/pl src/interfaces/ecpg contrib,check)
 
 $(call recurse,installcheck-world,src/test src/pl src/interfaces/ecpg contrib,installcheck)
 
diff --git a/contrib/btree_gin/.gitignore b/contrib/btree_gin/.gitignore
index 19b6c5ba425ca92d1bb371bf43d9cdae372f8c1a..5dcb3ff9723501c3fe639bee1c1435e47a580a6f 100644
--- a/contrib/btree_gin/.gitignore
+++ b/contrib/btree_gin/.gitignore
@@ -1,2 +1,4 @@
 # Generated subdirectories
+/log/
 /results/
+/tmp_check/
diff --git a/contrib/btree_gist/.gitignore b/contrib/btree_gist/.gitignore
index 19b6c5ba425ca92d1bb371bf43d9cdae372f8c1a..5dcb3ff9723501c3fe639bee1c1435e47a580a6f 100644
--- a/contrib/btree_gist/.gitignore
+++ b/contrib/btree_gist/.gitignore
@@ -1,2 +1,4 @@
 # Generated subdirectories
+/log/
 /results/
+/tmp_check/
diff --git a/contrib/citext/.gitignore b/contrib/citext/.gitignore
index 19b6c5ba425ca92d1bb371bf43d9cdae372f8c1a..5dcb3ff9723501c3fe639bee1c1435e47a580a6f 100644
--- a/contrib/citext/.gitignore
+++ b/contrib/citext/.gitignore
@@ -1,2 +1,4 @@
 # Generated subdirectories
+/log/
 /results/
+/tmp_check/
diff --git a/contrib/cube/.gitignore b/contrib/cube/.gitignore
index a6484a05e7332d3df5dac6b1bb5effede80542ae..cb4c989fff10a0eb593fda8f9c90be57a7d8b26a 100644
--- a/contrib/cube/.gitignore
+++ b/contrib/cube/.gitignore
@@ -1,4 +1,6 @@
 /cubeparse.c
 /cubescan.c
 # Generated subdirectories
+/log/
 /results/
+/tmp_check/
diff --git a/contrib/dblink/.gitignore b/contrib/dblink/.gitignore
index 19b6c5ba425ca92d1bb371bf43d9cdae372f8c1a..5dcb3ff9723501c3fe639bee1c1435e47a580a6f 100644
--- a/contrib/dblink/.gitignore
+++ b/contrib/dblink/.gitignore
@@ -1,2 +1,4 @@
 # Generated subdirectories
+/log/
 /results/
+/tmp_check/
diff --git a/contrib/dict_int/.gitignore b/contrib/dict_int/.gitignore
index 19b6c5ba425ca92d1bb371bf43d9cdae372f8c1a..5dcb3ff9723501c3fe639bee1c1435e47a580a6f 100644
--- a/contrib/dict_int/.gitignore
+++ b/contrib/dict_int/.gitignore
@@ -1,2 +1,4 @@
 # Generated subdirectories
+/log/
 /results/
+/tmp_check/
diff --git a/contrib/dict_xsyn/.gitignore b/contrib/dict_xsyn/.gitignore
index 19b6c5ba425ca92d1bb371bf43d9cdae372f8c1a..5dcb3ff9723501c3fe639bee1c1435e47a580a6f 100644
--- a/contrib/dict_xsyn/.gitignore
+++ b/contrib/dict_xsyn/.gitignore
@@ -1,2 +1,4 @@
 # Generated subdirectories
+/log/
 /results/
+/tmp_check/
diff --git a/contrib/earthdistance/.gitignore b/contrib/earthdistance/.gitignore
index 19b6c5ba425ca92d1bb371bf43d9cdae372f8c1a..5dcb3ff9723501c3fe639bee1c1435e47a580a6f 100644
--- a/contrib/earthdistance/.gitignore
+++ b/contrib/earthdistance/.gitignore
@@ -1,2 +1,4 @@
 # Generated subdirectories
+/log/
 /results/
+/tmp_check/
diff --git a/contrib/earthdistance/Makefile b/contrib/earthdistance/Makefile
index 49f6e6675fc67df745b62bb55356be99a7e5c6bd..48a7cf8c7c021fffc660a2ed4a93eeaf55800d2c 100644
--- a/contrib/earthdistance/Makefile
+++ b/contrib/earthdistance/Makefile
@@ -6,6 +6,7 @@ EXTENSION = earthdistance
 DATA = earthdistance--1.0.sql earthdistance--unpackaged--1.0.sql
 
 REGRESS = earthdistance
+REGRESS_OPTS = --extra-install=contrib/cube
 
 LDFLAGS_SL += $(filter -lm, $(LIBS))
 
diff --git a/contrib/file_fdw/.gitignore b/contrib/file_fdw/.gitignore
index 19b6c5ba425ca92d1bb371bf43d9cdae372f8c1a..5dcb3ff9723501c3fe639bee1c1435e47a580a6f 100644
--- a/contrib/file_fdw/.gitignore
+++ b/contrib/file_fdw/.gitignore
@@ -1,2 +1,4 @@
 # Generated subdirectories
+/log/
 /results/
+/tmp_check/
diff --git a/contrib/hstore/.gitignore b/contrib/hstore/.gitignore
index 19b6c5ba425ca92d1bb371bf43d9cdae372f8c1a..5dcb3ff9723501c3fe639bee1c1435e47a580a6f 100644
--- a/contrib/hstore/.gitignore
+++ b/contrib/hstore/.gitignore
@@ -1,2 +1,4 @@
 # Generated subdirectories
+/log/
 /results/
+/tmp_check/
diff --git a/contrib/intarray/.gitignore b/contrib/intarray/.gitignore
index 19b6c5ba425ca92d1bb371bf43d9cdae372f8c1a..5dcb3ff9723501c3fe639bee1c1435e47a580a6f 100644
--- a/contrib/intarray/.gitignore
+++ b/contrib/intarray/.gitignore
@@ -1,2 +1,4 @@
 # Generated subdirectories
+/log/
 /results/
+/tmp_check/
diff --git a/contrib/ltree/.gitignore b/contrib/ltree/.gitignore
index 19b6c5ba425ca92d1bb371bf43d9cdae372f8c1a..5dcb3ff9723501c3fe639bee1c1435e47a580a6f 100644
--- a/contrib/ltree/.gitignore
+++ b/contrib/ltree/.gitignore
@@ -1,2 +1,4 @@
 # Generated subdirectories
+/log/
 /results/
+/tmp_check/
diff --git a/contrib/pg_trgm/.gitignore b/contrib/pg_trgm/.gitignore
index 19b6c5ba425ca92d1bb371bf43d9cdae372f8c1a..5dcb3ff9723501c3fe639bee1c1435e47a580a6f 100644
--- a/contrib/pg_trgm/.gitignore
+++ b/contrib/pg_trgm/.gitignore
@@ -1,2 +1,4 @@
 # Generated subdirectories
+/log/
 /results/
+/tmp_check/
diff --git a/contrib/pgcrypto/.gitignore b/contrib/pgcrypto/.gitignore
index 19b6c5ba425ca92d1bb371bf43d9cdae372f8c1a..5dcb3ff9723501c3fe639bee1c1435e47a580a6f 100644
--- a/contrib/pgcrypto/.gitignore
+++ b/contrib/pgcrypto/.gitignore
@@ -1,2 +1,4 @@
 # Generated subdirectories
+/log/
 /results/
+/tmp_check/
diff --git a/contrib/seg/.gitignore b/contrib/seg/.gitignore
index 102f8b3246da9bedee88199f52d88fc9d7004295..69e73d20966bca15624527edd09e258c23f75ecb 100644
--- a/contrib/seg/.gitignore
+++ b/contrib/seg/.gitignore
@@ -1,4 +1,6 @@
 /segparse.c
 /segscan.c
 # Generated subdirectories
+/log/
 /results/
+/tmp_check/
diff --git a/contrib/tablefunc/.gitignore b/contrib/tablefunc/.gitignore
index 19b6c5ba425ca92d1bb371bf43d9cdae372f8c1a..5dcb3ff9723501c3fe639bee1c1435e47a580a6f 100644
--- a/contrib/tablefunc/.gitignore
+++ b/contrib/tablefunc/.gitignore
@@ -1,2 +1,4 @@
 # Generated subdirectories
+/log/
 /results/
+/tmp_check/
diff --git a/contrib/test_parser/.gitignore b/contrib/test_parser/.gitignore
index 19b6c5ba425ca92d1bb371bf43d9cdae372f8c1a..5dcb3ff9723501c3fe639bee1c1435e47a580a6f 100644
--- a/contrib/test_parser/.gitignore
+++ b/contrib/test_parser/.gitignore
@@ -1,2 +1,4 @@
 # Generated subdirectories
+/log/
 /results/
+/tmp_check/
diff --git a/contrib/tsearch2/.gitignore b/contrib/tsearch2/.gitignore
index 19b6c5ba425ca92d1bb371bf43d9cdae372f8c1a..5dcb3ff9723501c3fe639bee1c1435e47a580a6f 100644
--- a/contrib/tsearch2/.gitignore
+++ b/contrib/tsearch2/.gitignore
@@ -1,2 +1,4 @@
 # Generated subdirectories
+/log/
 /results/
+/tmp_check/
diff --git a/contrib/unaccent/.gitignore b/contrib/unaccent/.gitignore
index 19b6c5ba425ca92d1bb371bf43d9cdae372f8c1a..5dcb3ff9723501c3fe639bee1c1435e47a580a6f 100644
--- a/contrib/unaccent/.gitignore
+++ b/contrib/unaccent/.gitignore
@@ -1,2 +1,4 @@
 # Generated subdirectories
+/log/
 /results/
+/tmp_check/
diff --git a/contrib/xml2/.gitignore b/contrib/xml2/.gitignore
index 19b6c5ba425ca92d1bb371bf43d9cdae372f8c1a..5dcb3ff9723501c3fe639bee1c1435e47a580a6f 100644
--- a/contrib/xml2/.gitignore
+++ b/contrib/xml2/.gitignore
@@ -1,2 +1,4 @@
 # Generated subdirectories
+/log/
 /results/
+/tmp_check/
diff --git a/src/makefiles/pgxs.mk b/src/makefiles/pgxs.mk
index 87ade0a420f1eba356b2a61727fd7b21dc2bd3e1..7fb007fb1c3a174c7c3ec1dc379b32109dbd909e 100644
--- a/src/makefiles/pgxs.mk
+++ b/src/makefiles/pgxs.mk
@@ -281,13 +281,14 @@ endif
 installcheck: submake
 	$(pg_regress_installcheck) $(REGRESS_OPTS) $(REGRESS)
 
-# in-tree test doesn't work yet (no way to install my shared library)
-#check: all submake
-#	$(pg_regress_check) $(REGRESS_OPTS) $(REGRESS)
+ifdef PGXS
 check:
-	@echo "'make check' is not supported."
-	@echo "Do 'make install', then 'make installcheck' instead."
-	@exit 1
+	@echo '"$(MAKE) check" is not supported.'
+	@echo 'Do "$(MAKE) install", then "$(MAKE) installcheck" instead.'
+else
+check: all submake
+	$(pg_regress_check) --extra-install=$(subdir) $(REGRESS_OPTS) $(REGRESS)
+endif
 endif # REGRESS
 
 
diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c
index 5dba7eb8f2267a3a24b8928243bf29bee483f0b2..23ef0a94e5d070b66585bd76ac5697a6347bc825 100644
--- a/src/test/regress/pg_regress.c
+++ b/src/test/regress/pg_regress.c
@@ -102,6 +102,7 @@ static bool port_specified_by_user = false;
 static char *dlpath = PKGLIBDIR;
 static char *user = NULL;
 static _stringlist *extraroles = NULL;
+static _stringlist *extra_install = NULL;
 
 /* internal variables */
 static const char *progname;
@@ -1896,6 +1897,7 @@ help(void)
 	printf(_("  --top-builddir=DIR        (relative) path to top level build directory\n"));
 	printf(_("  --port=PORT               start postmaster on PORT\n"));
 	printf(_("  --temp-config=PATH        append contents of PATH to temporary config\n"));
+	printf(_("  --extra-install=DIR       additional directory to install (e.g., contrib\n"));
 	printf(_("\n"));
 	printf(_("Options for using an existing installation:\n"));
 	printf(_("  --host=HOST               use postmaster running on HOST\n"));
@@ -1943,6 +1945,7 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
 		{"use-existing", no_argument, NULL, 20},
 		{"launcher", required_argument, NULL, 21},
 		{"load-extension", required_argument, NULL, 22},
+		{"extra-install", required_argument, NULL, 23},
 		{NULL, 0, NULL, 0}
 	};
 
@@ -2042,6 +2045,9 @@ 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;
 			default:
 				/* getopt_long already emitted a complaint */
 				fprintf(stderr, _("\nTry \"%s -h\" for more information.\n"),
@@ -2086,6 +2092,7 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
 	if (temp_install)
 	{
 		FILE	   *pg_conf;
+		_stringlist *sl;
 
 		/*
 		 * Prepare the temp installation
@@ -2128,6 +2135,24 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
 			exit_nicely(2);
 		}
 
+		for (sl = extra_install; sl != NULL; sl = sl->next)
+		{
+#ifndef WIN32_ONLY_COMPILER
+			snprintf(buf, sizeof(buf),
+					 SYSTEMQUOTE "\"%s\" -C \"%s/%s\" DESTDIR=\"%s/install\" install >> \"%s/log/install.log\" 2>&1" SYSTEMQUOTE,
+					 makeprog, top_builddir, sl->str, temp_install, outputdir);
+#else
+			fprintf(stderr, _("\n%s: --extra-install option not supported on this platform\n", progname));
+			exit_nicely(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_nicely(2);
+			}
+		}
+
 		/* initdb */
 		header(_("initializing database system"));
 		snprintf(buf, sizeof(buf),