diff options
-rw-r--r-- | ChangeLog | 86 | ||||
-rw-r--r-- | build_w32.bat | 149 | ||||
-rw-r--r-- | config.h.W32.template | 2 | ||||
-rw-r--r-- | function.c | 36 | ||||
-rw-r--r-- | job.c | 207 | ||||
-rw-r--r-- | job.h | 47 | ||||
-rw-r--r-- | main.c | 47 | ||||
-rw-r--r-- | makeint.h | 8 | ||||
-rw-r--r-- | read.c | 7 | ||||
-rw-r--r-- | w32/compat/posixfcn.c | 258 | ||||
-rw-r--r-- | w32/include/sub_proc.h | 4 | ||||
-rw-r--r-- | w32/subproc/build.bat | 10 | ||||
-rw-r--r-- | w32/subproc/sub_proc.c | 24 |
13 files changed, 772 insertions, 113 deletions
@@ -1,3 +1,84 @@ +2013-04-27 Eli Zaretskii <eliz@gnu.org> + + * read.c (record_files): Pay attention to .ONESHELL in MS-Windows. + + * job.c (construct_command_argv_internal): Support .ONESHELL on + MS-Windows, when the shell is not a Unixy shell. + +2013-04-27 Eli Zaretskii <eliz@gnu.org> + + * job.c: Fix compilation error on GNU/Linux due to "label at end + of compound statement". + +2013-04-27 Frank Heckenbach <f.heckenbach@fh-soft.de> (tiny change) + + * job.c (sync_output): Don't discard the output if + acquire_semaphore fails; instead, dump the output unsynchronized. + +2013-04-27 Eli Zaretskii <eliz@gnu.org> + + Support --output-sync on MS-Windows. + * w32/compat/posixfcn.c: New file, with emulations of Posix + functions and Posix functionality for MS-Windows. + + * w32/subproc/sub_proc.c: Include io.h. + (process_noinherit): New function, forces a file descriptor to not + be inherited by child processes. + (process_easy): Accept two additional arguments, and use them to + set up the standard output and standard error handles of the child + process. + + * w32/include/sub_proc.h (process_easy): Adjust prototype. + (process_noinherit): Add prototype. + + * read.c [WINDOWS32]: Include windows.h and sub_proc.h. + + * makeint.h (LOCALEDIR) [WINDOWS32}: Define to NULL if not + defined. This is needed because the MS-Windows build doesn't have + a canonical place for LOCALEDIR. + (WIN32_LEAN_AND_MEAN) [WINDOWS32]: Define, to avoid getting from + windows.h header too much stuff that could conflict with the code. + + * main.c <sync_mutex>: New static variable. + <switches>: Add support for "--sync-mutex" switch. + (decode_output_sync_flags): Decode the --sync-mutex= switch. + (prepare_mutex_handle_string) [WINDOWS32]: New function. + (main): Add "output-sync" to .FEATURES. + + * job.h (CLOSE_ON_EXEC) [WINDOWS32]: Define to call + process_noinherit. + (F_GETFD, F_SETLKW, F_WRLCK, F_UNLCK, struct flock) [WINDOWS32]: + New macros. + (RECORD_SYNC_MUTEX): New macro, a no-op for Posix platforms. + (sync_handle_t): New typedef. + + * job.c <sync_handle>: Change type to sync_handle_t. + (FD_NOT_EMPTY): Seek to the file's end. Suggested by Frank + Heckenbach <f.heckenbach@fh-soft.de>. + (pump_from_tmp_fd) [WINDOWS32]: Switch to_fd to binary mode for + the duration of this function, and then change back before + returning. + (start_job_command) [WINDOWS32]: Support output_sync mode on + MS-Windows. Use a system-wide mutex instead of locking + stdout/stderr. Call process_easy with two additional arguments: + child->outfd and child->errfd. + (exec_command) [WINDOWS32]: Pass two additional arguments, both + -1, to process_easy, to adjust for the changed function signature. + + * function.c (windows32_openpipe) [WINDOWS32]: This function now + returns an int, which is -1 if it fails and zero otherwise. It + also calls 'error' instead of 'fatal', to avoid exiting + prematurely. + (func_shell_base) [WINDOWS32]: Call perror_with_name if + windows32_openpipe fails, now that it always returns. This avoids + a compiler warning that error_prefix is not used in the MS-Windows + build. + + * config.h.W32.template (OUTPUT_SYNC): Define. + + * build_w32.bat: Add w32/compat/posixfcn.c to compilation and + linking commands. + 2013-04-20 Stefano Lattarini <stefano.lattarini@gmail.com> (tiny change) * README.git: Our autoconf input file is 'configure.ac', not @@ -8,11 +89,6 @@ 2013-04-16 Paul Smith <psmith@gnu.org> - * build_w32.bat: Add load.c to the Windows build. - * main.c: Parse the output-sync options, even if they're not - supported on the platform. They'll just be ignored. - Patches from Ray Donnelly <mingw.android@gmail.com> - * misc.c (open_tmpfd): Add a new function that returns a temporary file by file descriptor. (open_tmpfile): Move here from main.c. diff --git a/build_w32.bat b/build_w32.bat index 63736eb..27ac3db 100644 --- a/build_w32.bat +++ b/build_w32.bat @@ -1,5 +1,5 @@ @echo off
-rem Copyright (C) 1996-2012 Free Software Foundation, Inc.
+rem Copyright (C) 1996-2013 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
@@ -15,28 +15,53 @@ 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/>.
-setlocal
-
-if exist config.h.W32 GoTo NotSCM
+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
+copy config.h.W32 config.h
+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
-if not exist config.h copy config.h.W32 config.h
rem Guile configuration
set GUILECFLAGS=
set GUILELIBS=
set GUILESRC=
+set NOGUILE=
+set OPT=-O2
+set COMPILER=
set PKGMSC=
+:ParseSW
+if "%1" == "--debug" GoTo SetOpt
if "%1" == "--without-guile" GoTo NoGuile
-if "%2" == "--without-guile" GoTo NoGuile
+if "%1" == "gcc" GoTo SetCC
+if "%1" == "" GoTo ChkGuile
+:SetOpt
+set OPT=-O0
+shift
+GoTo ParseSW
+:NoGuile
+set NOGUILE=Y
+echo "Building without Guile"
+shift
+GoTo ParseSW
+:SetCC
+set COMPILER=gcc
+echo "Building with GCC"
+shift
+GoTo ParseSW
rem Build with Guile is supported only on NT and later versions
+:ChkGuile
+if "%NOGUILE%" == "Y" GoTo GuileDone
if not "%OS%" == "Windows_NT" GoTo NoGuile
pkg-config --help > guile.tmp 2> NUL
if ERRORLEVEL 1 GoTo NoPkgCfg
echo "Checking for Guile 2.0"
-if not "%1" == "gcc" set PKGMSC=--msvc-syntax
+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
@@ -49,26 +74,25 @@ 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 NoGuile
+GoTo GuileDone
:NoPkgCfg
echo "pkg-config not found, building without Guile"
-:NoGuile
:GuileDone
if not "%GUILECFLAGS%" == "" echo "Guile found, building with Guile"
if not "%GUILECFLAGS%" == "" set GUILESRC=guile.c
if not "%GUILECFLAGS%" == "" set GUILECFLAGS=%GUILECFLAGS% -DHAVE_GUILE
-if "%1" == "--without-guile" shift
+if "%COMPILER%" == "gcc" if "%OPT%" == "-O0" echo "Building without compiler optimizations"
cd w32\subproc
+echo.
echo "Creating the subproc library"
-%ComSpec% /c build.bat %1
+%ComSpec% /c build.bat
cd ..\..
if exist link.dbg del link.dbg
if exist link.rel del link.rel
-
-echo "Creating GNU Make for Windows 9X/NT/2K/XP"
-
-if "%1" == "gcc" GoTo GCCBuild
+echo.
+echo "Creating GNU Make for Windows 9X/NT/2K/XP/Vista/7/8"
+if "%COMPILER%" == "gcc" GoTo GCCBuild
set make=gnumake
echo on
if not exist .\WinDebug\nul mkdir .\WinDebug
@@ -100,8 +124,6 @@ cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D 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 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 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 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
@@ -124,8 +146,14 @@ cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D 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
@@ -138,7 +166,7 @@ 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/read.obj .\WinDebug/load.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
+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/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"
@@ -173,8 +201,6 @@ cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIND 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 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 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 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
@@ -197,8 +223,14 @@ cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIND 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
@@ -211,7 +243,7 @@ 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/read.obj .\WinRel/load.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
+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/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"
@@ -220,44 +252,54 @@ set make= GoTo BuildEnd
:GCCBuild
echo on
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c variable.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c rule.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c remote-stub.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c commands.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c file.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c getloadavg.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c default.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c signame.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c expand.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c dir.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H %GUILECFLAGS% -c main.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c getopt1.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c job.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c read.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c load.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c version.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c getopt.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c arscan.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c remake.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c hash.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c strcache.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c misc.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c ar.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c function.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c vpath.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c implicit.c
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c ./glob/glob.c -o glob.o
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c ./glob/fnmatch.c -o fnmatch.o
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -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 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 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
@echo off
set GUILEOBJ=
if "%GUILESRC%" == "" GoTo LinkGCC
set GUILEOBJ=guile.o
echo on
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 %GUILECFLAGS% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c guile.c
+gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% %GUILECFLAGS% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c guile.c
:LinkGCC
@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 %GUILEOBJ% job.o read.o load.o version.o getopt.o arscan.o remake.o misc.o hash.o strcache.o ar.o function.o vpath.o implicit.o glob.o fnmatch.o pathstuff.o w32_misc.o sub_proc.o w32err.o %GUILELIBS% -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32
+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 %GUILEOBJ% job.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
+@GoTo BuildEnd
+:Usage
+echo Usage: %0 [options] [gcc]
+echo Options:
+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 GUILEOBJ=
@@ -265,4 +307,7 @@ set GUILESRC= set GUILELIBS=
set GUILECFLAGS=
set PKGMSC=
+set OPT=
+set COMPILER=
+set NOGUILE=
echo on
diff --git a/config.h.W32.template b/config.h.W32.template index 03efa99..a00e095 100644 --- a/config.h.W32.template +++ b/config.h.W32.template @@ -554,3 +554,5 @@ this program. If not, see <http://www.gnu.org/licenses/>. */ #ifdef HAVE_CYGWIN_SHELL #undef BATCH_MODE_ONLY_SHELL #endif + +#define OUTPUT_SYNC @@ -1431,7 +1431,7 @@ int shell_function_pid = 0, shell_function_completed; #include "sub_proc.h" -void +int windows32_openpipe (int *pipedes, pid_t *pid_p, char **command_argv, char **envp) { SECURITY_ATTRIBUTES saAttr; @@ -1442,6 +1442,10 @@ windows32_openpipe (int *pipedes, pid_t *pid_p, char **command_argv, char **envp HANDLE hProcess, tmpIn, tmpErr; DWORD e; + /* Set status for return. */ + pipedes[0] = pipedes[1] = -1; + *pid_p = (pid_t)-1; + saAttr.nLength = sizeof (SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; @@ -1472,8 +1476,10 @@ windows32_openpipe (int *pipedes, pid_t *pid_p, char **command_argv, char **envp DUPLICATE_SAME_ACCESS) == FALSE) CloseHandle(tmpIn); } - if (hIn == INVALID_HANDLE_VALUE) - fatal (NILF, _("windows32_openpipe: DuplicateHandle(In) failed (e=%ld)\n"), e); + if (hIn == INVALID_HANDLE_VALUE) { + error (NILF, _("windows32_openpipe: DuplicateHandle(In) failed (e=%ld)\n"), e); + return -1; + } } tmpErr = GetStdHandle(STD_ERROR_HANDLE); if (DuplicateHandle(GetCurrentProcess(), @@ -1497,17 +1503,23 @@ windows32_openpipe (int *pipedes, pid_t *pid_p, char **command_argv, char **envp DUPLICATE_SAME_ACCESS) == FALSE) CloseHandle(tmpErr); } - if (hErr == INVALID_HANDLE_VALUE) - fatal (NILF, _("windows32_openpipe: DuplicateHandle(Err) failed (e=%ld)\n"), e); + if (hErr == INVALID_HANDLE_VALUE) { + error (NILF, _("windows32_openpipe: DuplicateHandle(Err) failed (e=%ld)\n"), e); + return -1; + } } - if (!CreatePipe(&hChildOutRd, &hChildOutWr, &saAttr, 0)) - fatal (NILF, _("CreatePipe() failed (e=%ld)\n"), GetLastError()); + if (!CreatePipe(&hChildOutRd, &hChildOutWr, &saAttr, 0)) { + error (NILF, _("CreatePipe() failed (e=%ld)\n"), GetLastError()); + return -1; + } hProcess = process_init_fd(hIn, hChildOutWr, hErr); - if (!hProcess) - fatal (NILF, _("windows32_openpipe(): process_init_fd() failed\n")); + if (!hProcess) { + error (NILF, _("windows32_openpipe(): process_init_fd() failed\n")); + return -1; + } /* make sure that CreateProcess() has Path it needs */ sync_Path_environment(); @@ -1527,6 +1539,7 @@ windows32_openpipe (int *pipedes, pid_t *pid_p, char **command_argv, char **envp /* this will be closed almost right away */ pipedes[1] = _open_osfhandle((intptr_t) hChildOutWr, O_APPEND); + return 0; } else { /* reap/cleanup the failed process */ process_cleanup(hProcess); @@ -1541,9 +1554,7 @@ windows32_openpipe (int *pipedes, pid_t *pid_p, char **command_argv, char **envp CloseHandle(hChildOutRd); CloseHandle(hChildOutWr); - /* set status for return */ - pipedes[0] = pipedes[1] = -1; - *pid_p = (pid_t)-1; + return -1; } } #endif @@ -1698,6 +1709,7 @@ func_shell_base (char *o, char **argv, int trim_newlines) { /* Open of the pipe failed, mark as failed execution. */ shell_function_completed = -1; + perror_with_name (error_prefix, "pipe"); return o; } else @@ -246,11 +246,11 @@ unsigned int jobserver_tokens = 0; #ifdef OUTPUT_SYNC /* Semaphore for use in -j mode with output_sync. */ -int sync_handle = -1; +sync_handle_t sync_handle = -1; #define STREAM_OK(_s) ((fcntl (fileno (_s), F_GETFD) != -1) || (errno != EBADF)) -#define FD_NOT_EMPTY(_f) ((_f) >= 0 && lseek ((_f), 0, SEEK_CUR) > 0) +#define FD_NOT_EMPTY(_f) ((_f) >= 0 && lseek ((_f), 0, SEEK_END) > 0) #endif /* OUTPUT_SYNC */ #ifdef WINDOWS32 @@ -588,6 +588,14 @@ pump_from_tmp_fd (int from_fd, int to_fd) ssize_t nleft, nwrite; char buffer[8192]; +#ifdef WINDOWS32 + int prev_mode; + + /* from_fd is opened by open_tmpfd, which does it in binary mode, so + we need the mode of to_fd to match that. */ + prev_mode = _setmode (to_fd, _O_BINARY); +#endif + if (lseek (from_fd, 0, SEEK_SET) == -1) perror ("lseek()"); @@ -605,13 +613,25 @@ pump_from_tmp_fd (int from_fd, int to_fd) if (nwrite < 0) { perror ("write()"); - return; + goto finished; } write_buf += nwrite; nleft -= nwrite; } } + + finished: + +#ifdef WINDOWS32 + /* Switch to_fd back to its original mode, so that log messages by + Make have the same EOL format as without --output-sync. */ + _setmode (to_fd, prev_mode); +#endif + + /* This is needed to avoid the "label at end of compound statement" + diagnostics on Posix platforms. */ + return; } /* Support routine for sync_output() */ @@ -622,7 +642,7 @@ acquire_semaphore (void) fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; - fl.l_start = 0; /* lock just one byte according to pid */ + fl.l_start = 0; /* lock just one byte */ fl.l_len = 1; if (fcntl (sync_handle, F_SETLKW, &fl) != -1) return &fl; @@ -648,13 +668,15 @@ release_semaphore (void *sem) static void sync_output (struct child *c) { - void *sem; - int outfd_not_empty = FD_NOT_EMPTY (c->outfd); int errfd_not_empty = FD_NOT_EMPTY (c->errfd); - if ((outfd_not_empty || errfd_not_empty) && (sem = acquire_semaphore ())) + if (outfd_not_empty || errfd_not_empty) { + /* Try to acquire the semaphore. If it fails, dump the output + unsynchronized; still better than silently discarding it. */ + void *sem = acquire_semaphore (); + /* We've entered the "critical section" during which a lock is held. We want to keep it as short as possible. */ if (outfd_not_empty) @@ -667,7 +689,8 @@ sync_output (struct child *c) pump_from_tmp_fd (c->errfd, fileno (stderr)); /* Exit the critical section. */ - release_semaphore (sem); + if (sem) + release_semaphore (sem); } if (c->outfd >= 0) @@ -1723,6 +1746,42 @@ start_job_command (struct child *child) HANDLE hPID; char* arg0; +#ifdef OUTPUT_SYNC + if (output_sync) + { + static int combined_output; + /* If output_sync is turned on, create a mutex to + synchronize on. This is done only once. */ + if (sync_handle == -1) + { + if ((!STREAM_OK (stdout) && !STREAM_OK (stderr)) + || (sync_handle = create_mutex ()) == -1) + { + perror_with_name ("output-sync suppressed: ", "stderr"); + output_sync = 0; + } + else + { + combined_output = same_stream (stdout, stderr); + prepare_mutex_handle_string (sync_handle); + } + } + /* If we can synchronize, create a temporary file to hold + child's stdout, and another one for its stderr, if they + are separate. */ + if (output_sync == OUTPUT_SYNC_MAKE + || (output_sync == OUTPUT_SYNC_TARGET + && !(flags & COMMANDS_RECURSE))) + { + if (!assign_child_tempfiles (child, combined_output)) + { + perror_with_name ("output-sync suppressed: ", "stderr"); + output_sync = 0; + } + } + } +#endif /* OUTPUT_SYNC */ + /* make UNC paths safe for CreateProcess -- backslash format */ arg0 = argv[0]; if (arg0 && arg0[0] == '/' && arg0[1] == '/') @@ -1733,7 +1792,14 @@ start_job_command (struct child *child) /* make sure CreateProcess() has Path it needs */ sync_Path_environment(); - hPID = process_easy(argv, child->environment); +#ifdef OUTPUT_SYNC + /* Divert child output into tempfile(s) if output_sync in use. */ + if (output_sync) + hPID = process_easy(argv, child->environment, + child->outfd, child->errfd); + else +#endif + hPID = process_easy(argv, child->environment, -1, -1); if (hPID != INVALID_HANDLE_VALUE) child->pid = (pid_t) hPID; @@ -2417,7 +2483,7 @@ exec_command (char **argv, char **envp) sync_Path_environment(); /* launch command */ - hPID = process_easy(argv, envp); + hPID = process_easy(argv, envp, -1, -1); /* make sure launch ok */ if (hPID == INVALID_HANDLE_VALUE) @@ -3166,7 +3232,12 @@ construct_command_argv_internal (char *line, char **restp, char *shell, #if defined __MSDOS__ || defined (__EMX__) if (unixy_shell) /* the test is complicated and we already did it */ #else - if (is_bourne_compatible_shell(shell)) + if (is_bourne_compatible_shell(shell) +#ifdef WINDOWS32 + /* If we didn't find any sh.exe, don't behave is if we did! */ + && !no_default_sh_exe +#endif + ) #endif { const char *f = line; @@ -3201,31 +3272,103 @@ construct_command_argv_internal (char *line, char **restp, char *shell, } } *t = '\0'; - } - /* Create an argv list for the shell command line. */ - { - int n = 0; + /* Create an argv list for the shell command line. */ + { + int n = 0; - new_argv = xmalloc ((4 + sflags_len/2) * sizeof (char *)); - new_argv[n++] = xstrdup (shell); + new_argv = xmalloc ((4 + sflags_len/2) * sizeof (char *)); + new_argv[n++] = xstrdup (shell); - /* Chop up the shellflags (if any) and assign them. */ - if (! shellflags) - new_argv[n++] = xstrdup (""); - else - { - const char *s = shellflags; - char *t; - unsigned int len; - while ((t = find_next_token (&s, &len)) != 0) - new_argv[n++] = xstrndup (t, len); - } + /* Chop up the shellflags (if any) and assign them. */ + if (! shellflags) + new_argv[n++] = xstrdup (""); + else + { + const char *s = shellflags; + char *t; + unsigned int len; + while ((t = find_next_token (&s, &len)) != 0) + new_argv[n++] = xstrndup (t, len); + } - /* Set the command to invoke. */ - new_argv[n++] = line; - new_argv[n++] = NULL; - } + /* Set the command to invoke. */ + new_argv[n++] = line; + new_argv[n++] = NULL; + } + } +#ifdef WINDOWS32 + else /* non-Posix shell */ + { + const char *f = line; + char *t = line; + char *tstart = t; + int temp_fd; + FILE* batch = NULL; + int id = GetCurrentProcessId(); + PATH_VAR(fbuf); + + /* Generate a file name for the temporary batch file. */ + sprintf(fbuf, "make%d", id); + *batch_filename = create_batch_file (fbuf, 0, &temp_fd); + DB (DB_JOBS, (_("Creating temporary batch file %s\n"), + *batch_filename)); + + /* Create a FILE object for the batch file, and write to it the + commands to be executed. Put the batch file in TEXT mode. */ + _setmode (temp_fd, _O_TEXT); + batch = _fdopen (temp_fd, "wt"); + fputs ("@echo off\n", batch); + DB (DB_JOBS, (_("Batch file contents:\n\t@echo off\n"))); + + /* Copy the recipe, removing and ignoring interior prefix chars + [@+-]: they're meaningless in .ONESHELL mode. */ + while (*f != '\0') + { + /* This is the start of a new recipe line. + Skip whitespace and prefix characters. */ + while (isblank (*f) || *f == '-' || *f == '@' || *f == '+') + ++f; + + /* Copy until we get to the next logical recipe line. */ + while (*f != '\0') + { + /* Remove the escaped newlines in the command, and + the whitespace that follows them. Windows + shells cannot handle escaped newlines. */ + if (*f == '\\' && f[1] == '\n') + { + f += 2; + while (isblank (*f)) + ++f; + } + *(t++) = *(f++); + /* On an unescaped newline, we're done with this + line. */ + if (f[-1] == '\n') + break; + } + /* Write another line into the batch file. */ + if (t > tstart) + { + int c = *t; + *t = '\0'; + fputs (tstart, batch); + DB (DB_JOBS, ("\t%s", tstart)); + tstart = t; + *t = c; + } + } + DB (DB_JOBS, ("\n")); + fclose (batch); + + /* Create an argv list for the shell command line that + will run the batch file. */ + new_argv = xmalloc (2 * sizeof (char *)); + new_argv[0] = xstrdup (*batch_filename); + new_argv[1] = NULL; + } +#endif /* WINDOWS32 */ return new_argv; } @@ -26,7 +26,11 @@ this program. If not, see <http://www.gnu.org/licenses/>. */ /* How to set close-on-exec for a file descriptor. */ #if !defined F_SETFD -# define CLOSE_ON_EXEC(_d) +# ifdef WINDOWS32 +# define CLOSE_ON_EXEC(_d) process_noinherit(_d) +# else +# define CLOSE_ON_EXEC(_d) +# endif #else # ifndef FD_CLOEXEC # define FD_CLOEXEC 1 @@ -34,6 +38,47 @@ this program. If not, see <http://www.gnu.org/licenses/>. */ # define CLOSE_ON_EXEC(_d) (void) fcntl ((_d), F_SETFD, FD_CLOEXEC) #endif +#ifdef OUTPUT_SYNC +# ifdef WINDOWS32 +/* For emulations in w32/compat/posixfcn.c. */ +# define F_GETFD 1 +# define F_SETLKW 2 +/* Implementation note: None of the values of l_type below can be zero + -- they are compared with a static instance of the struct, so zero + means unknown/invalid, see w32/compat/posixfcn.c. */ +# define F_WRLCK 1 +# define F_UNLCK 2 + +struct flock { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; +}; + +/* This type is actually a HANDLE, but we want to avoid including + windows.h as much as possible. */ +typedef intptr_t sync_handle_t; + +/* Public functions emulated/provided in posixfcn.c. */ +int fcntl (intptr_t fd, int cmd, ...); +intptr_t create_mutex (void); +int same_stream (FILE *f1, FILE *f2); + +# define RECORD_SYNC_MUTEX(m) record_sync_mutex(m) +void record_sync_mutex (const char *str); +void prepare_mutex_handle_string (intptr_t hdl); + +# else /* !WINDOWS32 */ + +typedef int sync_handle_t; /* file descriptor */ + +# define RECORD_SYNC_MUTEX(m) (void)(m) + +# endif +#endif /* OUTPUT_SYNC */ + /* Structure describing a running or dead child process. */ struct child @@ -239,6 +239,11 @@ static struct stringlist *jobserver_fds = 0; int job_fds[2] = { -1, -1 }; int job_rfd = -1; +/* Handle for the mutex used on Windows to synchronize output of our + children under -O. */ + +static struct stringlist *sync_mutex = 0; + /* Maximum load average at which multiple jobs will be run. Negative values mean unlimited, while zero means limit to zero load (which could be useful to start infinite jobs remotely @@ -415,6 +420,7 @@ static const struct command_switch switches[] = { 'n', flag, &just_print_flag, 1, 1, 1, 0, 0, "just-print" }, { 'o', filename, &old_files, 0, 0, 0, 0, 0, "old-file" }, { 'O', string, &output_sync_option, 1, 1, 0, "target", 0, "output-sync" }, + { CHAR_MAX+7, string, &sync_mutex, 1, 1, 0, 0, 0, "sync-mutex" }, { 'p', flag, &print_data_base_flag, 1, 1, 0, 0, 0, "print-data-base" }, { 'q', flag, &question_flag, 1, 1, 1, 0, 0, "question" }, { 'r', flag, &no_builtin_rules_flag, 1, 1, 0, 0, 0, "no-builtin-rules" }, @@ -696,9 +702,47 @@ decode_output_sync_flags (void) else fatal (NILF, _("unknown output-sync type '%s'"), p); } + + if (sync_mutex) + { + const char *mp; + unsigned int idx; + + for (idx = 1; idx < sync_mutex->idx; idx++) + if (!streq (sync_mutex->list[0], sync_mutex->list[idx])) + fatal (NILF, _("internal error: multiple --sync-mutex options")); + + /* Now parse the mutex handle string. */ + mp = sync_mutex->list[0]; + RECORD_SYNC_MUTEX (mp); + } } #ifdef WINDOWS32 + +/* This is called from start_job_command when it detects that + output_sync option is in effect. The handle to the synchronization + mutex is passed, as a string, to sub-makes via the --sync-mutex + command-line argument. */ +void +prepare_mutex_handle_string (sync_handle_t handle) +{ + if (!sync_mutex) + { + /* 2 hex digits per byte + 2 characters for "0x" + null. */ + char hdl_string[2 * sizeof (sync_handle_t) + 2 + 1]; + + /* Prepare the mutex handle string for our children. */ + sprintf (hdl_string, "0x%x", handle); + sync_mutex = xmalloc (sizeof (struct stringlist)); + sync_mutex->list = xmalloc (sizeof (char *)); + sync_mutex->list[0] = xstrdup (hdl_string); + sync_mutex->idx = 1; + sync_mutex->max = 1; + define_makeflags (1, 0); + } +} + /* * HANDLE runtime exceptions by avoiding a requestor on the GUI. Capture * exception and print it to stderr instead. @@ -1137,6 +1181,9 @@ main (int argc, char **argv, char **envp) #ifdef MAKE_JOBSERVER " jobserver" #endif +#ifdef OUTPUT_SYNC + " output-sync" +#endif #ifdef MAKE_SYMLINKS " check-symlink" #endif @@ -355,6 +355,14 @@ extern int no_default_sh_exe; /* is default_shell unixy? */ extern int unixy_shell; + +/* We don't have a preferred fixed value for LOCALEDIR. */ +# ifndef LOCALEDIR +# define LOCALEDIR NULL +# endif + +/* Include only the minimal stuff from windows.h. */ +#define WIN32_LEAN_AND_MEAN #endif /* WINDOWS32 */ #if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) @@ -30,7 +30,10 @@ this program. If not, see <http://www.gnu.org/licenses/>. */ #include "hash.h" -#ifndef WINDOWS32 +#ifdef WINDOWS32 +#include <windows.h> +#include "sub_proc.h" +#else /* !WINDOWS32 */ #ifndef _AMIGA #ifndef VMS #include <pwd.h> @@ -2045,7 +2048,7 @@ record_files (struct nameseq *filenames, const char *pattern, } else if (streq (name, ".SECONDEXPANSION")) second_expansion = 1; -#if !defined(WINDOWS32) && !defined (__MSDOS__) && !defined (__EMX__) +#if !defined (__MSDOS__) && !defined (__EMX__) else if (streq (name, ".ONESHELL")) one_shell = 1; #endif diff --git a/w32/compat/posixfcn.c b/w32/compat/posixfcn.c new file mode 100644 index 0000000..90534d0 --- /dev/null +++ b/w32/compat/posixfcn.c @@ -0,0 +1,258 @@ +/* Replacements for Posix functions and Posix functionality for MS-Windows. + +Copyright (C) 2013 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 <string.h> +#include <io.h> +#include <stdarg.h> +#include <errno.h> +#include <windows.h> + +#include "makeint.h" +#include "job.h" + +#ifdef OUTPUT_SYNC +/* Support for OUTPUT_SYNC and related functionality. */ + +/* Emulation of fcntl that supports only F_GETFD and F_SETLKW. */ +int +fcntl (intptr_t fd, int cmd, ...) +{ + va_list ap; + + va_start (ap, cmd); + + switch (cmd) + { + case F_GETFD: + va_end (ap); + /* Could have used GetHandleInformation, but that isn't + supported on Windows 9X. */ + if (_get_osfhandle (fd) == -1) + return -1; + return 0; + case F_SETLKW: + { + void *buf = va_arg (ap, void *); + struct flock *fl = (struct flock *)buf; + HANDLE hmutex = (HANDLE)fd; + static struct flock last_fl; + short last_type = last_fl.l_type; + + va_end (ap); + + if (hmutex == INVALID_HANDLE_VALUE || !hmutex) + return -1; + + last_fl = *fl; + + switch (fl->l_type) + { + + case F_WRLCK: + { + DWORD result; + + if (last_type == F_WRLCK) + { + /* Don't call WaitForSingleObject if we already + own the mutex, because doing so will require + us to call ReleaseMutex an equal number of + times, before the mutex is actually + released. */ + return 0; + } + + result = WaitForSingleObject (hmutex, INFINITE); + switch (result) + { + case WAIT_OBJECT_0: + /* We don't care if the mutex owner crashed or + exited. */ + case WAIT_ABANDONED: + return 0; + case WAIT_FAILED: + case WAIT_TIMEOUT: /* cannot happen, really */ + { + DWORD err = GetLastError (); + + /* Invalidate the last command. */ + memset (&last_fl, 0, sizeof (last_fl)); + + switch (err) + { + case ERROR_INVALID_HANDLE: + case ERROR_INVALID_FUNCTION: + errno = EINVAL; + return -1; + default: + errno = EDEADLOCK; + return -1; + } + } + } + } + case F_UNLCK: + { + /* FIXME: Perhaps we should call ReleaseMutex + repatedly until it errors out, to make sure the + mutext is released even if we somehow managed to + to take ownership multiple times? */ + BOOL status = ReleaseMutex (hmutex); + + if (status) + return 0; + else + { + DWORD err = GetLastError (); + + if (err == ERROR_NOT_OWNER) + errno = EPERM; + else + { + memset (&last_fl, 0, sizeof (last_fl)); + errno = EINVAL; + } + return -1; + } + } + default: + errno = ENOSYS; + return -1; + } + } + default: + errno = ENOSYS; + va_end (ap); + return -1; + } +} + +static intptr_t mutex_handle = -1; + +/* Record in a static variable the mutex handle we were requested to + use. That nameless mutex was created by the top-level Make, and + its handle was passed to us via inheritance. The value of that + handle is passed via the command-line arguments, so that we know + which handle to use. */ +void +record_sync_mutex (const char *str) +{ + char *endp; + intptr_t hmutex = strtol (str, &endp, 16); + + if (*endp == '\0') + mutex_handle = hmutex; + else + { + mutex_handle = -1; + errno = EINVAL; + } +} + +/* Create a new mutex or reuse one created by our parent. */ +intptr_t +create_mutex (void) +{ + SECURITY_ATTRIBUTES secattr; + intptr_t hmutex = -1; + + /* If we have a mutex handle passed from the parent Make, just use + that. */ + if (mutex_handle > 0) + return mutex_handle; + + /* We are the top-level Make, and we want the handle to be inherited + by our child processes. */ + secattr.nLength = sizeof (secattr); + secattr.lpSecurityDescriptor = NULL; /* use default security descriptor */ + secattr.bInheritHandle = TRUE; + + hmutex = (intptr_t)CreateMutex (&secattr, FALSE, NULL); + if (!hmutex) + { + DWORD err = GetLastError (); + + fprintf (stderr, "CreateMutex: error %lu\n", err); + errno = ENOLCK; + hmutex = -1; + } + + mutex_handle = hmutex; + return hmutex; +} + +/* Return non-zero if F1 and F2 are 2 streams representing the same + file or pipe or device. */ +int +same_stream (FILE *f1, FILE *f2) +{ + HANDLE fh1 = (HANDLE)_get_osfhandle (fileno (f1)); + HANDLE fh2 = (HANDLE)_get_osfhandle (fileno (f2)); + + /* Invalid file descriptors get treated as different streams. */ + if (fh1 && fh1 != INVALID_HANDLE_VALUE + && fh2 && fh2 != INVALID_HANDLE_VALUE) + { + if (fh1 == fh2) + return 1; + else + { + DWORD ftyp1 = GetFileType (fh1), ftyp2 = GetFileType (fh2); + + if (ftyp1 != ftyp2 + || ftyp1 == FILE_TYPE_UNKNOWN || ftyp2 == FILE_TYPE_UNKNOWN) + return 0; + else if (ftyp1 == FILE_TYPE_CHAR) + { + /* For character devices, check if they both refer to a + console. This loses if both handles refer to the + null device (FIXME!), but in that case we don't care + in the context of Make. */ + DWORD conmode1, conmode2; + + /* Each process on Windows can have at most 1 console, + so if both handles are for the console device, they + are the same. We also compare the console mode to + distinguish between tsdin and stdout/stderr. */ + if (GetConsoleMode (fh1, &conmode1) + && GetConsoleMode (fh2, &conmode2) + && conmode1 == conmode2) + return 1; + } + else + { + /* For disk files and pipes, compare their unique + attributes. */ + BY_HANDLE_FILE_INFORMATION bhfi1, bhfi2; + + /* Pipes get zero in the volume serial number, but do + appear to have meaningful information in file index + attributes. We test file attributes as well, for a + good measure. */ + if (GetFileInformationByHandle (fh1, &bhfi1) + && GetFileInformationByHandle (fh2, &bhfi2)) + return (bhfi1.dwVolumeSerialNumber == bhfi2.dwVolumeSerialNumber + && bhfi1.nFileIndexLow == bhfi2.nFileIndexLow + && bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh + && bhfi1.dwFileAttributes == bhfi2.dwFileAttributes); + } + } + } + return 0; +} + +#endif /* OUTPUT_SYNC */ diff --git a/w32/include/sub_proc.h b/w32/include/sub_proc.h index 0aeaf00..d209aff 100644 --- a/w32/include/sub_proc.h +++ b/w32/include/sub_proc.h @@ -41,7 +41,8 @@ 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)); EXTERN_DECL(void process_register, (HANDLE proc)); -EXTERN_DECL(HANDLE process_easy, (char** argv, char** env)); +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)); @@ -55,6 +56,7 @@ EXTERN_DECL(char * process_errbuf, (HANDLE proc)); EXTERN_DECL(int process_outcnt, (HANDLE proc)); 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)); diff --git a/w32/subproc/build.bat b/w32/subproc/build.bat index c27ecfb..ecd2ab7 100644 --- a/w32/subproc/build.bat +++ b/w32/subproc/build.bat @@ -1,4 +1,4 @@ -@if "%1" == "gcc" GoTo GCCBuild
+@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
@@ -11,13 +11,13 @@ cl.exe /nologo /MT /W4 /GX /YX /O2 /I .. /I . /I ../include /I ../.. /D WIN32 /D 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 -O2 -I.. -I. -I../include -I../.. -DWINDOWS32 -c misc.c -o ../../w32_misc.o
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I.. -I. -I../include -I../.. -DWINDOWS32 -c sub_proc.c -o ../../sub_proc.o
-gcc -mthreads -Wall -gdwarf-2 -g3 -O2 -I.. -I. -I../include -I../.. -DWINDOWS32 -c w32err.c -o ../../w32err.o
+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-2012 Free Software Foundation, Inc.
+rem Copyright (C) 1996-2013 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
diff --git a/w32/subproc/sub_proc.c b/w32/subproc/sub_proc.c index 6cc3081..2c36777 100644 --- a/w32/subproc/sub_proc.c +++ b/w32/subproc/sub_proc.c @@ -17,6 +17,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */ #include <config.h> #include <stdlib.h> #include <stdio.h> +#include <io.h> /* for _get_osfhandle */ #ifdef _MSC_VER # include <stddef.h> /* for intptr_t */ #else @@ -341,6 +342,15 @@ process_exit_code(HANDLE proc) return (((sub_process *)proc)->exit_code); } +void +process_noinherit(int fd) +{ + HANDLE fh = (HANDLE)_get_osfhandle(fd); + + if (fh && fh != INVALID_HANDLE_VALUE) + SetHandleInformation(fh, HANDLE_FLAG_INHERIT, 0); +} + /* 2006-02: All the following functions are currently unused. @@ -1340,7 +1350,9 @@ make_command_line( char *shell_name, char *full_exec_path, char **argv) HANDLE process_easy( char **argv, - char **envp) + char **envp, + int outfd, + int errfd) { HANDLE hIn = INVALID_HANDLE_VALUE; HANDLE hOut = INVALID_HANDLE_VALUE; @@ -1383,7 +1395,10 @@ process_easy( return INVALID_HANDLE_VALUE; } } - tmpOut = GetStdHandle (STD_OUTPUT_HANDLE); + if (outfd >= 0) + tmpOut = (HANDLE)_get_osfhandle (outfd); + else + tmpOut = GetStdHandle (STD_OUTPUT_HANDLE); if (DuplicateHandle(GetCurrentProcess(), tmpOut, GetCurrentProcess(), @@ -1410,7 +1425,10 @@ process_easy( return INVALID_HANDLE_VALUE; } } - tmpErr = GetStdHandle(STD_ERROR_HANDLE); + if (errfd >= 0) + tmpErr = (HANDLE)_get_osfhandle (errfd); + else + tmpErr = GetStdHandle(STD_ERROR_HANDLE); if (DuplicateHandle(GetCurrentProcess(), tmpErr, GetCurrentProcess(), |