mirror of
https://salsa.debian.org/srivasta/make-dfsg.git
synced 2024-12-25 05:29:47 +00:00
* Fix up and document $(apply ...) function.
This commit is contained in:
parent
adb1632033
commit
9d89ad56bf
9 changed files with 181 additions and 121 deletions
16
ChangeLog
16
ChangeLog
|
@ -1,3 +1,12 @@
|
||||||
|
1999-07-15 Paul D. Smith <psmith@gnu.org>
|
||||||
|
|
||||||
|
* function.c (func_apply): Various code cleanup and tightening.
|
||||||
|
(function_table): Add "apply" as a valid builtin function.
|
||||||
|
|
||||||
|
* make.texinfo (Apply Function): Document it.
|
||||||
|
|
||||||
|
* NEWS: Announce it.
|
||||||
|
|
||||||
1999-07-09 Paul D. Smith <psmith@gnu.org>
|
1999-07-09 Paul D. Smith <psmith@gnu.org>
|
||||||
|
|
||||||
* job.c (start_waiting_job): Don't get a second job token if we
|
* job.c (start_waiting_job): Don't get a second job token if we
|
||||||
|
@ -227,7 +236,12 @@
|
||||||
|
|
||||||
* function.c: Rewrite to use one C function per make function,
|
* function.c: Rewrite to use one C function per make function,
|
||||||
instead of a huge switch statement. Also allows some cleanup of
|
instead of a huge switch statement. Also allows some cleanup of
|
||||||
multi-architecture issues.
|
multi-architecture issues, and a cleaner API which makes things
|
||||||
|
like func_apply() simple.
|
||||||
|
|
||||||
|
* function.c (func_apply): Initial implementation. Expand either
|
||||||
|
a builtin function or a make variable in the context of some
|
||||||
|
arguments, provided as $1, $2, ... $N.
|
||||||
|
|
||||||
1999-03-19 Eli Zaretskii <eliz@is.elta.co.il>
|
1999-03-19 Eli Zaretskii <eliz@is.elta.co.il>
|
||||||
1999-03-19 Rob Tulloh <rob_tulloh@dev.tivoli.com>
|
1999-03-19 Rob Tulloh <rob_tulloh@dev.tivoli.com>
|
||||||
|
|
7
NEWS
7
NEWS
|
@ -18,6 +18,11 @@ Version 3.78
|
||||||
causes the text provided to be printed as a warning message, but make
|
causes the text provided to be printed as a warning message, but make
|
||||||
proceeds normally.
|
proceeds normally.
|
||||||
|
|
||||||
|
* A new function, $(apply ...) is provided. This allows users to create
|
||||||
|
their own parameterized macros and invoke them later. This
|
||||||
|
implementation of this feature was provided by Han-Wen Nienhuys
|
||||||
|
<hanwen@cs.uu.nl>.
|
||||||
|
|
||||||
* Make defines a new variable, .LIBPATTERNS. This variable controls how
|
* Make defines a new variable, .LIBPATTERNS. This variable controls how
|
||||||
library dependency expansion (dependencies like ``-lfoo'') is performed.
|
library dependency expansion (dependencies like ``-lfoo'') is performed.
|
||||||
|
|
||||||
|
@ -29,7 +34,7 @@ Version 3.78
|
||||||
LD, AR, etc.). Specifying this option forces -r (--no-builtin-rules)
|
LD, AR, etc.). Specifying this option forces -r (--no-builtin-rules)
|
||||||
as well.
|
as well.
|
||||||
|
|
||||||
* A "job server" feature, proposed by Howard Chu <hyc@highlandsun.com>.
|
* A "job server" feature, suggested by Howard Chu <hyc@highlandsun.com>.
|
||||||
|
|
||||||
On systems that support POSIX pipe(2) semantics, GNU make can now pass
|
On systems that support POSIX pipe(2) semantics, GNU make can now pass
|
||||||
-jN options to submakes rather than forcing them all to use -j1. The
|
-jN options to submakes rather than forcing them all to use -j1. The
|
||||||
|
|
3
dep.h
3
dep.h
|
@ -38,8 +38,7 @@ struct dep
|
||||||
struct dep *next;
|
struct dep *next;
|
||||||
char *name;
|
char *name;
|
||||||
struct file *file;
|
struct file *file;
|
||||||
unsigned short changed;
|
int changed;
|
||||||
unsigned short deferred; /* Only used in update_goal_chain(). */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
3
file.c
3
file.c
|
@ -348,6 +348,8 @@ in favor of those for `%s'.",
|
||||||
/* %%% Kludge so -W wins on a file that gets vpathized. */
|
/* %%% Kludge so -W wins on a file that gets vpathized. */
|
||||||
oldfile->last_mtime = file->last_mtime;
|
oldfile->last_mtime = file->last_mtime;
|
||||||
|
|
||||||
|
oldfile->mtime_before_update = file->mtime_before_update;
|
||||||
|
|
||||||
#define MERGE(field) oldfile->field |= file->field
|
#define MERGE(field) oldfile->field |= file->field
|
||||||
MERGE (precious);
|
MERGE (precious);
|
||||||
MERGE (tried_implicit);
|
MERGE (tried_implicit);
|
||||||
|
@ -468,6 +470,7 @@ snap_deps ()
|
||||||
/* Mark this file as phony and nonexistent. */
|
/* Mark this file as phony and nonexistent. */
|
||||||
f2->phony = 1;
|
f2->phony = 1;
|
||||||
f2->last_mtime = (FILE_TIMESTAMP) -1;
|
f2->last_mtime = (FILE_TIMESTAMP) -1;
|
||||||
|
f2->mtime_before_update = (FILE_TIMESTAMP) -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (f = lookup_file (".INTERMEDIATE"); f != 0; f = f->prev)
|
for (f = lookup_file (".INTERMEDIATE"); f != 0; f = f->prev)
|
||||||
|
|
|
@ -35,6 +35,8 @@ struct file
|
||||||
rule has been used */
|
rule has been used */
|
||||||
struct dep *also_make; /* Targets that are made by making this. */
|
struct dep *also_make; /* Targets that are made by making this. */
|
||||||
FILE_TIMESTAMP last_mtime; /* File's modtime, if already known. */
|
FILE_TIMESTAMP last_mtime; /* File's modtime, if already known. */
|
||||||
|
FILE_TIMESTAMP mtime_before_update; /* File's modtime before any updating
|
||||||
|
has been performed. */
|
||||||
struct file *prev; /* Previous entry for same file name;
|
struct file *prev; /* Previous entry for same file name;
|
||||||
used when there are multiple double-colon
|
used when there are multiple double-colon
|
||||||
entries for the same file. */
|
entries for the same file. */
|
||||||
|
|
147
function.c
147
function.c
|
@ -1719,130 +1719,83 @@ func_if (char* o, char **argv, char *funcname)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* This might not be very useful, but the code was simple to
|
/* User-defined functions. Expand the first argument as either a builtin
|
||||||
implement, I just had to do it.
|
function or a make variable, in the context of the rest of the arguments
|
||||||
|
assigned to $1, $2, ... $N. $0 is the name of the function. */
|
||||||
|
|
||||||
Here goes anyway
|
|
||||||
|
|
||||||
Apply & User defined functions.
|
|
||||||
|
|
||||||
SYNTAX
|
|
||||||
|
|
||||||
$(apply funcname, arg1, arg2, .. )
|
|
||||||
|
|
||||||
SEMANTICS
|
|
||||||
|
|
||||||
You can specify a builtin function, for funcname, eg
|
|
||||||
|
|
||||||
f = addprefix
|
|
||||||
$(apply addprefix,a, b c d)
|
|
||||||
|
|
||||||
This will result in
|
|
||||||
|
|
||||||
ab ac ad
|
|
||||||
|
|
||||||
You can specify your own functions, eg
|
|
||||||
|
|
||||||
funcname=BODY
|
|
||||||
|
|
||||||
BODY contains $(1) .. $(N) as argument markers.
|
|
||||||
upon expansions the strings ARG1 .. ARGN are substituted for $(1) .. $(N)
|
|
||||||
into BODY
|
|
||||||
|
|
||||||
Because the funcname is computed as well you can combine this do some
|
|
||||||
funky things, eg
|
|
||||||
|
|
||||||
map=$(foreach a, $(2), $(apply $(1), $(a)))
|
|
||||||
|
|
||||||
|
|
||||||
LIMITATIONS.
|
|
||||||
|
|
||||||
Make has no support for nested lists (or tuples), so you can't do
|
|
||||||
stuff like (Haskell notation):
|
|
||||||
|
|
||||||
f :: (a,b) -> c -- type of F
|
|
||||||
map :: (a->b) -> [a] -> b -- type of MAP
|
|
||||||
|
|
||||||
map f [(1,2), (2,3)] -- map F over list containing (1,2) and (2,3)
|
|
||||||
|
|
||||||
to get
|
|
||||||
|
|
||||||
[f (1, 2), f (2, 3)]
|
|
||||||
|
|
||||||
|
|
||||||
If only we had nested lists and quotes, we could duplicate LISP in make by
|
|
||||||
transforming
|
|
||||||
|
|
||||||
$(a, b, c) <-> (a b c)
|
|
||||||
$(quote $(a, b, c)) <-> '(a b c)
|
|
||||||
|
|
||||||
(or something alike ;-) (We could have automatic integration of
|
|
||||||
GUILE and make :-)
|
|
||||||
|
|
||||||
[Actually -- why should this be a joke? If we could somehow integrate the
|
|
||||||
rules and targets into a functional model make could be a lot cleaner in
|
|
||||||
concept. ]
|
|
||||||
|
|
||||||
*/
|
|
||||||
char *
|
char *
|
||||||
func_apply (o, argv, funcname)
|
func_apply (o, argv, funcname)
|
||||||
char *o;
|
char *o;
|
||||||
char **argv;
|
char **argv;
|
||||||
const char *funcname;
|
const char *funcname;
|
||||||
{
|
{
|
||||||
char *userfunc_name;
|
char *fname;
|
||||||
int func_len;
|
int flen;
|
||||||
char *body = 0;
|
char *body;
|
||||||
char *expanded_body = 0;
|
|
||||||
int i;
|
int i;
|
||||||
const struct function_table_entry *entry_p;
|
const struct function_table_entry *entry_p;
|
||||||
|
|
||||||
userfunc_name = argv[0];
|
/* Applying nothing is a no-op. */
|
||||||
while (isspace (*userfunc_name))
|
if (*argv[0] == '\0')
|
||||||
++userfunc_name;
|
return o;
|
||||||
|
|
||||||
entry_p = lookup_function (function_table, userfunc_name);
|
/* There is no way to define a variable with a space in the name, so strip
|
||||||
|
trailing whitespace as a favor to the user. */
|
||||||
|
|
||||||
|
flen = strlen (argv[0]);
|
||||||
|
fname = argv[0] + flen - 1;
|
||||||
|
while (isspace (*fname))
|
||||||
|
--fname;
|
||||||
|
fname[1] = '\0';
|
||||||
|
|
||||||
|
flen = fname - argv[0] + 1;
|
||||||
|
fname = argv[0];
|
||||||
|
|
||||||
|
/* Are we invoking a builtin function? */
|
||||||
|
|
||||||
|
entry_p = lookup_function (function_table, fname);
|
||||||
|
|
||||||
/* builtin function? */
|
|
||||||
if (entry_p)
|
if (entry_p)
|
||||||
{
|
{
|
||||||
for (i=0; argv[i+1]; i++)
|
for (i=0; argv[i+1]; ++i)
|
||||||
;
|
;
|
||||||
|
|
||||||
o = expand_builtin_function (o, i, argv + 1, entry_p);
|
return expand_builtin_function (o, i, argv + 1, entry_p);
|
||||||
return o;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func_len = strlen (userfunc_name);
|
/* No, so the first argument is the name of a variable to be expanded and
|
||||||
body = xmalloc (func_len + 4);
|
interpreted as a function. Create the variable reference. */
|
||||||
strcpy (body + 2, userfunc_name);
|
body = alloca (flen + 4);
|
||||||
body [func_len+2]=')';
|
body[0]='$';
|
||||||
body [func_len+3]= 0;
|
body[1]='(';
|
||||||
body [1]='(';
|
strcpy (body + 2, fname);
|
||||||
body [0]='$';
|
body[flen+2]=')';
|
||||||
|
body[flen+3]= '\0';
|
||||||
|
|
||||||
|
/* Set up arguments $(1) .. $(N). $(0) is the function name. */
|
||||||
|
|
||||||
push_new_variable_scope ();
|
push_new_variable_scope ();
|
||||||
|
|
||||||
/* set up arguments $(1) .. $(N) */
|
for (i=0; *argv; ++i, ++argv)
|
||||||
for (i=0; argv[i]; i++)
|
|
||||||
{
|
{
|
||||||
char num[10];
|
char num[11];
|
||||||
struct variable* var;
|
|
||||||
sprintf (num, "%d", i);
|
sprintf (num, "%d", i);
|
||||||
var = define_variable (num, strlen (num), argv[i], o_automatic, 0);
|
define_variable (num, strlen (num), *argv, o_automatic, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
expanded_body = allocated_variable_expand (body);
|
/* Expand the body in the context of the arguments, adding the result to
|
||||||
o = variable_buffer_output (o, expanded_body, strlen (expanded_body));
|
the variable buffer. */
|
||||||
free (expanded_body);
|
|
||||||
|
o = variable_expand_string (o, body, flen+3);
|
||||||
|
|
||||||
pop_variable_scope ();
|
pop_variable_scope ();
|
||||||
|
|
||||||
free (body);
|
return o + strlen(o);
|
||||||
return o;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define STRING_SIZE_TUPLE(s) (s), (sizeof(s)-1)
|
#define STRING_SIZE_TUPLE(_s) (_s), (sizeof(_s)-1)
|
||||||
|
|
||||||
/* Lookup table for builtin functions.
|
/* Lookup table for builtin functions.
|
||||||
|
|
||||||
|
@ -1851,7 +1804,7 @@ func_apply (o, argv, funcname)
|
||||||
table.
|
table.
|
||||||
|
|
||||||
REQUIRED_ARGUMENTS is the minimum number of arguments. A function
|
REQUIRED_ARGUMENTS is the minimum number of arguments. A function
|
||||||
can have more, but they will be ignored.
|
can have more, but if they have less an error will be generated.
|
||||||
|
|
||||||
EXPAND_ALL_ARGUMENTS means that all arguments should be expanded
|
EXPAND_ALL_ARGUMENTS means that all arguments should be expanded
|
||||||
before invocation. Functions that do namespace tricks (foreach)
|
before invocation. Functions that do namespace tricks (foreach)
|
||||||
|
@ -1881,11 +1834,11 @@ static struct function_table_entry function_table[] =
|
||||||
{ STRING_SIZE_TUPLE("wordlist"), 3, 1, func_wordlist},
|
{ STRING_SIZE_TUPLE("wordlist"), 3, 1, func_wordlist},
|
||||||
{ STRING_SIZE_TUPLE("words"), 1, 1, func_words},
|
{ STRING_SIZE_TUPLE("words"), 1, 1, func_words},
|
||||||
{ STRING_SIZE_TUPLE("origin"), 1, 1, func_origin},
|
{ STRING_SIZE_TUPLE("origin"), 1, 1, func_origin},
|
||||||
|
{ STRING_SIZE_TUPLE("foreach"), 3, 0, func_foreach},
|
||||||
|
{ STRING_SIZE_TUPLE("apply"), 1, 1, func_apply},
|
||||||
{ STRING_SIZE_TUPLE("error"), 1, 1, func_error},
|
{ STRING_SIZE_TUPLE("error"), 1, 1, func_error},
|
||||||
{ STRING_SIZE_TUPLE("warning"), 1, 1, func_error},
|
{ STRING_SIZE_TUPLE("warning"), 1, 1, func_error},
|
||||||
{ STRING_SIZE_TUPLE("foreach"), 3, 0, func_foreach},
|
|
||||||
#ifdef EXPERIMENTAL
|
#ifdef EXPERIMENTAL
|
||||||
{ STRING_SIZE_TUPLE("apply"), 1, 1, func_apply},
|
|
||||||
{ STRING_SIZE_TUPLE("eq"), 2, 1, func_eq},
|
{ STRING_SIZE_TUPLE("eq"), 2, 1, func_eq},
|
||||||
{ STRING_SIZE_TUPLE("if"), 3, 0, func_if},
|
{ STRING_SIZE_TUPLE("if"), 3, 0, func_if},
|
||||||
{ STRING_SIZE_TUPLE("not"), 1, 1, func_not},
|
{ STRING_SIZE_TUPLE("not"), 1, 1, func_not},
|
||||||
|
|
4
main.c
4
main.c
|
@ -1358,7 +1358,7 @@ int main (int argc, char ** argv)
|
||||||
for (p = old_files->list; *p != 0; ++p)
|
for (p = old_files->list; *p != 0; ++p)
|
||||||
{
|
{
|
||||||
f = enter_command_line_file (*p);
|
f = enter_command_line_file (*p);
|
||||||
f->last_mtime = (FILE_TIMESTAMP) 1;
|
f->last_mtime = f->mtime_before_update = (FILE_TIMESTAMP) 1;
|
||||||
f->updated = 1;
|
f->updated = 1;
|
||||||
f->update_status = 0;
|
f->update_status = 0;
|
||||||
f->command_state = cs_finished;
|
f->command_state = cs_finished;
|
||||||
|
@ -1369,7 +1369,7 @@ int main (int argc, char ** argv)
|
||||||
for (p = new_files->list; *p != 0; ++p)
|
for (p = new_files->list; *p != 0; ++p)
|
||||||
{
|
{
|
||||||
f = enter_command_line_file (*p);
|
f = enter_command_line_file (*p);
|
||||||
f->last_mtime = NEW_MTIME;
|
f->last_mtime = f->mtime_before_update = NEW_MTIME;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
100
make.texinfo
100
make.texinfo
|
@ -269,6 +269,7 @@ Functions for Transforming Text
|
||||||
* Text Functions:: General-purpose text manipulation functions.
|
* Text Functions:: General-purpose text manipulation functions.
|
||||||
* File Name Functions:: Functions for manipulating file names.
|
* File Name Functions:: Functions for manipulating file names.
|
||||||
* Foreach Function:: Repeat some text with controlled variation.
|
* Foreach Function:: Repeat some text with controlled variation.
|
||||||
|
* Apply Function:: Expand a user-defined function.
|
||||||
* Origin Function:: Find where a variable got its value.
|
* Origin Function:: Find where a variable got its value.
|
||||||
* Shell Function:: Substitute the output of a shell command.
|
* Shell Function:: Substitute the output of a shell command.
|
||||||
|
|
||||||
|
@ -5199,6 +5200,7 @@ call, just as a variable might be substituted.
|
||||||
* Text Functions:: General-purpose text manipulation functions.
|
* Text Functions:: General-purpose text manipulation functions.
|
||||||
* File Name Functions:: Functions for manipulating file names.
|
* File Name Functions:: Functions for manipulating file names.
|
||||||
* Foreach Function:: Repeat some text with controlled variation.
|
* Foreach Function:: Repeat some text with controlled variation.
|
||||||
|
* Apply Function:: Expand a user-defined function.
|
||||||
* Origin Function:: Find where a variable got its value.
|
* Origin Function:: Find where a variable got its value.
|
||||||
* Shell Function:: Substitute the output of a shell command.
|
* Shell Function:: Substitute the output of a shell command.
|
||||||
* Make Control Functions:: Functions that control how make runs.
|
* Make Control Functions:: Functions that control how make runs.
|
||||||
|
@ -5224,8 +5226,9 @@ or like this:
|
||||||
$@{@var{function} @var{arguments}@}
|
$@{@var{function} @var{arguments}@}
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
Here @var{function} is a function name; one of a short list of names that
|
Here @var{function} is a function name; one of a short list of names
|
||||||
are part of @code{make}. There is no provision for defining new functions.
|
that are part of @code{make}. You can also essentially create your own
|
||||||
|
functions by using the @code{apply} builtin function.
|
||||||
|
|
||||||
The @var{arguments} are the arguments of the function. They are
|
The @var{arguments} are the arguments of the function. They are
|
||||||
separated from the function name by one or more spaces or tabs, and if
|
separated from the function name by one or more spaces or tabs, and if
|
||||||
|
@ -5746,7 +5749,7 @@ that match the pattern.
|
||||||
@xref{Wildcards, ,Using Wildcard Characters in File Names}.
|
@xref{Wildcards, ,Using Wildcard Characters in File Names}.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@node Foreach Function, Origin Function, File Name Functions, Functions
|
@node Foreach Function, Apply Function, File Name Functions, Functions
|
||||||
@section The @code{foreach} Function
|
@section The @code{foreach} Function
|
||||||
@findex foreach
|
@findex foreach
|
||||||
@cindex words, iterating over
|
@cindex words, iterating over
|
||||||
|
@ -5834,7 +5837,96 @@ might be useful if the value of @code{find_files} references the variable
|
||||||
whose name is @samp{Esta escrito en espanol!} (es un nombre bastante largo,
|
whose name is @samp{Esta escrito en espanol!} (es un nombre bastante largo,
|
||||||
no?), but it is more likely to be a mistake.
|
no?), but it is more likely to be a mistake.
|
||||||
|
|
||||||
@node Origin Function, Shell Function, Foreach Function, Functions
|
@node Apply Function, Origin Function, Foreach Function, Functions
|
||||||
|
@section The @code{apply} Function
|
||||||
|
@findex apply
|
||||||
|
@cindex functions, user defined
|
||||||
|
@cindex user defined functions
|
||||||
|
|
||||||
|
The @code{apply} function is unique in that it can be used to create new
|
||||||
|
parameterized functions. You can write a complex expression as the
|
||||||
|
value of a variable, then use @code{apply} to expand it with different
|
||||||
|
values.
|
||||||
|
|
||||||
|
The syntax of the @code{apply} function is:
|
||||||
|
|
||||||
|
@example
|
||||||
|
$(apply @var{variable}, @var{param}, @var{param}, @dots{})
|
||||||
|
@end example
|
||||||
|
|
||||||
|
When @code{make} expands this function, it assigns each @var{param} to
|
||||||
|
temporary variables @var{$(1)}, @var{$(2)}, etc. The variable
|
||||||
|
@var{$(0)} will contain @var{variable}. There is no maximum number of
|
||||||
|
parameter arguments. There is no minimum, either, but it doesn't make
|
||||||
|
sense to use @code{apply} with no parameters.
|
||||||
|
|
||||||
|
Then @var{variable} is expanded as a @code{make} variable in the context
|
||||||
|
of these temporary assignments. Thus, any reference to @var{$(1)} in
|
||||||
|
the value of @var{variable} will resolve to the first @var{param} in the
|
||||||
|
invocation of @code{apply}.
|
||||||
|
|
||||||
|
Note that @var{variable} is the @emph{name} of a variable, not a
|
||||||
|
@emph{reference} to that variable. Therefore you would not normally use
|
||||||
|
a @samp{$} or parentheses when writing it. (You can, however, use a
|
||||||
|
variable reference in the name if you want the name not to be a
|
||||||
|
constant.)
|
||||||
|
|
||||||
|
If @var{variable} is the name of a builtin function, the builtin function
|
||||||
|
is always invoked (even if a @code{make} variable by that name also
|
||||||
|
exists).
|
||||||
|
|
||||||
|
Some examples may make this clearer.
|
||||||
|
|
||||||
|
This macro simply reverses its arguments:
|
||||||
|
|
||||||
|
@smallexample
|
||||||
|
reverse = $2 $1
|
||||||
|
|
||||||
|
foo = a b
|
||||||
|
bar = $(apply reverse,$(foo))
|
||||||
|
@end smallexample
|
||||||
|
|
||||||
|
@noindent
|
||||||
|
Here @var{bar} will contain @samp{b a}.
|
||||||
|
|
||||||
|
This one is slightly more interesting: it defines a macro to search for
|
||||||
|
the first instance of a program in @code{PATH}:
|
||||||
|
|
||||||
|
@smallexample
|
||||||
|
pathsearch = $(firstword $(wildcard $(addsufix /$1,$(subst :, ,$(PATH)))))
|
||||||
|
|
||||||
|
LS := $(apply pathsearch,ls)
|
||||||
|
@end smallexample
|
||||||
|
|
||||||
|
@noindent
|
||||||
|
Now the variable LS contains @code{/bin/ls} or similar.
|
||||||
|
|
||||||
|
The @code{apply} function can be nested. Each recursive invocation gets
|
||||||
|
its own local values for @var{$(1)}, etc. that mask the values of
|
||||||
|
higher-level @code{apply}. For example, here is an implementation of a
|
||||||
|
@dfn{map} function:
|
||||||
|
|
||||||
|
@smallexample
|
||||||
|
map = $(foreach a,$2,$(apply $1,$a))
|
||||||
|
@end smallexample
|
||||||
|
|
||||||
|
Now you can @var{map} a function that normally takes only one argument,
|
||||||
|
such as @code{origin}, to multiple values in one step:
|
||||||
|
|
||||||
|
@smallexample
|
||||||
|
o = $(apply map,origin,o map MAKE)
|
||||||
|
@end smallexample
|
||||||
|
|
||||||
|
and end up with @var{o} containing something like @samp{file file default}.
|
||||||
|
|
||||||
|
A final caution: be careful when adding whitespace to the arguments to
|
||||||
|
@code{apply}. As with other functions, any whitespace contained in the
|
||||||
|
second and subsequent arguments is kept; this can cause strange
|
||||||
|
effects. It's generally safest to remove all extraneous whitespace when
|
||||||
|
defining variables for use with @code{apply}.
|
||||||
|
|
||||||
|
|
||||||
|
@node Origin Function, Shell Function, Apply Function, Functions
|
||||||
@section The @code{origin} Function
|
@section The @code{origin} Function
|
||||||
@findex origin
|
@findex origin
|
||||||
@cindex variables, origin of
|
@cindex variables, origin of
|
||||||
|
|
20
remake.c
20
remake.c
|
@ -94,7 +94,7 @@ update_goal_chain (goals, makefiles)
|
||||||
|
|
||||||
struct dep *g;
|
struct dep *g;
|
||||||
for (g = goals; g != 0; g = g->next)
|
for (g = goals; g != 0; g = g->next)
|
||||||
g->changed = g->deferred = 0;
|
g->changed = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -134,7 +134,6 @@ update_goal_chain (goals, makefiles)
|
||||||
{
|
{
|
||||||
unsigned int ocommands_started;
|
unsigned int ocommands_started;
|
||||||
int x;
|
int x;
|
||||||
FILE_TIMESTAMP mtime = MTIME (file);
|
|
||||||
check_renamed (file);
|
check_renamed (file);
|
||||||
if (makefiles)
|
if (makefiles)
|
||||||
{
|
{
|
||||||
|
@ -161,16 +160,6 @@ update_goal_chain (goals, makefiles)
|
||||||
decide when to give an "up to date" diagnostic. */
|
decide when to give an "up to date" diagnostic. */
|
||||||
g->changed += commands_started - ocommands_started;
|
g->changed += commands_started - ocommands_started;
|
||||||
|
|
||||||
/* Set the goal's `deferred' flag if we started a command but
|
|
||||||
it didn't finish (parallel builds). We need to remember
|
|
||||||
this, because the next time through the goal chain the call
|
|
||||||
to reap_children() will set the mtime, not the call to
|
|
||||||
update_file() above. So, the saved mtime from before
|
|
||||||
update_file() will be the same as the mtime after it, and
|
|
||||||
we'll think nothing changed when it did (see below). */
|
|
||||||
if (file->command_state == cs_running)
|
|
||||||
g->deferred = 1;
|
|
||||||
|
|
||||||
stop = 0;
|
stop = 0;
|
||||||
if (x != 0 || file->updated)
|
if (x != 0 || file->updated)
|
||||||
{
|
{
|
||||||
|
@ -191,7 +180,8 @@ update_goal_chain (goals, makefiles)
|
||||||
stop = (!keep_going_flag && !question_flag
|
stop = (!keep_going_flag && !question_flag
|
||||||
&& !makefiles);
|
&& !makefiles);
|
||||||
}
|
}
|
||||||
else if (MTIME (file) != mtime || g->deferred)
|
else if (file->updated && g->changed &&
|
||||||
|
file->last_mtime != file->mtime_before_update)
|
||||||
{
|
{
|
||||||
/* Updating was done. If this is a makefile and
|
/* Updating was done. If this is a makefile and
|
||||||
just_print_flag or question_flag is set
|
just_print_flag or question_flag is set
|
||||||
|
@ -199,7 +189,6 @@ update_goal_chain (goals, makefiles)
|
||||||
specified as a command-line target), don't
|
specified as a command-line target), don't
|
||||||
change STATUS. If STATUS is changed, we will
|
change STATUS. If STATUS is changed, we will
|
||||||
get re-exec'd, and fall into an infinite loop. */
|
get re-exec'd, and fall into an infinite loop. */
|
||||||
g->deferred = 0;
|
|
||||||
if (!makefiles
|
if (!makefiles
|
||||||
|| (!just_print_flag && !question_flag))
|
|| (!just_print_flag && !question_flag))
|
||||||
status = 0;
|
status = 0;
|
||||||
|
@ -736,6 +725,9 @@ notice_finished_file (file)
|
||||||
{
|
{
|
||||||
struct file *f;
|
struct file *f;
|
||||||
|
|
||||||
|
assert(file->mtime_before_update == 0);
|
||||||
|
file->mtime_before_update = file->last_mtime;
|
||||||
|
|
||||||
if (just_print_flag || question_flag
|
if (just_print_flag || question_flag
|
||||||
|| (file->is_target && file->cmds == 0))
|
|| (file->is_target && file->cmds == 0))
|
||||||
file->last_mtime = NEW_MTIME;
|
file->last_mtime = NEW_MTIME;
|
||||||
|
|
Loading…
Reference in a new issue