Extract jobserver implementation into OS-specific files.

* os.h, posixos.c, w32/w32os.c: New files implementing jobserver.
* job.c, job.h, main.c, makeint.h: Move content to new files.
* w32/include/sub_proc.h, w32/subproc/sub_proc.c: Ditto.
* Makefile.am: Build and package OS-specific files.
* build_w32.bat, make_msvc_net2003.vcproj, README.W32.template:
Update for new files, and clean up the build.
* POTFILES.in, maintMakefile, NMakefile.template: Ditto.
* w32/subproc/build.bat: Delete as unused.
diff --git a/.gitignore b/.gitignore
index 00cfa73..3990c55 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,6 +34,12 @@
 *.pdb
 *.sbr
 
+# Windows build artifacts
+/WinDebug/
+/WinRel/
+/GccDebug/
+/GccRel/
+
 # Distribution artifacts
 .dep_segment
 .check-git-HEAD
diff --git a/Makefile.am b/Makefile.am
index d0291d0..8c102a3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -41,14 +41,14 @@
 
 make_SOURCES =	ar.c arscan.c commands.c default.c dir.c expand.c file.c \
 		function.c getopt.c getopt1.c guile.c implicit.c job.c load.c \
-		loadapi.c main.c misc.c output.c read.c remake.c rule.c \
-		signame.c strcache.c variable.c version.c vpath.c hash.c \
-		$(remote)
+		loadapi.c main.c misc.c output.c posixos.c read.c remake.c \
+		rule.c signame.c strcache.c variable.c version.c vpath.c \
+		hash.c $(remote)
 
 EXTRA_make_SOURCES = vmsjobs.c remote-stub.c remote-cstms.c
 
 noinst_HEADERS = commands.h dep.h filedef.h job.h makeint.h rule.h variable.h \
-		debug.h getopt.h gettext.h hash.h output.h
+		debug.h getopt.h gettext.h hash.h output.h os.h
 
 make_LDADD =	@LIBOBJS@ @ALLOCA@ $(GLOBLIB) @GETLOADAVG_LIBS@ @LIBINTL@ \
 		$(GUILE_LIBS)
diff --git a/NMakefile.template b/NMakefile.template
index 511288f..2007a3b 100644
--- a/NMakefile.template
+++ b/NMakefile.template
@@ -107,6 +107,7 @@
 	$(OUTDIR)/dirent.obj \
 	$(OUTDIR)/pathstuff.obj \
 	$(OUTDIR)/posixfcn.obj \
+	$(OUTDIR)/w32os.obj \
 	$(guile)
 
 $(OUTDIR)/make.exe: $(OUTDIR) $(OBJS)
@@ -127,3 +128,5 @@
 	$(CC) $(CFLAGS) /c $?
 $(OUTDIR)/pathstuff.obj : w32/pathstuff.c
 	$(CC) $(CFLAGS) /c $?
+$(OUTDIR)/w32os.obj : w32/w32os.c
+	$(CC) $(CFLAGS) /c $?
diff --git a/README.W32.template b/README.W32.template
index d7fedb1..3ac3354 100644
--- a/README.W32.template
+++ b/README.W32.template
@@ -1,11 +1,12 @@
-This version of GNU make has been tested on
-Microsoft Windows 2000/XP/2003/Vista/7/2008.
+This version of GNU make has been tested on:
+  Microsoft Windows 2000/XP/2003/Vista/7/8/10
 It has also been used on Windows 95/98/NT, and on OS/2.
 
-It builds with the MinGW port of GCC (tested with GCC 3.4.2 and 4.8.1).
+It builds with the MinGW port of GCC (tested with GCC 3.4.2, 4.8.1,
+and 4.9.3).
 
-It also builds with MSVC 2.x, 4.x, 5.x, 6.x, and 2003 as well as
-with .NET 7.x and .NET 2003.
+It also builds with MSVC 2.x, 4.x, 5.x, 6.x, 2003, and 14 (2015) as
+well as with .NET 7.x and .NET 2003.
 
 As of version 4.0, a build with Guile is supported (tested with Guile
 2.0.3).  To build with Guile, you will need, in addition to Guile
@@ -25,8 +26,9 @@
 them.  A precompiled 32-bit Windows build of Guile is available from
 the ezwinports site mentioned above.
 
-The Windows 32-bit port of GNU make is maintained jointly by various
-people.  It was originally made by Rob Tulloh.
+The Windows port of GNU make is maintained jointly by various people.
+It was originally made by Rob Tulloh.
+It is currently maintained by Eli Zaretskii.
 
 
 Do this first, regardless of the build method you choose:
@@ -56,7 +58,9 @@
 
         build_w32.bat gcc
 
-    This produces gnumake.exe in the current directory.
+    This produces gnumake.exe in the GccRel directory.
+    If you want a version of GNU make built with debugging enabled,
+    add the --debug option.
 
     The batch file will probe for Guile installation, and will build
     gnumake.exe with Guile if it finds it.  If you have Guile
@@ -76,7 +80,9 @@
 
         build_w32.bat
 
-    (this produces WinDebug/gnumake.exe and WinRel/gnumake.exe)
+    This produces gnumake.exe in the WinRel directory.
+    If you want a version of GNU make built with debugging enabled,
+    add the --debug option.
 
     ... OR ...
 
diff --git a/build_w32.bat b/build_w32.bat
old mode 100644
new mode 100755
index f720776..bef80f9
--- a/build_w32.bat
+++ b/build_w32.bat
@@ -15,283 +15,217 @@
 rem You should have received a copy of the GNU General Public License along

 rem with this program.  If not, see <http://www.gnu.org/licenses/>.

 

-if "%1" == "-h" GoTo Usage

-if "%1" == "--help" GoTo Usage

-if not exist config.h.W32.template GoTo NotSCM

-sed -n "s/^AC_INIT(\[GNU make\],\[\([^]]\+\)\].*/s,%%VERSION%%,\1,g/p" configure.ac > config.h.W32.sed

-echo s,%%PACKAGE%%,make,g >> config.h.W32.sed

-sed -f config.h.W32.sed config.h.W32.template > config.h.W32

-echo static const char *const GUILE_module_defn = ^" \> gmk-default.h

-sed -e "s/;.*//" -e "/^[ \t]*$/d" -e "s/\"/\\\\\"/g" -e "s/$/ \\/" gmk-default.scm >> gmk-default.h

-echo ^";>> gmk-default.h

-:NotSCM

-copy config.h.W32 config.h

+call :Reset

 

-rem Guile configuration

-set GUILECFLAGS=

-set GUILELIBS=

-set NOGUILE=

-set OPT=-O2

-set COMPILER=

-set PKGMSC=

+if "%1" == "-h" goto Usage

+if "%1" == "--help" goto Usage

+

+set MAKE=gnumake

+set GUILE=Y

+set COMPILER=msvc

+

 :ParseSW

-if "%1" == "--debug" GoTo SetOpt

-if "%1" == "--without-guile" GoTo NoGuile

-if "%1" == "gcc" GoTo SetCC

-if "%1" == "" GoTo ChkGuile

-:SetOpt

-set OPT=-O0

+if "%1" == "--debug" goto SetDebug

+if "%1" == "--without-guile" goto NoGuile

+if "%1" == "gcc" goto SetCC

+if "%1" == "" goto DoneSW

+

+:SetDebug

+set DEBUG=Y

 shift

-GoTo ParseSW

+goto ParseSW

+

 :NoGuile

-set NOGUILE=Y

-echo "Building without Guile"

+set GUILE=N

+echo Building without Guile

 shift

-GoTo ParseSW

+goto ParseSW

+

 :SetCC

 set COMPILER=gcc

-echo "Building with GCC"

+echo Building with GCC

 shift

-GoTo ParseSW

-rem Build with Guile is supported only on NT and later versions

-:ChkGuile

-if "%NOGUILE%" == "Y" GoTo GuileDone

-if not "%OS%" == "Windows_NT" GoTo NoGuile

-pkg-config --help > guile.tmp 2> NUL

-if ERRORLEVEL 1 GoTo NoPkgCfg

-echo "Checking for Guile 2.0"

-if not "%COMPILER%" == "gcc" set PKGMSC=--msvc-syntax

-pkg-config --cflags --short-errors "guile-2.0" > guile.tmp

-if not ERRORLEVEL 1 set /P GUILECFLAGS= < guile.tmp

-pkg-config --libs --static --short-errors %PKGMSC% "guile-2.0" > guile.tmp

-if not ERRORLEVEL 1 set /P GUILELIBS= < guile.tmp

-if not "%GUILECFLAGS%" == "" GoTo GuileDone

-echo "Checking for Guile 1.8"

-pkg-config --cflags --short-errors "guile-1.8" > guile.tmp

-if not ERRORLEVEL 1 set /P GUILECFLAGS= < guile.tmp

-pkg-config --libs --static --short-errors %PKGMSC% "guile-1.8" > guile.tmp

-if not ERRORLEVEL 1 set /P GUILELIBS= < guile.tmp

-if not "%GUILECFLAGS%" == "" GoTo GuileDone

-echo "No Guile found, building without Guile"

-GoTo GuileDone

-:NoPkgCfg

-echo "pkg-config not found, building without Guile"

-:GuileDone

-if not "%GUILECFLAGS%" == "" echo "Guile found, building with Guile"

-if not "%GUILECFLAGS%" == "" set GUILECFLAGS=%GUILECFLAGS% -DHAVE_GUILE

-if "%COMPILER%" == "gcc" if "%OPT%" == "-O0" echo "Building without compiler optimizations"

-cd w32\subproc

-echo.

-echo "Creating the subproc library"

-%ComSpec% /c build.bat

-cd ..\..

+goto ParseSW

 

-if exist link.dbg del link.dbg

-if exist link.rel del link.rel

+rem Build with Guile is supported only on NT and later versions

+:DoneSW

 echo.

-echo "Creating GNU Make for Windows 9X/NT/2K/XP/Vista/7/8"

-if "%COMPILER%" == "gcc" GoTo GCCBuild

-set make=gnumake

+echo Creating GNU Make for Windows 9X/NT/2K/XP/Vista/7/8

+if "%DEBUG%" == "Y" echo Building without compiler optimizations

+

+if "%COMPILER%" == "gcc" goto GccBuild

+

+set OUTDIR=.\WinRel

+set "OPTS=/O2 /D NDEBUG"

+set LINKOPTS=

+if "%DEBUG%" == "Y" set OUTDIR=.\WinDebug

+if "%DEBUG%" == "Y" set "OPTS=/Zi /Od /D _DEBUG"

+if "%DEBUG%" == "Y" set LINKOPTS=/DEBUG

+call :Build

+goto Done

+

+:GccBuild

+set OUTDIR=.\GccRel

+set OPTS=-O2

+if "%DEBUG%" == "Y" set OPTS=-O0

+if "%DEBUG%" == "Y" set OUTDIR=.\GccDebug

+call :Build

+goto Done

+

+:Done

+call :Reset

+goto :EOF

+

+:Build

+:: Clean the directory if it exists

+if exist %OUTDIR%\nul rmdir /S /Q %OUTDIR%

+

+:: Recreate it

+mkdir %OUTDIR%

+mkdir %OUTDIR%\glob

+mkdir %OUTDIR%\w32

+mkdir %OUTDIR%\w32\compat

+mkdir %OUTDIR%\w32\subproc

+

+if "%GUILE%" == "Y" call :ChkGuile

+

+echo.

+echo Compiling %OUTDIR% version

+

+if exist config.h.W32.template call :ConfigSCM

+copy config.h.W32 %OUTDIR%\config.h

+

+call :Compile ar

+call :Compile arscan

+call :Compile commands

+call :Compile default

+call :Compile dir

+call :Compile expand

+call :Compile file

+call :Compile function

+call :Compile getloadavg

+call :Compile getopt

+call :Compile getopt1

+call :Compile glob\fnmatch

+call :Compile glob\glob

+call :Compile guile GUILE

+call :Compile hash

+call :Compile implicit

+call :Compile job

+call :Compile load

+call :Compile loadapi

+call :Compile main GUILE

+call :Compile misc

+call :Compile output

+call :Compile read

+call :Compile remake

+call :Compile remote-stub

+call :Compile rule

+call :Compile signame

+call :Compile strcache

+call :Compile variable

+call :Compile version

+call :Compile vpath

+call :Compile w32\compat\posixfcn

+call :Compile w32\pathstuff

+call :Compile w32\subproc\misc

+call :Compile w32\subproc\sub_proc

+call :Compile w32\subproc\w32err

+call :Compile w32\w32os

+

+if not "%COMPILER%" == "gcc" call :Compile w32\compat\dirent

+

+call :Link

+

+echo.

+if not exist %OUTDIR%\%MAKE%.exe echo %OUTDIR% build FAILED!

+if exist %OUTDIR%\%MAKE%.exe echo %OUTDIR% build succeeded.

+goto :EOF

+

+:Compile

+set EXTRAS=

+if "%2" == "GUILE" set "EXTRAS=%GUILECFLAGS%"

+if "%COMPILER%" == "gcc" goto GccCompile

+

+:: MSVC Compile

 echo on

-if not exist .\WinDebug\nul mkdir .\WinDebug

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D TIVOLI /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c variable.c

-echo WinDebug\variable.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c rule.c

-echo WinDebug\rule.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c remote-stub.c

-echo WinDebug\remote-stub.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c commands.c

-echo WinDebug\commands.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c file.c

-echo WinDebug\file.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c getloadavg.c

-echo WinDebug\getloadavg.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c default.c

-echo WinDebug\default.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c signame.c

-echo WinDebug\signame.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c expand.c

-echo WinDebug\expand.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c dir.c

-echo WinDebug\dir.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od %GUILECFLAGS% /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c main.c

-echo WinDebug\main.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c getopt1.c

-echo WinDebug\getopt1.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c job.c

-echo WinDebug\job.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c output.c

-echo WinDebug\output.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c read.c

-echo WinDebug\read.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c version.c

-echo WinDebug\version.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c getopt.c

-echo WinDebug\getopt.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c arscan.c

-echo WinDebug\arscan.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c hash.c

-echo WinDebug\hash.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c strcache.c

-echo WinDebug\strcache.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c remake.c

-echo WinDebug\remake.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c misc.c

-echo WinDebug\misc.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c ar.c

-echo WinDebug\ar.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c function.c

-echo WinDebug\function.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c vpath.c

-echo WinDebug\vpath.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c implicit.c

-echo WinDebug\implicit.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c loadapi.c

-echo WinDebug\loadapi.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c load.c

-echo WinDebug\load.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c  .\w32\compat\dirent.c

-echo WinDebug\dirent.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c  .\w32\compat\posixfcn.c

-echo WinDebug\posixfcn.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c  .\glob\glob.c

-echo WinDebug\glob.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c  .\glob\fnmatch.c

-echo WinDebug\fnmatch.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c  .\w32\pathstuff.c

-echo WinDebug\pathstuff.obj >>link.dbg

-cl.exe /nologo /MT /W4 /GX /Zi /YX /Od %GUILECFLAGS% /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c guile.c

-echo WinDebug\guile.obj >>link.dbg

-:LinkDbg

-echo off

-echo "Linking WinDebug/%make%.exe"

-rem link.exe %GUILELIBS% kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib w32\subproc\windebug\subproc.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes /PDB:.\WinDebug/%make%.pdb /DEBUG /OUT:.\WinDebug/%make%.exe .\WinDebug/variable.obj  .\WinDebug/rule.obj  .\WinDebug/remote-stub.obj  .\WinDebug/commands.obj  .\WinDebug/file.obj  .\WinDebug/getloadavg.obj  .\WinDebug/default.obj  .\WinDebug/signame.obj  .\WinDebug/expand.obj  .\WinDebug/dir.obj  .\WinDebug/main.obj  .\WinDebug/getopt1.obj  .\WinDebug/job.obj  .\WinDebug/output.obj  .\WinDebug/read.obj  .\WinDebug/version.obj  .\WinDebug/getopt.obj  .\WinDebug/arscan.obj  .\WinDebug/remake.obj  .\WinDebug/hash.obj  .\WinDebug/strcache.obj  .\WinDebug/misc.obj  .\WinDebug/ar.obj  .\WinDebug/function.obj  .\WinDebug/vpath.obj  .\WinDebug/implicit.obj  .\WinDebug/dirent.obj  .\WinDebug/glob.obj  .\WinDebug/fnmatch.obj  .\WinDebug/pathstuff.obj

-echo %GUILELIBS% kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib w32\subproc\windebug\subproc.lib >>link.dbg

-link.exe /NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes /PDB:.\WinDebug/%make%.pdb /DEBUG /OUT:.\WinDebug/%make%.exe @link.dbg

-if not exist .\WinDebug/%make%.exe echo "WinDebug build failed"

-if exist .\WinDebug/%make%.exe echo "WinDebug build succeeded!"

-if not exist .\WinRel\nul mkdir .\WinRel

-echo on

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D TIVOLI /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c variable.c

-echo WinRel\variable.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c rule.c

-echo WinRel\rule.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c remote-stub.c

-echo WinRel\remote-stub.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c commands.c

-echo WinRel\commands.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c file.c

-echo WinRel\file.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c getloadavg.c

-echo WinRel\getloadavg.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c default.c

-echo WinRel\default.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c signame.c

-echo WinRel\signame.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c expand.c

-echo WinRel\expand.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c dir.c

-echo WinRel\dir.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 %GUILECFLAGS% /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c main.c

-echo WinRel\main.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c getopt1.c

-echo WinRel\getopt1.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c job.c

-echo WinRel\job.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c output.c

-echo WinRel\output.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c read.c

-echo WinRel\read.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c version.c

-echo WinRel\version.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c getopt.c

-echo WinRel\getopt.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c arscan.c

-echo WinRel\arscan.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c remake.c

-echo WinRel\remake.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c hash.c

-echo WinRel\hash.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c strcache.c

-echo WinRel\strcache.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c misc.c

-echo WinRel\misc.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c ar.c

-echo WinRel\ar.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c function.c

-echo WinRel\function.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c vpath.c

-echo WinRel\vpath.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c implicit.c

-echo WinRel\implicit.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c loadapi.c

-echo WinRel\loadapi.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c load.c

-echo WinRel\load.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c  .\w32\compat\dirent.c

-echo WinRel\dirent.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c  .\w32\compat\posixfcn.c

-echo WinRel\posixfcn.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c  .\glob\glob.c

-echo WinRel\glob.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c  .\glob\fnmatch.c

-echo WinRel\fnmatch.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c  .\w32\pathstuff.c

-echo WinRel\pathstuff.obj >>link.rel

-cl.exe /nologo /MT /W4 /GX /YX /O2 %GUILECFLAGS% /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c guile.c

-echo WinRel\guile.obj >>link.rel

-:LinkRel

-echo off

-echo "Linking WinRel/%make%.exe"

-rem link.exe %GUILELIBS% kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib w32\subproc\winrel\subproc.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:no /PDB:.\WinRel/%make%.pdb /OUT:.\WinRel/%make%.exe .\WinRel/variable.obj  .\WinRel/rule.obj  .\WinRel/remote-stub.obj  .\WinRel/commands.obj  .\WinRel/file.obj  .\WinRel/getloadavg.obj  .\WinRel/default.obj  .\WinRel/signame.obj  .\WinRel/expand.obj  .\WinRel/dir.obj  .\WinRel/main.obj  .\WinRel/getopt1.obj  .\WinRel/job.obj  .\WinRel/output.obj  .\WinRel/read.obj  .\WinRel/version.obj  .\WinRel/getopt.obj  .\WinRel/arscan.obj  .\WinRel/remake.obj  .\WinRel/misc.obj  .\WinRel/hash.obj  .\WinRel/strcache.obj  .\WinRel/ar.obj  .\WinRel/function.obj  .\WinRel/vpath.obj  .\WinRel/implicit.obj  .\WinRel/dirent.obj  .\WinRel/glob.obj  .\WinRel/fnmatch.obj  .\WinRel/pathstuff.obj

-echo %GUILELIBS% kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib w32\subproc\winrel\subproc.lib >>link.rel

-link.exe /NOLOGO /SUBSYSTEM:console /INCREMENTAL:no /PDB:.\WinRel/%make%.pdb /OUT:.\WinRel/%make%.exe @link.rel

-if not exist .\WinRel/%make%.exe echo "WinRel build failed"

-if exist .\WinRel/%make%.exe echo "WinRel build succeeded!"

-set make=

-GoTo BuildEnd

-:GCCBuild

-echo on

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c variable.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c rule.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c remote-stub.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c commands.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c file.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c getloadavg.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c default.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c signame.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c expand.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c dir.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H %GUILECFLAGS% -c main.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c getopt1.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c job.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c output.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c read.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c version.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c getopt.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c arscan.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c remake.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c hash.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c strcache.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c misc.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c ar.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c function.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c vpath.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c implicit.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c loadapi.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c load.c

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c ./glob/glob.c -o glob.o

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c ./glob/fnmatch.c -o fnmatch.o

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c ./w32/pathstuff.c -o pathstuff.o

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c ./w32/compat/posixfcn.c -o posixfcn.o

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% %GUILECFLAGS% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c guile.c

-:LinkGCC

+cl.exe /nologo /MT /W4 /GX /YX %OPTS% /I %OUTDIR% /I . /I glob /I w32/include /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR%OUTDIR% /Fp%OUTDIR%\%MAKE%.pch /Fo%OUTDIR%\%1.obj /Fd%OUTDIR%\%MAKE%.pdb %EXTRAS% /c %1.c

 @echo off

-Rem The version NN of libgnumake-NN.dll.a should be bumped whenever

-Rem the API changes in binary-incompatible manner.

-@echo on

-gcc -mthreads -gdwarf-2 -g3 -o gnumake.exe variable.o rule.o remote-stub.o commands.o file.o getloadavg.o default.o signame.o expand.o dir.o main.o getopt1.o guile.o job.o output.o read.o version.o getopt.o arscan.o remake.o misc.o hash.o strcache.o ar.o function.o vpath.o implicit.o loadapi.o load.o glob.o fnmatch.o pathstuff.o posixfcn.o w32_misc.o sub_proc.o w32err.o %GUILELIBS% -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -Wl,--out-implib=libgnumake-1.dll.a

-@GoTo BuildEnd

+echo %OUTDIR%\%1.obj >>%OUTDIR%\link.sc

+goto :EOF

+

+:GccCompile

+:: GCC Compile

+echo on

+gcc -mthreads -Wall -gdwarf-2 -g3 %OPTS% -I%OUTDIR% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H %EXTRAS% -o %OUTDIR%\%1.o -c %1.c

+@echo off

+goto :EOF

+

+:Link

+echo Linking %OUTDIR%/%MAKE%.exe

+if "%COMPILER%" == "gcc" goto GccLink

+

+:: MSVC Link

+echo %GUILELIBS% kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib >>%OUTDIR%\link.sc

+echo on

+link.exe /NOLOGO /SUBSYSTEM:console /PDB:%OUTDIR%\%MAKE%.pdb %LINKOPTS% /OUT:%OUTDIR%\%MAKE%.exe @%OUTDIR%\link.sc

+@echo off

+goto :EOF

+

+:GccLink

+:: GCC Link

+echo on

+gcc -mthreads -gdwarf-2 -g3 -o %OUTDIR%\%MAKE%.exe %OUTDIR%\variable.o %OUTDIR%\rule.o %OUTDIR%\remote-stub.o %OUTDIR%\commands.o %OUTDIR%\file.o %OUTDIR%\getloadavg.o %OUTDIR%\default.o %OUTDIR%\signame.o %OUTDIR%\expand.o %OUTDIR%\dir.o %OUTDIR%\main.o %OUTDIR%\getopt1.o %OUTDIR%\guile.o %OUTDIR%\job.o %OUTDIR%\output.o %OUTDIR%\read.o %OUTDIR%\version.o %OUTDIR%\getopt.o %OUTDIR%\arscan.o %OUTDIR%\remake.o %OUTDIR%\misc.o %OUTDIR%\hash.o %OUTDIR%\strcache.o %OUTDIR%\ar.o %OUTDIR%\function.o %OUTDIR%\vpath.o %OUTDIR%\implicit.o %OUTDIR%\loadapi.o %OUTDIR%\load.o %OUTDIR%\glob\glob.o %OUTDIR%\glob\fnmatch.o %OUTDIR%\w32\pathstuff.o %OUTDIR%\w32\compat\posixfcn.o %OUTDIR%\w32\w32os.o %OUTDIR%\w32\subproc\misc.o %OUTDIR%\w32\subproc\sub_proc.o %OUTDIR%\w32\subproc\w32err.o %GUILELIBS% -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -Wl,--out-implib=%OUTDIR%\libgnumake-1.dll.a

+@echo off

+goto :EOF

+

+:ConfigSCM

+echo Generating config from SCM templates

+sed -n "s/^AC_INIT(\[GNU make\],\[\([^]]\+\)\].*/s,%%VERSION%%,\1,g/p" configure.ac > %OUTDIR%\config.h.W32.sed

+echo s,%%PACKAGE%%,make,g >> %OUTDIR%\config.h.W32.sed

+sed -f %OUTDIR%\config.h.W32.sed config.h.W32.template > config.h.W32

+echo static const char *const GUILE_module_defn = ^" \> gmk-default.h

+sed -e "s/;.*//" -e "/^[ \t]*$/d" -e "s/\"/\\\\\"/g" -e "s/$/ \\\/" gmk-default.scm >> gmk-default.h

+echo ^";>> gmk-default.h

+goto :EOF

+

+:ChkGuile

+if not "%OS%" == "Windows_NT" goto NoGuile

+pkg-config --help > %OUTDIR%\guile.tmp 2> NUL

+if ERRORLEVEL 1 goto NoPkgCfg

+

+echo Checking for Guile 2.0

+if not "%COMPILER%" == "gcc" set PKGMSC=--msvc-syntax

+pkg-config --cflags --short-errors "guile-2.0" > %OUTDIR%\guile.tmp

+if not ERRORLEVEL 1 set /P GUILECFLAGS= < %OUTDIR%\guile.tmp

+

+pkg-config --libs --static --short-errors %PKGMSC% "guile-2.0" > %OUTDIR%\guile.tmp

+if not ERRORLEVEL 1 set /P GUILELIBS= < %OUTDIR%\guile.tmp

+

+if not "%GUILECFLAGS%" == "" goto GuileDone

+

+echo Checking for Guile 1.8

+pkg-config --cflags --short-errors "guile-1.8" > %OUTDIR%\guile.tmp

+if not ERRORLEVEL 1 set /P GUILECFLAGS= < %OUTDIR%\guile.tmp

+

+pkg-config --libs --static --short-errors %PKGMSC% "guile-1.8" > %OUTDIR%\guile.tmp

+if not ERRORLEVEL 1 set /P GUILELIBS= < %OUTDIR%\guile.tmp

+

+if not "%GUILECFLAGS%" == "" goto GuileDone

+

+echo No Guile found, building without Guile

+goto GuileDone

+

+:NoPkgCfg

+echo pkg-config not found, building without Guile

+

+:GuileDone

+if "%GUILECFLAGS%" == "" goto :EOF

+

+echo Guile found, building with Guile

+set "GUILECFLAGS=%GUILECFLAGS% -DHAVE_GUILE"

+goto :EOF

+

 :Usage

 echo Usage: %0 [options] [gcc]

 echo Options:

@@ -299,12 +233,18 @@
 echo.                    (MSVC build always makes both debug and release)

 echo.  --without-guile   Do not compile Guile support even if found

 echo.  --help            Display these instructions and exit

-:BuildEnd

-@echo off

-set GUILELIBS=

-set GUILECFLAGS=

-set PKGMSC=

-set OPT=

+goto :EOF

+

+:Reset

 set COMPILER=

+set DEBUG=

+set GUILE=

+set GUILECFLAGS=

+set GUILELIBS=

+set LINKOPTS=

+set MAKE=

 set NOGUILE=

-echo on

+set OPTS=

+set OUTDIR=

+set PKGMSC=

+goto :EOF

diff --git a/job.c b/job.c
index 7717b26..321a1e8 100644
--- a/job.c
+++ b/job.c
@@ -23,6 +23,7 @@
 #include "filedef.h"
 #include "commands.h"
 #include "variable.h"
+#include "os.h"
 #include "debug.h"
 
 #include <string.h>
@@ -541,11 +542,7 @@
 {
   ++dead_children;
 
-  if (job_rfd >= 0)
-    {
-      close (job_rfd);
-      job_rfd = -1;
-    }
+  jobserver_signal ();
 
 #ifdef __EMX__
   /* The signal handler must called only once! */
@@ -1012,35 +1009,12 @@
   /* If we're using the jobserver and this child is not the only outstanding
      job, put a token back into the pipe for it.  */
 
-#ifdef WINDOWS32
-  if (has_jobserver_semaphore () && jobserver_tokens > 1)
+  if (jobserver_enabled () && jobserver_tokens > 1)
     {
-      if (! release_jobserver_semaphore ())
-        {
-          DWORD err = GetLastError ();
-          const char *estr = map_windows32_error_to_string (err);
-          ONS (fatal, NILF,
-               _("release jobserver semaphore: (Error %ld: %s)"), err, estr);
-        }
-
-      DB (DB_JOBS, (_("Released token for child %p (%s).\n"), child, child->file->name));
-    }
-#else
-  if (job_fds[1] >= 0 && jobserver_tokens > 1)
-    {
-      char token = '+';
-      int r;
-
-      /* Write a job token back to the pipe.  */
-
-      EINTRLOOP (r, write (job_fds[1], &token, 1));
-      if (r != 1)
-        pfatal_with_name (_("write jobserver"));
-
+      jobserver_release (1);
       DB (DB_JOBS, (_("Released token for child %p (%s).\n"),
                     child, child->file->name));
     }
-#endif
 
   --jobserver_tokens;
 
@@ -1092,60 +1066,6 @@
 }
 #endif
 
-#if defined(MAKE_JOBSERVER) && !defined(WINDOWS32)
-RETSIGTYPE
-job_noop (int sig UNUSED)
-{
-}
-/* Set the child handler action flags to FLAGS.  */
-static void
-set_child_handler_action_flags (int set_handler, int set_alarm)
-{
-  struct sigaction sa;
-
-#ifdef __EMX__
-  /* The child handler must be turned off here.  */
-  signal (SIGCHLD, SIG_DFL);
-#endif
-
-  memset (&sa, '\0', sizeof sa);
-  sa.sa_handler = child_handler;
-  sa.sa_flags = set_handler ? 0 : SA_RESTART;
-#if defined SIGCHLD
-  if (sigaction (SIGCHLD, &sa, NULL) < 0)
-    pfatal_with_name ("sigaction: SIGCHLD");
-#endif
-#if defined SIGCLD && SIGCLD != SIGCHLD
-  if (sigaction (SIGCLD, &sa, NULL) < 0)
-    pfatal_with_name ("sigaction: SIGCLD");
-#endif
-#if defined SIGALRM
-  if (set_alarm)
-    {
-      /* If we're about to enter the read(), set an alarm to wake up in a
-         second so we can check if the load has dropped and we can start more
-         work.  On the way out, turn off the alarm and set SIG_DFL.  */
-      if (set_handler)
-        {
-          sa.sa_handler = job_noop;
-          sa.sa_flags = 0;
-          if (sigaction (SIGALRM, &sa, NULL) < 0)
-            pfatal_with_name ("sigaction: SIGALRM");
-          alarm (1);
-        }
-      else
-        {
-          alarm (0);
-          sa.sa_handler = SIG_DFL;
-          sa.sa_flags = 0;
-          if (sigaction (SIGALRM, &sa, NULL) < 0)
-            pfatal_with_name ("sigaction: SIGALRM");
-        }
-    }
-#endif
-}
-#endif
-
 
 /* Start a job to run the commands specified in CHILD.
    CHILD is updated to reflect the commands and ID of the child process.
@@ -1516,13 +1436,8 @@
 # ifdef __EMX__
       /* If we aren't running a recursive command and we have a jobserver
          pipe, close it before exec'ing.  */
-      if (!(flags & COMMANDS_RECURSE) && job_fds[0] >= 0)
-        {
-          CLOSE_ON_EXEC (job_fds[0]);
-          CLOSE_ON_EXEC (job_fds[1]);
-        }
-      if (job_rfd >= 0)
-        CLOSE_ON_EXEC (job_rfd);
+      if (!(flags & COMMANDS_RECURSE) && jobserver_enabled ())
+        jobserver_pre_child ();
 
       /* Never use fork()/exec() here! Use spawn() instead in exec_command() */
       child->pid = child_execute_job (child->good_stdin ? FD_STDIN : bad_stdin,
@@ -1537,13 +1452,8 @@
         }
 
       /* undo CLOSE_ON_EXEC() after the child process has been started */
-      if (!(flags & COMMANDS_RECURSE) && job_fds[0] >= 0)
-        {
-          fcntl (job_fds[0], F_SETFD, 0);
-          fcntl (job_fds[1], F_SETFD, 0);
-        }
-      if (job_rfd >= 0)
-        fcntl (job_rfd, F_SETFD, 0);
+      if (!(flags & COMMANDS_RECURSE) && jobserver_enabled ())
+        jobserver_post_child ();
 
 #else  /* !__EMX__ */
 
@@ -1554,15 +1464,10 @@
           /* We are the child side.  */
           unblock_sigs ();
 
-          /* If we aren't running a recursive command and we have a jobserver
-             pipe, close it before exec'ing.  */
-          if (!(flags & COMMANDS_RECURSE) && job_fds[0] >= 0)
-            {
-              close (job_fds[0]);
-              close (job_fds[1]);
-            }
-          if (job_rfd >= 0)
-            close (job_rfd);
+          /* If we AREN'T running a recursive command and we have a jobserver,
+             clear it before exec'ing.  */
+          if (!(flags & COMMANDS_RECURSE) && jobserver_enabled ())
+            jobserver_clear ();
 
 #ifdef SET_STACK_SIZE
           /* Reset limits, if necessary.  */
@@ -1952,18 +1857,10 @@
      just once).  Also more thought needs to go into the entire algorithm;
      this is where the old parallel job code waits, so...  */
 
-#ifdef WINDOWS32
-  else if (has_jobserver_semaphore ())
-#else
-  else if (job_fds[0] >= 0)
-#endif
+  else if (jobserver_enabled ())
     while (1)
       {
         int got_token;
-#ifndef WINDOWS32
-        char token;
-        int saved_errno;
-#endif
 
         DB (DB_JOBS, ("Need a job token; we %shave children\n",
                       children ? "" : "don't "));
@@ -1972,36 +1869,8 @@
         if (!jobserver_tokens)
           break;
 
-#ifndef WINDOWS32
-        /* Read a token.  As long as there's no token available we'll block.
-           We enable interruptible system calls before the read(2) so that if
-           we get a SIGCHLD while we're waiting, we'll return with EINTR and
-           we can process the death(s) and return tokens to the free pool.
-
-           Once we return from the read, we immediately reinstate restartable
-           system calls.  This allows us to not worry about checking for
-           EINTR on all the other system calls in the program.
-
-           There is one other twist: there is a span between the time
-           reap_children() does its last check for dead children and the time
-           the read(2) call is entered, below, where if a child dies we won't
-           notice.  This is extremely serious as it could cause us to
-           deadlock, given the right set of events.
-
-           To avoid this, we do the following: before we reap_children(), we
-           dup(2) the read FD on the jobserver pipe.  The read(2) call below
-           uses that new FD.  In the signal handler, we close that FD.  That
-           way, if a child dies during the section mentioned above, the
-           read(2) will be invoked with an invalid FD and will return
-           immediately with EBADF.  */
-
-        /* Make sure we have a dup'd FD.  */
-        if (job_rfd < 0)
-          {
-            DB (DB_JOBS, ("Duplicate the job FD\n"));
-            EINTRLOOP (job_rfd, dup (job_fds[0]));
-          }
-#endif
+        /* Prepare for jobserver token acquisition.  */
+        jobserver_pre_acquire ();
 
         /* Reap anything that's currently waiting.  */
         reap_children (0, 0);
@@ -2010,8 +1879,7 @@
            can run now (i.e., waiting for load). */
         start_waiting_jobs ();
 
-        /* If our "free" slot has become available, use it; we don't need an
-           actual token.  */
+        /* If our "free" slot is available, use it; we don't need a token.  */
         if (!jobserver_tokens)
           break;
 
@@ -2020,26 +1888,8 @@
         if (!children)
           O (fatal, NILF, "INTERNAL: no children as we go to sleep on read\n");
 
-#ifdef WINDOWS32
-        /* On Windows we simply wait for the jobserver semaphore to become
-         * signalled or one of our child processes to terminate.
-         */
-        got_token = wait_for_semaphore_or_child_process ();
-        if (got_token < 0)
-          {
-            DWORD err = GetLastError ();
-            const char *estr = map_windows32_error_to_string (err);
-            ONS (fatal, NILF,
-                 _("semaphore or child process wait: (Error %ld: %s)"),
-                 err, estr);
-          }
-#else
-        /* Set interruptible system calls, and read() for a job token.  */
-        set_child_handler_action_flags (1, waiting_jobs != NULL);
-        EINTRLOOP (got_token, read (job_rfd, &token, 1));
-        saved_errno = errno;
-        set_child_handler_action_flags (0, waiting_jobs != NULL);
-#endif
+        /* Get a token.  */
+        got_token = jobserver_acquire (waiting_jobs != NULL);
 
         /* If we got one, we're done here.  */
         if (got_token == 1)
@@ -2048,16 +1898,6 @@
                           c, c->file->name));
             break;
           }
-
-#ifndef WINDOWS32
-        /* If the error _wasn't_ expected (EINTR or EBADF), punt.  Otherwise,
-           go back and reap_children(), and try again.  */
-        errno = saved_errno;
-        if (errno != EINTR && errno != EBADF)
-          pfatal_with_name (_("read jobs pipe"));
-        if (errno == EBADF)
-          DB (DB_JOBS, ("Read returned EBADF.\n"));
-#endif
       }
 #endif
 
diff --git a/job.h b/job.h
index 0beff73..4d7f53f 100644
--- a/job.h
+++ b/job.h
@@ -115,6 +115,8 @@
 
 extern struct child *children;
 
+/* A signal handler for SIGCHLD, if needed.  */
+RETSIGTYPE child_handler (int sig);
 int is_bourne_compatible_shell(const char *path);
 void new_job (struct file *file);
 void reap_children (int block, int err);
diff --git a/main.c b/main.c
index df5540a..8b3dcfa 100644
--- a/main.c
+++ b/main.c
@@ -15,6 +15,7 @@
 this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "makeint.h"
+#include "os.h"
 #include "filedef.h"
 #include "dep.h"
 #include "variable.h"
@@ -270,15 +271,12 @@
 
 /* File descriptors for the jobs pipe.  */
 
-char *jobserver_fds = 0;
-
-int job_fds[2] = { -1, -1 };
-int job_rfd = -1;
+char *jobserver_fds = NULL;
 
 /* Handle for the mutex used on Windows to synchronize output of our
    children under -O.  */
 
-char *sync_mutex = 0;
+char *sync_mutex = NULL;
 
 /* Maximum load average at which multiple jobs will be run.
    Negative values mean unlimited, while zero means limit to
@@ -600,7 +598,7 @@
 
 /* Mask of signals that are being caught with fatal_error_signal.  */
 
-#ifdef  POSIX
+#ifdef POSIX
 sigset_t fatal_signal_set;
 #else
 # ifdef HAVE_SIGSETMASK
@@ -1597,85 +1595,33 @@
   starting_directory = current_directory;
 
 #ifdef MAKE_JOBSERVER
-  /* If the jobserver-fds option is seen, make sure that -j is reasonable.
+  /* If the jobserver_fds option is seen, make sure that -j is reasonable.
      This can't be usefully set in the makefile, and we want to verify the
      FDs are valid before any other aspect of make has a chance to start
      using them for something else.  */
 
   if (jobserver_fds)
     {
-      /* Make sure the jobserver option has the proper format.  */
-      const char *cp = jobserver_fds;
-
-#ifdef WINDOWS32
-      if (! open_jobserver_semaphore (cp))
-        {
-          DWORD err = GetLastError ();
-          const char *estr = map_windows32_error_to_string (err);
-          fatal (NILF, strlen (cp) + INTSTR_LENGTH + strlen (estr),
-                 _("internal error: unable to open jobserver semaphore '%s': (Error %ld: %s)"),
-                 cp, err, estr);
-        }
-      DB (DB_JOBS, (_("Jobserver client (semaphore %s)\n"), cp));
-#else
-      if (sscanf (cp, "%d,%d", &job_fds[0], &job_fds[1]) != 2)
-        OS (fatal, NILF,
-            _("internal error: invalid --jobserver-fds string '%s'"), cp);
-
-      DB (DB_JOBS,
-          (_("Jobserver client (fds %d,%d)\n"), job_fds[0], job_fds[1]));
-#endif
-
-      /* The combination of a pipe + !job_slots means we're using the
-         jobserver.  If !job_slots and we don't have a pipe, we can start
-         infinite jobs.  If we see both a pipe and job_slots >0 that means the
+      /* The combination of jobserver_fds and !job_slots means we're using the
+         jobserver.  If !job_slots and no jobserver_fds, we can start infinite
+         jobs.  If we see both jobserver_fds and job_slots >0 that means the
          user set -j explicitly.  This is broken; in this case obey the user
-         (ignore the jobserver pipe for this make) but print a message.
-         If we've restarted, we already printed this the first time.  */
+         (ignore the jobserver for this make) but print a message.  If we've
+         restarted, we already printed this the first time.  */
+
+      if (!job_slots)
+        jobserver_parse_arg (jobserver_fds);
+
+      else if (! restarts)
+        O (error, NILF,
+           _("warning: -jN forced in submake: disabling jobserver mode."));
 
       if (job_slots > 0)
         {
-          if (! restarts)
-            O (error, NILF,
-               _("warning: -jN forced in submake: disabling jobserver mode."));
-        }
-#ifndef WINDOWS32
-#ifdef HAVE_FCNTL
-# define FD_OK(_f) ((fcntl ((_f), F_GETFD) != -1) || (errno != EBADF))
-#else
-# define FD_OK(_f) 1
-#endif
-      /* Create a duplicate pipe, that will be closed in the SIGCHLD
-         handler.  If this fails with EBADF, the parent has closed the pipe
-         on us because it didn't think we were a submake.  If so, print a
-         warning then default to -j1.  */
-      else if (!FD_OK (job_fds[0]) || !FD_OK (job_fds[1])
-               || (job_rfd = dup (job_fds[0])) < 0)
-        {
-          if (errno != EBADF)
-            pfatal_with_name (_("dup jobserver"));
-
-          O (error, NILF,
-             _("warning: jobserver unavailable: using -j1.  Add '+' to parent make rule."));
-          job_slots = 1;
-          job_fds[0] = job_fds[1] = -1;
-        }
-#endif
-
-      if (job_slots > 0)
-        {
-#ifdef WINDOWS32
-          free_jobserver_semaphore ();
-#else
-          if (job_fds[0] >= 0)
-            close (job_fds[0]);
-          if (job_fds[1] >= 0)
-            close (job_fds[1]);
-#endif
-          job_fds[0] = job_fds[1] = -1;
-
+          /* If job_slots is set now then we're not using jobserver */
+          jobserver_clear ();
           free (jobserver_fds);
-          jobserver_fds = 0;
+          jobserver_fds = NULL;
         }
     }
 #endif
@@ -1902,7 +1848,7 @@
     }
 
 #ifndef __EMX__ /* Don't use a SIGCHLD handler for OS/2 */
-#if defined(MAKE_JOBSERVER) || !defined(HAVE_WAIT_NOHANG)
+#if !defined(HAVE_WAIT_NOHANG) || defined(MAKE_JOBSERVER)
   /* Set up to handle children dying.  This must be done before
      reading in the makefiles so that 'shell' function calls will work.
 
@@ -1910,9 +1856,9 @@
      functionality here and rely on the signal handler and counting
      children.
 
-     If we're using the jobs pipe we need a signal handler so that
-     SIGCHLD is not ignored; we need it to interrupt the read(2) of the
-     jobserver pipe in job.c if we're waiting for a token.
+     If we're using the jobs pipe we need a signal handler so that SIGCHLD is
+     not ignored; we need it to interrupt the read(2) of the jobserver pipe if
+     we're waiting for a token.
 
      If none of these are true, we don't need a signal handler at all.  */
   {
@@ -2074,66 +2020,23 @@
 #endif
 
 #ifdef MAKE_JOBSERVER
-  /* If we have >1 slot but no jobserver-fds, then we're a top-level make.
-     Set up the pipe and install the fds option for our children.  */
-
   if (job_slots > 1)
     {
-#ifdef WINDOWS32
-      /* sub_proc.c cannot wait for more than MAXIMUM_WAIT_OBJECTS objects
-       * and one of them is the job-server semaphore object.  Limit the
-       * number of available job slots to (MAXIMUM_WAIT_OBJECTS - 1). */
+      /* If we have >1 slot at this point, then we're a top-level make.
+         Set up the jobserver.
 
-      if (job_slots >= MAXIMUM_WAIT_OBJECTS)
-        {
-          job_slots = MAXIMUM_WAIT_OBJECTS - 1;
-          DB (DB_JOBS, (_("Jobserver slots limited to %d\n"), job_slots));
-        }
-
-      if (! create_jobserver_semaphore (job_slots - 1))
-        {
-          DWORD err = GetLastError ();
-          const char *estr = map_windows32_error_to_string (err);
-          ONS (fatal, NILF,
-               _("creating jobserver semaphore: (Error %ld: %s)"), err, estr);
-        }
-#else
-      char c = '+';
-
-      if (pipe (job_fds) < 0 || (job_rfd = dup (job_fds[0])) < 0)
-        pfatal_with_name (_("creating jobs pipe"));
-#endif
-
-      /* Every make assumes that it always has one job it can run.  For the
+         Every make assumes that it always has one job it can run.  For the
          submakes it's the token they were given by their parent.  For the
-         top make, we just subtract one from the number the user wants.  We
-         want job_slots to be 0 to indicate we're using the jobserver.  */
+         top make, we just subtract one from the number the user wants.  */
 
+      jobserver_setup (job_slots - 1);
+
+      /* We're using the jobserver so set job_slots to 0.  */
       master_job_slots = job_slots;
-
-#ifdef WINDOWS32
-      /* We're using the jobserver so set job_slots to 0. */
       job_slots = 0;
-#else
-      while (--job_slots)
-        {
-          int r;
-
-          EINTRLOOP (r, write (job_fds[1], &c, 1));
-          if (r != 1)
-            pfatal_with_name (_("init jobserver pipe"));
-        }
-#endif
 
       /* Fill in the jobserver_fds for our children.  */
-
-#ifdef WINDOWS32
-      jobserver_fds = xmalloc (MAX_PATH + 1);
-      strcpy (jobserver_fds, get_jobserver_semaphore_name ());
-#else
-      jobserver_fds = xmalloc ((INTSTR_LENGTH * 2) + 2);
-      sprintf (jobserver_fds, "%d,%d", job_fds[0], job_fds[1]);
-#endif
+      jobserver_fds = jobserver_get_arg ();
     }
 #endif
 
@@ -2489,10 +2392,6 @@
           fflush (stdout);
           fflush (stderr);
 
-          /* Close the dup'd jobserver pipe if we opened one.  */
-          if (job_rfd >= 0)
-            close (job_rfd);
-
 #ifdef _AMIGA
           exec_command (nargv);
           exit (0);
@@ -3444,13 +3343,7 @@
      have written all our tokens so do that now.  If tokens are left
      after any other error code, that's bad.  */
 
-#ifdef WINDOWS32
-  if (has_jobserver_semaphore () && jobserver_tokens)
-#else
-  char token = '+';
-
-  if (job_fds[0] != -1 && jobserver_tokens)
-#endif
+  if (jobserver_enabled() && jobserver_tokens)
     {
       if (status != 2)
         ON (error, NILF,
@@ -3459,18 +3352,7 @@
       else
         /* Don't write back the "free" token */
         while (--jobserver_tokens)
-          {
-#ifdef WINDOWS32
-            if (! release_jobserver_semaphore ())
-              perror_with_name ("release_jobserver_semaphore", "");
-#else
-            int r;
-
-            EINTRLOOP (r, write (job_fds[1], &token, 1));
-            if (r != 1)
-              perror_with_name ("write", "");
-#endif
-          }
+          jobserver_release (0);
     }
 
 
@@ -3479,42 +3361,21 @@
   if (master_job_slots)
     {
       /* We didn't write one for ourself, so start at 1.  */
-      unsigned int tcnt = 1;
+      unsigned int tokens = 1 + jobserver_acquire_all ();
 
-#ifdef WINDOWS32
-      while (acquire_jobserver_semaphore ())
-          ++tcnt;
-#else
-      /* Close the write side, so the read() won't hang.  */
-      close (job_fds[1]);
-
-      while (1)
-        {
-          int r;
-          EINTRLOOP (r, read (job_fds[0], &token, 1));
-          if (r != 1)
-            break;
-          ++tcnt;
-        }
-#endif
-
-      if (tcnt != master_job_slots)
+      if (tokens != master_job_slots)
         ONN (error, NILF,
              "INTERNAL: Exiting with %u jobserver tokens available; should be %u!",
-             tcnt, master_job_slots);
+             tokens, master_job_slots);
 
-#ifdef WINDOWS32
-      free_jobserver_semaphore ();
-#else
-      close (job_fds[0]);
-#endif
+      jobserver_clear ();
 
       /* Clean out jobserver_fds so we don't pass this information to any
          sub-makes.  Also reset job_slots since it will be put on the command
          line, not in MAKEFLAGS.  */
       job_slots = default_job_slots;
       free (jobserver_fds);
-      jobserver_fds = 0;
+      jobserver_fds = NULL;
     }
 }
 
diff --git a/maintMakefile b/maintMakefile
index 3edf8d7..f7bdf00 100644
--- a/maintMakefile
+++ b/maintMakefile
@@ -276,7 +276,7 @@
 po-check:
 	if test -f po/POTFILES.in; then \
 	  grep '^[^#]' po/POTFILES.in | sort > $@-1; \
-	  $(PERL) -wn -e 'if (/\b_\(/) { $$ARGV eq "makeint.h" || print "$$ARGV\n" and close ARGV }' *.c *.h | sort > $@-2; \
+	  $(PERL) -wn -e 'if (/\b_\(/) { $$ARGV eq "./makeint.h" || print "$$ARGV\n" and close ARGV }' `find . -name '*.[ch]'` | sed 's,^\./,,' | sort > $@-2; \
 	  diff -u $@-1 $@-2 || exit 1; \
 	  rm -f $@-1 $@-2; \
 	fi
diff --git a/make_msvc_net2003.vcproj b/make_msvc_net2003.vcproj
index 01b1f0d..bcc2e8b 100644
--- a/make_msvc_net2003.vcproj
+++ b/make_msvc_net2003.vcproj
@@ -235,6 +235,9 @@
 					RelativePath=".\w32\pathstuff.c">

 				</File>

 				<File

+					RelativePath=".\w32\w32os.c">

+				</File>

+				<File

 					RelativePath=".\w32\subproc\sub_proc.c">

 				</File>

 				<File

diff --git a/makeint.h b/makeint.h
index 7e191d9..bf75d0a 100644
--- a/makeint.h
+++ b/makeint.h
@@ -623,8 +623,6 @@
 extern char cmd_prefix;
 
 extern unsigned int job_slots;
-extern int job_fds[2];
-extern int job_rfd;
 #ifndef NO_FLOAT
 extern double max_load_average;
 #else
diff --git a/os.h b/os.h
new file mode 100644
index 0000000..545018f
--- /dev/null
+++ b/os.h
@@ -0,0 +1,77 @@
+/* Declarations for operating system interfaces for GNU Make.
+Copyright (C) 2016 Free Software Foundation, Inc.
+This file is part of GNU Make.
+
+GNU Make is free software; you can redistribute it and/or modify it under the
+terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+/* This section provides OS-specific functions to support the jobserver.  */
+
+#ifdef MAKE_JOBSERVER
+
+/* Returns 1 if the jobserver is enabled, else 0.  */
+unsigned int jobserver_enabled ();
+
+/* Called in the master instance to set up the jobserver initially.  */
+void jobserver_setup (int job_slots);
+
+/* Called in a child instance to connect to the jobserver.  */
+void jobserver_parse_arg (const char* arg);
+
+/* Returns an allocated buffer used to pass to child instances.  */
+char *jobserver_get_arg ();
+
+/* Clear this instance's jobserver configuration.  */
+void jobserver_clear ();
+
+/* Recover all the jobserver tokens and return the number we got.  */
+unsigned int jobserver_acquire_all ();
+
+/* Release a jobserver token.  If it fails and is_fatal is 1, fatal.  */
+void jobserver_release (int is_fatal);
+
+/* Notify the jobserver that a child exited.  */
+void jobserver_signal ();
+
+/* Get ready to start a non-recursive child.  */
+void jobserver_pre_child ();
+
+/* Complete starting a non-recursive child.  */
+void jobserver_post_child ();
+
+/* Set up to acquire a new token.  */
+void jobserver_pre_acquire ();
+
+/* Wait until we can acquire a jobserver token.
+   TIMEOUT is 1 if we have other jobs waiting for the load to go down;
+   in this case we won't wait forever, so we can check the load.
+   Returns 1 if we got a token, or 0 if we stopped waiting due to a child
+   exiting or a timeout.    */
+int jobserver_acquire (int timeout);
+
+#else
+
+#define jobserver_enabled()       (0)
+#define jobserver_setup(_slots)   (void)(0)
+#define jobserver_parse_arg(_arg) (void)(0)
+#define jobserver_get_arg()       (NULL)
+#define jobserver_clear()         (void)(0)
+#define jobserver_release(_fatal) (void)(0)
+#define jobserver_acquire_all()   (0)
+#define jobserver_signal()        (void)(0)
+#define jobserver_pre_child()     (void)(0)
+#define jobserver_post_child()    (void)(0)
+#define jobserver_pre_acquire()   (void)(0)
+#define jobserver_acquire(_tmout) (0)
+
+#endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index fce6f36..061ff2b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -32,6 +32,7 @@
 main.c
 misc.c
 output.c
+posixos.c
 read.c
 remake.c
 remote-cstms.c
@@ -43,3 +44,4 @@
 vmsfunctions.c
 vmsjobs.c
 vpath.c
+w32/w32os.c
diff --git a/posixos.c b/posixos.c
new file mode 100644
index 0000000..443c115
--- /dev/null
+++ b/posixos.c
@@ -0,0 +1,320 @@
+/* POSIX-based operating system interface for GNU Make.
+Copyright (C) 2016 Free Software Foundation, Inc.
+This file is part of GNU Make.
+
+GNU Make is free software; you can redistribute it and/or modify it under the
+terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "makeint.h"
+
+#include <stdio.h>
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#include "debug.h"
+#include "job.h"
+#include "os.h"
+
+#ifdef MAKE_JOBSERVER
+
+/* This section provides OS-specific functions to support the jobserver.  */
+
+/* These track the state of the jobserver pipe.  Passed to child instances.  */
+static int job_fds[2] = { -1, -1 };
+
+/* Used to signal read() that a SIGCHLD happened.  Always CLOEXEC.  */
+static int job_rfd = -1;
+
+/* Token written to the pipe (could be any character...)  */
+static char token = '+';
+
+static int
+make_job_rfd ()
+{
+  EINTRLOOP (job_rfd, dup (job_fds[0]));
+  if (job_rfd >= 0)
+    CLOSE_ON_EXEC (job_rfd);
+
+  return job_rfd;
+}
+
+void
+jobserver_setup (int slots)
+{
+  int r;
+
+  EINTRLOOP (r, pipe (job_fds));
+  if (r < 0)
+    pfatal_with_name (_("creating jobs pipe"));
+
+  if (make_job_rfd () < 0)
+    pfatal_with_name (_("duping jobs pipe"));
+
+  while (slots--)
+    {
+      EINTRLOOP (r, write (job_fds[1], &token, 1));
+      if (r != 1)
+        pfatal_with_name (_("init jobserver pipe"));
+    }
+}
+
+void
+jobserver_parse_arg (const char* arg)
+{
+  /* Given the command-line parameter, parse it.  */
+  if (sscanf (arg, "%d,%d", &job_fds[0], &job_fds[1]) != 2)
+    OS (fatal, NILF,
+        _("internal error: invalid --jobserver-fds string '%s'"), arg);
+
+  DB (DB_JOBS,
+      (_("Jobserver client (fds %d,%d)\n"), job_fds[0], job_fds[1]));
+
+#ifdef HAVE_FCNTL
+# define FD_OK(_f) ((fcntl ((_f), F_GETFD) != -1) || (errno != EBADF))
+#else
+# define FD_OK(_f) 1
+#endif
+
+  /* Create a duplicate pipe, that will be closed in the SIGCHLD handler.  If
+     this fails with EBADF, the parent has closed the pipe on us because it
+     didn't think we were a submake.  If so, warn then default to -j1.  */
+  if (!FD_OK (job_fds[0]) || !FD_OK (job_fds[1]) || make_job_rfd () < 0)
+    {
+      if (errno != EBADF)
+        pfatal_with_name (_("dup jobserver"));
+
+      O (error, NILF,
+         _("warning: jobserver unavailable: using -j1.  Add '+' to parent make rule."));
+
+      job_slots = 1;
+      job_fds[0] = job_fds[1] = -1;
+    }
+}
+
+char *
+jobserver_get_arg ()
+{
+  char *fds = xmalloc ((INTSTR_LENGTH * 2) + 2);
+  sprintf (fds, "%d,%d", job_fds[0], job_fds[1]);
+  return fds;
+}
+
+unsigned int
+jobserver_enabled ()
+{
+  return job_fds[0] >= 0;
+}
+
+void
+jobserver_clear ()
+{
+  if (job_fds[0] >= 0)
+    close (job_fds[0]);
+  if (job_fds[1] >= 0)
+    close (job_fds[1]);
+  if (job_rfd >= 0)
+    close (job_rfd);
+
+  job_fds[0] = job_fds[1] = job_rfd = -1;
+}
+
+void
+jobserver_release (int is_fatal)
+{
+  int r;
+  EINTRLOOP (r, write (job_fds[1], &token, 1));
+  if (r != 1)
+    {
+      if (is_fatal)
+        pfatal_with_name (_("write jobserver"));
+      perror_with_name ("write", "");
+    }
+}
+
+unsigned int
+jobserver_acquire_all ()
+{
+  unsigned int tokens = 0;
+
+  /* Close the write side, so the read() won't hang.  */
+  close (job_fds[1]);
+  job_fds[1] = -1;
+
+  while (1)
+    {
+      char intake;
+      int r;
+      EINTRLOOP (r, read (job_fds[0], &intake, 1));
+      if (r != 1)
+        return tokens;
+      ++tokens;
+    }
+}
+
+/* This is really only invoked on OS/2.
+   On POSIX we just call jobserver_clear() in the child process.  */
+void jobserver_pre_child ()
+{
+  CLOSE_ON_EXEC (job_fds[0]);
+  CLOSE_ON_EXEC (job_fds[1]);
+}
+
+void jobserver_post_child ()
+{
+#if defined(F_GETFD) && defined(F_SETFD)
+  for (int i = 0; i < 2; ++i)
+    {
+      int flags;
+      EINTRLOOP (flags, fcntl (job_fds[i], F_GETFD));
+      if (flags >= 0)
+        {
+          int r;
+          EINTRLOOP (r, fcntl (job_fds[i], F_SETFD, flags & ~FD_CLOEXEC));
+        }
+    }
+#endif
+}
+
+/* The acquire algorithm goes like this (from job.c):
+
+   Read a token.  As long as there's no token available we'll block.  We
+   enable interruptible system calls before the read(2) so that if we get a
+   SIGCHLD while we're waiting, we'll return with EINTR and we can process the
+   death(s) and return tokens to the free pool.
+
+   Once we return from the read, we immediately reinstate restartable system
+   calls.  This allows us to not worry about checking for EINTR on all the
+   other system calls in the program.
+
+   There is one other twist: there is a span between the time reap_children()
+   does its last check for dead children and the time the read(2) call is
+   entered, below, where if a child dies we won't notice.  This is extremely
+   serious as it could cause us to deadlock, given the right set of events.
+
+   To avoid this, we do the following: before we reap_children(), we dup(2)
+   the read FD on the jobserver pipe.  The read(2) call below uses that new
+   FD.  In the signal handler, we close that FD.  That way, if a child dies
+   during the section mentioned above, the read(2) will be invoked with an
+   invalid FD and will return immediately with EBADF.  */
+
+static RETSIGTYPE
+job_noop (int sig UNUSED)
+{
+}
+
+/* Set the child handler action flags to FLAGS.  */
+static void
+set_child_handler_action_flags (int set_handler, int set_alarm)
+{
+  struct sigaction sa;
+
+#ifdef __EMX__
+  /* The child handler must be turned off here.  */
+  signal (SIGCHLD, SIG_DFL);
+#endif
+
+  memset (&sa, '\0', sizeof sa);
+  sa.sa_handler = child_handler;
+  sa.sa_flags = set_handler ? 0 : SA_RESTART;
+
+#if defined SIGCHLD
+  if (sigaction (SIGCHLD, &sa, NULL) < 0)
+    pfatal_with_name ("sigaction: SIGCHLD");
+#endif
+
+#if defined SIGCLD && SIGCLD != SIGCHLD
+  if (sigaction (SIGCLD, &sa, NULL) < 0)
+    pfatal_with_name ("sigaction: SIGCLD");
+#endif
+
+#if defined SIGALRM
+  if (set_alarm)
+    {
+      /* If we're about to enter the read(), set an alarm to wake up in a
+         second so we can check if the load has dropped and we can start more
+         work.  On the way out, turn off the alarm and set SIG_DFL.  */
+      if (set_handler)
+        {
+          sa.sa_handler = job_noop;
+          sa.sa_flags = 0;
+          if (sigaction (SIGALRM, &sa, NULL) < 0)
+            pfatal_with_name ("sigaction: SIGALRM");
+          alarm (1);
+        }
+      else
+        {
+          alarm (0);
+          sa.sa_handler = SIG_DFL;
+          sa.sa_flags = 0;
+          if (sigaction (SIGALRM, &sa, NULL) < 0)
+            pfatal_with_name ("sigaction: SIGALRM");
+        }
+    }
+#endif
+}
+
+void
+jobserver_signal ()
+{
+  if (job_rfd >= 0)
+    {
+      close (job_rfd);
+      job_rfd = -1;
+    }
+}
+
+void
+jobserver_pre_acquire ()
+{
+  /* Make sure we have a dup'd FD.  */
+  if (job_rfd < 0 && job_fds[0] >= 0)
+    {
+      DB (DB_JOBS, ("Duplicate the job FD\n"));
+      if (make_job_rfd () < 0)
+        pfatal_with_name (_("duping jobs pipe"));
+    }
+}
+
+int
+jobserver_acquire (int timeout)
+{
+  char intake;
+  int got_token;
+  int saved_errno;
+
+  /* Set interruptible system calls, and read() for a job token.  */
+  set_child_handler_action_flags (1, timeout);
+
+  EINTRLOOP (got_token, read (job_rfd, &intake, 1));
+  saved_errno = errno;
+
+  set_child_handler_action_flags (0, timeout);
+
+  if (got_token == 1)
+    return 1;
+
+  /* If the error _wasn't_ expected (EINTR or EBADF), fatal.  Otherwise,
+     go back and reap_children(), and try again.  */
+  errno = saved_errno;
+
+  if (errno != EINTR && errno != EBADF)
+    pfatal_with_name (_("read jobs pipe"));
+
+  if (errno == EBADF)
+    DB (DB_JOBS, ("Read returned EBADF.\n"));
+
+  return 0;
+}
+
+#endif /* MAKE_JOBSERVER */
diff --git a/vmsfunctions.c b/vmsfunctions.c
index 09cb124..e422d48 100644
--- a/vmsfunctions.c
+++ b/vmsfunctions.c
@@ -118,7 +118,7 @@
       struct FAB *dfab = &dir->fab;
       struct NAM *dnam = (struct NAM *)(dfab->fab$l_nam);
       if (dnam != NULL)
-	free (dnam->nam$l_esa);
+        free (dnam->nam$l_esa);
       free (dnam);
       free (dir);
     }
diff --git a/w32/include/sub_proc.h b/w32/include/sub_proc.h
index 5ba1946..4afa4b4 100644
--- a/w32/include/sub_proc.h
+++ b/w32/include/sub_proc.h
@@ -32,11 +32,11 @@
 
 EXTERN_DECL(HANDLE process_init, (VOID_DECL));
 EXTERN_DECL(HANDLE process_init_fd, (HANDLE stdinh, HANDLE stdouth,
-        HANDLE stderrh));
+                                     HANDLE stderrh));
 EXTERN_DECL(long process_begin, (HANDLE proc, char **argv, char **envp,
-        char *exec_path, char *as_user));
+                                 char *exec_path, char *as_user));
 EXTERN_DECL(long process_pipe_io, (HANDLE proc, char *stdin_data,
-        int stdin_data_len));
+                                   int stdin_data_len));
 EXTERN_DECL(long process_file_io, (HANDLE proc));
 EXTERN_DECL(void process_cleanup, (HANDLE proc));
 EXTERN_DECL(HANDLE process_wait_for_any, (int block, DWORD* pdwWaitStatus));
@@ -45,6 +45,7 @@
                                   int outfd, int errfd));
 EXTERN_DECL(BOOL process_kill, (HANDLE proc, int signal));
 EXTERN_DECL(int process_used_slots, (VOID_DECL));
+EXTERN_DECL(DWORD process_set_handles, (HANDLE *handles));
 
 /* support routines */
 EXTERN_DECL(long process_errno, (HANDLE proc));
@@ -58,14 +59,4 @@
 EXTERN_DECL(void process_pipes, (HANDLE proc, int pipes[3]));
 EXTERN_DECL(void process_noinherit, (int fildes));
 
-/* jobserver routines */
-EXTERN_DECL(int open_jobserver_semaphore, (const char* name));
-EXTERN_DECL(int create_jobserver_semaphore, (int tokens));
-EXTERN_DECL(void free_jobserver_semaphore, (VOID_DECL));
-EXTERN_DECL(int acquire_jobserver_semaphore, (VOID_DECL));
-EXTERN_DECL(int release_jobserver_semaphore, (VOID_DECL));
-EXTERN_DECL(int has_jobserver_semaphore, (VOID_DECL));
-EXTERN_DECL(char* get_jobserver_semaphore_name, (VOID_DECL));
-EXTERN_DECL(int wait_for_semaphore_or_child_process, (VOID_DECL));
-
 #endif
diff --git a/w32/subproc/build.bat b/w32/subproc/build.bat
deleted file mode 100644
index bb6b24d..0000000
--- a/w32/subproc/build.bat
+++ /dev/null
@@ -1,34 +0,0 @@
-@if "%COMPILER%" == "gcc" GoTo GCCBuild

-if not exist .\WinDebug\nul mkdir .\WinDebug

-cl.exe /nologo /MT /W4 /GX /Z7 /YX /Od /I .. /I . /I ../include /I ../.. /D WIN32 /D WINDOWS32 /D _DEBUG /D _WINDOWS /FR.\WinDebug/ /Fp.\WinDebug/subproc.pch /Fo.\WinDebug/ /c misc.c

-cl.exe /nologo /MT /W4 /GX /Z7 /YX /Od /I .. /I . /I ../include /I ../.. /D WIN32 /D WINDOWS32 /D _DEBUG /D _WINDOWS /FR.\WinDebug/ /Fp.\WinDebug/subproc.pch /Fo.\WinDebug/ /c sub_proc.c

-cl.exe /nologo /MT /W4 /GX /Z7 /YX /Od /I .. /I . /I ../include /I ../.. /D WIN32 /D WINDOWS32 /D _DEBUG /D _WINDOWS /FR.\WinDebug/ /Fp.\WinDebug/subproc.pch /Fo.\WinDebug/ /c w32err.c

-lib.exe /NOLOGO /OUT:.\WinDebug\subproc.lib  .\WinDebug/misc.obj  .\WinDebug/sub_proc.obj  .\WinDebug/w32err.obj

-if not exist .\WinRel\nul mkdir .\WinRel

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I .. /I . /I ../include /I ../.. /D WIN32 /D WINDOWS32 /D NDEBUG /D _WINDOWS /FR.\WinRel/ /Fp.\WinRel/subproc.pch /Fo.\WinRel/ /c misc.c

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I .. /I . /I ../include /I ../.. /D WIN32 /D WINDOWS32 /D NDEBUG /D _WINDOWS /FR.\WinRel/ /Fp.\WinRel/subproc.pch /Fo.\WinRel/ /c sub_proc.c

-cl.exe /nologo /MT /W4 /GX /YX /O2 /I .. /I . /I ../include /I ../.. /D WIN32 /D WINDOWS32 /D NDEBUG /D _WINDOWS /FR.\WinRel/ /Fp.\WinRel/subproc.pch /Fo.\WinRel/ /c w32err.c

-lib.exe /NOLOGO /OUT:.\WinRel\subproc.lib  .\WinRel/misc.obj  .\WinRel/sub_proc.obj  .\WinRel/w32err.obj

-GoTo BuildEnd

-:GCCBuild

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I.. -I. -I../include -I../.. -DWINDOWS32 -c misc.c -o ../../w32_misc.o

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I.. -I. -I../include -I../.. -DWINDOWS32 -c sub_proc.c -o ../../sub_proc.o

-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I.. -I. -I../include -I../.. -DWINDOWS32 -c w32err.c -o ../../w32err.o

-:BuildEnd

-

-@echo off

-rem Copyright (C) 1996-2016 Free Software Foundation, Inc.

-rem This file is part of GNU Make.

-rem

-rem GNU Make is free software; you can redistribute it and/or modify it under

-rem the terms of the GNU General Public License as published by the Free

-rem Software Foundation; either version 3 of the License, or (at your option)

-rem any later version.

-rem

-rem GNU Make is distributed in the hope that it will be useful, but WITHOUT

-rem ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or

-rem FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for.

-rem more details.

-rem

-rem You should have received a copy of the GNU General Public License along

-rem with this program.  If not, see <http://www.gnu.org/licenses/>.

diff --git a/w32/subproc/sub_proc.c b/w32/subproc/sub_proc.c
index aa07b7b..2442411 100644
--- a/w32/subproc/sub_proc.c
+++ b/w32/subproc/sub_proc.c
@@ -61,124 +61,26 @@
 static int proc_index = 0;
 static int fake_exits_pending = 0;
 
-/* Windows jobserver implementation variables */
-static char jobserver_semaphore_name[MAX_PATH + 1];
-static HANDLE jobserver_semaphore = NULL;
 
-/* Open existing jobserver semaphore */
-int open_jobserver_semaphore(const char* name)
-{
-    jobserver_semaphore = OpenSemaphore(
-        SEMAPHORE_ALL_ACCESS,   // Semaphore access setting
-        FALSE,                  // Child processes DON'T inherit
-        name);                  // Semaphore name
-
-    if (jobserver_semaphore == NULL)
-        return 0;
-
-    return 1;
-}
-
-/* Create new jobserver semaphore */
-int create_jobserver_semaphore(int tokens)
-{
-    sprintf(jobserver_semaphore_name, "gmake_semaphore_%d", _getpid());
-
-    jobserver_semaphore = CreateSemaphore(
-        NULL,                           // Use default security descriptor
-        tokens,                         // Initial count
-        tokens,                         // Maximum count
-        jobserver_semaphore_name);      // Semaphore name
-
-    if (jobserver_semaphore == NULL)
-        return 0;
-
-    return 1;
-}
-
-/* Close jobserver semaphore */
-void free_jobserver_semaphore()
-{
-    if (jobserver_semaphore != NULL)
-    {
-        CloseHandle(jobserver_semaphore);
-        jobserver_semaphore = NULL;
-    }
-}
-
-/* Decrement semaphore count */
-int acquire_jobserver_semaphore()
-{
-    DWORD dwEvent = WaitForSingleObject(
-        jobserver_semaphore,    // Handle to semaphore
-        0);                     // DON'T wait on semaphore
-
-    return (dwEvent == WAIT_OBJECT_0);
-}
-
-/* Increment semaphore count */
-int release_jobserver_semaphore()
-{
-    BOOL bResult = ReleaseSemaphore(
-        jobserver_semaphore,    // handle to semaphore
-        1,                      // increase count by one
-        NULL);                  // not interested in previous count
-
-    return (bResult);
-}
-
-int has_jobserver_semaphore()
-{
-    return (jobserver_semaphore != NULL);
-}
-
-char* get_jobserver_semaphore_name()
-{
-    return (jobserver_semaphore_name);
-}
-
-/* Wait for either the jobserver semaphore to become signalled or one of our
- * child processes to terminate.
+/*
+ * Fill a HANDLE list with handles to wait for.
  */
-int wait_for_semaphore_or_child_process()
+DWORD
+process_set_handles(HANDLE *handles)
 {
-    HANDLE handles[MAXIMUM_WAIT_OBJECTS];
-    DWORD dwHandleCount = 1;
-    DWORD dwEvent;
+    DWORD count = 0;
     int i;
 
-    /* Add jobserver semaphore to first slot. */
-    handles[0] = jobserver_semaphore;
-
     /* Build array of handles to wait for */
-    for (i = 0; i < proc_index; i++)
-    {
+    for (i = 0; i < proc_index; i++) {
         /* Don't wait on child processes that have already finished */
         if (fake_exits_pending && proc_array[i]->exit_code)
             continue;
 
-        handles[dwHandleCount++] = (HANDLE) proc_array[i]->pid;
+        handles[count++] = (HANDLE) proc_array[i]->pid;
     }
 
-    dwEvent = WaitForMultipleObjects(
-        dwHandleCount,  // number of objects in array
-        handles,        // array of objects
-        FALSE,          // wait for any object
-        INFINITE);      // wait until object is signalled
-
-    switch(dwEvent)
-    {
-      case WAIT_FAILED:
-        return -1;
-
-      case WAIT_OBJECT_0:
-        /* Indicate that the semaphore was signalled */
-        return 1;
-
-      default:
-        /* Assume that one or more of the child processes terminated. */
-        return 0;
-    }
+    return count;
 }
 
 /*
@@ -756,7 +658,7 @@
                         pproc->lerrno = E_NO_MEM;
                         free( command_line );
                         if ((pproc->last_err == ERROR_INVALID_PARAMETER
-			     || pproc->last_err == ERROR_MORE_DATA)
+                             || pproc->last_err == ERROR_MORE_DATA)
                             && envsize_needed > 32*1024) {
                                 fprintf (stderr, "CreateProcess failed, probably because environment is too large (%d bytes).\n",
                                          envsize_needed);
diff --git a/w32/w32os.c b/w32/w32os.c
new file mode 100644
index 0000000..0b572fe
--- /dev/null
+++ b/w32/w32os.c
@@ -0,0 +1,196 @@
+/* Windows32-based operating system interface for GNU Make.
+Copyright (C) 2016 Free Software Foundation, Inc.
+This file is part of GNU Make.
+
+GNU Make is free software; you can redistribute it and/or modify it under the
+terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "makeint.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <windows.h>
+#include <process.h>
+#include <io.h>
+#include "pathstuff.h"
+#include "sub_proc.h"
+#include "w32err.h"
+#include "os.h"
+#include "debug.h"
+
+/* This section provides OS-specific functions to support the jobserver.  */
+
+static char jobserver_semaphore_name[MAX_PATH + 1];
+static HANDLE jobserver_semaphore = NULL;
+
+void
+jobserver_setup (int slots)
+{
+  /* sub_proc.c cannot wait for more than MAXIMUM_WAIT_OBJECTS objects
+   * and one of them is the job-server semaphore object.  Limit the
+   * number of available job slots to (MAXIMUM_WAIT_OBJECTS - 1). */
+
+  if (slots >= MAXIMUM_WAIT_OBJECTS)
+    {
+      slots = MAXIMUM_WAIT_OBJECTS - 1;
+      DB (DB_JOBS, (_("Jobserver slots limited to %d\n"), slots));
+    }
+
+  sprintf (jobserver_semaphore_name, "gmake_semaphore_%d", _getpid ());
+
+  jobserver_semaphore = CreateSemaphore (
+      NULL,                           /* Use default security descriptor */
+      slots,                          /* Initial count */
+      slots,                          /* Maximum count */
+      jobserver_semaphore_name);      /* Semaphore name */
+
+  if (jobserver_semaphore == NULL)
+    {
+      DWORD err = GetLastError ();
+      const char *estr = map_windows32_error_to_string (err);
+      ONS (fatal, NILF,
+           _("creating jobserver semaphore: (Error %ld: %s)"), err, estr);
+    }
+}
+
+void
+jobserver_parse_arg (const char* arg)
+{
+  jobserver_semaphore = OpenSemaphore (
+  SEMAPHORE_ALL_ACCESS,   /* Semaphore access setting */
+    FALSE,                  /* Child processes DON'T inherit */
+    arg);                   /* Semaphore name */
+
+  if (jobserver_semaphore == NULL)
+    {
+      DWORD err = GetLastError ();
+      const char *estr = map_windows32_error_to_string (err);
+      fatal (NILF, strlen (arg) + INTSTR_LENGTH + strlen (estr),
+             _("internal error: unable to open jobserver semaphore '%s': (Error %ld: %s)"),
+             arg, err, estr);
+    }
+  DB (DB_JOBS, (_("Jobserver client (semaphore %s)\n"), arg));
+}
+
+char *
+jobserver_get_arg ()
+{
+  char *fds = xmalloc (MAX_PATH + 1);
+  strcpy (fds, jobserver_semaphore_name);
+  return fds;
+}
+
+unsigned int
+jobserver_enabled ()
+{
+  return jobserver_semaphore != NULL;
+}
+
+/* Close jobserver semaphore */
+void
+jobserver_clear ()
+{
+  if (jobserver_semaphore != NULL)
+    {
+      CloseHandle (jobserver_semaphore);
+      jobserver_semaphore = NULL;
+    }
+}
+
+void
+jobserver_release (int is_fatal)
+{
+  if (! ReleaseSemaphore (
+          jobserver_semaphore,    /* handle to semaphore */
+          1,                      /* increase count by one */
+          NULL))                  /* not interested in previous count */
+    {
+      if (is_fatal)
+        {
+          DWORD err = GetLastError ();
+          const char *estr = map_windows32_error_to_string (err);
+          ONS (fatal, NILF,
+               _("release jobserver semaphore: (Error %ld: %s)"), err, estr);
+        }
+      perror_with_name ("release_jobserver_semaphore", "");
+    }
+}
+
+unsigned int
+jobserver_acquire_all ()
+{
+  unsigned int tokens = 0;
+  while (1)
+    {
+      DWORD dwEvent = WaitForSingleObject (
+          jobserver_semaphore,    /* Handle to semaphore */
+          0);                     /* DON'T wait on semaphore */
+
+      if (dwEvent != WAIT_OBJECT_0)
+        return tokens;
+
+      ++tokens;
+    }
+}
+
+void
+jobserver_signal ()
+{
+}
+
+void jobserver_pre_child ()
+{
+}
+
+void jobserver_post_child ()
+{
+}
+
+void
+jobserver_pre_acquire ()
+{
+}
+
+/* Returns 1 if we got a token, or 0 if a child has completed.
+   The Windows implementation doesn't support load detection.  */
+int
+jobserver_acquire (int timeout)
+{
+    HANDLE handles[MAXIMUM_WAIT_OBJECTS];
+    DWORD dwHandleCount;
+    DWORD dwEvent;
+
+    /* Add jobserver semaphore to first slot. */
+    handles[0] = jobserver_semaphore;
+
+    /* Build array of handles to wait for.  */
+    dwHandleCount = 1 + process_set_handles (&handles[1]);
+
+    dwEvent = WaitForMultipleObjects (
+        dwHandleCount,  /* number of objects in array */
+        handles,        /* array of objects */
+        FALSE,          /* wait for any object */
+        INFINITE);      /* wait until object is signalled */
+
+    if (dwEvent == WAIT_FAILED)
+      {
+        DWORD err = GetLastError ();
+        const char *estr = map_windows32_error_to_string (err);
+        ONS (fatal, NILF,
+             _("semaphore or child process wait: (Error %ld: %s)"),
+             err, estr);
+      }
+
+    /* WAIT_OBJECT_0 indicates that the semaphore was signalled.  */
+    return dwEvent == WAIT_OBJECT_0;
+}