* 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.
*.pdb
*.sbr
+# Windows build artifacts
+/WinDebug/
+/WinRel/
+/GccDebug/
+/GccRel/
+
# Distribution artifacts
.dep_segment
.check-git-HEAD
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)
$(OUTDIR)/dirent.obj \
$(OUTDIR)/pathstuff.obj \
$(OUTDIR)/posixfcn.obj \
+ $(OUTDIR)/w32os.obj \
$(guile)
$(OUTDIR)/make.exe: $(OUTDIR) $(OBJS)
$(CC) $(CFLAGS) /c $?
$(OUTDIR)/pathstuff.obj : w32/pathstuff.c
$(CC) $(CFLAGS) /c $?
+$(OUTDIR)/w32os.obj : w32/w32os.c
+ $(CC) $(CFLAGS) /c $?
-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
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:
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
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 ...
rem You should have received a copy of the GNU General Public License along\r
rem with this program. If not, see <http://www.gnu.org/licenses/>.\r
\r
-if "%1" == "-h" GoTo Usage\r
-if "%1" == "--help" GoTo Usage\r
-if not exist config.h.W32.template GoTo NotSCM\r
-sed -n "s/^AC_INIT(\[GNU make\],\[\([^]]\+\)\].*/s,%%VERSION%%,\1,g/p" configure.ac > config.h.W32.sed\r
-echo s,%%PACKAGE%%,make,g >> config.h.W32.sed\r
-sed -f config.h.W32.sed config.h.W32.template > config.h.W32\r
-echo static const char *const GUILE_module_defn = ^" \> gmk-default.h\r
-sed -e "s/;.*//" -e "/^[ \t]*$/d" -e "s/\"/\\\\\"/g" -e "s/$/ \\/" gmk-default.scm >> gmk-default.h\r
-echo ^";>> gmk-default.h\r
-:NotSCM\r
-copy config.h.W32 config.h\r
+call :Reset\r
+\r
+if "%1" == "-h" goto Usage\r
+if "%1" == "--help" goto Usage\r
+\r
+set MAKE=gnumake\r
+set GUILE=Y\r
+set COMPILER=msvc\r
\r
-rem Guile configuration\r
-set GUILECFLAGS=\r
-set GUILELIBS=\r
-set NOGUILE=\r
-set OPT=-O2\r
-set COMPILER=\r
-set PKGMSC=\r
:ParseSW\r
-if "%1" == "--debug" GoTo SetOpt\r
-if "%1" == "--without-guile" GoTo NoGuile\r
-if "%1" == "gcc" GoTo SetCC\r
-if "%1" == "" GoTo ChkGuile\r
-:SetOpt\r
-set OPT=-O0\r
+if "%1" == "--debug" goto SetDebug\r
+if "%1" == "--without-guile" goto NoGuile\r
+if "%1" == "gcc" goto SetCC\r
+if "%1" == "" goto DoneSW\r
+\r
+:SetDebug\r
+set DEBUG=Y\r
shift\r
-GoTo ParseSW\r
+goto ParseSW\r
+\r
:NoGuile\r
-set NOGUILE=Y\r
-echo "Building without Guile"\r
+set GUILE=N\r
+echo Building without Guile\r
shift\r
-GoTo ParseSW\r
+goto ParseSW\r
+\r
:SetCC\r
set COMPILER=gcc\r
-echo "Building with GCC"\r
+echo Building with GCC\r
shift\r
-GoTo ParseSW\r
+goto ParseSW\r
+\r
rem Build with Guile is supported only on NT and later versions\r
-:ChkGuile\r
-if "%NOGUILE%" == "Y" GoTo GuileDone\r
-if not "%OS%" == "Windows_NT" GoTo NoGuile\r
-pkg-config --help > guile.tmp 2> NUL\r
-if ERRORLEVEL 1 GoTo NoPkgCfg\r
-echo "Checking for Guile 2.0"\r
-if not "%COMPILER%" == "gcc" set PKGMSC=--msvc-syntax\r
-pkg-config --cflags --short-errors "guile-2.0" > guile.tmp\r
-if not ERRORLEVEL 1 set /P GUILECFLAGS= < guile.tmp\r
-pkg-config --libs --static --short-errors %PKGMSC% "guile-2.0" > guile.tmp\r
-if not ERRORLEVEL 1 set /P GUILELIBS= < guile.tmp\r
-if not "%GUILECFLAGS%" == "" GoTo GuileDone\r
-echo "Checking for Guile 1.8"\r
-pkg-config --cflags --short-errors "guile-1.8" > guile.tmp\r
-if not ERRORLEVEL 1 set /P GUILECFLAGS= < guile.tmp\r
-pkg-config --libs --static --short-errors %PKGMSC% "guile-1.8" > guile.tmp\r
-if not ERRORLEVEL 1 set /P GUILELIBS= < guile.tmp\r
-if not "%GUILECFLAGS%" == "" GoTo GuileDone\r
-echo "No Guile found, building without Guile"\r
-GoTo GuileDone\r
-:NoPkgCfg\r
-echo "pkg-config not found, building without Guile"\r
-:GuileDone\r
-if not "%GUILECFLAGS%" == "" echo "Guile found, building with Guile"\r
-if not "%GUILECFLAGS%" == "" set GUILECFLAGS=%GUILECFLAGS% -DHAVE_GUILE\r
-if "%COMPILER%" == "gcc" if "%OPT%" == "-O0" echo "Building without compiler optimizations"\r
-cd w32\subproc\r
+:DoneSW\r
echo.\r
-echo "Creating the subproc library"\r
-%ComSpec% /c build.bat\r
-cd ..\..\r
+echo Creating GNU Make for Windows 9X/NT/2K/XP/Vista/7/8\r
+if "%DEBUG%" == "Y" echo Building without compiler optimizations\r
+\r
+if "%COMPILER%" == "gcc" goto GccBuild\r
+\r
+set OUTDIR=.\WinRel\r
+set "OPTS=/O2 /D NDEBUG"\r
+set LINKOPTS=\r
+if "%DEBUG%" == "Y" set OUTDIR=.\WinDebug\r
+if "%DEBUG%" == "Y" set "OPTS=/Zi /Od /D _DEBUG"\r
+if "%DEBUG%" == "Y" set LINKOPTS=/DEBUG\r
+call :Build\r
+goto Done\r
+\r
+:GccBuild\r
+set OUTDIR=.\GccRel\r
+set OPTS=-O2\r
+if "%DEBUG%" == "Y" set OPTS=-O0\r
+if "%DEBUG%" == "Y" set OUTDIR=.\GccDebug\r
+call :Build\r
+goto Done\r
+\r
+:Done\r
+call :Reset\r
+goto :EOF\r
+\r
+:Build\r
+:: Clean the directory if it exists\r
+if exist %OUTDIR%\nul rmdir /S /Q %OUTDIR%\r
+\r
+:: Recreate it\r
+mkdir %OUTDIR%\r
+mkdir %OUTDIR%\glob\r
+mkdir %OUTDIR%\w32\r
+mkdir %OUTDIR%\w32\compat\r
+mkdir %OUTDIR%\w32\subproc\r
+\r
+if "%GUILE%" == "Y" call :ChkGuile\r
\r
-if exist link.dbg del link.dbg\r
-if exist link.rel del link.rel\r
echo.\r
-echo "Creating GNU Make for Windows 9X/NT/2K/XP/Vista/7/8"\r
-if "%COMPILER%" == "gcc" GoTo GCCBuild\r
-set make=gnumake\r
+echo Compiling %OUTDIR% version\r
+\r
+if exist config.h.W32.template call :ConfigSCM\r
+copy config.h.W32 %OUTDIR%\config.h\r
+\r
+call :Compile ar\r
+call :Compile arscan\r
+call :Compile commands\r
+call :Compile default\r
+call :Compile dir\r
+call :Compile expand\r
+call :Compile file\r
+call :Compile function\r
+call :Compile getloadavg\r
+call :Compile getopt\r
+call :Compile getopt1\r
+call :Compile glob\fnmatch\r
+call :Compile glob\glob\r
+call :Compile guile GUILE\r
+call :Compile hash\r
+call :Compile implicit\r
+call :Compile job\r
+call :Compile load\r
+call :Compile loadapi\r
+call :Compile main GUILE\r
+call :Compile misc\r
+call :Compile output\r
+call :Compile read\r
+call :Compile remake\r
+call :Compile remote-stub\r
+call :Compile rule\r
+call :Compile signame\r
+call :Compile strcache\r
+call :Compile variable\r
+call :Compile version\r
+call :Compile vpath\r
+call :Compile w32\compat\posixfcn\r
+call :Compile w32\pathstuff\r
+call :Compile w32\subproc\misc\r
+call :Compile w32\subproc\sub_proc\r
+call :Compile w32\subproc\w32err\r
+call :Compile w32\w32os\r
+\r
+if not "%COMPILER%" == "gcc" call :Compile w32\compat\dirent\r
+\r
+call :Link\r
+\r
+echo.\r
+if not exist %OUTDIR%\%MAKE%.exe echo %OUTDIR% build FAILED!\r
+if exist %OUTDIR%\%MAKE%.exe echo %OUTDIR% build succeeded.\r
+goto :EOF\r
+\r
+:Compile\r
+set EXTRAS=\r
+if "%2" == "GUILE" set "EXTRAS=%GUILECFLAGS%"\r
+if "%COMPILER%" == "gcc" goto GccCompile\r
+\r
+:: MSVC Compile\r
+echo on\r
+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\r
+@echo off\r
+echo %OUTDIR%\%1.obj >>%OUTDIR%\link.sc\r
+goto :EOF\r
+\r
+:GccCompile\r
+:: GCC Compile\r
echo on\r
-if not exist .\WinDebug\nul mkdir .\WinDebug\r
-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\r
-echo WinDebug\variable.obj >>link.dbg\r
-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\r
-echo WinDebug\rule.obj >>link.dbg\r
-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\r
-echo WinDebug\remote-stub.obj >>link.dbg\r
-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\r
-echo WinDebug\commands.obj >>link.dbg\r
-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\r
-echo WinDebug\file.obj >>link.dbg\r
-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\r
-echo WinDebug\getloadavg.obj >>link.dbg\r
-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\r
-echo WinDebug\default.obj >>link.dbg\r
-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\r
-echo WinDebug\signame.obj >>link.dbg\r
-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\r
-echo WinDebug\expand.obj >>link.dbg\r
-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\r
-echo WinDebug\dir.obj >>link.dbg\r
-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\r
-echo WinDebug\main.obj >>link.dbg\r
-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\r
-echo WinDebug\getopt1.obj >>link.dbg\r
-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\r
-echo WinDebug\job.obj >>link.dbg\r
-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\r
-echo WinDebug\output.obj >>link.dbg\r
-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\r
-echo WinDebug\read.obj >>link.dbg\r
-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\r
-echo WinDebug\version.obj >>link.dbg\r
-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\r
-echo WinDebug\getopt.obj >>link.dbg\r
-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\r
-echo WinDebug\arscan.obj >>link.dbg\r
-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\r
-echo WinDebug\hash.obj >>link.dbg\r
-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\r
-echo WinDebug\strcache.obj >>link.dbg\r
-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\r
-echo WinDebug\remake.obj >>link.dbg\r
-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\r
-echo WinDebug\misc.obj >>link.dbg\r
-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\r
-echo WinDebug\ar.obj >>link.dbg\r
-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\r
-echo WinDebug\function.obj >>link.dbg\r
-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\r
-echo WinDebug\vpath.obj >>link.dbg\r
-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\r
-echo WinDebug\implicit.obj >>link.dbg\r
-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\r
-echo WinDebug\loadapi.obj >>link.dbg\r
-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\r
-echo WinDebug\load.obj >>link.dbg\r
-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\r
-echo WinDebug\dirent.obj >>link.dbg\r
-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\r
-echo WinDebug\posixfcn.obj >>link.dbg\r
-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\r
-echo WinDebug\glob.obj >>link.dbg\r
-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\r
-echo WinDebug\fnmatch.obj >>link.dbg\r
-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\r
-echo WinDebug\pathstuff.obj >>link.dbg\r
-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\r
-echo WinDebug\guile.obj >>link.dbg\r
-:LinkDbg\r
-echo off\r
-echo "Linking WinDebug/%make%.exe"\r
-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\r
-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\r
-link.exe /NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes /PDB:.\WinDebug/%make%.pdb /DEBUG /OUT:.\WinDebug/%make%.exe @link.dbg\r
-if not exist .\WinDebug/%make%.exe echo "WinDebug build failed"\r
-if exist .\WinDebug/%make%.exe echo "WinDebug build succeeded!"\r
-if not exist .\WinRel\nul mkdir .\WinRel\r
+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\r
+@echo off\r
+goto :EOF\r
+\r
+:Link\r
+echo Linking %OUTDIR%/%MAKE%.exe\r
+if "%COMPILER%" == "gcc" goto GccLink\r
+\r
+:: MSVC Link\r
+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\r
echo on\r
-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\r
-echo WinRel\variable.obj >>link.rel\r
-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\r
-echo WinRel\rule.obj >>link.rel\r
-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\r
-echo WinRel\remote-stub.obj >>link.rel\r
-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\r
-echo WinRel\commands.obj >>link.rel\r
-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\r
-echo WinRel\file.obj >>link.rel\r
-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\r
-echo WinRel\getloadavg.obj >>link.rel\r
-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\r
-echo WinRel\default.obj >>link.rel\r
-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\r
-echo WinRel\signame.obj >>link.rel\r
-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\r
-echo WinRel\expand.obj >>link.rel\r
-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\r
-echo WinRel\dir.obj >>link.rel\r
-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\r
-echo WinRel\main.obj >>link.rel\r
-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\r
-echo WinRel\getopt1.obj >>link.rel\r
-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\r
-echo WinRel\job.obj >>link.rel\r
-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\r
-echo WinRel\output.obj >>link.rel\r
-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\r
-echo WinRel\read.obj >>link.rel\r
-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\r
-echo WinRel\version.obj >>link.rel\r
-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\r
-echo WinRel\getopt.obj >>link.rel\r
-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\r
-echo WinRel\arscan.obj >>link.rel\r
-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\r
-echo WinRel\remake.obj >>link.rel\r
-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\r
-echo WinRel\hash.obj >>link.rel\r
-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\r
-echo WinRel\strcache.obj >>link.rel\r
-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\r
-echo WinRel\misc.obj >>link.rel\r
-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\r
-echo WinRel\ar.obj >>link.rel\r
-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\r
-echo WinRel\function.obj >>link.rel\r
-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\r
-echo WinRel\vpath.obj >>link.rel\r
-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\r
-echo WinRel\implicit.obj >>link.rel\r
-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\r
-echo WinRel\loadapi.obj >>link.rel\r
-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\r
-echo WinRel\load.obj >>link.rel\r
-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\r
-echo WinRel\dirent.obj >>link.rel\r
-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\r
-echo WinRel\posixfcn.obj >>link.rel\r
-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\r
-echo WinRel\glob.obj >>link.rel\r
-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\r
-echo WinRel\fnmatch.obj >>link.rel\r
-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\r
-echo WinRel\pathstuff.obj >>link.rel\r
-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\r
-echo WinRel\guile.obj >>link.rel\r
-:LinkRel\r
-echo off\r
-echo "Linking WinRel/%make%.exe"\r
-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\r
-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\r
-link.exe /NOLOGO /SUBSYSTEM:console /INCREMENTAL:no /PDB:.\WinRel/%make%.pdb /OUT:.\WinRel/%make%.exe @link.rel\r
-if not exist .\WinRel/%make%.exe echo "WinRel build failed"\r
-if exist .\WinRel/%make%.exe echo "WinRel build succeeded!"\r
-set make=\r
-GoTo BuildEnd\r
-:GCCBuild\r
+link.exe /NOLOGO /SUBSYSTEM:console /PDB:%OUTDIR%\%MAKE%.pdb %LINKOPTS% /OUT:%OUTDIR%\%MAKE%.exe @%OUTDIR%\link.sc\r
+@echo off\r
+goto :EOF\r
+\r
+:GccLink\r
+:: GCC Link\r
echo on\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c variable.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c rule.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c remote-stub.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c commands.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c file.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c getloadavg.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c default.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c signame.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c expand.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c dir.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H %GUILECFLAGS% -c main.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c getopt1.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c job.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c output.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c read.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c version.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c getopt.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c arscan.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c remake.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c hash.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c strcache.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c misc.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c ar.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c function.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c vpath.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c implicit.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c loadapi.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c load.c\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c ./glob/glob.c -o glob.o\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c ./glob/fnmatch.c -o fnmatch.o\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c ./w32/pathstuff.c -o pathstuff.o\r
-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\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% %GUILECFLAGS% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c guile.c\r
-:LinkGCC\r
+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\r
@echo off\r
-Rem The version NN of libgnumake-NN.dll.a should be bumped whenever\r
-Rem the API changes in binary-incompatible manner.\r
-@echo on\r
-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\r
-@GoTo BuildEnd\r
+goto :EOF\r
+\r
+:ConfigSCM\r
+echo Generating config from SCM templates\r
+sed -n "s/^AC_INIT(\[GNU make\],\[\([^]]\+\)\].*/s,%%VERSION%%,\1,g/p" configure.ac > %OUTDIR%\config.h.W32.sed\r
+echo s,%%PACKAGE%%,make,g >> %OUTDIR%\config.h.W32.sed\r
+sed -f %OUTDIR%\config.h.W32.sed config.h.W32.template > config.h.W32\r
+echo static const char *const GUILE_module_defn = ^" \> gmk-default.h\r
+sed -e "s/;.*//" -e "/^[ \t]*$/d" -e "s/\"/\\\\\"/g" -e "s/$/ \\\/" gmk-default.scm >> gmk-default.h\r
+echo ^";>> gmk-default.h\r
+goto :EOF\r
+\r
+:ChkGuile\r
+if not "%OS%" == "Windows_NT" goto NoGuile\r
+pkg-config --help > %OUTDIR%\guile.tmp 2> NUL\r
+if ERRORLEVEL 1 goto NoPkgCfg\r
+\r
+echo Checking for Guile 2.0\r
+if not "%COMPILER%" == "gcc" set PKGMSC=--msvc-syntax\r
+pkg-config --cflags --short-errors "guile-2.0" > %OUTDIR%\guile.tmp\r
+if not ERRORLEVEL 1 set /P GUILECFLAGS= < %OUTDIR%\guile.tmp\r
+\r
+pkg-config --libs --static --short-errors %PKGMSC% "guile-2.0" > %OUTDIR%\guile.tmp\r
+if not ERRORLEVEL 1 set /P GUILELIBS= < %OUTDIR%\guile.tmp\r
+\r
+if not "%GUILECFLAGS%" == "" goto GuileDone\r
+\r
+echo Checking for Guile 1.8\r
+pkg-config --cflags --short-errors "guile-1.8" > %OUTDIR%\guile.tmp\r
+if not ERRORLEVEL 1 set /P GUILECFLAGS= < %OUTDIR%\guile.tmp\r
+\r
+pkg-config --libs --static --short-errors %PKGMSC% "guile-1.8" > %OUTDIR%\guile.tmp\r
+if not ERRORLEVEL 1 set /P GUILELIBS= < %OUTDIR%\guile.tmp\r
+\r
+if not "%GUILECFLAGS%" == "" goto GuileDone\r
+\r
+echo No Guile found, building without Guile\r
+goto GuileDone\r
+\r
+:NoPkgCfg\r
+echo pkg-config not found, building without Guile\r
+\r
+:GuileDone\r
+if "%GUILECFLAGS%" == "" goto :EOF\r
+\r
+echo Guile found, building with Guile\r
+set "GUILECFLAGS=%GUILECFLAGS% -DHAVE_GUILE"\r
+goto :EOF\r
+\r
:Usage\r
echo Usage: %0 [options] [gcc]\r
echo Options:\r
echo. (MSVC build always makes both debug and release)\r
echo. --without-guile Do not compile Guile support even if found\r
echo. --help Display these instructions and exit\r
-:BuildEnd\r
-@echo off\r
-set GUILELIBS=\r
-set GUILECFLAGS=\r
-set PKGMSC=\r
-set OPT=\r
+goto :EOF\r
+\r
+:Reset\r
set COMPILER=\r
+set DEBUG=\r
+set GUILE=\r
+set GUILECFLAGS=\r
+set GUILELIBS=\r
+set LINKOPTS=\r
+set MAKE=\r
set NOGUILE=\r
-echo on\r
+set OPTS=\r
+set OUTDIR=\r
+set PKGMSC=\r
+goto :EOF\r
#include "filedef.h"
#include "commands.h"
#include "variable.h"
+#include "os.h"
#include "debug.h"
#include <string.h>
{
++dead_children;
- if (job_rfd >= 0)
- {
- close (job_rfd);
- job_rfd = -1;
- }
+ jobserver_signal ();
#ifdef __EMX__
/* The signal handler must called only once! */
/* 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;
}
#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.
# 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,
}
/* 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__ */
/* 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. */
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 "));
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);
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;
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)
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
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);
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"
/* 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
\f
/* Mask of signals that are being caught with fatal_error_signal. */
-#ifdef POSIX
+#ifdef POSIX
sigset_t fatal_signal_set;
#else
# ifdef HAVE_SIGSETMASK
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 > 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"));
+ if (!job_slots)
+ jobserver_parse_arg (jobserver_fds);
- O (error, NILF,
- _("warning: jobserver unavailable: using -j1. Add '+' to parent make rule."));
- job_slots = 1;
- job_fds[0] = job_fds[1] = -1;
- }
-#endif
+ else if (! restarts)
+ O (error, NILF,
+ _("warning: -jN forced in submake: disabling jobserver mode."));
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
}
#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.
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. */
{
#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. */
- master_job_slots = job_slots;
+ jobserver_setup (job_slots - 1);
-#ifdef WINDOWS32
- /* We're using the jobserver so set job_slots to 0. */
+ /* We're using the jobserver so set job_slots to 0. */
+ master_job_slots = job_slots;
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
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);
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,
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);
}
if (master_job_slots)
{
/* We didn't write one for ourself, so start at 1. */
- unsigned int tcnt = 1;
-
-#ifdef WINDOWS32
- while (acquire_jobserver_semaphore ())
- ++tcnt;
-#else
- /* Close the write side, so the read() won't hang. */
- close (job_fds[1]);
+ unsigned int tokens = 1 + jobserver_acquire_all ();
- 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;
}
}
\f
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
<File\r
RelativePath=".\w32\pathstuff.c">\r
</File>\r
+ <File\r
+ RelativePath=".\w32\w32os.c">\r
+ </File>\r
<File\r
RelativePath=".\w32\subproc\sub_proc.c">\r
</File>\r
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
--- /dev/null
+/* 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
main.c
misc.c
output.c
+posixos.c
read.c
remake.c
remote-cstms.c
vmsfunctions.c
vmsjobs.c
vpath.c
+w32/w32os.c
--- /dev/null
+/* 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 */
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);
}
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));
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));
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
+++ /dev/null
-@if "%COMPILER%" == "gcc" GoTo GCCBuild\r
-if not exist .\WinDebug\nul mkdir .\WinDebug\r
-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\r
-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\r
-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\r
-lib.exe /NOLOGO /OUT:.\WinDebug\subproc.lib .\WinDebug/misc.obj .\WinDebug/sub_proc.obj .\WinDebug/w32err.obj\r
-if not exist .\WinRel\nul mkdir .\WinRel\r
-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\r
-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\r
-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\r
-lib.exe /NOLOGO /OUT:.\WinRel\subproc.lib .\WinRel/misc.obj .\WinRel/sub_proc.obj .\WinRel/w32err.obj\r
-GoTo BuildEnd\r
-:GCCBuild\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I.. -I. -I../include -I../.. -DWINDOWS32 -c misc.c -o ../../w32_misc.o\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I.. -I. -I../include -I../.. -DWINDOWS32 -c sub_proc.c -o ../../sub_proc.o\r
-gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I.. -I. -I../include -I../.. -DWINDOWS32 -c w32err.c -o ../../w32err.o\r
-:BuildEnd\r
-\r
-@echo off\r
-rem Copyright (C) 1996-2016 Free Software Foundation, Inc.\r
-rem This file is part of GNU Make.\r
-rem\r
-rem GNU Make is free software; you can redistribute it and/or modify it under\r
-rem the terms of the GNU General Public License as published by the Free\r
-rem Software Foundation; either version 3 of the License, or (at your option)\r
-rem any later version.\r
-rem\r
-rem GNU Make is distributed in the hope that it will be useful, but WITHOUT\r
-rem ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
-rem FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for.\r
-rem more details.\r
-rem\r
-rem You should have received a copy of the GNU General Public License along\r
-rem with this program. If not, see <http://www.gnu.org/licenses/>.\r
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;
}
/*
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);
--- /dev/null
+/* 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;
+}