mirror of
https://github.com/mirror/make.git
synced 2026-08-20 00:43:29 +08:00
Compare commits
76 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52191d9d61 | ||
|
|
dc9ae5e017 | ||
|
|
723e047428 | ||
|
|
b69b04dc8c | ||
|
|
b539908f73 | ||
|
|
2fb91e19a0 | ||
|
|
f96c114e22 | ||
|
|
98197303b1 | ||
|
|
f8786092ad | ||
|
|
1d4c15b4e1 | ||
|
|
b1c7f0df4e | ||
|
|
8e12202870 | ||
|
|
1f4ca0539b | ||
|
|
d0944ee2e8 | ||
|
|
38066b6f19 | ||
|
|
3bf3fde984 | ||
|
|
543521cd47 | ||
|
|
e8122ecb5d | ||
|
|
55a0c0e414 | ||
|
|
8a3436c65d | ||
|
|
fd30db1290 | ||
|
|
c3524b83b9 | ||
|
|
0296e40fc7 | ||
|
|
f69922b335 | ||
|
|
65931ce7a9 | ||
|
|
1a991ada47 | ||
|
|
7e77685bc3 | ||
|
|
300d1296fb | ||
|
|
822f8dae41 | ||
|
|
d2d44f76c4 | ||
|
|
6c3e88e60f | ||
|
|
9cd01958da | ||
|
|
4120f91846 | ||
|
|
30a5ee0d85 | ||
|
|
8a6205b43f | ||
|
|
bc120f27bd | ||
|
|
5c0fba7240 | ||
|
|
fa0f2c516a | ||
|
|
20ecc58126 | ||
|
|
1b90248893 | ||
|
|
a4d8444b59 | ||
|
|
0a81d50d66 | ||
|
|
3aa2aa7e82 | ||
|
|
29a94ceb76 | ||
|
|
ab78cbc71c | ||
|
|
c5bfa40044 | ||
|
|
deff9dacc9 | ||
|
|
40a49f244d | ||
|
|
87ac68fe79 | ||
|
|
72462ef1e1 | ||
|
|
f80222c15b | ||
|
|
4b81f5ca92 | ||
|
|
5601726151 | ||
|
|
9453a7451d | ||
|
|
5e7bf7c554 | ||
|
|
138d020e1b | ||
|
|
5b65c5b916 | ||
|
|
cc85b927cd | ||
|
|
bee4d93a59 | ||
|
|
353fcfdb30 | ||
|
|
d4043519f7 | ||
|
|
ef11217de7 | ||
|
|
e8f5d322cf | ||
|
|
dc922e3f4c | ||
|
|
c11024b3b3 | ||
|
|
2fc0f614be | ||
|
|
bf60bbd67a | ||
|
|
d2eaed1f0a | ||
|
|
8ab3564a71 | ||
|
|
ecf307bb0b | ||
|
|
a674abe702 | ||
|
|
80183457ad | ||
|
|
cece7ad61f | ||
|
|
943c06de47 | ||
|
|
171eb41908 | ||
|
|
9babfe49a5 |
523
ChangeLog
523
ChangeLog
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
90
NEWS
@@ -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.
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
24
TODO.private
24
TODO.private
@@ -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.
|
||||
|
||||
7
arscan.c
7
arscan.c
@@ -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;
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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%"
|
||||
|
||||
46
configure.ac
46
configure.ac
@@ -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 &&
|
||||
|
||||
@@ -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
19
dep.h
@@ -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
60
dir.c
@@ -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;
|
||||
|
||||
174
doc/make.texi
174
doc/make.texi
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
10
expand.c
10
expand.c
@@ -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
28
file.c
@@ -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
|
||||
|
||||
13
filedef.h
13
filedef.h
@@ -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. */
|
||||
|
||||
159
function.c
159
function.c
@@ -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;
|
||||
|
||||
|
||||
28
gnumake.h
28
gnumake.h
@@ -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
35
guile.c
@@ -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;
|
||||
}
|
||||
|
||||
74
implicit.c
74
implicit.c
@@ -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
589
job.c
@@ -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
48
job.h
@@ -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
11
load.c
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
26
make.1
@@ -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
|
||||
|
||||
2
make.lnk
2
make.lnk
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
74
makefile.vms
74
makefile.vms
@@ -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) $< $@
|
||||
|
||||
54
makeint.h
54
makeint.h
@@ -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
351
misc.c
@@ -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
762
output.c
Normal 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
51
output.h
Normal 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
|
||||
@@ -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
148
read.c
@@ -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;
|
||||
|
||||
99
remake.c
99
remake.c
@@ -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;
|
||||
|
||||
|
||||
@@ -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
4
rule.c
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
128
tests/ChangeLog
128
tests/ChangeLog
@@ -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.
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
61
tests/scripts/features/jobserver
Normal file
61
tests/scripts/features/jobserver
Normal 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;
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
#
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
37
tests/scripts/features/rule_glob
Normal file
37
tests/scripts/features/rule_glob
Normal 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;
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
15
tests/scripts/misc/fopen-fail
Normal file
15
tests/scripts/misc/fopen-fail
Normal 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;
|
||||
@@ -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');
|
||||
|
||||
@@ -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;
|
||||
|
||||
33
tests/scripts/options/print-directory
Normal file
33
tests/scripts/options/print-directory
Normal 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;
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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#'");
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 == '$')
|
||||
|
||||
@@ -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
713
vmsjobs.c
@@ -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
19
vpath.c
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user