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.
This commit is contained in:
Paul Smith 2016-03-06 13:29:43 -05:00
parent 4f8be4bb28
commit fb7a7adc8a
19 changed files with 912 additions and 799 deletions

6
.gitignore vendored
View file

@ -34,6 +34,12 @@ make
*.pdb *.pdb
*.sbr *.sbr
# Windows build artifacts
/WinDebug/
/WinRel/
/GccDebug/
/GccRel/
# Distribution artifacts # Distribution artifacts
.dep_segment .dep_segment
.check-git-HEAD .check-git-HEAD

View file

@ -41,14 +41,14 @@ endif
make_SOURCES = ar.c arscan.c commands.c default.c dir.c expand.c file.c \ 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 \ 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 \ loadapi.c main.c misc.c output.c posixos.c read.c remake.c \
signame.c strcache.c variable.c version.c vpath.c hash.c \ rule.c signame.c strcache.c variable.c version.c vpath.c \
$(remote) hash.c $(remote)
EXTRA_make_SOURCES = vmsjobs.c remote-stub.c remote-cstms.c 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 \ 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@ \ make_LDADD = @LIBOBJS@ @ALLOCA@ $(GLOBLIB) @GETLOADAVG_LIBS@ @LIBINTL@ \
$(GUILE_LIBS) $(GUILE_LIBS)

View file

@ -107,6 +107,7 @@ OBJS = \
$(OUTDIR)/dirent.obj \ $(OUTDIR)/dirent.obj \
$(OUTDIR)/pathstuff.obj \ $(OUTDIR)/pathstuff.obj \
$(OUTDIR)/posixfcn.obj \ $(OUTDIR)/posixfcn.obj \
$(OUTDIR)/w32os.obj \
$(guile) $(guile)
$(OUTDIR)/make.exe: $(OUTDIR) $(OBJS) $(OUTDIR)/make.exe: $(OUTDIR) $(OBJS)
@ -127,3 +128,5 @@ $(OUTDIR)/posixfcn.obj : w32/compat/posixfcn.c
$(CC) $(CFLAGS) /c $? $(CC) $(CFLAGS) /c $?
$(OUTDIR)/pathstuff.obj : w32/pathstuff.c $(OUTDIR)/pathstuff.obj : w32/pathstuff.c
$(CC) $(CFLAGS) /c $? $(CC) $(CFLAGS) /c $?
$(OUTDIR)/w32os.obj : w32/w32os.c
$(CC) $(CFLAGS) /c $?

View file

@ -1,11 +1,12 @@
This version of GNU make has been tested on This version of GNU make has been tested on:
Microsoft Windows 2000/XP/2003/Vista/7/2008. Microsoft Windows 2000/XP/2003/Vista/7/8/10
It has also been used on Windows 95/98/NT, and on OS/2. 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 It also builds with MSVC 2.x, 4.x, 5.x, 6.x, 2003, and 14 (2015) as
with .NET 7.x and .NET 2003. well as with .NET 7.x and .NET 2003.
As of version 4.0, a build with Guile is supported (tested with Guile 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 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 them. A precompiled 32-bit Windows build of Guile is available from
the ezwinports site mentioned above. the ezwinports site mentioned above.
The Windows 32-bit port of GNU make is maintained jointly by various The Windows port of GNU make is maintained jointly by various people.
people. It was originally made by Rob Tulloh. It was originally made by Rob Tulloh.
It is currently maintained by Eli Zaretskii.
Do this first, regardless of the build method you choose: 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 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 The batch file will probe for Guile installation, and will build
gnumake.exe with Guile if it finds it. If you have Guile 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 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 ... ... OR ...

484
build_w32.bat Normal file → Executable file
View file

@ -15,283 +15,217 @@ rem
rem You should have received a copy of the GNU General Public License along rem You should have received a copy of the GNU General Public License along
rem with this program. If not, see <http://www.gnu.org/licenses/>. rem with this program. If not, see <http://www.gnu.org/licenses/>.
if "%1" == "-h" GoTo Usage call :Reset
if "%1" == "--help" GoTo Usage
if not exist config.h.W32.template GoTo NotSCM if "%1" == "-h" goto Usage
sed -n "s/^AC_INIT(\[GNU make\],\[\([^]]\+\)\].*/s,%%VERSION%%,\1,g/p" configure.ac > config.h.W32.sed if "%1" == "--help" goto Usage
echo s,%%PACKAGE%%,make,g >> config.h.W32.sed
sed -f config.h.W32.sed config.h.W32.template > config.h.W32 set MAKE=gnumake
echo static const char *const GUILE_module_defn = ^" \> gmk-default.h set GUILE=Y
sed -e "s/;.*//" -e "/^[ \t]*$/d" -e "s/\"/\\\\\"/g" -e "s/$/ \\/" gmk-default.scm >> gmk-default.h set COMPILER=msvc
echo ^";>> gmk-default.h
:NotSCM
copy config.h.W32 config.h
rem Guile configuration
set GUILECFLAGS=
set GUILELIBS=
set NOGUILE=
set OPT=-O2
set COMPILER=
set PKGMSC=
:ParseSW :ParseSW
if "%1" == "--debug" GoTo SetOpt if "%1" == "--debug" goto SetDebug
if "%1" == "--without-guile" GoTo NoGuile if "%1" == "--without-guile" goto NoGuile
if "%1" == "gcc" GoTo SetCC if "%1" == "gcc" goto SetCC
if "%1" == "" GoTo ChkGuile if "%1" == "" goto DoneSW
:SetOpt
set OPT=-O0 :SetDebug
set DEBUG=Y
shift shift
GoTo ParseSW goto ParseSW
:NoGuile :NoGuile
set NOGUILE=Y set GUILE=N
echo "Building without Guile" echo Building without Guile
shift shift
GoTo ParseSW goto ParseSW
:SetCC :SetCC
set COMPILER=gcc set COMPILER=gcc
echo "Building with GCC" echo Building with GCC
shift 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
echo.
echo "Creating the subproc library"
%ComSpec% /c build.bat
cd ..\..
if exist link.dbg del link.dbg rem Build with Guile is supported only on NT and later versions
if exist link.rel del link.rel :DoneSW
echo. echo.
echo "Creating GNU Make for Windows 9X/NT/2K/XP/Vista/7/8" echo Creating GNU Make for Windows 9X/NT/2K/XP/Vista/7/8
if "%COMPILER%" == "gcc" GoTo GCCBuild if "%DEBUG%" == "Y" echo Building without compiler optimizations
set make=gnumake
if "%COMPILER%" == "gcc" goto GccBuild
set OUTDIR=.\WinRel
set "OPTS=/O2 /D NDEBUG"
set LINKOPTS=
if "%DEBUG%" == "Y" set OUTDIR=.\WinDebug
if "%DEBUG%" == "Y" set "OPTS=/Zi /Od /D _DEBUG"
if "%DEBUG%" == "Y" set LINKOPTS=/DEBUG
call :Build
goto Done
:GccBuild
set OUTDIR=.\GccRel
set OPTS=-O2
if "%DEBUG%" == "Y" set OPTS=-O0
if "%DEBUG%" == "Y" set OUTDIR=.\GccDebug
call :Build
goto Done
:Done
call :Reset
goto :EOF
:Build
:: Clean the directory if it exists
if exist %OUTDIR%\nul rmdir /S /Q %OUTDIR%
:: Recreate it
mkdir %OUTDIR%
mkdir %OUTDIR%\glob
mkdir %OUTDIR%\w32
mkdir %OUTDIR%\w32\compat
mkdir %OUTDIR%\w32\subproc
if "%GUILE%" == "Y" call :ChkGuile
echo.
echo Compiling %OUTDIR% version
if exist config.h.W32.template call :ConfigSCM
copy config.h.W32 %OUTDIR%\config.h
call :Compile ar
call :Compile arscan
call :Compile commands
call :Compile default
call :Compile dir
call :Compile expand
call :Compile file
call :Compile function
call :Compile getloadavg
call :Compile getopt
call :Compile getopt1
call :Compile glob\fnmatch
call :Compile glob\glob
call :Compile guile GUILE
call :Compile hash
call :Compile implicit
call :Compile job
call :Compile load
call :Compile loadapi
call :Compile main GUILE
call :Compile misc
call :Compile output
call :Compile read
call :Compile remake
call :Compile remote-stub
call :Compile rule
call :Compile signame
call :Compile strcache
call :Compile variable
call :Compile version
call :Compile vpath
call :Compile w32\compat\posixfcn
call :Compile w32\pathstuff
call :Compile w32\subproc\misc
call :Compile w32\subproc\sub_proc
call :Compile w32\subproc\w32err
call :Compile w32\w32os
if not "%COMPILER%" == "gcc" call :Compile w32\compat\dirent
call :Link
echo.
if not exist %OUTDIR%\%MAKE%.exe echo %OUTDIR% build FAILED!
if exist %OUTDIR%\%MAKE%.exe echo %OUTDIR% build succeeded.
goto :EOF
:Compile
set EXTRAS=
if "%2" == "GUILE" set "EXTRAS=%GUILECFLAGS%"
if "%COMPILER%" == "gcc" goto GccCompile
:: MSVC Compile
echo on echo on
if not exist .\WinDebug\nul mkdir .\WinDebug 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
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D TIVOLI /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c variable.c
echo WinDebug\variable.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c rule.c
echo WinDebug\rule.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c remote-stub.c
echo WinDebug\remote-stub.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c commands.c
echo WinDebug\commands.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c file.c
echo WinDebug\file.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c getloadavg.c
echo WinDebug\getloadavg.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c default.c
echo WinDebug\default.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c signame.c
echo WinDebug\signame.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c expand.c
echo WinDebug\expand.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c dir.c
echo WinDebug\dir.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od %GUILECFLAGS% /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c main.c
echo WinDebug\main.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c getopt1.c
echo WinDebug\getopt1.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c job.c
echo WinDebug\job.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c output.c
echo WinDebug\output.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c read.c
echo WinDebug\read.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c version.c
echo WinDebug\version.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c getopt.c
echo WinDebug\getopt.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c arscan.c
echo WinDebug\arscan.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c hash.c
echo WinDebug\hash.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c strcache.c
echo WinDebug\strcache.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c remake.c
echo WinDebug\remake.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c misc.c
echo WinDebug\misc.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c ar.c
echo WinDebug\ar.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c function.c
echo WinDebug\function.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c vpath.c
echo WinDebug\vpath.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c implicit.c
echo WinDebug\implicit.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c loadapi.c
echo WinDebug\loadapi.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c load.c
echo WinDebug\load.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c .\w32\compat\dirent.c
echo WinDebug\dirent.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c .\w32\compat\posixfcn.c
echo WinDebug\posixfcn.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c .\glob\glob.c
echo WinDebug\glob.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c .\glob\fnmatch.c
echo WinDebug\fnmatch.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c .\w32\pathstuff.c
echo WinDebug\pathstuff.obj >>link.dbg
cl.exe /nologo /MT /W4 /GX /Zi /YX /Od %GUILECFLAGS% /I . /I glob /I w32/include /D _DEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinDebug/ /Fp.\WinDebug/%make%.pch /Fo.\WinDebug/ /Fd.\WinDebug/%make%.pdb /c guile.c
echo WinDebug\guile.obj >>link.dbg
:LinkDbg
echo off
echo "Linking WinDebug/%make%.exe"
rem link.exe %GUILELIBS% kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib w32\subproc\windebug\subproc.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes /PDB:.\WinDebug/%make%.pdb /DEBUG /OUT:.\WinDebug/%make%.exe .\WinDebug/variable.obj .\WinDebug/rule.obj .\WinDebug/remote-stub.obj .\WinDebug/commands.obj .\WinDebug/file.obj .\WinDebug/getloadavg.obj .\WinDebug/default.obj .\WinDebug/signame.obj .\WinDebug/expand.obj .\WinDebug/dir.obj .\WinDebug/main.obj .\WinDebug/getopt1.obj .\WinDebug/job.obj .\WinDebug/output.obj .\WinDebug/read.obj .\WinDebug/version.obj .\WinDebug/getopt.obj .\WinDebug/arscan.obj .\WinDebug/remake.obj .\WinDebug/hash.obj .\WinDebug/strcache.obj .\WinDebug/misc.obj .\WinDebug/ar.obj .\WinDebug/function.obj .\WinDebug/vpath.obj .\WinDebug/implicit.obj .\WinDebug/dirent.obj .\WinDebug/glob.obj .\WinDebug/fnmatch.obj .\WinDebug/pathstuff.obj
echo %GUILELIBS% kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib w32\subproc\windebug\subproc.lib >>link.dbg
link.exe /NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes /PDB:.\WinDebug/%make%.pdb /DEBUG /OUT:.\WinDebug/%make%.exe @link.dbg
if not exist .\WinDebug/%make%.exe echo "WinDebug build failed"
if exist .\WinDebug/%make%.exe echo "WinDebug build succeeded!"
if not exist .\WinRel\nul mkdir .\WinRel
echo on
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /D TIVOLI /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c variable.c
echo WinRel\variable.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c rule.c
echo WinRel\rule.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c remote-stub.c
echo WinRel\remote-stub.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c commands.c
echo WinRel\commands.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c file.c
echo WinRel\file.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c getloadavg.c
echo WinRel\getloadavg.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c default.c
echo WinRel\default.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c signame.c
echo WinRel\signame.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c expand.c
echo WinRel\expand.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c dir.c
echo WinRel\dir.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 %GUILECFLAGS% /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c main.c
echo WinRel\main.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c getopt1.c
echo WinRel\getopt1.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c job.c
echo WinRel\job.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c output.c
echo WinRel\output.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c read.c
echo WinRel\read.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c version.c
echo WinRel\version.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c getopt.c
echo WinRel\getopt.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c arscan.c
echo WinRel\arscan.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c remake.c
echo WinRel\remake.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c hash.c
echo WinRel\hash.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c strcache.c
echo WinRel\strcache.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c misc.c
echo WinRel\misc.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c ar.c
echo WinRel\ar.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c function.c
echo WinRel\function.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c vpath.c
echo WinRel\vpath.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c implicit.c
echo WinRel\implicit.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c loadapi.c
echo WinRel\loadapi.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c load.c
echo WinRel\load.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c .\w32\compat\dirent.c
echo WinRel\dirent.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c .\w32\compat\posixfcn.c
echo WinRel\posixfcn.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c .\glob\glob.c
echo WinRel\glob.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c .\glob\fnmatch.c
echo WinRel\fnmatch.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c .\w32\pathstuff.c
echo WinRel\pathstuff.obj >>link.rel
cl.exe /nologo /MT /W4 /GX /YX /O2 %GUILECFLAGS% /I . /I glob /I w32/include /D NDEBUG /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR.\WinRel/ /Fp.\WinRel/%make%.pch /Fo.\WinRel/ /c guile.c
echo WinRel\guile.obj >>link.rel
:LinkRel
echo off
echo "Linking WinRel/%make%.exe"
rem link.exe %GUILELIBS% kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib w32\subproc\winrel\subproc.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:no /PDB:.\WinRel/%make%.pdb /OUT:.\WinRel/%make%.exe .\WinRel/variable.obj .\WinRel/rule.obj .\WinRel/remote-stub.obj .\WinRel/commands.obj .\WinRel/file.obj .\WinRel/getloadavg.obj .\WinRel/default.obj .\WinRel/signame.obj .\WinRel/expand.obj .\WinRel/dir.obj .\WinRel/main.obj .\WinRel/getopt1.obj .\WinRel/job.obj .\WinRel/output.obj .\WinRel/read.obj .\WinRel/version.obj .\WinRel/getopt.obj .\WinRel/arscan.obj .\WinRel/remake.obj .\WinRel/misc.obj .\WinRel/hash.obj .\WinRel/strcache.obj .\WinRel/ar.obj .\WinRel/function.obj .\WinRel/vpath.obj .\WinRel/implicit.obj .\WinRel/dirent.obj .\WinRel/glob.obj .\WinRel/fnmatch.obj .\WinRel/pathstuff.obj
echo %GUILELIBS% kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib w32\subproc\winrel\subproc.lib >>link.rel
link.exe /NOLOGO /SUBSYSTEM:console /INCREMENTAL:no /PDB:.\WinRel/%make%.pdb /OUT:.\WinRel/%make%.exe @link.rel
if not exist .\WinRel/%make%.exe echo "WinRel build failed"
if exist .\WinRel/%make%.exe echo "WinRel build succeeded!"
set make=
GoTo BuildEnd
:GCCBuild
echo on
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c variable.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c rule.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c remote-stub.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c commands.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c file.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c getloadavg.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c default.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c signame.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c expand.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c dir.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H %GUILECFLAGS% -c main.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c getopt1.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c job.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c output.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c read.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c version.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c getopt.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c arscan.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c remake.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c hash.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c strcache.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c misc.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c ar.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c function.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c vpath.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c implicit.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c loadapi.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c load.c
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c ./glob/glob.c -o glob.o
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c ./glob/fnmatch.c -o fnmatch.o
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c ./w32/pathstuff.c -o pathstuff.o
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c ./w32/compat/posixfcn.c -o posixfcn.o
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% %GUILECFLAGS% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c guile.c
:LinkGCC
@echo off @echo off
Rem The version NN of libgnumake-NN.dll.a should be bumped whenever echo %OUTDIR%\%1.obj >>%OUTDIR%\link.sc
Rem the API changes in binary-incompatible manner. goto :EOF
@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 :GccCompile
@GoTo BuildEnd :: GCC Compile
echo on
gcc -mthreads -Wall -gdwarf-2 -g3 %OPTS% -I%OUTDIR% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H %EXTRAS% -o %OUTDIR%\%1.o -c %1.c
@echo off
goto :EOF
:Link
echo Linking %OUTDIR%/%MAKE%.exe
if "%COMPILER%" == "gcc" goto GccLink
:: MSVC Link
echo %GUILELIBS% kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib >>%OUTDIR%\link.sc
echo on
link.exe /NOLOGO /SUBSYSTEM:console /PDB:%OUTDIR%\%MAKE%.pdb %LINKOPTS% /OUT:%OUTDIR%\%MAKE%.exe @%OUTDIR%\link.sc
@echo off
goto :EOF
:GccLink
:: GCC Link
echo on
gcc -mthreads -gdwarf-2 -g3 -o %OUTDIR%\%MAKE%.exe %OUTDIR%\variable.o %OUTDIR%\rule.o %OUTDIR%\remote-stub.o %OUTDIR%\commands.o %OUTDIR%\file.o %OUTDIR%\getloadavg.o %OUTDIR%\default.o %OUTDIR%\signame.o %OUTDIR%\expand.o %OUTDIR%\dir.o %OUTDIR%\main.o %OUTDIR%\getopt1.o %OUTDIR%\guile.o %OUTDIR%\job.o %OUTDIR%\output.o %OUTDIR%\read.o %OUTDIR%\version.o %OUTDIR%\getopt.o %OUTDIR%\arscan.o %OUTDIR%\remake.o %OUTDIR%\misc.o %OUTDIR%\hash.o %OUTDIR%\strcache.o %OUTDIR%\ar.o %OUTDIR%\function.o %OUTDIR%\vpath.o %OUTDIR%\implicit.o %OUTDIR%\loadapi.o %OUTDIR%\load.o %OUTDIR%\glob\glob.o %OUTDIR%\glob\fnmatch.o %OUTDIR%\w32\pathstuff.o %OUTDIR%\w32\compat\posixfcn.o %OUTDIR%\w32\w32os.o %OUTDIR%\w32\subproc\misc.o %OUTDIR%\w32\subproc\sub_proc.o %OUTDIR%\w32\subproc\w32err.o %GUILELIBS% -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -Wl,--out-implib=%OUTDIR%\libgnumake-1.dll.a
@echo off
goto :EOF
:ConfigSCM
echo Generating config from SCM templates
sed -n "s/^AC_INIT(\[GNU make\],\[\([^]]\+\)\].*/s,%%VERSION%%,\1,g/p" configure.ac > %OUTDIR%\config.h.W32.sed
echo s,%%PACKAGE%%,make,g >> %OUTDIR%\config.h.W32.sed
sed -f %OUTDIR%\config.h.W32.sed config.h.W32.template > config.h.W32
echo static const char *const GUILE_module_defn = ^" \> gmk-default.h
sed -e "s/;.*//" -e "/^[ \t]*$/d" -e "s/\"/\\\\\"/g" -e "s/$/ \\\/" gmk-default.scm >> gmk-default.h
echo ^";>> gmk-default.h
goto :EOF
:ChkGuile
if not "%OS%" == "Windows_NT" goto NoGuile
pkg-config --help > %OUTDIR%\guile.tmp 2> NUL
if ERRORLEVEL 1 goto NoPkgCfg
echo Checking for Guile 2.0
if not "%COMPILER%" == "gcc" set PKGMSC=--msvc-syntax
pkg-config --cflags --short-errors "guile-2.0" > %OUTDIR%\guile.tmp
if not ERRORLEVEL 1 set /P GUILECFLAGS= < %OUTDIR%\guile.tmp
pkg-config --libs --static --short-errors %PKGMSC% "guile-2.0" > %OUTDIR%\guile.tmp
if not ERRORLEVEL 1 set /P GUILELIBS= < %OUTDIR%\guile.tmp
if not "%GUILECFLAGS%" == "" goto GuileDone
echo Checking for Guile 1.8
pkg-config --cflags --short-errors "guile-1.8" > %OUTDIR%\guile.tmp
if not ERRORLEVEL 1 set /P GUILECFLAGS= < %OUTDIR%\guile.tmp
pkg-config --libs --static --short-errors %PKGMSC% "guile-1.8" > %OUTDIR%\guile.tmp
if not ERRORLEVEL 1 set /P GUILELIBS= < %OUTDIR%\guile.tmp
if not "%GUILECFLAGS%" == "" goto GuileDone
echo No Guile found, building without Guile
goto GuileDone
:NoPkgCfg
echo pkg-config not found, building without Guile
:GuileDone
if "%GUILECFLAGS%" == "" goto :EOF
echo Guile found, building with Guile
set "GUILECFLAGS=%GUILECFLAGS% -DHAVE_GUILE"
goto :EOF
:Usage :Usage
echo Usage: %0 [options] [gcc] echo Usage: %0 [options] [gcc]
echo Options: 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. (MSVC build always makes both debug and release)
echo. --without-guile Do not compile Guile support even if found echo. --without-guile Do not compile Guile support even if found
echo. --help Display these instructions and exit echo. --help Display these instructions and exit
:BuildEnd goto :EOF
@echo off
set GUILELIBS= :Reset
set GUILECFLAGS=
set PKGMSC=
set OPT=
set COMPILER= set COMPILER=
set DEBUG=
set GUILE=
set GUILECFLAGS=
set GUILELIBS=
set LINKOPTS=
set MAKE=
set NOGUILE= set NOGUILE=
echo on set OPTS=
set OUTDIR=
set PKGMSC=
goto :EOF

196
job.c
View file

@ -23,6 +23,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include "filedef.h" #include "filedef.h"
#include "commands.h" #include "commands.h"
#include "variable.h" #include "variable.h"
#include "os.h"
#include "debug.h" #include "debug.h"
#include <string.h> #include <string.h>
@ -541,11 +542,7 @@ child_handler (int sig UNUSED)
{ {
++dead_children; ++dead_children;
if (job_rfd >= 0) jobserver_signal ();
{
close (job_rfd);
job_rfd = -1;
}
#ifdef __EMX__ #ifdef __EMX__
/* The signal handler must called only once! */ /* 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 /* If we're using the jobserver and this child is not the only outstanding
job, put a token back into the pipe for it. */ job, put a token back into the pipe for it. */
#ifdef WINDOWS32 if (jobserver_enabled () && jobserver_tokens > 1)
if (has_jobserver_semaphore () && jobserver_tokens > 1)
{ {
if (! release_jobserver_semaphore ()) jobserver_release (1);
{
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"));
DB (DB_JOBS, (_("Released token for child %p (%s).\n"), DB (DB_JOBS, (_("Released token for child %p (%s).\n"),
child, child->file->name)); child, child->file->name));
} }
#endif
--jobserver_tokens; --jobserver_tokens;
@ -1092,60 +1066,6 @@ unblock_sigs (void)
} }
#endif #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. /* Start a job to run the commands specified in CHILD.
CHILD is updated to reflect the commands and ID of the child process. 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__ # ifdef __EMX__
/* If we aren't running a recursive command and we have a jobserver /* If we aren't running a recursive command and we have a jobserver
pipe, close it before exec'ing. */ pipe, close it before exec'ing. */
if (!(flags & COMMANDS_RECURSE) && job_fds[0] >= 0) if (!(flags & COMMANDS_RECURSE) && jobserver_enabled ())
{ jobserver_pre_child ();
CLOSE_ON_EXEC (job_fds[0]);
CLOSE_ON_EXEC (job_fds[1]);
}
if (job_rfd >= 0)
CLOSE_ON_EXEC (job_rfd);
/* Never use fork()/exec() here! Use spawn() instead in exec_command() */ /* Never use fork()/exec() here! Use spawn() instead in exec_command() */
child->pid = child_execute_job (child->good_stdin ? FD_STDIN : bad_stdin, 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 */ /* undo CLOSE_ON_EXEC() after the child process has been started */
if (!(flags & COMMANDS_RECURSE) && job_fds[0] >= 0) if (!(flags & COMMANDS_RECURSE) && jobserver_enabled ())
{ jobserver_post_child ();
fcntl (job_fds[0], F_SETFD, 0);
fcntl (job_fds[1], F_SETFD, 0);
}
if (job_rfd >= 0)
fcntl (job_rfd, F_SETFD, 0);
#else /* !__EMX__ */ #else /* !__EMX__ */
@ -1554,15 +1464,10 @@ start_job_command (struct child *child)
/* We are the child side. */ /* We are the child side. */
unblock_sigs (); unblock_sigs ();
/* If we aren't running a recursive command and we have a jobserver /* If we AREN'T running a recursive command and we have a jobserver,
pipe, close it before exec'ing. */ clear it before exec'ing. */
if (!(flags & COMMANDS_RECURSE) && job_fds[0] >= 0) if (!(flags & COMMANDS_RECURSE) && jobserver_enabled ())
{ jobserver_clear ();
close (job_fds[0]);
close (job_fds[1]);
}
if (job_rfd >= 0)
close (job_rfd);
#ifdef SET_STACK_SIZE #ifdef SET_STACK_SIZE
/* Reset limits, if necessary. */ /* 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; just once). Also more thought needs to go into the entire algorithm;
this is where the old parallel job code waits, so... */ this is where the old parallel job code waits, so... */
#ifdef WINDOWS32 else if (jobserver_enabled ())
else if (has_jobserver_semaphore ())
#else
else if (job_fds[0] >= 0)
#endif
while (1) while (1)
{ {
int got_token; int got_token;
#ifndef WINDOWS32
char token;
int saved_errno;
#endif
DB (DB_JOBS, ("Need a job token; we %shave children\n", DB (DB_JOBS, ("Need a job token; we %shave children\n",
children ? "" : "don't ")); children ? "" : "don't "));
@ -1972,36 +1869,8 @@ new_job (struct file *file)
if (!jobserver_tokens) if (!jobserver_tokens)
break; break;
#ifndef WINDOWS32 /* Prepare for jobserver token acquisition. */
/* Read a token. As long as there's no token available we'll block. jobserver_pre_acquire ();
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
/* Reap anything that's currently waiting. */ /* Reap anything that's currently waiting. */
reap_children (0, 0); reap_children (0, 0);
@ -2010,8 +1879,7 @@ new_job (struct file *file)
can run now (i.e., waiting for load). */ can run now (i.e., waiting for load). */
start_waiting_jobs (); start_waiting_jobs ();
/* If our "free" slot has become available, use it; we don't need an /* If our "free" slot is available, use it; we don't need a token. */
actual token. */
if (!jobserver_tokens) if (!jobserver_tokens)
break; break;
@ -2020,26 +1888,8 @@ new_job (struct file *file)
if (!children) if (!children)
O (fatal, NILF, "INTERNAL: no children as we go to sleep on read\n"); O (fatal, NILF, "INTERNAL: no children as we go to sleep on read\n");
#ifdef WINDOWS32 /* Get a token. */
/* On Windows we simply wait for the jobserver semaphore to become got_token = jobserver_acquire (waiting_jobs != NULL);
* 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
/* If we got one, we're done here. */ /* If we got one, we're done here. */
if (got_token == 1) if (got_token == 1)
@ -2048,16 +1898,6 @@ new_job (struct file *file)
c, c->file->name)); c, c->file->name));
break; 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 #endif

2
job.h
View file

@ -115,6 +115,8 @@ struct child
extern struct child *children; extern struct child *children;
/* A signal handler for SIGCHLD, if needed. */
RETSIGTYPE child_handler (int sig);
int is_bourne_compatible_shell(const char *path); int is_bourne_compatible_shell(const char *path);
void new_job (struct file *file); void new_job (struct file *file);
void reap_children (int block, int err); void reap_children (int block, int err);

217
main.c
View file

@ -15,6 +15,7 @@ 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 program. If not, see <http://www.gnu.org/licenses/>. */
#include "makeint.h" #include "makeint.h"
#include "os.h"
#include "filedef.h" #include "filedef.h"
#include "dep.h" #include "dep.h"
#include "variable.h" #include "variable.h"
@ -270,15 +271,12 @@ static unsigned int inf_jobs = 0;
/* File descriptors for the jobs pipe. */ /* File descriptors for the jobs pipe. */
char *jobserver_fds = 0; char *jobserver_fds = NULL;
int job_fds[2] = { -1, -1 };
int job_rfd = -1;
/* Handle for the mutex used on Windows to synchronize output of our /* Handle for the mutex used on Windows to synchronize output of our
children under -O. */ children under -O. */
char *sync_mutex = 0; char *sync_mutex = NULL;
/* Maximum load average at which multiple jobs will be run. /* Maximum load average at which multiple jobs will be run.
Negative values mean unlimited, while zero means limit to 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. */ /* Mask of signals that are being caught with fatal_error_signal. */
#ifdef POSIX #ifdef POSIX
sigset_t fatal_signal_set; sigset_t fatal_signal_set;
#else #else
# ifdef HAVE_SIGSETMASK # ifdef HAVE_SIGSETMASK
@ -1597,85 +1595,33 @@ main (int argc, char **argv, char **envp)
starting_directory = current_directory; starting_directory = current_directory;
#ifdef MAKE_JOBSERVER #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 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 FDs are valid before any other aspect of make has a chance to start
using them for something else. */ using them for something else. */
if (jobserver_fds) if (jobserver_fds)
{ {
/* Make sure the jobserver option has the proper format. */ /* The combination of jobserver_fds and !job_slots means we're using the
const char *cp = jobserver_fds; 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
#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
user set -j explicitly. This is broken; in this case obey the user user set -j explicitly. This is broken; in this case obey the user
(ignore the jobserver pipe for this make) but print a message. (ignore the jobserver for this make) but print a message. If we've
If we've restarted, we already printed this the first time. */ restarted, we already printed this the first time. */
if (!job_slots)
jobserver_parse_arg (jobserver_fds);
else if (! restarts)
O (error, NILF,
_("warning: -jN forced in submake: disabling jobserver mode."));
if (job_slots > 0) if (job_slots > 0)
{ {
if (! restarts) /* If job_slots is set now then we're not using jobserver */
O (error, NILF, jobserver_clear ();
_("warning: -jN forced in submake: disabling jobserver mode."));
}
#ifndef WINDOWS32
#ifdef HAVE_FCNTL
# define FD_OK(_f) ((fcntl ((_f), F_GETFD) != -1) || (errno != EBADF))
#else
# define FD_OK(_f) 1
#endif
/* Create a duplicate pipe, that will be closed in the SIGCHLD
handler. If this fails with EBADF, the parent has closed the pipe
on us because it didn't think we were a submake. If so, print a
warning then default to -j1. */
else if (!FD_OK (job_fds[0]) || !FD_OK (job_fds[1])
|| (job_rfd = dup (job_fds[0])) < 0)
{
if (errno != EBADF)
pfatal_with_name (_("dup jobserver"));
O (error, NILF,
_("warning: jobserver unavailable: using -j1. Add '+' to parent make rule."));
job_slots = 1;
job_fds[0] = job_fds[1] = -1;
}
#endif
if (job_slots > 0)
{
#ifdef WINDOWS32
free_jobserver_semaphore ();
#else
if (job_fds[0] >= 0)
close (job_fds[0]);
if (job_fds[1] >= 0)
close (job_fds[1]);
#endif
job_fds[0] = job_fds[1] = -1;
free (jobserver_fds); free (jobserver_fds);
jobserver_fds = 0; jobserver_fds = NULL;
} }
} }
#endif #endif
@ -1902,7 +1848,7 @@ main (int argc, char **argv, char **envp)
} }
#ifndef __EMX__ /* Don't use a SIGCHLD handler for OS/2 */ #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 /* Set up to handle children dying. This must be done before
reading in the makefiles so that 'shell' function calls will work. 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 functionality here and rely on the signal handler and counting
children. children.
If we're using the jobs pipe we need a signal handler so that If we're using the jobs pipe we need a signal handler so that SIGCHLD is
SIGCHLD is not ignored; we need it to interrupt the read(2) of the not ignored; we need it to interrupt the read(2) of the jobserver pipe if
jobserver pipe in job.c if we're waiting for a token. we're waiting for a token.
If none of these are true, we don't need a signal handler at all. */ 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 #endif
#ifdef MAKE_JOBSERVER #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) if (job_slots > 1)
{ {
#ifdef WINDOWS32 /* If we have >1 slot at this point, then we're a top-level make.
/* sub_proc.c cannot wait for more than MAXIMUM_WAIT_OBJECTS objects Set up the jobserver.
* and one of them is the job-server semaphore object. Limit the
* number of available job slots to (MAXIMUM_WAIT_OBJECTS - 1). */
if (job_slots >= MAXIMUM_WAIT_OBJECTS) Every make assumes that it always has one job it can run. For the
{
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
submakes it's the token they were given by their parent. 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 top make, we just subtract one from the number the user wants. */
want job_slots to be 0 to indicate we're using the jobserver. */
jobserver_setup (job_slots - 1);
/* We're using the jobserver so set job_slots to 0. */
master_job_slots = job_slots; master_job_slots = job_slots;
#ifdef WINDOWS32
/* We're using the jobserver so set job_slots to 0. */
job_slots = 0; job_slots = 0;
#else
while (--job_slots)
{
int r;
EINTRLOOP (r, write (job_fds[1], &c, 1));
if (r != 1)
pfatal_with_name (_("init jobserver pipe"));
}
#endif
/* Fill in the jobserver_fds for our children. */ /* Fill in the jobserver_fds for our children. */
jobserver_fds = jobserver_get_arg ();
#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
} }
#endif #endif
@ -2489,10 +2392,6 @@ main (int argc, char **argv, char **envp)
fflush (stdout); fflush (stdout);
fflush (stderr); fflush (stderr);
/* Close the dup'd jobserver pipe if we opened one. */
if (job_rfd >= 0)
close (job_rfd);
#ifdef _AMIGA #ifdef _AMIGA
exec_command (nargv); exec_command (nargv);
exit (0); exit (0);
@ -3444,13 +3343,7 @@ clean_jobserver (int status)
have written all our tokens so do that now. If tokens are left have written all our tokens so do that now. If tokens are left
after any other error code, that's bad. */ after any other error code, that's bad. */
#ifdef WINDOWS32 if (jobserver_enabled() && jobserver_tokens)
if (has_jobserver_semaphore () && jobserver_tokens)
#else
char token = '+';
if (job_fds[0] != -1 && jobserver_tokens)
#endif
{ {
if (status != 2) if (status != 2)
ON (error, NILF, ON (error, NILF,
@ -3459,18 +3352,7 @@ clean_jobserver (int status)
else else
/* Don't write back the "free" token */ /* Don't write back the "free" token */
while (--jobserver_tokens) while (--jobserver_tokens)
{ jobserver_release (0);
#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
}
} }
@ -3479,42 +3361,21 @@ clean_jobserver (int status)
if (master_job_slots) if (master_job_slots)
{ {
/* We didn't write one for ourself, so start at 1. */ /* We didn't write one for ourself, so start at 1. */
unsigned int tcnt = 1; unsigned int tokens = 1 + jobserver_acquire_all ();
#ifdef WINDOWS32 if (tokens != master_job_slots)
while (acquire_jobserver_semaphore ())
++tcnt;
#else
/* Close the write side, so the read() won't hang. */
close (job_fds[1]);
while (1)
{
int r;
EINTRLOOP (r, read (job_fds[0], &token, 1));
if (r != 1)
break;
++tcnt;
}
#endif
if (tcnt != master_job_slots)
ONN (error, NILF, ONN (error, NILF,
"INTERNAL: Exiting with %u jobserver tokens available; should be %u!", "INTERNAL: Exiting with %u jobserver tokens available; should be %u!",
tcnt, master_job_slots); tokens, master_job_slots);
#ifdef WINDOWS32 jobserver_clear ();
free_jobserver_semaphore ();
#else
close (job_fds[0]);
#endif
/* Clean out jobserver_fds so we don't pass this information to any /* 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 sub-makes. Also reset job_slots since it will be put on the command
line, not in MAKEFLAGS. */ line, not in MAKEFLAGS. */
job_slots = default_job_slots; job_slots = default_job_slots;
free (jobserver_fds); free (jobserver_fds);
jobserver_fds = 0; jobserver_fds = NULL;
} }
} }

View file

@ -276,7 +276,7 @@ changelog-check:
po-check: po-check:
if test -f po/POTFILES.in; then \ if test -f po/POTFILES.in; then \
grep '^[^#]' po/POTFILES.in | sort > $@-1; \ 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; \ diff -u $@-1 $@-2 || exit 1; \
rm -f $@-1 $@-2; \ rm -f $@-1 $@-2; \
fi fi

View file

@ -234,6 +234,9 @@
<File <File
RelativePath=".\w32\pathstuff.c"> RelativePath=".\w32\pathstuff.c">
</File> </File>
<File
RelativePath=".\w32\w32os.c">
</File>
<File <File
RelativePath=".\w32\subproc\sub_proc.c"> RelativePath=".\w32\subproc\sub_proc.c">
</File> </File>

View file

@ -623,8 +623,6 @@ extern int batch_mode_shell;
extern char cmd_prefix; extern char cmd_prefix;
extern unsigned int job_slots; extern unsigned int job_slots;
extern int job_fds[2];
extern int job_rfd;
#ifndef NO_FLOAT #ifndef NO_FLOAT
extern double max_load_average; extern double max_load_average;
#else #else

77
os.h Normal file
View file

@ -0,0 +1,77 @@
/* Declarations for operating system interfaces for GNU Make.
Copyright (C) 2016 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */
/* This section provides OS-specific functions to support the jobserver. */
#ifdef MAKE_JOBSERVER
/* Returns 1 if the jobserver is enabled, else 0. */
unsigned int jobserver_enabled ();
/* Called in the master instance to set up the jobserver initially. */
void jobserver_setup (int job_slots);
/* Called in a child instance to connect to the jobserver. */
void jobserver_parse_arg (const char* arg);
/* Returns an allocated buffer used to pass to child instances. */
char *jobserver_get_arg ();
/* Clear this instance's jobserver configuration. */
void jobserver_clear ();
/* Recover all the jobserver tokens and return the number we got. */
unsigned int jobserver_acquire_all ();
/* Release a jobserver token. If it fails and is_fatal is 1, fatal. */
void jobserver_release (int is_fatal);
/* Notify the jobserver that a child exited. */
void jobserver_signal ();
/* Get ready to start a non-recursive child. */
void jobserver_pre_child ();
/* Complete starting a non-recursive child. */
void jobserver_post_child ();
/* Set up to acquire a new token. */
void jobserver_pre_acquire ();
/* Wait until we can acquire a jobserver token.
TIMEOUT is 1 if we have other jobs waiting for the load to go down;
in this case we won't wait forever, so we can check the load.
Returns 1 if we got a token, or 0 if we stopped waiting due to a child
exiting or a timeout. */
int jobserver_acquire (int timeout);
#else
#define jobserver_enabled() (0)
#define jobserver_setup(_slots) (void)(0)
#define jobserver_parse_arg(_arg) (void)(0)
#define jobserver_get_arg() (NULL)
#define jobserver_clear() (void)(0)
#define jobserver_release(_fatal) (void)(0)
#define jobserver_acquire_all() (0)
#define jobserver_signal() (void)(0)
#define jobserver_pre_child() (void)(0)
#define jobserver_post_child() (void)(0)
#define jobserver_pre_acquire() (void)(0)
#define jobserver_acquire(_tmout) (0)
#endif

View file

@ -32,6 +32,7 @@ load.c
main.c main.c
misc.c misc.c
output.c output.c
posixos.c
read.c read.c
remake.c remake.c
remote-cstms.c remote-cstms.c
@ -43,3 +44,4 @@ variable.h
vmsfunctions.c vmsfunctions.c
vmsjobs.c vmsjobs.c
vpath.c vpath.c
w32/w32os.c

320
posixos.c Normal file
View file

@ -0,0 +1,320 @@
/* POSIX-based operating system interface for GNU Make.
Copyright (C) 2016 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */
#include "makeint.h"
#include <stdio.h>
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#include "debug.h"
#include "job.h"
#include "os.h"
#ifdef MAKE_JOBSERVER
/* This section provides OS-specific functions to support the jobserver. */
/* These track the state of the jobserver pipe. Passed to child instances. */
static int job_fds[2] = { -1, -1 };
/* Used to signal read() that a SIGCHLD happened. Always CLOEXEC. */
static int job_rfd = -1;
/* Token written to the pipe (could be any character...) */
static char token = '+';
static int
make_job_rfd ()
{
EINTRLOOP (job_rfd, dup (job_fds[0]));
if (job_rfd >= 0)
CLOSE_ON_EXEC (job_rfd);
return job_rfd;
}
void
jobserver_setup (int slots)
{
int r;
EINTRLOOP (r, pipe (job_fds));
if (r < 0)
pfatal_with_name (_("creating jobs pipe"));
if (make_job_rfd () < 0)
pfatal_with_name (_("duping jobs pipe"));
while (slots--)
{
EINTRLOOP (r, write (job_fds[1], &token, 1));
if (r != 1)
pfatal_with_name (_("init jobserver pipe"));
}
}
void
jobserver_parse_arg (const char* arg)
{
/* Given the command-line parameter, parse it. */
if (sscanf (arg, "%d,%d", &job_fds[0], &job_fds[1]) != 2)
OS (fatal, NILF,
_("internal error: invalid --jobserver-fds string '%s'"), arg);
DB (DB_JOBS,
(_("Jobserver client (fds %d,%d)\n"), job_fds[0], job_fds[1]));
#ifdef HAVE_FCNTL
# define FD_OK(_f) ((fcntl ((_f), F_GETFD) != -1) || (errno != EBADF))
#else
# define FD_OK(_f) 1
#endif
/* Create a duplicate pipe, that will be closed in the SIGCHLD handler. If
this fails with EBADF, the parent has closed the pipe on us because it
didn't think we were a submake. If so, warn then default to -j1. */
if (!FD_OK (job_fds[0]) || !FD_OK (job_fds[1]) || make_job_rfd () < 0)
{
if (errno != EBADF)
pfatal_with_name (_("dup jobserver"));
O (error, NILF,
_("warning: jobserver unavailable: using -j1. Add '+' to parent make rule."));
job_slots = 1;
job_fds[0] = job_fds[1] = -1;
}
}
char *
jobserver_get_arg ()
{
char *fds = xmalloc ((INTSTR_LENGTH * 2) + 2);
sprintf (fds, "%d,%d", job_fds[0], job_fds[1]);
return fds;
}
unsigned int
jobserver_enabled ()
{
return job_fds[0] >= 0;
}
void
jobserver_clear ()
{
if (job_fds[0] >= 0)
close (job_fds[0]);
if (job_fds[1] >= 0)
close (job_fds[1]);
if (job_rfd >= 0)
close (job_rfd);
job_fds[0] = job_fds[1] = job_rfd = -1;
}
void
jobserver_release (int is_fatal)
{
int r;
EINTRLOOP (r, write (job_fds[1], &token, 1));
if (r != 1)
{
if (is_fatal)
pfatal_with_name (_("write jobserver"));
perror_with_name ("write", "");
}
}
unsigned int
jobserver_acquire_all ()
{
unsigned int tokens = 0;
/* Close the write side, so the read() won't hang. */
close (job_fds[1]);
job_fds[1] = -1;
while (1)
{
char intake;
int r;
EINTRLOOP (r, read (job_fds[0], &intake, 1));
if (r != 1)
return tokens;
++tokens;
}
}
/* This is really only invoked on OS/2.
On POSIX we just call jobserver_clear() in the child process. */
void jobserver_pre_child ()
{
CLOSE_ON_EXEC (job_fds[0]);
CLOSE_ON_EXEC (job_fds[1]);
}
void jobserver_post_child ()
{
#if defined(F_GETFD) && defined(F_SETFD)
for (int i = 0; i < 2; ++i)
{
int flags;
EINTRLOOP (flags, fcntl (job_fds[i], F_GETFD));
if (flags >= 0)
{
int r;
EINTRLOOP (r, fcntl (job_fds[i], F_SETFD, flags & ~FD_CLOEXEC));
}
}
#endif
}
/* The acquire algorithm goes like this (from job.c):
Read a token. As long as there's no token available we'll block. We
enable interruptible system calls before the read(2) so that if we get a
SIGCHLD while we're waiting, we'll return with EINTR and we can process the
death(s) and return tokens to the free pool.
Once we return from the read, we immediately reinstate restartable system
calls. This allows us to not worry about checking for EINTR on all the
other system calls in the program.
There is one other twist: there is a span between the time reap_children()
does its last check for dead children and the time the read(2) call is
entered, below, where if a child dies we won't notice. This is extremely
serious as it could cause us to deadlock, given the right set of events.
To avoid this, we do the following: before we reap_children(), we dup(2)
the read FD on the jobserver pipe. The read(2) call below uses that new
FD. In the signal handler, we close that FD. That way, if a child dies
during the section mentioned above, the read(2) will be invoked with an
invalid FD and will return immediately with EBADF. */
static RETSIGTYPE
job_noop (int sig UNUSED)
{
}
/* Set the child handler action flags to FLAGS. */
static void
set_child_handler_action_flags (int set_handler, int set_alarm)
{
struct sigaction sa;
#ifdef __EMX__
/* The child handler must be turned off here. */
signal (SIGCHLD, SIG_DFL);
#endif
memset (&sa, '\0', sizeof sa);
sa.sa_handler = child_handler;
sa.sa_flags = set_handler ? 0 : SA_RESTART;
#if defined SIGCHLD
if (sigaction (SIGCHLD, &sa, NULL) < 0)
pfatal_with_name ("sigaction: SIGCHLD");
#endif
#if defined SIGCLD && SIGCLD != SIGCHLD
if (sigaction (SIGCLD, &sa, NULL) < 0)
pfatal_with_name ("sigaction: SIGCLD");
#endif
#if defined SIGALRM
if (set_alarm)
{
/* If we're about to enter the read(), set an alarm to wake up in a
second so we can check if the load has dropped and we can start more
work. On the way out, turn off the alarm and set SIG_DFL. */
if (set_handler)
{
sa.sa_handler = job_noop;
sa.sa_flags = 0;
if (sigaction (SIGALRM, &sa, NULL) < 0)
pfatal_with_name ("sigaction: SIGALRM");
alarm (1);
}
else
{
alarm (0);
sa.sa_handler = SIG_DFL;
sa.sa_flags = 0;
if (sigaction (SIGALRM, &sa, NULL) < 0)
pfatal_with_name ("sigaction: SIGALRM");
}
}
#endif
}
void
jobserver_signal ()
{
if (job_rfd >= 0)
{
close (job_rfd);
job_rfd = -1;
}
}
void
jobserver_pre_acquire ()
{
/* Make sure we have a dup'd FD. */
if (job_rfd < 0 && job_fds[0] >= 0)
{
DB (DB_JOBS, ("Duplicate the job FD\n"));
if (make_job_rfd () < 0)
pfatal_with_name (_("duping jobs pipe"));
}
}
int
jobserver_acquire (int timeout)
{
char intake;
int got_token;
int saved_errno;
/* Set interruptible system calls, and read() for a job token. */
set_child_handler_action_flags (1, timeout);
EINTRLOOP (got_token, read (job_rfd, &intake, 1));
saved_errno = errno;
set_child_handler_action_flags (0, timeout);
if (got_token == 1)
return 1;
/* If the error _wasn't_ expected (EINTR or EBADF), fatal. Otherwise,
go back and reap_children(), and try again. */
errno = saved_errno;
if (errno != EINTR && errno != EBADF)
pfatal_with_name (_("read jobs pipe"));
if (errno == EBADF)
DB (DB_JOBS, ("Read returned EBADF.\n"));
return 0;
}
#endif /* MAKE_JOBSERVER */

View file

@ -118,7 +118,7 @@ closedir (DIR *dir)
struct FAB *dfab = &dir->fab; struct FAB *dfab = &dir->fab;
struct NAM *dnam = (struct NAM *)(dfab->fab$l_nam); struct NAM *dnam = (struct NAM *)(dfab->fab$l_nam);
if (dnam != NULL) if (dnam != NULL)
free (dnam->nam$l_esa); free (dnam->nam$l_esa);
free (dnam); free (dnam);
free (dir); free (dir);
} }

View file

@ -32,11 +32,11 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
EXTERN_DECL(HANDLE process_init, (VOID_DECL)); EXTERN_DECL(HANDLE process_init, (VOID_DECL));
EXTERN_DECL(HANDLE process_init_fd, (HANDLE stdinh, HANDLE stdouth, 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, 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, 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(long process_file_io, (HANDLE proc));
EXTERN_DECL(void process_cleanup, (HANDLE proc)); EXTERN_DECL(void process_cleanup, (HANDLE proc));
EXTERN_DECL(HANDLE process_wait_for_any, (int block, DWORD* pdwWaitStatus)); 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)); int outfd, int errfd));
EXTERN_DECL(BOOL process_kill, (HANDLE proc, int signal)); EXTERN_DECL(BOOL process_kill, (HANDLE proc, int signal));
EXTERN_DECL(int process_used_slots, (VOID_DECL)); EXTERN_DECL(int process_used_slots, (VOID_DECL));
EXTERN_DECL(DWORD process_set_handles, (HANDLE *handles));
/* support routines */ /* support routines */
EXTERN_DECL(long process_errno, (HANDLE proc)); 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_pipes, (HANDLE proc, int pipes[3]));
EXTERN_DECL(void process_noinherit, (int fildes)); 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 #endif

View file

@ -1,34 +0,0 @@
@if "%COMPILER%" == "gcc" GoTo GCCBuild
if not exist .\WinDebug\nul mkdir .\WinDebug
cl.exe /nologo /MT /W4 /GX /Z7 /YX /Od /I .. /I . /I ../include /I ../.. /D WIN32 /D WINDOWS32 /D _DEBUG /D _WINDOWS /FR.\WinDebug/ /Fp.\WinDebug/subproc.pch /Fo.\WinDebug/ /c misc.c
cl.exe /nologo /MT /W4 /GX /Z7 /YX /Od /I .. /I . /I ../include /I ../.. /D WIN32 /D WINDOWS32 /D _DEBUG /D _WINDOWS /FR.\WinDebug/ /Fp.\WinDebug/subproc.pch /Fo.\WinDebug/ /c sub_proc.c
cl.exe /nologo /MT /W4 /GX /Z7 /YX /Od /I .. /I . /I ../include /I ../.. /D WIN32 /D WINDOWS32 /D _DEBUG /D _WINDOWS /FR.\WinDebug/ /Fp.\WinDebug/subproc.pch /Fo.\WinDebug/ /c w32err.c
lib.exe /NOLOGO /OUT:.\WinDebug\subproc.lib .\WinDebug/misc.obj .\WinDebug/sub_proc.obj .\WinDebug/w32err.obj
if not exist .\WinRel\nul mkdir .\WinRel
cl.exe /nologo /MT /W4 /GX /YX /O2 /I .. /I . /I ../include /I ../.. /D WIN32 /D WINDOWS32 /D NDEBUG /D _WINDOWS /FR.\WinRel/ /Fp.\WinRel/subproc.pch /Fo.\WinRel/ /c misc.c
cl.exe /nologo /MT /W4 /GX /YX /O2 /I .. /I . /I ../include /I ../.. /D WIN32 /D WINDOWS32 /D NDEBUG /D _WINDOWS /FR.\WinRel/ /Fp.\WinRel/subproc.pch /Fo.\WinRel/ /c sub_proc.c
cl.exe /nologo /MT /W4 /GX /YX /O2 /I .. /I . /I ../include /I ../.. /D WIN32 /D WINDOWS32 /D NDEBUG /D _WINDOWS /FR.\WinRel/ /Fp.\WinRel/subproc.pch /Fo.\WinRel/ /c w32err.c
lib.exe /NOLOGO /OUT:.\WinRel\subproc.lib .\WinRel/misc.obj .\WinRel/sub_proc.obj .\WinRel/w32err.obj
GoTo BuildEnd
:GCCBuild
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I.. -I. -I../include -I../.. -DWINDOWS32 -c misc.c -o ../../w32_misc.o
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I.. -I. -I../include -I../.. -DWINDOWS32 -c sub_proc.c -o ../../sub_proc.o
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I.. -I. -I../include -I../.. -DWINDOWS32 -c w32err.c -o ../../w32err.o
:BuildEnd
@echo off
rem Copyright (C) 1996-2016 Free Software Foundation, Inc.
rem This file is part of GNU Make.
rem
rem GNU Make is free software; you can redistribute it and/or modify it under
rem the terms of the GNU General Public License as published by the Free
rem Software Foundation; either version 3 of the License, or (at your option)
rem any later version.
rem
rem GNU Make is distributed in the hope that it will be useful, but WITHOUT
rem ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
rem FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for.
rem more details.
rem
rem You should have received a copy of the GNU General Public License along
rem with this program. If not, see <http://www.gnu.org/licenses/>.

View file

@ -61,124 +61,26 @@ static sub_process *proc_array[MAXIMUM_WAIT_OBJECTS];
static int proc_index = 0; static int proc_index = 0;
static int fake_exits_pending = 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) * Fill a HANDLE list with handles to wait for.
{
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.
*/ */
int wait_for_semaphore_or_child_process() DWORD
process_set_handles(HANDLE *handles)
{ {
HANDLE handles[MAXIMUM_WAIT_OBJECTS]; DWORD count = 0;
DWORD dwHandleCount = 1;
DWORD dwEvent;
int i; int i;
/* Add jobserver semaphore to first slot. */
handles[0] = jobserver_semaphore;
/* Build array of handles to wait for */ /* 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 */ /* Don't wait on child processes that have already finished */
if (fake_exits_pending && proc_array[i]->exit_code) if (fake_exits_pending && proc_array[i]->exit_code)
continue; continue;
handles[dwHandleCount++] = (HANDLE) proc_array[i]->pid; handles[count++] = (HANDLE) proc_array[i]->pid;
} }
dwEvent = WaitForMultipleObjects( return count;
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;
}
} }
/* /*
@ -756,7 +658,7 @@ process_begin(
pproc->lerrno = E_NO_MEM; pproc->lerrno = E_NO_MEM;
free( command_line ); free( command_line );
if ((pproc->last_err == ERROR_INVALID_PARAMETER if ((pproc->last_err == ERROR_INVALID_PARAMETER
|| pproc->last_err == ERROR_MORE_DATA) || pproc->last_err == ERROR_MORE_DATA)
&& envsize_needed > 32*1024) { && envsize_needed > 32*1024) {
fprintf (stderr, "CreateProcess failed, probably because environment is too large (%d bytes).\n", fprintf (stderr, "CreateProcess failed, probably because environment is too large (%d bytes).\n",
envsize_needed); envsize_needed);

196
w32/w32os.c Normal file
View file

@ -0,0 +1,196 @@
/* Windows32-based operating system interface for GNU Make.
Copyright (C) 2016 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */
#include "makeint.h"
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <process.h>
#include <io.h>
#include "pathstuff.h"
#include "sub_proc.h"
#include "w32err.h"
#include "os.h"
#include "debug.h"
/* This section provides OS-specific functions to support the jobserver. */
static char jobserver_semaphore_name[MAX_PATH + 1];
static HANDLE jobserver_semaphore = NULL;
void
jobserver_setup (int slots)
{
/* sub_proc.c cannot wait for more than MAXIMUM_WAIT_OBJECTS objects
* and one of them is the job-server semaphore object. Limit the
* number of available job slots to (MAXIMUM_WAIT_OBJECTS - 1). */
if (slots >= MAXIMUM_WAIT_OBJECTS)
{
slots = MAXIMUM_WAIT_OBJECTS - 1;
DB (DB_JOBS, (_("Jobserver slots limited to %d\n"), slots));
}
sprintf (jobserver_semaphore_name, "gmake_semaphore_%d", _getpid ());
jobserver_semaphore = CreateSemaphore (
NULL, /* Use default security descriptor */
slots, /* Initial count */
slots, /* Maximum count */
jobserver_semaphore_name); /* Semaphore name */
if (jobserver_semaphore == NULL)
{
DWORD err = GetLastError ();
const char *estr = map_windows32_error_to_string (err);
ONS (fatal, NILF,
_("creating jobserver semaphore: (Error %ld: %s)"), err, estr);
}
}
void
jobserver_parse_arg (const char* arg)
{
jobserver_semaphore = OpenSemaphore (
SEMAPHORE_ALL_ACCESS, /* Semaphore access setting */
FALSE, /* Child processes DON'T inherit */
arg); /* Semaphore name */
if (jobserver_semaphore == NULL)
{
DWORD err = GetLastError ();
const char *estr = map_windows32_error_to_string (err);
fatal (NILF, strlen (arg) + INTSTR_LENGTH + strlen (estr),
_("internal error: unable to open jobserver semaphore '%s': (Error %ld: %s)"),
arg, err, estr);
}
DB (DB_JOBS, (_("Jobserver client (semaphore %s)\n"), arg));
}
char *
jobserver_get_arg ()
{
char *fds = xmalloc (MAX_PATH + 1);
strcpy (fds, jobserver_semaphore_name);
return fds;
}
unsigned int
jobserver_enabled ()
{
return jobserver_semaphore != NULL;
}
/* Close jobserver semaphore */
void
jobserver_clear ()
{
if (jobserver_semaphore != NULL)
{
CloseHandle (jobserver_semaphore);
jobserver_semaphore = NULL;
}
}
void
jobserver_release (int is_fatal)
{
if (! ReleaseSemaphore (
jobserver_semaphore, /* handle to semaphore */
1, /* increase count by one */
NULL)) /* not interested in previous count */
{
if (is_fatal)
{
DWORD err = GetLastError ();
const char *estr = map_windows32_error_to_string (err);
ONS (fatal, NILF,
_("release jobserver semaphore: (Error %ld: %s)"), err, estr);
}
perror_with_name ("release_jobserver_semaphore", "");
}
}
unsigned int
jobserver_acquire_all ()
{
unsigned int tokens = 0;
while (1)
{
DWORD dwEvent = WaitForSingleObject (
jobserver_semaphore, /* Handle to semaphore */
0); /* DON'T wait on semaphore */
if (dwEvent != WAIT_OBJECT_0)
return tokens;
++tokens;
}
}
void
jobserver_signal ()
{
}
void jobserver_pre_child ()
{
}
void jobserver_post_child ()
{
}
void
jobserver_pre_acquire ()
{
}
/* Returns 1 if we got a token, or 0 if a child has completed.
The Windows implementation doesn't support load detection. */
int
jobserver_acquire (int timeout)
{
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
DWORD dwHandleCount;
DWORD dwEvent;
/* Add jobserver semaphore to first slot. */
handles[0] = jobserver_semaphore;
/* Build array of handles to wait for. */
dwHandleCount = 1 + process_set_handles (&handles[1]);
dwEvent = WaitForMultipleObjects (
dwHandleCount, /* number of objects in array */
handles, /* array of objects */
FALSE, /* wait for any object */
INFINITE); /* wait until object is signalled */
if (dwEvent == WAIT_FAILED)
{
DWORD err = GetLastError ();
const char *estr = map_windows32_error_to_string (err);
ONS (fatal, NILF,
_("semaphore or child process wait: (Error %ld: %s)"),
err, estr);
}
/* WAIT_OBJECT_0 indicates that the semaphore was signalled. */
return dwEvent == WAIT_OBJECT_0;
}