2021-10-11 18:37:13 -03:00

842 lines
25 KiB
C

#ident "@(#)implicit.c 1.1 94/10/31 Copyright 1986,1987,1988 Sun Micro"
/*
* implicit.c
*
* Handle suffix and percent rules
*/
/*
* Included files
*/
#include "defs.h"
#include <sys/file.h>
/*
* Defined macros
*/
/*
* typedefs & structs
*/
/*
* Static variables
*/
/*
* File table of contents
*/
extern Doname find_suffix_rule();
extern Doname find_ar_suffix_rule();
extern Doname find_double_suffix_rule();
extern void build_suffix_list();
extern Doname find_percent_rule();
extern Boolean dependency_exists();
/*
* find_suffix_rule(target, target_body, target_suffix, command)
*
* Does the lookup for single and double suffix rules.
* It calls build_suffix_list() to build the list of possible suffixes
* for the given target.
* It then scans the list to find the first possible source file that
* exists. This is done by concatenating the body of the target name
* (target name less target suffix) and the source suffix and checking
* if the resulting file exists.
*
* Return value:
* Indicates if search failed or not
*
* Parameters:
* target The target we need a rule for
* target_body The target name without the suffix
* target_suffix The suffix of the target
* command Pointer to slot to deposit cmd in if found
*
* Global variables used:
* debug_level Indicates how much tracing to do
* recursion_level Used for tracing
*/
Doname
find_suffix_rule(target, target_body, target_suffix, command)
Name target;
Name target_body;
Name target_suffix;
Property *command;
{
register Name source;
register Property source_suffix;
char sourcename[MAXPATHLEN];
register char *put_suffix;
register Property line;
Name true_target = target;
Doname result;
/* If the target is a constructed one for a "::" target we need to */
/* consider that */
if (target->has_target_prop) {
true_target = get_prop(target->prop,
target_prop)->body.target.target;
}
if (debug_level > 1) {
(void) printf("%*sfind_suffix_rule(%s,%s,%s)\n",
recursion_level,
"",
true_target->string,
target_body->string,
target_suffix->string);
}
if ((true_target->suffix_scan_done == true) && (*command == NULL)) {
return build_ok;
}
true_target->suffix_scan_done = true;
/* Enter all names from the directory where the target lives as */
/* files in makes sense */
/* This will make finding the synthesized source possible */
read_directory_of_file(target_body);
/* Cache the suffixes for this target suffix if not done */
if (!target_suffix->has_read_suffixes) {
build_suffix_list(target_suffix);
}
/* Preload the sourcename vector with the head of the target name */
(void) strncpy(sourcename,
target_body->string,
(int) target_body->hash.length);
put_suffix = sourcename + target_body->hash.length;
/* Scan the suffix list for the target if one exists */
if (target_suffix->has_suffixes) {
for (source_suffix = get_prop(target_suffix->prop,
suffix_prop);
source_suffix != NULL;
source_suffix = get_prop(source_suffix->next,
suffix_prop)) {
/* Build the synthesized source name */
(void) strncpy(put_suffix,
source_suffix->body.
suffix.suffix->string,
(int) source_suffix->body.
suffix.suffix->hash.length);
put_suffix[source_suffix->body.
suffix.suffix->hash.length] =
(int) nul_char;
if (debug_level > 1) {
(void) printf("%*sTrying %s\n",
recursion_level,
"",
sourcename);
}
source = GETNAME(sourcename, FIND_LENGTH);
/* If the synth source file is not registered as a */
/* file this source suffix did not match */
if (!source->stat.is_file) {
continue;
}
/* The synth source is a file. Make sure it is up to */
/* date */
if (dependency_exists(source,
get_prop(target->prop,
line_prop))) {
result = source->state;
} else {
result = doname(source,
source_suffix->body.
suffix.suffix->with_squiggle,
true);
}
switch (result) {
case build_dont_know:
/* If we still cant build the synth source */
/* this rule is not a match, try the next one*/
if (source->stat.time ==
(int) file_doesnt_exist) {
continue;
}
case build_running:
true_target->suffix_scan_done = false;
enter_dependency(maybe_append_prop(target,
line_prop),
source,
false);
return build_running;
case build_ok:
break;
case build_failed:
return build_failed;
}
if (debug_level > 1) {
(void) printf("%*sFound %s\n",
recursion_level,
"",
sourcename);
}
if (source->depends_on_conditional) {
target->depends_on_conditional = true;
}
/* Since it is possible that the same target is built several times during */
/* the make run we have to patch the target with all information we found */
/* here . Thus the target will have an explicit rule the next time around */
line = maybe_append_prop(target, line_prop);
if (*command == NULL) {
*command = line;
}
if ((source->stat.time >
(*command)->body.line.dependency_time) &&
(debug_level > 1)) {
(void) printf("%*sDate(%s)=%s Date-dependencies(%s)=%s\n",
recursion_level,
"",
source->string,
time_to_string(source->
stat.time),
true_target->string,
time_to_string((*command)->
body.line.
dependency_time));
}
/* Determine if this new dependency made the target */
/* out of date */
(*command)->body.line.dependency_time =
MAX((*command)->body.line.dependency_time,
source->stat.time);
if (OUT_OF_DATE(target->stat.time,
(*command)->body.
line.dependency_time)) {
line->body.line.is_out_of_date = true;
if (debug_level > 0) {
(void) printf("%*sBuilding %s using suffix rule for %s%s because it is out of date relative to %s\n",
recursion_level,
"",
true_target->string,
source_suffix->body.
suffix.suffix->string,
target_suffix->string,
source->string);
}
}
/* Add the implicit rule as the targets explicit rule
* if none actually given and register dependency.
* the time checking above really should be conditional
* on actual use of implicit rule as well
*/
line->body.line.sccs_command = false;
if (line->body.line.command_template == NULL) {
line->body.line.command_template =
source_suffix->body.suffix.command_template;
}
enter_dependency(line, source, false);
line->body.line.target = true_target;
/* Also make sure the rule is build with $* and $< */
/* bound properly */
line->body.line.star = target_body;
line->body.line.less = source;
line->body.line.percent = NULL;
if (line->body.line.query == NULL) {
line->body.line.query = ALLOC(Chain);
line->body.line.query->next = NULL;
line->body.line.query->name =
line->body.line.less;
} else {
Chain ch = line->body.line.query;
for (; ch->next != NULL; ch = ch->next);
ch->next = ALLOC(Chain);
ch->next->next = NULL;
ch->next->name = line->body.line.less;
}
return build_ok;
}
}
/* Return here in case no rule matched the target */
return build_dont_know;
}
/*
* find_ar_suffix_rule(target, true_target, command)
*
* Scans the .SUFFIXES list and tries
* to find a suffix on it that matches the tail of the target member name.
* If it finds a matching suffix it calls find_suffix_rule() to find
* a rule for the target using the suffix ".a".
*
* Return value:
* Indicates if search failed or not
*
* Parameters:
* target The target we need a rule for
* true_target The proper name
* command Pointer to slot where we stuff cmd, if found
*
* Global variables used:
* debug_level Indicates how much tracing to do
* dot_a The Name ".a", compared against
* recursion_level Used for tracing
* suffixes List of suffixes used for scan (from .SUFFIXES)
*/
Doname
find_ar_suffix_rule(target, true_target, command)
register Name target;
Name true_target;
Property *command;
{
register Dependency suffix;
register int suffix_length;
register int target_end;
Property line;
Name body;
static Name dot_a;
if (dot_a == NULL) {
dot_a = GETNAME(".a", FIND_LENGTH);
}
/* We compare the tail of the target name with the suffixes */
/* from .SUFFIXES */
target_end = (int) true_target->string + true_target->hash.length;
if (debug_level > 1) {
(void) printf("%*sfind_ar_suffix_rule(%s)\n",
recursion_level,
"",
true_target->string);
}
/* Scan the .SUFFIXES list to see if the target matches any of */
/* those suffixes */
for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
/* Compare one suffix */
suffix_length = suffix->name->hash.length;
if (!IS_EQUALN(suffix->name->string,
(char *)(target_end - suffix_length),
suffix_length)) {
goto not_this_one;
}
/* The target tail matched a suffix from the .SUFFIXES list. */
/* Now check for a rule to match. */
target->suffix_scan_done = false;
body = GETNAME(true_target->string,
(int)(true_target->hash.length -
suffix_length));
switch (find_suffix_rule(target,
body,
dot_a,
command)) {
case build_ok:
line = get_prop(target->prop, line_prop);
line->body.line.star = body;
return build_ok;
case build_running:
return build_running;
}
/* If no rule is found we try the next suffix to see if it */
/* matched the target tail. And so on. */
/* Go here if the suffix did not match the target tail */
not_this_one:;
}
return build_dont_know;
}
/*
* find_double_suffix_rule(target, command)
*
* Scans the .SUFFIXES list and tries
* to find a suffix on it that matches the tail of the target name.
* If it finds a matching suffix it calls find_suffix_rule() to find
* a rule for the target.
*
* Return value:
* Indicates if scan failed or not
*
* Parameters:
* target Target we need a rule for
* command Pointer to slot where we stuff cmd, if found
*
* Global variables used:
* debug_level Indicates how much tracing to do
* recursion_level Used for tracing
* suffixes List of suffixes used for scan (from .SUFFIXES)
*/
Doname
find_double_suffix_rule(target, command)
register Name target;
Property *command;
{
register Dependency suffix;
register int suffix_length;
register int target_end;
Name true_target = target;
/* If the target is a constructed one for a "::" target we need to */
/* consider that */
if (target->has_target_prop) {
true_target = get_prop(target->prop,
target_prop)->body.target.target;
}
/* We compare the tail of the target name with the */
/* suffixes from .SUFFIXES */
target_end = (int) true_target->string + true_target->hash.length;
if (debug_level > 1) {
(void) printf("%*sfind_double_suffix_rule(%s)\n",
recursion_level,
"",
true_target->string);
}
/* Scan the .SUFFIXES list to see if the target matches */
/* any of those suffixes */
for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
/* Compare one suffix */
suffix_length = suffix->name->hash.length;
if (!IS_EQUALN(suffix->name->string,
(char *)(target_end - suffix_length),
suffix_length)) {
goto not_this_one;
}
/* The target tail matched a suffix from the .SUFFIXES list. */
/* Now check for a rule to match. */
switch (find_suffix_rule(target,
GETNAME(true_target->string,
(int)(true_target->
hash.length -
suffix_length)),
suffix->name,
command)) {
case build_ok:
return build_ok;
case build_running:
return build_running;
}
target->suffix_scan_done = false;
true_target->suffix_scan_done = false;
/* If no rule is found we try the next suffix to see if it */
/* matched the target tail. And so on. */
/* Go here if the suffix did not match the target tail */
not_this_one:;
}
return build_dont_know;
}
/*
* build_suffix_list(target_suffix)
*
* Scans the .SUFFIXES list and figures out
* which suffixes this target can be derived from.
* The target itself is not know here, we just know the suffix of the
* target. For each suffix on the list the target can be derived iff
* a rule exists for the name "<suffix-on-list><target-suffix>".
* A list of all possible building suffixes is built, with the rule for
* each, and tacked to the target suffix nameblock.
*
* Parameters:
* target_suffix The suffix we build a match list for
*
* Global variables used:
* debug_level Indicates how much tracing to do
* recursion_level Used for tracing
* suffixes List of suffixes used for scan (from .SUFFIXES)
* working_on_targets Indicates that this is a real target
*/
void
build_suffix_list(target_suffix)
register Name target_suffix;
{
register Dependency source_suffix;
char rule_name[MAXPATHLEN];
register Property line;
register Property suffix;
Name rule;
/* If this is before default.mk has been read we just return to try */
/* again later */
if ((suffixes == NULL) || !working_on_targets) {
return;
}
if (debug_level > 1) {
(void) printf("%*sbuild_suffix_list(%s) ",
recursion_level,
"",
target_suffix->string);
}
/* Mark the target suffix saying we cashed its list */
target_suffix->has_read_suffixes = true;
/* Scan the .SUFFIXES list */
for (source_suffix = suffixes;
source_suffix != NULL;
source_suffix = source_suffix->next) {
/* Build the name "<suffix-on-list><target-suffix>" */
/* (a popular one would be ".c.o") */
(void) strncpy(rule_name,
source_suffix->name->string,
(int) source_suffix->name->hash.length);
(void) strncpy(rule_name + source_suffix->name->hash.length,
target_suffix->string,
(int) target_suffix->hash.length);
/* Check if that name has a rule, if not it cannot match any */
/* implicit rule scan and is ignored */
/* The GETNAME() call only check for presence, it will not */
/* enter the name if it is not defined */
if (((rule = getname_fn(rule_name,
(int) (source_suffix->name->
hash.length +
target_suffix->hash.length),
true)) != NULL) &&
((line = get_prop(rule->prop, line_prop)) != NULL)) {
if (debug_level > 1) {
(void) printf("%s ", rule->string);
}
/* This makes it possible to quickly determine it it */
/* will pay to look for a suffix property */
target_suffix->has_suffixes = true;
/* Add the suffix property to the target suffix and */
/* save the rule with it */
/* All information the implicit rule scanner need is */
/* save in the suffix property */
suffix = append_prop(target_suffix, suffix_prop);
suffix->body.suffix.suffix = source_suffix->name;
suffix->body.suffix.command_template =
line->body.line.command_template;
}
}
if (debug_level > 1) {
(void) printf("\n");
}
}
/*
* find_percent_rule(target, command)
*
* Tries to find a rule from the list of wildcard matched rules.
* It scans the list attempting to match the target.
* For each target match it checks if the corresponding source exists.
* If it does the match is returned.
* The percent_list is built at makefile read time.
* Each percent rule get one entry on the list.
*
* Return value:
* Indicates if the scan failed or not
*
* Parameters:
* target The target we need a rule for
* command Pointer to slot where we stuff cmd, if found
*
* Global variables used:
* debug_level Indicates how much tracing to do
* percent_list List of all percent rules
* recursion_level Used for tracing
*/
Doname
find_percent_rule(target, command)
register Name target;
Property *command;
{
register Percent pat_list;
String_rec source_string;
char buffer[STRING_BUFFER_LENGTH];
register Name source;
register Property line;
Name true_target = target;
register int prefix_length;
register int suffix_length;
Doname result;
Dependency dp;
/* If the target is constructed for a "::" target we consider that */
if (target->has_target_prop) {
true_target = get_prop(target->prop,
target_prop)->body.target.target;
}
if (debug_level > 1) {
(void) printf("%*sLooking for %% rule for %s\n",
recursion_level,
"",
true_target->string);
}
for (pat_list = percent_list;
pat_list != NULL;
pat_list = pat_list->next) {
/* Avoid infinite recursion when expanding patterns */
if (pat_list->being_expanded == true) {
continue;
}
/* Compare the target name with the head/tail of pattern */
/* If the pattern head/tail refs macros they are expanded */
if (!pat_list->target_prefix->dollar) {
prefix_length =
(int) pat_list->target_prefix->hash.length;
if (!IS_EQUALN(true_target->string,
pat_list->target_prefix->string,
prefix_length)) {
continue;
}
} else {
INIT_STRING_FROM_STACK(source_string, buffer);
expand_value(pat_list->target_prefix,
&source_string,
false);
prefix_length =
source_string.text.p-source_string.buffer.start;
if (!IS_EQUALN(true_target->string,
source_string.buffer.start,
prefix_length)) {
continue;
}
}
if (!pat_list->target_suffix->dollar) {
suffix_length = pat_list->target_suffix->hash.length;
if (!IS_EQUAL(true_target->string +
true_target->hash.length -
pat_list->target_suffix->hash.length,
pat_list->target_suffix->string)) {
continue;
}
} else {
INIT_STRING_FROM_STACK(source_string, buffer);
expand_value(pat_list->target_suffix,
&source_string,
false);
suffix_length =
source_string.text.p-source_string.buffer.start;
if (!IS_EQUAL(true_target->string +
true_target->hash.length -
suffix_length,
source_string.buffer.start)) {
continue;
}
}
/* The rule matched the target. Construct the source name as */
/* "source head" + "target body" + "source tail" */
INIT_STRING_FROM_STACK(source_string, buffer);
if (!pat_list->source_prefix->dollar) {
append_string(pat_list->source_prefix->string,
&source_string,
(int) pat_list->source_prefix->
hash.length);
} else {
expand_value(pat_list->source_prefix,
&source_string,
false);
}
if (pat_list->source_percent) {
append_string(true_target->string + prefix_length,
&source_string,
(int) (true_target->hash.length -
prefix_length -
suffix_length));
}
if (!pat_list->source_suffix->dollar) {
append_string(pat_list->source_suffix->string,
&source_string,
(int) pat_list->source_suffix->
hash.length);
} else {
expand_value(pat_list->source_suffix,
&source_string,
false);
}
/* Internalize the synthesized source name */
source = GETNAME(source_string.buffer.start, FIND_LENGTH);
if (source_string.free_after_use) {
retmem(source_string.buffer.start);
}
if (debug_level > 1) {
(void) printf("%*sTrying %s\n",
recursion_level,
"",
source->string);
}
/* Try to build the source */
pat_list->being_expanded = true;
if (dependency_exists(source,
get_prop(target->prop,
line_prop))) {
result = source->state;
} else {
result = doname(source, true, true);
}
switch (result) {
case build_dont_know:
/* If make cant figure out how to build the source we*/
/* just try the next percent rule */
pat_list->being_expanded = false;
if (source->stat.time == (int) file_doesnt_exist) {
continue;
}
case build_running:
pat_list->being_expanded = false;
enter_dependency(maybe_append_prop(target, line_prop),
source,
false);
return build_running;
case build_ok:
/* If we managed to build the source this rule */
/* is a match */
break;
case build_failed:
/* If the build of the source failed we give up */
/* looking for a percent rule and propagate the error*/
pat_list->being_expanded = false;
return build_failed;
}
/* We matched the rule since the source exists */
/* Now make sure "%.o: %.c" behaves the same as "foo.o:foo.c"*/
/* by saying that the target we matched has been */
/* mentioned in the makefile */
if (true_target->colons == no_colon) {
true_target->colons = one_colon;
}
pat_list->being_expanded = false;
if (debug_level > 1) {
(void) printf("%*sMatched %s: %s from %s%%%s: %s%s%s\n",
recursion_level,
"",
true_target->string,
source->string,
pat_list->target_prefix->string,
pat_list->target_suffix->string,
pat_list->source_prefix->string,
pat_list->source_percent ?
"%" : "",
pat_list->source_suffix->string);
}
/* Since it is possible that the same target is built several times during */
/* the make run we have to patch the target with all information we found */
/* here . Thus the target will have an explicit rule the next time around */
/* Enter the synthesized source as a dependency for the target in case the */
/* target is built again */
line = maybe_append_prop(target, line_prop);
*command = line;
if ((source->stat.time >
(*command)->body.line.dependency_time) &&
(debug_level > 1)) {
(void) printf("%*sDate(%s)=%s Date-dependencies(%s)=%s\n",
recursion_level,
"",
source->string,
time_to_string(source->stat.time),
true_target->string,
time_to_string((*command)->
body.line.dependency_time));
}
/* Add all dependencies from the % rule */
for (dp = pat_list->dependencies; dp != NULL; dp = dp->next) {
enter_dependency(line, dp->name, false);
if (doname_check(dp->name,
true,
true,
false) == build_failed) {
return build_failed;
}
/* Determine if this new dependency make the */
/* target out of date */
(*command)->body.line.dependency_time =
MAX((*command)->body.line.dependency_time,
dp->name->stat.time);
if (OUT_OF_DATE(true_target->stat.time,
(*command)->body.line.dependency_time)) {
line->body.line.is_out_of_date = true;
if (debug_level > 0) {
(void) printf("%*sBuilding %s using percent rule for %s%%%s: %s%s%s because it is out of date relative to %s\n",
recursion_level,
"",
true_target->string,
pat_list->target_prefix->string,
pat_list->target_suffix->string,
pat_list->source_prefix->string,
pat_list->source_percent ?
"%" : "",
pat_list->source_suffix->string,
dp->name->string);
}
}
}
/* Determine if this new dependency make the target */
/* out of date */
(*command)->body.line.dependency_time =
MAX((*command)->body.line.dependency_time,
source->stat.time);
if (OUT_OF_DATE(true_target->stat.time,
(*command)->body.line.dependency_time)) {
line->body.line.is_out_of_date = true;
if (debug_level > 0) {
(void) printf("%*sBuilding %s using percent rule for %s%%%s: %s%s%s because it is out of date relative to %s\n",
recursion_level,
"",
true_target->string,
pat_list->target_prefix->string,
pat_list->target_suffix->string,
pat_list->source_prefix->string,
pat_list->source_percent ?
"%" : "",
pat_list->source_suffix->string,
source->string);
}
}
/* And stuff the rule we found as an explicit rule for target*/
line->body.line.sccs_command = false;
line->body.line.target = true_target;
if (line->body.line.command_template == NULL) {
line->body.line.command_template =
pat_list->command_template;
enter_dependency(line, source, false);
/* Also make sure the rule is build with $* and $< */
/* $* is bound to the stuff that matched the "%" */
line->body.line.star =
GETNAME(true_target->string + prefix_length,
(int)(true_target->hash.length -
prefix_length - suffix_length));
line->body.line.less = source;
}
if (true_target->parenleft) {
char *left;
char *right;
left = strchr(true_target->string,
(int) parenleft_char);
right = strchr(true_target->string,
(int) parenright_char);
if ((left == NULL) || (right == NULL)) {
line->body.line.percent = NULL;
} else {
line->body.line.percent =
GETNAME(left+1, right-left-1);
}
} else {
line->body.line.percent = NULL;
}
return build_ok;
}
/* This return is taken if no percent rule was found for the target */
return build_dont_know;
}
/*
* dependency_exists(target, line)
*
* Returns true if the target exists in the
* dependency list of the line.
*
* Return value:
* True if target is on dependency list
*
* Parameters:
* target Target we scan for
* line We get the dependency list from here
*
* Global variables used:
*/
static Boolean
dependency_exists(target, line)
Name target;
Property line;
{
Dependency dp;
if (line == NULL) {
return false;
}
for (dp = line->body.line.dependencies; dp != NULL; dp = dp->next) {
if (dp->name == target) {
return true;
}
}
return false;
}