Compare commits

..

19 Commits
3.99.92 ... 4.0

Author SHA1 Message Date
Paul Smith
52191d9d61 GNU Make release 4.0. 2013-10-09 02:09:21 -04:00
Paul Smith
dc9ae5e017 [SV 39709] Fix some typos. 2013-10-09 01:53:55 -04:00
Eli Zaretskii
723e047428 Untabify posixfcn.c. 2013-10-07 19:16:11 +03:00
Eli Zaretskii
b69b04dc8c Foix compilation with MSVC.
w32/compat/posixfcn.c (tmpfile): Move declaration of h before
 the first executable statement.  Reported by Gisle Vanem <gvanem@yahoo.no>.
2013-10-07 19:14:01 +03:00
Paul Smith
b539908f73 Clean up some tests for use on Windows. 2013-10-05 19:30:48 -04:00
Paul Smith
2fb91e19a0 Sanitize the registered function interface.
Expand the characters which are legal in a function name, and check
the name for validity.  Create a type for the function pointer.
Convert the last argument from a boolean to flags, to allow for expansion.
2013-10-05 16:10:30 -04:00
Eli Zaretskii
f96c114e22 function.c (abspath): Reset root_len to one for Cygwin only when
HAVE_DOS_PATHS is defined.  Suggested by Christopher Faylor.
2013-10-03 19:02:14 +03:00
Eli Zaretskii
98197303b1 Fix tmpfile on MS-Windows.
w32/compat/posixfcn.c (tmpfile): New function, a replacement for
 the Windows libc version.
2013-10-02 19:48:21 +03:00
Eli Zaretskii
f8786092ad Fix $abspath on Cygwin when HAVE_DOS_PATHS is in effect.
function.c (IS_ABSOLUTE) [__CYGWIN__]: Special definition for Cygwin.
 (abspath) [__CYGWIN__]: Reset root_len to 1 if the absolute file name
 has the Posix /foo/bar form.
 [HAVE_DOS_PATHS]: Use root_len instead of hard-coded 2.
2013-10-02 19:39:53 +03:00
Paul Smith
1d4c15b4e1 Release GNU Make version 3.99.93. 2013-10-01 00:33:01 -04:00
Paul Smith
b1c7f0df4e Fix portability issues for Guile 1.8. 2013-09-30 10:56:20 -04:00
Paul Smith
8e12202870 Final fixes for obscure output-sync errors. 2013-09-30 00:12:36 -04:00
Paul Smith
1f4ca0539b Fixes for building with MSVC. 2013-09-30 00:12:36 -04:00
Paul Smith
d0944ee2e8 Solaris /bin/sh can't handle multiple options ("-e -c"). 2013-09-30 00:12:18 -04:00
Paul Smith
38066b6f19 Fix build failures on EMX for output-sync support. 2013-09-29 13:17:56 -04:00
Paul Smith
3bf3fde984 Portability for Guile 1.8. Force UTF-8 encoding. 2013-09-29 13:16:21 -04:00
Paul Smith
543521cd47 Reset GNUMAKEFLAGS after parsing.
If we don't do this we'll continually add flags on recursion.  This
is mainly for users to set in their environment before invoking make.
2013-09-29 13:15:00 -04:00
Paul Smith
e8122ecb5d Rename dash-w to print-directory.
Avoid conflicts with dash-W on case-insensitive filesystems.
2013-09-23 11:24:51 -04:00
Eli Zaretskii
55a0c0e414 Fix broken w32 build due to OUTPUT_SYNC -> NO_OUTPUT_SYNC inversion.
w32/compat/posixfcn.c: Fix the forgotten OUTPUT_SYNC conditional.
 job.h: Ditto, but in a comment.
2013-09-23 10:56:51 +03:00
32 changed files with 825 additions and 447 deletions

106
ChangeLog
View File

@@ -1,3 +1,109 @@
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.

View File

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

28
NEWS
View File

@@ -1,6 +1,6 @@
GNU make NEWS -*-indented-text-*-
History of user-visible changes.
23 Sep 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.92
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
@@ -47,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
@@ -58,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
@@ -73,7 +78,8 @@ 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.
* 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'
@@ -81,8 +87,10 @@ http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=101&set
* 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 there. If no simple flags are present MAKEFLAGS
begins with a space. MFLAGS never begins with "- ".
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.

View File

@@ -7,7 +7,7 @@ It builds with the MinGW port of GCC (tested with GCC 3.4.2).
It also builds with MSVC 2.x, 4.x, 5.x, 6.x, and 2003 as well as
with .NET 7.x and .NET 2003.
As of version 3.83, a build with Guile is supported (tested with Guile
As of version 4.0, a build with Guile is supported (tested with Guile
2.0.3). To build with Guile, you will need, in addition to Guile
itself, its dependency libraries and the pkg-config program. The
latter is used to figure out which compilation and link switches and

View File

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

View File

@@ -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.92],[bug-make@gnu.org])
AC_INIT([GNU make],[4.0],[bug-make@gnu.org])
AC_PREREQ([2.62])

View File

@@ -4808,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
@@ -11108,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
@@ -11133,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
@@ -11177,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

View File

@@ -31,7 +31,7 @@ struct function_table_entry
{
union {
char *(*func_ptr) (char *output, char **argv, const char *fname);
char *(*alloc_func_ptr) (const char *fname, int argc, char **argv);
gmk_func_ptr alloc_func_ptr;
} fptr;
const char *name;
unsigned char len;
@@ -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);
}
@@ -1620,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
@@ -1636,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);
@@ -1652,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;
@@ -1678,6 +1678,9 @@ func_shell_base (char *o, char **argv, int trim_newlines)
/* 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)
@@ -1710,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 (FD_STDIN, pipedes[1], FD_STDOUT, 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__ */
@@ -1724,9 +1727,7 @@ func_shell_base (char *o, char **argv, int trim_newlines)
if (stack_limit.rlim_cur)
setrlimit (RLIMIT_STACK, &stack_limit);
# endif
child_execute_job (FD_STDIN, pipedes[1],
output_context ? output_context->err : FD_STDERR,
command_argv, envp);
child_execute_job (FD_STDIN, pipedes[1], errfd, command_argv, envp);
}
else
# endif
@@ -1948,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
@@ -2000,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 (! STOP_SET (apath[2], MAP_PATHSEP))
if (! STOP_SET (apath[root_len - 1], MAP_PATHSEP))
{
/* Convert d:foo into d:./foo and increase root_len. */
apath[2] = '.';
@@ -2017,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
}
@@ -2436,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;
@@ -2521,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);
@@ -2542,7 +2560,7 @@ define_new_function (const gmk_floc *flocp,
ent->len = len;
ent->minimum_args = min;
ent->maximum_args = max;
ent->expand_args = expand ? 1 : 0;
ent->expand_args = ANY_SET(flags, GMK_FUNC_NOEXPAND) ? 0 : 1;
ent->alloc_fn = 1;
ent->fptr.alloc_func_ptr = func;

View File

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

20
guile.c
View File

@@ -24,6 +24,16 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#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;
@@ -72,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, (scm_t_subr) 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, (scm_t_subr) 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);
@@ -100,12 +110,12 @@ 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;
@@ -130,7 +140,7 @@ int
guile_gmake_setup (const gmk_floc *flocp UNUSED)
{
/* 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;
}

6
job.c
View File

@@ -2234,7 +2234,7 @@ child_execute_job (int stdin_fd, int stdout_fd, int stderr_fd,
/* Restore stdout/stdin/stderr of the parent and close temporary FDs. */
if (save_stdin >= 0)
{
if (dup2 (save_stdin, FD_STDIN) != 0)
if (dup2 (save_stdin, FD_STDIN) != FD_STDIN)
fatal (NILF, _("Could not restore stdin\n"));
else
close (save_stdin);
@@ -2242,7 +2242,7 @@ child_execute_job (int stdin_fd, int stdout_fd, int stderr_fd,
if (save_stdout >= 0)
{
if (dup2 (save_stdout, FD_STDOUT) != 0)
if (dup2 (save_stdout, FD_STDOUT) != FD_STDOUT)
fatal (NILF, _("Could not restore stdout\n"));
else
close (save_stdout);
@@ -2250,7 +2250,7 @@ child_execute_job (int stdin_fd, int stdout_fd, int stderr_fd,
if (save_stderr >= 0)
{
if (dup2 (save_stderr, FD_STDERR) != 0)
if (dup2 (save_stderr, FD_STDERR) != FD_STDERR)
fatal (NILF, _("Could not restore stderr\n"));
else
close (save_stderr);

4
job.h
View File

@@ -80,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. */
@@ -128,7 +128,7 @@ int child_execute_job (char *argv, struct child *child);
# 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)
char **argv, char **envp);
# else
void child_execute_job (int stdin_fd, int stdout_fd, int stderr_fd,
char **argv, char **envp) __attribute__ ((noreturn));

View File

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

97
main.c
View File

@@ -612,10 +612,13 @@ initialize_stopchar_map ()
stopchar_map[(int)':'] = MAP_COLON;
stopchar_map[(int)'%'] = MAP_PERCENT;
stopchar_map[(int)'|'] = MAP_PIPE;
stopchar_map[(int)'.'] = MAP_DOT;
stopchar_map[(int)'.'] = MAP_DOT | MAP_USERFUNC;
stopchar_map[(int)','] = MAP_COMMA;
stopchar_map[(int)'$'] = MAP_VARIABLE;
stopchar_map[(int)'-'] = MAP_USERFUNC;
stopchar_map[(int)'_'] = MAP_USERFUNC;
stopchar_map[(int)'/'] = MAP_PATHSEP;
#if defined(VMS)
stopchar_map[(int)']'] = MAP_PATHSEP;
@@ -629,6 +632,8 @@ initialize_stopchar_map ()
stopchar_map[i] = MAP_BLANK;
if (isspace(i))
stopchar_map[i] |= MAP_SPACE;
if (isalnum(i))
stopchar_map[i] = MAP_USERFUNC;
}
}
@@ -1295,64 +1300,62 @@ main (int argc, char **argv, char **envp)
for (i = 0; envp[i] != 0; ++i)
{
int do_not_define = 0;
struct variable *v;
char *ep = envp[i];
/* By default, export all variables culled from the environment. */
enum variable_export export = v_export;
unsigned int len;
while (! STOP_SET (*ep, MAP_EQUALS))
++ep;
/* If there's no equals sign it's a malformed environment. Ignore. */
if (*ep == '\0')
continue;
#ifdef WINDOWS32
if (!unix_path && strneq (envp[i], "PATH=", 5))
unix_path = ep+1;
else if (!strnicmp (envp[i], "Path=", 5))
{
do_not_define = 1; /* it gets defined after loop exits */
if (!windows32_path)
windows32_path = ep+1;
/* PATH gets defined after the loop exits. */
continue;
}
#endif
/* The result of pointer arithmetic is cast to unsigned int for
machines where ptrdiff_t is a different size that doesn't widen
the same. */
if (!do_not_define)
/* Length of the variable name, and skip the '='. */
len = ep++ - envp[i];
/* If this is MAKE_RESTARTS, check to see if the "already printed
the enter statement" flag is set. */
if (len == 13 && strneq (envp[i], "MAKE_RESTARTS", 13))
{
struct variable *v;
v = define_variable (envp[i], (unsigned int) (ep - envp[i]),
ep + 1, o_env, 1);
/* Force exportation of every variable culled from the
environment. We used to rely on target_environment's
v_default code to do this. But that does not work for the
case where an environment variable is redefined in a makefile
with 'override'; it should then still be exported, because it
was originally in the environment. */
v->export = v_export;
/* Another wrinkle is that POSIX says the value of SHELL set in
the makefile won't change the value of SHELL given to
subprocesses. */
if (streq (v->name, "SHELL"))
if (*ep == '-')
{
#ifndef __MSDOS__
v->export = v_noexport;
#endif
shell_var.name = "SHELL";
shell_var.length = 5;
shell_var.value = xstrdup (ep + 1);
}
/* If MAKE_RESTARTS is set, remember it but don't export it.
If it's negative, it means the "enter" message was printed. */
else if (streq (v->name, "MAKE_RESTARTS"))
{
v->export = v_noexport;
if (*(++ep) == '-')
{
OUTPUT_TRACED ();
++ep;
}
restarts = (unsigned int) atoi (ep);
OUTPUT_TRACED ();
++ep;
}
restarts = (unsigned int) atoi (ep);
export = v_noexport;
}
v = define_variable (envp[i], len, ep, o_env, 1);
/* POSIX says the value of SHELL set in the makefile won't change the
value of SHELL given to subprocesses. */
if (streq (v->name, "SHELL"))
{
#ifndef __MSDOS__
export = v_noexport;
#endif
shell_var.name = "SHELL";
shell_var.length = 5;
shell_var.value = xstrdup (ep);
}
v->export = export;
}
}
#ifdef WINDOWS32
@@ -1396,6 +1399,10 @@ main (int argc, char **argv, char **envp)
/* Decode the switches. */
decode_env_switches (STRING_SIZE_TUPLE ("GNUMAKEFLAGS"));
/* Clear GNUMAKEFLAGS to avoid duplication. */
define_variable_cname ("GNUMAKEFLAGS", "", o_env, 0);
decode_env_switches (STRING_SIZE_TUPLE ("MAKEFLAGS"));
/* In output sync mode we need to sync any output generated by reading the
@@ -1931,12 +1938,16 @@ main (int argc, char **argv, char **envp)
/* Decode switches again, for variables set by the makefile. */
decode_env_switches (STRING_SIZE_TUPLE ("GNUMAKEFLAGS"));
/* Clear GNUMAKEFLAGS to avoid duplication. */
define_variable_cname ("GNUMAKEFLAGS", "", o_override, 0);
decode_env_switches (STRING_SIZE_TUPLE ("MAKEFLAGS"));
#if 0
decode_env_switches (STRING_SIZE_TUPLE ("MFLAGS"));
#endif
/* Reset in case the switches changed our minds. */
/* Reset in case the switches changed our mind. */
syncing = (output_sync == OUTPUT_SYNC_LINE
|| output_sync == OUTPUT_SYNC_TARGET);

View File

@@ -2,6 +2,8 @@
# only if you have the full copy of the GNU make sources from the Git
# tree, not a dist copy.
GPG_FINGERPRINT := 6338B6D4
# We like mondo-warnings!
AM_CFLAGS += -Wall -Wextra -Wdeclaration-after-statement -Wshadow -Wpointer-arith -Wbad-function-cast
@@ -243,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. ##
## ------------------------- ##
@@ -252,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))

View File

@@ -171,6 +171,9 @@
<File
RelativePath=".\job.c">
</File>
<File
RelativePath=".\load.c">
</File>
<File
RelativePath=".\output.c">
</File>
@@ -210,6 +213,9 @@
<File
RelativePath=".\w32\compat\dirent.c">
</File>
<File
RelativePath=".\w32\compat\posixfcn.c">
</File>
<File
RelativePath=".\w32\subproc\misc.c">
<FileConfiguration

View File

@@ -396,6 +396,8 @@ extern int unixy_shell;
#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. */

View File

@@ -22,7 +22,10 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include <assert.h>
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
@@ -32,6 +35,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#ifdef WINDOWS32
# include <windows.h>
# include <io.h>
# include "sub_proc.h"
#endif /* WINDOWS32 */
@@ -92,10 +96,8 @@ _outputs (struct output *out, int is_err, const char *msg)
while (1)
{
EINTRLOOP (r, write (fd, msg, len));
if (r == len)
if (r == len || r <= 0)
break;
if (r <= 0)
return;
len -= r;
msg += r;
}
@@ -106,7 +108,7 @@ _outputs (struct output *out, int is_err, const char *msg)
left (according to ENTERING) the current directory. */
static int
log_working_directory (struct output *out, int entering)
log_working_directory (int entering)
{
static char *buf = NULL;
static unsigned int len = 0;
@@ -168,7 +170,7 @@ log_working_directory (struct output *out, int entering)
else
sprintf (p, fmt, program, makelevel, starting_directory);
_outputs (out, 0, buf);
_outputs (NULL, 0, buf);
return 1;
}
@@ -387,7 +389,7 @@ output_dump (struct output *out)
/* Log the working directory for this dump. */
if (print_directory_flag && output_sync != OUTPUT_SYNC_RECURSE)
traced = log_working_directory (output_context, 1);
traced = log_working_directory (1);
if (outfd_not_empty)
pump_from_tmp (out->out, stdout);
@@ -395,7 +397,7 @@ output_dump (struct output *out)
pump_from_tmp (out->err, stderr);
if (traced)
log_working_directory (output_context, 0);
log_working_directory (0);
/* Exit the critical section. */
if (sem)
@@ -558,7 +560,7 @@ output_close (struct output *out)
if (! out)
{
if (stdio_traced)
log_working_directory (NULL, 0);
log_working_directory (0);
return;
}
@@ -579,15 +581,17 @@ void
output_start ()
{
#ifndef NO_OUTPUT_SYNC
if (output_context && output_context->syncout && ! OUTPUT_ISSET(output_context))
setup_tmpfile (output_context);
/* 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 (! output_context || output_sync == OUTPUT_SYNC_RECURSE)
{
if (! stdio_traced && print_directory_flag)
stdio_traced = log_working_directory (NULL, 1);
}
/* 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

2
read.c
View File

@@ -1073,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. */

View File

@@ -1,3 +1,33 @@
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

View File

@@ -40,3 +40,5 @@ if ($case_sensitive) {
compare_output("It chose Makefile\n",&get_logfile(1));
unlink("Makefile");
}
1;

View File

@@ -43,10 +43,10 @@ unlink('inc.mk');
# Or Red Hat bug https://bugzilla.redhat.com/show_bug.cgi?id=885474
open(MAKEFILE,"> Makefile2");
print MAKEFILE <<EOF;
vpath %.c $ENV{HOME}/
print MAKEFILE '
vpath %.c ../
foo:
EOF
';
close(MAKEFILE);
run_make_test(q!

View File

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

View File

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

View File

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

View File

@@ -23,4 +23,20 @@ all: ; @echo $(MAKEFLAGS)
echo erR --trace --no-print-directory
erR --trace --no-print-directory");
# Verify that re-exec / recursion doesn't duplicate flags from GNUMAKEFLAGS
unlink('x.mk');
$extraENV{GNUMAKEFLAGS} = '-Itst/bad -Oline';
run_make_test(q!
recurse: ; @echo $@; echo MAKEFLAGS = $$MAKEFLAGS; echo GNUMAKEFLAGS = $$GNUMAKEFLAGS; #MAKEPATH# -f #MAKEFILE# all
all: ; @echo $@; echo MAKEFLAGS = $$MAKEFLAGS; echo GNUMAKEFLAGS = $$GNUMAKEFLAGS
-include x.mk
x.mk: ; @echo $@; echo MAKEFLAGS = $$MAKEFLAGS; echo GNUMAKEFLAGS = $$GNUMAKEFLAGS; echo > $@
!,
"", "x.mk\nMAKEFLAGS = -Itst/bad -Oline\nGNUMAKEFLAGS =\nrecurse\nMAKEFLAGS = -Itst/bad -Oline\nGNUMAKEFLAGS =\n#MAKE#[1]: Entering directory '#PWD#'\nall\nMAKEFLAGS = w -Itst/bad -Oline\nGNUMAKEFLAGS =\n#MAKE#[1]: Leaving directory '#PWD#'\n");
unlink('x.mk');
1;

View File

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

View File

@@ -202,7 +202,7 @@ sub toplevel
print "\n";
&run_each_test;
run_all_tests();
foreach $dir (@rmdirs)
{
@@ -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
@@ -713,7 +718,6 @@ sub compare_output
&run_command_with_output(&get_difffile,$command);
}
$suite_passed = 0;
return 0;
}

View File

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

View File

@@ -26,7 +26,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include "makeint.h"
#include "job.h"
#ifdef OUTPUT_SYNC
#ifndef NO_OUTPUT_SYNC
/* Support for OUTPUT_SYNC and related functionality. */
/* Emulation of fcntl that supports only F_GETFD and F_SETLKW. */
@@ -40,106 +40,106 @@ fcntl (intptr_t fd, int cmd, ...)
switch (cmd)
{
case F_GETFD:
va_end (ap);
/* Could have used GetHandleInformation, but that isn't
supported on Windows 9X. */
if (_get_osfhandle (fd) == -1)
return -1;
return 0;
va_end (ap);
/* Could have used GetHandleInformation, but that isn't
supported on Windows 9X. */
if (_get_osfhandle (fd) == -1)
return -1;
return 0;
case F_SETLKW:
{
void *buf = va_arg (ap, void *);
struct flock *fl = (struct flock *)buf;
HANDLE hmutex = (HANDLE)fd;
static struct flock last_fl;
short last_type = last_fl.l_type;
{
void *buf = va_arg (ap, void *);
struct flock *fl = (struct flock *)buf;
HANDLE hmutex = (HANDLE)fd;
static struct flock last_fl;
short last_type = last_fl.l_type;
va_end (ap);
va_end (ap);
if (hmutex == INVALID_HANDLE_VALUE || !hmutex)
return -1;
if (hmutex == INVALID_HANDLE_VALUE || !hmutex)
return -1;
last_fl = *fl;
last_fl = *fl;
switch (fl->l_type)
{
switch (fl->l_type)
{
case F_WRLCK:
{
DWORD result;
case F_WRLCK:
{
DWORD result;
if (last_type == F_WRLCK)
{
/* Don't call WaitForSingleObject if we already
own the mutex, because doing so will require
us to call ReleaseMutex an equal number of
times, before the mutex is actually
released. */
return 0;
}
if (last_type == F_WRLCK)
{
/* Don't call WaitForSingleObject if we already
own the mutex, because doing so will require
us to call ReleaseMutex an equal number of
times, before the mutex is actually
released. */
return 0;
}
result = WaitForSingleObject (hmutex, INFINITE);
switch (result)
{
case WAIT_OBJECT_0:
/* We don't care if the mutex owner crashed or
exited. */
case WAIT_ABANDONED:
return 0;
case WAIT_FAILED:
case WAIT_TIMEOUT: /* cannot happen, really */
{
DWORD err = GetLastError ();
result = WaitForSingleObject (hmutex, INFINITE);
switch (result)
{
case WAIT_OBJECT_0:
/* We don't care if the mutex owner crashed or
exited. */
case WAIT_ABANDONED:
return 0;
case WAIT_FAILED:
case WAIT_TIMEOUT: /* cannot happen, really */
{
DWORD err = GetLastError ();
/* Invalidate the last command. */
memset (&last_fl, 0, sizeof (last_fl));
/* Invalidate the last command. */
memset (&last_fl, 0, sizeof (last_fl));
switch (err)
{
case ERROR_INVALID_HANDLE:
case ERROR_INVALID_FUNCTION:
errno = EINVAL;
return -1;
default:
errno = EDEADLOCK;
return -1;
}
}
}
}
case F_UNLCK:
{
/* FIXME: Perhaps we should call ReleaseMutex
repatedly until it errors out, to make sure the
mutext is released even if we somehow managed to
to take ownership multiple times? */
BOOL status = ReleaseMutex (hmutex);
switch (err)
{
case ERROR_INVALID_HANDLE:
case ERROR_INVALID_FUNCTION:
errno = EINVAL;
return -1;
default:
errno = EDEADLOCK;
return -1;
}
}
}
}
case F_UNLCK:
{
/* FIXME: Perhaps we should call ReleaseMutex
repatedly until it errors out, to make sure the
mutext is released even if we somehow managed to
to take ownership multiple times? */
BOOL status = ReleaseMutex (hmutex);
if (status)
return 0;
else
{
DWORD err = GetLastError ();
if (status)
return 0;
else
{
DWORD err = GetLastError ();
if (err == ERROR_NOT_OWNER)
errno = EPERM;
else
{
memset (&last_fl, 0, sizeof (last_fl));
errno = EINVAL;
}
return -1;
}
}
default:
errno = ENOSYS;
return -1;
}
}
if (err == ERROR_NOT_OWNER)
errno = EPERM;
else
{
memset (&last_fl, 0, sizeof (last_fl));
errno = EINVAL;
}
return -1;
}
}
default:
errno = ENOSYS;
return -1;
}
}
default:
errno = ENOSYS;
va_end (ap);
return -1;
errno = ENOSYS;
va_end (ap);
return -1;
}
}
@@ -210,54 +210,156 @@ same_stream (FILE *f1, FILE *f2)
&& fh2 && fh2 != INVALID_HANDLE_VALUE)
{
if (fh1 == fh2)
return 1;
return 1;
else
{
DWORD ftyp1 = GetFileType (fh1), ftyp2 = GetFileType (fh2);
{
DWORD ftyp1 = GetFileType (fh1), ftyp2 = GetFileType (fh2);
if (ftyp1 != ftyp2
|| ftyp1 == FILE_TYPE_UNKNOWN || ftyp2 == FILE_TYPE_UNKNOWN)
return 0;
else if (ftyp1 == FILE_TYPE_CHAR)
{
/* For character devices, check if they both refer to a
console. This loses if both handles refer to the
null device (FIXME!), but in that case we don't care
in the context of Make. */
DWORD conmode1, conmode2;
if (ftyp1 != ftyp2
|| ftyp1 == FILE_TYPE_UNKNOWN || ftyp2 == FILE_TYPE_UNKNOWN)
return 0;
else if (ftyp1 == FILE_TYPE_CHAR)
{
/* For character devices, check if they both refer to a
console. This loses if both handles refer to the
null device (FIXME!), but in that case we don't care
in the context of Make. */
DWORD conmode1, conmode2;
/* Each process on Windows can have at most 1 console,
so if both handles are for the console device, they
are the same. We also compare the console mode to
distinguish between 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;
/* Each process on Windows can have at most 1 console,
so if both handles are for the console device, they
are the same. We also compare the console mode to
distinguish between stdin and stdout/stderr. */
if (GetConsoleMode (fh1, &conmode1)
&& GetConsoleMode (fh2, &conmode2)
&& conmode1 == conmode2)
return 1;
}
else
{
/* For disk files and pipes, compare their unique
attributes. */
BY_HANDLE_FILE_INFORMATION bhfi1, bhfi2;
/* Pipes get zero in the volume serial number, but do
appear to have meaningful information in file index
attributes. We test file attributes as well, for a
good measure. */
if (GetFileInformationByHandle (fh1, &bhfi1)
&& GetFileInformationByHandle (fh2, &bhfi2))
return (bhfi1.dwVolumeSerialNumber == bhfi2.dwVolumeSerialNumber
&& bhfi1.nFileIndexLow == bhfi2.nFileIndexLow
&& bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh
&& bhfi1.dwFileAttributes == bhfi2.dwFileAttributes);
}
}
/* Pipes get zero in the volume serial number, but do
appear to have meaningful information in file index
attributes. We test file attributes as well, for a
good measure. */
if (GetFileInformationByHandle (fh1, &bhfi1)
&& GetFileInformationByHandle (fh2, &bhfi2))
return (bhfi1.dwVolumeSerialNumber == bhfi2.dwVolumeSerialNumber
&& bhfi1.nFileIndexLow == bhfi2.nFileIndexLow
&& bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh
&& bhfi1.dwFileAttributes == bhfi2.dwFileAttributes);
}
}
}
return 0;
}
#endif /* OUTPUT_SYNC */
/* A replacement for tmpfile, since the MSVCRT implementation creates
the file in the root directory of the current drive, which might
not be writable by our user. Most of the code borrowed from
create_batch_file, see job.c. */
FILE *
tmpfile (void)
{
char temp_path[MAXPATHLEN];
unsigned path_size = GetTempPath (sizeof temp_path, temp_path);
int path_is_dot = 0;
/* The following variable is static so we won't try to reuse a name
that was generated a little while ago, because that file might
not be on disk yet, since we use FILE_ATTRIBUTE_TEMPORARY below,
which tells the OS it doesn't need to flush the cache to disk.
If the file is not yet on disk, we might think the name is
available, while it really isn't. This happens in parallel
builds, where Make doesn't wait for one job to finish before it
launches the next one. */
static unsigned uniq = 0;
static int second_loop = 0;
const char base[] = "gmake_tmpf";
const unsigned sizemax = sizeof base - 1 + 4 + 10 + 10;
unsigned pid = GetCurrentProcessId ();
if (path_size == 0)
{
path_size = GetCurrentDirectory (sizeof temp_path, temp_path);
path_is_dot = 1;
}
++uniq;
if (uniq >= 0x10000 && !second_loop)
{
/* If we already had 64K batch files in this
process, make a second loop through the numbers,
looking for free slots, i.e. files that were
deleted in the meantime. */
second_loop = 1;
uniq = 1;
}
while (path_size > 0 &&
path_size + sizemax < sizeof temp_path &&
!(uniq >= 0x10000 && second_loop))
{
HANDLE h;
sprintf (temp_path + path_size,
"%s%s%u-%x.tmp",
temp_path[path_size - 1] == '\\' ? "" : "\\",
base, pid, uniq);
h = CreateFile (temp_path, /* file name */
GENERIC_READ | GENERIC_WRITE | DELETE, /* desired access */
FILE_SHARE_READ | FILE_SHARE_WRITE, /* share mode */
NULL, /* default security attributes */
CREATE_NEW, /* creation disposition */
FILE_ATTRIBUTE_NORMAL | /* flags and attributes */
FILE_ATTRIBUTE_TEMPORARY |
FILE_FLAG_DELETE_ON_CLOSE,
NULL); /* no template file */
if (h == INVALID_HANDLE_VALUE)
{
const DWORD er = GetLastError ();
if (er == ERROR_FILE_EXISTS || er == ERROR_ALREADY_EXISTS)
{
++uniq;
if (uniq == 0x10000 && !second_loop)
{
second_loop = 1;
uniq = 1;
}
}
/* The temporary path is not guaranteed to exist, or might
not be writable by user. Use the current directory as
fallback. */
else if (path_is_dot == 0)
{
path_size = GetCurrentDirectory (sizeof temp_path, temp_path);
path_is_dot = 1;
}
else
{
errno = EACCES;
break;
}
}
else
{
int fd = _open_osfhandle ((intptr_t)h, 0);
return _fdopen (fd, "w+b");
}
}
if (uniq >= 0x10000)
errno = EEXIST;
return NULL;
}
#endif /* !NO_OUTPUT_SYNC */
#if MAKE_LOAD
@@ -286,8 +388,8 @@ dlopen (const char *file, int mode)
/* MSDN says to be sure to use backslashes in the DLL file name. */
strcpy (dllfn, file);
for (p = dllfn; *p; p++)
if (*p == '/')
*p = '\\';
if (*p == '/')
*p = '\\';
dllhandle = LoadLibrary (dllfn);
}
@@ -307,8 +409,8 @@ dlerror (void)
return NULL;
ret = FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, last_err, 0, errbuf, sizeof (errbuf), NULL);
| FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, last_err, 0, errbuf, sizeof (errbuf), NULL);
while (ret > 0 && (errbuf[ret - 1] == '\n' || errbuf[ret - 1] == '\r'))
--ret;
@@ -350,5 +452,5 @@ dlclose (void *handle)
}
#endif /* MAKE_LOAD */
#endif /* MAKE_LOAD */

View File

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