Compare commits

..

76 Commits
3.99.90 ... 4.0

Author SHA1 Message Date
Paul Smith
52191d9d61 GNU Make release 4.0. 2013-10-09 02:09:21 -04:00
Paul Smith
dc9ae5e017 [SV 39709] Fix some typos. 2013-10-09 01:53:55 -04:00
Eli Zaretskii
723e047428 Untabify posixfcn.c. 2013-10-07 19:16:11 +03:00
Eli Zaretskii
b69b04dc8c Foix compilation with MSVC.
w32/compat/posixfcn.c (tmpfile): Move declaration of h before
 the first executable statement.  Reported by Gisle Vanem <gvanem@yahoo.no>.
2013-10-07 19:14:01 +03:00
Paul Smith
b539908f73 Clean up some tests for use on Windows. 2013-10-05 19:30:48 -04:00
Paul Smith
2fb91e19a0 Sanitize the registered function interface.
Expand the characters which are legal in a function name, and check
the name for validity.  Create a type for the function pointer.
Convert the last argument from a boolean to flags, to allow for expansion.
2013-10-05 16:10:30 -04:00
Eli Zaretskii
f96c114e22 function.c (abspath): Reset root_len to one for Cygwin only when
HAVE_DOS_PATHS is defined.  Suggested by Christopher Faylor.
2013-10-03 19:02:14 +03:00
Eli Zaretskii
98197303b1 Fix tmpfile on MS-Windows.
w32/compat/posixfcn.c (tmpfile): New function, a replacement for
 the Windows libc version.
2013-10-02 19:48:21 +03:00
Eli Zaretskii
f8786092ad Fix $abspath on Cygwin when HAVE_DOS_PATHS is in effect.
function.c (IS_ABSOLUTE) [__CYGWIN__]: Special definition for Cygwin.
 (abspath) [__CYGWIN__]: Reset root_len to 1 if the absolute file name
 has the Posix /foo/bar form.
 [HAVE_DOS_PATHS]: Use root_len instead of hard-coded 2.
2013-10-02 19:39:53 +03:00
Paul Smith
1d4c15b4e1 Release GNU Make version 3.99.93. 2013-10-01 00:33:01 -04:00
Paul Smith
b1c7f0df4e Fix portability issues for Guile 1.8. 2013-09-30 10:56:20 -04:00
Paul Smith
8e12202870 Final fixes for obscure output-sync errors. 2013-09-30 00:12:36 -04:00
Paul Smith
1f4ca0539b Fixes for building with MSVC. 2013-09-30 00:12:36 -04:00
Paul Smith
d0944ee2e8 Solaris /bin/sh can't handle multiple options ("-e -c"). 2013-09-30 00:12:18 -04:00
Paul Smith
38066b6f19 Fix build failures on EMX for output-sync support. 2013-09-29 13:17:56 -04:00
Paul Smith
3bf3fde984 Portability for Guile 1.8. Force UTF-8 encoding. 2013-09-29 13:16:21 -04:00
Paul Smith
543521cd47 Reset GNUMAKEFLAGS after parsing.
If we don't do this we'll continually add flags on recursion.  This
is mainly for users to set in their environment before invoking make.
2013-09-29 13:15:00 -04:00
Paul Smith
e8122ecb5d Rename dash-w to print-directory.
Avoid conflicts with dash-W on case-insensitive filesystems.
2013-09-23 11:24:51 -04:00
Eli Zaretskii
55a0c0e414 Fix broken w32 build due to OUTPUT_SYNC -> NO_OUTPUT_SYNC inversion.
w32/compat/posixfcn.c: Fix the forgotten OUTPUT_SYNC conditional.
 job.h: Ditto, but in a comment.
2013-09-23 10:56:51 +03:00
Paul Smith
8a3436c65d Release GNU Make version 3.99.92. 2013-09-23 00:55:55 -04:00
Paul Smith
fd30db1290 [SV 31155] Parse order-only tokens in second expansion results. 2013-09-22 17:10:35 -04:00
Paul Smith
c3524b83b9 Use explicit cast between void* and pointer-to-function. 2013-09-22 17:10:35 -04:00
Paul Smith
0296e40fc7 Allow loaded objects to opt out of the "auto-rebuild" feature. 2013-09-22 17:10:35 -04:00
Paul Smith
f69922b335 Defer Guile initialization until the first $(guile...) call. 2013-09-22 17:10:35 -04:00
Paul Smith
65931ce7a9 Regression test portability to Solaris. 2013-09-22 17:10:34 -04:00
Paul Smith
1a991ada47 Add VMS port updates from Hartmut Becker. 2013-09-22 17:10:34 -04:00
Paul Smith
7e77685bc3 Portability enhancements for Mac OSX.
Don't dup stdout into stderr in the test suite.
Don't rely on $port_type eq "UNIX" to mean case-preserving.
Check against the real output of ar when creating archives.
2013-09-22 17:09:46 -04:00
Paul Smith
300d1296fb Create a target that tests alternative configurations. 2013-09-21 18:10:08 -04:00
Paul Smith
822f8dae41 Remove obsolete tests. 2013-09-21 17:41:11 -04:00
Paul Smith
d2d44f76c4 Invert the #define for output-sync: turn it off with NO_OUTPUT_SYNC 2013-09-21 17:37:59 -04:00
Paul Smith
6c3e88e60f Ensure that output generated while reading makefiles is synced. 2013-09-21 17:24:59 -04:00
Paul Smith
9cd01958da Ensure that stderr from shell functions in recipes is synced. 2013-09-21 17:08:42 -04:00
Paul Smith
4120f91846 Don't write "Entering" every time we re-exec for remake makefiles. 2013-09-21 14:24:44 -04:00
Paul Smith
30a5ee0d85 [SV 40043] Set the current directory before printing errors. 2013-09-18 19:29:28 -04:00
Eli Zaretskii
8a6205b43f Fix a typo in a comment. 2013-09-16 11:42:20 +03:00
Eli Zaretskii
bc120f27bd Avoid compiler warnings in output.c on MS-Windows.
output.c [WINDOWS32]: Include windows.h and sub_proc.h, to avoid
 compiler warnings for CLOSE_ON_EXEC.
2013-09-16 11:30:01 +03:00
Paul Smith
5c0fba7240 Release GNU Make version 3.99.91. 2013-09-16 00:30:01 -04:00
Paul Smith
fa0f2c516a Small cleanup defining MAKEFLAGS. 2013-09-16 00:12:09 -04:00
Paul Smith
20ecc58126 [SV 31326] Enhance the info on static pattern errors. 2013-09-15 17:53:30 -04:00
Paul Smith
1b90248893 [SV 27374] Fatal immediately on unrecoverable fopen() errors. 2013-09-15 17:09:01 -04:00
Paul Smith
a4d8444b59 [SV 39934] Verify jobserver FDs before something else uses them. 2013-09-15 15:21:33 -04:00
Paul Smith
0a81d50d66 [SV 39203] Don't set MAKEFLAGS when restarting.
We are restarting with the original command line flags, so if we set
MAKEFLAGS as well that will cause double flags.
2013-09-15 13:30:21 -04:00
Paul Smith
3aa2aa7e82 [SV 35248] Add --debug "n" flag to turn off current debug options. 2013-09-14 21:01:10 -04:00
Paul Smith
29a94ceb76 [SV 33134] Don't try to close stdout when it's already closed. 2013-09-14 20:40:30 -04:00
Petr Machata
ab78cbc71c [SV 39851] Reinstate stack size limit for processes spawned via $(shell) 2013-09-14 20:38:06 -04:00
Paul Smith
c5bfa40044 Support the -Orecurse option properly.
In this mode we still collect all the output from a given target and
dump it at once.  However we don't treat recursive lines any differently
from non-recursive lines.  Also we don't print enter/leave messages
after every dump.  However we do ensure that we always print them once
to stdout, so the parent make will collect it properly.
2013-09-14 01:04:04 -04:00
Paul Smith
deff9dacc9 Enhance the output sync mode.
Create a new file, output.c, and collect functions that generate output there.
We introduce a new global context specifying where output should go (to stdout
or to a sync file), and the lowest level output generator chooses where to
write output based on that context.

This allows us to set the context globally, and all operations that write
output (including functions like $(info ...) etc.) will use it.

Removed the "--trace=dir" capability.  It was too confusing.  If you have
directory tracking enabled then output sync will print the enter/leave message
for each synchronized block.  If you don't want that, disable directory
tracking.
2013-09-12 04:07:52 -04:00
Paul Smith
40a49f244d [Bug #39310] Parse simple pattern prereqs for globbing.
We tried to get some efficiency by avoiding a parse_file_seq() for simple
pattern prerequisites, but this also means no wildcard expansion was
happening, so add it back.  Add regression tests for wildcards in target and
prerequisite lists.
2013-07-22 02:23:02 -04:00
Paul Smith
87ac68fe79 [Bug #39158] Source cleanups suggested by cppcheck utility. 2013-07-21 17:52:13 -04:00
Paul Smith
72462ef1e1 Safety cleanups: ensure OUTFD is -1 when closed. 2013-07-21 16:56:00 -04:00
Paul Smith
f80222c15b Notify the compiler that exec_command() won't return. 2013-07-14 19:18:46 -04:00
Paul Smith
4b81f5ca92 Modify the update_status field in struct file to be an enum.
Makes the code a little clearer/cleaner, and solves a problem on systems
where a char is unsigned by default.
2013-07-14 19:18:21 -04:00
Paul Smith
5601726151 Keep a local count of the max dependency list size.
This global variable could be modified during recursion so keep our
own local copy to compare against.
2013-07-09 19:14:40 -04:00
Paul Smith
9453a7451d Set O_APPEND mode for stdout/stderr and output-sync temporary files.
POSIX does not guarantee that writes will be atomic if a file is
opened for normal (non-append) output.  That means if multiple processes
are writing to the same file, output could be lost.  I can't think of
a real use-case where we would NOT want append for stdout/stderr, so
force it if we can.
2013-06-28 21:57:59 -04:00
Eli Zaretskii
5e7bf7c554 Minor fix in build_w32.bat.
build_w32.bat (LinkGCC): Prevent a comment from being displayed
 at build time.
2013-06-22 17:32:46 +03:00
Eli Zaretskii
138d020e1b Compare internal commands of non-Unix shells on Windows case-insensitively.
job.c (construct_command_argv_internal) [WINDOWS32]: Use
 case-insensitive comparison with internal commands of non-Unix
 shells.
2013-06-22 16:22:25 +03:00
Eli Zaretskii
5b65c5b916 Fix a fatal error at startup on Windows due to non-ASCII characters in PATH.
main.c (find_and_set_default_shell): Don't use file_exists_p or
 dir_file_exists_p, as those call readdir, which can fail if PATH
 includes directories with non-ASCII characters, and that would
 cause Make to fail at startup with confusing diagnostics.  See
 https://sourceforge.net/mailarchive/message.php?msg_id=30846737
 for the details.
2013-06-22 16:16:56 +03:00
Paul Smith
cc85b927cd Create a character map to use for locating stop-points in strings.
In various places we were passing flags and characters to compare, then
using complex conditionals to see where to stop in string searches.
Performance numbers reveal that we were spending as much as 23% of our
processing time in these functions, most of it in the comparison lines.
Instead create a character map and use a single bitwise comparison to
determine if this is any one of the stop characters.
2013-06-22 00:22:08 -04:00
Paul Smith
bee4d93a59 Disable database verification unless debug enabled.
The database verification can take a long time.  Only enable it if debug mode
is enabled.  If MAKE_MAINTAINER_MODE is set, it's also enabled by default.
2013-06-21 23:59:38 -04:00
Paul Smith
353fcfdb30 Add job.h to POTFILES as it now has a translation. 2013-06-21 21:57:35 -04:00
Paul Smith
d4043519f7 Cleanups. 2013-05-27 13:52:15 -04:00
Paul Smith
ef11217de7 Create a new variable MAKE_HOST providing the host architecture. 2013-05-27 13:52:08 -04:00
Paul Smith
e8f5d322cf Porting to VMS, from Hartmut Becker. 2013-05-27 13:01:48 -04:00
Paul Smith
dc922e3f4c [SV #38442] Add library names to the string cache. 2013-05-26 16:53:17 -04:00
Paul Smith
c11024b3b3 [SV #38945] Copy the entire buffer back when overwriting CR 2013-05-26 14:41:45 -04:00
Paul Smith
2fc0f614be [SV #39028] Fix some small typos in messages. 2013-05-26 14:06:25 -04:00
Paul Smith
bf60bbd67a [SV #39035] Compare OUT to the beginning of the OUT var/func, not IN. 2013-05-26 13:56:51 -04:00
Paul Smith
d2eaed1f0a Add dates to the NEWS file to make things simpler. 2013-05-26 13:53:21 -04:00
Paul Smith
8ab3564a71 Fix regression tests after MAKEFLAGS enhancements. 2013-05-22 07:51:46 -04:00
Paul Smith
ecf307bb0b Force version printing whenever we print the database. 2013-05-22 02:51:45 -04:00
Paul Smith
a674abe702 Make MFLAGS and MAKEFLAGS more reliable and predictable.
Ensure all simple flags are kept in the initial batch of flags.
Do not allow any flags with options in that batch.
If there are only non-simple flags ensure MAKEFLAGS begins with " ".
Don't let MFLAGS start with "- ".
2013-05-22 02:14:19 -04:00
Alexey Pavlov
80183457ad Fix the MS-Windows build using the Posix configury.
w32/Makefile.am (libw32_a_SOURCES): Add compat/posixfcn.c.

 configure.ac (OUTPUT_SYNC): Define for mingw32 target.
2013-05-18 17:58:10 +03:00
Eli Zaretskii
cece7ad61f Support "move" as internal shell command on Windows with cmd.exe.
job.c (construct_command_argv_internal) <sh_cmds_dos> [WINDOWS32]: Add
 "move".  Fixes Savannah bug #30714.
2013-05-18 14:07:36 +03:00
Eli Zaretskii
943c06de47 Fix MS-Windows build with Guile.
guile.c: Move inclusion of makeint.h before gnumake.h.  This
 order must be observed when building Make, because gnumake.h must
 be included with GMK_BUILDING_MAKE defined, which makeint.h
 already does.  Otherwise, the linker will look for, and fail to
 find, gmk_* functions in some external dynamic library.
2013-05-18 14:03:26 +03:00
Eli Zaretskii
171eb41908 Fix MS-Windows compilation when OUTPUT_SYNC is not defined.
main.c (prepare_mutex_handle_string): Define conditioned on OUTPUT_SYNC.
2013-05-17 16:24:13 +03:00
Eli Zaretskii
9babfe49a5 Fix a bug in build_w32.bat when building a released tarball.
build_w32.bat: Copy config.h.W32 to config.h regardless of
 whether or not we are building from SCM.
2013-05-17 13:34:24 +03:00
84 changed files with 4187 additions and 2760 deletions

523
ChangeLog
View File

@@ -1,3 +1,526 @@
2013-10-09 Paul Smith <psmith@gnu.org>
Version 4.0 released.
* configure.ac: Updated for the release.
* NEWS: Updated for the release.
* maintMakefile (tag-release): New target to add a Git tag.
* read.c (eval): Typo fix.
* ChangeLog.1: Typo fixes.
* w32/subproc/sub_proc.c (process_cleanup): Typo fix.
2013-10-07 Eli Zaretskii <eliz@gnu.org>
* w32/compat/posixfcn.c (tmpfile): Move declaration of h before
the first executable statement. Reported by Gisle Vanem
<gvanem@yahoo.no>.
2013-10-05 Paul Smith <psmith@gnu.org>
* makeint.h (MAP_USERFUNC): A new map type for function names.
* main.c (initialize_stopchar_map): Set up the function name map.
* gnumake.h (gmk_func_ptr): Define a type for function pointers.
(gmk_add_function): Convert the last argument to FLAGS.
(GMK_FUNC_*): Define flags for the function. Change the default
behavior to "expand" since that's the most common one.
* function.c (function_table_entry): Use new function pointer type.
(lookup_function): Accept any valid function name character based
on the MAP_USERFUNC values.
(define_new_function): Use the new calling signature. Verify that
registered functions have valid names.
* guile.c (guile_gmake_setup): Use new calling signatures.
* loadapi.c (gmk_add_function): Ditto.
* variable.h (define_new_function): Ditto.
* doc/make.texi (Loaded Object API): Make the registered function
API documentation more clear.
2013-10-03 Eli Zaretskii <eliz@gnu.org>
* function.c (abspath): Reset root_len to one for Cygwin only when
HAVE_DOS_PATHS is defined. Suggested by Christopher Faylor.
2013-10-02 Eli Zaretskii <eliz@gnu.org>
* w32/compat/posixfcn.c (tmpfile): New function, a replacement for
the Windows libc version.
Fix $abspath on Cygwin when HAVE_DOS_PATHS is in effect.
* function.c (IS_ABSOLUTE) [__CYGWIN__]: Special definition for
Cygwin.
(abspath) [__CYGWIN__]: Reset root_len to 1 if the absolute file
name has the Posix /foo/bar form.
[HAVE_DOS_PATHS]: Use root_len instead of hard-coded 2.
2013-10-01 Paul Smith <psmith@gnu.org>
* configure.ac: Update version to 3.99.93.
* NEWS: Ditto.
2013-09-30 Paul Smith <psmith@gnu.org>
* guile.c: Portability fixes for Guile 1.8.
2013-09-29 Paul Smith <psmith@gnu.org>
* output.c (output_dump): Always write Enter/Leave messages to stdio.
(log_working_directory): This now always writes to stdio, so we
don't need the struct output parameter anymore.
(output_start): Show the working directory when output_sync is not
set or is recursive.
* main.c (main): Ensure the special "already shown Enter message"
token is removed from MAKE_RESTARTS before the user can see it.
* function.c (func_shell_base): If the output_context stderr
exists but is invalid, write to the real stderr.
Fixes suggested by Frank Heckenbach <f.heckenbach@fh-soft.de>.
* output.c: Guard unistd.h inclusion, add io.h.
* gnumake.h: Move GMK_EXPORT before the declarations.
* make_msvc_net2003.vcproj: Add missing files.
Changes for MSVC suggested by Gerte Hoogewerf <g.hoogewerf@gmail.com>
* function.c (func_shell_base) [EMX]: Fix EMX support for output-sync.
* job.c (child_execute_job) [EMX]: Ditto.
* job.h (child_execute_job) [EMX]: Ditto.
* w32/compat/posixfcn.c: Invert the test for NO_OUTPUT_SYNC.
* guile.c (GSUBR_TYPE): Pre-2.0 Guile doesn't provide a typedef
for gsubr pointers. Create one.
(guile_define_module): Use it.
(internal_guile_eval): Force UTF-8 encoding for Guile strings.
* main.c (main): Clear GNUMAKEFLAGS after parsing, to avoid
proliferation of options.
* NEWS: Document it.
* doc/make.texi (Options/Recursion): Ditto.
2013-09-23 Eli Zaretskii <eliz@gnu.org>
* w32/compat/posixfcn.c: Fix the forgotten OUTPUT_SYNC conditional.
* job.h: Ditto, but in a comment.
2013-09-22 Paul Smith <psmith@gnu.org>
* configure.ac: Update version to 3.99.92.
* NEWS: Ditto.
* implicit.c (pattern_search): After second expansion be sure to
handle order-only markers inside the expansion properly.
Fixes Savannah bug #31155.
* guile.c (guile_define_module): Technically a void* cannot
contain a pointer-to-function and some compilers warn about this.
Cast the function pointers.
* load.c (load_object): Ditto.
* read.c (eval): If load_file() returns -1, don't add this to the
"to be rebuilt" list.
* doc/make.texi (load Directive): Document it.
* guile.c (guile_gmake_setup): Don't initialize Guile so early.
(func_guile): Lazily initialize Guile the first time the $(guile ..)
function is invoked. Guile can steal file descriptors which
confuses our jobserver FD checking, so we don't want to initialize
it before we have to.
VMS port updates by Hartmut Becker <becker.ismaning@freenet.de>
* makefile.com: Add output to the filelist.
* output.c (va_copy): Add an implementation of this macro for VMS.
* commands.c: Ensure filedef.h is #included before dep.h.
* dir.c: Ditto.
* file.c: Ditto.
* guile.c: Ditto.
* main.c: Ditto.
* misc.c: Ditto.
* read.c: Ditto.
* rule.c: Ditto.
* variable.c: Ditto.
* readme.vms: Renamed to README.VMS and updates for this release.
* Makefile.am: Ditto.
* NEWS: Ditto.
* README.template: Ditto.
* Makefile.DOS.template: Ditto.
2013-09-21 Paul Smith <psmith@gnu.org>
* maintMakefile (check-alt-config): Create a target to test
alternative configurations. Each one will build make with a
different configuration then run the test suite.
Invert the output-sync #define to NO_OUTPUT_SYNC
* configure.ac: Don't set OUTPUT_SYNC.
* makeint.h: Ditto.
* main.c: Use NO_OUTPUT_SYNC instead of OUTPUT_SYNC.
* output.c: Ditto.
* output.h: Ditto.
* job.h: Ditto.
* job.c: Ditto.
* config.ami.template: Set NO_OUTPUT_SYNC.
* config.h-vms.template: Ditto.
* config.h.W32.template: Ditto.
* configh.dos.template: Ditto.
Output generated while reading makefiles should be synced.
* main.c (make_sync): Define a context for syncing while reading
makefiles and other top-level operations.
(main): If we request syncing, enable it while we are parsing
options, reading makefiles, etc. to capture that output. Just
before we start to run rules, dump the output if any.
(die): Dump any output we've been syncing before we die
* output.h (OUTPUT_SET): Disable output_context if not syncout.
Stderr generated from shell functions in recipes should be synced.
* job.h (FD_STDIN, FD_STDOUT, FD_STDERR): Create new macros to
avoid magic numbers.
(child_execute_job): Take a FD for stderr.
* job.c (child_execute_job): Handle STDERR FD's in addition to
stdin and stdout.
(start_job_command): Call child_execute_job() with the new STDERR
parameter. Instead of performing the dup() here, send it to
child_execute_job() where it's already being done.
* function.c (func_shell_base): Pass the OUTPUT_CONTEXT stderr to
child_execute_job() if it's set, otherwise FD_STDERR.
* main.c (main): Pass FD_STDERR to child_execute_job().
2013-09-19 Paul Smith <psmith@gnu.org>
* main.c (main): Set MAKE_RESTARTS to negative before re-exec if
we've already generated an "Entering" message. If we are started
and notice that MAKE_RESTARTS is negative, assume we already wrote
"Entering" and don't write it again.
2013-09-18 Paul Smith <psmith@gnu.org>
* main.c (main): Set starting_directory before we write any
errors. Fixes Savannah bug #40043.
2013-09-16 Eli Zaretskii <eliz@gnu.org>
* output.c [WINDOWS32]: Include windows.h and sub_proc.h, to avoid
compiler warnings for CLOSE_ON_EXEC.
2013-09-16 Paul Smith <psmith@gnu.org>
* configure.ac: Update version to 3.99.91.
* NEWS: Ditto.
2013-09-15 Paul Smith <psmith@gnu.org>
* doc/make.texi (Error Messages): Add a bit more info to the
section on static pattern errors, since they're common.
Fixes Savannah bug #31326.
* read.c (eval_makefile): If the file open fails with an
unrecoverable error, stop now rather than trying to make it.
Fixes Savannah bug #27374.
* main.c (main): Perform the validation of the jobserver FDs
early, before we read makefiles, to ensure that something hasn't
opened and used those FDs for some other reason.
Fixes Savannah bug #39934.
* main.c (main): Don't set MAKEFLAGS in the environment when we
restart. We have the original command line flags so keep the
original MAKEFLAGS settings as well.
Fixes Savannah bug #39203.
2013-09-14 Paul Smith <psmith@gnu.org>
* main.c (decode_debug_flags): Add support for the "n" flag to
disable all debugging.
* make.1: Document the "n" (none) flag.
* doc/make.texi (Options Summary): Ditto.
* NEWS: Ditto.
Fixes Savannah bug #35248.
* misc.c (close_stdout): Move to output.c.
* main.c (main): Move atexit call to output_init().
* makeint.h: Remove close_stdout() declaration.
* output.c (output_init): Add close_stdout at exit only if it's open.
Fixes Savannah bug #33134. Suggested by David Boyce <dsb@boyski.com>.
2013-09-14 Paul Smith <psmith@gnu.org>
* misc.c (set_append_mode, open_tmpfd, open_tmpfile): Move to output.c.
* misc.h: Ditto.
* output.h: Ditto.
* main.c (main): Move stdio init into output.c:output_init().
Change open_tmpfile() to output_tmpfile().
* output.c: Rename open_*() to output_*(). set_append_mode() and
open_tmpfd() are static.
(_outputs, log_working_directory): Accept a struct output and
print to that rather than the global context.
(output_dump): In recurse mode print enter/leave once for the
whole makefile.
(output_init): Initialize this processes stdio as well as child's.
* vmsjobs.c: Reformat to be closer to convention.
2013-09-12 Paul Smith <psmith@gnu.org>
Rework output to handle synchronization and directory logging more
reliably.
* output.c: New file. Implement lazy synchronization and
directory logging so that we manage them "just in time", and the
destination of the output is set via a global state variable.
* output.h: New file.
* function.c (func_shell_base): Ensure the output is set up before
running a shell command, in case it writes to stderr.
(func_error): Use outputs() to generate output.
* job.h (struct child): Add struct output to track the child's output.
* job.c: Use struct output in the child structure to track output.
(child_out, sync_init, assign_child_tempfiles, pump_from_tmp)
(acquire_semaphore, release_semaphore, sync_output): Move most of
the output_sync handling to output.c.
(child_error): Set output, then use simple message() and error()
not _s versions.
* main.c (log_working_directory): Moved to output.c
(trace_option, decode_trace_flags) Remove. Remove support for
different trace modes; we don't use it anymore.
(die) Invoke output_close() before we exit.
* misc.c (message_s, error_s): Removed; no longer needed.
(message, error, fatal, perror_with_name, pfatal_with_name): Moved
to output.c.
* makeint.h: Remove message_s(), error_s(), and
log_working_directory(). Remove the TRACE_* macros.
* doc/make.texi: Enhance documentation for output sync, and remove
MODE assignment for --trace.
* make.1: Remove MODE assignment for --trace.
* Makefile.am: Add new files.
* NMakefile.template: Ditto.
* SMakefile.template: Ditto.
* build_w32.bat: Ditto.
* dosbuild.bat: Ditto.
* make.lnk: Ditto.
* make_nsvc_net2003.vcproj: Ditto.
* makefile.vms: Ditto.
* po/POTFILES.in: Ditto.
2013-08-22 Petr Machata <pmachata@redhat.com>
* function.c (func_shell_base): Get rid of any avoidable limit on
stack size for processes spawned via $(shell).
2013-07-22 Paul Smith <psmith@gnu.org>
* implicit.c (pattern_search): Use PARSE_SIMPLE_SEQ() even for
non-second expansion prerequisites, to handle globbing in patterns.
Fixes Savannah bug #39310.
* dep.h (PARSE_SIMPLE_SEQ): Macro for simple file sequence parsing.
* default.c (set_default_suffixes): Use it.
* file.c (split_prereqs): Ditto.
* main.c (main): Ditto.
* read.c (eval): Ditto.
* rule.c (install_pattern_rule): Ditto.
* file.c (split_prereqs): Use PARSEFS_NONE instead of 0.
2013-07-21 Paul Smith <psmith@gnu.org>
Cleanups detected by cppcheck. Fixes Savannah bug #39158.
* arscan.c (ar_scan): Reduce the scope of local variables.
* dir.c (vms_hash): Ditto.
(find_directory): Ditto.
(file_impossible_p): Ditto.
* expand.c (variable_expand_string): Ditto.
* function.c (func_sort): Ditto.
(func_and): Ditto.
* job.c (reap_children): Ditto.
(exec_command): Ditto.
* main.c (main): Ditto.
* misc.c (collapse_continuations): Ditto.
* read.c (eval): Ditto.
(parse_file_seq): Ditto.
* vpath.c (gpath_search): Ditto.
(selective_vpath_search): Ditto.
* job.c (is_bourne_compatible_shell): Simplify for non-Windows systems.
* remake.c (f_mtime): Remove duplicate test.
* signame.c (strsignal): Fix bogus conditional.
* job.c (assign_child_tempfiles): Assign OUTFD to -1 for safety.
(start_job_command): Don't test output_sync and sync_cmd: redundant.
Changes suggested by Frank Heckenbach <f.heckenbach@fh-soft.de>.
2013-07-14 Paul Smith <psmith@gnu.org>
* filedef.h (update_status): Convert UPDATE_STATUS from a char to
an enumeration. Some systems declare "char" to be "unsigned"
which broke the code (which expected to be able to use -1 as a
flag). Using magic values was unpleasant, so rather than just
force "signed char" I reworked it to use an enum.
* dep.h (update_goal_chain): Return an update_status value not int.
* remake.c (touch_file): Ditto.
(update_goal_chain): Track the update_status enum.
* file.c (enter_file): Use new enumeration values with update_status.
(remove_intermediates): Ditto.
(print_file): Ditto.
* commands.c (execute_file_commands): Ditto.
* job.c (reap_children): Ditto.
(start_job_command): Ditto.
(start_waiting_job): Ditto.
* main.c (main): Ditto.
* remake.c (update_file): Ditto.
(complain): Ditto.
(update_file_1): Ditto.
(notice_finished_file): Ditto.
(remake_file): Ditto.
* vmsjobs.c (vmsHandleChildTerm): Ditto.
2013-07-09 Paul Smith <psmith@gnu.org>
* implicit.c (pattern_search): Keep a local copy of the number of
deps in deplist: the global max might change due to recursion.
Fixes a bug reported by Martin d'Anjou <martin.danjou14@gmail.com>.
2013-06-28 Paul Smith <psmith@gnu.org>
* misc.c (set_append_mode): Set the O_APPEND flag on a file descriptor.
(open_tmpfd): Set append mode on the temporary file descriptor.
* main.c (main): Set append mode on stdout and stderr.
* makeint.h (set_append_mode): Declare it.
2013-06-22 Eli Zaretskii <eliz@gnu.org>
* build_w32.bat (LinkGCC): Prevent a comment from being displayed
at build time.
* job.c (construct_command_argv_internal) [WINDOWS32]: Use
case-insensitive comparison with internal commands of non-Unix
shells.
* main.c (find_and_set_default_shell): Don't use file_exists_p or
dir_file_exists_p, as those call readdir, which can fail if PATH
includes directories with non-ASCII characters, and that would
cause Make to fail at startup with confusing diagnostics. See
https://sourceforge.net/mailarchive/message.php?msg_id=30846737
for the details.
2013-06-22 Paul Smith <psmith@gnu.org>
Improve performance by using a character map to determine where we
want to stop searching strings, rather than discrete comparisons.
* read.c (find_char_unquote): Pass a stop map instead of various
flags and use that to check when to stop parsing the string.
(eval): Use the new find_char_unquote() calling signature.
(remove_comments): Ditto.
(unescape_char): Ditto.
(find_percent_cached): Ditto.
(parse_file_seq): Use a stop-map flag.
* main.c (stopchar_map): Character map definition.
(initialize_stopchar_map): Initialize the map definition.
(main): Invoke the map initialization function.
* misc.c (end_of_token_w32): Remove unused function.
* dir.c (dosify): Use STOP_SET to check for stop chars.
* main.c (main): Ditto.
* misc.c (end_of_token): Ditto.
* function.c (subst_expand): Ditto.
(func_notdir_suffix): Ditto.
(func_basename_dir): Ditto.
(abspath): Ditto.
* job.c (is_bourne_compatible_shell): Ditto.
* variable.c (parse_variable_definition): Ditto.
* read.c (eval): Ditto.
(conditional_line): Ditto.
(find_percent_cached): Ditto.
* dep.h (PARSE_FILE_SEQ): Update function declaration.
* default.c (set_default_suffixes): Update PARSE_FILE_SEQ() call.
* file.c (split_prereqs): Ditto.
* function.c (string_glob): Ditto.
* implicit.c (pattern_search): Ditto.
* rule.c (install_pattern_rule): Ditto.
* main.c (main): Ditto.
2013-06-21 Paul Smith <psmith@gnu.org>
* main.c (verify_flag): Global variable to determine whether to
verify the database or not.
(decode_debug_flags): If debug mode, enable verify_flag.
(main): If MAKE_MAINTAINER_MODE, enable verify_flag, otherwise not.
(die): Only verify the database if verify_flag is set.
* file.c (enter_file): Don't check caching unless verify_flag.
* makeint.h: Export verify_flag.
2013-05-27 Paul Smith <psmith@gnu.org>
* variable.c (define_automatic_variables): Create a new variable
MAKE_HOST.
2013-05-27 Hartmut Becker <becker.ismaning@freenet.de>
* function.c (func_shell_base) [VMS]: Support VMS.
* makefile.com [VMS]: Ditto.
* makefile.vms [VMS]: Ditto.
* makeint.h [VMS]: Ditto.
* vmsjobs.c [VMS]: Ditto.
* job.h: Define RECORD_SYNC_MUTEX() when OUTPUT_SYNC is not set.
* load.c (unload_file): Fix signature if MAKE_LOAD is not set.
2013-05-26 Paul Smith <psmith@gnu.org>
* remake.c (f_mtime): Ensure that archive file names are in the
string cache. Fixes Savannah bug #38442.
* read.c (readline): To be safe, move the entire buffer if we
detect a CR. Fixes Savannah bug #38945.
* job.c (new_job): Compare OUT to the beginning of the OUT
var/function, not IN. Fixes Savannah bug #39035.
2013-05-22 Paul Smith <psmith@gnu.org>
* main.c (switches[]): Order switches so simple flags all come first.
(define_makeflags): Rework to make option passing more
reliable and the code less tricksy. Ensure simple flags are kept
in the initial batch of flags. Do not allow any flags with
options in that batch. If there are only non-simple flags MAKEFLAGS
begins with ' '.
(print_data_base): Print the version. Fixes part of Savannah #35336.
* read.c (eval_buffer): Initialize lineno.
2013-05-18 Alexey Pavlov <alexpux@gmail.com> (tiny change)
* w32/Makefile.am (libw32_a_SOURCES): Add compat/posixfcn.c.
* configure.ac (OUTPUT_SYNC): Define for mingw32 target.
* job.c (construct_command_argv_internal) <sh_cmds_dos>
[WINDOWS32]: Add "move". Fixes Savannah bug #30714.
* guile.c: Move inclusion of makeint.h before gnumake.h. This
order must be observed when building Make, because gnumake.h must
be included with GMK_BUILDING_MAKE defined, which makeint.h
already does. Otherwise, the linker will look for, and fail to
find, gmk_* functions in some external dynamic library.
2013-05-17 Benno Schulenberg <bensberg@justemail.net>
* main.c (decode_output_sync_flags): Fix output message.
* read.c (EXTRANEOUS): Ditto.
(record_files): Ditto.
* remake.c (update_file_1): Ditto.
2013-05-17 Eli Zaretskii <eliz@gnu.org>
* main.c (prepare_mutex_handle_string): Define conditioned on
OUTPUT_SYNC.
* build_w32.bat: Copy config.h.W32 to config.h regardless of
whether or not we are building from SCM.
2013-05-17 Paul Smith <psmith@gnu.org>
* configure.ac: Update version to 3.99.90.

View File

@@ -1703,7 +1703,7 @@ Thu Sep 14 18:29:38 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU)
existing variable's origin, is `o_env', make it `o_env_override'.
* load.c: Use the symbol KERNEL_FILE_NAME instead of KERNEL_FILE.
* compatMakefile: Changed the comment for `LOAD_AVG' accordinly.
* compatMakefile: Changed the comment for `LOAD_AVG' accordingly.
Thu Sep 7 16:46:26 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU)
@@ -3218,7 +3218,7 @@ Sun Feb 5 19:52:38 1989 Roland McGrath (mcgrath at paris.Berkeley.EDU)
* variable.c (expand_function: `shell'): Use
`shell_function_completed'. Block children before forking and
unblock after `shell_function_pid' is set properly and
`shell_functon_completed' is reset to 0.
`shell_function_completed' is reset to 0.
* commands.c (child_handler): When the child of the `shell' function
completes, set `shell_function_completed' to 1 if it actually ran,
@@ -4465,7 +4465,7 @@ Fri Sep 16 13:59:59 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU)
`maxsuffix', and must be called before count_implicit_rule_limits.
* rule.c (pattern_search): If an existent (non-intermediate)
dependendency was found via a terminal rule, set its
dependency was found via a terminal rule, set its
`tried_implicit' flag, so it will never have implicit rule search done.
* glob.c: Bug fix to avoid alloca(0).
@@ -4826,7 +4826,7 @@ Sat Jul 30 15:47:23 1988 Roland McGrath (mcgrath at tully.Berkeley.EDU)
new entry as the old entry's prev pointer.
* dir.c: Re-indented the `struct dir' definition to be right.
(dir_load): Cleaned up slighty.
(dir_load): Cleaned up slightly.
(file_exists_p): Removed comment saying we could use `access', since
that is a bad idea (except for setuid programs). Cleaned up slightly.

View File

@@ -88,7 +88,7 @@ INCLUDES = -I$(srcdir)/glob -DLIBDIR=\"$(prefix)$(libdir)\" -DINCLUDEDIR=\"$(pre
BUILT_SOURCES = README build.sh-in
EXTRA_DIST = $(BUILT_SOURCES) $(man_MANS) README.customs remote-cstms.c make-stds.texi texinfo.tex SCOPTIONS SMakefile Makefile.ami README.Amiga config.ami amiga.c amiga.h NMakefile README.DOS configh.dos configure.bat makefile.com README.W32 build_w32.bat config.h-W32 subproc.bat make.lnk config.h-vms makefile.vms readme.vms vmsdir.h vmsfunctions.c vmsify.c gmk-default.scm gmk-default.h
EXTRA_DIST = $(BUILT_SOURCES) $(man_MANS) README.customs remote-cstms.c make-stds.texi texinfo.tex SCOPTIONS SMakefile Makefile.ami README.Amiga config.ami amiga.c amiga.h NMakefile README.DOS configh.dos configure.bat makefile.com README.W32 build_w32.bat config.h-W32 subproc.bat make.lnk config.h-vms makefile.vms README.VMS vmsdir.h vmsfunctions.c vmsify.c gmk-default.scm gmk-default.h
SUBDIRS = glob doc
mkinstalldirs = ${exec_prefix}/bin/gmkdir -p

View File

@@ -41,8 +41,8 @@ endif
make_SOURCES = ar.c arscan.c commands.c default.c dir.c expand.c file.c \
function.c getopt.c getopt1.c implicit.c job.c load.c \
loadapi.c main.c misc.c read.c remake.c rule.c signame.c \
strcache.c variable.c version.c vpath.c hash.c \
loadapi.c main.c misc.c output.c read.c remake.c rule.c \
signame.c strcache.c variable.c version.c vpath.c hash.c \
$(remote)
if HAVE_GUILE
@@ -52,7 +52,7 @@ endif
EXTRA_make_SOURCES = vmsjobs.c remote-stub.c remote-cstms.c
noinst_HEADERS = commands.h dep.h filedef.h job.h makeint.h rule.h variable.h \
debug.h getopt.h gettext.h hash.h
debug.h getopt.h gettext.h hash.h output.h
make_LDADD = @LIBOBJS@ @ALLOCA@ $(GLOBLIB) @GETLOADAVG_LIBS@ @LIBINTL@ \
$(GUILE_LIBS)
@@ -82,7 +82,7 @@ EXTRA_DIST = README build.sh.in $(man_MANS) \
README.DOS Makefile.DOS configure.bat dosbuild.bat configh.dos\
README.W32 NMakefile config.h.W32 build_w32.bat subproc.bat \
make_msvc_net2003.sln make_msvc_net2003.vcproj \
readme.vms makefile.vms makefile.com config.h-vms \
README.VMS makefile.vms makefile.com config.h-vms \
vmsdir.h vmsfunctions.c vmsify.c \
gmk-default.scm gmk-default.h

90
NEWS
View File

@@ -1,6 +1,6 @@
GNU make NEWS -*-indented-text-*-
History of user-visible changes.
17 May 2013
09 Oct 2013
See the end of this file for copyrights and conditions.
@@ -9,7 +9,7 @@ manual, which is contained in this distribution as the file doc/make.texi.
See the README file and the GNU make manual for instructions for
reporting bugs.
Version 3.99.90
Version 4.0 (09 Oct 2013)
A complete list of bugs fixed in this version is available here:
@@ -23,6 +23,14 @@ http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=101&set
* Each backslash/newline (plus subsequent whitespace) is converted to a
single space
* New feature: GNU Guile integration
This version of GNU make can be compiled with GNU Guile integration.
GNU Guile serves as an embedded extension language for make.
See the "Guile Function" section in the GNU Make manual for details.
Currently GNU Guile 1.8 and 2.0+ are supported. In Guile 1.8 there is no
support for internationalized character sets. In Guile 2.0+, scripts can be
encoded in UTF-8.
* New command line option: --output-sync (-O) enables grouping of output by
target or by recursive make. This is useful during parallel builds to avoid
mixing output from different jobs together giving hard-to-understand
@@ -34,9 +42,10 @@ http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=101&set
the recipe to be invoked is printed even if it would otherwise be suppressed
by .SILENT or a "@" prefix character. Also before each recipe is run the
makefile name and linenumber where it was defined are shown as well as the
prerequisites that caused the target to be considered out of date. If the
"dir" option argument is given, it will display directory enter/leave
logging around each block of synchronized output.
prerequisites that caused the target to be considered out of date.
* New command line option argument: --debug now accepts a "n" (none) flag
which disables all debugging settings that are currently enabled.
* New feature: The "job server" capability is now supported on Windows.
Implementation contributed by Troy Runkel <Troy.Runkel@mathworks.com>
@@ -46,6 +55,8 @@ http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=101&set
* New feature: "!=" shell assignment operator as an alternative to the
$(shell ...) function. Implemented for compatibility with BSD makefiles.
Note there are subtle differences between "!=" and $(shell ...). See the
description in the GNU make manual.
WARNING: Backward-incompatibility!
Variables ending in "!" previously defined as "variable!= value" will now be
interpreted as shell assignment. Change your assignment to add whitespace
@@ -57,11 +68,6 @@ http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=101&set
version of POSIX (see http://austingroupbugs.net/view.php?id=330). It is
not necessary to define the .POSIX target to access this operator.
* New feature: GNU Guile integration
This version of GNU make can be compiled with GNU Guile integration.
GNU Guile serves as an embedded extension language for make.
See the "Guile Function" section in the GNU Make manual for details.
* New feature: Loadable objects
This version of GNU make contains a "technology preview": the ability to
load dynamic objects into the make runtime. These objects can be created by
@@ -72,10 +78,24 @@ http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=101&set
* New variable: $(GNUMAKEFLAGS) will be parsed for make flags, just like
MAKEFLAGS is. It can be set in the environment or the makefile, containing
GNU make-specific flags to allow your makefile to be portable to other
versions of make. GNU make never sets or modifies GNUMAKEFLAGS.
versions of make. Once this variable is parsed, GNU make will set it to the
empty string so that flags will not be duplicated on recursion.
* On failure, the makefile name and linenumber of the recipe that failed are
shown.
* New variable: `MAKE_HOST' gives the name of the host architecture
make was compiled for. This is the same value you see after 'Built for'
when running 'make --version'.
* Behavior of MAKEFLAGS and MFLAGS is more rigorously defined. All simple
flags are grouped together in the first word of MAKEFLAGS. No options that
accept arguments appear in the first word. If no simple flags are present
MAKEFLAGS begins with a space. Flags with both short and long versions
always use the short versions in MAKEFLAGS. Flags are listed in
alphabetical order using ASCII ordering. MFLAGS never begins with "- ".
* Setting the -r and -R options in MAKEFLAGS inside a makefile now works as
expected, removing all built-in rules and variables, respectively.
* If a recipe fails, the makefile name and linenumber of the recipe are shown.
* A .RECIPEPREFIX setting is remembered per-recipe and variables expanded
in that recipe also use that recipe prefix setting.
@@ -93,7 +113,7 @@ http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=101&set
behavior when the recipe uses quoted string on shell command lines.
Version 3.82
Version 3.82 (28 Jul 2010)
A complete list of bugs fixed in this version is available here:
@@ -206,7 +226,7 @@ http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=104&set
multi-line variable assignment.
Version 3.81
Version 3.81 (01 Apr 2006)
* GNU make is ported to OS/2.
@@ -329,7 +349,7 @@ Version 3.81
could be found on the system.
* On VMS there is now support for case-sensitive filesystems such as ODS5.
See the readme.vms file for information.
See the README.VMS file for information.
* Parallel builds (-jN) no longer require a working Bourne shell on
Windows platforms. They work even with the stock Windows shells, such
@@ -347,7 +367,7 @@ A complete list of bugs fixed in this version is available here:
http://savannah.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=103
Version 3.80
Version 3.80 (03 Oct 2002)
* A new feature exists: order-only prerequisites. These prerequisites
affect the order in which targets are built, but they do not impact
@@ -429,7 +449,7 @@ A complete list of bugs fixed in this version is available here:
http://savannah.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=102
Version 3.79.1
Version 3.79.1 (23 Jun 2000)
* .SECONDARY with no prerequisites now prevents any target from being
removed because make thinks it's an intermediate file, not just those
@@ -438,7 +458,7 @@ Version 3.79.1
* New configure option --disable-nsec-timestamps, but this was
superseded in later versions by the .LOW_RESOLUTION_TIME pseudo-target.
Version 3.79
Version 3.79 (04 Apr 2000)
* GNU make optionally supports internationalization and locales via the
GNU gettext (or local gettext if suitable) package. See the ABOUT-NLS
@@ -479,9 +499,9 @@ Version 3.79
returned.
* Hartmut Becker provided many updates for the VMS port of GNU make.
See the readme.vms file for more details.
See the README.VMS file for more details.
Version 3.78
Version 3.78 (22 Sep 1999)
* Two new functions, $(error ...) and $(warning ...) are available. The
former will cause make to fail and exit immediately upon expansion of
@@ -537,7 +557,7 @@ Version 3.78
by running "make check" in the distribution. Note that it requires
Perl (either Perl 4 or Perl 5) to run.
Version 3.77
Version 3.77 (28 Jul 1998)
* Implement BSD make's "?=" variable assignment operator. The variable
is assigned the specified value only if that variable is not already
@@ -583,11 +603,11 @@ Version 3.77
* Updates to the Windows 95/NT port from Rob Tulloh (see README.W32),
and to the DOS port from Eli Zaretski (see README.DOS).
Version 3.76.1
Version 3.76.1 (19 Sep 1997)
* Small (but serious) bug fix. Quick rollout to get into the GNU source CD.
Version 3.76
Version 3.76 (16 Sep 1997)
* GNU make now uses automake to control Makefile.in generation. This
should make it more consistent with the GNU standards.
@@ -632,7 +652,7 @@ Version 3.76
* John W. Eaton has updated the VMS port to support libraries and VPATH.
Version 3.75
Version 3.75 (27 Aug 1996)
* The directory messages printed by `-w' and implicitly in sub-makes,
are now omitted if Make runs no commands and has no other messages to print.
@@ -653,7 +673,7 @@ Version 3.75
See README.W32 for details, and direct all Windows-related questions to
<rob_tulloh@tivoli.com>.
Version 3.73
Version 3.73 (05 Apr 1995)
* Converted to use Autoconf version 2, so `configure' has some new options.
See INSTALL for details.
@@ -661,7 +681,7 @@ Version 3.73
* You can now send a SIGUSR1 signal to Make to toggle printing of debugging
output enabled by -d, at any time during the run.
Version 3.72
Version 3.72 (04 Nov 1994)
* DJ Delorie has ported Make to MS-DOS using the GO32 extender.
He is maintaining the DOS port, not the GNU Make maintainer;
@@ -695,7 +715,7 @@ Version 3.72
of `.SILENT', then the recipe to update that file will not be printed
before it is run. (This change was made to conform to POSIX.2.)
Version 3.71
Version 3.71 (21 May 1994)
* The automatic variables `$(@D)', `$(%D)', `$(*D)', `$(<D)', `$(?D)', and
`$(^D)' now omit the trailing slash from the directory name. (This change
@@ -717,7 +737,7 @@ Version 3.71
The exit status is 1 only when using -q and some target is not up to date.
(This change was made to comply with POSIX.2.)
Version 3.70
Version 3.70 (03 Jan 1994)
* It is no longer a fatal error to have a NUL character in a makefile.
You should never put a NUL in a makefile because it can have strange
@@ -728,7 +748,7 @@ Version 3.70
makefile name and line number where the `include' appeared, so Emacs's
C-x ` command takes you there (in case it's a typo you need to fix).
Version 3.69
Version 3.69 (07 Nov 1993)
* Implicit rule search for archive member references is now done in the
opposite order from previous versions: the whole target name `LIB(MEM)'
@@ -758,7 +778,7 @@ Version 3.69
* The recipe given for `.DEFAULT' is now used for phony targets with no
recipe.
Version 3.68
Version 3.68 (28 Jul 1993)
* You can list several archive member names inside parenthesis:
`lib(mem1 mem2 mem3)' is equivalent to `lib(mem1) lib(mem2) lib(mem3)'.
@@ -784,16 +804,16 @@ Version 3.68
to set up variables for them. They used to run with the environment
that `make' started with.
Version 3.66
Version 3.66 (21 May 1993)
* `make --version' (or `make -v') now exits immediately after printing
the version number.
Version 3.65
Version 3.65 (09 May 1993)
* Make now supports long-named members in `ar' archive files.
Version 3.64
Version 3.64 (21 Apr 1993)
* Make now supports the `+=' syntax for a variable definition which appends
to the variable's previous value. See the section `Appending More Text
@@ -807,7 +827,7 @@ Version 3.64
* The built-in implicit rules now support the alternative extension
`.txinfo' for Texinfo files, just like `.texinfo' and `.texi'.
Version 3.63
Version 3.63 (22 Jan 1993)
* Make now uses a standard GNU `configure' script. See the new file
INSTALL for the new (and much simpler) installation procedure.

View File

@@ -91,6 +91,7 @@ OBJS = \
$(OUTDIR)/job.obj \
$(OUTDIR)/main.obj \
$(OUTDIR)/misc.obj \
$(OUTDIR)/output.obj \
$(OUTDIR)/read.obj \
$(OUTDIR)/remake.obj \
$(OUTDIR)/remote-stub.obj \

View File

@@ -1,23 +1,33 @@
This is the VMS version of GNU Make, updated by Hartmut Becker
Changes are based on GNU make 3.82.
This version was built and tested on OpenVMS V7.3 (VAX), V7.3-2 (Alpha) and
V8.3-1H1 (I64).
This version of GNU make has been tested on
OpenVMS V8.3 (Alpha) and V8.4 (Integrity).
Build instructions
------------------
Make a 1st version
$ @makefile.com ! ignore any compiler and/or linker warning
$ rena make.exe 1st-make.exe
Use the 1st version to generate a 2nd version
$ mc sys$disk:[]1st-make clean
$ copy make.exe 1st-make.exe
Use the 1st version to generate a 2nd version
$ mc sys$disk:[]1st-make clean ! ignore any file not found messages
$ mc sys$disk:[]1st-make
Verify your 2nd version
$ rena make.exe 2nd-make.exe
Verify your 2nd version
$ copy make.exe 2nd-make.exe
$ mc sys$disk:[]2nd-make clean
$ mc sys$disk:[]2nd-make
Don't use the HP C V7.2-001 compiler, which has an incompatible change
how __STDC__ is defined. This results at least in compile time warnings.
Changes since GNU make 3.82
---------------------------
Changes (3.81.90)
Fix build problems.
The new feature "Loadable objects" is not yet supported. If you need it,
please send a change request or submit a bug report.
The new option --output-sync (-O) is accepted but has no effect: GNU make
for VMS does not support running multiple commands simultaneously.
Changes for GNU make 3.82
Michael Gehre (at VISTEC-SEMI dot COM) supplied a fix for a problem with
timestamps of object modules in OLBs. The timestamps were not correctly
@@ -34,30 +44,6 @@ systems.
Build fixes for const-ified code in VMS specific sources.
Build notes:
- Try to avoid HP C V7.2-001, which has an incompatible change
how __STDC__ is defined. This results at least in compile time warnings.
- On V8.3-1H1, if you press Ctrl+C you may see a traceback, starting with
%SYSTEM-F-CONTROLC, operation completed under CTRL/C
%TRACE-F-TRACEBACK, symbolic stack dump follows
image module routine line rel PC abs PC
DECC$SHR C$SIGNAL gsignal 27991 0000000000001180
FFFFFFFF84AB2DA0
DECC$SHR C$SIGNAL raise 28048 0000000000001280
FFFFFFFF84AB2EA0
DECC$SHR C$SIGPENDING decc$$deliver_signals
12475 0000000000000890
FFFFFFFF84C13690
...
This looks like an incompatibility to the Alpha and VAX behavior, so it looks
like a problem in I64 VMS version(s).
- There is no clean build on VAX. In the environment I tested, I had to use GNU
make's alloca which produced a couple of compile time warnings. It seems too
much effort to work on a clean build on VAX.
A note on appending the redirected output. With this change, a simple mechanism
is implemented to make ">>" work in action lines. In VMS there is no simple
feature like ">>" to have DCL command or program output redirected and appended
@@ -78,117 +64,24 @@ happens. Pressing Ctrl+Y to abort make is one case. In case of Ctrl+Y the
associated command procedure is left in SYS$SCRATCH as well. Its name is
CMDxxxxx.COM.
Change in the Ctrl+Y handling
Change in the Ctrl+Y handling. The CtrlY handler now uses $delprc to delete all
children. This way also actions with DCL commands will be stopped. As before
the CtrlY handler then sends SIGQUIT to itself, which is handled in common
code.
Ctrl+Y was: The CtrlY handler called $forcex for the current child.
Ctrl+Y changed: The CtrlY handler uses $delprc to delete all children. This way
also actions with DCL commands will be stopped. As before Ctrl+Y then sends
SIGQUIT to itself, which is handled in common code.
Change in deleteing temporary command files
Temporary command files were deleted in the main line, after returning from the
vms child termination handler. If Ctrl+C was pressed, the handler is called but
did not return to main line.
Now, temporary command files are deleted in the vms child termination
handler. That deletes the them even if a Ctrl+C was pressed.
Change in deleteing temporary command files. Temporary command files are now
deleted in the vms child termination handler. That deletes them even if
a Ctrl+C was pressed.
The behavior of pressing Ctrl+C is not changed. It still has only an effect,
after the current action is terminated. If that doesn't happen or takes too
long, Ctrl+Y should be used instead.
Changes (3.80)
Changes for GNU make 3.80
. In default.c define variable ARCH as IA64 for VMS on Itanium systems.
. In makefile.vms avoid name collision for glob and globfree.
In newer version of the VMS CRTL there are glob and globfree implemented.
Compiling and linking may result in
%ILINK-W-MULDEFLNKG, symbol DECC$GLOBFREE has subsequent linkage definition
in module DECC$SHR file SYS$COMMON:[SYSLIB]DECC$SHR.EXE;1
%ILINK-W-MULDEF, symbol DECC$GLOBFREE multiply defined
in module DECC$SHR file SYS$COMMON:[SYSLIB]DECC$SHR.EXE;1
linker messages (and similar for DECC$GLOB). The messages just say, that
globfree is a known CRTL whose name was mapped by the compiler to
DECC$GLOBFREE. This is done in glob.c as well, so this name is defined
twice. One possible solution is to use the VMS versions of glob and
globfree. However, then the build environment needs to figure out if
there is a new CRTL supporting these or not. This adds complexity. Even
more, these functions return VMS file specifications, which is not
expected by the other make sources. There is a switch at run time (a VMS
logical DECC$GLOB_UNIX_STYLE), which can be set to get Unix style
names. This may conflict with other software. The recommended solution
for this is to set this switch just prior to calling main: in an
initialization routine. This adds more complexity and more VMS specific
code. It is easier to tell the compiler NOT to map the routine names
with a simple change in makefile.vms.
Some notes on case sensitive names in rules and on the disk. In the VMS
template for CONFIG.H case sensitive rules can be enabled with defining
WANT_CASE_SENSITIVE_TARGETS. For recent version of VMS there is a case
sensitive file system: ODS5. To make use of that, additionally un-defining
the HAVE_CASE_INSENSITIVE_FS is required. As these are C macros, different
versions of make need to be built to have any case sensitivity for VMS
working. Unfortunately, for ODS5 disks that's not all.
- Usually DCL upcases command line tokens (except strings) and usually the
file system is case blind (similar to how Windows systems work)
$ set proc/parse=extended/case=sensitive
preserves lower and UPPER on the command line and (for this process and all
sub-processes) enables case sensitivity in the file system
- Usually the CRTL tries to reverse what DCL did with command line tokens, it
lowercases all tokens (except strings)
$ define DECC$ARGV_PARSE_STYLE enable
passes (the now preserved) lower and UPPER from the command line to main()
- Usually the CRTL upcases the arguments to open() and friends
$ define DECC$EFS_CASE_PRESERVE enable
preserves the names as is.
It is important to know that not all VMS tools are ready for case sensitivity.
With this setup some tools may not work as expected. The setup should not
blindly be applied for all users in default login procedures.
Example? The poor coding gives a compiler message, showing that there are
different files:
$ dir
Directory ODS5DISK[HB]
A.c;1 B.c;1 c.c;1 X.c;1
x.c;1
Total of 5 files.
$ ods5make x.obj
cc /obj=x.obj x.c
foo(){lowercase_x();}
......^
%CC-I-IMPLICITFUNC, In this statement, the identifier "lowercase_x" is implicitly declared as a function.
at line number 1 in file ODS5DISK[HB]x.c;1
$ mc SYS$SYSDEVICE:[HARTMUT.MAKE_3_80P]ods5make X.obj
cc /obj=X.obj X.c
foo() {UPPERCASE_X();}
.......^
%CC-I-IMPLICITFUNC, In this statement, the identifier "UPPERCASE_X" is implicitly declared as a function.
at line number 1 in file ODS5DISK[HB]X.c;1
$ dir
Directory ODS5DISK[HB]
A.c;1 B.c;1 c.c;1 X.c;1
x.c;1 X.obj;1 x.obj;1
Total of 7 files.
$
This is the VMS port of GNU Make done by Hartmut.Becker@compaq.com.

View File

@@ -7,7 +7,7 @@ It builds with the MinGW port of GCC (tested with GCC 3.4.2).
It also builds with MSVC 2.x, 4.x, 5.x, 6.x, and 2003 as well as
with .NET 7.x and .NET 2003.
As of version 3.83, 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
itself, its dependency libraries and the pkg-config program. The
latter is used to figure out which compilation and link switches and

View File

@@ -214,7 +214,7 @@ For both final releases and pre-releases, send an email with the URL of
the package to the GNU translation robot to allow the translators to
work on it:
<translation@iro.umontreal.ca>
<coordinator@translationproject.org>
Where to Announce

View File

@@ -142,7 +142,7 @@ Ports
- See README.customs for details on integrating GNU make with the
Customs distributed build environment from the Pmake distribution.
- See readme.vms for details about GNU Make on OpenVMS.
- See README.VMS for details about GNU Make on OpenVMS.
- See README.Amiga for details about GNU Make on AmigaDOS.

View File

@@ -128,7 +128,8 @@ CTAGS = ctags -w
objs = commands.o job.o dir.o file.o misc.o main.o read.o remake.o \
rule.o implicit.o default.o variable.o expand.o function.o \
vpath.o version.o ar.o arscan.o signame.o strcache.o hash.o \
remote-$(REMOTE).o $(GLOB) $(GETOPT) $(ALLOCA) $(extras) $(guile)
output.o remote-$(REMOTE).o $(GLOB) $(GETOPT) $(ALLOCA) \
$(extras) $(guile)
srcs = $(srcdir)commands.c $(srcdir)job.c $(srcdir)dir.c \
$(srcdir)file.c $(srcdir)getloadavg.c $(srcdir)misc.c \
@@ -141,6 +142,7 @@ srcs = $(srcdir)commands.c $(srcdir)job.c $(srcdir)dir.c \
$(srcdir)signame.c $(srcdir)signame.h $(GETOPT_SRC) \
$(srcdir)commands.h $(srcdir)dep.h $(srcdir)file.h \
$(srcdir)job.h $(srcdir)makeint.h $(srcdir)rule.h \
$(srcdir)output.c $(srcdir)output.h \
$(srcdir)variable.h $(ALLOCA_SRC) $(srcdir)config.h.in

View File

@@ -99,30 +99,6 @@ The Rest of the List
you just can't figure it out. The way variables are expanded now
means this isn't 100% trivial, but it probably won't be hard.
8) Integration of Guile as an embedded scripting language. This means:
allowing Guile functions to be declared in makefiles somehow, then
providing a syntax for invoking them. At least one formulation of
that would have the function resolve to a string which would be
substituted in the makefile, kind of like $(shell ...) does now, but
using the embedded interpreter so there's no process forked of
course. Obviously this is an optional add-on feature.
It could be more advanced than that, even, who knows? Maybe make
could provide Guile functions that allow Guile scripts more direct
access to internal make structures, somehow. This kind of thing
needs a lot of thought.
Also there's always the flip side: in some very fundamental ways
make isn't the best choice right now for a complex build tool. It's
great for simple-to-medium tasks, but there are already other tools
available for the really tough situations. Ask yourself,
realistically, how much work is worthwhile to add to make, given the
fundamentals you can't really overcome without significantly
affecting backward compatibility--and then why not use another tool
in the first place?
Something to think about.
-------------------------------------------------------------------------------
Copyright (C) 1997-2013 Free Software Foundation, Inc.

View File

@@ -328,12 +328,10 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
{
#ifdef AIAMAG
FL_HDR fl_header;
#ifdef AIAMAGBIG
# ifdef AIAMAGBIG
int big_archive = 0;
FL_HDR_BIG fl_header_big;
#endif
#else
int long_name = 0;
# endif
#endif
char *namemap = 0;
int desc = open (archive, O_RDONLY, 0);
@@ -461,6 +459,7 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg)
char namebuf[sizeof member_header.ar_name + 1];
char *name;
int is_namemap; /* Nonzero if this entry maps long names. */
int long_name = 0;
#endif
long int eltsize;
int eltmode;

View File

@@ -21,11 +21,11 @@ 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
copy config.h.W32 config.h
rem Guile configuration
set GUILECFLAGS=
@@ -122,6 +122,8 @@ cl.exe /nologo /MT /W4 /GX /Zi /YX /Od /I . /I glob /I w32/include /D _DEBUG /D
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
@@ -166,7 +168,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/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/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"
@@ -199,6 +201,8 @@ cl.exe /nologo /MT /W4 /GX /YX /O2 /I . /I glob /I w32/include /D NDEBUG /D WIND
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
@@ -243,7 +247,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/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/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"
@@ -265,6 +269,7 @@ gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% -I. -I./glob -I./w32/include -DWINDOWS32
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
@@ -290,10 +295,11 @@ set GUILEOBJ=guile.o
echo on
gcc -mthreads -Wall -gdwarf-2 -g3 %OPT% %GUILECFLAGS% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H -c guile.c
:LinkGCC
@echo off
Rem The version NN of libgnumake-NN.dll.a should be bumped whenever
Rem the API changes in binary-incompatible manner.
@echo on
gcc -mthreads -gdwarf-2 -g3 -o gnumake.exe variable.o rule.o remote-stub.o commands.o file.o getloadavg.o default.o signame.o expand.o dir.o main.o getopt1.o %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 -Wl,--out-implib=libgnumake-1.dll.a
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 output.o read.o version.o getopt.o arscan.o remake.o misc.o hash.o strcache.o ar.o function.o vpath.o implicit.o loadapi.o load.o glob.o fnmatch.o pathstuff.o posixfcn.o w32_misc.o sub_proc.o w32err.o %GUILELIBS% -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -Wl,--out-implib=libgnumake-1.dll.a
@GoTo BuildEnd
:Usage
echo Usage: %0 [options] [gcc]

View File

@@ -17,8 +17,8 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include <dlfcn.h>
#include "makeint.h"
#include "dep.h"
#include "filedef.h"
#include "dep.h"
#include "variable.h"
#include "job.h"
#include "commands.h"
@@ -459,7 +459,7 @@ execute_file_commands (struct file *file)
{
/* If there are no commands, assume everything worked. */
set_command_state (file, cs_running);
file->update_status = 0;
file->update_status = us_success;
notice_finished_file (file);
return;
}

View File

@@ -321,6 +321,9 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
/* Define if you have the sun library (-lsun). */
/* #undef HAVE_LIBSUN */
/* Output sync sypport */
#define NO_OUTPUT_SYNC
/* Define for Case Insensitve behavior */
#define HAVE_CASE_INSENSITIVE_FS

View File

@@ -411,5 +411,8 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#define alloca(n) __ALLOCA(n)
#endif
/* Output sync sypport */
#define NO_OUTPUT_SYNC
/* Build host information. */
#define MAKE_HOST "VMS"

View File

@@ -523,5 +523,3 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CYGWIN_SHELL
#undef BATCH_MODE_ONLY_SHELL
#endif
#define OUTPUT_SYNC

View File

@@ -100,8 +100,8 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
/* Define to the version of this package. */
#define PACKAGE_VERSION "%VERSION%"
/* Define to 1 if the C compiler supports function prototypes. */
#define PROTOTYPES 1
/* Output sync sypport */
#define NO_OUTPUT_SYNC
/* Version number of package */
#define VERSION "%VERSION%"

View File

@@ -16,7 +16,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/>.
AC_INIT([GNU make],[3.99.90],[bug-make@gnu.org])
AC_INIT([GNU make],[4.0],[bug-make@gnu.org])
AC_PREREQ([2.62])
@@ -62,7 +62,7 @@ AC_HEADER_DIRENT
AC_HEADER_STAT
AC_HEADER_TIME
AC_CHECK_HEADERS([stdlib.h locale.h unistd.h limits.h fcntl.h string.h \
memory.h sys/param.h sys/resource.h sys/time.h sys/timeb.h])
memory.h sys/param.h sys/resource.h sys/time.h sys/timeb.h])
AM_PROG_CC_C_O
AC_C_CONST
@@ -90,12 +90,12 @@ AC_CACHE_CHECK([whether to use high resolution file timestamps],
#if HAVE_INTTYPES_H
# include <inttypes.h>
#endif]],
[[char a[0x7fffffff < (uintmax_t)-1 >> 30 ? 1 : -1];]])],
[[char a[0x7fffffff < (uintmax_t)-1 >> 30 ? 1 : -1];]])],
[make_cv_file_timestamp_hi_res=yes])
])])
AS_IF([test "$make_cv_file_timestamp_hi_res" = yes], [val=1], [val=0])
AC_DEFINE_UNQUOTED([FILE_TIMESTAMP_HI_RES], [$val],
[Use high resolution file timestamps if nonzero.])
[Use high resolution file timestamps if nonzero.])
AS_IF([test "$make_cv_file_timestamp_hi_res" = yes],
[ # Solaris 2.5.1 needs -lposix4 to get the clock_gettime function.
@@ -103,7 +103,7 @@ AS_IF([test "$make_cv_file_timestamp_hi_res" = yes],
AC_SEARCH_LIBS([clock_gettime], [rt posix4])
AS_IF([test "$ac_cv_search_clock_gettime" != no],
[ AC_DEFINE([HAVE_CLOCK_GETTIME], [1],
[Define to 1 if you have the clock_gettime function.])
[Define to 1 if you have the clock_gettime function.])
])
])
@@ -117,24 +117,24 @@ AC_CACHE_CHECK([for standard gettimeofday], [ac_cv_func_gettimeofday],
[ac_cv_func_gettimeofday=no
AC_RUN_IFELSE([AC_LANG_SOURCE([[#include <sys/time.h>
int main ()
{
struct timeval t; t.tv_sec = -1; t.tv_usec = -1;
exit (gettimeofday (&t, 0) != 0
|| t.tv_sec < 0 || t.tv_usec < 0);
}]])],
[ac_cv_func_gettimeofday=yes],
[ac_cv_func_gettimeofday=no],
[ac_cv_func_gettimeofday="no (cross-compiling)"])])
{
struct timeval t; t.tv_sec = -1; t.tv_usec = -1;
exit (gettimeofday (&t, 0) != 0
|| t.tv_sec < 0 || t.tv_usec < 0);
}]])],
[ac_cv_func_gettimeofday=yes],
[ac_cv_func_gettimeofday=no],
[ac_cv_func_gettimeofday="no (cross-compiling)"])])
AS_IF([test "$ac_cv_func_gettimeofday" = yes],
[ AC_DEFINE([HAVE_GETTIMEOFDAY], [1],
[Define to 1 if you have a standard gettimeofday function])
[Define to 1 if you have a standard gettimeofday function])
])
AC_CHECK_FUNCS([strdup strndup mkstemp mktemp fdopen fileno \
dup dup2 getcwd realpath sigsetmask sigaction \
dup dup2 getcwd realpath sigsetmask sigaction \
getgroups seteuid setegid setlinebuf setreuid setregid \
getrlimit setrlimit setvbuf pipe strerror strsignal \
lstat readlink atexit])
lstat readlink atexit])
# We need to check declarations, not just existence, because on Tru64 this
# function is not declared without special flags, which themselves cause
@@ -181,11 +181,11 @@ AC_FUNC_GETLOADAVG
AS_IF([test "$ac_cv_header_nlist_h" = yes],
[ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <nlist.h>]],
[[struct nlist nl;
[[struct nlist nl;
nl.n_name = "string";
return 0;]])],
[make_cv_nlist_struct=yes],
[make_cv_nlist_struct=no])
[make_cv_nlist_struct=yes],
[make_cv_nlist_struct=no])
AS_IF([test "$make_cv_nlist_struct" = yes],
[ AC_DEFINE([NLIST_STRUCT], [1],
[Define to 1 if struct nlist.n_name is a pointer rather than an array.])
@@ -244,7 +244,7 @@ AC_SUBST([REMOTE]) REMOTE=stub
use_customs=false
AC_ARG_WITH([customs],
[ AC_HELP_STRING([--with-customs=DIR],
[enable remote jobs via Customs--see README.customs])],
[enable remote jobs via Customs--see README.customs])],
[ AS_CASE([$withval], [n|no], [:],
[make_cppflags="$CPPFLAGS"
AS_CASE([$withval],
@@ -254,7 +254,7 @@ AC_ARG_WITH([customs],
CF_NETLIBS
AC_CHECK_HEADER([customs.h],
[use_customs=true
REMOTE=cstms
REMOTE=cstms
LIBS="$LIBS -lcustoms" LDFLAGS="$make_ldflags"],
[with_customs=no
CPPFLAGS="$make_cppflags" make_badcust=yes])
@@ -268,7 +268,7 @@ AM_CONDITIONAL([USE_CUSTOMS], [test "$use_customs" = true])
AH_TEMPLATE([HAVE_CASE_INSENSITIVE_FS], [Use case insensitive file names])
AC_ARG_ENABLE([case-insensitive-file-system],
AC_HELP_STRING([--enable-case-insensitive-file-system],
[assume file systems are case insensitive]),
[assume file systems are case insensitive]),
[AS_IF([test "$enableval" = yes], [AC_DEFINE([HAVE_CASE_INSENSITIVE_FS])])])
# See if we can handle the job server feature, and if the user wants it.
@@ -368,7 +368,7 @@ AC_CACHE_CHECK([for location of SCCS get command], [make_cv_path_sccs_get], [
[make_cv_path_sccs_get=get])
])
AC_DEFINE_UNQUOTED([SCCS_GET], ["$make_cv_path_sccs_get"],
[Define to the name of the SCCS 'get' command.])
[Define to the name of the SCCS 'get' command.])
ac_clean_files="$ac_clean_files s.conftest conftoast" # Remove these later.
AS_IF([(/usr/sccs/admin -n s.conftest || admin -n s.conftest) >/dev/null 2>&1 &&

View File

@@ -547,9 +547,8 @@ set_default_suffixes (void)
{
struct dep *d;
char *p = default_suffixes;
suffix_file->deps = enter_prereqs (PARSE_FILE_SEQ (&p, struct dep, '\0',
NULL, 0),
NULL);
suffix_file->deps = enter_prereqs (PARSE_SIMPLE_SEQ (&p, struct dep),
NULL);
for (d = suffix_file->deps; d; d = d->next)
d->file->builtin = 1;

19
dep.h
View File

@@ -53,22 +53,23 @@ struct nameseq
const char *name;
};
#define PARSEFS_NONE (0x0000)
#define PARSEFS_NOSTRIP (0x0001)
#define PARSEFS_NOAR (0x0002)
#define PARSEFS_NOGLOB (0x0004)
#define PARSEFS_EXISTS (0x0008)
#define PARSEFS_NOCACHE (0x0010)
#define PARSEFS_NONE 0x0000
#define PARSEFS_NOSTRIP 0x0001
#define PARSEFS_NOAR 0x0002
#define PARSEFS_NOGLOB 0x0004
#define PARSEFS_EXISTS 0x0008
#define PARSEFS_NOCACHE 0x0010
#define PARSE_FILE_SEQ(_s,_t,_c,_p,_f) \
(_t *)parse_file_seq ((_s),sizeof (_t),(_c),(_p),(_f))
#define PARSE_SIMPLE_SEQ(_s,_t) \
(_t *)parse_file_seq ((_s),sizeof (_t),MAP_NUL,NULL,PARSEFS_NONE)
#ifdef VMS
void *parse_file_seq ();
#else
void *parse_file_seq (char **stringp, unsigned int size,
int stopchar, const char *prefix, int flags);
int stopmap, const char *prefix, int flags);
#endif
char *tilde_expand (const char *name);
@@ -88,4 +89,4 @@ void free_dep_chain (struct dep *d);
void free_ns_chain (struct nameseq *n);
struct dep *read_all_makefiles (const char **makefiles);
void eval_buffer (char *buffer, const gmk_floc *floc);
int update_goal_chain (struct dep *goals);
enum update_status update_goal_chain (struct dep *goals);

60
dir.c
View File

@@ -16,6 +16,8 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include "makeint.h"
#include "hash.h"
#include "filedef.h"
#include "dep.h"
#ifdef HAVE_DIRENT_H
# include <dirent.h>
@@ -84,21 +86,21 @@ dosify (const char *filename)
df = dos_filename;
/* First, transform the name part. */
for (i = 0; *filename != '\0' && i < 8 && *filename != '.'; ++i)
for (i = 0; i < 8 && ! STOP_SET (*filename, MAP_DOT|MAP_NUL); ++i)
*df++ = tolower ((unsigned char)*filename++);
/* Now skip to the next dot. */
while (*filename != '\0' && *filename != '.')
while (! STOP_SET (*filename, MAP_DOT|MAP_NUL))
++filename;
if (*filename != '\0')
{
*df++ = *filename++;
for (i = 0; *filename != '\0' && i < 3 && *filename != '.'; ++i)
for (i = 0; i < 3 && ! STOP_SET (*filename, MAP_DOT|MAP_NUL); ++i)
*df++ = tolower ((unsigned char)*filename++);
}
/* Look for more dots. */
while (*filename != '\0' && *filename != '.')
while (! STOP_SET (*filename, MAP_DOT|MAP_NUL))
++filename;
if (*filename == '.')
return filename;
@@ -144,11 +146,11 @@ static int
vms_hash (const char *name)
{
int h = 0;
int g;
while (*name)
{
unsigned char uc = *name;
int g;
#ifdef HAVE_CASE_INSENSITIVE_FS
h = (h << 4) + (isupper (uc) ? tolower (uc) : uc);
#else
@@ -413,19 +415,10 @@ static struct directory *find_directory (const char *name);
static struct directory *
find_directory (const char *name)
{
const char *p;
struct directory *dir;
struct directory **dir_slot;
struct directory dir_key;
int r;
#ifdef WINDOWS32
char* w32_path;
char fs_label[BUFSIZ];
char fs_type[BUFSIZ];
unsigned long fs_serno;
unsigned long fs_flags;
unsigned long fs_len;
#endif
#ifdef VMS
if ((*name == '.') && (*(name+1) == 0))
name = "[]";
@@ -439,11 +432,11 @@ find_directory (const char *name)
if (HASH_VACANT (dir))
{
struct stat st;
/* The directory was not found. Create a new entry for it. */
const char *p = name + strlen (name);
struct stat st;
int r;
p = name + strlen (name);
dir = xmalloc (sizeof (struct directory));
#if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS)
dir->name = strcache_add_len (downcase (name), p - name);
@@ -487,6 +480,9 @@ find_directory (const char *name)
{
/* Search the contents hash table; device and inode are the key. */
#ifdef WINDOWS32
char *w32_path;
#endif
struct directory_contents *dc;
struct directory_contents **dc_slot;
struct directory_contents dc_key;
@@ -510,7 +506,13 @@ find_directory (const char *name)
if (HASH_VACANT (dc))
{
/* Nope; this really is a directory we haven't seen before. */
#ifdef WINDOWS32
char fs_label[BUFSIZ];
char fs_type[BUFSIZ];
unsigned long fs_serno;
unsigned long fs_flags;
unsigned long fs_len;
#endif
dc = (struct directory_contents *)
xmalloc (sizeof (struct directory_contents));
@@ -521,11 +523,8 @@ find_directory (const char *name)
dc->ctime = st.st_ctime;
dc->mtime = st.st_mtime;
/*
* NTFS is the only WINDOWS32 filesystem that bumps mtime
* on a directory when files are added/deleted from
* a directory.
*/
/* NTFS is the only WINDOWS32 filesystem that bumps mtime on a
directory when files are added/deleted from a directory. */
w32_path[3] = '\0';
if (GetVolumeInformation (w32_path, fs_label, sizeof (fs_label),
&fs_serno, &fs_len, &fs_flags, fs_type,
@@ -893,7 +892,6 @@ int
file_impossible_p (const char *filename)
{
const char *dirend;
const char *p = filename;
struct directory_contents *dir;
struct dirfile *dirfile;
struct dirfile dirfile_key;
@@ -938,12 +936,12 @@ file_impossible_p (const char *filename)
dirend++;
#endif
cp = alloca (dirend - filename + 1);
memcpy (cp, p, dirend - p);
cp[dirend - p] = '\0';
memcpy (cp, filename, dirend - filename);
cp[dirend - filename] = '\0';
dirname = cp;
}
dir = find_directory (dirname)->contents;
p = filename = slash + 1;
filename = slash + 1;
}
if (dir == 0 || dir->dirfiles.ht_vec == 0)
@@ -951,13 +949,13 @@ file_impossible_p (const char *filename)
return 0;
#ifdef __MSDOS__
filename = dosify (p);
filename = dosify (filename);
#endif
#ifdef HAVE_CASE_INSENSITIVE_FS
filename = downcase (p);
filename = downcase (filename);
#endif
#ifdef VMS
filename = vmsify (p, 1);
filename = vmsify (filename, 1);
#endif
dirfile_key.name = filename;

View File

@@ -4130,6 +4130,11 @@ Additionally, if there are multiple recursive @code{make} invocations
running in parallel, they will communicate so that only one of them is
generating output at a time.
If working directory printing is enabled (@pxref{-w Option, ,The
@samp{--print-directory} Option}), the enter/leave messages are
printed around each output grouping. If you prefer not to see these
messages add the @samp{--no-print-directory} option to @code{MAKEFLAGS}.
There are four levels of granularity when synchronizing output,
specified by giving an argument to the option (e.g., @samp{-Oline} or
@samp{--output-sync=recurse}).
@@ -4196,12 +4201,12 @@ completed.
Some programs invoked by @code{make} may behave differently if they
determine they're writing output to a terminal versus a file (often
described as ``interactive'' vs. ``non-interactive'' modes). For
example, many programs that can display colorized output often will
not do so if they determine they are not displaying on a terminal. If
your makefile invokes a program like this then using the output
example, many programs that can display colorized output will not do
so if they determine they are not writing to a terminal. If your
makefile invokes a program like this then using the output
synchronization options will cause the program to believe it's running
in ``non-interactive'' mode even when it's ultimately writing to the
terminal.
in ``non-interactive'' mode even though the output will ultimately go
to the terminal.
@node Parallel Input, , Parallel Output, Parallel
@subsection Input During Parallel Execution
@@ -4803,10 +4808,17 @@ to GNU @code{make}, and hence do not want to add GNU
@code{make}-specific flags to the @code{MAKEFLAGS} variable, you can
add them to the @code{GNUMAKEFLAGS} variable instead. This variable
is parsed just before @code{MAKEFLAGS}, in the same way as
@code{MAKEFLAGS}. Note, however, that when @code{make} constructs
@code{MAKEFLAGS} to pass to a recursive @code{make} it will include
all flags. GNU @code{make} never sets the @code{GNUMAKEFLAGS}
variable itself.
@code{MAKEFLAGS}. When @code{make} constructs @code{MAKEFLAGS} to
pass to a recursive @code{make} it will include all flags, even those
taken from @code{GNUMAKEFLAGS}. As a result, after parsing
@code{GNUMAKEFLAGS} GNU @code{make} sets this variable to the empty
string to avoid duplicating flags during recursion.
It's best to use @code{GNUMAKEFLAGS} only with flags which won't
materially change the behavior of your makefiles. If your makefiles
require GNU make anyway then simply use @code{MAKEFLAGS}. Flags such
as @samp{--no-print-directory} or @samp{--output-sync} may be
appropriate for @code{GNUMAKEFLAGS}.
@node -w Option, , Options/Recursion, Recursion
@subsection The @samp{--print-directory} Option
@@ -8590,6 +8602,10 @@ By default, the above messages are not enabled while trying to remake
the makefiles. This option enables messages while rebuilding makefiles,
too. Note that the @samp{all} option does enable this option. This
option also enables @samp{basic} messages.
@item n (@i{none})
Disable all debugging currently enabled. If additional debugging
flags are encountered after this they will still take effect.
@end table
@item -e
@@ -8708,22 +8724,6 @@ prerequisites, and do not remake anything on account of changes in
are ignored. @xref{Avoiding Compilation, ,Avoiding Recompilation of
Some Files}.@refill
@item -p
@cindex @code{-p}
@itemx --print-data-base
@cindex @code{--print-data-base}
@cindex data base of @code{make} rules
@cindex predefined rules and variables, printing
Print the data base (rules and variable values) that results from
reading the makefiles; then execute as usual or as otherwise
specified. This also prints the version information given by the
@samp{-v} switch (see below). To print the data base without trying
to remake any files, use @w{@samp{make -qp}}. To print the data base
of predefined rules and variables, use @w{@samp{make -p -f /dev/null}}.
The data base output contains file name and line number information for
recipe and variable definitions, so it can be a useful debugging tool
in complex environments.
@item -O[@var{type}]
@cindex @code{-O}
@itemx --output-sync[=@var{type}]
@@ -8743,6 +8743,22 @@ from each line in the recipe is grouped together. With the type
together. With the type @samp{none}, no output synchronization is
performed. @xref{Parallel Output, ,Output During Parallel Execution}.
@item -p
@cindex @code{-p}
@itemx --print-data-base
@cindex @code{--print-data-base}
@cindex data base of @code{make} rules
@cindex predefined rules and variables, printing
Print the data base (rules and variable values) that results from
reading the makefiles; then execute as usual or as otherwise
specified. This also prints the version information given by the
@samp{-v} switch (see below). To print the data base without trying
to remake any files, use @w{@samp{make -qp}}. To print the data base
of predefined rules and variables, use @w{@samp{make -p -f /dev/null}}.
The data base output contains file name and line number information for
recipe and variable definitions, so it can be a useful debugging tool
in complex environments.
@item -q
@cindex @code{-q}
@itemx --question
@@ -8814,17 +8830,13 @@ instead of running their recipes. This is used to pretend that the
recipes were done, in order to fool future invocations of
@code{make}. @xref{Instead of Execution, ,Instead of Executing Recipes}.
@item --trace[=@var{mode}]
@item --trace
@cindex @code{--trace}
Show tracing information for @code{make} execution. With no mode or
the type @samp{rule}, print the entire recipe to be executed, even for
recipes that are normally silent (due to @code{.SILENT} or @samp{@@}).
Also print the makefile name and line number where the recipe was
defined, and information on why the target is being rebuilt. With the
type @samp{dir}, directory enter/leave lines are shown around each
synchronized output segment. These modes are cumulative and can be
set with multiple instances of the @code{--trace} flag. With the type
@samp{none}, all tracing is disabled.
Show tracing information for @code{make} execution. Prints the entire
recipe to be executed, even for recipes that are normally silent (due
to @code{.SILENT} or @samp{@@}). Also prints the makefile name and
line number where the recipe was defined, and information on why the
target is being rebuilt.
@item -v
@cindex @code{-v}
@@ -10905,7 +10917,8 @@ The @code{load} directive and extension capability is considered a
``technology preview'' in this release of GNU make. We encourage you
to experiment with this feature and we appreciate any feedback on it.
However we cannot guarantee to maintain backward-compatibility in the
next release.
next release. Consider using GNU Guile instead for extending GNU make
(@pxref{Guile Function, ,The @code{guile} Function}).
@end quotation
@end cartouche
@@ -10973,7 +10986,9 @@ same directive.
The initializing function will be provided the file name and line
number of the invocation of the @code{load} operation. It should
return a value of type @code{int}, which must be @code{0} on failure
and non-@code{0} on success.
and non-@code{0} on success. If the return value is @code{-1}, then
GNU make will @emph{not} attempt to rebuild the object file
(@pxref{Remaking Loaded Objects, ,How Loaded Objects Are Remade}).
For example:
@@ -11100,16 +11115,14 @@ arguments are as follows:
@table @code
@item name
The function name. This is what the makefile should use to invoke the
function. The name must be between 1 and 255 characters long.
function. The name must be between 1 and 255 characters long and it
may only contain alphanumeric, period (@samp{.}), dash (@samp{-}), and
underscore (@samp{_}) characters. It may not begin with a period.
@item func_ptr
A pointer to a function that @code{make} will invoke when it expands
the function in a makefile. This function must be defined by the
loaded object. GNU @code{make} will call it with three arguments:
@code{name} (the same name as above), @code{argc} (the number of
arguments to the function), and @code{argv} (the list of arguments to
the function). The last argument (that is, @code{argv[argc]} will be
null (@code{0}).
loaded object.
@item min_args
The minimum number of arguments the function will accept. Must be
@@ -11125,12 +11138,30 @@ arguments. If the value is 0, then any number of arguments is
accepted. If the value is greater than 0, then it must be greater
than or equal to @code{min_args}.
@item expand_args
If this value is 0, then @code{make} will not expand the arguments to
the function before passing them to @code{func_ptr}. If the value is
non-0, then the arguments will be expanded first.
@item flags
Flags that specify how this function will operate; the desired flags
should be OR'd together. If the @code{GMK_FUNC_NOEXPAND} flag is
given then the function arguments will not be expanded before the
function is called; otherwise they will be expanded first.
@end table
@subsubheading Registered Function Interface
@findex gmk_func_ptr
A function registered with @code{make} must match the
@code{gmk_func_ptr} type. It will be invoked with three parameters:
@code{name} (the name of the function), @code{argc} (the number of
arguments to the function), and @code{argv} (an array of pointers to
arguments to the function). The last pointer (that is,
@code{argv[argc]}) will be null (@code{0}).
The return value of the function is the result of expanding the
function. If the function expands to nothing the return value may be
null. Otherwise, it must be a pointer to a string created with
@code{gmk_alloc}. Once the function returns, @code{make} owns this
string and will free it when appropriate; it cannot be accessed by the
loaded object.
@subsubheading GNU @code{make} Facilities
There are some facilities exported by GNU @code{make} for use by
@@ -11169,6 +11200,12 @@ should never pass memory that you've allocated directly to any
memory returned to you by any @code{make} function. Instead, use the
@code{gmk_alloc} and @code{gmk_free} functions.
In particular, the string returned to @code{make} by a function
registered using @code{gmk_add_function} @emph{must} be allocated
using @code{gmk_alloc}, and the string returned from the @code{make}
@code{gmk_expand} function @emph{must} be freed (when no longer
needed) using @code{gmk_free}.
@table @code
@item gmk_alloc
@findex gmk_alloc
@@ -11387,6 +11424,11 @@ The concept of doing several things at once (parallelism) exists in
many incarnations of @code{make} and similar programs, though not in the
System V or BSD implementations. @xref{Execution, ,Recipe Execution}.
@item
A number of different build tools that support parallelism also
support collecting output and displaying as a single block.
@xref{Parallel Output, ,Output During Parallel Execution}.
@item
Modified variable references using pattern substitution come from
SunOS 4. @xref{Reference, ,Basics of Variable References}.
@@ -11532,11 +11574,6 @@ functionality in that it will check out SCCS files for makefiles.
Various new built-in implicit rules.
@xref{Catalogue of Rules, ,Catalogue of Implicit Rules}.
@item
The built-in variable @samp{MAKE_VERSION} gives the version number of
@code{make}.
@vindex MAKE_VERSION
@item
Load dynamic objects which can modify the behavior of @code{make}.
@xref{Loading Objects, ,Loading Dynamic Objects}.
@@ -11883,6 +11920,11 @@ Evaluate @var{text} then read the results as makefile commands.
Expands to the empty string.@*
@xref{Eval Function, ,The @code{eval} Function}.
@item $(file @var{op} @var{filename},@var{text})
Expand the arguments, then open the file @var{filename} using mode
@var{op} and write @var{text} to that file.@*
@xref{File Function, ,The @code{file} Function}.
@item $(value @var{var})
Evaluates to the contents of the variable @var{var}, with no expansion
performed on it.@*
@@ -11982,6 +12024,18 @@ The name with which @code{make} was invoked. Using this variable in
recipes has special meaning. @xref{MAKE Variable, ,How the
@code{MAKE} Variable Works}.
@item MAKE_VERSION
The built-in variable @samp{MAKE_VERSION} expands to the version
number of the GNU @code{make} program.
@vindex MAKE_VERSION
@item MAKE_HOST
The built-in variable @samp{MAKE_HOST} expands to a string
representing the host that GNU @code{make} was built to run on.
@vindex MAKE_HOST
@item MAKELEVEL
The number of levels of recursion (sub-@code{make}s).@*
@@ -12007,6 +12061,7 @@ you'd like to set GNU @code{make}-specific flags in a POSIX-compliant
makefile. This variable will be seen by GNU @code{make} and ignored
by other @code{make} implementations. It's not needed if you only use
GNU @code{make}; just use @code{MAKEFLAGS} directly.
@xref{Options/Recursion, ,Communicating Options to a Sub-@code{make}}.
@item MAKECMDGOALS
@@ -12151,12 +12206,15 @@ of its arguments. @xref{Functions, ,Functions for Transforming Text}.
@itemx multiple target patterns. Stop.
@itemx target pattern contains no `%'. Stop.
@itemx mixed implicit and static pattern rules. Stop.
These are generated for malformed static pattern rules. The first means
there's no pattern in the target section of the rule; the second means
there are multiple patterns in the target section; the third means
the target doesn't contain a pattern character (@code{%}); and the
fourth means that all three parts of the static pattern rule contain
pattern characters (@code{%})--only the first two parts should.
These are generated for malformed static pattern rules. The first
means there's no pattern in the target section of the rule; the second
means there are multiple patterns in the target section; the third
means the target doesn't contain a pattern character (@code{%}); and
the fourth means that all three parts of the static pattern rule
contain pattern characters (@code{%})--only the first two parts
should. If you see these errors and you aren't trying to create a
static pattern rule, check the value of any variables in your target
and prerequisite lists to be sure they do not contain colons.
@xref{Static Usage, ,Syntax of Static Pattern Rules}.
@item warning: -jN forced in submake: disabling jobserver mode.

View File

@@ -20,6 +20,7 @@ echo Building Make for MSDOS
rem Echo ON so they will see what is going on.
@echo on
gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g commands.c -o commands.o
gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g output.c -o output.o
gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g job.c -o job.o
gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g dir.c -o dir.o
gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g file.c -o file.o
@@ -51,7 +52,7 @@ ar rv libglob.a glob.o fnmatch.o
@echo off
cd ..
echo commands.o > respf.$$$
for %%f in (job dir file misc main read remake rule implicit default variable) do echo %%f.o >> respf.$$$
for %%f in (job output dir file misc main read remake rule implicit default variable) do echo %%f.o >> respf.$$$
for %%f in (expand function vpath hash strcache version ar arscan signame remote-stub getopt getopt1) do echo %%f.o >> respf.$$$
echo glob/libglob.a >> respf.$$$
rem gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g guile.c -o guile.o

View File

@@ -304,10 +304,8 @@ variable_expand_string (char *line, const char *string, long length)
if (colon)
{
/* This looks like a substitution reference: $(FOO:A=B). */
const char *subst_beg, *subst_end, *replace_beg, *replace_end;
subst_beg = colon + 1;
subst_end = lindex (subst_beg, end, '=');
const char *subst_beg = colon + 1;
const char *subst_end = lindex (subst_beg, end, '=');
if (subst_end == 0)
/* There is no = in sight. Punt on the substitution
reference and treat this as a variable name containing
@@ -315,8 +313,8 @@ variable_expand_string (char *line, const char *string, long length)
colon = 0;
else
{
replace_beg = subst_end + 1;
replace_end = end;
const char *replace_beg = subst_end + 1;
const char *replace_end = end;
/* Extract the variable name before the colon
and look up that variable. */

28
file.c
View File

@@ -18,8 +18,8 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include <assert.h>
#include "dep.h"
#include "filedef.h"
#include "dep.h"
#include "job.h"
#include "commands.h"
#include "variable.h"
@@ -153,7 +153,7 @@ enter_file (const char *name)
struct file file_key;
assert (*name != '\0');
assert (strcache_iscached (name));
assert (! verify_flag || strcache_iscached (name));
#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS)
if (*name != '.')
@@ -184,7 +184,7 @@ enter_file (const char *name)
new = xcalloc (sizeof (struct file));
new->name = new->hname = name;
new->update_status = -1;
new->update_status = us_none;
if (HASH_VACANT (f))
{
@@ -378,7 +378,7 @@ remove_intermediates (int sig)
&& !f->secondary && !f->cmd_target)
{
int status;
if (f->update_status == -1)
if (f->update_status == us_none)
/* If nothing would have created this file yet,
don't print an "rm" command for it. */
continue;
@@ -430,7 +430,8 @@ remove_intermediates (int sig)
struct dep *
split_prereqs (char *p)
{
struct dep *new = PARSE_FILE_SEQ (&p, struct dep, '|', NULL, 0);
struct dep *new = PARSE_FILE_SEQ (&p, struct dep, MAP_PIPE, NULL,
PARSEFS_NONE);
if (*p)
{
@@ -439,7 +440,7 @@ split_prereqs (char *p)
struct dep *ood;
++p;
ood = PARSE_FILE_SEQ (&p, struct dep, '\0', NULL, 0);
ood = PARSE_SIMPLE_SEQ (&p, struct dep);
if (! new)
new = ood;
@@ -1000,23 +1001,18 @@ print_file (const void *item)
case cs_finished:
switch (f->update_status)
{
case -1:
case us_none:
break;
case 0:
case us_success:
puts (_("# Successfully updated."));
break;
case 1:
case us_question:
assert (question_flag);
puts (_("# Needs to be updated (-q is set)."));
break;
case 2:
case us_failed:
puts (_("# Failed to be updated."));
break;
default:
puts (_("# Invalid value in 'update_status' member!"));
fflush (stdout);
fflush (stderr);
abort ();
}
break;
default:
@@ -1052,7 +1048,7 @@ print_file_data_base (void)
#define VERIFY_CACHED(_p,_n) \
do{\
if (_p->_n && _p->_n[0] && !strcache_iscached (_p->_n)) \
error (NULL, "%s: Field '%s' not cached: %s\n", _p->name, # _n, _p->_n); \
error (NULL, _("%s: Field '%s' not cached: %s"), _p->name, # _n, _p->_n); \
}while(0)
static void

View File

@@ -59,11 +59,16 @@ struct file
FILE_TIMESTAMP mtime_before_update; /* File's modtime before any updating
has been performed. */
int command_flags; /* Flags OR'd in for cmds; see commands.h. */
char update_status; /* Status of the last attempt to update,
or -1 if none has been made. */
enum update_status /* Status of the last attempt to update. */
{
us_success = 0, /* Successfully updated. Must be 0! */
us_none, /* No attempt to update has been made. */
us_question, /* Needs to be updated (-q is is set). */
us_failed /* Update failed. */
} update_status ENUM_BITFIELD (2);
enum cmd_state /* State of the commands. */
{ /* Note: It is important that cs_not_started be zero. */
cs_not_started, /* Not yet started. */
{
cs_not_started = 0, /* Not yet started. Must be 0! */
cs_deps_running, /* Dep commands running. */
cs_running, /* Commands running. */
cs_finished /* Commands finished. */

View File

@@ -31,7 +31,7 @@ struct function_table_entry
{
union {
char *(*func_ptr) (char *output, char **argv, const char *fname);
char *(*alloc_func_ptr) (const char *fname, int argc, char **argv);
gmk_func_ptr alloc_func_ptr;
} fptr;
const char *name;
unsigned char len;
@@ -116,7 +116,7 @@ subst_expand (char *o, const char *text, const char *subst, const char *replace,
or only at the ends of words, check that this case qualifies. */
if (by_word
&& ((p > text && !isblank ((unsigned char)p[-1]))
|| (p[slen] != '\0' && !isblank ((unsigned char)p[slen]))))
|| ! STOP_SET (p[slen], MAP_BLANK|MAP_NUL)))
/* Struck out. Output the rest of the string that is
no longer to be replaced. */
o = variable_buffer_output (o, subst, slen);
@@ -269,19 +269,19 @@ patsubst_expand (char *o, const char *text, char *pattern, char *replace)
static const struct function_table_entry *
lookup_function (const char *s)
{
struct function_table_entry function_table_entry_key;
const char *e = s;
while (*e && ( (*e >= 'a' && *e <= 'z') || *e == '-'))
while (STOP_SET (*e, MAP_USERFUNC))
e++;
if (*e == '\0' || isblank ((unsigned char) *e))
{
struct function_table_entry function_table_entry_key;
function_table_entry_key.name = s;
function_table_entry_key.len = e - s;
return hash_find_item (&function_table, &function_table_entry_key);
}
return 0;
if (e == s || !STOP_SET(*e, MAP_NUL|MAP_SPACE))
return NULL;
function_table_entry_key.name = s;
function_table_entry_key.len = e - s;
return hash_find_item (&function_table, &function_table_entry_key);
}
@@ -357,7 +357,7 @@ string_glob (char *line)
struct nameseq *chain;
unsigned int idx;
chain = PARSE_FILE_SEQ (&line, struct nameseq, '\0', NULL,
chain = PARSE_FILE_SEQ (&line, struct nameseq, MAP_NUL, NULL,
/* We do not want parse_file_seq to strip './'s.
That would break examples like:
$(patsubst ./%.c,obj/%.o,$(wildcard ./?*.c)). */
@@ -507,16 +507,6 @@ func_flavor (char *o, char **argv, const char *funcname UNUSED)
return o;
}
#ifdef VMS
# define IS_PATHSEP(c) ((c) == ']')
#else
# ifdef HAVE_DOS_PATHS
# define IS_PATHSEP(c) ((c) == '/' || (c) == '\\')
# else
# define IS_PATHSEP(c) ((c) == '/')
# endif
#endif
static char *
func_notdir_suffix (char *o, char **argv, const char *funcname)
@@ -529,17 +519,13 @@ func_notdir_suffix (char *o, char **argv, const char *funcname)
int is_suffix = funcname[0] == 's';
int is_notdir = !is_suffix;
int stop = MAP_PATHSEP | (is_suffix ? MAP_DOT : 0);
while ((p2 = find_next_token (&list_iterator, &len)) != 0)
{
const char *p = p2 + len;
const char *p = p2 + len - 1;
while (p >= p2 && (!is_suffix || *p != '.'))
{
if (IS_PATHSEP (*p))
break;
--p;
}
while (p >= p2 && ! STOP_SET (*p, stop))
--p;
if (p >= p2)
{
@@ -586,16 +572,12 @@ func_basename_dir (char *o, char **argv, const char *funcname)
int is_basename = funcname[0] == 'b';
int is_dir = !is_basename;
int stop = MAP_PATHSEP | (is_basename ? MAP_DOT : 0) | MAP_NUL;
while ((p2 = find_next_token (&p3, &len)) != 0)
{
const char *p = p2 + len;
while (p >= p2 && (!is_basename || *p != '.'))
{
if (IS_PATHSEP (*p))
break;
--p;
}
const char *p = p2 + len - 1;
while (p >= p2 && ! STOP_SET (*p, stop))
--p;
if (p >= p2 && (is_dir))
o = variable_buffer_output (o, p2, ++p - p2);
@@ -1107,8 +1089,8 @@ func_error (char *o, char **argv, const char *funcname)
break;
case 'i':
printf ("%s\n", msg);
fflush (stdout);
outputs (0, msg);
outputs (0, "\n");
break;
default:
@@ -1131,7 +1113,6 @@ func_sort (char *o, char **argv, const char *funcname UNUSED)
int wordi;
char *p;
unsigned int len;
int i;
/* Find the maximum number of words we'll have. */
t = argv[0];
@@ -1156,6 +1137,8 @@ func_sort (char *o, char **argv, const char *funcname UNUSED)
if (wordi)
{
int i;
/* Now sort the list of words. */
qsort (words, wordi, sizeof (char *), alpha_compare);
@@ -1299,12 +1282,12 @@ static char *
func_and (char *o, char **argv, const char *funcname UNUSED)
{
char *expansion;
int result;
while (1)
{
const char *begp = *argv;
const char *endp = begp + strlen (*argv) - 1;
int result;
/* An empty condition is always false. */
strip_whitespace (&begp, &endp);
@@ -1626,6 +1609,7 @@ func_shell_base (char *o, char **argv, int trim_newlines)
{
fprintf (stderr, "This platform does not support shell\n");
die (EXIT_FAILURE);
return NULL;
}
#define func_shell 0
@@ -1636,7 +1620,7 @@ char *
func_shell_base (char *o, char **argv, int trim_newlines)
{
char *batch_filename = NULL;
int errfd;
#ifdef __MSDOS__
FILE *fpipe;
#endif
@@ -1652,9 +1636,9 @@ func_shell_base (char *o, char **argv, int trim_newlines)
are used to run the commands, because we normally refrain from
creating batch files under -n. */
int j_p_f = just_print_flag;
just_print_flag = 0;
#endif
/* Construct the argument list. */
command_argv = construct_command_argv (argv[0], NULL, NULL, 0,
&batch_filename);
@@ -1668,15 +1652,15 @@ func_shell_base (char *o, char **argv, int trim_newlines)
#endif
/* Using a target environment for 'shell' loses in cases like:
export var = $(shell echo foobie)
because target_environment hits a loop trying to expand $(var)
to put it in the environment. This is even more confusing when
var was not explicitly exported, but just appeared in the
calling environment.
export var = $(shell echo foobie)
bad := $(var)
because target_environment hits a loop trying to expand $(var) to put it
in the environment. This is even more confusing when 'var' was not
explicitly exported, but just appeared in the calling environment.
See Savannah bug #10593.
envp = target_environment (NILF);
envp = target_environment (NULL);
*/
envp = environ;
@@ -1691,6 +1675,12 @@ func_shell_base (char *o, char **argv, int trim_newlines)
else
error_prefix = "";
/* Set up the output in case the shell writes something. */
output_start ();
errfd = (output_context && output_context->err >= 0
? output_context->err : FD_STDERR);
#if defined(__MSDOS__)
fpipe = msdos_openpipe (pipedes, &pid, argv[0]);
if (pipedes[0] < 0)
@@ -1723,7 +1713,7 @@ func_shell_base (char *o, char **argv, int trim_newlines)
CLOSE_ON_EXEC(pipedes[1]);
CLOSE_ON_EXEC(pipedes[0]);
/* Never use fork()/exec() here! Use spawn() instead in exec_command() */
pid = child_execute_job (0, pipedes[1], command_argv, envp);
pid = child_execute_job (FD_STDIN, pipedes[1], errfd, command_argv, envp);
if (pid < 0)
perror_with_name (error_prefix, "spawn");
# else /* ! __EMX__ */
@@ -1731,7 +1721,14 @@ func_shell_base (char *o, char **argv, int trim_newlines)
if (pid < 0)
perror_with_name (error_prefix, "fork");
else if (pid == 0)
child_execute_job (0, pipedes[1], command_argv, envp);
{
# ifdef SET_STACK_SIZE
/* Reset limits, if necessary. */
if (stack_limit.rlim_cur)
setrlimit (RLIMIT_STACK, &stack_limit);
# endif
child_execute_job (FD_STDIN, pipedes[1], errfd, command_argv, envp);
}
else
# endif
#endif
@@ -1859,7 +1856,7 @@ func_shell_base (char *o, char **argv, int trim_newlines)
return o;
/* Note the mktemp() is a security hole, but this only runs on Amiga.
Ideally we would use main.c:open_tmpfile(), but this uses a special
Ideally we would use output_tmpfile(), but this uses a special
Open(), not fopen(), and I'm not familiar enough with the code to mess
with it. */
strcpy (tmp_output, "t:MakeshXXXXXXXX");
@@ -1952,8 +1949,12 @@ func_not (char *o, char **argv, char *funcname UNUSED)
#ifdef HAVE_DOS_PATHS
#define IS_ABSOLUTE(n) (n[0] && n[1] == ':')
#define ROOT_LEN 3
# ifdef __CYGWIN__
# define IS_ABSOLUTE(n) ((n[0] && n[1] == ':') || STOP_SET (n[0], MAP_PATHSEP))
# else
# define IS_ABSOLUTE(n) (n[0] && n[1] == ':')
# endif
# define ROOT_LEN 3
#else
#define IS_ABSOLUTE(n) (n[0] == '/')
#define ROOT_LEN 1
@@ -1983,9 +1984,9 @@ abspath (const char *name, char *apath)
strcpy (apath, starting_directory);
#ifdef HAVE_DOS_PATHS
if (IS_PATHSEP(name[0]))
if (STOP_SET (name[0], MAP_PATHSEP))
{
if (IS_PATHSEP(name[1]))
if (STOP_SET (name[1], MAP_PATHSEP))
{
/* A UNC. Don't prepend a drive letter. */
apath[0] = name[0];
@@ -2004,13 +2005,17 @@ abspath (const char *name, char *apath)
}
else
{
#if defined(__CYGWIN__) && defined(HAVE_DOS_PATHS)
if (STOP_SET (name[0], MAP_PATHSEP))
root_len = 1;
#endif
strncpy (apath, name, root_len);
apath[root_len] = '\0';
dest = apath + root_len;
/* Get past the root, since we already copied it. */
name += root_len;
#ifdef HAVE_DOS_PATHS
if (!IS_PATHSEP(apath[2]))
if (! STOP_SET (apath[root_len - 1], MAP_PATHSEP))
{
/* Convert d:foo into d:./foo and increase root_len. */
apath[2] = '.';
@@ -2021,7 +2026,7 @@ abspath (const char *name, char *apath)
name--;
}
else
apath[2] = '/'; /* make sure it's a forward slash */
apath[root_len - 1] = '/'; /* make sure it's a forward slash */
#endif
}
@@ -2030,11 +2035,11 @@ abspath (const char *name, char *apath)
unsigned long len;
/* Skip sequence of multiple path-separators. */
while (IS_PATHSEP(*start))
while (STOP_SET (*start, MAP_PATHSEP))
++start;
/* Find end of path component. */
for (end = start; *end != '\0' && !IS_PATHSEP(*end); ++end)
for (end = start; ! STOP_SET (*end, MAP_PATHSEP|MAP_NUL); ++end)
;
len = end - start;
@@ -2047,11 +2052,12 @@ abspath (const char *name, char *apath)
{
/* Back up to previous component, ignore if at root already. */
if (dest > apath + root_len)
for (--dest; !IS_PATHSEP(dest[-1]); --dest);
for (--dest; ! STOP_SET (dest[-1], MAP_PATHSEP); --dest)
;
}
else
{
if (!IS_PATHSEP(dest[-1]))
if (! STOP_SET (dest[-1], MAP_PATHSEP))
*dest++ = '/';
if (dest + len >= apath_limit)
@@ -2064,7 +2070,7 @@ abspath (const char *name, char *apath)
}
/* Unless it is root strip trailing separator. */
if (dest > apath + root_len && IS_PATHSEP(dest[-1]))
if (dest > apath + root_len && STOP_SET (dest[-1], MAP_PATHSEP))
--dest;
*dest = '\0';
@@ -2439,7 +2445,7 @@ func_call (char *o, char **argv, const char *funcname UNUSED)
/* There is no way to define a variable with a space in the name, so strip
leading and trailing whitespace as a favor to the user. */
fname = argv[0];
while (*fname != '\0' && isspace ((unsigned char)*fname))
while (isspace ((unsigned char)*fname))
++fname;
cp = fname + strlen (fname) - 1;
@@ -2524,19 +2530,28 @@ func_call (char *o, char **argv, const char *funcname UNUSED)
}
void
define_new_function (const gmk_floc *flocp,
const char *name, int min, int max, int expand,
char *(*func)(const char *, int, char **))
define_new_function (const gmk_floc *flocp, const char *name,
unsigned int min, unsigned int max, unsigned int flags,
gmk_func_ptr func)
{
const char *e = name;
struct function_table_entry *ent;
size_t len = strlen (name);
size_t len;
while (STOP_SET (*e, MAP_USERFUNC))
e++;
len = e - name;
if (len == 0)
fatal (flocp, _("Empty function name\n"));
if (*name == '.' || *e != '\0')
fatal (flocp, _("Invalid function name: %s\n"), name);
if (len > 255)
fatal (flocp, _("Function name too long: %s\n"), name);
if (min < 0 || min > 255)
if (min > 255)
fatal (flocp, _("Invalid minimum argument count (%d) for function %s\n"),
min, name);
if (max < 0 || max > 255 || (max && max < min))
if (max > 255 || (max && max < min))
fatal (flocp, _("Invalid maximum argument count (%d) for function %s\n"),
max, name);
@@ -2545,7 +2560,7 @@ define_new_function (const gmk_floc *flocp,
ent->len = len;
ent->minimum_args = min;
ent->maximum_args = max;
ent->expand_args = expand ? 1 : 0;
ent->expand_args = ANY_SET(flags, GMK_FUNC_NOEXPAND) ? 0 : 1;
ent->alloc_fn = 1;
ent->fptr.alloc_func_ptr = func;

View File

@@ -26,6 +26,7 @@ typedef struct
unsigned long lineno;
} gmk_floc;
typedef char *(*gmk_func_ptr)(const char *nm, unsigned int argc, char **argv);
#ifdef _WIN32
# ifdef GMK_BUILDING_MAKE
@@ -38,17 +39,17 @@ typedef struct
#endif
/* Free memory returned by the gmk_expand() function. */
void GMK_EXPORT gmk_free (char *str);
GMK_EXPORT void gmk_free (char *str);
/* Allocate memory in GNU make's context. */
char * GMK_EXPORT gmk_alloc (unsigned int len);
GMK_EXPORT char *gmk_alloc (unsigned int len);
/* Run $(eval ...) on the provided string BUFFER. */
void GMK_EXPORT gmk_eval (const char *buffer, const gmk_floc *floc);
GMK_EXPORT void gmk_eval (const char *buffer, const gmk_floc *floc);
/* Run GNU make expansion on the provided string STR.
Returns an allocated buffer that the caller must free with gmk_free(). */
char * GMK_EXPORT gmk_expand (const char *str);
GMK_EXPORT char *gmk_expand (const char *str);
/* Register a new GNU make function NAME (maximum of 255 chars long).
When the function is expanded in the makefile, FUNC will be invoked with
@@ -60,14 +61,19 @@ char * GMK_EXPORT gmk_expand (const char *str);
MIN_ARGS is the minimum number of arguments the function requires.
MAX_ARGS is the maximum number of arguments (or 0 if there's no maximum).
MIN_ARGS and MAX_ARGS must be >= 0 and <= 255.
MIN_ARGS and MAX_ARGS may not exceed 255.
If EXPAND_ARGS is 0, the arguments to the function will not be expanded
before FUNC is called. If EXPAND_ARGS is non-0, they will be expanded.
The FLAGS value may be GMK_FUNC_DEFAULT, or one or more of the following
flags OR'd together:
GMK_FUNC_NOEXPAND: the arguments to the function will be not be expanded
before FUNC is called.
*/
void GMK_EXPORT gmk_add_function (const char *name,
char *(*func)(const char *nm,
int argc, char **argv),
int min_args, int max_args, int expand_args);
GMK_EXPORT void gmk_add_function (const char *name, gmk_func_ptr func,
unsigned int min_args, unsigned int max_args,
unsigned int flags);
#define GMK_FUNC_DEFAULT 0x00
#define GMK_FUNC_NOEXPAND 0x01
#endif /* _GNUMAKE_H_ */

35
guile.c
View File

@@ -14,15 +14,26 @@ 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 "gnumake.h"
#include "makeint.h"
#include "debug.h"
#include "filedef.h"
#include "dep.h"
#include "variable.h"
#include <libguile.h>
/* Pre-2.0 versions of Guile don't have a typedef for gsubr function types. */
#if SCM_MAJOR_VERSION < 2
# define GSUBR_TYPE SCM (*) ()
/* Guile 1.x doesn't really support i18n. */
# define EVAL_STRING(_s) scm_c_eval_string (_s)
#else
# define GSUBR_TYPE scm_t_subr
# define EVAL_STRING(_s) scm_eval_string (scm_from_utf8_string (_s))
#endif
static SCM make_mod = SCM_EOL;
static SCM obj_to_str = SCM_EOL;
@@ -71,10 +82,10 @@ guile_define_module (void *data UNUSED)
#include "gmk-default.h"
/* Register a subr for GNU make's eval capability. */
scm_c_define_gsubr ("gmk-expand", 1, 0, 0, guile_expand_wrapper);
scm_c_define_gsubr ("gmk-expand", 1, 0, 0, (GSUBR_TYPE) guile_expand_wrapper);
/* Register a subr for GNU make's eval capability. */
scm_c_define_gsubr ("gmk-eval", 1, 0, 0, guile_eval_wrapper);
scm_c_define_gsubr ("gmk-eval", 1, 0, 0, (GSUBR_TYPE) guile_eval_wrapper);
/* Define the rest of the module. */
scm_c_eval_string (GUILE_module_defn);
@@ -99,13 +110,22 @@ guile_init (void *arg UNUSED)
static void *
internal_guile_eval (void *arg)
{
return cvt_scm_to_str (scm_c_eval_string (arg));
return cvt_scm_to_str (EVAL_STRING (arg));
}
/* This is the function registered with make */
static char *
func_guile (const char *funcname UNUSED, int argc UNUSED, char **argv)
func_guile (const char *funcname UNUSED, unsigned int argc UNUSED, char **argv)
{
static int init = 0;
if (! init)
{
/* Initialize the Guile interpreter. */
scm_with_guile (guile_init, NULL);
init = 1;
}
if (argv[0] && argv[0][0] != '\0')
return scm_with_guile (internal_guile_eval, argv[0]);
@@ -119,11 +139,8 @@ func_guile (const char *funcname UNUSED, int argc UNUSED, char **argv)
int
guile_gmake_setup (const gmk_floc *flocp UNUSED)
{
/* Initialize the Guile interpreter. */
scm_with_guile (guile_init, NULL);
/* Create a make function "guile". */
gmk_add_function ("guile", func_guile, 0, 1, 1);
gmk_add_function ("guile", func_guile, 0, 1, GMK_FUNC_DEFAULT);
return 1;
}

View File

@@ -217,8 +217,8 @@ pattern_search (struct file *file, int archive,
struct file *int_file = 0;
/* List of dependencies found recursively. */
struct patdeps *deplist
= xmalloc (max_pattern_deps * sizeof (struct patdeps));
unsigned int max_deps = max_pattern_deps;
struct patdeps *deplist = xmalloc (max_deps * sizeof (struct patdeps));
struct patdeps *pat = deplist;
/* Names of possible dependencies are constructed in this buffer. */
@@ -249,8 +249,6 @@ pattern_search (struct file *file, int archive,
that is not just '%'. */
int specific_rule_matched = 0;
struct dep dep_simple;
unsigned int ri; /* uninit checks OK */
struct rule *rule;
@@ -532,11 +530,9 @@ pattern_search (struct file *file, int archive,
/* If we don't need a second expansion, just replace the %. */
if (! dep->need_2nd_expansion)
{
dep_simple = *dep;
dep_simple.next = 0;
p = strchr (nptr, '%');
if (p == 0)
dep_simple.name = nptr;
strcpy (depname, nptr);
else
{
char *o = depname;
@@ -550,13 +546,19 @@ pattern_search (struct file *file, int archive,
memcpy (o, stem_str, stemlen);
o += stemlen;
strcpy (o, p + 1);
dep_simple.name = strcache_add (depname);
}
dl = &dep_simple;
/* Parse the expanded string. It might have wildcards. */
p = depname;
dl = PARSE_SIMPLE_SEQ (&p, struct dep);
for (d = dl; d != NULL; d = d->next)
{
++deps_found;
d->ignore_mtime = dep->ignore_mtime;
}
/* We've used up this dep, so next time get a new one. */
nptr = 0;
++deps_found;
}
/* We have to perform second expansion on this prereq. In an
@@ -572,6 +574,7 @@ pattern_search (struct file *file, int archive,
{
int add_dir = 0;
unsigned int len;
struct dep **dptr;
nptr = get_next_word (nptr, &len);
if (nptr == 0)
@@ -614,6 +617,9 @@ pattern_search (struct file *file, int archive,
add_dir = 1;
}
/* Set up for the next word. */
nptr += len;
/* Initialize and set file variables if we haven't already
done so. */
if (!file_vars_initialized)
@@ -632,32 +638,47 @@ pattern_search (struct file *file, int archive,
/* Perform the 2nd expansion. */
p = variable_expand_for_file (depname, file);
dptr = &dl;
/* Parse the expanded string. */
dl = PARSE_FILE_SEQ (&p, struct dep, order_only ? '\0' : '|',
add_dir ? dir : NULL, 0);
for (d = dl; d != NULL; d = d->next)
/* Parse the results into a deps list. */
do
{
++deps_found;
if (order_only)
d->ignore_mtime = 1;
}
/* Parse the expanded string. */
struct dep *dp = PARSE_FILE_SEQ (&p, struct dep,
order_only ? MAP_NUL : MAP_PIPE,
add_dir ? dir : NULL, PARSEFS_NONE);
*dptr = dp;
/* Set up for the next word. */
nptr += len;
for (d = dp; d != NULL; d = d->next)
{
++deps_found;
if (order_only)
d->ignore_mtime = 1;
dptr = &d->next;
}
/* If we stopped due to an order-only token, note it. */
if (*p == '|')
{
order_only = 1;
++p;
}
}
while (*p != '\0');
}
/* If there are more than max_pattern_deps prerequisites (due to
2nd expansion), reset it and realloc the arrays. */
if (deps_found > max_pattern_deps)
if (deps_found > max_deps)
{
unsigned int l = pat - deplist;
/* This might have changed due to recursion. */
max_pattern_deps = MAX(max_pattern_deps, deps_found);
max_deps = max_pattern_deps;
deplist = xrealloc (deplist,
deps_found * sizeof (struct patdeps));
max_deps * sizeof (struct patdeps));
pat = deplist + l;
max_pattern_deps = deps_found;
}
/* Go through the nameseq and handle each as a prereq name. */
@@ -757,8 +778,8 @@ pattern_search (struct file *file, int archive,
pat->pattern = int_file->name;
int_file->name = d->name;
pat->file = int_file;
(pat++)->name = d->name;
int_file = 0;
(pat++)->name = d->name;
continue;
}
@@ -779,8 +800,7 @@ pattern_search (struct file *file, int archive,
}
/* Free the ns chain. */
if (dl != &dep_simple)
free_dep_chain (dl);
free_dep_chain (dl);
if (failed)
break;

589
job.c
View File

@@ -242,20 +242,8 @@ unsigned long job_counter = 0;
/* Number of jobserver tokens this instance is currently using. */
unsigned int jobserver_tokens = 0;
#ifdef OUTPUT_SYNC
/* Semaphore for use in -j mode with output_sync. */
static sync_handle_t sync_handle = -1;
/* Is make's stdout going to the same place as stderr? */
static int combined_output = 0;
#define STREAM_OK(_s) ((fcntl (fileno (_s), F_GETFD) != -1) || (errno != EBADF))
#define FD_NOT_EMPTY(_f) ((_f) >= 0 && lseek ((_f), 0, SEEK_END) > 0)
#endif /* OUTPUT_SYNC */
#ifdef WINDOWS32
/*
* The macro which references this function is defined in makeint.h.
@@ -427,8 +415,8 @@ _is_unixy_shell (const char *path)
int
is_bourne_compatible_shell (const char *path)
{
/* list of known unix (Bourne-like) shells */
const char *unix_shells[] = {
/* List of known POSIX (or POSIX-ish) shells. */
static const char *unix_shells[] = {
"sh",
"bash",
"ksh",
@@ -438,7 +426,7 @@ is_bourne_compatible_shell (const char *path)
"dash",
NULL
};
unsigned i, len;
const char **s;
/* find the rightmost '/' or '\\' */
const char *name = strrchr (path, '/');
@@ -451,18 +439,18 @@ is_bourne_compatible_shell (const char *path)
else if (!name) /* name and p must be 0 */
name = path;
if (*name == '/' || *name == '\\') name++;
if (*name == '/' || *name == '\\')
++name;
/* this should be able to deal with extensions on Windows-like systems */
for (i = 0; unix_shells[i] != NULL; i++)
for (s = unix_shells; *s != NULL; ++s)
{
len = strlen (unix_shells[i]);
#if defined(WINDOWS32) || defined(__MSDOS__)
if ((strncasecmp (name, unix_shells[i], len) == 0) &&
(strlen (name) >= len && (name[len] == '\0' || name[len] == '.')))
unsigned int len = strlen (*s);
if ((strlen (name) >= len && STOP_SET (name[len], MAP_DOT|MAP_NUL))
&& strncasecmp (name, *s, len) == 0)
#else
if ((strncmp (name, unix_shells[i], len) == 0) &&
(strlen (name) >= len && name[len] == '\0'))
if (strcmp (name, *s) == 0)
#endif
return 1; /* a known unix-style shell */
}
@@ -472,50 +460,12 @@ is_bourne_compatible_shell (const char *path)
}
/* Write a message in the child's context. Write it to the child's output
sync file if present, otherwise to the terminal. */
static void
child_out (const struct child *child, const char *msg, int out)
{
int fd = out ? child->outfd : child->errfd;
if (!msg || msg[0] == '\0')
return;
if (fd >= 0)
{
int len = strlen (msg);
int b;
lseek (fd, 0, SEEK_END);
while (1)
{
EINTRLOOP (b, write (fd, msg, len));
if (b == len)
break;
if (b <= 0)
return;
len -= b;
msg += b;
}
EINTRLOOP (b, write (fd, "\n", 1));
}
else
{
FILE *f = out ? stdout : stderr;
fputs (msg, f);
putc ('\n', f);
fflush (f);
}
}
/* Write an error message describing the exit status given in
EXIT_CODE, EXIT_SIG, and COREDUMP, for the target TARGET_NAME.
Append "(ignored)" if IGNORED is nonzero. */
static void
child_error (const struct child *child,
child_error (struct child *child,
int exit_code, int exit_sig, int coredump, int ignored)
{
const char *pre = "*** ";
@@ -523,9 +473,7 @@ child_error (const struct child *child,
const char *dump = "";
const struct file *f = child->file;
const gmk_floc *flocp = &f->cmds->fileinfo;
const char *msg;
const char *nm;
unsigned int l;
if (ignored && silent_flag)
return;
@@ -548,31 +496,29 @@ child_error (const struct child *child,
nm = a;
}
msg = message_s (strlen (nm) + strlen (f->name), 0,
_("%s: recipe for target '%s' failed"), nm, f->name);
child_out (child, msg, 1);
OUTPUT_SET (&child->output);
l = strlen (pre) + strlen (f->name) + strlen (post);
message (0, _("%s: recipe for target '%s' failed"), nm, f->name);
#ifdef VMS
if ((exit_code & 1) != 0)
return;
{
OUTPUT_UNSET ();
return;
}
msg = error_s (l + INTEGER_LENGTH, NILF,
_("%s[%s] Error 0x%x%s"), pre, f->name, exit_code, post);
error (NILF, _("%s[%s] Error 0x%x%s"), pre, f->name, exit_code, post);
#else
if (exit_sig == 0)
msg = error_s (l + INTEGER_LENGTH, NILF,
_("%s[%s] Error %d%s"), pre, f->name, exit_code, post);
error (NILF, _("%s[%s] Error %d%s"), pre, f->name, exit_code, post);
else
{
const char *s = strsignal (exit_sig);
msg = error_s (l + strlen (s) + strlen (dump), NILF,
_("%s[%s] %s%s%s"), pre, f->name, s, dump, post);
error (NILF, _("%s[%s] %s%s%s"), pre, f->name, s, dump, post);
}
#endif /* VMS */
child_out (child, msg, 0);
OUTPUT_UNSET ();
}
@@ -609,203 +555,6 @@ child_handler (int sig UNUSED)
*/
}
#ifdef OUTPUT_SYNC
/* Set up the sync handle and configure combined_output.
Disables output_sync on error. */
static void
sync_init ()
{
#ifdef WINDOWS32
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);
}
#else
if (STREAM_OK (stdout))
{
struct stat stbuf_o, stbuf_e;
sync_handle = fileno (stdout);
combined_output =
fstat (fileno (stdout), &stbuf_o) == 0 &&
fstat (fileno (stderr), &stbuf_e) == 0 &&
stbuf_o.st_dev == stbuf_e.st_dev &&
stbuf_o.st_ino == stbuf_e.st_ino;
}
else if (STREAM_OK (stderr))
sync_handle = fileno (stderr);
else
{
perror_with_name ("output-sync suppressed: ", "stderr");
output_sync = 0;
}
#endif
}
/* Adds file descriptors to the child structure to support output_sync; one
for stdout and one for stderr as long as they are open. If stdout and
stderr share a device they can share a temp file too.
Will reset output_sync on error. */
static void
assign_child_tempfiles (struct child *c)
{
/* If we don't have a temp file, get one. */
if (c->outfd < 0 && c->errfd < 0)
{
if (STREAM_OK (stdout))
{
c->outfd = open_tmpfd ();
if (c->outfd < 0)
goto error;
CLOSE_ON_EXEC (c->outfd);
}
if (STREAM_OK (stderr))
{
if (c->outfd >= 0 && combined_output)
c->errfd = c->outfd;
else
{
c->errfd = open_tmpfd ();
if (c->errfd < 0)
goto error;
CLOSE_ON_EXEC (c->errfd);
}
}
}
return;
error:
if (c->outfd >= 0)
close (c->outfd);
output_sync = 0;
}
/* Support routine for sync_output() */
static void
pump_from_tmp (int from, FILE *to)
{
static 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 (fileno (to), _O_BINARY);
#endif
if (lseek (from, 0, SEEK_SET) == -1)
perror ("lseek()");
while (1)
{
int len;
EINTRLOOP (len, read (from, buffer, sizeof (buffer)));
if (len < 0)
perror ("read()");
if (len <= 0)
break;
if (fwrite (buffer, len, 1, to) < 1)
perror ("fwrite()");
}
#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 (fileno (to), prev_mode);
#endif
}
/* Support routine for sync_output() */
static void *
acquire_semaphore (void)
{
static struct flock fl;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 1;
if (fcntl (sync_handle, F_SETLKW, &fl) != -1)
return &fl;
perror ("fcntl()");
return NULL;
}
/* Support routine for sync_output() */
static void
release_semaphore (void *sem)
{
struct flock *flp = (struct flock *)sem;
flp->l_type = F_UNLCK;
if (fcntl (sync_handle, F_SETLKW, flp) == -1)
perror ("fcntl()");
}
/* Synchronize the output of jobs in -j mode to keep the results of
each job together. This is done by holding the results in temp files,
one for stdout and potentially another for stderr, and only releasing
them to "real" stdout/stderr when a semaphore can be obtained. */
static void
sync_output (struct child *c)
{
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)
{
/* 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. */
/* Log the working directory. Force it if we're doing dir tracing. */
log_working_directory (1, (trace_flag & TRACE_DIRECTORY));
if (outfd_not_empty)
pump_from_tmp (c->outfd, stdout);
if (errfd_not_empty && c->errfd != c->outfd)
pump_from_tmp (c->errfd, stderr);
/* If we're doing dir tracing, force the leave message. */
if (trace_flag & TRACE_DIRECTORY)
log_working_directory (0, 1);
/* Exit the critical section. */
if (sem)
release_semaphore (sem);
/* Truncate and reset the output, in case we use it again. */
if (c->outfd >= 0)
{
int e;
lseek (c->outfd, 0, SEEK_SET);
EINTRLOOP (e, ftruncate (c->outfd, 0));
}
if (c->errfd >= 0 && c->errfd != c->outfd)
{
int e;
lseek (c->errfd, 0, SEEK_SET);
EINTRLOOP (e, ftruncate (c->errfd, 0));
}
}
}
#endif /* OUTPUT_SYNC */
extern int shell_function_pid, shell_function_completed;
/* Reap all dead children, storing the returned status and the new command
@@ -989,7 +738,6 @@ reap_children (int block, int err)
#ifdef WINDOWS32
{
HANDLE hPID;
int werr;
HANDLE hcTID, hcPID;
DWORD dwWaitStatus = 0;
exit_code = 0;
@@ -1018,9 +766,8 @@ reap_children (int block, int err)
hPID = process_wait_for_any (block, &dwWaitStatus);
if (hPID)
{
/* was an error found on this process? */
werr = process_last_err (hPID);
int werr = process_last_err (hPID);
/* get exit data */
exit_code = process_exit_code (hPID);
@@ -1116,7 +863,7 @@ reap_children (int block, int err)
if (!dontcare)
child_error (c, exit_code, exit_sig, coredump, 0);
c->file->update_status = 2;
c->file->update_status = us_failed;
if (delete_on_error == -1)
{
struct file *f = lookup_file (".DELETE_ON_ERROR");
@@ -1143,15 +890,15 @@ reap_children (int block, int err)
Since there are more commands that wanted to be run,
the target was not completely remade. So we treat
this as if a command had failed. */
c->file->update_status = 2;
c->file->update_status = us_failed;
}
else
{
#ifdef OUTPUT_SYNC
#ifndef NO_OUTPUT_SYNC
/* If we're sync'ing per line, write the previous line's
output before starting the next one. */
if (output_sync == OUTPUT_SYNC_LINE)
sync_output (c);
output_dump (&c->output);
#endif
/* Check again whether to start remotely.
Whether or not we want to changes over time.
@@ -1170,7 +917,7 @@ reap_children (int block, int err)
continue;
}
if (c->file->update_status != 0)
if (c->file->update_status != us_success)
/* We failed to start the commands. */
delete_child_targets (c);
}
@@ -1178,17 +925,17 @@ reap_children (int block, int err)
/* There are no more commands. We got through them all
without an unignored error. Now the target has been
successfully updated. */
c->file->update_status = 0;
c->file->update_status = us_success;
}
/* When we get here, all the commands for c->file are finished. */
#ifdef OUTPUT_SYNC
#ifndef NO_OUTPUT_SYNC
/* Synchronize any remaining parallel output. */
sync_output (c);
#endif /* OUTPUT_SYNC */
output_dump (&c->output);
#endif
/* At this point c->file->update_status contains 0 or 2. But
/* At this point c->file->update_status is success or failed. But
c->file->command_state is still cs_running if all the commands
ran; notice_finish_file looks for cs_running to tell it that
it's interesting to check the file's modtime again now. */
@@ -1242,10 +989,7 @@ reap_children (int block, int err)
static void
free_child (struct child *child)
{
if (child->outfd >= 0)
close (child->outfd);
if (child->errfd >= 0 && child->errfd != child->outfd)
close (child->errfd);
output_close (&child->output);
if (!jobserver_tokens)
fatal (NILF, "INTERNAL: Freeing child %p (%s) but no tokens left!\n",
@@ -1387,8 +1131,6 @@ start_job_command (struct child *child)
#if !defined(_AMIGA) && !defined(WINDOWS32)
static int bad_stdin = -1;
#endif
int print_cmd;
int sync_cmd;
int flags;
char *p;
#ifdef VMS
@@ -1476,7 +1218,7 @@ start_job_command (struct child *child)
free (argv[0]);
free (argv);
#endif
child->file->update_status = 1;
child->file->update_status = us_question;
notice_finished_file (child->file);
return;
}
@@ -1509,46 +1251,33 @@ start_job_command (struct child *child)
/* No more commands. Make sure we're "running"; we might not be if
(e.g.) all commands were skipped due to -n. */
set_command_state (child->file, cs_running);
child->file->update_status = 0;
child->file->update_status = us_success;
notice_finished_file (child->file);
}
OUTPUT_UNSET();
return;
}
print_cmd = (just_print_flag || (trace_flag & TRACE_RULE)
|| (!(flags & COMMANDS_SILENT) && !silent_flag));
#ifdef OUTPUT_SYNC
if (output_sync && sync_handle == -1)
sync_init ();
#endif
/* Are we going to synchronize this command's output? Do so if either we're
in SYNC_MAKE mode or this command is not recursive. We'll also check
in SYNC_RECURSE mode or this command is not recursive. We'll also check
output_sync separately below in case it changes due to error. */
sync_cmd = output_sync && (output_sync == OUTPUT_SYNC_RECURSE
|| !(flags & COMMANDS_RECURSE));
child->output.syncout = output_sync && (output_sync == OUTPUT_SYNC_RECURSE
|| !(flags & COMMANDS_RECURSE));
#ifdef OUTPUT_SYNC
if (sync_cmd)
{
/* If syncing, make sure we have temp files.
Write the command to the temp file so it's output in order. */
assign_child_tempfiles (child);
if (print_cmd)
child_out (child, p, 1);
}
else
OUTPUT_SET (&child->output);
#ifndef NO_OUTPUT_SYNC
if (! child->output.syncout)
/* We don't want to sync this command: to avoid misordered
output ensure any already-synced content is written. */
sync_output (child);
#endif /* OUTPUT_SYNC */
output_dump (&child->output);
#endif
/* If we're not syncing, print out the command. If silent, we call
'message' with null so it can log the working directory before the
command's own error messages appear. */
if (! sync_cmd)
message (0, print_cmd ? "%s" : NULL, p);
/* Print the command if appropriate. */
if (just_print_flag || trace_flag
|| (!(flags & COMMANDS_SILENT) && !silent_flag))
message (0, "%s", p);
/* Tell update_goal_chain that a command has been started on behalf of
this target. It is important that this happens here and not in
@@ -1597,6 +1326,9 @@ start_job_command (struct child *child)
goto next_command;
}
/* We're sure we're going to invoke a command: set up the output. */
output_start ();
/* Flush the output streams so they won't have things written twice. */
fflush (stdout);
@@ -1706,7 +1438,8 @@ start_job_command (struct child *child)
CLOSE_ON_EXEC (job_rfd);
/* Never use fork()/exec() here! Use spawn() instead in exec_command() */
child->pid = child_execute_job (child->good_stdin ? 0 : bad_stdin, 1,
child->pid = child_execute_job (child->good_stdin ? FD_STDIN : bad_stdin,
FD_STDOUT, FD_STDERR,
argv, child->environment);
if (child->pid < 0)
{
@@ -1731,6 +1464,9 @@ start_job_command (struct child *child)
environ = parent_environ; /* Restore value child may have clobbered. */
if (child->pid == 0)
{
int outfd = FD_STDOUT;
int errfd = FD_STDERR;
/* We are the child side. */
unblock_sigs ();
@@ -1750,24 +1486,17 @@ start_job_command (struct child *child)
setrlimit (RLIMIT_STACK, &stack_limit);
#endif
#ifdef OUTPUT_SYNC
/* Divert child output if output_sync in use. Don't capture
recursive make output unless we are synchronizing "make" mode. */
if (output_sync && sync_cmd)
/* Divert child output if output_sync in use. */
if (child->output.syncout)
{
int outfd = fileno (stdout);
int errfd = fileno (stderr);
if ((child->outfd >= 0 && (close (outfd) == -1
|| dup2 (child->outfd, outfd) == -1))
|| (child->errfd >= 0 && (close (errfd) == -1
|| dup2 (child->errfd, errfd) == -1)))
perror_with_name ("output-sync: ", "dup2()");
if (child->output.out >= 0)
outfd = child->output.out;
if (child->output.err >= 0)
errfd = child->output.err;
}
#endif /* OUTPUT_SYNC */
child_execute_job (child->good_stdin ? 0 : bad_stdin, 1,
argv, child->environment);
child_execute_job (child->good_stdin ? FD_STDIN : bad_stdin,
outfd, errfd, argv, child->environment);
}
else if (child->pid < 0)
{
@@ -1863,12 +1592,12 @@ start_job_command (struct child *child)
/* make sure CreateProcess() has Path it needs */
sync_Path_environment ();
#ifdef OUTPUT_SYNC
#ifndef NO_OUTPUT_SYNC
/* Divert child output if output_sync in use. Don't capture
recursive make output unless we are synchronizing "make" mode. */
if (output_sync && sync_cmd)
if (child->output.syncout)
hPID = process_easy (argv, child->environment,
child->outfd, child->errfd);
child->output.out, child->output.err);
else
#endif
hPID = process_easy (argv, child->environment, -1, -1);
@@ -1905,12 +1634,13 @@ start_job_command (struct child *child)
free (argv);
#endif
OUTPUT_UNSET();
return;
error:
child->file->update_status = 2;
child->file->update_status = us_failed;
notice_finished_file (child->file);
return;
OUTPUT_UNSET();
}
/* Try to start a child running.
@@ -1963,7 +1693,7 @@ start_waiting_job (struct child *c)
case cs_not_started:
/* All the command lines turned out to be empty. */
f->update_status = 0;
f->update_status = us_success;
/* FALLTHROUGH */
case cs_finished:
@@ -1999,6 +1729,22 @@ new_job (struct file *file)
/* Chop the commands up into lines if they aren't already. */
chop_commands (cmds);
/* Start the command sequence, record it in a new
'struct child', and add that to the chain. */
c = xcalloc (sizeof (struct child));
output_init (&c->output);
c->file = file;
c->sh_batch_file = NULL;
/* Cache dontcare flag because file->dontcare can be changed once we
return. Check dontcare inheritance mechanism for details. */
c->dontcare = file->dontcare;
/* Start saving output in case the expansion uses $(info ...) etc. */
OUTPUT_SET (&c->output);
/* Expand the command lines and store the results in LINES. */
lines = xmalloc (cmds->ncommand_lines * sizeof (char *));
for (i = 0; i < cmds->ncommand_lines; ++i)
@@ -2036,10 +1782,12 @@ new_job (struct file *file)
{
char openparen = *ref;
char closeparen = openparen == '(' ? ')' : '}';
char *outref;
int count;
char *p;
*out++ = *in++; /* Copy OPENPAREN. */
outref = out;
/* IN now points past the opening paren or brace.
Count parens or braces until it is matched. */
count = 0;
@@ -2072,7 +1820,7 @@ new_job (struct file *file)
/* Discard any preceding whitespace that has
already been written to the output. */
while (out > ref
while (out > outref
&& isblank ((unsigned char)out[-1]))
--out;
@@ -2101,18 +1849,7 @@ new_job (struct file *file)
file);
}
/* Start the command sequence, record it in a new
'struct child', and add that to the chain. */
c = xcalloc (sizeof (struct child));
c->file = file;
c->command_lines = lines;
c->sh_batch_file = NULL;
c->outfd = c->errfd = -1;
/* Cache dontcare flag because file->dontcare can be changed once we
return. Check dontcare inheritance mechanism for details. */
c->dontcare = file->dontcare;
/* Fetch the first command line to be run. */
job_next_command (c);
@@ -2248,7 +1985,7 @@ new_job (struct file *file)
/* Trace the build.
Use message here so that changes to working directories are logged. */
if (trace_flag & TRACE_RULE)
if (trace_flag)
{
char *newer = allocated_variable_expand_for_file ("$?", c->file);
const char *nm;
@@ -2271,7 +2008,6 @@ new_job (struct file *file)
free (newer);
}
/* The job is now primed. Start it running.
(This will notice if there is in fact no recipe.) */
start_waiting_job (c);
@@ -2282,6 +2018,7 @@ new_job (struct file *file)
while (file->command_state == cs_running)
reap_children (1, 0);
OUTPUT_UNSET ();
return;
}
@@ -2443,59 +2180,82 @@ start_waiting_jobs (void)
/* EMX: Start a child process. This function returns the new pid. */
# if defined __EMX__
int
child_execute_job (int stdin_fd, int stdout_fd, char **argv, char **envp)
child_execute_job (int stdin_fd, int stdout_fd, int stderr_fd,
char **argv, char **envp)
{
int pid;
/* stdin_fd == 0 means: nothing to do for stdin;
stdout_fd == 1 means: nothing to do for stdout */
int save_stdin = (stdin_fd != 0) ? dup (0) : 0;
int save_stdout = (stdout_fd != 1) ? dup (1): 1;
int save_stdin = -1;
int save_stdout = -1;
int save_stderr = -1;
/* < 0 only if dup() failed */
if (save_stdin < 0)
fatal (NILF, _("no more file handles: could not duplicate stdin\n"));
if (save_stdout < 0)
fatal (NILF, _("no more file handles: could not duplicate stdout\n"));
/* For each FD which needs to be redirected first make a dup of the standard
FD to save and mark it close on exec so our child won't see it. Then
dup2() the standard FD to the redirect FD, and also mark the redirect FD
as close on exec. */
if (stdin_fd != FD_STDIN)
{
save_stdin = dup (FD_STDIN);
if (save_stdin < 0)
fatal (NILF, _("no more file handles: could not duplicate stdin\n"));
CLOSE_ON_EXEC (save_stdin);
/* Close unnecessary file handles for the child. */
if (save_stdin != 0)
CLOSE_ON_EXEC (save_stdin);
if (save_stdout != 1)
CLOSE_ON_EXEC (save_stdout);
dup2 (stdin_fd, FD_STDIN);
CLOSE_ON_EXEC (stdin_fd);
}
/* Connect the pipes to the child process. */
if (stdin_fd != 0)
(void) dup2 (stdin_fd, 0);
if (stdout_fd != 1)
(void) dup2 (stdout_fd, 1);
if (stdout_fd != FD_STDOUT)
{
save_stdout = dup (FD_STDOUT);
if (save_stdout < 0)
fatal (NILF, _("no more file handles: could not duplicate stdout\n"));
CLOSE_ON_EXEC (save_stdout);
/* stdin_fd and stdout_fd must be closed on exit because we are
still in the parent process */
if (stdin_fd != 0)
CLOSE_ON_EXEC (stdin_fd);
if (stdout_fd != 1)
CLOSE_ON_EXEC (stdout_fd);
dup2 (stdout_fd, FD_STDOUT);
CLOSE_ON_EXEC (stdout_fd);
}
if (stderr_fd != FD_STDERR)
{
if (stderr_fd != stdout_fd)
{
save_stderr = dup (FD_STDERR);
if (save_stderr < 0)
fatal (NILF, _("no more file handles: could not duplicate stderr\n"));
CLOSE_ON_EXEC (save_stderr);
}
dup2 (stderr_fd, FD_STDERR);
CLOSE_ON_EXEC (stderr_fd);
}
/* Run the command. */
pid = exec_command (argv, envp);
/* Restore stdout/stdin of the parent and close temporary FDs. */
if (stdin_fd != 0)
/* Restore stdout/stdin/stderr of the parent and close temporary FDs. */
if (save_stdin >= 0)
{
if (dup2 (save_stdin, 0) != 0)
if (dup2 (save_stdin, FD_STDIN) != FD_STDIN)
fatal (NILF, _("Could not restore stdin\n"));
else
close (save_stdin);
}
if (stdout_fd != 1)
if (save_stdout >= 0)
{
if (dup2 (save_stdout, 1) != 1)
if (dup2 (save_stdout, FD_STDOUT) != FD_STDOUT)
fatal (NILF, _("Could not restore stdout\n"));
else
close (save_stdout);
}
if (save_stderr >= 0)
{
if (dup2 (save_stderr, FD_STDERR) != FD_STDERR)
fatal (NILF, _("Could not restore stderr\n"));
else
close (save_stderr);
}
return pid;
}
@@ -2503,19 +2263,28 @@ child_execute_job (int stdin_fd, int stdout_fd, char **argv, char **envp)
/* UNIX:
Replace the current process with one executing the command in ARGV.
STDIN_FD and STDOUT_FD are used as the process's stdin and stdout; ENVP is
the environment of the new program. This function does not return. */
STDIN_FD/STDOUT_FD/STDERR_FD are used as the process's stdin/stdout/stderr;
ENVP is the environment of the new program. This function does not return. */
void
child_execute_job (int stdin_fd, int stdout_fd, char **argv, char **envp)
child_execute_job (int stdin_fd, int stdout_fd, int stderr_fd,
char **argv, char **envp)
{
if (stdin_fd != 0)
(void) dup2 (stdin_fd, 0);
if (stdout_fd != 1)
(void) dup2 (stdout_fd, 1);
if (stdin_fd != 0)
(void) close (stdin_fd);
if (stdout_fd != 1)
(void) close (stdout_fd);
/* For any redirected FD, dup2() it to the standard FD then close it. */
if (stdin_fd != FD_STDIN)
{
dup2 (stdin_fd, FD_STDIN);
close (stdin_fd);
}
if (stdout_fd != FD_STDOUT)
dup2 (stdout_fd, FD_STDOUT);
if (stderr_fd != FD_STDERR)
dup2 (stderr_fd, FD_STDERR);
if (stdout_fd != FD_STDOUT)
close (stdout_fd);
if (stderr_fd != FD_STDERR && stderr_fd != stdout_fd)
close (stderr_fd);
/* Run the command. */
exec_command (argv, envp);
@@ -2548,7 +2317,6 @@ exec_command (char **argv, char **envp)
#ifdef WINDOWS32
HANDLE hPID;
HANDLE hWaitPID;
int err = 0;
int exit_code = EXIT_FAILURE;
/* make sure CreateProcess() has Path it needs */
@@ -2574,7 +2342,7 @@ exec_command (char **argv, char **envp)
while (hWaitPID)
{
/* was an error found on this process? */
err = process_last_err (hWaitPID);
int err = process_last_err (hWaitPID);
/* get exit data */
exit_code = process_exit_code (hWaitPID);
@@ -2613,10 +2381,8 @@ exec_command (char **argv, char **envp)
child_access ();
# ifdef __EMX__
/* Run the program. */
pid = spawnvpe (P_NOWAIT, argv[0], argv, envp);
if (pid >= 0)
return pid;
@@ -2625,7 +2391,6 @@ exec_command (char **argv, char **envp)
errno = ENOEXEC;
# else
/* Run the program. */
environ = envp;
execvp (argv[0], argv);
@@ -2849,8 +2614,8 @@ construct_command_argv_internal (char *line, char **restp, char *shell,
"chdir", "cls", "color", "copy", "ctty",
"date", "del", "dir", "echo", "echo.",
"endlocal", "erase", "exit", "for", "ftype",
"goto", "if", "if", "md", "mkdir", "path",
"pause", "prompt", "rd", "rem", "ren",
"goto", "if", "if", "md", "mkdir", "move",
"path", "pause", "prompt", "rd", "rem", "ren",
"rename", "rmdir", "set", "setlocal",
"shift", "time", "title", "type", "ver",
"verify", "vol", ":", 0 };
@@ -3170,12 +2935,12 @@ construct_command_argv_internal (char *line, char **restp, char *shell,
{
if (streq (sh_cmds[j], new_argv[0]))
goto slow;
# ifdef __EMX__
#if defined(__EMX__) || defined(WINDOWS32)
/* Non-Unix shells are case insensitive. */
if (!unixy_shell
&& strcasecmp (sh_cmds[j], new_argv[0]) == 0)
goto slow;
# endif
#endif
}
}
@@ -3285,11 +3050,13 @@ construct_command_argv_internal (char *line, char **restp, char *shell,
Then recurse, expanding this command line to get the final
argument list. */
char *new_line;
unsigned int shell_len = strlen (shell);
unsigned int line_len = strlen (line);
unsigned int sflags_len = shellflags ? strlen (shellflags) : 0;
#ifdef WINDOWS32
char *command_ptr = NULL; /* used for batch_mode_shell mode */
char *new_line;
#endif
# ifdef __EMX__ /* is this necessary? */
if (!unixy_shell && shellflags)
@@ -3473,7 +3240,9 @@ construct_command_argv_internal (char *line, char **restp, char *shell,
memcpy (ap, shellflags, sflags_len);
ap += sflags_len;
*(ap++) = ' ';
#ifdef WINDOWS32
command_ptr = ap;
#endif
for (p = line; *p != '\0'; ++p)
{
if (restp != NULL && *p == '\n')

48
job.h
View File

@@ -14,8 +14,7 @@ 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/>. */
#ifndef SEEN_JOB_H
#define SEEN_JOB_H
#include "output.h"
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
@@ -38,7 +37,11 @@ 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 NO_OUTPUT_SYNC
# define RECORD_SYNC_MUTEX(m) \
error (NILF, \
_("-O[TYPE] (--output-sync[=TYPE]) is not configured for this build."));
#else
# ifdef WINDOWS32
/* For emulations in w32/compat/posixfcn.c. */
# define F_GETFD 1
@@ -70,7 +73,6 @@ 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 */
@@ -78,7 +80,7 @@ typedef int sync_handle_t; /* file descriptor */
# define RECORD_SYNC_MUTEX(m) (void)(m)
# endif
#endif /* OUTPUT_SYNC */
#endif /* !NO_OUTPUT_SYNC */
/* Structure describing a running or dead child process. */
@@ -99,15 +101,14 @@ struct child
int cstatus; /* Completion status */
#endif
unsigned int command_line; /* Index into command_lines. */
int outfd; /* File descriptor for saving stdout */
int errfd; /* File descriptor for saving stderr */
pid_t pid; /* Child process's ID number. */
unsigned int remote:1; /* Nonzero if executing remotely. */
unsigned int noerror:1; /* Nonzero if commands contained a '-'. */
unsigned int good_stdin:1; /* Nonzero if this child has a good stdin. */
unsigned int deleted:1; /* Nonzero if targets have been deleted. */
unsigned int dontcare:1; /* Saved dontcare flag. */
unsigned int command_line; /* Index into command_lines. */
struct output output; /* Output for this child. */
pid_t pid; /* Child process's ID number. */
unsigned int remote:1; /* Nonzero if executing remotely. */
unsigned int noerror:1; /* Nonzero if commands contained a '-'. */
unsigned int good_stdin:1; /* Nonzero if this child has a good stdin. */
unsigned int deleted:1; /* Nonzero if targets have been deleted. */
unsigned int dontcare:1; /* Saved dontcare flag. */
};
extern struct child *children;
@@ -121,17 +122,24 @@ char **construct_command_argv (char *line, char **restp, struct file *file,
int cmd_flags, char** batch_file);
#ifdef VMS
int child_execute_job (char *argv, struct child *child);
#elif defined(__EMX__)
int child_execute_job (int stdin_fd, int stdout_fd, char **argv, char **envp);
#else
void child_execute_job (int stdin_fd, int stdout_fd, char **argv, char **envp);
# define FD_STDIN (fileno (stdin))
# define FD_STDOUT (fileno (stdout))
# define FD_STDERR (fileno (stderr))
# if defined(__EMX__)
int child_execute_job (int stdin_fd, int stdout_fd, int stderr_fd,
char **argv, char **envp);
# else
void child_execute_job (int stdin_fd, int stdout_fd, int stderr_fd,
char **argv, char **envp) __attribute__ ((noreturn));
# endif
#endif
#ifdef _AMIGA
void exec_command (char **argv);
void exec_command (char **argv) __attribute__ ((noreturn));
#elif defined(__EMX__)
int exec_command (char **argv, char **envp);
#else
void exec_command (char **argv, char **envp);
void exec_command (char **argv, char **envp) __attribute__ ((noreturn));
#endif
extern unsigned int job_slots_used;
@@ -149,5 +157,3 @@ extern int fatal_signal_mask;
#endif
extern unsigned int jobserver_tokens;
#endif /* SEEN_JOB_H */

11
load.c
View File

@@ -82,12 +82,12 @@ load_object (const gmk_floc *flocp, int noerror,
}
/* Assert that the GPL license symbol is defined. */
symp = dlsym (dlp, "plugin_is_GPL_compatible");
symp = (load_func_t) dlsym (dlp, "plugin_is_GPL_compatible");
if (! symp)
fatal (flocp, _("Loaded object %s is not declared to be GPL compatible"),
ldname);
symp = dlsym (dlp, symname);
symp = (load_func_t) dlsym (dlp, symname);
if (! symp)
fatal (flocp, _("Failed to load symbol %s from %s: %s"),
symname, ldname, dlerror ());
@@ -231,11 +231,10 @@ load_file (const gmk_floc *flocp, const char **ldname, int noerror)
return 0;
}
int
unload_file (struct file *file)
void
unload_file (const char *name)
{
fatal (flocp, "INTERNAL: Cannot unload when load is not supported!");
return 0;
fatal (NILF, "INTERNAL: Cannot unload when load is not supported!");
}
#endif /* MAKE_LOAD */

View File

@@ -54,9 +54,8 @@ gmk_expand (const char *ref)
/* Register a function to be called from makefiles. */
void
gmk_add_function (const char *name,
char *(*func)(const char *nm, int argc, char **argv),
int min, int max, int expand)
gmk_add_function (const char *name, gmk_func_ptr func,
unsigned int min, unsigned int max, unsigned int flags)
{
define_new_function (reading_file, name, min, max, expand, func);
define_new_function (reading_file, name, min, max, flags, func);
}

955
main.c

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,8 @@
# only if you have the full copy of the GNU make sources from the Git
# tree, not a dist copy.
GPG_FINGERPRINT := 6338B6D4
# We like mondo-warnings!
AM_CFLAGS += -Wall -Wextra -Wdeclaration-after-statement -Wshadow -Wpointer-arith -Wbad-function-cast
@@ -184,10 +186,41 @@ scm-update: get-config/texinfo.tex get-config/config.guess get-config/config.sub
update: po-update scm-update
# ---------------------------------- #
# Alternative configuration checks. #
# ---------------------------------- #
.PHONY: check-alt-config
check-alt-config: \
checkcfg.--disable-job-server \
checkcfg.--disable-load \
checkcfg.--without-guile \
checkcfg.CPPFLAGS^-DNO_OUTPUT_SYNC \
checkcfg.CPPFLAGS^-DNO_ARCHIVES
checkcfg.%: distdir
@ rm -rf $(distdir)/_build \
&& mkdir $(distdir)/_build \
&& cd $(distdir)/_build \
&& echo "Testing configure with $(subst ^,=,$*)" \
&& ../configure --srcdir=.. $(subst ^,=,$*) \
$(AM_DISTCHECK_CONFIGURE_FLAGS) $(DISTCHECK_CONFIGURE_FLAGS) \
CFLAGS='$(AM_CFLAGS)' \
&& $(MAKE) $(AM_MAKEFLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) check
.PHONY: update
update: po-update scm-update
## --------------- ##
## Sanity checks. ##
## --------------- ##
# Before we build a distribution be sure we run our local checks
#distdir: local-check
# Checks that don't require Git. Run 'changelog-check' last as
# previous test may reveal problems requiring new ChangeLog entries.
local-check: po-check changelog-check
@@ -212,6 +245,17 @@ po-check:
rm -f $@-1 $@-2; \
fi
## ------------------------- ##
## Make release targets. ##
## ------------------------- ##
tag-release:
case '$(VERSION)' in \
(*.*.9*) message=" candidate" ;; \
(*) message= ;; \
esac; \
$(GIT) tag -m "GNU Make release$$message $(VERSION)" -u '$(GPG_FINGERPRINT)' '$(VERSION)'
## ------------------------- ##
## GNU FTP upload artifacts. ##
## ------------------------- ##
@@ -221,7 +265,7 @@ po-check:
# you're SOL! :)
GPG = gpg
GPGFLAGS = -u 6338B6D4
GPGFLAGS = -u $(GPG_FINGERPRINT)
DIST_ARCHIVES_SIG = $(addsuffix .sig,$(DIST_ARCHIVES))
DIST_ARCHIVES_DIRECTIVE = $(addsuffix .directive.asc,$(DIST_ARCHIVES))

26
make.1
View File

@@ -143,7 +143,9 @@ for showing implicit rules,
.I j
for details on invocation of commands, and
.I m
for debugging while remaking makefiles.
for debugging while remaking makefiles. Use
.I n
to disable all previous debugging flags.
.TP 0.5i
\fB\-e\fR, \fB\-\-environment\-overrides\fR
Give variables taken from the environment precedence
@@ -289,25 +291,9 @@ This is used to pretend that the commands were done, in order to fool
future invocations of
.BR make .
.TP 0.5i
.B \-\-trace\fR[=\fImode\fR]
Print information about the commands invoked by
.BR make .
If
.I mode
is not specified or is
.B rule
information about the disposition of each target is printed. If
.I mode
is
.B dir
then directory enter/leave trace statements are shown for each synchronized
output segment (see
.BR \-O ).
If
.I mode
is
.B none
then no tracing is performed.
.B \-\-trace
Information about the disposition of each target is printed (why the target is
being rebuilt and what commands are run to rebuild it).
.TP 0.5i
\fB\-v\fR, \fB\-\-version\fR
Print the version of the

View File

@@ -1,4 +1,4 @@
FROM LIB:cres.o "commands.o"+"job.o"+"dir.o"+"file.o"+"misc.o"+"main.o"+"read.o"+"remake.o"+"rule.o"+"implicit.o"+"default.o"+"variable.o"+"expand.o"+"function.o"+"vpath.o"+"version.o"+"ar.o"+"arscan.o"+"signame.o"+"remote-stub.o"+"getopt.o"+"getopt1.o"+"alloca.o"+"amiga.o"+"hash.o"+"strcache.o"
FROM LIB:cres.o "commands.o"+"job.o"+"dir.o"+"file.o"+"misc.o"+"main.o"+"read.o"+"remake.o"+"rule.o"+"implicit.o"+"default.o"+"variable.o"+"expand.o"+"function.o"+"vpath.o"+"version.o"+"ar.o"+"arscan.o"+"signame.o"+"remote-stub.o"+"getopt.o"+"getopt1.o"+"alloca.o"+"amiga.o"+"hash.o"+"strcache.o"+"output.o"
TO "make.new"
LIB glob/glob.lib LIB:sc.lib LIB:amiga.lib
QUIET

View File

@@ -171,6 +171,12 @@
<File
RelativePath=".\job.c">
</File>
<File
RelativePath=".\load.c">
</File>
<File
RelativePath=".\output.c">
</File>
<File
RelativePath=".\main.c">
</File>
@@ -207,6 +213,9 @@
<File
RelativePath=".\w32\compat\dirent.c">
</File>
<File
RelativePath=".\w32\compat\posixfcn.c">
</File>
<File
RelativePath=".\w32\subproc\misc.c">
<FileConfiguration
@@ -277,6 +286,9 @@
<File
RelativePath=".\job.h">
</File>
<File
RelativePath=".\output.h">
</File>
<File
RelativePath=".\makeint.h">
</File>

View File

@@ -67,8 +67,8 @@ $ then
$ gosub check_cc_qual
$ endif
$ filelist = "alloca ar arscan commands default dir expand file function " + -
"hash implicit job main misc read remake remote-stub rule " + -
"signame variable version vmsfunctions vmsify vpath " + -
"hash implicit job load main misc read remake remote-stub rule " + -
"output signame variable version vmsfunctions vmsify vpath " + -
"[.glob]glob [.glob]fnmatch getopt1 getopt strcache"
$ copy config.h-vms config.h
$ n=0

View File

@@ -20,7 +20,7 @@
# Klaus Kämpf (kkaempf@rmi.de)
# Modified for version 3.78.1 by Hartmut.Becker@compaq.com.
# Modified for version 3.80 by zinser@decus.de
# Modified for version 3.81 by Hartmut Becker
# Modified for versions 3.81, 3.99.90 by Hartmut Becker
CC = cc
CP = copy
@@ -90,17 +90,17 @@ manext = 1
#guile = ,guile.obj
objs = commands.obj,job.obj,dir.obj,file.obj,misc.obj,hash.obj,\
main.obj,read.obj,remake.obj,rule.obj,implicit.obj,\
objs = commands.obj,job.obj,output.obj,dir.obj,file.obj,misc.obj,hash.obj,\
load.obj,main.obj,read.obj,remake.obj,rule.obj,implicit.obj,\
default.obj,variable.obj,expand.obj,function.obj,strcache.obj,\
vpath.obj,version.obj\
$(ARCHIVES)$(ALLOCA)$(extras)$(getopt)$(glob)$(guile)
srcs = commands.c job.c dir.c file.c misc.c guile.c hash.c \
main.c read.c remake.c rule.c implicit.c \
srcs = commands.c job.c output.c dir.c file.c misc.c guile.c hash.c \
load.c main.c read.c remake.c rule.c implicit.c \
default.c variable.c expand.c function.c strcache.c \
vpath.c version.c vmsfunctions.c vmsify.c $(ARCHIVES_SRC) $(ALLOCASRC) \
commands.h dep.h filedef.h job.h make.h rule.h variable.h
commands.h dep.h filedef.h job.h output.h makeint.h rule.h variable.h
.PHONY: all doc
@@ -114,40 +114,44 @@ make.exe: $(objs)
.PHONY: clean realclean
clean:
$$ purge [...]
-purge [...]
-$(RM) make.exe;,*.obj;
-$(RM) [.glob]*.obj;
# Automatically generated dependencies.
commands.obj: commands.c make.h dep.h commands.h filedef.h variable.h job.h
job.obj: job.c vmsjobs.c make.h commands.h job.h filedef.h variable.h
dir.obj: dir.c make.h
file.obj: file.c make.h commands.h dep.h filedef.h variable.h
misc.obj: misc.c make.h dep.h
hash.obj: hash.c make.h hash.h
strcache.obj: strcache.c make.h hash.h
main.obj: main.c make.h commands.h dep.h filedef.h variable.h job.h
guile.obj: guile.c make.h debug.h dep.h gmk-default.h
read.obj: read.c make.h commands.h dep.h filedef.h variable.h
remake.obj: remake.c make.h commands.h job.h dep.h filedef.h
rule.obj: rule.c make.h commands.h dep.h filedef.h variable.h rule.h
implicit.obj: implicit.c make.h rule.h dep.h filedef.h
default.obj: default.c make.h rule.h dep.h filedef.h commands.h variable.h
variable.obj: variable.c make.h commands.h variable.h dep.h filedef.h
expand.obj: expand.c make.h commands.h filedef.h variable.h
function.obj: function.c make.h variable.h dep.h commands.h job.h
vpath.obj: vpath.c make.h filedef.h variable.h
# makeint.h: config.h gnumake.h gettext.h
# filedef.h: hash.h
ar.obj: ar.c makeint.h filedef.h dep.h [.glob]fnmatch.h
arscan.obj: arscan.c makeint.h
commands.obj: commands.c makeint.h dep.h commands.h filedef.h variable.h job.h
default.obj: default.c makeint.h rule.h dep.h job.h filedef.h commands.h variable.h
dir.obj: dir.c makeint.h hash.h [.glob]glob.h
expand.obj: expand.c makeint.h commands.h filedef.h job.h rule.h variable.h
file.obj: file.c makeint.h commands.h dep.h filedef.h variable.h job.h debug.h
function.obj: function.c makeint.h variable.h dep.h commands.h filedef.h debug.h job.h
getopt.obj: getopt.c getopt.h config.h gettext.h
getopt1.obj: getopt1.c getopt.h config.h
guile.obj: guile.c makeint.h debug.h dep.h gmk-default.h
hash.obj: hash.c makeint.h hash.h
implicit.obj: implicit.c makeint.h rule.h dep.h filedef.h debug.h variable.h job.h commands.h
job.obj: job.c vmsjobs.c makeint.h commands.h job.h filedef.h variable.h debug.h
output.obj: output.c vmsjobs.c makeint.h output.h filedef.h debug.h
load.obj: load.c makeint.h debug.h filedef.h variable.h
main.obj: main.c makeint.h commands.h dep.h filedef.h variable.h job.h rule.h debug.h getopt.h
misc.obj: misc.c makeint.h dep.h debug.h
read.obj: read.c makeint.h commands.h dep.h filedef.h variable.h [.glob]glob.h debug.h rule.h job.h
remake.obj: remake.c makeint.h commands.h job.h dep.h filedef.h variable.h debug.h
remote-stub.obj: remote-stub.c makeint.h filedef.h job.h commands.h
rule.obj: rule.c makeint.h commands.h dep.h filedef.h variable.h rule.h job.h
signame.obj: signame.c makeint.h
strcache.obj: strcache.c makeint.h hash.h
variable.obj: variable.c makeint.h commands.h variable.h dep.h filedef.h job.h rule.h
version.obj: version.c config.h
arscan.obj: arscan.c
ar.obj: ar.c make.h filedef.h
signame.obj: signame.c
remote-stub.obj: remote-stub.c
[.glob]glob.obj: [.glob]glob.c
[.glob]fnmatch.obj: [.glob]fnmatch.c
getopt.obj: getopt.c
getopt1.obj: getopt1.c
vmsfunctions.obj: vmsfunctions.c make.h vmsdir.h
vmsify.obj: vmsify.c make.h
vmsfunctions.obj: vmsfunctions.c makeint.h vmsdir.h debug.h job.h
vmsify.obj: vmsify.c
vpath.obj: vpath.c makeint.h filedef.h variable.h
[.glob]fnmatch.obj: [.glob]fnmatch.c [.glob]fnmatch.h config.h
[.glob]glob.obj: [.glob]glob.c [.glob]glob.h [.glob]fnmatch.h config.h
config.h: config.h-vms
$(CP) $< $@

View File

@@ -197,6 +197,7 @@ unsigned int get_path_max (void);
#endif
#ifdef VMS
# include <fcntl.h>
# include <types.h>
# include <unixlib.h>
# include <unixio.h>
@@ -363,7 +364,6 @@ char *strsignal (int signum);
void sync_Path_environment (void);
int w32_kill (pid_t pid, int sig);
char *end_of_token_w32 (const char *s, char stopchar);
int find_and_set_default_shell (const char *token);
/* indicates whether or not we have Bourne shell */
@@ -381,6 +381,36 @@ extern int unixy_shell;
#define WIN32_LEAN_AND_MEAN
#endif /* WINDOWS32 */
#define ANY_SET(_v,_m) (((_v)&(_m)) != 0)
#define NONE_SET(_v,_m) (! ANY_SET ((_v),(_m)))
#define MAP_NUL 0x0001
#define MAP_BLANK 0x0002
#define MAP_SPACE 0x0004
#define MAP_COMMENT 0x0008
#define MAP_SEMI 0x0010
#define MAP_EQUALS 0x0020
#define MAP_COLON 0x0040
#define MAP_PERCENT 0x0080
#define MAP_PIPE 0x0100
#define MAP_DOT 0x0200
#define MAP_COMMA 0x0400
/* These are the valid characters for a user-defined function. */
#define MAP_USERFUNC 0x2000
/* This means not only a '$', but skip the variable reference. */
#define MAP_VARIABLE 0x4000
/* The set of characters which are path separators is OS-specific. */
#define MAP_PATHSEP 0x8000
#ifdef VMS
# define MAP_VMSCOMMA MAP_COMMA
#else
# define MAP_VMSCOMMA 0x0000
#endif
#define STOP_SET(_v,_m) ANY_SET (stopchar_map[(int)(_v)],(_m))
#if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT)
# define SET_STACK_SIZE
#endif
@@ -396,10 +426,6 @@ extern struct rlimit stack_limit;
const char *concat (unsigned int, ...);
const char *message_s (unsigned int length, int prefix, const char *fmt, ...)
__attribute__ ((__format__ (__printf__, 3, 4)));
const char *error_s (unsigned int length, const gmk_floc *flocp, const char *fmt, ...)
__attribute__ ((__format__ (__printf__, 3, 4)));
void message (int prefix, const char *fmt, ...)
__attribute__ ((__format__ (__printf__, 2, 3)));
void error (const gmk_floc *flocp, const char *fmt, ...)
@@ -408,9 +434,9 @@ void fatal (const gmk_floc *flocp, const char *fmt, ...)
__attribute__ ((noreturn, __format__ (__printf__, 2, 3)));
void die (int) __attribute__ ((noreturn));
void log_working_directory (int, int);
void pfatal_with_name (const char *) __attribute__ ((noreturn));
void perror_with_name (const char *, const char *);
#define xstrlen(_s) ((_s)==NULL ? 0 : strlen (_s))
void *xmalloc (unsigned int);
void *xcalloc (unsigned int);
void *xrealloc (void *, unsigned int);
@@ -425,8 +451,6 @@ int alpha_compare (const void *, const void *);
void print_spaces (unsigned int);
char *find_percent (char *);
const char *find_percent_cached (const char **);
int open_tmpfd (void);
FILE *open_tmpfile (char **, const char *);
#ifndef NO_ARCHIVES
int ar_name (const char *);
@@ -471,8 +495,6 @@ void user_access (void);
void make_access (void);
void child_access (void);
void close_stdout (void);
char *strip_whitespace (const char **begpp, const char **endpp);
/* String caching */
@@ -536,31 +558,25 @@ int strncasecmp (const char *s1, const char *s2, int n);
# endif
#endif
#ifdef POSIX
# define OUTPUT_SYNC
#endif
#define OUTPUT_SYNC_NONE 0
#define OUTPUT_SYNC_LINE 1
#define OUTPUT_SYNC_TARGET 2
#define OUTPUT_SYNC_RECURSE 3
#define TRACE_NONE 0x0
#define TRACE_RULE 0x1
#define TRACE_DIRECTORY 0x2
extern const gmk_floc *reading_file;
extern const gmk_floc **expanding_var;
extern char **environ;
extern unsigned short stopchar_map[];
extern int just_print_flag, silent_flag, ignore_errors_flag, keep_going_flag;
extern int print_data_base_flag, question_flag, touch_flag, always_make_flag;
extern int env_overrides, no_builtin_rules_flag, no_builtin_variables_flag;
extern int print_version_flag, print_directory_flag, check_symlink_flag;
extern int warn_undefined_variables_flag, trace_flag, posix_pedantic;
extern int not_parallel, second_expansion, clock_skew_detected;
extern int rebuilding_makefiles, one_shell, output_sync;
extern int rebuilding_makefiles, one_shell, output_sync, verify_flag;
/* can we run commands via 'sh -c xxx' or must we use batch files? */
extern int batch_mode_shell;

351
misc.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/>. */
#include "makeint.h"
#include "filedef.h"
#include "dep.h"
#include "debug.h"
@@ -22,6 +23,11 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include <stdarg.h>
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#else
# include <sys/file.h>
#endif
/* Compare strings *S1 and *S2.
Return negative if the first is less, positive if it is greater,
@@ -45,9 +51,7 @@ alpha_compare (const void *v1, const void *v2)
void
collapse_continuations (char *line)
{
register char *in, *out, *p;
register int backslash;
register unsigned int bs_write;
char *in, *out, *p;
in = strchr (line, '\n');
if (in == 0)
@@ -62,8 +66,8 @@ collapse_continuations (char *line)
/* BS_WRITE gets the number of quoted backslashes at
the end just before IN, and BACKSLASH gets nonzero
if the next character is quoted. */
backslash = 0;
bs_write = 0;
unsigned int backslash = 0;
unsigned int bs_write = 0;
for (p = in - 1; p >= line && *p == '\\'; --p)
{
if (backslash)
@@ -149,7 +153,7 @@ concat (unsigned int num, ...)
while (num-- > 0)
{
const char *s = va_arg (args, const char *);
unsigned int l = s ? strlen (s) : 0;
unsigned int l = xstrlen (s);
if (l == 0)
continue;
@@ -180,163 +184,8 @@ concat (unsigned int num, ...)
}
/* Return a formatted string buffer.
LENGTH must be the maximum length of all format arguments, stringified.
If we had a standard-compliant vsnprintf() this would be a lot simpler.
Maybe in the future we'll include gnulib's version. */
const char *
message_s (unsigned int length, int prefix, const char *fmt, ...)
{
static char *buffer = NULL;
static unsigned int bsize = 0;
char *bp;
va_list args;
/* Compute the maximum buffer size we'll need, and make sure we have it. */
length += strlen (fmt) + strlen (program) + 4 + INTEGER_LENGTH + 2;
if (length > bsize)
{
bsize = length * 2;
buffer = xrealloc (buffer, bsize);
}
bp = buffer;
if (prefix)
{
if (makelevel == 0)
sprintf (bp, "%s: ", program);
else
sprintf (bp, "%s[%u]: ", program, makelevel);
bp += strlen (buffer);
}
va_start (args, fmt);
vsprintf (bp, fmt, args);
va_end (args);
return buffer;
}
/* Return a formatted error message in a buffer.
LENGTH must be the maximum length of all format arguments, stringified. */
const char *
error_s (unsigned int length, const gmk_floc *flocp, const char *fmt, ...)
{
static char *buffer = NULL;
static unsigned int bsize = 0;
char *bp;
va_list args;
/* Compute the maximum buffer size we'll need, and make sure we have it. */
length += (strlen (fmt) + strlen (program) + 4 + INTEGER_LENGTH + 2
+ (flocp && flocp->filenm ? strlen (flocp->filenm) : 0));
if (length > bsize)
{
bsize = length * 2;
buffer = xrealloc (buffer, bsize);
}
bp = buffer;
if (flocp && flocp->filenm)
sprintf (bp, "%s:%lu: ", flocp->filenm, flocp->lineno);
else if (makelevel == 0)
sprintf (bp, "%s: ", program);
else
sprintf (bp, "%s[%u]: ", program, makelevel);
bp += strlen (bp);
va_start (args, fmt);
vsprintf (bp, fmt, args);
va_end (args);
return buffer;
}
/* Print a message on stdout. We could use message_s() to format it but then
we'd need a va_list version... */
void
message (int prefix, const char *fmt, ...)
{
va_list args;
log_working_directory (1, 0);
if (fmt != 0)
{
if (prefix)
{
if (makelevel == 0)
printf ("%s: ", program);
else
printf ("%s[%u]: ", program, makelevel);
}
va_start (args, fmt);
vfprintf (stdout, fmt, args);
va_end (args);
putchar ('\n');
}
fflush (stdout);
}
/* Print an error message. */
void
error (const gmk_floc *flocp, const char *fmt, ...)
{
va_list args;
log_working_directory (1, 0);
if (flocp && flocp->filenm)
fprintf (stderr, "%s:%lu: ", flocp->filenm, flocp->lineno);
else if (makelevel == 0)
fprintf (stderr, "%s: ", program);
else
fprintf (stderr, "%s[%u]: ", program, makelevel);
va_start (args, fmt);
vfprintf (stderr, fmt, args);
va_end (args);
putc ('\n', stderr);
fflush (stderr);
}
/* Print an error message and exit. */
void
fatal (const gmk_floc *flocp, const char *fmt, ...)
{
va_list args;
log_working_directory (1, 0);
if (flocp && flocp->filenm)
fprintf (stderr, "%s:%lu: *** ", flocp->filenm, flocp->lineno);
else if (makelevel == 0)
fprintf (stderr, "%s: *** ", program);
else
fprintf (stderr, "%s[%u]: *** ", program, makelevel);
va_start (args, fmt);
vfprintf (stderr, fmt, args);
va_end (args);
fputs (_(". Stop.\n"), stderr);
log_working_directory (0, 1);
die (2);
}
#ifndef HAVE_STRERROR
#undef strerror
char *
strerror (int errnum)
{
@@ -353,24 +202,6 @@ strerror (int errnum)
return buf;
}
#endif
/* Print an error message from errno. */
void
perror_with_name (const char *str, const char *name)
{
error (NILF, _("%s%s: %s"), str, name, strerror (errno));
}
/* Print an error message from errno and exit. */
void
pfatal_with_name (const char *name)
{
fatal (NILF, _("%s: %s"), name, strerror (errno));
/* NOTREACHED */
}
/* Like malloc but get fatal error if memory is exhausted. */
/* Don't bother if we're using dmalloc; it provides these for us. */
@@ -483,41 +314,11 @@ lindex (const char *s, const char *limit, int c)
char *
end_of_token (const char *s)
{
while (*s != '\0' && !isblank ((unsigned char)*s))
while (! STOP_SET (*s, MAP_BLANK|MAP_NUL))
++s;
return (char *)s;
}
#ifdef WINDOWS32
/*
* Same as end_of_token, but take into account a stop character
*/
char *
end_of_token_w32 (const char *s, char stopchar)
{
const char *p = s;
int backslash = 0;
while (*p != '\0' && *p != stopchar
&& (backslash || !isblank ((unsigned char)*p)))
{
if (*p++ == '\\')
{
backslash = !backslash;
while (*p == '\\')
{
backslash = !backslash;
++p;
}
}
else
backslash = 0;
}
return (char *)p;
}
#endif
/* Return the address of the first nonwhitespace or null in the string S. */
char *
@@ -605,7 +406,6 @@ free_ns_chain (struct nameseq *ns)
#if !HAVE_STRCASECMP && !HAVE_STRICMP && !HAVE_STRCMPI
/* If we don't have strcasecmp() (from POSIX), or anything that can substitute
for it, define our own version. */
@@ -631,7 +431,6 @@ strcasecmp (const char *s1, const char *s2)
#endif
#if !HAVE_STRNCASECMP && !HAVE_STRNICMP && !HAVE_STRNCMPI
/* If we don't have strncasecmp() (from POSIX), or anything that can
substitute for it, define our own version. */
@@ -906,7 +705,7 @@ child_access (void)
#endif /* GETLOADAVG_PRIVILEGED */
}
#ifdef NEED_GET_PATH_MAX
unsigned int
get_path_max (void)
@@ -925,129 +724,3 @@ get_path_max (void)
return value;
}
#endif
/* Provide support for temporary files. */
#ifndef HAVE_STDLIB_H
# ifdef HAVE_MKSTEMP
int mkstemp (char *template);
# else
char *mktemp (char *template);
# endif
#endif
/* This is only used by output-sync, and it may not be portable. */
#ifdef OUTPUT_SYNC
/* Returns a file descriptor to a temporary file. The file is automatically
closed/deleted on exit. Don't use a FILE* stream. */
int
open_tmpfd ()
{
int fd = -1;
FILE *tfile = tmpfile ();
if (! tfile)
pfatal_with_name ("tmpfile");
/* Create a duplicate so we can close the stream. */
fd = dup (fileno (tfile));
if (fd < 0)
pfatal_with_name ("dup");
fclose (tfile);
return fd;
}
#endif
FILE *
open_tmpfile (char **name, const char *template)
{
#ifdef HAVE_FDOPEN
int fd;
#endif
#if defined HAVE_MKSTEMP || defined HAVE_MKTEMP
# define TEMPLATE_LEN strlen (template)
#else
# define TEMPLATE_LEN L_tmpnam
#endif
*name = xmalloc (TEMPLATE_LEN + 1);
strcpy (*name, template);
#if defined HAVE_MKSTEMP && defined HAVE_FDOPEN
/* It's safest to use mkstemp(), if we can. */
fd = mkstemp (*name);
if (fd == -1)
return 0;
return fdopen (fd, "w");
#else
# ifdef HAVE_MKTEMP
(void) mktemp (*name);
# else
(void) tmpnam (*name);
# endif
# ifdef HAVE_FDOPEN
/* Can't use mkstemp(), but guard against a race condition. */
fd = open (*name, O_CREAT|O_EXCL|O_WRONLY, 0600);
if (fd == -1)
return 0;
return fdopen (fd, "w");
# else
/* Not secure, but what can we do? */
return fopen (*name, "w");
# endif
#endif
}
/* This code is stolen from gnulib.
If/when we abandon the requirement to work with K&R compilers, we can
remove this (and perhaps other parts of GNU make!) and migrate to using
gnulib directly.
This is called only through atexit(), which means die() has already been
invoked. So, call exit() here directly. Apparently that works...?
*/
/* Close standard output, exiting with status 'exit_failure' on failure.
If a program writes *anything* to stdout, that program should close
stdout and make sure that it succeeds before exiting. Otherwise,
suppose that you go to the extreme of checking the return status
of every function that does an explicit write to stdout. The last
printf can succeed in writing to the internal stream buffer, and yet
the fclose(stdout) could still fail (due e.g., to a disk full error)
when it tries to write out that buffered data. Thus, you would be
left with an incomplete output file and the offending program would
exit successfully. Even calling fflush is not always sufficient,
since some file systems (NFS and CODA) buffer written/flushed data
until an actual close call.
Besides, it's wasteful to check the return value from every call
that writes to stdout -- just let the internal stream state record
the failure. That's what the ferror test is checking below.
It's important to detect such failures and exit nonzero because many
tools (most notably 'make' and other build-management systems) depend
on being able to detect failure in other tools via their exit status. */
void
close_stdout (void)
{
int prev_fail = ferror (stdout);
int fclose_fail = fclose (stdout);
if (prev_fail || fclose_fail)
{
if (fclose_fail)
error (NILF, _("write error: %s"), strerror (errno));
else
error (NILF, _("write error"));
exit (EXIT_FAILURE);
}
}

762
output.c Normal file
View File

@@ -0,0 +1,762 @@
/* Output to stdout / stderr for GNU make
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 "makeint.h"
#include "job.h"
/* GNU make no longer supports pre-ANSI89 environments. */
#include <assert.h>
#include <stdio.h>
#include <stdarg.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#else
# include <sys/file.h>
#endif
#ifdef WINDOWS32
# include <windows.h>
# include <io.h>
# include "sub_proc.h"
#endif /* WINDOWS32 */
struct output *output_context = NULL;
unsigned int stdio_traced = 0;
#define OUTPUT_NONE (-1)
#define OUTPUT_ISSET(_out) ((_out)->out >= 0 || (_out)->err >= 0)
#ifdef HAVE_FCNTL
# define STREAM_OK(_s) ((fcntl (fileno (_s), F_GETFD) != -1) || (errno != EBADF))
#else
# define STREAM_OK(_s) 1
#endif
/* I really want to move to gnulib. However, this is a big undertaking
especially for non-UNIX platforms: how to get bootstrapping to work, etc.
I don't want to take the time to do it right now. Use a hack to get a
useful version of vsnprintf() for Windows. */
#ifdef __VMS
# define va_copy(_d, _s) ((_d) = (_s))
#endif
#ifdef _MSC_VER
# define va_copy(_d, _s) ((_d) = (_s))
# define snprintf msc_vsnprintf
static int
msc_vsnprintf (char *str, size_t size, const char *format, va_list ap)
{
int len = -1;
if (size > 0)
len = _vsnprintf_s (str, size, _TRUNCATE, format, ap);
if (len == -1)
len = _vscprintf (format, ap);
return len;
}
#endif
/* Write a string to the current STDOUT or STDERR. */
static void
_outputs (struct output *out, int is_err, const char *msg)
{
if (! out || ! out->syncout)
{
FILE *f = is_err ? stderr : stdout;
fputs (msg, f);
fflush (f);
}
else
{
int fd = is_err ? out->err : out->out;
int len = strlen (msg);
int r;
EINTRLOOP (r, lseek (fd, 0, SEEK_END));
while (1)
{
EINTRLOOP (r, write (fd, msg, len));
if (r == len || r <= 0)
break;
len -= r;
msg += r;
}
}
}
/* Write a message indicating that we've just entered or
left (according to ENTERING) the current directory. */
static int
log_working_directory (int entering)
{
static char *buf = NULL;
static unsigned int len = 0;
unsigned int need;
const char *fmt;
char *p;
/* Get enough space for the longest possible output. */
need = strlen (program) + INTEGER_LENGTH + 2 + 1;
if (starting_directory)
need += strlen (starting_directory);
/* Use entire sentences to give the translators a fighting chance. */
if (makelevel == 0)
if (starting_directory == 0)
if (entering)
fmt = _("%s: Entering an unknown directory\n");
else
fmt = _("%s: Leaving an unknown directory\n");
else
if (entering)
fmt = _("%s: Entering directory '%s'\n");
else
fmt = _("%s: Leaving directory '%s'\n");
else
if (starting_directory == 0)
if (entering)
fmt = _("%s[%u]: Entering an unknown directory\n");
else
fmt = _("%s[%u]: Leaving an unknown directory\n");
else
if (entering)
fmt = _("%s[%u]: Entering directory '%s'\n");
else
fmt = _("%s[%u]: Leaving directory '%s'\n");
need += strlen (fmt);
if (need > len)
{
buf = xrealloc (buf, need);
len = need;
}
p = buf;
if (print_data_base_flag)
{
*(p++) = '#';
*(p++) = ' ';
}
if (makelevel == 0)
if (starting_directory == 0)
sprintf (p, fmt , program);
else
sprintf (p, fmt, program, starting_directory);
else if (starting_directory == 0)
sprintf (p, fmt, program, makelevel);
else
sprintf (p, fmt, program, makelevel, starting_directory);
_outputs (NULL, 0, buf);
return 1;
}
/* Set a file descriptor to be in O_APPEND mode.
If it fails, just ignore it. */
static void
set_append_mode (int fd)
{
#if defined(F_GETFL) && defined(F_SETFL) && defined(O_APPEND)
int flags = fcntl (fd, F_GETFL, 0);
if (flags >= 0)
fcntl (fd, F_SETFL, flags | O_APPEND);
#endif
}
#ifndef NO_OUTPUT_SYNC
/* Semaphore for use in -j mode with output_sync. */
static sync_handle_t sync_handle = -1;
#define FD_NOT_EMPTY(_f) ((_f) != OUTPUT_NONE && lseek ((_f), 0, SEEK_END) > 0)
/* Set up the sync handle. Disables output_sync on error. */
static int
sync_init ()
{
int combined_output = 0;
#ifdef WINDOWS32
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);
}
#else
if (STREAM_OK (stdout))
{
struct stat stbuf_o, stbuf_e;
sync_handle = fileno (stdout);
combined_output = (fstat (fileno (stdout), &stbuf_o) == 0
&& fstat (fileno (stderr), &stbuf_e) == 0
&& stbuf_o.st_dev == stbuf_e.st_dev
&& stbuf_o.st_ino == stbuf_e.st_ino);
}
else if (STREAM_OK (stderr))
sync_handle = fileno (stderr);
else
{
perror_with_name ("output-sync suppressed: ", "stderr");
output_sync = 0;
}
#endif
return combined_output;
}
/* Support routine for output_sync() */
static void
pump_from_tmp (int from, FILE *to)
{
static char buffer[8192];
#ifdef WINDOWS32
int prev_mode;
/* "from" is opened by open_tmpfd, which does it in binary mode, so
we need the mode of "to" to match that. */
prev_mode = _setmode (fileno (to), _O_BINARY);
#endif
if (lseek (from, 0, SEEK_SET) == -1)
perror ("lseek()");
while (1)
{
int len;
EINTRLOOP (len, read (from, buffer, sizeof (buffer)));
if (len < 0)
perror ("read()");
if (len <= 0)
break;
if (fwrite (buffer, len, 1, to) < 1)
perror ("fwrite()");
}
#ifdef WINDOWS32
/* Switch "to" back to its original mode, so that log messages by
Make have the same EOL format as without --output-sync. */
_setmode (fileno (to), prev_mode);
#endif
}
/* Obtain the lock for writing output. */
static void *
acquire_semaphore (void)
{
static struct flock fl;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 1;
if (fcntl (sync_handle, F_SETLKW, &fl) != -1)
return &fl;
perror ("fcntl()");
return NULL;
}
/* Release the lock for writing output. */
static void
release_semaphore (void *sem)
{
struct flock *flp = (struct flock *)sem;
flp->l_type = F_UNLCK;
if (fcntl (sync_handle, F_SETLKW, flp) == -1)
perror ("fcntl()");
}
/* Returns a file descriptor to a temporary file. The file is automatically
closed/deleted on exit. Don't use a FILE* stream. */
int
output_tmpfd ()
{
int fd = -1;
FILE *tfile = tmpfile ();
if (! tfile)
pfatal_with_name ("tmpfile");
/* Create a duplicate so we can close the stream. */
fd = dup (fileno (tfile));
if (fd < 0)
pfatal_with_name ("dup");
fclose (tfile);
set_append_mode (fd);
return fd;
}
/* Adds file descriptors to the child structure to support output_sync; one
for stdout and one for stderr as long as they are open. If stdout and
stderr share a device they can share a temp file too.
Will reset output_sync on error. */
static void
setup_tmpfile (struct output *out)
{
/* Is make's stdout going to the same place as stderr? */
static int combined_output = -1;
if (combined_output < 0)
combined_output = sync_init ();
if (STREAM_OK (stdout))
{
int fd = output_tmpfd ();
if (fd < 0)
goto error;
CLOSE_ON_EXEC (fd);
out->out = fd;
}
if (STREAM_OK (stderr))
{
if (out->out != OUTPUT_NONE && combined_output)
out->err = out->out;
else
{
int fd = output_tmpfd ();
if (fd < 0)
goto error;
CLOSE_ON_EXEC (fd);
out->err = fd;
}
}
return;
/* If we failed to create a temp file, disable output sync going forward. */
error:
output_close (out);
output_sync = 0;
}
/* Synchronize the output of jobs in -j mode to keep the results of
each job together. This is done by holding the results in temp files,
one for stdout and potentially another for stderr, and only releasing
them to "real" stdout/stderr when a semaphore can be obtained. */
void
output_dump (struct output *out)
{
int outfd_not_empty = FD_NOT_EMPTY (out->out);
int errfd_not_empty = FD_NOT_EMPTY (out->err);
if (outfd_not_empty || errfd_not_empty)
{
int traced = 0;
/* Try to acquire the semaphore. If it fails, dump the output
unsynchronized; still better than silently discarding it.
We want to keep this lock for as little time as possible. */
void *sem = acquire_semaphore ();
/* Log the working directory for this dump. */
if (print_directory_flag && output_sync != OUTPUT_SYNC_RECURSE)
traced = log_working_directory (1);
if (outfd_not_empty)
pump_from_tmp (out->out, stdout);
if (errfd_not_empty && out->err != out->out)
pump_from_tmp (out->err, stderr);
if (traced)
log_working_directory (0);
/* Exit the critical section. */
if (sem)
release_semaphore (sem);
/* Truncate and reset the output, in case we use it again. */
if (out->out != OUTPUT_NONE)
{
int e;
lseek (out->out, 0, SEEK_SET);
EINTRLOOP (e, ftruncate (out->out, 0));
}
if (out->err != OUTPUT_NONE && out->err != out->out)
{
int e;
lseek (out->err, 0, SEEK_SET);
EINTRLOOP (e, ftruncate (out->err, 0));
}
}
}
#endif /* NO_OUTPUT_SYNC */
/* Provide support for temporary files. */
#ifndef HAVE_STDLIB_H
# ifdef HAVE_MKSTEMP
int mkstemp (char *template);
# else
char *mktemp (char *template);
# endif
#endif
FILE *
output_tmpfile (char **name, const char *template)
{
#ifdef HAVE_FDOPEN
int fd;
#endif
#if defined HAVE_MKSTEMP || defined HAVE_MKTEMP
# define TEMPLATE_LEN strlen (template)
#else
# define TEMPLATE_LEN L_tmpnam
#endif
*name = xmalloc (TEMPLATE_LEN + 1);
strcpy (*name, template);
#if defined HAVE_MKSTEMP && defined HAVE_FDOPEN
/* It's safest to use mkstemp(), if we can. */
fd = mkstemp (*name);
if (fd == -1)
return 0;
return fdopen (fd, "w");
#else
# ifdef HAVE_MKTEMP
(void) mktemp (*name);
# else
(void) tmpnam (*name);
# endif
# ifdef HAVE_FDOPEN
/* Can't use mkstemp(), but guard against a race condition. */
fd = open (*name, O_CREAT|O_EXCL|O_WRONLY, 0600);
if (fd == -1)
return 0;
return fdopen (fd, "w");
# else
/* Not secure, but what can we do? */
return fopen (*name, "w");
# endif
#endif
}
/* This code is stolen from gnulib.
If/when we abandon the requirement to work with K&R compilers, we can
remove this (and perhaps other parts of GNU make!) and migrate to using
gnulib directly.
This is called only through atexit(), which means die() has already been
invoked. So, call exit() here directly. Apparently that works...?
*/
/* Close standard output, exiting with status 'exit_failure' on failure.
If a program writes *anything* to stdout, that program should close
stdout and make sure that it succeeds before exiting. Otherwise,
suppose that you go to the extreme of checking the return status
of every function that does an explicit write to stdout. The last
printf can succeed in writing to the internal stream buffer, and yet
the fclose(stdout) could still fail (due e.g., to a disk full error)
when it tries to write out that buffered data. Thus, you would be
left with an incomplete output file and the offending program would
exit successfully. Even calling fflush is not always sufficient,
since some file systems (NFS and CODA) buffer written/flushed data
until an actual close call.
Besides, it's wasteful to check the return value from every call
that writes to stdout -- just let the internal stream state record
the failure. That's what the ferror test is checking below.
It's important to detect such failures and exit nonzero because many
tools (most notably 'make' and other build-management systems) depend
on being able to detect failure in other tools via their exit status. */
static void
close_stdout (void)
{
int prev_fail = ferror (stdout);
int fclose_fail = fclose (stdout);
if (prev_fail || fclose_fail)
{
if (fclose_fail)
error (NILF, _("write error: %s"), strerror (errno));
else
error (NILF, _("write error"));
exit (EXIT_FAILURE);
}
}
void
output_init (struct output *out)
{
if (out)
{
out->out = out->err = OUTPUT_NONE;
out->syncout = !!output_sync;
return;
}
/* Configure this instance of make. Be sure stdout is line-buffered. */
#ifdef HAVE_SETVBUF
# ifdef SETVBUF_REVERSED
setvbuf (stdout, _IOLBF, xmalloc (BUFSIZ), BUFSIZ);
# else /* setvbuf not reversed. */
/* Some buggy systems lose if we pass 0 instead of allocating ourselves. */
setvbuf (stdout, 0, _IOLBF, BUFSIZ);
# endif /* setvbuf reversed. */
#elif HAVE_SETLINEBUF
setlinebuf (stdout);
#endif /* setlinebuf missing. */
/* Force stdout/stderr into append mode. This ensures parallel jobs won't
lose output due to overlapping writes. */
set_append_mode (fileno (stdout));
set_append_mode (fileno (stderr));
#ifdef HAVE_ATEXIT
if (STREAM_OK (stdout))
atexit (close_stdout);
#endif
}
void
output_close (struct output *out)
{
if (! out)
{
if (stdio_traced)
log_working_directory (0);
return;
}
#ifndef NO_OUTPUT_SYNC
output_dump (out);
#endif
if (out->out >= 0)
close (out->out);
if (out->err >= 0 && out->err != out->out)
close (out->err);
output_init (out);
}
/* We're about to generate output: be sure it's set up. */
void
output_start ()
{
#ifndef NO_OUTPUT_SYNC
/* If we're syncing output make sure the temporary file is set up. */
if (output_context && output_context->syncout)
if (! OUTPUT_ISSET(output_context))
setup_tmpfile (output_context);
#endif
/* If we're not syncing this output per-line or per-target, make sure we emit
the "Entering..." message where appropriate. */
if (output_sync == OUTPUT_SYNC_NONE || output_sync == OUTPUT_SYNC_RECURSE)
if (! stdio_traced && print_directory_flag)
stdio_traced = log_working_directory (1);
}
void
outputs (int is_err, const char *msg)
{
if (! msg || *msg == '\0')
return;
output_start ();
_outputs (output_context, is_err, msg);
}
/* Return formatted string buffers.
If we move to gnulib we can use vasnprintf() etc. to make this simpler.
Note these functions use a static buffer, so each call overwrites the
results of the previous call. */
static struct fmtstring
{
char *buffer;
unsigned int size;
unsigned int len;
} fmtbuf = { NULL, 0, 0 };
/* Concatenate a formatted string onto the format buffer. */
static const char *
vfmtconcat (const char *fmt, va_list args)
{
va_list vcopy;
int tot;
int unused = fmtbuf.size - fmtbuf.len;
va_copy (vcopy, args);
tot = vsnprintf (&fmtbuf.buffer[fmtbuf.len], unused, fmt, args);
assert (tot >= 0);
if (tot >= unused)
{
fmtbuf.size += tot * 2;
fmtbuf.buffer = xrealloc (fmtbuf.buffer, fmtbuf.size);
unused = fmtbuf.size - fmtbuf.len;
tot = vsnprintf (&fmtbuf.buffer[fmtbuf.len], unused, fmt, vcopy);
}
va_end (vcopy);
fmtbuf.len += tot;
return fmtbuf.buffer;
}
static const char *
fmtconcat (const char *fmt, ...)
{
const char *p;
va_list args;
va_start (args, fmt);
p = vfmtconcat (fmt, args);
va_end (args);
return p;
}
/* Print a message on stdout. */
void
message (int prefix, const char *fmt, ...)
{
va_list args;
assert (fmt != NULL);
fmtbuf.len = 0;
if (prefix)
{
if (makelevel == 0)
fmtconcat ("%s: ", program);
else
fmtconcat ("%s[%u]: ", program, makelevel);
}
va_start (args, fmt);
vfmtconcat (fmt, args);
va_end (args);
fmtconcat ("\n");
outputs (0, fmtbuf.buffer);
}
/* Print an error message. */
void
error (const gmk_floc *flocp, const char *fmt, ...)
{
va_list args;
assert (fmt != NULL);
fmtbuf.len = 0;
if (flocp && flocp->filenm)
fmtconcat ("%s:%lu: ", flocp->filenm, flocp->lineno);
else if (makelevel == 0)
fmtconcat ("%s: ", program);
else
fmtconcat ("%s[%u]: ", program, makelevel);
va_start (args, fmt);
vfmtconcat (fmt, args);
va_end (args);
fmtconcat ("\n");
outputs (1, fmtbuf.buffer);
}
/* Print an error message and exit. */
void
fatal (const gmk_floc *flocp, const char *fmt, ...)
{
va_list args;
assert (fmt != NULL);
fmtbuf.len = 0;
if (flocp && flocp->filenm)
fmtconcat ("%s:%lu: *** ", flocp->filenm, flocp->lineno);
else if (makelevel == 0)
fmtconcat ("%s: *** ", program);
else
fmtconcat ("%s[%u]: *** ", program, makelevel);
va_start (args, fmt);
vfmtconcat (fmt, args);
va_end (args);
fmtconcat (_(". Stop.\n"));
outputs (1, fmtbuf.buffer);
die (2);
}
/* Print an error message from errno. */
void
perror_with_name (const char *str, const char *name)
{
error (NILF, _("%s%s: %s"), str, name, strerror (errno));
}
/* Print an error message from errno and exit. */
void
pfatal_with_name (const char *name)
{
fatal (NILF, _("%s: %s"), name, strerror (errno));
/* NOTREACHED */
}

51
output.h Normal file
View File

@@ -0,0 +1,51 @@
/* Output to stdout / stderr for GNU make
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/>. */
struct output
{
int out;
int err;
unsigned int syncout:1; /* True if we want to synchronize output. */
};
extern struct output *output_context;
extern unsigned int stdio_traced;
#define OUTPUT_SET(_new) do{ output_context = (_new)->syncout ? (_new) : NULL; }while(0)
#define OUTPUT_UNSET() do{ output_context = NULL; }while(0)
#define OUTPUT_TRACED() do{ stdio_traced = 1; }while(0)
#define OUTPUT_IS_TRACED() (!!stdio_traced)
FILE *output_tmpfile (char **, const char *);
/* Initialize and close a child output structure: if NULL do this program's
output (this should only be done once). */
void output_init (struct output *out);
void output_close (struct output *out);
/* In situations where output may be about to be displayed but we're not
sure if we've set it up yet, call this. */
void output_start (void);
/* Show a message on stdout or stderr. Will start the output if needed. */
void outputs (int is_err, const char *msg);
#ifndef NO_OUTPUT_SYNC
int output_tmpfd (void);
/* Dump any child output content to stdout, and reset it. */
void output_dump (struct output *out);
#endif

View File

@@ -27,9 +27,11 @@ guile.c
hash.c
implicit.c
job.c
job.h
load.c
main.c
misc.c
output.c
read.c
remake.c
remote-cstms.c

148
read.c
View File

@@ -20,8 +20,8 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include <glob.h>
#include "dep.h"
#include "filedef.h"
#include "dep.h"
#include "job.h"
#include "commands.h"
#include "variable.h"
@@ -155,8 +155,7 @@ static void record_target_var (struct nameseq *filenames, char *defn,
static enum make_word_type get_next_mword (char *buffer, char *delim,
char **startp, unsigned int *length);
static void remove_comments (char *line);
static char *find_char_unquote (char *string, int stop1, int stop2,
int blank, int ignorevars);
static char *find_char_unquote (char *string, int map);
static char *unescape_char (char *string, int c);
@@ -354,10 +353,24 @@ eval_makefile (const char *filename, int flags)
filename = expanded;
}
ebuf.fp = fopen (filename, "r");
ENULLLOOP (ebuf.fp, fopen (filename, "r"));
/* Save the error code so we print the right message later. */
makefile_errno = errno;
/* Check for unrecoverable errors: out of mem or FILE slots. */
switch (makefile_errno)
{
#ifdef EMFILE
case EMFILE:
#endif
#ifdef ENFILE
case ENFILE:
#endif
case ENOMEM:
fatal (reading_file, "%s", strerror (makefile_errno));
}
/* If the makefile wasn't found and it's either a makefile from
the 'MAKEFILES' variable or an included makefile,
search the included makefile search path for this makefile. */
@@ -456,7 +469,10 @@ eval_buffer (char *buffer, const gmk_floc *floc)
else if (reading_file)
ebuf.floc = *reading_file;
else
ebuf.floc.filenm = NULL;
{
ebuf.floc.filenm = NULL;
ebuf.floc.lineno = 1;
}
curfile = reading_file;
reading_file = &ebuf.floc;
@@ -755,7 +771,7 @@ eval (struct ebuffer *ebuf, int set_default)
if (in_ignored_define)
{
/* See if this is an endef line (plus optional comment). */
if (word1eq ("endef") && (*p2 == '\0' || *p2 == '#'))
if (word1eq ("endef") && STOP_SET (*p2, MAP_COMMENT|MAP_NUL))
in_ignored_define = 0;
continue;
@@ -869,7 +885,7 @@ eval (struct ebuffer *ebuf, int set_default)
/* Parse the list of file names. Don't expand archive references! */
p2 = p;
files = PARSE_FILE_SEQ (&p2, struct nameseq, '\0', NULL,
files = PARSE_FILE_SEQ (&p2, struct nameseq, MAP_NUL, NULL,
PARSEFS_NOAR);
free (p);
@@ -927,23 +943,31 @@ eval (struct ebuffer *ebuf, int set_default)
/* Parse the list of file names.
Don't expand archive references or strip "./" */
p2 = p;
files = PARSE_FILE_SEQ (&p2, struct nameseq, '\0', NULL,
files = PARSE_FILE_SEQ (&p2, struct nameseq, MAP_NUL, NULL,
PARSEFS_NOAR);
free (p);
/* Load each file and add it to the list "to be rebuilt". */
/* Load each file. */
while (files != 0)
{
struct nameseq *next = files->next;
const char *name = files->name;
struct dep *deps;
int r;
/* Load the file. 0 means failure. */
r = load_file (&ebuf->floc, &name, noerror);
if (! r && ! noerror)
fatal (&ebuf->floc, _("%s: failed to load"), name);
free_ns (files);
files = next;
if (! load_file (&ebuf->floc, &name, noerror) && ! noerror)
fatal (&ebuf->floc, _("%s: failed to load"), name);
/* Return of -1 means a special load: don't rebuild it. */
if (r == -1)
continue;
/* It succeeded, so add it to the list "to be rebuilt". */
deps = alloc_dep ();
deps->next = read_files;
read_files = deps;
@@ -986,7 +1010,7 @@ eval (struct ebuffer *ebuf, int set_default)
/* Search the line for an unquoted ; that is not after an
unquoted #. */
cmdleft = find_char_unquote (line, ';', '#', 0, 1);
cmdleft = find_char_unquote (line, MAP_SEMI|MAP_COMMENT|MAP_VARIABLE);
if (cmdleft != 0 && *cmdleft == '#')
{
/* We found a comment before a semicolon. */
@@ -1033,7 +1057,7 @@ eval (struct ebuffer *ebuf, int set_default)
if (cmdleft == 0)
{
/* Look for a semicolon in the expanded line. */
cmdleft = find_char_unquote (p2, ';', 0, 0, 0);
cmdleft = find_char_unquote (p2, MAP_SEMI);
if (cmdleft != 0)
{
@@ -1049,7 +1073,7 @@ eval (struct ebuffer *ebuf, int set_default)
here, but merely copy, since now you're beyond a ";"
and into a command script. However, the old parser
expanded the whole line, so we continue that for
backwards-compatiblity. Also, it wouldn't be
backwards-compatibility. Also, it wouldn't be
entirely consistent, since we do an unconditional
expand below once we know we don't have a
target-specific variable. */
@@ -1060,7 +1084,7 @@ eval (struct ebuffer *ebuf, int set_default)
}
}
colonp = find_char_unquote (p2, ':', 0, 0, 0);
colonp = find_char_unquote (p2, MAP_COLON);
#ifdef HAVE_DOS_PATHS
/* The drive spec brain-damage strikes again... */
/* Note that the only separators of targets in this context
@@ -1069,7 +1093,7 @@ eval (struct ebuffer *ebuf, int set_default)
while (colonp && (colonp[1] == '/' || colonp[1] == '\\') &&
colonp > p2 && isalpha ((unsigned char)colonp[-1]) &&
(colonp == p2 + 1 || strchr (" \t(", colonp[-2]) != 0))
colonp = find_char_unquote (colonp + 1, ':', 0, 0, 0);
colonp = find_char_unquote (colonp + 1, MAP_COLON);
#endif
if (colonp != 0)
break;
@@ -1105,7 +1129,7 @@ eval (struct ebuffer *ebuf, int set_default)
/* Make the colon the end-of-string so we know where to stop
looking for targets. Start there again once we're done. */
*colonp = '\0';
filenames = PARSE_FILE_SEQ (&p2, struct nameseq, '\0', NULL, 0);
filenames = PARSE_SIMPLE_SEQ (&p2, struct nameseq);
*colonp = ':';
p2 = colonp;
@@ -1160,7 +1184,7 @@ eval (struct ebuffer *ebuf, int set_default)
/* This is a normal target, _not_ a target-specific variable.
Unquote any = in the dependency list. */
find_char_unquote (lb_next, '=', 0, 0, 0);
find_char_unquote (lb_next, MAP_EQUALS);
/* Remember the command prefix for this target. */
prefix = cmd_prefix;
@@ -1178,7 +1202,7 @@ eval (struct ebuffer *ebuf, int set_default)
/* Look for a semicolon in the expanded line. */
if (cmdleft == 0)
{
cmdleft = find_char_unquote (p2, ';', 0, 0, 0);
cmdleft = find_char_unquote (p2, MAP_SEMI);
if (cmdleft != 0)
*(cmdleft++) = '\0';
}
@@ -1232,7 +1256,7 @@ eval (struct ebuffer *ebuf, int set_default)
if (p != 0)
{
struct nameseq *target;
target = PARSE_FILE_SEQ (&p2, struct nameseq, ':', NULL,
target = PARSE_FILE_SEQ (&p2, struct nameseq, MAP_COLON, NULL,
PARSEFS_NOGLOB);
++p2;
if (target == 0)
@@ -1295,14 +1319,13 @@ eval (struct ebuffer *ebuf, int set_default)
if (set_default && default_goal_var->value[0] == '\0')
{
const char *name;
struct dep *d;
struct nameseq *t = filenames;
for (; t != 0; t = t->next)
{
int reject = 0;
name = t->name;
const char *name = t->name;
/* We have nothing to do if this is an implicit rule. */
if (strchr (name, '%') != 0)
@@ -1384,7 +1407,7 @@ remove_comments (char *line)
{
char *comment;
comment = find_char_unquote (line, '#', 0, 0, 0);
comment = find_char_unquote (line, MAP_COMMENT);
if (comment != 0)
/* Cut off the line at the #. */
@@ -1563,7 +1586,7 @@ conditional_line (char *line, int len, const gmk_floc *flocp)
/* Found one: skip past it and any whitespace after it. */
line = next_token (line + len);
#define EXTRANEOUS() error (flocp, _("Extraneous text after '%s' directive"), cmdname)
#define EXTRANEOUS() error (flocp, _("extraneous text after '%s' directive"), cmdname)
/* An 'endif' cannot contain extra text, and reduces the if-depth by 1 */
if (cmdtype == c_endif)
@@ -1617,7 +1640,7 @@ conditional_line (char *line, int len, const gmk_floc *flocp)
and cannot be an 'else' or 'endif'. */
/* Find the length of the next word. */
for (p = line+1; *p != '\0' && !isspace ((unsigned char)*p); ++p)
for (p = line+1; ! STOP_SET (*p, MAP_SPACE|MAP_NUL); ++p)
;
len = p - line;
@@ -2079,7 +2102,7 @@ record_files (struct nameseq *filenames, const char *pattern,
more than once. Just give a warning since this is harmless. */
if (cmds != 0 && cmds == f->cmds)
error (flocp,
_("target '%s' given more than once in the same rule."),
_("target '%s' given more than once in the same rule"),
f->name);
/* Check for two single-colon entries both with commands.
@@ -2208,37 +2231,24 @@ record_files (struct nameseq *filenames, const char *pattern,
STOPCHAR _cannot_ be '$' if IGNOREVARS is true. */
static char *
find_char_unquote (char *string, int stop1, int stop2, int blank,
int ignorevars)
find_char_unquote (char *string, int map)
{
unsigned int string_len = 0;
char *p = string;
if (ignorevars)
ignorevars = '$';
/* Always stop on NUL. */
map |= MAP_NUL;
while (1)
{
if (stop2 && blank)
while (*p != '\0' && *p != ignorevars && *p != stop1 && *p != stop2
&& ! isblank ((unsigned char) *p))
++p;
else if (stop2)
while (*p != '\0' && *p != ignorevars && *p != stop1 && *p != stop2)
++p;
else if (blank)
while (*p != '\0' && *p != ignorevars && *p != stop1
&& ! isblank ((unsigned char) *p))
++p;
else
while (*p != '\0' && *p != ignorevars && *p != stop1)
++p;
while (! STOP_SET (*p, map))
++p;
if (*p == '\0')
break;
/* If we stopped due to a variable reference, skip over its contents. */
if (*p == ignorevars)
if (STOP_SET (*p, MAP_VARIABLE))
{
char openparen = p[1];
@@ -2346,7 +2356,7 @@ unescape_char (char *string, int c)
char *
find_percent (char *pattern)
{
return find_char_unquote (pattern, '%', 0, 0, 0);
return find_char_unquote (pattern, MAP_PERCENT);
}
/* Search STRING for an unquoted % and handle quoting. Returns a pointer to
@@ -2369,7 +2379,7 @@ find_percent_cached (const char **string)
while (1)
{
while (*p != '\0' && *p != '%')
while (! STOP_SET (*p, MAP_PERCENT|MAP_NUL))
++p;
if (*p == '\0')
@@ -2539,7 +2549,7 @@ readline (struct ebuffer *ebuf)
if ((p - start) > 1 && p[-2] == '\r')
{
--p;
p[-1] = '\n';
memmove (p-1, p, strlen (p) + 1);
}
#endif
@@ -2984,7 +2994,7 @@ tilde_expand (const char *name)
*/
void *
parse_file_seq (char **stringp, unsigned int size, int stopchar,
parse_file_seq (char **stringp, unsigned int size, int stopmap,
const char *prefix, int flags)
{
extern void dir_setup_glob (glob_t *glob);
@@ -2992,9 +3002,8 @@ parse_file_seq (char **stringp, unsigned int size, int stopchar,
/* tmp points to tmpbuf after the prefix, if any.
tp is the end of the buffer. */
static char *tmpbuf = NULL;
static int tmpbuf_len = 0;
int cachep = (! (flags & PARSEFS_NOCACHE));
int cachep = NONE_SET (flags, PARSEFS_NOCACHE);
struct nameseq *new = 0;
struct nameseq **newp = &new;
@@ -3009,20 +3018,18 @@ parse_file_seq (char **stringp, unsigned int size, int stopchar,
glob_t gl;
char *tp;
#ifdef VMS
# define VMS_COMMA ','
#else
# define VMS_COMMA 0
#endif
/* Always stop on NUL. */
stopmap |= MAP_NUL;
if (size < sizeof (struct nameseq))
size = sizeof (struct nameseq);
if (! (flags & PARSEFS_NOGLOB))
if (NONE_SET (flags, PARSEFS_NOGLOB))
dir_setup_glob (&gl);
/* Get enough temporary space to construct the largest possible target. */
{
static int tmpbuf_len = 0;
int l = strlen (*stringp) + 1;
if (l > tmpbuf_len)
{
@@ -3050,39 +3057,39 @@ parse_file_seq (char **stringp, unsigned int size, int stopchar,
/* Skip whitespace; at the end of the string or STOPCHAR we're done. */
p = next_token (p);
if (*p == '\0' || *p == stopchar)
if (STOP_SET (*p, stopmap))
break;
/* There are names left, so find the end of the next name.
Throughout this iteration S points to the start. */
s = p;
p = find_char_unquote (p, stopchar, VMS_COMMA, 1, 0);
p = find_char_unquote (p, stopmap|MAP_VMSCOMMA|MAP_BLANK);
#ifdef VMS
/* convert comma separated list to space separated */
if (p && *p == ',')
*p =' ';
#endif
#ifdef _AMIGA
if (stopchar == ':' && p && *p == ':'
if (p && STOP_SET (*p, stopmap & MAP_COLON)
&& !(isspace ((unsigned char)p[1]) || !p[1]
|| isspace ((unsigned char)p[-1])))
p = find_char_unquote (p+1, stopchar, VMS_COMMA, 1, 0);
p = find_char_unquote (p+1, stopmap|MAP_VMSCOMMA|MAP_BLANK);
#endif
#ifdef HAVE_DOS_PATHS
/* For DOS paths, skip a "C:\..." or a "C:/..." until we find the
first colon which isn't followed by a slash or a backslash.
Note that tokens separated by spaces should be treated as separate
tokens since make doesn't allow path names with spaces */
if (stopchar == ':')
if (stopmap | MAP_COLON)
while (p != 0 && !isspace ((unsigned char)*p) &&
(p[1] == '\\' || p[1] == '/') && isalpha ((unsigned char)p[-1]))
p = find_char_unquote (p + 1, stopchar, VMS_COMMA, 1, 0);
p = find_char_unquote (p + 1, stopmap|MAP_VMSCOMMA|MAP_BLANK);
#endif
if (p == 0)
p = s + strlen (s);
/* Strip leading "this directory" references. */
if (! (flags & PARSEFS_NOSTRIP))
if (NONE_SET (flags, PARSEFS_NOSTRIP))
#ifdef VMS
/* Skip leading '[]'s. */
while (p - s > 2 && s[0] == '[' && s[1] == ']')
@@ -3156,7 +3163,7 @@ parse_file_seq (char **stringp, unsigned int size, int stopchar,
Finally, note that archive groups must end with ')' as the last
character, so ensure there's some word ending like that before
considering this an archive group. */
if (! (flags & PARSEFS_NOAR)
if (NONE_SET (flags, PARSEFS_NOAR)
&& tp == tmpbuf && tp[0] != '(' && tp[nlen-1] != ')')
{
char *n = strchr (tp, '(');
@@ -3172,8 +3179,7 @@ parse_file_seq (char **stringp, unsigned int size, int stopchar,
/* Find the end of this word. We don't want to unquote and
we don't care about quoting since we're looking for the
last char in the word. */
while (*e != '\0' && *e != stopchar && *e != VMS_COMMA
&& ! isblank ((unsigned char) *e))
while (! STOP_SET (*e, stopmap|MAP_BLANK|MAP_VMSCOMMA))
++e;
/* If we didn't move, we're done now. */
if (e == o)
@@ -3222,7 +3228,7 @@ parse_file_seq (char **stringp, unsigned int size, int stopchar,
/* If we're not globbing we're done: add it to the end of the chain.
Go to the next item in the string. */
if (flags & PARSEFS_NOGLOB)
if (ANY_SET (flags, PARSEFS_NOGLOB))
{
NEWELT (concat (2, prefix, tmpbuf));
continue;
@@ -3245,7 +3251,7 @@ parse_file_seq (char **stringp, unsigned int size, int stopchar,
/* If NAME is an archive member reference replace it with the archive
file name, and save the member name in MEMNAME. We will glob on the
archive name and then reattach MEMNAME later. */
if (! (flags & PARSEFS_NOAR) && ar_name (name))
if (NONE_SET (flags, PARSEFS_NOAR) && ar_name (name))
{
ar_parse_name (name, &arname, &memname);
name = arname;
@@ -3253,7 +3259,7 @@ parse_file_seq (char **stringp, unsigned int size, int stopchar,
#endif /* !NO_ARCHIVES */
/* glob() is expensive: don't call it unless we need to. */
if (!(flags & PARSEFS_EXISTS) && strpbrk (name, "?*[") == NULL)
if (NONE_SET (flags, PARSEFS_EXISTS) && strpbrk (name, "?*[") == NULL)
{
globme = 0;
i = 1;
@@ -3273,7 +3279,7 @@ parse_file_seq (char **stringp, unsigned int size, int stopchar,
case GLOB_NOMATCH:
/* If we want only existing items, skip this one. */
if (flags & PARSEFS_EXISTS)
if (ANY_SET (flags, PARSEFS_EXISTS))
{
i = 0;
break;

View File

@@ -62,7 +62,7 @@ static int update_file (struct file *file, unsigned int depth);
static int update_file_1 (struct file *file, unsigned int depth);
static int check_dep (struct file *file, unsigned int depth,
FILE_TIMESTAMP this_mtime, int *must_make_ptr);
static int touch_file (struct file *file);
static enum update_status touch_file (struct file *file);
static void remake_file (struct file *file);
static FILE_TIMESTAMP name_mtime (const char *name);
static const char *library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr);
@@ -76,11 +76,11 @@ static const char *library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr);
targets, and we should only make one goal at a time and return as soon as
one goal whose 'changed' member is nonzero is successfully made. */
int
enum update_status
update_goal_chain (struct dep *goals)
{
int t = touch_flag, q = question_flag, n = just_print_flag;
int status = -1;
enum update_status status = us_none;
#define MTIME(file) (rebuilding_makefiles ? file_mtime_no_search (file) \
: file_mtime (file))
@@ -130,7 +130,7 @@ update_goal_chain (struct dep *goals)
file = file->prev)
{
unsigned int ocommands_started;
int x;
int fail;
file->dontcare = g->dontcare;
@@ -152,7 +152,7 @@ update_goal_chain (struct dep *goals)
actually run. */
ocommands_started = commands_started;
x = update_file (file, rebuilding_makefiles ? 1 : 0);
fail = update_file (file, rebuilding_makefiles ? 1 : 0);
check_renamed (file);
/* Set the goal's 'changed' flag if any commands were started
@@ -166,9 +166,9 @@ update_goal_chain (struct dep *goals)
STATUS as it is if no updating was done. */
stop = 0;
if ((x != 0 || file->updated) && status < 1)
if ((fail || file->updated) && status < us_question)
{
if (file->update_status != 0)
if (file->update_status != us_success)
{
/* Updating failed, or -q triggered. The STATUS value
tells our caller which. */
@@ -195,7 +195,7 @@ update_goal_chain (struct dep *goals)
enter an infinite loop. */
if (!rebuilding_makefiles
|| (!just_print_flag && !question_flag))
status = 0;
status = us_success;
if (rebuilding_makefiles && file->dontcare)
/* This is a default makefile; stop remaking. */
stop = 1;
@@ -222,10 +222,10 @@ update_goal_chain (struct dep *goals)
print a message saying nothing needs doing. */
if (!rebuilding_makefiles
/* If the update_status is zero, we updated successfully
/* If the update_status is success, we updated successfully
or not at all. G->changed will have been set above if
any commands were actually started for this goal. */
&& file->update_status == 0 && !g->changed
&& file->update_status == us_success && !g->changed
/* Never give a message under -s or -q. */
&& !silent_flag && !question_flag)
message (1, ((file->phony || file->cmds == 0)
@@ -271,7 +271,7 @@ update_goal_chain (struct dep *goals)
}
/* If FILE is not up to date, execute the commands for it.
Return 0 if successful, 1 if unsuccessful;
Return 0 if successful, non-0 if unsuccessful;
but with some flag settings, just call 'exit' if unsuccessful.
DEPTH is the depth in recursions of this function.
@@ -285,7 +285,7 @@ update_goal_chain (struct dep *goals)
static int
update_file (struct file *file, unsigned int depth)
{
register int status = 0;
int status = 0;
register struct file *f;
f = file->double_colon ? file->double_colon : file;
@@ -297,9 +297,10 @@ update_file (struct file *file, unsigned int depth)
if (f->considered == considered)
{
/* Check for the case where a target has been tried and failed but
the diagnostics hasn't been issued. If we need the diagnostics
the diagnostics haven't been issued. If we need the diagnostics
then we will have to continue. */
if (!(f->updated && f->update_status > 0 && !f->dontcare && f->no_diag))
if (!(f->updated && f->update_status > us_none
&& !f->dontcare && f->no_diag))
{
DBF (DB_VERBOSE, _("Pruning file '%s'.\n"));
return f->command_state == cs_finished ? f->update_status : 0;
@@ -363,7 +364,7 @@ complain (struct file *file)
for (d = file->deps; d != 0; d = d->next)
{
if (d->file->updated && d->file->update_status > 0 && file->no_diag)
if (d->file->updated && d->file->update_status > us_none && file->no_diag)
{
complain (d->file);
break;
@@ -395,7 +396,8 @@ complain (struct file *file)
}
}
/* Consider a single 'struct file' and update it as appropriate. */
/* Consider a single 'struct file' and update it as appropriate.
Return 0 on success, or non-0 on failure. */
static int
update_file_1 (struct file *file, unsigned int depth)
@@ -412,7 +414,7 @@ update_file_1 (struct file *file, unsigned int depth)
if (file->updated)
{
if (file->update_status > 0)
if (file->update_status > us_none)
{
DBF (DB_VERBOSE,
_("Recently tried and failed to update file '%s'.\n"));
@@ -577,7 +579,7 @@ update_file_1 (struct file *file, unsigned int depth)
while (f != 0);
}
if (dep_status != 0 && !keep_going_flag)
if (dep_status && !keep_going_flag)
break;
if (!running)
@@ -638,7 +640,7 @@ update_file_1 (struct file *file, unsigned int depth)
while (f != 0);
}
if (dep_status != 0 && !keep_going_flag)
if (dep_status && !keep_going_flag)
break;
if (!running)
@@ -664,7 +666,7 @@ update_file_1 (struct file *file, unsigned int depth)
if (dep_status != 0)
{
file->update_status = dep_status;
file->update_status = us_failed;
notice_finished_file (file);
--depth;
@@ -820,17 +822,16 @@ update_file_1 (struct file *file, unsigned int depth)
switch (file->update_status)
{
case 2:
case us_failed:
DBF (DB_BASIC, _("Failed to remake target file '%s'.\n"));
break;
case 0:
case us_success:
DBF (DB_BASIC, _("Successfully remade target file '%s'.\n"));
break;
case 1:
DBF (DB_BASIC, _("Target file '%s' needs remade under -q.\n"));
case us_question:
DBF (DB_BASIC, _("Target file '%s' needs to be remade under -q.\n"));
break;
default:
assert (file->update_status >= 0 && file->update_status <= 2);
case us_none:
break;
}
@@ -842,7 +843,7 @@ update_file_1 (struct file *file, unsigned int depth)
files listed in its 'also_make' member. Under -t, this function also
touches FILE.
On return, FILE->update_status will no longer be -1 if it was. */
On return, FILE->update_status will no longer be us_none if it was. */
void
notice_finished_file (struct file *file)
@@ -856,12 +857,12 @@ notice_finished_file (struct file *file)
if (touch_flag
/* The update status will be:
-1 if this target was not remade;
0 if 0 or more commands (+ or ${MAKE}) were run and won;
1 if some commands were run and lost.
us_success if 0 or more commands (+ or ${MAKE}) were run and won;
us_none if this target was not remade;
>us_none if some commands were run and lost.
We touch the target if it has commands which either were not run
or won when they ran (i.e. status is 0). */
&& file->update_status == 0)
&& file->update_status == us_success)
{
if (file->cmds != 0 && file->cmds->any_recurse)
{
@@ -876,7 +877,7 @@ notice_finished_file (struct file *file)
{
have_nonrecursing:
if (file->phony)
file->update_status = 0;
file->update_status = us_success;
/* According to POSIX, -t doesn't affect targets with no cmds. */
else if (file->cmds != 0)
{
@@ -950,7 +951,7 @@ notice_finished_file (struct file *file)
f->last_mtime = max_mtime;
}
if (ran && file->update_status != -1)
if (ran && file->update_status != us_none)
/* We actually tried to update FILE, which has
updated its also_make's as well (if it worked).
If it didn't work, it wouldn't work again for them.
@@ -968,10 +969,10 @@ notice_finished_file (struct file *file)
never be done because the target is already updated. */
f_mtime (d->file, 0);
}
else if (file->update_status == -1)
else if (file->update_status == us_none)
/* Nothing was done for FILE, but it needed nothing done.
So mark it now as "succeeded". */
file->update_status = 0;
file->update_status = us_success;
}
/* Check whether another file (whose mtime is THIS_MTIME) needs updating on
@@ -1112,11 +1113,12 @@ check_dep (struct file *file, unsigned int depth,
return dep_status;
}
/* Touch FILE. Return zero if successful, one if not. */
/* Touch FILE. Return us_success if successful, us_failed if not. */
#define TOUCH_ERROR(call) return (perror_with_name (call, file->name), 1)
#define TOUCH_ERROR(call) do{ perror_with_name ((call), file->name); \
return us_failed; }while(0)
static int
static enum update_status
touch_file (struct file *file)
{
if (!silent_flag)
@@ -1124,11 +1126,11 @@ touch_file (struct file *file)
/* Print-only (-n) takes precedence over touch (-t). */
if (just_print_flag)
return 0;
return us_success;
#ifndef NO_ARCHIVES
if (ar_name (file->name))
return ar_touch (file->name);
return ar_touch (file->name) ? us_failed : us_success;
else
#endif
{
@@ -1165,7 +1167,7 @@ touch_file (struct file *file)
}
}
return 0;
return us_success;
}
/* Having checked and updated the dependencies of FILE,
@@ -1179,17 +1181,17 @@ remake_file (struct file *file)
{
if (file->phony)
/* Phony target. Pretend it succeeded. */
file->update_status = 0;
file->update_status = us_success;
else if (file->is_target)
/* This is a nonexistent target file we cannot make.
Pretend it was successfully remade. */
file->update_status = 0;
file->update_status = us_success;
else
{
/* This is a dependency file we cannot remake. Fail. */
if (!rebuilding_makefiles || !file->dontcare)
complain (file);
file->update_status = 2;
file->update_status = us_failed;
}
}
else
@@ -1204,7 +1206,7 @@ remake_file (struct file *file)
}
/* This tells notice_finished_file it is ok to touch the file. */
file->update_status = 0;
file->update_status = us_success;
}
/* This does the touching under -t. */
@@ -1256,7 +1258,7 @@ f_mtime (struct file *file, int search)
arlen = strlen (arfile->hname);
memlen = strlen (memname);
name = xmalloc (arlen + 1 + memlen + 2);
name = alloca (arlen + 1 + memlen + 2);
memcpy (name, arfile->hname, arlen);
name[arlen] = '(';
memcpy (name + arlen + 1, memname, memlen);
@@ -1266,9 +1268,9 @@ f_mtime (struct file *file, int search)
/* If the archive was found with GPATH, make the change permanent;
otherwise defer it until later. */
if (arfile->name == arfile->hname)
rename_file (file, name);
rename_file (file, strcache_add (name));
else
rehash_file (file, name);
rehash_file (file, strcache_add (name));
check_renamed (file);
}
@@ -1400,7 +1402,6 @@ f_mtime (struct file *file, int search)
started. So, turn off the intermediate bit so make doesn't
delete it, since it didn't create it. */
if (mtime != NONEXISTENT_MTIME && file->command_state == cs_not_started
&& file->command_state == cs_not_started
&& !file->tried_implicit && file->intermediate)
file->intermediate = 0;

View File

@@ -19,7 +19,6 @@ 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 "job.h"
#include "filedef.h"
#include "commands.h"
#include "job.h"

4
rule.c
View File

@@ -18,8 +18,8 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include <assert.h>
#include "dep.h"
#include "filedef.h"
#include "dep.h"
#include "job.h"
#include "commands.h"
#include "variable.h"
@@ -373,7 +373,7 @@ install_pattern_rule (struct pspec *p, int terminal)
++r->suffixes[0];
ptr = p->dep;
r->deps = PARSE_FILE_SEQ (&ptr, struct dep, '\0', NULL, 0);
r->deps = PARSE_SIMPLE_SEQ (&ptr, struct dep);
if (new_pattern_rule (r, 0))
{

View File

@@ -244,7 +244,7 @@ strsignal (int sig)
# endif
#endif
if (sig > 0 || sig < NSIG)
if (sig > 0 && sig < NSIG)
return (char *) sys_siglist[sig];
sprintf (buf, "Signal %d", sig);

View File

@@ -1,3 +1,131 @@
2013-10-09 Paul Smith <psmith@gnu.org>
* scripts/features/patspecific_vars: Typo fixes.
2013-10-05 Paul Smith <psmith@gnu.org>
* test_driver.pl (run_all_tests): Rewrite to be more clear.
* scripts/features/jobserver: Avoid using $ENV{HOME} as it doesn't
exist everywhere.
* scripts/features/default_names: End with 1;
* scripts/features/loadapi: Use new calling signatures. Verify
the NOEXPAND flag works. Test with all valid function name
characters.
2013-09-29 Paul Smith <psmith@gnu.org>
* scripts/variables/SHELL: Solaris /bin/sh can't handle options in
multiple words; skip that test.
* scripts/targets/ONESHELL: Ditto.
* scripts/variables/GNUMAKEFLAGS: Verify that GNUMAKEFLAGS is
cleared and options are not duplicated.
2013-09-23 Paul Smith <psmith@gnu.org>
* scripts/options/print-directory: Rename dash-w to
print-directory to avoid conflicts with dash-W on case-insensitive
filesystems.
2013-09-22 Paul Smith <psmith@gnu.org>
* scripts/features/se_implicit: Verify that order-only tokens
inside second expansion are parsed correctly.
Test for Savannah bug #31155.
* run_make_tests.pl (set_more_defaults): If we can't find
gnumake.h based on the make program we might be running from a
remote build directory. Parse the Makefile for the right path.
Fix some test issues on Solaris.
* scripts/features/archives: Determine what output ar gives when
adding and replacing objects and compare with that.
* scripts/features/escape: Solaris /bin/sh doesn't properly handle
backslashes inside single quotes, so don't rely on it.
* scripts/features/output-sync: false(1) gives different exit
codes on different systems; use "exit 1" instead.
* scripts/features/parallelism: Increase the timeout for slower systems.
2013-09-21 Paul Smith <psmith@gnu.org>
* scripts/features/archives: Some versions of ar (MacOSX) generate
different output when creating archives. Run it and verify the
real output.
* scripts/features/default_names: MacOSX is, like Windows,
case-preserving / case-insensitive. Redo the test to avoid
checking for "UNIX".
* test_driver.pl (attach_default_output): Don't dup stdout into
stderr. Reported by Denis Excoffier <bug-tar@Denis-Excoffier.org>
* scripts/features/se_explicit: Fix a test that behaves
differently with/without archive capability enabled.
* scripts/features/output-sync: Don't test output-sync if it's not
enabled. We also skip it if parallelism is not enabled, although
strictly speaking some of the output-sync tests are valid even
without parallelism.
* scripts/features/jobserver: Move some tests that require the
jobserver from features/parallelism to a separate suite. Only run
this if jobserver mode is enabled.
* scripts/features/output-sync: Test shell functions writing to
stderr in recipes: ensure it's captured via output-sync. Test
output generated while reading makefiles and make sure it's
captured via output-sync. Make sure that fatal errors dump the
output so it's not lost.
* scripts/options/dash-w: Add a test for -w flag.
2013-09-15 Paul Smith <psmith@gnu.org>
* scripts/misc/fopen-fail: Check for failure on infinite recursion.
* run_make_tests.pl (run_make_test): Allow the answer string to be
undef, which means that we shouldn't compare it at all. Only the
exit code matters in this case.
* test_driver.pl (compare_output): Ditto.
Test for Savannah bug #27374.
* scripts/features/parallelism: Test broken jobserver on recursion.
Test for Savannah bug #39934.
* scripts/options/eval: Verify --eval during restart.
Test for Savannah bug #39203.
2013-09-14 Paul Smith <psmith@gnu.org>
* scripts/features/output-sync: Verify -Orecurse properly.
2013-09-12 Paul Smith <psmith@gnu.org>
* scripts/features/output-sync: Modify for output sync behavior.
* scripts/variables/MAKE_RESTARTS: Ditto.
* scripts/variables/MAKEFLAGS: Remove mode for --trace.
* scripts/variables/GNUMAKEFLAGS: Ditto.
2013-07-22 Paul Smith <psmith@gnu.org>
* scripts/features/rule_glob: Add tests for wildcards in rules.
Test for Savannah bug #39310.
2013-07-09 Paul Smith <psmith@gnu.org>
* scripts/features/se_implicit: Add a test for SE rules depending
on other SE rules to be built.
2013-05-26 Paul Smith <psmith@gnu.org>
* scripts/features/archives: Test for Savannah bug #38442.
* scripts/misc/bs-nl: Test for Savannah bug #39035.
Add a test for Savannah bug #38945.
2013-05-22 Paul Smith <psmith@gnu.org>
* scripts/options/dash-n: Fix results after MAKEFLAGS fixes.
* scripts/variables/MAKEFLAGS: Ditto.
* scripts/variables/GNUMAKEFLAGS: Ditto.
2013-05-14 Paul Smith <psmith@gnu.org>
* scripts/features/loadapi: Add plugin_is_GPL_compatible symbol.

View File

@@ -148,8 +148,10 @@ sub run_make_test
}
# Do the same processing on $answer as we did on $makestring.
$answer && $answer !~ /\n$/s and $answer .= "\n";
$answer = subst_make_string($answer);
if (defined $answer) {
$answer && $answer !~ /\n$/s and $answer .= "\n";
$answer = subst_make_string($answer);
}
run_make_with_options($makefile, $options, &get_logfile(0),
$err_code, $timeout);
@@ -367,6 +369,15 @@ sub set_more_defaults
-f "${d}gnumake.h" and $srcdir = $d;
}
# Not with the make program, so see if we can get it out of the makefile
if (! $srcdir && open(MF, "< ../Makefile")) {
local $/ = undef;
$_ = <MF>;
close(MF);
/^abs_srcdir\s*=\s*(.*?)\s*$/m;
-f "$1/gnumake.h" and $srcdir = $1;
}
# Get Purify log info--if any.
if (exists $ENV{PURIFYOPTIONS}

View File

@@ -11,17 +11,32 @@ exists $FEATURES{archives} or return -1;
# Create some .o files to work with
utouch(-60, qw(a1.o a2.o a3.o));
# Some versions of ar print different things on creation. Find out.
my $created = `ar rv libxx.a a1.o 2>&1`;
# Some versions of ar print different things on add. Find out.
my $add = `ar rv libxx.a a2.o 2>&1`;
$add =~ s/a2\.o/#OBJECT#/g;
# Some versions of ar print different things on replacement. Find out.
my $repl = `ar rv libxx.a a2.o 2>&1`;
$repl =~ s/a2\.o/#OBJECT#/g;
unlink('libxx.a');
# Very simple
run_make_test('all: libxx.a(a1.o)',
'', "ar rv libxx.a a1.o\nar: creating libxx.a\na - a1.o\n");
'', "ar rv libxx.a a1.o\n$created");
# Multiple .o's. Add a new one to the existing library
($_ = $add) =~ s/#OBJECT#/a2.o/g;
run_make_test('all: libxx.a(a1.o a2.o)',
'', "ar rv libxx.a a2.o\na - a2.o\n");
'', "ar rv libxx.a a2.o\n$_");
# Touch one of the .o's so it's rebuilt
utouch(-40, 'a1.o');
run_make_test(undef, '', "ar rv libxx.a a1.o\nr - a1.o\n");
($_ = $repl) =~ s/#OBJECT#/a1.o/g;
run_make_test(undef, '', "ar rv libxx.a a1.o\n$_");
# Use wildcards
run_make_test('all: libxx.a(*.o)',
@@ -29,17 +44,22 @@ run_make_test('all: libxx.a(*.o)',
# Touch one of the .o's so it's rebuilt
utouch(-30, 'a1.o');
run_make_test(undef, '', "ar rv libxx.a a1.o\nr - a1.o\n");
($_ = $repl) =~ s/#OBJECT#/a1.o/g;
run_make_test(undef, '', "ar rv libxx.a a1.o\n$_");
# Use both wildcards and simple names
utouch(-50, 'a2.o');
($_ = $add) =~ s/#OBJECT#/a3.o/g;
$_ .= "ar rv libxx.a a2.o\n";
($_ .= $repl) =~ s/#OBJECT#/a2.o/g;
run_make_test('all: libxx.a(a3.o *.o)', '',
"ar rv libxx.a a3.o\na - a3.o\nar rv libxx.a a2.o\nr - a2.o\n");
"ar rv libxx.a a3.o\n$_");
# Check whitespace handling
utouch(-40, 'a2.o');
($_ = $repl) =~ s/#OBJECT#/a2.o/g;
run_make_test('all: libxx.a( a3.o *.o )', '',
"ar rv libxx.a a2.o\nr - a2.o\n");
"ar rv libxx.a a2.o\n$_");
rmfiles(qw(a1.o a2.o a3.o libxx.a));
@@ -51,5 +71,25 @@ foo(bar).baz: ; @echo '$@'
!,
'', "foo(bar).baz\n");
# Check renaming of archive targets.
# See Savannah bug #38442
mkdir('artest', 0777);
touch('foo.vhd');
run_make_test(q!
DIR = artest
vpath % $(DIR)
default: lib(foo)
(%): %.vhd ; @cd $(DIR) && touch $(*F) && $(AR) $(ARFLAGS) $@ $(*F) >/dev/null 2>&1 && rm $(*F)
.PHONY: default
!,
'', "");
run_make_test(undef, '', "#MAKE#: Nothing to be done for 'default'.\n");
unlink('foo.vhd');
remove_directory_tree('artest');
# This tells the test driver that the perl test script executed properly.
1;

View File

@@ -10,32 +10,35 @@ open(MAKEFILE,"> $makefile");
print MAKEFILE "FIRST: ; \@echo It chose GNUmakefile\n";
close(MAKEFILE);
# DOS/WIN32 platforms preserve case, but Makefile is the same file as makefile.
# Just test what we can here (avoid Makefile versus makefile test).
if ($port_type eq 'UNIX') {
# Create another makefile called "makefile"
open(MAKEFILE,"> makefile");
print MAKEFILE "SECOND: ; \@echo It chose makefile\n";
close(MAKEFILE);
}
# Create another makefile called "Makefile"
open(MAKEFILE,"> Makefile");
print MAKEFILE "THIRD: ; \@echo It chose Makefile\n";
# Create another makefile called "makefile"
open(MAKEFILE,"> makefile");
print MAKEFILE "SECOND: ; \@echo It chose makefile\n";
close(MAKEFILE);
# DOS/WIN32/MacOSX platforms are case-insensitive / case-preserving, so
# Makefile is the same file as makefile. Just test what we can here.
&run_make_with_options("","",&get_logfile);
&compare_output("It chose GNUmakefile\n",&get_logfile(1));
unlink $makefile;
if ($port_type eq 'UNIX') {
&run_make_with_options("","",&get_logfile);
&compare_output("It chose makefile\n",&get_logfile(1));
unlink "makefile";
my $case_sensitive = 0;
if (! -f 'Makefile') {
# Create another makefile called "Makefile"
$case_sensitive = 1;
open(MAKEFILE,"> Makefile");
print MAKEFILE "THIRD: ; \@echo It chose Makefile\n";
close(MAKEFILE);
}
&run_make_with_options("","",&get_logfile);
&compare_output("It chose Makefile\n",&get_logfile(1));
unlink "Makefile";
run_make_with_options("","",&get_logfile);
compare_output("It chose GNUmakefile\n",&get_logfile(1));
unlink($makefile);
run_make_with_options("","",&get_logfile);
compare_output("It chose makefile\n",&get_logfile(1));
unlink("makefile");
if ($case_sensitive) {
run_make_with_options("","",&get_logfile);
compare_output("It chose Makefile\n",&get_logfile(1));
unlink("Makefile");
}
1;

View File

@@ -54,19 +54,21 @@ run_make_test(undef,
# Test escaped colons in prerequisites
# Quoting of backslashes in q!! is kind of messy.
# Solaris sh does not properly handle backslashes even in '' so just
# check the output make prints, not what the shell interprets.
run_make_test(q!
foo: foo\\:bar foo\\\\\\:bar foo\\\\\\\\\\:bar
foo foo\\:bar foo\\\\\\:bar foo\\\\\\\\\\:bar: ; @echo '$@'
foo foo\\:bar foo\\\\\\:bar foo\\\\\\\\\\:bar: ; : '$@'
!,
'', "foo:bar\nfoo\\:bar\nfoo\\\\:bar\nfoo\n");
'', ": 'foo:bar'\n: 'foo\\:bar'\n: 'foo\\\\:bar'\n: 'foo'\n");
# Test backslash before non-special chars: should be kept as-is
run_make_test(q!
all: ..\foo
.DEFAULT: ; @echo '$@'
.DEFAULT: ; : '$@'
!,
'', '..\foo');
'', ": '..\\foo'\n");
# This tells the test driver that the perl test script executed properly.
1;

View File

@@ -0,0 +1,61 @@
# -*-perl-*-
$description = "Test jobserver.";
$details = "These tests are ones that specifically are different when the
jobserver feature is available. Most -j tests are the same whether or not
jobserver is available, and those appear in the 'parallelism' test suite.";
exists $FEATURES{'jobserver'} or return -1;
if (!$parallel_jobs) {
return -1;
}
# Don't put --jobserver-fds into a re-exec'd MAKEFLAGS.
# We can't test this directly because there's no way a makefile can
# show the value of MAKEFLAGS we were re-exec'd with. We can intuit it
# by looking for "disabling jobserver mode" warnings; we should only
# get one from the original invocation and none from the re-exec.
# See Savannah bug #18124
unlink('inc.mk');
run_make_test(q!
-include inc.mk
recur:
# @echo 'MAKEFLAGS = $(MAKEFLAGS)'
@rm -f inc.mk
@$(MAKE) -j2 -f #MAKEFILE# all
all:
# @echo 'MAKEFLAGS = $(MAKEFLAGS)'
@echo $@
inc.mk:
# @echo 'MAKEFLAGS = $(MAKEFLAGS)'
@echo 'FOO = bar' > $@
!,
'--no-print-directory -j2', "#MAKE#[1]: warning: -jN forced in submake: disabling jobserver mode.\nall\n");
unlink('inc.mk');
# Test recursion when make doesn't think it exists.
# See Savannah bug #39934
# Or Red Hat bug https://bugzilla.redhat.com/show_bug.cgi?id=885474
open(MAKEFILE,"> Makefile2");
print MAKEFILE '
vpath %.c ../
foo:
';
close(MAKEFILE);
run_make_test(q!
default: ; @ #MAKEPATH# -f Makefile2
!,
'-j2 --no-print-directory',
"#MAKE#[1]: warning: jobserver unavailable: using -j1. Add '+' to parent make rule.
#MAKE#[1]: Nothing to be done for 'foo'.");
rmfiles('Makefile2');
1;

View File

@@ -36,7 +36,15 @@ test_expand (const char *val)
}
static char *
func_test (const char *funcname, int argc, char **argv)
test_noexpand (const char *val)
{
char *str = gmk_alloc (strlen (val));
strcpy (str, val);
return str;
}
static char *
func_test (const char *funcname, unsigned int argc, char **argv)
{
char *mem;
@@ -46,7 +54,10 @@ func_test (const char *funcname, int argc, char **argv)
if (strcmp (funcname, "test-eval") == 0)
return test_eval (argv[0]);
mem = gmk_alloc (strlen ("unknown") + 1);
if (strcmp (funcname, "test-noexpand") == 0)
return test_noexpand (argv[0]);
mem = gmk_alloc (sizeof ("unknown"));
strcpy (mem, "unknown");
return mem;
}
@@ -54,8 +65,10 @@ func_test (const char *funcname, int argc, char **argv)
int
testapi_gmk_setup ()
{
gmk_add_function ("test-expand", func_test, 1, 1, 1);
gmk_add_function ("test-eval", func_test, 1, 1, 1);
gmk_add_function ("test-expand", func_test, 1, 1, GMK_FUNC_DEFAULT);
gmk_add_function ("test-noexpand", func_test, 1, 1, GMK_FUNC_NOEXPAND);
gmk_add_function ("test-eval", func_test, 1, 1, GMK_FUNC_DEFAULT);
gmk_add_function ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.", func_test, 0, 0, 0);
return 1;
}
EOF
@@ -84,6 +97,15 @@ all:;@echo '$(VAR)'
!,
'', "hi there\n");
# TEST 2
# Check the no-expand capability
run_make_test(q!
load testapi.so
TEST = hi
all:;@echo '$(test-noexpand $(TEST))'
!,
'', "\$(TEST)\n");
unlink(qw(testapi.c testapi.so)) unless $keep;
# This tells the test driver that the perl test script executed properly.

View File

@@ -4,9 +4,12 @@ $description = "Test --output-sync (-O) option.";
$details = "Test the synchronization of output from parallel jobs.";
if (!$parallel_jobs) {
return -1;
}
# If we don't have output sync support, never mind.
exists $FEATURES{'output-sync'} or return -1;
# Output sync can't be tested without parallelization
$parallel_jobs or return -1;
if ($vos) {
$sleep_command = "sleep -seconds";
@@ -88,7 +91,7 @@ foo-fail:
\t\@echo foo-fail: start
\t\@$wait_bar
\t\@echo foo-fail: end
\t\@false
\t\@exit 1
EOF
close(MAKEFILE);
@@ -146,6 +149,9 @@ baz: end
unlink(@syncfiles);
run_make_test(qq!
x=1
\$xMAKEFLAGS += --no-print-directory
all: make-foo make-bar
make-foo: ; \$(MAKE) -C foo
@@ -157,14 +163,28 @@ $sleep_command 1 ; #MAKEPATH# -C bar
#MAKE#[1]: Entering directory '#PWD#/bar'
bar: start
bar: end
#MAKE#[1]: Leaving directory '#PWD#/bar'
#MAKE#[1]: Entering directory '#PWD#/foo'
foo: start
foo: end
#MAKE#[1]: Leaving directory '#PWD#/foo'
#MAKE#[1]: Entering directory '#PWD#/bar'
baz: start
baz: end
#MAKE#[1]: Leaving directory '#PWD#/bar'\n", 0, 6);
# Rerun but this time suppress the directory tracking
unlink(@syncfiles);
run_make_test(undef, '-j --output-sync=target x=',
"#MAKEPATH# -C foo
$sleep_command 1 ; #MAKEPATH# -C bar
bar: start
bar: end
foo: start
foo: end
baz: start
baz: end\n", 0, 6);
# Test that messages from make itself are enclosed with
# "Entering/Leaving directory" messages.
unlink(@syncfiles);
@@ -209,10 +229,14 @@ make-bar: ; $sleep_command 1 ; \$(MAKE) -C bar bar-job!,
$sleep_command 1 ; #MAKEPATH# -C bar bar-job
#MAKE#[1]: Entering directory '#PWD#/foo'
foo: start
#MAKE#[1]: Leaving directory '#PWD#/foo'
#MAKE#[1]: Entering directory '#PWD#/bar'
bar: start
#MAKE#[1]: Leaving directory '#PWD#/bar'
#MAKE#[1]: Entering directory '#PWD#/bar'
bar: end
#MAKE#[1]: Leaving directory '#PWD#/bar'
#MAKE#[1]: Entering directory '#PWD#/foo'
foo: end
#MAKE#[1]: Leaving directory '#PWD#/foo'\n", 0, 6);
@@ -240,5 +264,71 @@ all:
run_make_test(undef, '-j -Otarget', "foobar\ntrue\n");
# Ensure that shell functions inside recipes write stderr to the sync file
run_make_test(q!
all: ; @: $(shell echo foo 1>&2)
!,
'-w -Oline', "#MAKE#: Entering directory '#PWD#'\nfoo\n#MAKE#: Leaving directory '#PWD#'\n");
# Ensure that output generated while parsing makefiles is synced
# when appropriate.
run_make_test(q!
$(shell echo foo 1>&2)
all: ; echo bar
!,
'-s -w -Otarget', "#MAKE#: Entering directory '#PWD#'\nfoo\n#MAKE#: Leaving directory '#PWD#'\n#MAKE#: Entering directory '#PWD#'\nbar\n#MAKE#: Leaving directory '#PWD#'\n");
# Test recursion
$m1 = get_tmpfile();
$m2 = get_tmpfile();
open(M1, "> $m1");
print M1 <<'EOF';
$(shell echo d1 stderr 1>&2)
$(info d1 stdout)
all:; @:
EOF
close(M1);
open(M2, "> $m2");
print M2 <<'EOF';
$(shell echo d2 stderr 1>&2)
$(info d2 stdout)
all:; @:
# Force an ordering on the output
$(shell sleep 1)
EOF
close(M2);
run_make_test(qq!
all: t1 t2
t1: ; \@\$(MAKE) -f $m1
t2: ; \@\$(MAKE) -f $m2
!,
"-j -Oline", "#MAKE#[1]: Entering directory '#PWD#'\nd1 stderr\nd1 stdout\n#MAKE#[1]: Leaving directory '#PWD#'\n#MAKE#[1]: Entering directory '#PWD#'\nd2 stderr\nd2 stdout\n#MAKE#[1]: Leaving directory '#PWD#'\n");
rmfiles($m1, $m2);
# Ensure that output generated while parsing makefiles is synced
# when appropriate.
$m1 = get_tmpfile();
open(M1, "> $m1");
print M1 <<'EOF';
$(shell echo d1 stderr 1>&2)
$(info d1 stdout)
$(error d1 failed)
all:; @:
EOF
close(M1);
run_make_test(qq!
all: t1
t1: ; -\@\$(MAKE) -f $m1
!,
"-j -Oline", "#MAKE#[1]: Entering directory '#PWD#'\nd1 stderr\nd1 stdout\n$m1:3: *** d1 failed. Stop.\n#MAKE#[1]: Leaving directory '#PWD#'\n#MAKEFILE#:3: recipe for target 't1' failed\n#MAKE#: [t1] Error 2 (ignored)\n");
rmfiles($m1);
# This tells the test driver that the perl test script executed properly.
1;

View File

@@ -41,7 +41,7 @@ all: 1 2; \@echo success
1.inc: ; \@echo ONE.inc; $sleep_command 2; echo TWO.inc; echo '1: ; \@echo ONE; $sleep_command 2; echo TWO' > \$\@
2.inc: ; \@$sleep_command 1; echo THREE.inc; echo '2: ; \@$sleep_command 1; echo THREE' > \$\@",
"-j4",
"ONE.inc\nTHREE.inc\nTWO.inc\nONE\nTHREE\nTWO\nsuccess\n");
"ONE.inc\nTHREE.inc\nTWO.inc\nONE\nTHREE\nTWO\nsuccess\n", 0, 7);
rmfiles(qw(1.inc 2.inc));
@@ -60,7 +60,7 @@ endif
1.inc: ; \@echo ONE.inc; $sleep_command 2; echo TWO.inc; echo '1: ; \@echo ONE; $sleep_command 2; echo TWO' > \$\@
2.inc: ; \@$sleep_command 1; echo THREE.inc; echo '2: ; \@$sleep_command 1; echo THREE' > \$\@",
"-j4",
"ONE.inc\nTHREE.inc\nTWO.inc\nONE\nTHREE\nTWO\nsuccess\n");
"ONE.inc\nTHREE.inc\nTWO.inc\nONE\nTHREE\nTWO\nsuccess\n", 0, 7);
rmfiles(qw(1.inc 2.inc));
@@ -143,30 +143,6 @@ intermed: | phony ; touch $@
phony: ; : phony', '-rR -j', ': phony');
rmfiles('target');
# TEST #10: Don't put --jobserver-fds into a re-exec'd MAKEFLAGS.
# We can't test this directly because there's no way a makefile can
# show the value of MAKEFLAGS we were re-exec'd with. We can intuit it
# by looking for "disabling jobserver mode" warnings; we should only
# get one from the original invocation and none from the re-exec.
# See Savannah bug #18124
run_make_test(q!
-include inc.mk
recur:
# @echo 'MAKEFLAGS = $(MAKEFLAGS)'
@rm -f inc.mk
@$(MAKE) -j2 -f #MAKEFILE# all
all:
# @echo 'MAKEFLAGS = $(MAKEFLAGS)'
@echo $@
inc.mk:
# @echo 'MAKEFLAGS = $(MAKEFLAGS)'
@echo 'FOO = bar' > $@
!,
'--no-print-directory -j2', "#MAKE#[1]: warning: -jN forced in submake: disabling jobserver mode.\nall\n");
rmfiles('inc.mk');
# TEST #11: Make sure -jN from MAKEFLAGS is processed even when we re-exec
# See Savannah bug #33873
@@ -185,36 +161,6 @@ inc.mk: ; @touch $@
delete $extraENV{MAKEFLAGS};
rmfiles('inc.mk');
if ($all_tests) {
# Implicit files aren't properly recreated during parallel builds
# Savannah bug #26864
# The first run works fine
run_make_test(q!
%.bar: %.x foo.y ; cat $^ > $@
%.x: ; touch $@
foo.y: foo.y.in ; cp $< $@
foo.y.in: ; touch $@
!,
'-j2 main.bar',
"touch foo.y.in
touch main.x
cp foo.y.in foo.y
cat main.x foo.y > main.bar
rm main.x");
# Now we touch the .in file and make sure it still works
touch('foo.y.in');
run_make_test(undef, '-j2 main.bar', "cp foo.y.in foo.y
touch main.x
cat main.x foo.y > main.bar
rm main.x");
# Clean up
rmfiles(qw(foo.y foo.y.in main.bar));
}
# Ensure intermediate/secondary files are not pruned incorrectly.
# See Savannah bug #30653
@@ -232,28 +178,6 @@ file2: file1 ; @touch $@
rmfiles('file1', 'file2', 'file3', 'file4');
if ($all_tests) {
# Jobserver FD handling is messed up in some way.
# Savannah bug #28189
# It doesn't look like that bug anymore but this is the code it runs
run_make_test(q!
ifdef EXTRA
vpath %.dst /
xxx.dst: ; true
yyy.dst: ; true
endif
M := $(MAKE)
xx: ; $M --no-print-directory -j2 -f $(MAKEFILE_LIST) xxx.dst yyy.dst EXTRA=1
!,
'-j2',
'#MAKE#[1]: warning: -jN forced in submake: disabling jobserver mode.
true
true
');
}
# Make sure that all jobserver FDs are closed if we need to re-exec the
# master copy.
#

View File

@@ -81,7 +81,7 @@ all: bar baz
b%: pattern := good $$t
global := orginal $$t
global := original $$t
# normal target
@@ -103,14 +103,14 @@ else
%z: a := global: $(global) pattern: $(pattern) inherit: $(inherit)
endif
%z: ; @echo \'pattrn: $a;\'
%z: ; @echo \'pattern: $a;\'
global := new $$t
',
'',
'normal: global: orginal $t pattern: inherit: ;
pattrn: global: orginal $t pattern: inherit: ;');
'normal: global: original $t pattern: inherit: ;
pattern: global: original $t pattern: inherit: ;');
# TEST #7 -- test expansion of pattern-specific recursive variables
@@ -118,7 +118,7 @@ pattrn: global: orginal $t pattern: inherit: ;');
run_make_test(undef, # reuse previous makefile
'rec=1',
'normal: global: new $t pattern: good $t inherit: good $t;
pattrn: global: new $t pattern: good $t inherit: good $t;');
pattern: global: new $t pattern: good $t inherit: good $t;');
# TEST #8: override in pattern-specific variables

View File

@@ -0,0 +1,37 @@
# -*-perl-*-
$description = "Test globbing in targets and prerequisites.";
$details = "";
touch(qw(a.one a.two a.three));
# Test wildcards in regular targets and prerequisites
run_make_test(q{
.PHONY: all a.one a.two a.three
all: a.one* a.t[a-z0-9]o a.th[!q]ee
a.o[Nn][Ee] a.t*: ; @echo $@
},
'', "a.one\na.two\na.three");
# Test wildcards in pattern targets and prerequisites
run_make_test(q{
.PHONY: all
all: a.four
%.four : %.t* ; @echo $@: $(sort $^)
},
'', "a.four: a.three a.two");
# Test wildcards in second expansion targets and prerequisites
run_make_test(q{
.PHONY: all
all: a.four
.SECONDEXPANSION:
%.four : $$(sort %.t*) ; @echo $@: $(sort $^)
},
'', "a.four: a.three a.two");
unlink(qw(a.one a.two a.three));
# This tells the test driver that the perl test script executed properly.
1;

View File

@@ -6,6 +6,9 @@ $details = "";
# TEST #0: Test handing of '$' in prerequisites with and without second
# expansion.
# If we don't support archives then the prerequisite is different
my $prereq = exists $FEATURES{'archives'} ? '$' : '$(PRE)';
run_make_test(q!
ifdef SE
.SECONDEXPANSION:
@@ -18,7 +21,7 @@ PRE = three four
.DEFAULT: ; @echo '$@'
!,
'',
"\$\nbar\$biz\nfoo\$bar : bar\$baz bar\$biz");
"$prereq\nbar\$biz\nfoo\$bar : bar\$baz bar\$biz");
run_make_test(undef, 'SE=1', "three\nfour\nbariz\nfoo\$bar : baraz bariz");

View File

@@ -222,5 +222,39 @@ foo.o:
!,
'', "\n");
# Test #10: Test second expansion with second expansion prerequisites
# Ensures pattern_search() recurses with SE prereqs.
touch('a');
run_make_test(q!
.SECONDEXPANSION:
sim_base_rgg := just_a_name
sim_base_src := a
sim_base_f := a a a
sim_%.f: $${sim_$$*_f}
echo $@
sim_%.src: $${sim_$$*_src}
echo $@
sim_%: \
$$(if $$(sim_$$*_src),sim_%.src) \
$$(if $$(sim_$$*_f),sim_%.f) \
$$(if $$(sim_$$*_rgg),$$(sim_$$*_rgg).s)
echo $@
!,
'-s sim_base', "#MAKE#: *** No rule to make target 'sim_base'. Stop.", 512);
unlink('a');
# Ensure that order-only tokens embedded in second expansions are parsed
run_make_test(q!
.SECONDEXPANSION:
PREREQS=p1|p2
P2=p2
all : foo bar
f%o: $$(PREREQS) ; @echo '$@' from '$^' and '$|'
b%r: p1|$$(P2) ; @echo '$@' from '$^' and '$|'
p% : ; : $@
!,
"", ": p1\n: p2\nfoo from p1 and p2\nbar from p1 and p2\n");
# This tells the test driver that the perl test script executed properly.
1;

View File

@@ -99,4 +99,31 @@ var = he\
var:;@echo '|$(var)|'!,
'', "|he llo|");
# Savannah #39035: handle whitespace in call
run_make_test(q!
f = echo $(1)
t:; @$(call f,"a \
b"); \
$(call f,"a \
b")
!,
'', "a b\na b\n");
# Savannah #38945: handle backslash CRLF
# We need our own makefile so we can set binmode
my $m1 = get_tmpfile();
open(MAKEFILE, "> $m1");
binmode(MAKEFILE);
print MAKEFILE "FOO = foo \\\r\n";
close(MAKEFILE);
my $m2 = get_tmpfile();
open(MAKEFILE, "> $m2");
print MAKEFILE "include $m1\ndefine BAR\nall: ; \@echo \$(FOO) bar\nendef\n\$(eval \$(BAR))\n";
close(MAKEFILE);
run_make_with_options($m2, '', get_logfile());
compare_output("foo bar\n", get_logfile(1));
1;

View File

@@ -0,0 +1,15 @@
# -*-perl-*-
$description = "Make sure make exits with an error if fopen fails.";
# Recurse infinitely until we run out of open files, and ensure we
# fail with a non-zero exit code. Don't bother to test the output
# since it's hard to know what it will be, exactly.
# See Savannah bug #27374.
run_make_test(q!
include $(lastword $(MAKEFILE_LIST))
!,
'', undef, 512);
1;

View File

@@ -92,7 +92,7 @@ EOF
close(MAKEFILE);
&run_make_with_options($topmake, '-n --no-print-directory', &get_logfile);
$answer = "$make_path -f \"$submake\" bar\ntouch inc\necho --no-print-directory -n\n";
$answer = "$make_path -f \"$submake\" bar\ntouch inc\necho n --no-print-directory\n";
&compare_output($answer, &get_logfile(1));
unlink('inc');

View File

@@ -16,4 +16,14 @@ recurse: ; @$(MAKE) -f #MAKEFILE# && echo recurse!,
run_make_test(undef, '--no-print-directory --eval=\$\(info\ eval\) recurse',
"eval\neval\nall\nrecurse");
# Make sure that --eval is handled correctly during restarting
run_make_test(q!
all: ; @echo $@
-include gen.mk
gen.mk: ; @echo > $@
!,
'--eval=\$\(info\ eval\)', "eval\neval\nall");
unlink('gen.mk');
1;

View File

@@ -0,0 +1,33 @@
# -*-perl-*-
$description = "Test the -w option to GNU make.";
# Simple test without -w
run_make_test(q!
all: ; @echo hi
!,
"", "hi\n");
# Simple test with -w
run_make_test(undef, "-w",
"#MAKE#: Entering directory '#PWD#'\nhi\n#MAKE#: Leaving directory '#PWD#'\n");
# Test makefile rebuild to ensure no enter/leave
run_make_test(q!
include foo
all: ;@:
foo: ; touch foo
!,
"", "#MAKEFILE#:2: foo: No such file or directory\ntouch foo\n");
unlink('foo');
# Test makefile rebuild with -w
run_make_test(q!
include foo
all: ;@:
foo: ; touch foo
!,
"-w", "#MAKE#: Entering directory '#PWD#'\n#MAKEFILE#:2: foo: No such file or directory\ntouch foo\n#MAKE#: Leaving directory '#PWD#'\n");
unlink('foo');
1;

View File

@@ -4,6 +4,10 @@ $description = "Test the behaviour of the .ONESHELL target.";
$details = "";
# Some shells (*shakes fist at Solaris*) cannot handle multiple flags in
# separate arguments.
my $t = `/bin/sh -e -c true 2>/dev/null`;
my $multi_ok = $? == 0;
# Simple
@@ -19,7 +23,8 @@ all:
# Simple but use multi-word SHELLFLAGS
run_make_test(q!
if ($multi_ok) {
run_make_test(q!
.ONESHELL:
.SHELLFLAGS = -e -c
all:
@@ -29,6 +34,7 @@ all:
'', 'a=$$
[ 0"$a" -eq "$$" ] || echo fail
');
}
# Again, but this time with inner prefix chars

View File

@@ -10,15 +10,33 @@ $extraENV{'GNUMAKEFLAGS'} = '-e -r -R';
run_make_test(q!
all: ; @echo $(MAKEFLAGS)
!,
'', 'Rre');
'', 'erR');
# Long arguments mean everything is prefixed with "-"
$extraENV{'GNUMAKEFLAGS'} = '--no-print-directory -e -r -R --trace=none --trace=dir';
$extraENV{'GNUMAKEFLAGS'} = '--no-print-directory -e -r -R --trace';
run_make_test(q!
all: ; @echo $(MAKEFLAGS)
!,
'', '--no-print-directory --trace=none --trace=dir --trace=none --trace=dir -Rre');
'', "#MAKEFILE#:2: target 'all' does not exist
echo erR --trace --no-print-directory
erR --trace --no-print-directory");
# Verify that re-exec / recursion doesn't duplicate flags from GNUMAKEFLAGS
unlink('x.mk');
$extraENV{GNUMAKEFLAGS} = '-Itst/bad -Oline';
run_make_test(q!
recurse: ; @echo $@; echo MAKEFLAGS = $$MAKEFLAGS; echo GNUMAKEFLAGS = $$GNUMAKEFLAGS; #MAKEPATH# -f #MAKEFILE# all
all: ; @echo $@; echo MAKEFLAGS = $$MAKEFLAGS; echo GNUMAKEFLAGS = $$GNUMAKEFLAGS
-include x.mk
x.mk: ; @echo $@; echo MAKEFLAGS = $$MAKEFLAGS; echo GNUMAKEFLAGS = $$GNUMAKEFLAGS; echo > $@
!,
"", "x.mk\nMAKEFLAGS = -Itst/bad -Oline\nGNUMAKEFLAGS =\nrecurse\nMAKEFLAGS = -Itst/bad -Oline\nGNUMAKEFLAGS =\n#MAKE#[1]: Entering directory '#PWD#'\nall\nMAKEFLAGS = w -Itst/bad -Oline\nGNUMAKEFLAGS =\n#MAKE#[1]: Leaving directory '#PWD#'\n");
unlink('x.mk');
1;

View File

@@ -8,13 +8,15 @@ $details = "DETAILS";
run_make_test(q!
all: ; @echo $(MAKEFLAGS)
!,
'-e -r -R', 'Rre');
'-e -r -R', 'erR');
# Long arguments mean everything is prefixed with "-"
run_make_test(q!
all: ; @echo $(MAKEFLAGS)
!,
'--no-print-directory -e -r -R --trace=none --trace=dir', '--no-print-directory --trace=none --trace=dir -Rre');
'--no-print-directory -e -r -R --trace', "#MAKEFILE#:2: target 'all' does not exist
echo erR --trace --no-print-directory
erR --trace --no-print-directory");
# Recursive invocations of make should accumulate MAKEFLAGS values.
@@ -32,8 +34,8 @@ print:
.PHONY: all jump print
!,
'--no-print-directory',
'all: MAKEFLAGS=--no-print-directory
jump Works: MAKEFLAGS=--no-print-directory -e
print Works: MAKEFLAGS=--no-print-directory -e');
'all: MAKEFLAGS= --no-print-directory
jump Works: MAKEFLAGS=e --no-print-directory
print Works: MAKEFLAGS=e --no-print-directory');
1;

View File

@@ -52,8 +52,8 @@ MAKE_RESTARTS=1
foo.x:1: bar.x: No such file or directory
MAKE_RESTARTS=2
recurse MAKE_RESTARTS=
MAKE_RESTARTS=
#MAKE#[1]: Entering directory '#PWD#'
MAKE_RESTARTS=
all MAKE_RESTARTS=
#MAKE#[1]: Leaving directory '#PWD#'");

View File

@@ -71,12 +71,20 @@ all: ; \@$script
'', $out);
# Do it again but add spaces to SHELLFLAGS
$flags = '-x -c';
run_make_test(qq!
# Some shells (*shakes fist at Solaris*) cannot handle multiple flags in
# separate arguments.
my $t = `/bin/sh -e -c true 2>/dev/null`;
my $multi_ok = $? == 0;
if ($multi_ok) {
$flags = '-x -c';
run_make_test(qq!
.SHELLFLAGS = $flags
all: ; \@$script
!,
'', $out);
}
# We can't just use "false" because on different systems it provides a
# different exit code--once again Solaris: false exits with 255 not 1

View File

@@ -202,7 +202,7 @@ sub toplevel
print "\n";
&run_each_test;
run_all_tests();
foreach $dir (@rmdirs)
{
@@ -220,7 +220,7 @@ sub toplevel
print "s" unless $total_tests_failed == 1;
print " in $categories_failed Categor";
print ($categories_failed == 1 ? "y" : "ies");
print " Failed (See .$diffext files in $workdir dir for details) :-(\n\n";
print " Failed (See .$diffext* files in $workdir dir for details) :-(\n\n";
return 0;
}
else
@@ -415,128 +415,133 @@ sub print_banner
print "\n";
}
sub run_each_test
sub run_all_tests
{
$categories_run = 0;
$categories_run = 0;
foreach $testname (sort @TESTS)
{
++$categories_run;
$suite_passed = 1; # reset by test on failure
$num_of_logfiles = 0;
$num_of_tmpfiles = 0;
$description = "";
$details = "";
$old_makefile = undef;
$testname =~ s/^$scriptpath$pathsep//;
$perl_testname = "$scriptpath$pathsep$testname";
$testname =~ s/(\.pl|\.perl)$//;
$testpath = "$workpath$pathsep$testname";
# Leave enough space in the extensions to append a number, even
# though it needs to fit into 8+3 limits.
if ($short_filenames) {
$logext = 'l';
$diffext = 'd';
$baseext = 'b';
$runext = 'r';
$extext = '';
} else {
$logext = 'log';
$diffext = 'diff';
$baseext = 'base';
$runext = 'run';
$extext = '.';
foreach $testname (sort @TESTS) {
$suite_passed = 1; # reset by test on failure
$num_of_logfiles = 0;
$num_of_tmpfiles = 0;
$description = "";
$details = "";
$old_makefile = undef;
$testname =~ s/^$scriptpath$pathsep//;
$perl_testname = "$scriptpath$pathsep$testname";
$testname =~ s/(\.pl|\.perl)$//;
$testpath = "$workpath$pathsep$testname";
# Leave enough space in the extensions to append a number, even
# though it needs to fit into 8+3 limits.
if ($short_filenames) {
$logext = 'l';
$diffext = 'd';
$baseext = 'b';
$runext = 'r';
$extext = '';
} else {
$logext = 'log';
$diffext = 'diff';
$baseext = 'base';
$runext = 'run';
$extext = '.';
}
$log_filename = "$testpath.$logext";
$diff_filename = "$testpath.$diffext";
$base_filename = "$testpath.$baseext";
$run_filename = "$testpath.$runext";
$tmp_filename = "$testpath.$tmpfilesuffix";
setup_for_test();
$output = "........................................................ ";
substr($output,0,length($testname)) = "$testname ";
print $output;
$tests_run = 0;
$tests_passed = 0;
# Run the test!
$code = do $perl_testname;
++$categories_run;
$total_tests_run += $tests_run;
$total_tests_passed += $tests_passed;
# How did it go?
if (!defined($code)) {
# Failed to parse or called die
if (length ($@)) {
warn "\n*** Test died ($testname): $@\n";
} else {
warn "\n*** Couldn't parse $perl_testname\n";
}
$status = "FAILED ($tests_passed/$tests_run passed)";
}
elsif ($code == -1) {
# Skipped... not supported
$status = "N/A";
--$categories_run;
}
elsif ($code != 1) {
# Bad result... this shouldn't really happen. Usually means that
# the suite forgot to end with "1;".
warn "\n*** Test returned $code\n";
$status = "FAILED ($tests_passed/$tests_run passed)";
}
elsif ($tests_run == 0) {
# Nothing was done!!
$status = "FAILED (no tests found!)";
}
elsif ($tests_run > $tests_passed) {
# Lose!
$status = "FAILED ($tests_passed/$tests_run passed)";
}
else {
# Win!
++$categories_passed;
$status = "ok ($tests_passed passed)";
# Clean up
for ($i = $num_of_tmpfiles; $i; $i--) {
rmfiles($tmp_filename . num_suffix($i));
}
for ($i = $num_of_logfiles ? $num_of_logfiles : 1; $i; $i--) {
rmfiles($log_filename . num_suffix($i));
rmfiles($base_filename . num_suffix($i));
}
}
# If the verbose option has been specified, then a short description
# of each test is printed before displaying the results of each test
# describing WHAT is being tested.
if ($verbose) {
if ($detail) {
print "\nWHAT IS BEING TESTED\n";
print "--------------------";
}
print "\n\n$description\n\n";
}
# If the detail option has been specified, then the details of HOW
# the test is testing what it says it is testing in the verbose output
# will be displayed here before the results of the test are displayed.
if ($detail) {
print "\nHOW IT IS TESTED\n";
print "----------------";
print "\n\n$details\n\n";
}
print "$status\n";
}
$log_filename = "$testpath.$logext";
$diff_filename = "$testpath.$diffext";
$base_filename = "$testpath.$baseext";
$run_filename = "$testpath.$runext";
$tmp_filename = "$testpath.$tmpfilesuffix";
&setup_for_test; # suite-defined
$output = "........................................................ ";
substr($output,0,length($testname)) = "$testname ";
print $output;
# Run the actual test!
$tests_run = 0;
$tests_passed = 0;
$code = do $perl_testname;
$total_tests_run += $tests_run;
$total_tests_passed += $tests_passed;
# How did it go?
if (!defined($code))
{
$suite_passed = 0;
if (length ($@)) {
warn "\n*** Test died ($testname): $@\n";
} else {
warn "\n*** Couldn't run $perl_testname\n";
}
}
elsif ($code == -1) {
$suite_passed = 0;
}
elsif ($code != 1 && $code != -1) {
$suite_passed = 0;
warn "\n*** Test returned $code\n";
}
if ($suite_passed) {
++$categories_passed;
$status = "ok ($tests_passed passed)";
for ($i = $num_of_tmpfiles; $i; $i--)
{
&rmfiles ($tmp_filename . &num_suffix ($i) );
}
for ($i = $num_of_logfiles ? $num_of_logfiles : 1; $i; $i--)
{
&rmfiles ($log_filename . &num_suffix ($i) );
&rmfiles ($base_filename . &num_suffix ($i) );
}
}
elsif (!defined $code || $code > 0) {
$status = "FAILED ($tests_passed/$tests_run passed)";
}
elsif ($code < 0) {
$status = "N/A";
--$categories_run;
}
# If the verbose option has been specified, then a short description
# of each test is printed before displaying the results of each test
# describing WHAT is being tested.
if ($verbose)
{
if ($detail)
{
print "\nWHAT IS BEING TESTED\n";
print "--------------------";
}
print "\n\n$description\n\n";
}
# If the detail option has been specified, then the details of HOW
# the test is testing what it says it is testing in the verbose output
# will be displayed here before the results of the test are displayed.
if ($detail)
{
print "\nHOW IT IS TESTED\n";
print "----------------";
print "\n\n$details\n\n";
}
print "$status\n";
}
}
# If the keep flag is not set, this subroutine deletes all filenames that
@@ -653,38 +658,43 @@ sub compare_output
local($answer,$logfile) = @_;
local($slurp, $answer_matched) = ('', 0);
print "Comparing Output ........ " if $debug;
$slurp = &read_file_into_string ($logfile);
# For make, get rid of any time skew error before comparing--too bad this
# has to go into the "generic" driver code :-/
$slurp =~ s/^.*modification time .*in the future.*\n//gm;
$slurp =~ s/^.*Clock skew detected.*\n//gm;
++$tests_run;
if ($slurp eq $answer) {
$answer_matched = 1;
if (! defined $answer) {
print "Ignoring output ........ " if $debug;
$answer_matched = 1;
} else {
# See if it is a slash or CRLF problem
local ($answer_mod, $slurp_mod) = ($answer, $slurp);
print "Comparing Output ........ " if $debug;
$answer_mod =~ tr,\\,/,;
$answer_mod =~ s,\r\n,\n,gs;
$slurp = &read_file_into_string ($logfile);
$slurp_mod =~ tr,\\,/,;
$slurp_mod =~ s,\r\n,\n,gs;
# For make, get rid of any time skew error before comparing--too bad this
# has to go into the "generic" driver code :-/
$slurp =~ s/^.*modification time .*in the future.*\n//gm;
$slurp =~ s/^.*Clock skew detected.*\n//gm;
$answer_matched = ($slurp_mod eq $answer_mod);
if ($slurp eq $answer) {
$answer_matched = 1;
} else {
# See if it is a slash or CRLF problem
local ($answer_mod, $slurp_mod) = ($answer, $slurp);
# If it still doesn't match, see if the answer might be a regex.
if (!$answer_matched && $answer =~ m,^/(.+)/$,) {
$answer_matched = ($slurp =~ /$1/);
if (!$answer_matched && $answer_mod =~ m,^/(.+)/$,) {
$answer_matched = ($slurp_mod =~ /$1/);
$answer_mod =~ tr,\\,/,;
$answer_mod =~ s,\r\n,\n,gs;
$slurp_mod =~ tr,\\,/,;
$slurp_mod =~ s,\r\n,\n,gs;
$answer_matched = ($slurp_mod eq $answer_mod);
# If it still doesn't match, see if the answer might be a regex.
if (!$answer_matched && $answer =~ m,^/(.+)/$,) {
$answer_matched = ($slurp =~ /$1/);
if (!$answer_matched && $answer_mod =~ m,^/(.+)/$,) {
$answer_matched = ($slurp_mod =~ /$1/);
}
}
}
}
}
if ($answer_matched && $test_passed)
@@ -706,11 +716,8 @@ sub compare_output
local($command) = "diff -c " . &get_basefile . " " . $logfile;
&run_command_with_output(&get_difffile,$command);
} else {
&rmfiles ();
}
$suite_passed = 0;
return 0;
}
@@ -749,6 +756,7 @@ sub attach_default_output
open($dup, '>&', STDOUT) or error("ado: $! duping STDOUT\n", 1);
push @OUTSTACK, $dup;
$dup = undef;
open($dup, '>&', STDERR) or error("ado: $! duping STDERR\n", 1);
push @ERRSTACK, $dup;

View File

@@ -18,8 +18,8 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include <assert.h>
#include "dep.h"
#include "filedef.h"
#include "dep.h"
#include "job.h"
#include "commands.h"
#include "variable.h"
@@ -803,6 +803,7 @@ define_automatic_variables (void)
(remote_description == 0 || remote_description[0] == '\0')
? "" : remote_description);
define_variable_cname ("MAKE_VERSION", buf, o_default, 0);
define_variable_cname ("MAKE_HOST", make_host, o_default, 0);
#ifdef __MSDOS__
/* Allow to specify a special shell just for Make,
@@ -1418,7 +1419,7 @@ parse_variable_definition (const char *p, struct variable *var)
int c = *p++;
/* If we find a comment or EOS, it's not a variable definition. */
if (c == '\0' || c == '#')
if (STOP_SET (c, MAP_COMMENT|MAP_NUL))
return NULL;
if (c == '$')

View File

@@ -165,9 +165,9 @@ struct variable *try_variable_definition (const gmk_floc *flocp, char *line,
int target_var);
void init_hash_global_variable_set (void);
void hash_init_function_table (void);
void define_new_function(const gmk_floc *flocp,
const char *name, int min, int max, int expand,
char *(*func)(const char *, int, char **));
void define_new_function(const gmk_floc *flocp, const char *name,
unsigned int min, unsigned int max, unsigned int flags,
gmk_func_ptr func);
struct variable *lookup_variable (const char *name, unsigned int length);
struct variable *lookup_variable_in_set (const char *name, unsigned int length,
const struct variable_set *set);

713
vmsjobs.c
View File

@@ -31,10 +31,10 @@ vmsWaitForChildren(int *status)
while (1)
{
if (!vms_jobsefnmask)
{
*status = 0;
return;
}
{
*status = 0;
return;
}
*status = sys$wflor (32, vms_jobsefnmask);
}
@@ -59,9 +59,9 @@ vms_redirect (struct dsc$descriptor_s *desc, char *fname, char *ibuf)
{
strcpy (fname, vmsify (fptr, 0));
if (strchr (fname, '.') == 0)
strcat (fname, ".");
strcat (fname, ".");
}
desc->dsc$w_length = strlen(fname);
desc->dsc$w_length = strlen (fname);
desc->dsc$a_pointer = fname;
desc->dsc$b_dtype = DSC$K_DTYPE_T;
desc->dsc$b_class = DSC$K_CLASS_S;
@@ -74,7 +74,7 @@ vms_redirect (struct dsc$descriptor_s *desc, char *fname, char *ibuf)
/* found apostrophe at (p-1)
inc p until after closing apostrophe.
*/
*/
char *
vms_handle_apos (char *p)
@@ -86,25 +86,21 @@ vms_handle_apos (char *p)
alast = 0;
while (*p != 0)
{
if (*p == '"')
{
if (alast)
{
alast = 0;
p++;
}
else
{
p++;
if (strchr (SEPCHARS, *p))
break;
alast = 1;
}
}
if (*p == '"')
if (alast)
{
alast = 0;
p++;
}
else
p++;
}
{
p++;
if (strchr (SEPCHARS, *p))
break;
alast = 1;
}
else
p++;
return p;
}
@@ -118,100 +114,99 @@ static int ctrlYPressed= 0;
int
vmsHandleChildTerm(struct child *child)
{
int status;
register struct child *lastc, *c;
int child_failed;
int status;
register struct child *lastc, *c;
int child_failed;
vms_jobsefnmask &= ~(1 << (child->efn - 32));
vms_jobsefnmask &= ~(1 << (child->efn - 32));
lib$free_ef(&child->efn);
if (child->comname)
{
if (!ISDB (DB_JOBS)&&!ctrlYPressed)
unlink (child->comname);
free (child->comname);
}
lib$free_ef (&child->efn);
if (child->comname)
{
if (!ISDB (DB_JOBS) && !ctrlYPressed)
unlink (child->comname);
free (child->comname);
}
(void) sigblock (fatal_signal_mask);
(void) sigblock (fatal_signal_mask);
child_failed = !(child->cstatus & 1 || ((child->cstatus & 7) == 0));
child_failed = !(child->cstatus & 1 || ((child->cstatus & 7) == 0));
/* Search for a child matching the deceased one. */
lastc = 0;
/* Search for a child matching the deceased one. */
lastc = 0;
#if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */
for (c = children; c != 0 && c != child; lastc = c, c = c->next)
;
for (c = children; c != 0 && c != child; lastc = c, c = c->next)
;
#else
c = child;
c = child;
#endif
if (child_failed && !c->noerror && !ignore_errors_flag)
{
/* The commands failed. Write an error message,
delete non-precious targets, and abort. */
child_error (c->file->name, c->cstatus, 0, 0, 0);
c->file->update_status = 1;
delete_child_targets (c);
}
else
{
if (child_failed)
{
/* The commands failed, but we don't care. */
child_error (c->file->name, c->cstatus, 0, 0, 1);
child_failed = 0;
}
if (child_failed && !c->noerror && !ignore_errors_flag)
{
/* The commands failed. Write an error message,
delete non-precious targets, and abort. */
child_error (c, c->cstatus, 0, 0, 0);
c->file->update_status = us_failed;
delete_child_targets (c);
}
else
{
if (child_failed)
{
/* The commands failed, but we don't care. */
child_error (c, c->cstatus, 0, 0, 1);
child_failed = 0;
}
#if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */
/* If there are more commands to run, try to start them. */
start_job (c);
/* If there are more commands to run, try to start them. */
start_job (c);
switch (c->file->command_state)
{
case cs_running:
/* Successfully started. */
break;
switch (c->file->command_state)
{
case cs_running:
/* Successfully started. */
break;
case cs_finished:
if (c->file->update_status != 0) {
/* We failed to start the commands. */
delete_child_targets (c);
}
break;
case cs_finished:
if (c->file->update_status != us_success)
/* We failed to start the commands. */
delete_child_targets (c);
break;
default:
error (NILF, _("internal error: '%s' command_state"),
c->file->name);
abort ();
break;
}
default:
error (NILF, _("internal error: '%s' command_state"),
c->file->name);
abort ();
break;
}
#endif /* RECURSIVEJOBS */
}
}
/* Set the state flag to say the commands have finished. */
c->file->command_state = cs_finished;
notice_finished_file (c->file);
/* Set the state flag to say the commands have finished. */
c->file->command_state = cs_finished;
notice_finished_file (c->file);
#if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */
/* Remove the child from the chain and free it. */
if (lastc == 0)
children = c->next;
else
lastc->next = c->next;
free_child (c);
/* Remove the child from the chain and free it. */
if (lastc == 0)
children = c->next;
else
lastc->next = c->next;
free_child (c);
#endif /* RECURSIVEJOBS */
/* There is now another slot open. */
if (job_slots_used > 0)
--job_slots_used;
/* There is now another slot open. */
if (job_slots_used > 0)
--job_slots_used;
/* If the job failed, and the -k flag was not given, die. */
if (child_failed && !keep_going_flag)
die (EXIT_FAILURE);
/* If the job failed, and the -k flag was not given, die. */
if (child_failed && !keep_going_flag)
die (EXIT_FAILURE);
(void) sigsetmask (sigblock (0) & ~(fatal_signal_mask));
(void) sigsetmask (sigblock (0) & ~(fatal_signal_mask));
return 1;
return 1;
}
/* VMS:
@@ -232,67 +227,71 @@ static unsigned short int chan= 0;
static void
reEnableAst(void)
{
lib$enable_ctrl (&oldCtrlMask,0);
lib$enable_ctrl (&oldCtrlMask,0);
}
static int
astYHandler (void)
{
struct child *c;
for (c = children; c != 0; c = c->next)
sys$delprc (&c->pid, 0, 0);
ctrlYPressed= 1;
kill (getpid(),SIGQUIT);
return SS$_NORMAL;
struct child *c;
for (c = children; c != 0; c = c->next)
sys$delprc (&c->pid, 0, 0);
ctrlYPressed= 1;
kill (getpid(),SIGQUIT);
return SS$_NORMAL;
}
static void
tryToSetupYAst(void)
{
$DESCRIPTOR(inputDsc,"SYS$COMMAND");
int status;
struct {
short int status, count;
int dvi;
} iosb;
unsigned short int loc_chan;
$DESCRIPTOR(inputDsc,"SYS$COMMAND");
int status;
struct {
short int status, count;
int dvi;
} iosb;
unsigned short int loc_chan;
setupYAstTried++;
setupYAstTried++;
if (chan)
loc_chan= chan;
else {
status= sys$assign(&inputDsc,&loc_chan,0,0);
if (!(status&SS$_NORMAL)) {
lib$signal(status);
return;
}
}
status= sys$qiow (0, loc_chan, IO$_SETMODE|IO$M_CTRLYAST,&iosb,0,0,
astYHandler,0,0,0,0,0);
if (status==SS$_NORMAL)
status= iosb.status;
if (status!=SS$_NORMAL) {
if (!chan)
sys$dassgn(loc_chan);
if (status!=SS$_ILLIOFUNC && status!=SS$_NOPRIV)
lib$signal(status);
return;
}
if (chan)
loc_chan= chan;
else
{
status= sys$assign(&inputDsc,&loc_chan,0,0);
if (!(status&SS$_NORMAL))
{
lib$signal(status);
return;
}
}
status= sys$qiow (0, loc_chan, IO$_SETMODE|IO$M_CTRLYAST,&iosb,0,0,
astYHandler,0,0,0,0,0);
if (status==SS$_NORMAL)
status= iosb.status;
if (status!=SS$_NORMAL)
{
if (!chan)
sys$dassgn(loc_chan);
if (status!=SS$_ILLIOFUNC && status!=SS$_NOPRIV)
lib$signal(status);
return;
}
/* called from AST handler ? */
if (setupYAstTried>1)
return;
if (atexit(reEnableAst))
fprintf (stderr,
_("-warning, you may have to re-enable CTRL-Y handling from DCL.\n"));
status= lib$disable_ctrl (&ctrlMask, &oldCtrlMask);
if (!(status&SS$_NORMAL)) {
lib$signal(status);
return;
}
if (!chan)
chan = loc_chan;
/* called from AST handler ? */
if (setupYAstTried>1)
return;
if (atexit(reEnableAst))
fprintf (stderr,
_("-warning, you may have to re-enable CTRL-Y handling from DCL.\n"));
status= lib$disable_ctrl (&ctrlMask, &oldCtrlMask);
if (!(status&SS$_NORMAL))
{
lib$signal(status);
return;
}
if (!chan)
chan = loc_chan;
}
int
@@ -349,63 +348,61 @@ child_execute_job (char *argv, struct child *child)
continue;
}
switch (*p)
{
case '#':
*p-- = 0;
*q-- = 0;
break;
case '\\':
p++;
if (*p == '\n')
p++;
if (isspace ((unsigned char)*p))
{
do { p++; } while (isspace ((unsigned char)*p));
p--;
}
*q = *p;
break;
case '<':
p = vms_redirect (&ifiledsc, ifile, p);
*q = ' ';
have_redirection = 1;
break;
case '>':
have_redirection = 1;
if (*(p-1) == '2')
{
q--;
if (strncmp (p, ">&1", 3) == 0)
{
p += 3;
strcpy (efile, "sys$output");
efiledsc.dsc$w_length = strlen(efile);
efiledsc.dsc$a_pointer = efile;
efiledsc.dsc$b_dtype = DSC$K_DTYPE_T;
efiledsc.dsc$b_class = DSC$K_CLASS_S;
}
else
{
p = vms_redirect (&efiledsc, efile, p);
}
}
else
{
if (*(p+1) == '>')
{
have_append = 1;
p += 1;
}
p = vms_redirect (&ofiledsc, ofile, p);
}
*q = ' ';
break;
case '\n':
have_newline = 1;
default:
*q = *p;
break;
}
{
case '#':
*p-- = 0;
*q-- = 0;
break;
case '\\':
p++;
if (*p == '\n')
p++;
if (isspace ((unsigned char)*p))
{
do { p++; } while (isspace ((unsigned char)*p));
p--;
}
*q = *p;
break;
case '<':
p = vms_redirect (&ifiledsc, ifile, p);
*q = ' ';
have_redirection = 1;
break;
case '>':
have_redirection = 1;
if (*(p-1) == '2')
{
q--;
if (strncmp (p, ">&1", 3) == 0)
{
p += 3;
strcpy (efile, "sys$output");
efiledsc.dsc$w_length = strlen(efile);
efiledsc.dsc$a_pointer = efile;
efiledsc.dsc$b_dtype = DSC$K_DTYPE_T;
efiledsc.dsc$b_class = DSC$K_CLASS_S;
}
else
p = vms_redirect (&efiledsc, efile, p);
}
else
{
if (*(p+1) == '>')
{
have_append = 1;
p += 1;
}
p = vms_redirect (&ofiledsc, ofile, p);
}
*q = ' ';
break;
case '\n':
have_newline = 1;
default:
*q = *p;
break;
}
}
*q = *p;
while (isspace ((unsigned char)*--q))
@@ -422,55 +419,55 @@ child_execute_job (char *argv, struct child *child)
p = cmd + 8;
if ((*(p) == 'c')
&& (*(p+1) == 'd')
&& ((*(p+2) == ' ') || (*(p+2) == '\t')))
{
p += 3;
while ((*p == ' ') || (*p == '\t'))
p++;
DB (DB_JOBS, (_("BUILTIN CD %s\n"), p));
if (chdir (p))
return 0;
else
return 1;
}
&& (*(p+1) == 'd')
&& ((*(p+2) == ' ') || (*(p+2) == '\t')))
{
p += 3;
while ((*p == ' ') || (*p == '\t'))
p++;
DB (DB_JOBS, (_("BUILTIN CD %s\n"), p));
if (chdir (p))
return 0;
else
return 1;
}
else if ((*(p) == 'r')
&& (*(p+1) == 'm')
&& ((*(p+2) == ' ') || (*(p+2) == '\t')))
{
int in_arg;
&& (*(p+1) == 'm')
&& ((*(p+2) == ' ') || (*(p+2) == '\t')))
{
int in_arg;
/* rm */
p += 3;
while ((*p == ' ') || (*p == '\t'))
p++;
in_arg = 1;
/* rm */
p += 3;
while ((*p == ' ') || (*p == '\t'))
p++;
in_arg = 1;
DB (DB_JOBS, (_("BUILTIN RM %s\n"), p));
while (*p)
{
switch (*p)
{
case ' ':
case '\t':
if (in_arg)
{
*p++ = ';';
in_arg = 0;
}
break;
default:
break;
}
p++;
}
}
DB (DB_JOBS, (_("BUILTIN RM %s\n"), p));
while (*p)
{
switch (*p)
{
case ' ':
case '\t':
if (in_arg)
{
*p++ = ';';
in_arg = 0;
}
break;
default:
break;
}
p++;
}
}
else
{
printf(_("Unknown builtin command '%s'\n"), cmd);
fflush(stdout);
return 0;
}
{
printf (_("Unknown builtin command '%s'\n"), cmd);
fflush (stdout);
return 0;
}
}
/* Create a *.com file if either the command is too long for
@@ -485,56 +482,54 @@ child_execute_job (char *argv, struct child *child)
FILE *outfile;
char c;
char *sep;
int alevel = 0; /* apostrophe level */
int alevel = 0; /* apostrophe level */
if (strlen (cmd) == 0)
{
printf (_("Error, empty command\n"));
fflush (stdout);
return 0;
}
{
printf (_("Error, empty command\n"));
fflush (stdout);
return 0;
}
outfile = open_tmpfile (&child->comname, "sys$scratch:CMDXXXXXX.COM");
outfile = output_tmpfile (&child->comname, "sys$scratch:CMDXXXXXX.COM");
if (outfile == 0)
pfatal_with_name (_("fopen (temporary file)"));
pfatal_with_name (_("fopen (temporary file)"));
comnamelen = strlen (child->comname);
if (ifile[0])
{
fprintf (outfile, "$ assign/user %s sys$input\n", ifile);
{
fprintf (outfile, "$ assign/user %s sys$input\n", ifile);
DB (DB_JOBS, (_("Redirected input from %s\n"), ifile));
ifiledsc.dsc$w_length = 0;
}
ifiledsc.dsc$w_length = 0;
}
if (efile[0])
{
fprintf (outfile, "$ define sys$error %s\n", efile);
{
fprintf (outfile, "$ define sys$error %s\n", efile);
DB (DB_JOBS, (_("Redirected error to %s\n"), efile));
efiledsc.dsc$w_length = 0;
}
efiledsc.dsc$w_length = 0;
}
if (ofile[0])
{
if (have_append)
{
fprintf (outfile, "$ set noon\n");
fprintf (outfile, "$ define sys$output %.*s\n", comnamelen-3, child->comname);
DB (DB_JOBS, (_("Append output to %s\n"), ofile));
ofiledsc.dsc$w_length = 0;
}
else
{
fprintf (outfile, "$ define sys$output %s\n", ofile);
DB (DB_JOBS, (_("Redirected output to %s\n"), ofile));
ofiledsc.dsc$w_length = 0;
}
}
if (have_append)
{
fprintf (outfile, "$ set noon\n");
fprintf (outfile, "$ define sys$output %.*s\n", comnamelen-3, child->comname);
DB (DB_JOBS, (_("Append output to %s\n"), ofile));
ofiledsc.dsc$w_length = 0;
}
else
{
fprintf (outfile, "$ define sys$output %s\n", ofile);
DB (DB_JOBS, (_("Redirected output to %s\n"), ofile));
ofiledsc.dsc$w_length = 0;
}
p = sep = q = cmd;
for (c = '\n'; c; c = *q++)
{
switch (c)
{
{
switch (c)
{
case '\n':
/* At a newline, skip any whitespace around a leading $
from the command and issue exactly one $ into the DCL. */
@@ -551,8 +546,8 @@ child_execute_job (char *argv, struct child *child)
p = sep = q;
break;
/* Nice places for line breaks are after strings, after
comma or space and before slash. */
/* Nice places for line breaks are after strings, after
comma or space and before slash. */
case '"':
q = vms_handle_apos (q);
sep = q;
@@ -567,25 +562,25 @@ child_execute_job (char *argv, struct child *child)
break;
default:
break;
}
if (sep - p > 78)
{
/* Enough stuff for a line. */
fwrite (p, 1, sep - p, outfile);
p = sep;
if (*sep)
{
/* The command continues. */
fputc ('-', outfile);
}
fputc ('\n', outfile);
}
}
}
if (sep - p > 78)
{
/* Enough stuff for a line. */
fwrite (p, 1, sep - p, outfile);
p = sep;
if (*sep)
{
/* The command continues. */
fputc ('-', outfile);
}
fputc ('\n', outfile);
}
}
if (*p)
{
fwrite (p, 1, --q - p, outfile);
fputc ('\n', outfile);
fputc ('\n', outfile);
}
if (have_append)
@@ -630,66 +625,66 @@ child_execute_job (char *argv, struct child *child)
vms_jobsefnmask |= (1 << (child->efn - 32));
/*
LIB$SPAWN [command-string]
[,input-file]
[,output-file]
[,flags]
[,process-name]
[,process-id] [,completion-status-address] [,byte-integer-event-flag-num]
[,AST-address] [,varying-AST-argument]
[,prompt-string] [,cli] [,table]
*/
/*
LIB$SPAWN [command-string]
[,input-file]
[,output-file]
[,flags]
[,process-name]
[,process-id] [,completion-status-address] [,byte-integer-event-flag-num]
[,AST-address] [,varying-AST-argument]
[,prompt-string] [,cli] [,table]
*/
#ifndef DONTWAITFORCHILD
/*
* Code to make ctrl+c and ctrl+y working.
* The problem starts with the synchronous case where after lib$spawn is
* called any input will go to the child. But with input re-directed,
* both control characters won't make it to any of the programs, neither
* the spawning nor to the spawned one. Hence the caller needs to spawn
* with CLI$M_NOWAIT to NOT give up the input focus. A sys$waitfr
* has to follow to simulate the wanted synchronous behaviour.
* The next problem is ctrl+y which isn't caught by the crtl and
* therefore isn't converted to SIGQUIT (for a signal handler which is
* already established). The only way to catch ctrl+y, is an AST
* assigned to the input channel. But ctrl+y handling of DCL needs to be
* disabled, otherwise it will handle it. Not to mention the previous
* ctrl+y handling of DCL needs to be re-established before make exits.
* One more: At the time of LIB$SPAWN signals are blocked. SIGQUIT will
* make it to the signal handler after the child "normally" terminates.
* This isn't enough. It seems reasonable for simple command lines like
* a 'cc foobar.c' spawned in a subprocess but it is unacceptable for
* spawning make. Therefore we need to abort the process in the AST.
*
* Prior to the spawn it is checked if an AST is already set up for
* ctrl+y, if not one is set up for a channel to SYS$COMMAND. In general
* this will work except if make is run in a batch environment, but there
* nobody can press ctrl+y. During the setup the DCL handling of ctrl+y
* is disabled and an exit handler is established to re-enable it.
* If the user interrupts with ctrl+y, the assigned AST will fire, force
* an abort to the subprocess and signal SIGQUIT, which will be caught by
* the already established handler and will bring us back to common code.
* After the spawn (now /nowait) a sys$waitfr simulates the /wait and
* enables the ctrl+y be delivered to this code. And the ctrl+c too,
* which the crtl converts to SIGINT and which is caught by the common
* signal handler. Because signals were blocked before entering this code
* sys$waitfr will always complete and the SIGQUIT will be processed after
* it (after termination of the current block, somewhere in common code).
* And SIGINT too will be delayed. That is ctrl+c can only abort when the
* current command completes. Anyway it's better than nothing :-)
*/
/*
* Code to make ctrl+c and ctrl+y working.
* The problem starts with the synchronous case where after lib$spawn is
* called any input will go to the child. But with input re-directed,
* both control characters won't make it to any of the programs, neither
* the spawning nor to the spawned one. Hence the caller needs to spawn
* with CLI$M_NOWAIT to NOT give up the input focus. A sys$waitfr
* has to follow to simulate the wanted synchronous behaviour.
* The next problem is ctrl+y which isn't caught by the crtl and
* therefore isn't converted to SIGQUIT (for a signal handler which is
* already established). The only way to catch ctrl+y, is an AST
* assigned to the input channel. But ctrl+y handling of DCL needs to be
* disabled, otherwise it will handle it. Not to mention the previous
* ctrl+y handling of DCL needs to be re-established before make exits.
* One more: At the time of LIB$SPAWN signals are blocked. SIGQUIT will
* make it to the signal handler after the child "normally" terminates.
* This isn't enough. It seems reasonable for simple command lines like
* a 'cc foobar.c' spawned in a subprocess but it is unacceptable for
* spawning make. Therefore we need to abort the process in the AST.
*
* Prior to the spawn it is checked if an AST is already set up for
* ctrl+y, if not one is set up for a channel to SYS$COMMAND. In general
* this will work except if make is run in a batch environment, but there
* nobody can press ctrl+y. During the setup the DCL handling of ctrl+y
* is disabled and an exit handler is established to re-enable it.
* If the user interrupts with ctrl+y, the assigned AST will fire, force
* an abort to the subprocess and signal SIGQUIT, which will be caught by
* the already established handler and will bring us back to common code.
* After the spawn (now /nowait) a sys$waitfr simulates the /wait and
* enables the ctrl+y be delivered to this code. And the ctrl+c too,
* which the crtl converts to SIGINT and which is caught by the common
* signal handler. Because signals were blocked before entering this code
* sys$waitfr will always complete and the SIGQUIT will be processed after
* it (after termination of the current block, somewhere in common code).
* And SIGINT too will be delayed. That is ctrl+c can only abort when the
* current command completes. Anyway it's better than nothing :-)
*/
if (!setupYAstTried)
tryToSetupYAst();
status = lib$spawn (&cmddsc, /* cmd-string */
(ifiledsc.dsc$w_length == 0)?0:&ifiledsc, /* input-file */
(ofiledsc.dsc$w_length == 0)?0:&ofiledsc, /* output-file */
&spflags, /* flags */
&pnamedsc, /* proc name */
&child->pid, &child->cstatus, &child->efn,
0, 0,
0, 0, 0);
status = lib$spawn (&cmddsc, /* cmd-string */
(ifiledsc.dsc$w_length == 0)?0:&ifiledsc, /* input-file */
(ofiledsc.dsc$w_length == 0)?0:&ofiledsc, /* output-file */
&spflags, /* flags */
&pnamedsc, /* proc name */
&child->pid, &child->cstatus, &child->efn,
0, 0,
0, 0, 0);
if (status & 1)
{
status= sys$waitfr (child->efn);
@@ -697,13 +692,13 @@ child_execute_job (char *argv, struct child *child)
}
#else
status = lib$spawn (&cmddsc,
(ifiledsc.dsc$w_length == 0)?0:&ifiledsc,
(ofiledsc.dsc$w_length == 0)?0:&ofiledsc,
&spflags,
&pnamedsc,
&child->pid, &child->cstatus, &child->efn,
vmsHandleChildTerm, child,
0, 0, 0);
(ifiledsc.dsc$w_length == 0)?0:&ifiledsc,
(ofiledsc.dsc$w_length == 0)?0:&ofiledsc,
&spflags,
&pnamedsc,
&child->pid, &child->cstatus, &child->efn,
vmsHandleChildTerm, child,
0, 0, 0);
#endif
if (!(status & 1))

19
vpath.c
View File

@@ -306,12 +306,13 @@ construct_vpath_list (char *pattern, char *dirpath)
int
gpath_search (const char *file, unsigned int len)
{
const char **gp;
if (gpaths && (len <= gpaths->maxlen))
for (gp = gpaths->searchpath; *gp != NULL; ++gp)
if (strneq (*gp, file, len) && (*gp)[len] == '\0')
return 1;
{
const char **gp;
for (gp = gpaths->searchpath; *gp != NULL; ++gp)
if (strneq (*gp, file, len) && (*gp)[len] == '\0')
return 1;
}
return 0;
}
@@ -334,7 +335,7 @@ selective_vpath_search (struct vpath *path, const char *file,
const char **vpath = path->searchpath;
unsigned int maxvpath = path->maxlen;
unsigned int i;
unsigned int flen, vlen, name_dplen;
unsigned int flen, name_dplen;
int exists = 0;
/* Find out if *FILE is a target.
@@ -374,12 +375,10 @@ selective_vpath_search (struct vpath *path, const char *file,
for (i = 0; vpath[i] != 0; ++i)
{
int exists_in_cache = 0;
char *p;
p = name;
char *p = name;
unsigned int vlen = strlen (vpath[i]);
/* Put the next VPATH entry into NAME at P and increment P past it. */
vlen = strlen (vpath[i]);
memcpy (p, vpath[i], vlen);
p += vlen;

View File

@@ -18,6 +18,6 @@
noinst_LIBRARIES = libw32.a
libw32_a_SOURCES = subproc/misc.c subproc/sub_proc.c subproc/w32err.c \
pathstuff.c
compat/posixfcn.c pathstuff.c
libw32_a_CPPFLAGS = -I$(srcdir)/include -I$(srcdir)/subproc -I$(top_srcdir)

View File

@@ -26,7 +26,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include "makeint.h"
#include "job.h"
#ifdef OUTPUT_SYNC
#ifndef NO_OUTPUT_SYNC
/* Support for OUTPUT_SYNC and related functionality. */
/* Emulation of fcntl that supports only F_GETFD and F_SETLKW. */
@@ -40,106 +40,106 @@ fcntl (intptr_t fd, int 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;
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;
{
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);
va_end (ap);
if (hmutex == INVALID_HANDLE_VALUE || !hmutex)
return -1;
if (hmutex == INVALID_HANDLE_VALUE || !hmutex)
return -1;
last_fl = *fl;
last_fl = *fl;
switch (fl->l_type)
{
switch (fl->l_type)
{
case F_WRLCK:
{
DWORD result;
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;
}
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 ();
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));
/* 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);
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 (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;
}
}
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;
errno = ENOSYS;
va_end (ap);
return -1;
}
}
@@ -210,54 +210,156 @@ same_stream (FILE *f1, FILE *f2)
&& fh2 && fh2 != INVALID_HANDLE_VALUE)
{
if (fh1 == fh2)
return 1;
return 1;
else
{
DWORD ftyp1 = GetFileType (fh1), ftyp2 = GetFileType (fh2);
{
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;
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;
/* 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 stdin 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);
}
}
/* 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 */
/* A replacement for tmpfile, since the MSVCRT implementation creates
the file in the root directory of the current drive, which might
not be writable by our user. Most of the code borrowed from
create_batch_file, see job.c. */
FILE *
tmpfile (void)
{
char temp_path[MAXPATHLEN];
unsigned path_size = GetTempPath (sizeof temp_path, temp_path);
int path_is_dot = 0;
/* The following variable is static so we won't try to reuse a name
that was generated a little while ago, because that file might
not be on disk yet, since we use FILE_ATTRIBUTE_TEMPORARY below,
which tells the OS it doesn't need to flush the cache to disk.
If the file is not yet on disk, we might think the name is
available, while it really isn't. This happens in parallel
builds, where Make doesn't wait for one job to finish before it
launches the next one. */
static unsigned uniq = 0;
static int second_loop = 0;
const char base[] = "gmake_tmpf";
const unsigned sizemax = sizeof base - 1 + 4 + 10 + 10;
unsigned pid = GetCurrentProcessId ();
if (path_size == 0)
{
path_size = GetCurrentDirectory (sizeof temp_path, temp_path);
path_is_dot = 1;
}
++uniq;
if (uniq >= 0x10000 && !second_loop)
{
/* If we already had 64K batch files in this
process, make a second loop through the numbers,
looking for free slots, i.e. files that were
deleted in the meantime. */
second_loop = 1;
uniq = 1;
}
while (path_size > 0 &&
path_size + sizemax < sizeof temp_path &&
!(uniq >= 0x10000 && second_loop))
{
HANDLE h;
sprintf (temp_path + path_size,
"%s%s%u-%x.tmp",
temp_path[path_size - 1] == '\\' ? "" : "\\",
base, pid, uniq);
h = CreateFile (temp_path, /* file name */
GENERIC_READ | GENERIC_WRITE | DELETE, /* desired access */
FILE_SHARE_READ | FILE_SHARE_WRITE, /* share mode */
NULL, /* default security attributes */
CREATE_NEW, /* creation disposition */
FILE_ATTRIBUTE_NORMAL | /* flags and attributes */
FILE_ATTRIBUTE_TEMPORARY |
FILE_FLAG_DELETE_ON_CLOSE,
NULL); /* no template file */
if (h == INVALID_HANDLE_VALUE)
{
const DWORD er = GetLastError ();
if (er == ERROR_FILE_EXISTS || er == ERROR_ALREADY_EXISTS)
{
++uniq;
if (uniq == 0x10000 && !second_loop)
{
second_loop = 1;
uniq = 1;
}
}
/* The temporary path is not guaranteed to exist, or might
not be writable by user. Use the current directory as
fallback. */
else if (path_is_dot == 0)
{
path_size = GetCurrentDirectory (sizeof temp_path, temp_path);
path_is_dot = 1;
}
else
{
errno = EACCES;
break;
}
}
else
{
int fd = _open_osfhandle ((intptr_t)h, 0);
return _fdopen (fd, "w+b");
}
}
if (uniq >= 0x10000)
errno = EEXIST;
return NULL;
}
#endif /* !NO_OUTPUT_SYNC */
#if MAKE_LOAD
@@ -286,8 +388,8 @@ dlopen (const char *file, int mode)
/* MSDN says to be sure to use backslashes in the DLL file name. */
strcpy (dllfn, file);
for (p = dllfn; *p; p++)
if (*p == '/')
*p = '\\';
if (*p == '/')
*p = '\\';
dllhandle = LoadLibrary (dllfn);
}
@@ -307,8 +409,8 @@ dlerror (void)
return NULL;
ret = FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, last_err, 0, errbuf, sizeof (errbuf), NULL);
| FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, last_err, 0, errbuf, sizeof (errbuf), NULL);
while (ret > 0 && (errbuf[ret - 1] == '\n' || errbuf[ret - 1] == '\r'))
--ret;
@@ -350,5 +452,5 @@ dlclose (void *handle)
}
#endif /* MAKE_LOAD */
#endif /* MAKE_LOAD */

View File

@@ -1111,7 +1111,7 @@ done2:
/*
* Description: Clean up any leftover handles, etc. It is up to the
* caller to manage and free the input, ouput, and stderr buffers.
* caller to manage and free the input, output, and stderr buffers.
*/
void
process_cleanup(