- Fix bug #1405: allow multiple pattern-specific variables to match a target.

- Fix some uncleanliness about the implementation of patterns-specific vars.
- Some enhancements to the OS/2 port.
This commit is contained in:
Paul Smith 2003-05-02 01:44:59 +00:00
parent 652234e967
commit 1a5beef51f
24 changed files with 552 additions and 206 deletions

View File

@ -1,3 +1,60 @@
2003-04-30 Paul D. Smith <psmith@gnu.org>
* build.template: Make some changes to maybe allow this script to
work on DOS/Windows/OS2 systems. Suggested by Andreas Buening.
* README.OS2.template: New file for OS/2 support. Original
contributed by Andreas Buening.
* configure.in: Invoke new pds_AC_DOS_PATHS macro to test for
DOS-style paths.
2003-04-19 Paul D. Smith <psmith@gnu.org>
Fix bug #1405: allow a target to match multiple pattern-specific
variables.
* rule.c (create_pattern_var, lookup_pattern_var): Move these to
variable.c, where they've always belonged.
* rule.h: Move the prototypes and struct pattern_var as well.
* variable.c (initialize_file_variables): Invoke
lookup_pattern_var() in a loop, until no more matches are found.
If a match is found, create a new variable set for the target's
pattern variables. Then merge the contents of each matching
pattern variable set into the target's pattern variable set.
(lookup_pattern_var): Change this function to be usable
in a loop. It takes a starting position: if NULL, start at the
beginning; if non-NULL, start with the pattern variable after that
position, and return the next matching pattern.
(create_pattern_var): Create a unique instance of
pattern-specific variables for every definition in the makefile.
Don't combine the same pattern together. This allows us to
process the variable handling properly even when the same pattern
is used multiple times.
(parse_variable_definition): New function: break out the parsing
of a variable definition line from try_variable_definition.
(try_variable_definition): Call parse_variable_definition to
parse.
(print_variable_data_base): Print out pattern-specific variables.
* variable.h (struct variable): Remember when a variable is
conditional. Also remember its flavor.
(struct pattern_var): Instead of keeping a variable set, we just
keep a single variable for each pattern.
* read.c (record_target_var): Each pattern variable contains only a
single variable, not a set, so create it properly.
* doc/make.texi (Pattern-specific): Document the new behavior.
2003-04-17 Paul D. Smith <psmith@gnu.org>
* dir.c (file_exists_p) [VMS]: Patch provided with Bug #3018 by
Jean-Pierre Portier <portierjp2@free.fr>. I don't understand the
file/directory naming rules for VMS so I can't tell whether this
is correct or not.
2003-04-09 Paul D. Smith <psmith@gnu.org>
* configure.in (HAVE_DOS_PATHS): Define this on systems that need
DOS-style pathnames: backslash separators and drive specifiers.
2003-03-28 Paul D. Smith <psmith@gnu.org>
* file.c (snap_deps): If .SECONDARY with no targets is given, set

View File

@ -38,12 +38,12 @@ AM_CPPFLAGS = $(GLOBINC)
# because often that directory isn't built on the systems used by the
# maintainers.
EXTRA_DIST = README build.sh.in $(man_MANS)\
README.customs\
SCOPTIONS SMakefile\
README.Amiga Makefile.ami config.ami make.lnk amiga.c amiga.h\
EXTRA_DIST = README build.sh.in $(man_MANS) \
README.customs README.OS2 \
SCOPTIONS SMakefile \
README.Amiga Makefile.ami config.ami make.lnk amiga.c amiga.h \
README.DOS Makefile.DOS configure.bat dosbuild.bat configh.dos\
README.W32 NMakefile config.h.W32 build_w32.bat subproc.bat\
README.W32 NMakefile config.h.W32 build_w32.bat subproc.bat \
readme.vms makefile.vms makefile.com config.h-vms \
vmsdir.h vmsfunctions.c vmsify.c

21
NEWS
View File

@ -1,8 +1,8 @@
GNU make NEWS -*-indented-text-*-
History of user-visible changes.
03 October 2002
17 April 2003
Copyright (C) 2002 Free Software Foundation, Inc.
Copyright (C) 2002,2003 Free Software Foundation, Inc.
See the end for copying conditions.
All changes mentioned here are more fully described in the GNU make
@ -12,7 +12,22 @@ Please send GNU make bug reports to <bug-make@gnu.org>.
See the README file and the GNU make manual for details on sending bug
reports.
Version 3.81a1
Version 3.81a2
* GNU make is ported to OS/2.
Port provided by Andreas Buening <andreas.buening@nexgo.de>.
* All pattern-specific variables that match a given target are now used
(previously only the first match was used).
* Target-specific variables can be marked as exportable using the
"export" keyword.
* In a recursive $(call ...) context, any extra arguments from the outer
call are now masked in the context of the inner call.
* Enhancements for POSIX compatibility:
- Only touch targets (under -t) if they have at least one command.
Version 3.80

159
README.OS2.template Normal file
View File

@ -0,0 +1,159 @@
Port of GNU make to OS/2.
Features of GNU make that do not work under OS/2:
- remote job execution
- dynamic load balancing
Special features of the OS/2 version:
Due to the fact that some people might want to use sh syntax in
Makefiles while others might want to use OS/2's native shell cmd.exe,
GNU make supports both shell types. The following list defines the order
that is used to determine the shell:
1. The shell specified by the environment variable MAKESHELL.
2. The shell specified by the SHELL variable within a Makefile. As on
Unix, SHELL is NOT taken from the environment.
3. The shell specified by the COMSPEC environment variable.
4. The shell specified by the OS2_SHELL environment variable.
5. If none of the above is defined /bin/sh is used as default. This
happens e.g. in the make testsuite.
Note: - Points 3 and 4 can be turned off at compile time by adding
-DNO_CMD_DEFAULT to the CPPFLAGS.
- DOS support is not tested for EMX and therefore might not work.
- The UNIXROOT environment variable is supported to find /bin/sh
if it is not on the current drive.
COMPILATION OF GNU MAKE FOR OS/2:
I. ***** SPECIAL OPTIONS *****
- At compile time you can turn off that cmd is used as default shell
(but only /bin/sh). Simply set CPPFLAGS="-DNO_CMD_DEFAULT" and make
will not use cmd unless you cause it to do so by setting MAKESHELL to
cmd or by specifying SHELL=cmd in your Makefile.
- At compile time you can set CPPFLAGS="-DNO_CHDIR2" to turn off that
GNU make prints drive letters. This is necessary if you want to run
the testsuite.
II. ***** REQUIREMENTS FOR THE COMPILATION *****
A standard Unix like build environment:
- sh compatible shell (ksh, bash, ash, but tested only with pdksh 5.2.14
(release 2)
If you use pdksh it is recommended to update to 5.2.14 release 2. Older
versions may not work! You can get this version at
http://www.math.ohio-state.edu/~ilya/software/os2/pdksh-5.2.14-bin-2.zip
- GNU file utilities (make sure that install.exe from the file utilities
is in front of your PATH before X:\OS2\INSTALL\INSTALL.EXE. I recommend
also to change the filename to ginstall.exe instead of install.exe
to avoid confusion with X:\OS2\INSTALL\INSTALL.EXE)
- GNU shell utilities
- GNU text utilities
- gawk
- grep
- sed
- GNU make 3.79.1 (special OS/2 patched version)
- perl 5.005 or higher
- GNU texinfo (you can use 3.1 (gnuinfo.zip), but I recommend 4.0)
If you want to recreate the configuration files (developers only!)
you need also: GNU m4 1.4, autoconf 2.57, automake 1.7.2 (or compatible)
III. ***** COMPILATION AND INSTALLATION *****
a) ** Developers only - Everyone else should skip this section **
To recreate the configuration files use:
export EMXSHELL=ksh
aclocal -I config
automake
autoconf
autoheader
b) Installation into x:/usr
Note: Although it is possible to compile make using "./configure",
"make", "make install" this is not recommended. In particular,
you must ALWAYS use LDFLAGS="-Zstack 0x8000" because the default
stack size is far to small and make will not work properly!
Recommended environment variables and installation options:
export ac_executable_extensions=".exe"
export CPPFLAGS="-D__ST_MT_ERRNO__"
export CFLAGS="-O2 -Zomf -Zmt"
export LDFLAGS="-Zcrtdll -Zlinker /exepack:2 -Zlinker /pm:vio -Zstack 0x8000"
export RANLIB="echo"
./configure --prefix=x:/usr --infodir=x:/usr/share/info --mandir=x:/usr/share/man --without-included-gettext
make AR=emxomfar
make install
Note: If you use gcc 2.9.x or higher I recommend to set also LIBS="-lgcc"
Note: You can add -DNO_CMD_DEFAULT and -DNO_CHDIR2 to CPPFLAGS.
See section I. for details.
IV. ***** NLS support *****
GNU make has NLS (National Language Support), with the following
caveats:
a) It will only work with GNU gettext, and
b) GNU gettext support is not included in the GNU make package.
Therefore, if you wish to enable the internationalization features of
GNU make you must install GNU gettext on your system before configuring
GNU make.
You can choose the languages to be installed. To install support for
English, German and French only enter:
export LINGUAS="en de fr"
If you don't specify LINGUAS all languages are installed.
If you don't want NLS support (English only) use the option
--disable-nls for the configure script. Note if GNU gettext is not
installed then NLS will not be enabled regardless of this flag.
V. ***** Running the make test suite *****
To run the included make test suite you have to set
CPPFLAGS="-D__ST_MT_ERRNO__ -DNO_CMD_DEFAULT -DNO_CHDIR2"
before you compile make. This is due to some restrictions of the
testsuite itself. -DNO_CMD_DEFAULT causes make to use /bin/sh as default
shell in every case. Normally you could simply set MAKESHELL="/bin/sh"
to do this but the testsuite ignores the environment. -DNO_CHDIR2 causes
make not to use drive letters for directory names (i.e. _chdir2() and
_getcwd2() are NOT used). The testsuite interpretes the whole output of
make, especially statements like make[1]: Entering directory
`C:/somewhere/make-3.79.1/tests' where the testsuite does not expect the
drive letter. This would be interpreted as an error even if there is
none.
To run the testsuite do the following:
export CPPFLAGS="-D__ST_MT_ERRNO__ -DNO_CMD_DEFAULT -DNO_CHDIR2"
export CFLAGS="-Zomf -O2 -s -Zmt"
export LDFLAGS="-Zcrtdll -Zmt -s -Zlinker /exepack:2 -Zlinker /pm:vio -Zstack 0x8000"
export RANLIB="echo"
./configure --prefix=x:/usr --disable-nls
make AR=emxomfar
make checks
All tests should work fine with the exception of "default_names" which
is because OS/2 file systems are not case sensitive ("makefile" and
"Makefile" specify the same file).

View File

@ -48,6 +48,9 @@ to the point where you can run "make".
Use wget to retrieve various other files that GNU make relies on,
but does not keep in its own source tree.
NB: You may need GNU make to correctly perform this step; if you use
a platform-local make you may get problems with missing files in doc/.
At this point you have successfully brought your CVS copy of the GNU
make source directory up to the point where it can be treated

View File

@ -2,7 +2,7 @@
# Shell script to build GNU Make in the absence of any `make' program.
# @configure_input@
# Copyright (C) 1993, 1994, 1997 Free Software Foundation, Inc.
# Copyright (C) 1993, 1994, 1997, 2003 Free Software Foundation, Inc.
# This file is part of GNU Make.
#
# GNU Make is free software; you can redistribute it and/or modify
@ -29,9 +29,12 @@ CPPFLAGS='@CPPFLAGS@'
LDFLAGS='@LDFLAGS@'
ALLOCA='@ALLOCA@'
LOADLIBES='@LIBS@'
extras='@LIBOBJS@'
eval extras=\'@LIBOBJS@\'
REMOTE='@REMOTE@'
GLOBLIB='@GLOBLIB@'
PATH_SEPARATOR='@PATH_SEPARATOR@'
OBJEXT='@OBJEXT@'
EXEEXT='@EXEEXT@'
# Common prefix for machine-independent installed files.
prefix='@prefix@'
@ -43,7 +46,7 @@ libdir=${exec_prefix}/lib
includedir=${prefix}/include
localedir=${prefix}/share/locale
aliaspath=${localedir}:.
aliaspath=${localedir}${PATH_SEPARATOR}.
defines="-DALIASPATH=\"${aliaspath}\" -DLOCALEDIR=\"${localedir}\" -DLIBDIR=\"${libdir}\" -DINCLUDEDIR=\"${includedir}\""' @DEFS@'
@ -51,7 +54,7 @@ defines="-DALIASPATH=\"${aliaspath}\" -DLOCALEDIR=\"${localedir}\" -DLIBDIR=\"${
set -e
# These are all the objects we need to link together.
objs="%objs% remote-${REMOTE}.o ${extras} ${ALLOCA}"
objs="%objs% remote-${REMOTE}.${OBJEXT} ${extras} ${ALLOCA}"
if [ x"$GLOBLIB" != x ]; then
objs="$objs %globobjs%"
@ -59,7 +62,7 @@ if [ x"$GLOBLIB" != x ]; then
fi
# Compile the source files into those objects.
for file in `echo ${objs} | sed 's/\.o/.c/g'`; do
for file in `echo ${objs} | sed 's/\.'${OBJEXT}'/.c/g'`; do
echo compiling ${file}...
$CC $defines $CPPFLAGS $CFLAGS \
-c -I. -I${srcdir} ${globinc} ${srcdir}/$file
@ -75,6 +78,6 @@ done
# Link all the objects together.
echo linking make...
$CC $LDFLAGS $objs $LOADLIBES -o make.new
$CC $LDFLAGS $objs $LOADLIBES -o makenew${EXEEXT}
echo done
mv -f make.new make
mv -f makenew${EXEEXT} make${EXEEXT}

View File

@ -1,3 +1,8 @@
2003-04-30 Paul D. Smith <psmith@gnu.org>
* dospaths.m4: New macro to test for DOS-style pathnames, based on
coreutils 5.0 "dos.m4" by Jim Meyering.
2002-04-21 gettextize <bug-gnu-gettext@gnu.org>
* codeset.m4: New file, from gettext-0.11.1.

21
config/dospaths.m4 Normal file
View File

@ -0,0 +1,21 @@
# Test if the system uses DOS-style pathnames (drive specs and backslashes)
# By Paul Smith <psmith@gnu.org>. Based on dos.m4 by Jim Meyering.
AC_DEFUN([pds_AC_DOS_PATHS],
[
AC_CACHE_CHECK([whether system uses MSDOS-style paths], [ac_cv_dos_paths],
[
AC_COMPILE_IFELSE([
#if !defined _WIN32 && !defined __WIN32__ && !defined __MSDOS__ && !defined __EMX__
neither MSDOS nor Windows nor OS2
#endif
],
[ac_cv_dos_paths=yes],
[ac_cv_dos_paths=no])
])
if test x"$ac_cv_dos_paths" = xyes; then
AC_DEFINE_UNQUOTED([HAVE_DOS_PATHS], 1,
[Define if the system uses DOS-style pathnames.])
fi
])

View File

@ -103,6 +103,8 @@ if test "$make_cv_file_timestamp_hi_res" = yes; then
fi
fi
# Check for DOS-style pathnames.
pds_AC_DOS_PATHS
# See if we have a standard version of gettimeofday(). Since actual
# implementations can differ, just make sure we have the most common
@ -192,6 +194,13 @@ fi
AC_MSG_RESULT($make_cv_union_wait)
# If we're building on Windows/DOS/OS/2, add some support for DOS drive specs.
if test "$PATH_SEPARATOR" = ';'; then
AC_DEFINE(HAVE_DOS_PATHS, 1,
[Define this if your system requires backslashes or drive specs in pathnames.])
fi
# See if the user wants to use pmake's "customs" distributed build capability
AC_SUBST(REMOTE) REMOTE=stub

View File

@ -18,12 +18,12 @@ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "make.h"
#include "filedef.h"
#include "variable.h"
#include "rule.h"
#include "dep.h"
#include "filedef.h"
#include "job.h"
#include "commands.h"
#include "variable.h"
/* Define GCC_IS_NATIVE if gcc is the native development environment on
your system (gcc/bison/flex vs cc/yacc/lex). */

6
dir.c
View File

@ -590,7 +590,8 @@ dir_contents_file_exists_p (struct directory_contents *dir, char *filename)
#endif
#ifdef __EMX__
_fnlwr(filename); /* lower case for FAT drives */
if (filename != 0)
_fnlwr (filename); /* lower case for FAT drives */
#endif
#ifdef VMS
@ -736,8 +737,7 @@ file_exists_p (char *name)
dirend = strrchr (name, ']');
if (dirend == 0)
dirend = strrchr (name, ':');
dirend++;
if (dirend == (char *)1)
if (dirend == (char *)0)
return dir_file_exists_p ("[]", name);
#else /* !VMS */
dirend = strrchr (name, '/');

View File

@ -5245,13 +5245,16 @@ command scripts that create @file{prog.o}, @file{foo.o}, and
@cindex pattern-specific variables
@cindex variables, pattern-specific
In addition to target-specific variable values (@pxref{Target-specific,
,Target-specific Variable Values}), GNU @code{make} supports
pattern-specific variable values. In this form, a variable is defined
for any target that matches the pattern specified. Variables defined in
this way are searched after any target-specific variables defined
explicitly for that target, and before target-specific variables defined
for the parent target.
In addition to target-specific variable values
(@pxref{Target-specific, ,Target-specific Variable Values}), GNU
@code{make} supports pattern-specific variable values. In this form,
the variable is defined for any target that matches the pattern
specified. If a target matches more than one pattern, all the
matching pattern-specific variables are interpreted in the order in
which they were defined in the makefile, and collected together into
one set. Variables defined in this way are searched after any
target-specific variables defined explicitly for that target, and
before target-specific variables defined for the parent target.
Set a pattern-specific variable value like this:

View File

@ -681,9 +681,9 @@ func_words (char *o, char **argv, const char *funcname)
static char *
strip_whitespace (const char **begpp, const char **endpp)
{
while (isspace ((unsigned char)**begpp) && *begpp <= *endpp)
while (*begpp <= *endpp && isspace ((unsigned char)**begpp))
(*begpp) ++;
while (isspace ((unsigned char)**endpp) && *endpp >= *begpp)
while (*endpp >= *begpp && isspace ((unsigned char)**endpp))
(*endpp) --;
return (char *)*begpp;
}

View File

@ -18,9 +18,9 @@ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "make.h"
#include "filedef.h"
#include "rule.h"
#include "dep.h"
#include "filedef.h"
#include "debug.h"
static int pattern_search PARAMS ((struct file *file, int archive, unsigned int depth,

13
job.c
View File

@ -104,7 +104,7 @@ static int amiga_batch_file;
#endif /* WINDOWS32 */
#ifdef __EMX__
# include <sys/file.h>
# include <process.h>
#endif
#if defined (HAVE_SYS_WAIT_H) || defined (HAVE_UNION_WAIT)
@ -2507,9 +2507,9 @@ exec_command (char **argv, char **envp)
# ifdef __EMX__
/* Do not use $SHELL from the environment */
shell = lookup_variable ("SHELL", 5);
if (shell)
shell = shell->value;
struct variable *p = lookup_variable ("SHELL", 5);
if (p)
shell = p->value;
else
shell = 0;
# else
@ -2756,11 +2756,9 @@ construct_command_argv_internal (char *line, char **restp, char *shell,
DB (DB_BASIC, (_("$SHELL changed (was `%s', now `%s')\n"),
default_shell, shell));
unixy_shell = _is_unixy_shell (shell);
default_shell = shell;
/* we must allocate a copy of shell: construct_command_argv() will free
* shell after this function returns. */
default_shell = xmalloc (strlen (shell) + 1);
strcpy (default_shell, shell);
default_shell = xstrdup (shell);
}
if (unixy_shell)
{
@ -2778,6 +2776,7 @@ construct_command_argv_internal (char *line, char **restp, char *shell,
sh_cmds = sh_cmds_os2;
}
# endif
}
#else /* !__MSDOS__ */
else if (strcmp (shell, default_shell))
goto slow;

View File

@ -8,7 +8,7 @@
globsrc := $(wildcard glob/*.c)
globhdr := $(wildcard glob/*.h)
TEMPLATES = README README.DOS README.W32 \
TEMPLATES = README README.DOS README.W32 README.OS2 \
config.ami configh.dos config.h.W32 config.h-vms
MTEMPLATES = Makefile.DOS SMakefile
@ -54,8 +54,8 @@ NMakefile: NMakefile.template .dep_segment Makefile
#
build.sh.in: build.template Makefile
rm -f $@
sed -e 's@%objs%@$(filter-out remote-%,$(make_OBJECTS)@g' \
-e 's@%globobjs%@$(patsubst %.c,%.o,$(globsrc)))@g' \
sed -e 's@%objs%@$(patsubst %.o,%.$${OBJEXT},$(filter-out remote-%,$(make_OBJECTS)))@g' \
-e 's@%globobjs%@$(patsubst %.c,%.$${OBJEXT},$(globsrc)))@g' \
$< > $@
chmod a-w+x $@

36
read.c
View File

@ -1667,9 +1667,9 @@ record_target_var (struct nameseq *filenames, char *defn, int two_colon,
{
struct variable *v;
register char *name = filenames->name;
struct variable_set_list *vlist;
char *fname;
char *percent;
struct pattern_var *p;
nextf = filenames->next;
free ((char *) filenames);
@ -1679,11 +1679,13 @@ record_target_var (struct nameseq *filenames, char *defn, int two_colon,
percent = find_percent (name);
if (percent)
{
struct pattern_var *p;
/* Get a reference for this pattern-specific variable struct. */
p = create_pattern_var(name, percent);
vlist = p->vars;
p = create_pattern_var (name, percent);
p->variable.fileinfo = *flocp;
v = parse_variable_definition (&p->variable, defn);
v->value = xstrdup (v->value);
if (!v)
error (flocp, _("Malformed pattern-specific variable definition"));
fname = p->target;
}
else
@ -1701,15 +1703,17 @@ record_target_var (struct nameseq *filenames, char *defn, int two_colon,
f = f->double_colon;
initialize_file_variables (f, 1);
vlist = f->variables;
fname = f->name;
current_variable_set_list = f->variables;
v = try_variable_definition (flocp, defn, origin, 1);
if (!v)
error (flocp, _("Malformed target-specific variable definition"));
current_variable_set_list = global;
}
/* Make the new variable context current and define the variable. */
current_variable_set_list = vlist;
v = try_variable_definition (flocp, defn, origin, 1);
if (!v)
error (flocp, _("Malformed per-target variable definition"));
/* Set up the variable to be *-specific. */
v->origin = origin;
v->per_target = 1;
if (exported)
v->export = v_export;
@ -1721,12 +1725,14 @@ record_target_var (struct nameseq *filenames, char *defn, int two_colon,
struct variable *gv;
int len = strlen(v->name);
current_variable_set_list = global;
gv = lookup_variable (v->name, len);
if (gv && (gv->origin == o_env_override || gv->origin == o_command))
{
v = define_variable_in_set (v->name, len, gv->value, gv->origin,
gv->recursive, vlist->set, flocp);
if (v->value != 0)
free (v->value);
v->value = xstrdup (gv->value);
v->origin = gv->origin;
v->recursive = gv->recursive;
v->append = 0;
}
}
@ -1735,8 +1741,6 @@ record_target_var (struct nameseq *filenames, char *defn, int two_colon,
if (name != fname && (name < fname || name > fname + strlen (fname)))
free (name);
}
current_variable_set_list = global;
}
/* Record a description line for files FILENAMES,

100
rule.c
View File

@ -51,14 +51,6 @@ unsigned int max_pattern_deps;
unsigned int max_pattern_dep_length;
/* Chain of all pattern-specific variables. */
static struct pattern_var *pattern_vars;
/* Pointer to last struct in the chain, so we can add onto the end. */
static struct pattern_var *last_pattern_var;
/* Pointer to structure for the file .SUFFIXES
whose dependencies are the suffixes to be searched. */
@ -537,76 +529,6 @@ create_pattern_rule (char **targets, char **target_percents,
r->terminal = terminal;
}
/* Create a new pattern-specific variable struct. */
struct pattern_var *
create_pattern_var (char *target, char *suffix)
{
register struct pattern_var *p = 0;
unsigned int len = strlen(target);
/* Look to see if this pattern already exists in the list. */
for (p = pattern_vars; p != NULL; p = p->next)
if (p->len == len && !strcmp(p->target, target))
break;
if (p == 0)
{
p = (struct pattern_var *) xmalloc (sizeof (struct pattern_var));
if (last_pattern_var != 0)
last_pattern_var->next = p;
else
pattern_vars = p;
last_pattern_var = p;
p->next = 0;
p->target = target;
p->len = len;
p->suffix = suffix + 1;
p->vars = create_new_variable_set();
}
return p;
}
/* Look up a target in the pattern-specific variable list. */
struct pattern_var *
lookup_pattern_var (char *target)
{
struct pattern_var *p;
unsigned int targlen = strlen(target);
for (p = pattern_vars; p != 0; p = p->next)
{
char *stem;
unsigned int stemlen;
if (p->len > targlen)
/* It can't possibly match. */
continue;
/* From the lengths of the filename and the pattern parts,
find the stem: the part of the filename that matches the %. */
stem = target + (p->suffix - p->target - 1);
stemlen = targlen - p->len + 1;
/* Compare the text in the pattern before the stem, if any. */
if (stem > target && !strneq (p->target, target, stem - target))
continue;
/* Compare the text in the pattern after the stem, if any.
We could test simply using streq, but this way we compare the
first two characters immediately. This saves time in the very
common case where the first character matches because it is a
period. */
if (*p->suffix == stem[stemlen]
&& (*p->suffix == '\0' || streq (&p->suffix[1], &stem[stemlen+1])))
break;
}
return p;
}
/* Print the data base of rules. */
static void /* Useful to call from gdb. */
@ -678,26 +600,4 @@ print_rule_data_base (void)
fatal (NILF, _("BUG: num_pattern_rules wrong! %u != %u"),
num_pattern_rules, rules);
}
puts (_("\n# Pattern-specific variable values"));
{
struct pattern_var *p;
rules = 0;
for (p = pattern_vars; p != 0; p = p->next)
{
++rules;
printf ("\n%s :\n", p->target);
print_variable_set (p->vars->set, "# ");
}
if (rules == 0)
puts (_("\n# No pattern-specific variable values."));
else
{
printf (_("\n# %u pattern-specific variable values"), rules);
}
}
}

11
rule.h
View File

@ -31,15 +31,6 @@ struct rule
char in_use; /* If in use by a parent pattern_search. */
};
struct pattern_var
{
struct pattern_var *next;
char *target;
unsigned int len;
char *suffix;
struct variable_set_list *vars;
};
/* For calling install_pattern_rule. */
struct pspec
{
@ -61,8 +52,6 @@ extern unsigned int maxsuffix;
extern void install_pattern_rule PARAMS ((struct pspec *p, int terminal));
extern int new_pattern_rule PARAMS ((struct rule *rule, int override));
extern struct pattern_var *create_pattern_var PARAMS ((char *target, char *suffix));
extern struct pattern_var *lookup_pattern_var PARAMS ((char *target));
extern void count_implicit_rule_limits PARAMS ((void));
extern void convert_to_pattern PARAMS ((void));
extern void create_pattern_rule PARAMS ((char **targets,

View File

@ -1,3 +1,14 @@
2003-04-19 Paul D. Smith <psmith@gnu.org>
* scripts/features/patspecific_vars: Test multiple patterns
matching the same target--Bug #1405.
2003-04-09 Paul D. Smith <psmith@gnu.org>
* run_make_tests.pl (set_more_defaults): A new $port_type of
'OS/2' for (surprise!) OS/2. Also choose a wait time of 2 seconds
for OS/2.
2003-03-28 Paul D. Smith <psmith@gnu.org>
* scripts/targets/SECONDARY: Test the "global" .SECONDARY (with

View File

@ -169,6 +169,10 @@ sub set_more_defaults
elsif ($osname =~ /^([^ ]*|[^ ]* [^ ]*)D(OS|os|ev) /) {
$port_type = 'DOS';
}
# Check for OS/2
elsif ($osname =~ m%OS/2%) {
$port_type = 'OS/2';
}
# Everything else, right now, is UNIX. Note that we should integrate
# the VOS support into this as well and get rid of $vos; we'll do
# that next time.
@ -180,7 +184,7 @@ sub set_more_defaults
# timestamps with second granularity (!!). Change the sleep time
# needed to force a file to be considered "old".
#
$wtime = $port_type eq 'UNIX' ? 1 : 4;
$wtime = $port_type eq 'UNIX' ? 1 : $port_type eq 'OS/2' ? 2 : 4;
# Find the full pathname of Make. For DOS systems this is more
# complicated, so we ask make itself.

View File

@ -13,14 +13,22 @@ all: one.x two.x three.x
FOO = foo
BAR = bar
BAZ = baz
thr% : override BAZ = three
t%.x: BAR = four
%.x: BAR = two
%.x: override BAZ = three
one.x: override FOO = one
one.x two.x three.x: ; @echo $(FOO) $(BAR) $(BAZ)
four.x: baz ; @echo $(FOO) $(BAR) $(BAZ)
baz: ; @echo $(FOO) $(BAR) $(BAZ)
%.x: BAR = two
t%.x: BAR = four
thr% : override BAZ = three
one.x two.x three.x: ; @echo $@: $(FOO) $(BAR) $(BAZ)
four.x: baz ; @echo $@: $(FOO) $(BAR) $(BAZ)
baz: ; @echo $@: $(FOO) $(BAR) $(BAZ)
# test matching multiple patterns
a%: AAA = aaa
%b: BBB = ccc
a%: BBB += ddd
%b: AAA ?= xxx
%b: AAA += bbb
.PHONY: ab
ab: ; @echo $(AAA); echo $(BBB)
EOF
close(MAKEFILE);
@ -29,21 +37,28 @@ close(MAKEFILE);
# TEST #1 -- basics
&run_make_with_options($makefile, "", &get_logfile);
$answer = "one two three\nfoo four baz\nfoo bar three\n";
$answer = "one.x: one two baz\ntwo.x: foo four baz\nthree.x: foo four three\n";
&compare_output($answer,&get_logfile(1));
# TEST #2 -- try the override feature
&run_make_with_options($makefile, "BAZ=five", &get_logfile);
$answer = "one two three\nfoo four five\nfoo bar three\n";
$answer = "one.x: one two five\ntwo.x: foo four five\nthree.x: foo four three\n";
&compare_output($answer,&get_logfile(1));
# TEST #3 -- make sure patterns are inherited properly
&run_make_with_options($makefile, "four.x", &get_logfile);
$answer = "foo two three\nfoo two three\n";
$answer = "baz: foo two baz\nfour.x: foo two baz\n";
&compare_output($answer,&get_logfile(1));
# TEST #4 -- test multiple patterns matching the same target
&run_make_with_options($makefile, "ab", &get_logfile);
$answer = "aaa bbb\nccc ddd\n";
&compare_output($answer,&get_logfile(1));
1;

View File

@ -30,6 +30,75 @@ Boston, MA 02111-1307, USA. */
#endif
#include "hash.h"
/* Chain of all pattern-specific variables. */
static struct pattern_var *pattern_vars;
/* Pointer to last struct in the chain, so we can add onto the end. */
static struct pattern_var *last_pattern_var;
/* Create a new pattern-specific variable struct. */
struct pattern_var *
create_pattern_var (char *target, char *suffix)
{
register struct pattern_var *p
= (struct pattern_var *) xmalloc (sizeof (struct pattern_var));
if (last_pattern_var != 0)
last_pattern_var->next = p;
else
pattern_vars = p;
last_pattern_var = p;
p->next = 0;
p->target = target;
p->len = strlen (target);
p->suffix = suffix + 1;
return p;
}
/* Look up a target in the pattern-specific variable list. */
static struct pattern_var *
lookup_pattern_var (struct pattern_var *start, char *target)
{
struct pattern_var *p;
unsigned int targlen = strlen(target);
for (p = start ? start->next : pattern_vars; p != 0; p = p->next)
{
char *stem;
unsigned int stemlen;
if (p->len > targlen)
/* It can't possibly match. */
continue;
/* From the lengths of the filename and the pattern parts,
find the stem: the part of the filename that matches the %. */
stem = target + (p->suffix - p->target - 1);
stemlen = targlen - p->len + 1;
/* Compare the text in the pattern before the stem, if any. */
if (stem > target && !strneq (p->target, target, stem - target))
continue;
/* Compare the text in the pattern after the stem, if any.
We could test simply using streq, but this way we compare the
first two characters immediately. This saves time in the very
common case where the first character matches because it is a
period. */
if (*p->suffix == stem[stemlen]
&& (*p->suffix == '\0' || streq (&p->suffix[1], &stem[stemlen+1])))
break;
}
return p;
}
/* Hash table of all global variable definitions. */
static unsigned long
@ -147,6 +216,7 @@ define_variable_in_set (const char *name, unsigned int length,
v->fileinfo.filenm = 0;
v->origin = origin;
v->recursive = recursive;
v->special = 0;
v->expanding = 0;
v->exp_count = 0;
v->per_target = 0;
@ -405,21 +475,33 @@ initialize_file_variables (struct file *file, int reading)
}
/* If we're not reading makefiles and we haven't looked yet, see if
we can find a pattern variable. */
we can find pattern variables for this target. */
if (!reading && !file->pat_searched)
{
struct pattern_var *p = lookup_pattern_var (file->name);
struct pattern_var *p;
file->pat_searched = 1;
p = lookup_pattern_var (0, file->name);
if (p != 0)
{
/* If we found one, insert it between the current target's
variables and the next set, whatever it is. */
file->pat_variables = (struct variable_set_list *)
xmalloc (sizeof (struct variable_set_list));
file->pat_variables->set = p->vars->set;
struct variable_set_list *global = current_variable_set_list;
/* We found at least one. Set up a new variable set to accumulate
all the pattern variables that match this target. */
file->pat_variables = create_new_variable_set ();
current_variable_set_list = file->pat_variables;
do
/* We found one, so insert it into the set. */
do_variable_definition (&p->variable.fileinfo, p->variable.name,
p->variable.value, p->variable.origin,
p->variable.flavor, 1);
while ((p = lookup_pattern_var (p, file->name)) != 0);
current_variable_set_list = global;
}
file->pat_searched = 1;
}
/* If we have a pattern variable match, set it up. */
@ -483,7 +565,7 @@ push_new_variable_scope (void)
return (current_variable_set_list = create_new_variable_set());
}
/* Merge SET1 into SET0, freeing unused storage in SET1. */
/* Merge FROM_SET into TO_SET, freeing unused storage in FROM_SET. */
static void
merge_variable_sets (struct variable_set *to_set,
@ -834,6 +916,7 @@ do_variable_definition (const struct floc *flocp, const char *varname,
char *p, *alloc_value = NULL;
struct variable *v;
int append = 0;
int conditional = 0;
/* Calculate the variable's new value in VALUE. */
@ -857,6 +940,7 @@ do_variable_definition (const struct floc *flocp, const char *varname,
if (v)
return v;
conditional = 1;
flavor = f_recursive;
/* FALLTHROUGH */
case f_recursive:
@ -1034,6 +1118,7 @@ do_variable_definition (const struct floc *flocp, const char *varname,
? current_variable_set_list->set : NULL),
flocp);
v->append = append;
v->conditional = conditional;
if (alloc_value)
free (alloc_value);
@ -1055,16 +1140,14 @@ do_variable_definition (const struct floc *flocp, const char *varname,
returned. */
struct variable *
try_variable_definition (const struct floc *flocp, char *line,
enum variable_origin origin, int target_var)
parse_variable_definition (struct variable *v, char *line)
{
register int c;
register char *p = line;
register char *beg;
register char *end;
enum variable_flavor flavor = f_bogus;
char *name, *expanded_name;
struct variable *v;
char *name;
while (1)
{
@ -1128,29 +1211,62 @@ try_variable_definition (const struct floc *flocp, char *line,
}
}
}
v->flavor = flavor;
beg = next_token (line);
while (end > beg && isblank ((unsigned char)end[-1]))
--end;
p = next_token (p);
v->value = p;
/* Expand the name, so "$(foo)bar = baz" works. */
name = (char *) alloca (end - beg + 1);
bcopy (beg, name, end - beg);
name[end - beg] = '\0';
expanded_name = allocated_variable_expand (name);
v->name = allocated_variable_expand (name);
if (expanded_name[0] == '\0')
fatal (flocp, _("empty variable name"));
v = do_variable_definition (flocp, expanded_name, p,
origin, flavor, target_var);
free (expanded_name);
if (v->name[0] == '\0')
fatal (&v->fileinfo, _("empty variable name"));
return v;
}
/* Try to interpret LINE (a null-terminated string) as a variable definition.
ORIGIN may be o_file, o_override, o_env, o_env_override,
or o_command specifying that the variable definition comes
from a makefile, an override directive, the environment with
or without the -e switch, or the command line.
See the comments for parse_variable_definition().
If LINE was recognized as a variable definition, a pointer to its `struct
variable' is returned. If LINE is not a variable definition, NULL is
returned. */
struct variable *
try_variable_definition (const struct floc *flocp, char *line,
enum variable_origin origin, int target_var)
{
struct variable v;
struct variable *vp;
if (flocp != 0)
v.fileinfo = *flocp;
else
v.fileinfo.filenm = 0;
if (!parse_variable_definition (&v, line))
return 0;
vp = do_variable_definition (flocp, v.name, v.value,
origin, v.flavor, target_var);
free (v.name);
return vp;
}
/* Print information for variable V, prefixing it with PREFIX. */
static void
@ -1246,6 +1362,25 @@ print_variable_data_base (void)
puts (_("\n# Variables\n"));
print_variable_set (&global_variable_set, "");
puts (_("\n# Pattern-specific Variable Values"));
{
struct pattern_var *p;
int rules = 0;
for (p = pattern_vars; p != 0; p = p->next)
{
++rules;
printf ("\n%s :\n", p->target);
print_variable (&p->variable, "# ");
}
if (rules == 0)
puts (_("\n# No pattern-specific variable values."));
else
printf (_("\n# %u pattern-specific variable values"), rules);
}
}

View File

@ -47,7 +47,6 @@ enum variable_flavor
chained through `next'. */
#define EXP_COUNT_BITS 15 /* This gets all the bitfields into 32 bits */
#define EXP_COUNT_MAX ((1<<EXP_COUNT_BITS)-1)
struct variable
@ -57,20 +56,21 @@ struct variable
char *value; /* Variable value. */
struct floc fileinfo; /* Where the variable was defined. */
unsigned int recursive:1; /* Gets recursively re-evaluated. */
unsigned int per_target:1; /* Nonzero if a target-specific variable. */
unsigned int append:1; /* Nonzero if an appending target-specific
variable. */
unsigned int conditional:1; /* Nonzero if set with a ?=. */
unsigned int per_target:1; /* Nonzero if a target-specific variable. */
unsigned int special:1; /* Nonzero if this is a special variable. */
unsigned int exportable:1; /* Nonzero if the variable _could_ be
exported. */
unsigned int expanding:1; /* Nonzero if currently being expanded. */
unsigned int exp_count:EXP_COUNT_BITS;
/* If >1, allow this many self-referential
expansions. */
enum variable_flavor
flavor ENUM_BITFIELD (3); /* Variable flavor. */
enum variable_origin
origin ENUM_BITFIELD (3); /* Variable origin. */
unsigned int exportable:1; /* Nonzero if the variable _could_ be
exported. */
enum variable_export
{
v_export, /* Export this variable. */
@ -95,6 +95,17 @@ struct variable_set_list
struct variable_set *set; /* Variable set. */
};
/* Structure used for pattern-specific variables. */
struct pattern_var
{
struct pattern_var *next;
char *target;
unsigned int len;
char *suffix;
struct variable variable;
};
extern char *variable_buffer;
extern struct variable_set_list *current_variable_set_list;
@ -131,8 +142,9 @@ extern void define_automatic_variables PARAMS ((void));
extern void initialize_file_variables PARAMS ((struct file *file, int read));
extern void print_file_variables PARAMS ((struct file *file));
extern void print_variable_set PARAMS ((struct variable_set *set, char *prefix));
extern void merge_variable_set_lists PARAMS ((struct variable_set_list **setlist0, struct variable_set_list *setlist1));
extern void merge_variable_set_lists PARAMS ((struct variable_set_list **to_list, struct variable_set_list *from_list));
extern struct variable *do_variable_definition PARAMS ((const struct floc *flocp, const char *name, char *value, enum variable_origin origin, enum variable_flavor flavor, int target_var));
extern struct variable *parse_variable_definition PARAMS ((struct variable *v, char *line));
extern struct variable *try_variable_definition PARAMS ((const struct floc *flocp, char *line, enum variable_origin origin, int target_var));
extern void init_hash_global_variable_set PARAMS ((void));
extern void hash_init_function_table PARAMS ((void));
@ -179,6 +191,8 @@ extern struct variable *define_variable_in_set
extern char **target_environment PARAMS ((struct file *file));
extern struct pattern_var *create_pattern_var PARAMS ((char *target, char *suffix));
extern int export_all_variables;
#define MAKELEVEL_NAME "MAKELEVEL"