diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b01473c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+SOURCES/make-4.3.tar.gz
diff --git a/.make-latest.metadata b/.make-latest.metadata
new file mode 100644
index 0000000..ebf9a3e
--- /dev/null
+++ b/.make-latest.metadata
@@ -0,0 +1 @@
+3c40e5b49b893dbb14f1e2e1f8fe89b7298cc51d SOURCES/make-4.3.tar.gz
diff --git a/SOURCES/make-4.0-noclock_gettime.patch b/SOURCES/make-4.0-noclock_gettime.patch
new file mode 100644
index 0000000..f63e1fc
--- /dev/null
+++ b/SOURCES/make-4.0-noclock_gettime.patch
@@ -0,0 +1,14 @@
+diff -up make-3.82/configure\~ make-3.82/configure
+--- make-3.82/configure~	2010-07-28 07:41:51.000000000 +0200
++++ make-3.82/configure	2010-08-11 15:07:50.000000000 +0200
+@@ -7215,7 +7215,7 @@ return clock_gettime ();
+   return 0;
+ }
+ _ACEOF
+-for ac_lib in '' rt posix4; do
++for ac_lib in '' posix4; do
+   if test -z "$ac_lib"; then
+     ac_res="none required"
+   else
+
+Diff finished.  Wed Aug 11 15:07:59 2010
diff --git a/SOURCES/make-4.3-cloexec.patch b/SOURCES/make-4.3-cloexec.patch
new file mode 100644
index 0000000..c680367
--- /dev/null
+++ b/SOURCES/make-4.3-cloexec.patch
@@ -0,0 +1,36 @@
+From d79fe162c009788888faaf0317253b6f0cac7092 Mon Sep 17 00:00:00 2001
+From: Kevin Buettner <kevinb@redhat.com>
+Date: Thu, 23 Apr 2020 17:05:34 -0400
+Subject: [SV 58232] Disable inheritance of jobserver FDs for recursive make
+
+A parent make will invoke a sub-make with close-on-exec disabled for
+the jobserver pipe FDs.  Force close-on-exec to be to be enabled in
+the sub-make so the pipe is not always passed to child jobs.
+
+I have a test case which, when invoked with a suitable -j switch,
+will hang if the recipe inherits the jobserver pipe.  This test case
+was inspired by a real world case in which testing GDB on Fedora
+would hang due to some poorly written test GDB cases having been
+passed the jobserver file descriptors.
+
+* src/posixos.c (jobserver_parse_auth): Call fd_noinherit() for
+jobserver pipe descriptors.
+
+Copyright-paperwork-exempt: yes
+
+diff --git a/src/posixos.c b/src/posixos.c
+index 525f292c..eab175a4 100644
+--- a/src/posixos.c
++++ b/src/posixos.c
+@@ -145,6 +145,11 @@ jobserver_parse_auth (const char *auth)
+   /* When using pselect() we want the read to be non-blocking.  */
+   set_blocking (job_fds[0], 0);
+ 
++  /* By default we don't send the job pipe FDs to our children.
++     See jobserver_pre_child() and jobserver_post_child().  */
++  fd_noinherit (job_fds[0]);
++  fd_noinherit (job_fds[1]);
++
+   return 1;
+ }
+ 
diff --git a/SOURCES/make-4.3-filter-out.patch b/SOURCES/make-4.3-filter-out.patch
new file mode 100644
index 0000000..bdd2fcc
--- /dev/null
+++ b/SOURCES/make-4.3-filter-out.patch
@@ -0,0 +1,268 @@
+From e49e11e069fe7f214263be1782242b9b50f71eaa Mon Sep 17 00:00:00 2001
+From: Paul Smith <psmith@gnu.org>
+Date: Thu, 12 Nov 2020 17:00:39 -0500
+Subject: [SV 59093] Rewrite filter/filter-out to avoid large stack usage
+
+* src/function.c (func_filter_filterout): Allocate arrays to hold
+pattern and word information rather than creating linked lists on
+the stack.
+* tests/scripts/functions/filter-out: Test large filters.
+
+diff --git a/src/function.c b/src/function.c
+index 0917e0cd..5edfe8b3 100644
+--- a/src/function.c
++++ b/src/function.c
+@@ -910,7 +910,6 @@ func_foreach (char *o, char **argv, const char *funcname UNUSED)
+ 
+ struct a_word
+ {
+-  struct a_word *next;
+   struct a_word *chain;
+   char *str;
+   size_t length;
+@@ -941,7 +940,6 @@ a_word_hash_cmp (const void *x, const void *y)
+ 
+ struct a_pattern
+ {
+-  struct a_pattern *next;
+   char *str;
+   char *percent;
+   size_t length;
+@@ -950,78 +948,84 @@ struct a_pattern
+ static char *
+ func_filter_filterout (char *o, char **argv, const char *funcname)
+ {
+-  struct a_word *wordhead;
+-  struct a_word **wordtail;
++  struct a_word *words;
++  struct a_word *word_end;
+   struct a_word *wp;
+-  struct a_pattern *pathead;
+-  struct a_pattern **pattail;
++  struct a_pattern *patterns;
++  struct a_pattern *pat_end;
+   struct a_pattern *pp;
++  size_t pat_count = 0, word_count = 0;
+ 
+   struct hash_table a_word_table;
+   int is_filter = funcname[CSTRLEN ("filter")] == '\0';
+-  const char *pat_iterator = argv[0];
+-  const char *word_iterator = argv[1];
++  const char *cp;
+   int literals = 0;
+-  int words = 0;
+   int hashing = 0;
+   char *p;
+   size_t len;
++  int doneany = 0;
+ 
+-  /* Chop ARGV[0] up into patterns to match against the words.
+-     We don't need to preserve it because our caller frees all the
+-     argument memory anyway.  */
++  /* Find the number of words and get memory for them.  */
++  cp = argv[1];
++  while ((p = find_next_token (&cp, NULL)) != 0)
++    ++word_count;
+ 
+-  pattail = &pathead;
+-  while ((p = find_next_token (&pat_iterator, &len)) != 0)
+-    {
+-      struct a_pattern *pat = alloca (sizeof (struct a_pattern));
++  if (!word_count)
++    return o;
++
++  words = xcalloc (word_count * sizeof (struct a_word));
++  word_end = words + word_count;
+ 
+-      *pattail = pat;
+-      pattail = &pat->next;
++  /* Find the number of patterns and get memory for them.  */
++  cp = argv[0];
++  while ((p = find_next_token (&cp, NULL)) != 0)
++    ++pat_count;
+ 
+-      if (*pat_iterator != '\0')
+-        ++pat_iterator;
++  patterns = xcalloc (pat_count * sizeof (struct a_pattern));
++  pat_end = patterns + pat_count;
++
++  /* Chop argv[0] up into patterns to match against the words.  */
++
++  cp = argv[0];
++  pp = patterns;
++  while ((p = find_next_token (&cp, &len)) != 0)
++    {
++      if (*cp != '\0')
++        ++cp;
+ 
+-      pat->str = p;
+       p[len] = '\0';
+-      pat->percent = find_percent (p);
+-      if (pat->percent == 0)
++      pp->str = p;
++      pp->percent = find_percent (p);
++      if (pp->percent == 0)
+         literals++;
+-
+       /* find_percent() might shorten the string so LEN is wrong.  */
+-      pat->length = strlen (pat->str);
++      pp->length = strlen (pp->str);
++
++      ++pp;
+     }
+-  *pattail = 0;
+ 
+   /* Chop ARGV[1] up into words to match against the patterns.  */
+ 
+-  wordtail = &wordhead;
+-  while ((p = find_next_token (&word_iterator, &len)) != 0)
++  cp = argv[1];
++  wp = words;
++  while ((p = find_next_token (&cp, &len)) != 0)
+     {
+-      struct a_word *word = alloca (sizeof (struct a_word));
+-
+-      *wordtail = word;
+-      wordtail = &word->next;
+-
+-      if (*word_iterator != '\0')
+-        ++word_iterator;
++      if (*cp != '\0')
++        ++cp;
+ 
+       p[len] = '\0';
+-      word->str = p;
+-      word->length = len;
+-      word->matched = 0;
+-      word->chain = 0;
+-      words++;
++      wp->str = p;
++      wp->length = len;
++      ++wp;
+     }
+-  *wordtail = 0;
+ 
+   /* Only use a hash table if arg list lengths justifies the cost.  */
+-  hashing = (literals >= 2 && (literals * words) >= 10);
++  hashing = (literals > 1 && (literals * word_count) >= 10);
+   if (hashing)
+     {
+-      hash_init (&a_word_table, words, a_word_hash_1, a_word_hash_2,
++      hash_init (&a_word_table, word_count, a_word_hash_1, a_word_hash_2,
+                  a_word_hash_cmp);
+-      for (wp = wordhead; wp != 0; wp = wp->next)
++      for (wp = words; wp < word_end; ++wp)
+         {
+           struct a_word *owp = hash_insert (&a_word_table, wp);
+           if (owp)
+@@ -1029,51 +1033,49 @@ func_filter_filterout (char *o, char **argv, const char *funcname)
+         }
+     }
+ 
+-  if (words)
++  /* Run each pattern through the words, killing words.  */
++  for (pp = patterns; pp < pat_end; ++pp)
+     {
+-      int doneany = 0;
+-
+-      /* Run each pattern through the words, killing words.  */
+-      for (pp = pathead; pp != 0; pp = pp->next)
++      if (pp->percent)
++        for (wp = words; wp < word_end; ++wp)
++          wp->matched |= pattern_matches (pp->str, pp->percent, wp->str);
++      else if (hashing)
+         {
+-          if (pp->percent)
+-            for (wp = wordhead; wp != 0; wp = wp->next)
+-              wp->matched |= pattern_matches (pp->str, pp->percent, wp->str);
+-          else if (hashing)
++          struct a_word a_word_key;
++          a_word_key.str = pp->str;
++          a_word_key.length = pp->length;
++          wp = hash_find_item (&a_word_table, &a_word_key);
++          while (wp)
+             {
+-              struct a_word a_word_key;
+-              a_word_key.str = pp->str;
+-              a_word_key.length = pp->length;
+-              wp = hash_find_item (&a_word_table, &a_word_key);
+-              while (wp)
+-                {
+-                  wp->matched |= 1;
+-                  wp = wp->chain;
+-                }
++              wp->matched |= 1;
++              wp = wp->chain;
+             }
+-          else
+-            for (wp = wordhead; wp != 0; wp = wp->next)
+-              wp->matched |= (wp->length == pp->length
+-                              && strneq (pp->str, wp->str, wp->length));
+         }
++      else
++        for (wp = words; wp < word_end; ++wp)
++          wp->matched |= (wp->length == pp->length
++                          && strneq (pp->str, wp->str, wp->length));
++    }
+ 
+-      /* Output the words that matched (or didn't, for filter-out).  */
+-      for (wp = wordhead; wp != 0; wp = wp->next)
+-        if (is_filter ? wp->matched : !wp->matched)
+-          {
+-            o = variable_buffer_output (o, wp->str, strlen (wp->str));
+-            o = variable_buffer_output (o, " ", 1);
+-            doneany = 1;
+-          }
++  /* Output the words that matched (or didn't, for filter-out).  */
++  for (wp = words; wp < word_end; ++wp)
++    if (is_filter ? wp->matched : !wp->matched)
++      {
++        o = variable_buffer_output (o, wp->str, strlen (wp->str));
++        o = variable_buffer_output (o, " ", 1);
++        doneany = 1;
++      }
+ 
+-      if (doneany)
+-        /* Kill the last space.  */
+-        --o;
+-    }
++  if (doneany)
++    /* Kill the last space.  */
++    --o;
+ 
+   if (hashing)
+     hash_free (&a_word_table, 0);
+ 
++  free (patterns);
++  free (words);
++
+   return o;
+ }
+ 
+diff --git a/tests/scripts/functions/filter-out b/tests/scripts/functions/filter-out
+index 1fe4819d..dec5343e 100644
+--- a/tests/scripts/functions/filter-out
++++ b/tests/scripts/functions/filter-out
+@@ -27,6 +27,22 @@ all: ; @echo '$(files1) $(files2)'
+ !,
+               '', "foo.elc foo.elc\n");
+ 
++# Force use of hash (see function.c:func_filter_filterout for params)
++
++my $base = 'foo.1 foo.2 foo.3 foo.4 foo.5 foo.6 foo.7 foo.8 foo.9 foo.10';
++
++my $base10 = join(' ', ($base) x 10);
++my $out3 = join(' ', ('foo.3') x 10);
++my $out456 = join(' ', ('foo.4 foo.5 foo.6') x 10);
++
++run_make_test("words := $base10" . q!
++files1 := $(filter %.3, $(words))
++files2 := $(filter %.4 foo.5 foo.6, $(words))
++all: ; @echo '$(files1) $(files2)'
++!,
++              '', "$out3 $out456\n");
++
++
+ # Escaped patterns
+ run_make_test(q!all:;@echo '$(filter foo\%bar,foo%bar fooXbar)'!,
+               '', "foo%bar\n");
diff --git a/SOURCES/make-4.3-getcwd.patch b/SOURCES/make-4.3-getcwd.patch
new file mode 100644
index 0000000..7f6f18f
--- /dev/null
+++ b/SOURCES/make-4.3-getcwd.patch
@@ -0,0 +1,12 @@
+diff -Nrup a/src/makeint.h b/src/makeint.h
+--- a/src/makeint.h	2016-05-21 16:22:32.000000000 -0400
++++ b/src/makeint.h	2016-09-22 16:12:38.606702160 -0400
+@@ -596,7 +596,7 @@ long int lseek ();
+ # endif
+ 
+ # ifdef  HAVE_GETCWD
+-#  if !defined(VMS) && !defined(__DECC)
++#  if !defined(VMS) && !defined(__DECC) && !defined(getcwd)
+ char *getcwd ();
+ #  endif
+ # else
diff --git a/SOURCES/make-4.3-j8k.patch b/SOURCES/make-4.3-j8k.patch
new file mode 100644
index 0000000..60a0c7f
--- /dev/null
+++ b/SOURCES/make-4.3-j8k.patch
@@ -0,0 +1,25 @@
+diff -Nrup a/src/main.c b/src/main.c
+--- a/src/main.c	2016-05-31 03:17:26.000000000 -0400
++++ b/src/main.c	2016-09-22 16:18:52.283889265 -0400
+@@ -2051,6 +2051,21 @@ main (int argc, char **argv, char **envp
+     }
+ #endif
+ 
++#ifdef PIPE_BUF
++  if (job_slots > PIPE_BUF)
++#elif defined _POSIX_PIPE_BUF
++  if (job_slots > _POSIX_PIPE_BUF)
++#else
++  if (job_slots > 512)
++#endif
++    {
++      O (error, NILF,
++            _("More parallel jobs (-jN) than this platform can handle requested."));
++      O (error, NILF, _("Resetting to single job (-j1) mode."));
++      job_slots = 1;
++    }
++
++
+   /* If we have >1 slot at this point, then we're a top-level make.
+      Set up the jobserver.
+ 
diff --git a/SPECS/make-latest.spec b/SPECS/make-latest.spec
new file mode 100644
index 0000000..aff2cfc
--- /dev/null
+++ b/SPECS/make-latest.spec
@@ -0,0 +1,148 @@
+# -*- coding: utf-8 -*-
+# This decides the SRPM name.  Set to "make" for a rolling release
+# (like Fedora) or "make-latest" for a long term release that needs
+# optional versioned updates.
+Name: make-latest
+Epoch: 1
+Version: 4.3
+Release: 1%{?dist}
+License: GPLv3+
+URL: http://www.gnu.org/software/make/
+Source: ftp://ftp.gnu.org/gnu/make/make-%{version}.tar.gz
+
+%if "%{name}" != "make"
+# Set this to the sub-package base name, for "make-latest"
+%global make make43
+%if 0%{?rhel} > 0
+%global _prefix /opt/rh/%{make}
+%else
+# We intentionally do not define a case for Fedora, as it should not
+# need this functionality, and letting it error avoids accidents.
+%{error:"Each downstream must specify its own /opt namespace"}
+%endif
+Summary: Meta package to include latest version of make
+%else
+%global make %{name}
+Summary: A GNU tool which simplifies the build process for users
+%endif
+
+%if 0%{?rhel} > 0
+# This gives the user the option of saying --with guile, but defaults to WITHOUT
+%bcond_with guile
+%else
+# This gives the user the option of saying --without guile, but defaults to WITH
+%bcond_without guile
+%endif
+
+Patch0: make-4.3-getcwd.patch
+
+# Assume we don't have clock_gettime in configure, so that
+# make is not linked against -lpthread (and thus does not
+# limit stack to 2MB).
+Patch1: make-4.0-noclock_gettime.patch
+
+# BZs #142691, #17374
+Patch2: make-4.3-j8k.patch
+
+# https://bugzilla.redhat.com/show_bug.cgi?id=1827850
+# https://savannah.gnu.org/bugs/?58232
+# Remove on next make rebase
+Patch3: make-4.3-cloexec.patch
+
+# https://bugzilla.redhat.com/show_bug.cgi?id=2010506
+# https://savannah.gnu.org/bugs/?59093
+# Remove on next make rebase
+Patch4: make-4.3-filter-out.patch
+
+# autoreconf
+BuildRequires: make
+BuildRequires: autoconf, automake, gettext-devel
+BuildRequires: procps
+BuildRequires: perl
+%if %{with guile}
+BuildRequires: pkgconfig(guile-2.2)
+%endif
+BuildRequires: gcc
+
+%if "%{name}" != "make"
+# We're still on the make-latest package
+Requires: %{make}
+%description -n make-latest
+The latest GNU Make, with a version-specific install
+%files -n make-latest
+
+%package -n %{make}
+Summary: A GNU tool which simplifies the build process for users
+%endif
+
+%description -n %{make}
+A GNU tool for controlling the generation of executables and other
+non-source files of a program from the program's source files. Make
+allows users to build and install packages without any significant
+knowledge about the details of the build process. The details about
+how the program should be built are provided for make in the program's
+makefile.
+
+%package -n %{make}-devel
+Summary: Header file for externally visible definitions
+
+%description -n %{make}-devel
+The %{make}-devel package contains gnumake.h.
+
+%prep
+%autosetup -n make-%{version} -p1
+
+rm -f tests/scripts/features/parallelism.orig
+
+%build
+autoreconf -vfi
+
+%configure \
+%if %{with guile}
+    --with-guile
+%else
+    --without-guile
+%endif
+
+%make_build
+
+%install
+%make_install
+ln -sf make ${RPM_BUILD_ROOT}/%{_bindir}/gmake
+ln -sf make.1 ${RPM_BUILD_ROOT}/%{_mandir}/man1/gmake.1
+rm -f ${RPM_BUILD_ROOT}/%{_infodir}/dir
+
+%if "%{name}" != "make"
+install -d -m 755 ${RPM_BUILD_ROOT}/etc/scl/prefixes
+dirname %{_prefix} > %{make}.prefix
+install -p -m 644 %{make}.prefix ${RPM_BUILD_ROOT}/etc/scl/prefixes/%{make}
+
+echo "export PATH=%{_prefix}/bin:\$PATH" > enable.scl
+install -p -m 755 enable.scl ${RPM_BUILD_ROOT}/%{_prefix}/enable
+%endif
+
+%find_lang make
+
+%check
+echo ============TESTING===============
+/usr/bin/env LANG=C make check && true
+echo ============END TESTING===========
+
+%files -n %{make} -f make.lang
+%license COPYING
+%doc NEWS README AUTHORS
+%{_bindir}/*
+%{_mandir}/man*/*
+%{_infodir}/*.info*
+%{_includedir}/gnumake.h
+%if "%{name}" != "make"
+/etc/scl/prefixes/%{make}
+%{_prefix}/enable
+%endif
+
+%files -n %{make}-devel
+%{_includedir}/gnumake.h
+
+%changelog
+* Thu Jul 14 2022 DJ Delorie <dj@redhat.com> - 1:4.3-1
+Initial commit.