diff --git a/contrib/tsearch2/Makefile b/contrib/tsearch2/Makefile
index a58370ec51c90b21cd562a9cc214a4c6a4b9b345..7dd1e1b0810e695a2f1b4268f81300bf56ab976e 100644
--- a/contrib/tsearch2/Makefile
+++ b/contrib/tsearch2/Makefile
@@ -7,24 +7,26 @@ override CPPFLAGS := -I. -I./snowball -I./ispell -I./wordparser $(CPPFLAGS)
 
 MODULE_big = tsearch2
 OBJS = dict_ex.o dict.o snmap.o stopword.o common.o prs_dcfg.o \
-       snowball/english_stem.o snowball/api.o snowball/russian_stem.o snowball/utilities.o \
-       dict_snowball.o ispell/spell.o dict_ispell.o dict_syn.o \
-       wparser.o wordparser/parser.o wordparser/deflex.o wparser_def.o \
+       dict_snowball.o dict_ispell.o dict_syn.o \
+       wparser.o wparser_def.o \
        ts_cfg.o tsvector.o rewrite.o crc32.o query.o gistidx.o \
        tsvector_op.o rank.o ts_stat.o
 
+SUBDIRS     := snowball ispell wordparser
+SUBDIROBJS  := $(SUBDIRS:%=%/SUBSYS.o)
+
+OBJS:= $(OBJS) $(SUBDIROBJS)
+
+$(SUBDIROBJS): $(SUBDIRS:%=%-recursive) ;
+
+$(SUBDIRS:%=%-recursive):
+	$(MAKE) -C $(subst -recursive,,$@) SUBSYS.o
+
 DATA_built = tsearch2.sql untsearch2.sql
 DOCS = README.tsearch2
 REGRESS = tsearch2
 
-wordparser/parser.c: wordparser/parser.l
-ifdef FLEX
-	$(FLEX) $(FLEXFLAGS) -8 -Ptsearch2_yy -o'$@' $<
-else
-	@$(missing) flex $< $@
-endif
-
-EXTRA_CLEAN = wordparser/parser.c tsearch2.sql.in
+EXTRA_CLEAN = tsearch2.sql.in
 
 SHLIB_LINK := -lm
 include $(top_srcdir)/contrib/contrib-global.mk
@@ -40,5 +42,10 @@ tsearch2.sql.in: tsearch.sql._in
 	sed 's,DATA_PATH,$(datadir),g' < $< > $@
 
 untsearch2.sql: untsearch.sql.in
-	cp $< $@ 
+	cp $< $@
+
+clean: subclean
 
+subclean:
+	for dir in $(SUBDIRS); do $(MAKE) -C $$dir clean || exit; done
+ 
diff --git a/contrib/tsearch2/ispell/Makefile b/contrib/tsearch2/ispell/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..def0c3126c834172701c70c6c9b53db5e0fd6c28
--- /dev/null
+++ b/contrib/tsearch2/ispell/Makefile
@@ -0,0 +1,20 @@
+subdir = contrib/tsearch2/ispell
+top_builddir = ../../..
+include $(top_builddir)/src/Makefile.global
+
+
+override CPPFLAGS := -I. -I.. $(CPPFLAGS)
+
+SUBOBJS = spell.o 
+
+all: SUBSYS.o
+
+SUBSYS.o: $(SUBOBJS)
+	$(LD) $(LDREL) $(LDOUT) $@ $^
+
+EXTRA_CLEAN = SUBSYS.o $(SUBOBJS)
+
+include $(top_srcdir)/contrib/contrib-global.mk
+# DO NOT DELETE
+
+
diff --git a/contrib/tsearch2/snowball/Makefile b/contrib/tsearch2/snowball/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..94e48fb466272bd6676697a57b80bb616cb2dc67
--- /dev/null
+++ b/contrib/tsearch2/snowball/Makefile
@@ -0,0 +1,20 @@
+subdir = contrib/tsearch2/snowball
+top_builddir = ../../..
+include $(top_builddir)/src/Makefile.global
+
+
+override CPPFLAGS := -I. -I.. $(CPPFLAGS)
+
+SUBOBJS = english_stem.o api.o russian_stem.o utilities.o
+
+all: SUBSYS.o
+
+SUBSYS.o: $(SUBOBJS)
+	$(LD) $(LDREL) $(LDOUT) $@ $^
+
+EXTRA_CLEAN = SUBSYS.o $(SUBOBJS)
+
+include $(top_srcdir)/contrib/contrib-global.mk
+# DO NOT DELETE
+
+
diff --git a/contrib/tsearch2/wordparser/Makefile b/contrib/tsearch2/wordparser/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..8fa1e1f06ae71d6e829d30b312b64b3c2afb547d
--- /dev/null
+++ b/contrib/tsearch2/wordparser/Makefile
@@ -0,0 +1,27 @@
+subdir = contrib/tsearch2/wordparser
+top_builddir = ../../..
+include $(top_builddir)/src/Makefile.global
+
+
+override CPPFLAGS := -I. -I.. $(CPPFLAGS)
+
+SUBOBJS =  parser.o deflex.o
+
+all: SUBSYS.o
+
+parser.c: parser.l
+ifdef FLEX
+	$(FLEX) $(FLEXFLAGS) -8 -Ptsearch2_yy -o'$@' $<
+else
+	@$(missing) flex $< $@
+endif
+
+SUBSYS.o: $(SUBOBJS)
+	$(LD) $(LDREL) $(LDOUT) $@ $^
+
+EXTRA_CLEAN = SUBSYS.o $(SUBOBJS) parser.c
+
+include $(top_srcdir)/contrib/contrib-global.mk
+# DO NOT DELETE
+
+