From: Paul Smith Date: Sun, 6 Mar 2016 18:29:43 +0000 (-0500) Subject: Extract jobserver implementation into OS-specific files. X-Git-Tag: 4.1.90~30 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fb7a7adc8a54bfd33ca939f7ab6e039a3b2c3355;p=thirdparty%2Fmake.git 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 00cfa73d..3990c553 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,12 @@ make *.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 d0291d0c..8c102a3c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -41,14 +41,14 @@ endif 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 511288ff..2007a3b5 100644 --- a/NMakefile.template +++ b/NMakefile.template @@ -107,6 +107,7 @@ OBJS = \ $(OUTDIR)/dirent.obj \ $(OUTDIR)/pathstuff.obj \ $(OUTDIR)/posixfcn.obj \ + $(OUTDIR)/w32os.obj \ $(guile) $(OUTDIR)/make.exe: $(OUTDIR) $(OBJS) @@ -127,3 +128,5 @@ $(OUTDIR)/posixfcn.obj : w32/compat/posixfcn.c $(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 d7fedb17..3ac3354f 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 @@ also provide you with these dependencies or a URL where to download 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 @@ Building with (MinGW-)GCC using build_w32.bat 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 @@ Building with (MSVC++-)cl using build_w32.bat or NMakefile 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 f720776f..bef80f92 --- a/build_w32.bat +++ b/build_w32.bat @@ -15,283 +15,217 @@ rem rem You should have received a copy of the GNU General Public License along rem with this program. If not, see . -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 + +if "%1" == "-h" goto Usage +if "%1" == "--help" goto Usage + +set MAKE=gnumake +set GUILE=Y +set COMPILER=msvc -rem Guile configuration -set GUILECFLAGS= -set GUILELIBS= -set NOGUILE= -set OPT=-O2 -set COMPILER= -set PKGMSC= :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 +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 +:DoneSW echo. -echo "Creating the subproc library" -%ComSpec% /c build.bat -cd ..\.. +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 -if exist link.dbg del link.dbg -if exist link.rel del link.rel echo. -echo "Creating GNU Make for Windows 9X/NT/2K/XP/Vista/7/8" -if "%COMPILER%" == "gcc" GoTo GCCBuild -set make=gnumake +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 +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 +echo %OUTDIR%\%1.obj >>%OUTDIR%\link.sc +goto :EOF + +:GccCompile +:: GCC 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 +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 -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 +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 -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 +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 -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 +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. --debug For GCC only, make a debug build 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 7717b269..321a1e82 100644 --- a/job.c +++ b/job.c @@ -23,6 +23,7 @@ this program. If not, see . */ #include "filedef.h" #include "commands.h" #include "variable.h" +#include "os.h" #include "debug.h" #include @@ -541,11 +542,7 @@ child_handler (int sig UNUSED) { ++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 @@ free_child (struct child *child) /* 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 @@ unblock_sigs (void) } #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 @@ start_job_command (struct child *child) # 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 @@ start_job_command (struct child *child) } /* 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 @@ start_job_command (struct child *child) /* 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 @@ new_job (struct file *file) 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 @@ new_job (struct file *file) 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 @@ new_job (struct file *file) 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 @@ new_job (struct file *file) 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 @@ new_job (struct file *file) 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 0beff738..4d7f53fb 100644 --- a/job.h +++ b/job.h @@ -115,6 +115,8 @@ struct child 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 df5540a8..8b3dcfa7 100644 --- a/main.c +++ b/main.c @@ -15,6 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "makeint.h" +#include "os.h" #include "filedef.h" #include "dep.h" #include "variable.h" @@ -270,15 +271,12 @@ static unsigned int inf_jobs = 0; /* 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 @@ struct output make_sync; /* 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 @@ main (int argc, char **argv, char **envp) 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 @@ -1902,7 +1848,7 @@ main (int argc, char **argv, char **envp) } #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 @@ main (int argc, char **argv, char **envp) 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 @@ main (int argc, char **argv, char **envp) #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 @@ -2489,10 +2392,6 @@ main (int argc, char **argv, char **envp) 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 @@ clean_jobserver (int status) 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 @@ clean_jobserver (int status) 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 @@ clean_jobserver (int status) 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; } } diff --git a/maintMakefile b/maintMakefile index 3edf8d75..f7bdf002 100644 --- a/maintMakefile +++ b/maintMakefile @@ -276,7 +276,7 @@ changelog-check: 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 01b1f0d2..bcc2e8bc 100644 --- a/make_msvc_net2003.vcproj +++ b/make_msvc_net2003.vcproj @@ -234,6 +234,9 @@ + + diff --git a/makeint.h b/makeint.h index 7e191d91..bf75d0a9 100644 --- a/makeint.h +++ b/makeint.h @@ -623,8 +623,6 @@ extern int batch_mode_shell; 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 00000000..545018f5 --- /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 . */ + + +/* 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 fce6f362..061ff2b9 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -32,6 +32,7 @@ load.c main.c misc.c output.c +posixos.c read.c remake.c remote-cstms.c @@ -43,3 +44,4 @@ variable.h vmsfunctions.c vmsjobs.c vpath.c +w32/w32os.c diff --git a/posixos.c b/posixos.c new file mode 100644 index 00000000..443c1159 --- /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 . */ + +#include "makeint.h" + +#include + +#ifdef HAVE_FCNTL_H +# include +#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 09cb124c..e422d488 100644 --- a/vmsfunctions.c +++ b/vmsfunctions.c @@ -118,7 +118,7 @@ closedir (DIR *dir) 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 5ba19468..4afa4b47 100644 --- a/w32/include/sub_proc.h +++ b/w32/include/sub_proc.h @@ -32,11 +32,11 @@ this program. If not, see . */ 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 @@ EXTERN_DECL(HANDLE process_easy, (char** argv, char** env, 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(int process_errcnt, (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 diff --git a/w32/subproc/build.bat b/w32/subproc/build.bat deleted file mode 100644 index bb6b24da..00000000 --- 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 . diff --git a/w32/subproc/sub_proc.c b/w32/subproc/sub_proc.c index aa07b7bc..2442411a 100644 --- a/w32/subproc/sub_proc.c +++ b/w32/subproc/sub_proc.c @@ -61,124 +61,26 @@ static sub_process *proc_array[MAXIMUM_WAIT_OBJECTS]; 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 @@ process_begin( 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 00000000..0b572fe3 --- /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 . */ + +#include "makeint.h" + +#include +#include + +#include +#include +#include +#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; +}