Compare commits

...

9 Commits
3.99.93 ... 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
22 changed files with 591 additions and 324 deletions

View File

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

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.

4
NEWS
View File

@@ -1,6 +1,6 @@
GNU make NEWS -*-indented-text-*-
History of user-visible changes.
1 Oct 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.93
Version 4.0 (09 Oct 2013)
A complete list of bugs fixed in this version is available here:

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

View File

@@ -11115,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
@@ -11140,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
@@ -11184,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);
}
@@ -1949,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
@@ -2001,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] = '.';
@@ -2018,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
}
@@ -2437,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;
@@ -2522,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);
@@ -2543,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
@@ -60,14 +61,19 @@ GMK_EXPORT char *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.
*/
GMK_EXPORT void 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_ */

View File

@@ -115,7 +115,7 @@ internal_guile_eval (void *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;
@@ -140,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;
}

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);
}

7
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;
}
}

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

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

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,18 @@
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

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

@@ -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

@@ -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 /* !NO_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(