mirror of
https://github.com/mirror/make.git
synced 2026-08-21 09:23:27 +08:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52191d9d61 | ||
|
|
dc9ae5e017 | ||
|
|
723e047428 | ||
|
|
b69b04dc8c | ||
|
|
b539908f73 | ||
|
|
2fb91e19a0 | ||
|
|
f96c114e22 | ||
|
|
98197303b1 | ||
|
|
f8786092ad |
58
ChangeLog
58
ChangeLog
@@ -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.
|
||||
|
||||
@@ -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
4
NEWS
@@ -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:
|
||||
|
||||
|
||||
@@ -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])
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
61
function.c
61
function.c
@@ -31,7 +31,7 @@ struct function_table_entry
|
||||
{
|
||||
union {
|
||||
char *(*func_ptr) (char *output, char **argv, const char *fname);
|
||||
char *(*alloc_func_ptr) (const char *fname, int argc, char **argv);
|
||||
gmk_func_ptr alloc_func_ptr;
|
||||
} fptr;
|
||||
const char *name;
|
||||
unsigned char len;
|
||||
@@ -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;
|
||||
|
||||
|
||||
20
gnumake.h
20
gnumake.h
@@ -26,6 +26,7 @@ typedef struct
|
||||
unsigned long lineno;
|
||||
} gmk_floc;
|
||||
|
||||
typedef char *(*gmk_func_ptr)(const char *nm, unsigned int argc, char **argv);
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifdef GMK_BUILDING_MAKE
|
||||
@@ -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_ */
|
||||
|
||||
4
guile.c
4
guile.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
7
main.c
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
2
read.c
@@ -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. */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -40,3 +40,5 @@ if ($case_sensitive) {
|
||||
compare_output("It chose Makefile\n",&get_logfile(1));
|
||||
unlink("Makefile");
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
@@ -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!
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -1111,7 +1111,7 @@ done2:
|
||||
|
||||
/*
|
||||
* Description: Clean up any leftover handles, etc. It is up to the
|
||||
* caller to manage and free the input, ouput, and stderr buffers.
|
||||
* caller to manage and free the input, output, and stderr buffers.
|
||||
*/
|
||||
void
|
||||
process_cleanup(
|
||||
|
||||
Reference in New Issue
Block a user