diff options
author | Igor Pashev <igor.pashev@nexenta.com> | 2012-06-29 14:36:07 +0400 |
---|---|---|
committer | Igor Pashev <igor.pashev@nexenta.com> | 2012-06-29 14:36:07 +0400 |
commit | e0463df9c3d2ee6155221cc443c571d5da47098a (patch) | |
tree | 5c6b99e64c1b65d986e2722728c74f202a578be6 /usr/src/make_src/Make/bin/make/common/implicit.cc | |
download | sunmake-orig.tar.gz |
Initial import of DevPro make sourcesorig
Downloaded from http://dlc.sun.com/osol/devpro/downloads/current/
Licensed under CDDL http://www.opensource.org/licenses/CDDL-1.0
Diffstat (limited to 'usr/src/make_src/Make/bin/make/common/implicit.cc')
-rw-r--r-- | usr/src/make_src/Make/bin/make/common/implicit.cc | 1479 |
1 files changed, 1479 insertions, 0 deletions
diff --git a/usr/src/make_src/Make/bin/make/common/implicit.cc b/usr/src/make_src/Make/bin/make/common/implicit.cc new file mode 100644 index 0000000..a9b2f1d --- /dev/null +++ b/usr/src/make_src/Make/bin/make/common/implicit.cc @@ -0,0 +1,1479 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * @(#)implicit.cc 1.64 06/12/12 + */ + +#pragma ident "@(#)implicit.cc 1.64 06/12/12" + +/* + * implicit.c + * + * Handle suffix and percent rules + */ + +/* + * Included files + */ +#include <mk/defs.h> +#include <mksh/macro.h> /* expand_value() */ +#include <mksh/misc.h> /* retmem() */ + +/* + * Defined macros + */ + +/* + * typedefs & structs + */ + +/* + * Static variables + */ +static wchar_t WIDE_NULL[1] = {(wchar_t) nul_char}; + +/* + * File table of contents + */ +extern Doname find_suffix_rule(Name target, Name target_body, Name target_suffix, Property *command, Boolean rechecking); +extern Doname find_ar_suffix_rule(register Name target, Name true_target, Property *command, Boolean rechecking); +extern Doname find_double_suffix_rule(register Name target, Property *command, Boolean rechecking); +extern void build_suffix_list(register Name target_suffix); +extern Doname find_percent_rule(register Name target, Property *command, Boolean rechecking); +static void create_target_group_and_dependencies_list(Name target, Percent pat_rule, String percent); +static Boolean match_found_with_pattern(Name target, Percent pat_rule, String percent, wchar_t *percent_buf); +static void construct_string_from_pattern(Percent pat_rule, String percent, String result); +static Boolean dependency_exists(Name target, Property line); +extern Property maybe_append_prop(Name, Property_id); +extern void add_target_to_chain(Name target, Chain * query); + +/* + * find_suffix_rule(target, target_body, target_suffix, command, rechecking) + * + * 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 + * rechecking true if we are rechecking target which depends + * on conditional macro and keep_state is set + * + * Global variables used: + * debug_level Indicates how much tracing to do + * recursion_level Used for tracing + */ + +extern int printf (const char *, ...); + +static Boolean actual_doname = false; + +/* /tolik/ + * fix bug 1247448: Suffix Rules failed when combine with Pattern Matching Rules. + * When make attemps to apply % rule it didn't look for a single suffix rule because + * if "doname" is called from "find_percent_rule" argument "implicit" is set to true + * and find_suffix_rule was not called. I've commented the checking of "implicit" + * in "doname" and make got infinite recursion for SVR4 tilde rules. + * Usage of "we_are_in_tilde" is intended to avoid this recursion. + */ + +static Boolean we_are_in_tilde = false; + +Doname +find_suffix_rule(Name target, Name target_body, Name target_suffix, Property *command, Boolean rechecking) +{ + static wchar_t static_string_buf_3M [ 3 * MAXPATHLEN ]; + Name true_target = target; + wchar_t *sourcename = (wchar_t*)static_string_buf_3M; + register wchar_t *put_suffix; + register Property source_suffix; + register Name source; + Doname result; + register Property line; + extern Boolean tilde_rule; + Boolean name_found = true; + Boolean posix_tilde_attempt = true; + int src_len = MAXPATHLEN + strlen(target_body->string_mb); + + /* + * To avoid infinite recursion + */ + if(we_are_in_tilde) { + we_are_in_tilde = false; + return(build_dont_know); + } + + /* + * 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(NOCATGETS("%*sfind_suffix_rule(%s,%s,%s)\n"), + recursion_level, + "", + true_target->string_mb, + target_body->string_mb, + target_suffix->string_mb); + } + if (command != NULL) { + 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 that 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. */ + if (src_len >= sizeof(static_string_buf_3M)) { + sourcename = ALLOC_WC(src_len); + } + (void) mbstowcs(sourcename, + target_body->string_mb, + (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) { +posix_attempts: + 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) mbstowcs(put_suffix, + source_suffix->body. + suffix.suffix->string_mb, + (int) source_suffix->body. + suffix.suffix->hash.length); + put_suffix[source_suffix->body. + suffix.suffix->hash.length] = + (int) nul_char; + if (debug_level > 1) { + WCSTOMBS(mbs_buffer, sourcename); + (void) printf(catgets(catd, 1, 218, "%*sTrying %s\n"), + recursion_level, + "", + mbs_buffer); + } + source = getname_fn(sourcename, FIND_LENGTH, false, &name_found); + /* + * If the source file is not registered as + * a file, this source suffix did not match. + */ + if(vpath_defined && !posix && !svr4) { + (void) exists(source); + } + if (!source->stat.is_file) { + if(!(posix|svr4)) + { + if(!name_found) { + free_name(source); + } + continue; + } + + /* following code will ensure that the corresponding + ** tilde rules are executed when corresponding s. file + ** exists in the current directory. Though the current + ** target ends with a ~ character, there wont be any + ** any file in the current directory with that suffix + ** as it's fictitious. Even if it exists, it'll + ** execute all the rules for the ~ target. + */ + + if(source->string_mb[source->hash.length - 1] == '~' && + ( svr4 || posix_tilde_attempt ) ) + { + char *p, *np; + char *tmpbuf; + + tmpbuf = getmem(source->hash.length + 8); + /* + 8 to add "s." or "SCCS/s." */ + memset(tmpbuf,0,source->hash.length + 8); + source->string_mb[source->hash.length - 1] = '\0'; + if(p = (char *) memchr((char *)source->string_mb,'/',source->hash.length)) + { + while(1) { + if(np = (char *) memchr((char *)p+1,'/',source->hash.length - (p - source->string_mb))) { + p = np; + } else {break;} + } + /* copy everything including '/' */ + strncpy(tmpbuf, source->string_mb, p - source->string_mb + 1); + strcat(tmpbuf, NOCATGETS("s.")); + strcat(tmpbuf, p+1); + retmem((wchar_t *) source->string_mb); + source->string_mb = tmpbuf; + + } else { + strcpy(tmpbuf, NOCATGETS("s.")); + strcat(tmpbuf, source->string_mb); + retmem((wchar_t *) source->string_mb); + source->string_mb = tmpbuf; + + } + source->hash.length = strlen(source->string_mb); + if(exists(source) == file_doesnt_exist) + continue; + tilde_rule = true; + we_are_in_tilde = true; + } else { + if(!name_found) { + free_name(source); + } + continue; + } + } else { + if(posix && posix_tilde_attempt) { + if(exists(source) == file_doesnt_exist) { + if(!name_found) { + free_name(source); + } + continue; + } + } + } + + if (command != NULL) { + if(!name_found) { + store_name(source); + } + /* + * The source file is a file. + * Make sure it is up to date. + */ + if (dependency_exists(source, + get_prop(target->prop, + line_prop))) { + result = (Doname) source->state; + } else { +#ifdef NSE + nse_check_derived_src(target, source->string, + source_suffix->body.suffix.command_template); +#endif +#if 0 /* with_squiggle sends false, which is buggy. : djay */ + result = doname(source, + (Boolean) source_suffix->body. + suffix.suffix->with_squiggle, + true); +#else + result = doname(source, + true, + true); +#endif + } + } else { + result = target_can_be_built(source); + + if (result == build_ok) { + return result; + } else { + if(!name_found) { + free_name(source); + } + continue; + } + } + + switch (result) { + case build_dont_know: + /* + * If we still can't build the source, + * this rule is not a match, + * try the next one. + */ + if (source->stat.time == file_doesnt_exist) { + if(!name_found) { + free_name(source); + } + continue; + } + case build_running: + if(!name_found) { + store_name(source); + } + true_target->suffix_scan_done = false; + line = maybe_append_prop(target, line_prop); + enter_dependency(line, source, false); + line->body.line.target = true_target; + return build_running; + case build_ok: + if(!name_found) { + store_name(source); + } + break; + case build_failed: + if(!name_found) { + store_name(source); + } + if (sourcename != static_string_buf_3M) { + retmem(sourcename); + } + return build_failed; + } + + if (debug_level > 1) { + WCSTOMBS(mbs_buffer, sourcename); + (void) printf(catgets(catd, 1, 219, "%*sFound %s\n"), + recursion_level, + "", + mbs_buffer); + } + + 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(catgets(catd, 1, 220, "%*sDate(%s)=%s Date-dependencies(%s)=%s\n"), + recursion_level, + "", + source->string_mb, + time_to_string(source-> + stat.time), + true_target->string_mb, + 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); + Boolean out_of_date; + if (target->is_member) { + out_of_date = (Boolean) OUT_OF_DATE_SEC(target->stat.time, + (*command)->body.line.dependency_time); + } else { + out_of_date = (Boolean) OUT_OF_DATE(target->stat.time, + (*command)->body.line.dependency_time); + } + if (build_unconditional || out_of_date) { + if(!rechecking) { + line->body.line.is_out_of_date = true; + } + if (debug_level > 0) { + (void) printf(catgets(catd, 1, 221, "%*sBuilding %s using suffix rule for %s%s because it is out of date relative to %s\n"), + recursion_level, + "", + true_target->string_mb, + source_suffix->body.suffix.suffix->string_mb, + target_suffix->string_mb, + source->string_mb); + } + } + /* + * Add the implicit rule as the target's 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 built with + * $* and $< bound properly. + */ + line->body.line.star = target_body; + if(svr4|posix) { + char * p; + char tstr[256]; + extern Boolean dollarless_flag; + extern Name dollarless_value; + + if(tilde_rule) { + MBSTOWCS(wcs_buffer, NOCATGETS(source->string_mb)); + dollarless_value = GETNAME(wcs_buffer,FIND_LENGTH); + } + else { + dollarless_flag = false; + } + } + line->body.line.less = source; + line->body.line.percent = NULL; + add_target_to_chain(source, &(line->body.line.query)); + if (sourcename != static_string_buf_3M) { + retmem(sourcename); + } + return build_ok; + } + if(posix && posix_tilde_attempt) { + posix_tilde_attempt = false; + goto posix_attempts; + } + if ((command != NULL) && + ((*command) != NULL) && + ((*command)->body.line.star == NULL)) { + (*command)->body.line.star = target_body; + } + } + if (sourcename != static_string_buf_3M) { + retmem(sourcename); + } + /* Return here in case no rule matched the target */ + return build_dont_know; +} + +/* + * find_ar_suffix_rule(target, true_target, command, rechecking) + * + * 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 + * rechecking true if we are rechecking target which depends + * on conditional macro and keep_state is set + * + * 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(register Name target, Name true_target, Property *command, Boolean rechecking) +{ + wchar_t *target_end; + register Dependency suffix; + register int suffix_length; + Property line; + Name body; + static Name dot_a; + + Wstring targ_string(true_target); + Wstring suf_string; + + if (dot_a == NULL) { + MBSTOWCS(wcs_buffer, NOCATGETS(".a")); + dot_a = GETNAME(wcs_buffer, FIND_LENGTH); + } + target_end = targ_string.get_string() + true_target->hash.length; + + /* + * We compare the tail of the target name with the suffixes + * from .SUFFIXES. + */ + if (debug_level > 1) { + (void) printf(NOCATGETS("%*sfind_ar_suffix_rule(%s)\n"), + recursion_level, + "", + true_target->string_mb); + } + /* + * 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; + suf_string.init(suffix->name); + if (!IS_WEQUALN(suf_string.get_string(), + 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(targ_string.get_string(), + (int)(true_target->hash.length - + suffix_length)); + we_are_in_tilde = false; + switch (find_suffix_rule(target, + body, + dot_a, + command, + rechecking)) { + 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 was found, we try the next suffix to see + * if it matches 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, rechecking) + * + * 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 + * rechecking true if we are rechecking target which depends + * on conditional macro and keep_state is set + * + * 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(register Name target, Property *command, Boolean rechecking) +{ + Name true_target = target; + Name target_body; + register wchar_t *target_end; + register Dependency suffix; + register int suffix_length; + Boolean scanned_once = false; + Boolean name_found = true; + + Wstring targ_string; + Wstring suf_string; + + /* + * 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; + } + targ_string.init(true_target); + + /* + * We compare the tail of the target name with the + * suffixes from .SUFFIXES. + */ + target_end = targ_string.get_string() + true_target->hash.length; + if (debug_level > 1) { + (void) printf(NOCATGETS("%*sfind_double_suffix_rule(%s)\n"), + recursion_level, + "", + true_target->string_mb); + } + /* + * Scan the .SUFFIXES list to see if the target matches + * any of those suffixes. + */ + for (suffix = suffixes; suffix != NULL; suffix = suffix->next) { + target->suffix_scan_done = false; + true_target->suffix_scan_done = false; + /* Compare one suffix. */ + suffix_length = suffix->name->hash.length; + suf_string.init(suffix->name); + /* Check the lengths, or else RTC will report rua. */ + if (true_target->hash.length < suffix_length) { + goto not_this_one; + } else if (!IS_WEQUALN(suf_string.get_string(), + (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. + */ + we_are_in_tilde = false; + target_body = GETNAME( + targ_string.get_string(), + (int)(true_target->hash.length - suffix_length) + ); + switch (find_suffix_rule(target, + target_body, + suffix->name, + command, + rechecking)) { + case build_ok: + return build_ok; + case build_running: + return build_running; + } + if (true_target->suffix_scan_done == true) { + scanned_once = true; + } + /* + * If no rule was found, we try the next suffix to see + * if it matches the target tail. And so on. + * Go here if the suffix did not match the target tail. + */ + not_this_one:; + } + if (scanned_once) + true_target->suffix_scan_done = true; + 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(register Name target_suffix) +{ + register Dependency source_suffix; + wchar_t 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(NOCATGETS("%*sbuild_suffix_list(%s) "), + recursion_level, + "", + target_suffix->string_mb); + } + /* 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) mbstowcs(rule_name, + source_suffix->name->string_mb, + (int) source_suffix->name->hash.length); + (void) mbstowcs(rule_name + source_suffix->name->hash.length, + target_suffix->string_mb, + (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 checks 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_mb); + } + /* + * This makes it possible to quickly determine if + * 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 saved 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, rechecking) + * + * 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 + * rechecking true if we are rechecking target which depends + * on conditional macro and keep_state is set + * + * Global variables used: + * debug_level Indicates how much tracing to do + * percent_list List of all percent rules + * recursion_level Used for tracing + * empty_name + */ +Doname +find_percent_rule(register Name target, Property *command, Boolean rechecking) +{ + register Percent pat_rule, pat_depe; + register Name depe_to_check; + register Dependency depe; + register Property line; + String_rec string; + wchar_t string_buf[STRING_BUFFER_LENGTH]; + String_rec percent; + wchar_t percent_buf[STRING_BUFFER_LENGTH]; + Name true_target = target; + Name less; + Boolean nonpattern_less; + Boolean dep_name_found = false; + Doname result = build_dont_know; + Percent rule_candidate = NULL; + Boolean rule_maybe_ok; + Boolean is_pattern; + + /* 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 (target->has_long_member_name) { + true_target = get_prop(target->prop, + long_member_name_prop)->body.long_member_name.member_name; + } + if (debug_level > 1) { + (void) printf(catgets(catd, 1, 222, "%*sLooking for %% rule for %s\n"), + recursion_level, + "", + true_target->string_mb); + } + for (pat_rule = percent_list; + pat_rule != NULL; + pat_rule = pat_rule->next) { + /* Avoid infinite recursion when expanding patterns */ + if (pat_rule->being_expanded == true) { + continue; + } + + /* Mark this pat_rule as "maybe ok". If no % rule is found + make will use this rule. The following algorithm is used: + 1) make scans all pattern rules in order to find the rule + where ALL dependencies, including nonpattern ones, exist or + can be built (GNU behaviour). If such rule is found make + will apply it. + 2) During this check make also remembers the first pattern rule + where all PATTERN dependencies can be build (no matter what + happens with nonpattern dependencies). + 3) If no rule satisfying 1) is found, make will apply the rule + remembered in 2) if there is one. + */ + rule_maybe_ok = true; + + /* used to track first percent dependency */ + less = NULL; + nonpattern_less = true; + + /* check whether pattern matches. + if it matches, percent string will contain matched percent part of pattern */ + if (!match_found_with_pattern(true_target, pat_rule, &percent, percent_buf)) { + continue; + } + if (pat_rule->dependencies != NULL) { + for (pat_depe = pat_rule->dependencies; + pat_depe != NULL; + pat_depe = pat_depe->next) { + /* checking result for dependency */ + result = build_dont_know; + + dep_name_found = true; + if (pat_depe->name->percent) { + is_pattern = true; + /* build dependency name */ + INIT_STRING_FROM_STACK(string, string_buf); + construct_string_from_pattern(pat_depe, &percent, &string); + depe_to_check = getname_fn(string.buffer.start, + FIND_LENGTH, + false, + &dep_name_found + ); + + if ((less == NULL) || nonpattern_less) { + less = depe_to_check; + nonpattern_less = false; + } + } else { + /* nonpattern dependency */ + is_pattern = false; + depe_to_check = pat_depe->name; + if(depe_to_check->dollar) { + INIT_STRING_FROM_STACK(string, string_buf); + expand_value(depe_to_check, &string, false); + depe_to_check = getname_fn(string.buffer.start, + FIND_LENGTH, + false, + &dep_name_found + ); + } + if (less == NULL) { + less = depe_to_check; + } + } + + if (depe_to_check == empty_name) { + result = build_ok; + } else { + if (debug_level > 1) { + (void) printf(catgets(catd, 1, 223, "%*sTrying %s\n"), + recursion_level, + "", + depe_to_check->string_mb); + } + + pat_rule->being_expanded = true; + + /* suppress message output */ + int save_debug_level = debug_level; + debug_level = 0; + + /* check whether dependency can be built */ + if (dependency_exists(depe_to_check, + get_prop(target->prop, + line_prop))) + { + result = (Doname) depe_to_check->state; + } else { + if(actual_doname) { + result = doname(depe_to_check, true, true); + } else { + result = target_can_be_built(depe_to_check); + } + if(!dep_name_found) { + if(result != build_ok && result != build_running) { + free_name(depe_to_check); + } else { + store_name(depe_to_check); + } + } + } + if(result != build_ok && is_pattern) { + rule_maybe_ok = false; + } + + /* restore debug_level */ + debug_level = save_debug_level; + } + + if (pat_depe->name->percent) { + if (string.free_after_use) { + retmem(string.buffer.start); + } + } + /* make can't figure out how to make this dependency */ + if (result != build_ok && result != build_running) { + pat_rule->being_expanded = false; + break; + } + } + } else { + result = build_ok; + } + + /* this pattern rule is the needed one since all dependencies could be built */ + if (result == build_ok || result == build_running) { + break; + } + + /* Make does not know how to build some of dependencies from this rule. + But if all "pattern" dependencies can be built, we remember this rule + as a candidate for the case if no other pattern rule found. + */ + if(rule_maybe_ok && rule_candidate == NULL) { + rule_candidate = pat_rule; + } + } + + /* if no pattern matching rule was found, use the remembered candidate + or return build_dont_know if there is no candidate. + */ + if (result != build_ok && result != build_running) { + if(rule_candidate) { + pat_rule = rule_candidate; + } else { + return build_dont_know; + } + } + + /* if we are performing only check whether dependency could be built with existing rules, + return success */ + if (command == NULL) { + if(pat_rule != NULL) { + pat_rule->being_expanded = false; + } + return result; + } + + if (debug_level > 1) { + (void) printf(catgets(catd, 1, 224, "%*sMatched %s:"), + recursion_level, + "", + target->string_mb); + + for (pat_depe = pat_rule->dependencies; + pat_depe != NULL; + pat_depe = pat_depe->next) { + if (pat_depe->name->percent) { + INIT_STRING_FROM_STACK(string, string_buf); + construct_string_from_pattern(pat_depe, &percent, &string); + depe_to_check = GETNAME(string.buffer.start, FIND_LENGTH); + } else { + depe_to_check = pat_depe->name; + if(depe_to_check->dollar) { + INIT_STRING_FROM_STACK(string, string_buf); + expand_value(depe_to_check, &string, false); + depe_to_check = GETNAME(string.buffer.start, FIND_LENGTH); + } + } + + if (depe_to_check != empty_name) { + (void) printf(" %s", depe_to_check->string_mb); + } + } + + (void) printf(catgets(catd, 1, 225, " from: %s:"), + pat_rule->name->string_mb); + + for (pat_depe = pat_rule->dependencies; + pat_depe != NULL; + pat_depe = pat_depe->next) { + (void) printf(" %s", pat_depe->name->string_mb); + } + + (void) printf("\n"); + } + + if (true_target->colons == no_colon) { + true_target->colons = one_colon; + } + + /* create deppendency list and target group from matched pattern rule */ + create_target_group_and_dependencies_list(target, pat_rule, &percent); + + /* save command */ + line = get_prop(target->prop, line_prop); + *command = line; + + /* free query chain if one exist */ + while(line->body.line.query != NULL) { + Chain to_free = line->body.line.query; + line->body.line.query = line->body.line.query->next; + retmem_mb((char *) to_free); + } + + if (line->body.line.dependencies != NULL) { + /* build all collected dependencies */ + for (depe = line->body.line.dependencies; + depe != NULL; + depe = depe->next) { + actual_doname = true; + result = doname_check(depe->name, true, true, depe->automatic); + + actual_doname = false; + if (result == build_failed) { + pat_rule->being_expanded = false; + return build_failed; + } + if (result == build_running) { + pat_rule->being_expanded = false; + return build_running; + } + + if ((depe->name->stat.time > line->body.line.dependency_time) && + (debug_level > 1)) { + (void) printf(catgets(catd, 1, 226, "%*sDate(%s)=%s Date-dependencies(%s)=%s\n"), + recursion_level, + "", + depe->name->string_mb, + time_to_string(depe->name->stat.time), + true_target->string_mb, + time_to_string(line->body.line.dependency_time)); + } + + line->body.line.dependency_time = + MAX(line->body.line.dependency_time, depe->name->stat.time); + + /* determine whether this dependency made target out of date */ + Boolean out_of_date; + if (target->is_member || depe->name->is_member) { + out_of_date = (Boolean) OUT_OF_DATE_SEC(target->stat.time, depe->name->stat.time); + } else { + out_of_date = (Boolean) OUT_OF_DATE(target->stat.time, depe->name->stat.time); + } + if (build_unconditional || out_of_date) { + if(!rechecking) { + line->body.line.is_out_of_date = true; + } + add_target_to_chain(depe->name, &(line->body.line.query)); + + if (debug_level > 0) { + (void) printf(catgets(catd, 1, 227, "%*sBuilding %s using pattern rule %s:"), + recursion_level, + "", + true_target->string_mb, + pat_rule->name->string_mb); + + for (pat_depe = pat_rule->dependencies; + pat_depe != NULL; + pat_depe = pat_depe->next) { + (void) printf(" %s", pat_depe->name->string_mb); + } + + (void) printf(catgets(catd, 1, 228, " because it is out of date relative to %s\n"), + depe->name->string_mb); + } + } + } + } else { + if ((true_target->stat.time <= file_doesnt_exist) || + (true_target->stat.time < line->body.line.dependency_time)) { + if(!rechecking) { + line->body.line.is_out_of_date = true; + } + if (debug_level > 0) { + (void) printf(catgets(catd, 1, 229, "%*sBuilding %s using pattern rule %s: "), + recursion_level, + "", + true_target->string_mb, + pat_rule->name->string_mb, + (target->stat.time > file_doesnt_exist) ? + catgets(catd, 1, 230, "because it is out of date") : + catgets(catd, 1, 236, "because it does not exist")); + } + } + } + + /* enter explicit rule from percent rule */ + Name lmn_target = true_target; + if (true_target->has_long_member_name) { + lmn_target = get_prop(true_target->prop, long_member_name_prop)->body.long_member_name.member_name; + } + line->body.line.sccs_command = false; + line->body.line.target = true_target; + line->body.line.command_template = pat_rule->command_template; + line->body.line.star = GETNAME(percent.buffer.start, FIND_LENGTH); + line->body.line.less = less; + + if (lmn_target->parenleft) { + Wstring lmn_string(lmn_target); + + wchar_t *left = (wchar_t *) wschr(lmn_string.get_string(), (int) parenleft_char); + wchar_t *right = (wchar_t *) wschr(lmn_string.get_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; + } + pat_rule->being_expanded = false; + +#ifdef TEAMWARE_MAKE_CMN + /* + * This #ifdef fixes a dmake bug, but introduces bugid 1136156. + */ + return result; +#else + return build_ok; +#endif +} + +/* + * match_found_with_pattern + * ( target, pat_rule, percent, percent_buf) + * + * matches "target->string" with a % pattern. + * If pattern contains a MACRO definition, it's expanded first. + * + * Return value: + * true if a match was found + * + * Parameters: + * target The target we're trying to match + * pattern + * percent record that contains "percent_buf" below + * percent_buf This is where the patched % part of pattern is stored + * + */ + +static Boolean +match_found_with_pattern(Name target, Percent pat_rule, String percent, wchar_t *percent_buf) { + String_rec string; + wchar_t string_buf[STRING_BUFFER_LENGTH]; + + /* construct prefix string and check whether prefix matches */ + Name prefix = pat_rule->patterns[0]; + int prefix_length; + + Wstring targ_string(target); + Wstring pref_string(prefix); + Wstring suf_string; + + if (prefix->dollar) { + INIT_STRING_FROM_STACK(string, string_buf); + expand_value(prefix, &string, false); + prefix_length = string.text.p - string.buffer.start; + if ((string.buffer.start[0] == (int) period_char) && + (string.buffer.start[1] == (int) slash_char)) { + string.buffer.start += 2; + prefix_length -= 2; + } + if (!targ_string.equaln(string.buffer.start, prefix_length)) { + return false; + } + } else { + prefix_length = prefix->hash.length; + if (!targ_string.equaln(&pref_string, prefix_length)) { + return false; + } + } + + /* do the same with pattern suffix */ + Name suffix = pat_rule->patterns[pat_rule->patterns_total - 1]; + suf_string.init(suffix); + + int suffix_length; + if (suffix->dollar) { + INIT_STRING_FROM_STACK(string, string_buf); + expand_value(suffix, &string, false); + suffix_length = string.text.p - string.buffer.start; + if(suffix_length > target->hash.length) { + return false; + } + if (!targ_string.equal(string.buffer.start, target->hash.length - suffix_length)) { + return false; + } + } else { + suffix_length = (int) suffix->hash.length; + if(suffix_length > target->hash.length) { + return false; + } + if (!targ_string.equal(&suf_string, target->hash.length - suffix_length)) { + return false; + } + } + + Boolean match_found = false; + int percent_length = target->hash.length - prefix_length - suffix_length; + + while (!match_found && (percent_length >= 0)) { + /* init result string */ + INIT_STRING_FROM_STACK(string, string_buf); + + /* init percent string */ + percent->buffer.start = percent_buf; + percent->text.p = percent_buf; + percent->text.end = NULL; + percent->free_after_use = false; + percent->buffer.end = percent_buf + STRING_BUFFER_LENGTH; + + /* construct percent and result strings */ + targ_string.append_to_str(percent, prefix_length, percent_length); + construct_string_from_pattern(pat_rule, percent, &string); + + /* check for match */ + if (targ_string.equal(string.buffer.start, 0)) { + match_found = true; + } else { + percent_length--; + } + } + + /* result */ + return match_found; +} + + +/* + * create_target_group_and_dependencies_list + * (target, pat_rule, percent) + * + * constructs dependency list and a target group from pattern. + * + * If we have the lines + * %/%.a + %/%.b + C%/CC%.c: yyy %.d bb%/BB%.e + * commands + * + * and we have matched the pattern xx/xx.a with %/%.a, then we + * construct a target group that looks like this: + * xx/xx.a + xx/xx.b + Cxx/CCxx.c: dependencies + * + * and construct dependency list that looks like this: + * yyy xx.d bbxx/BBxx.e + already existed dependencies + * + * Return value: + * none + * + * Parameters: + * target The target we are building, in the previous + * example, this is xx/xx.a + * pat_rule the % pattern that matched "target", here %/%.a + * percent string containing matched % part. In the example=xx. + * + * Global variables used: + * empty_name + */ + +static void +create_target_group_and_dependencies_list(Name target, Percent pat_rule, String percent) { + String_rec string; + wchar_t string_buf[STRING_BUFFER_LENGTH]; + Percent pat_depe; + Name depe; + Property line = maybe_append_prop(target, line_prop); + Chain new_target_group = NULL; + Chain *new_target_group_tail = &new_target_group; + Chain group_member; + + /* create and append dependencies from rule */ + for (pat_depe = pat_rule->dependencies; pat_depe != NULL; pat_depe = pat_depe->next) { + if (pat_depe->name->percent) { + INIT_STRING_FROM_STACK(string, string_buf); + construct_string_from_pattern(pat_depe, percent, &string); + depe = GETNAME(string.buffer.start, FIND_LENGTH); + if (depe != empty_name) { + enter_dependency(line, depe, false); + } + } else { + depe = pat_depe->name; + if(depe->dollar) { + INIT_STRING_FROM_STACK(string, string_buf); + expand_value(depe, &string, false); + depe = GETNAME(string.buffer.start, FIND_LENGTH); + } + enter_dependency(line, depe, false); + } + } + + /* if matched pattern is a group member, create new target group */ + for (group_member = pat_rule->target_group; group_member != NULL; group_member = group_member->next) { + Name new_target = group_member->name; + if (group_member->name->percent) { + INIT_STRING_FROM_STACK(string, string_buf); + construct_string_from_pattern(group_member->percent_member, percent, &string); + new_target = GETNAME(string.buffer.start, FIND_LENGTH); + if (new_target == empty_name) { + continue; + } + } + + /* check for duplicates */ + Chain tgm; + for (tgm = new_target_group; tgm != NULL; tgm = tgm->next) { + if (new_target == tgm->name) { + break; + } + } + if (tgm != NULL) { + continue; + } + + /* insert it into the targets list */ + (*new_target_group_tail) = ALLOC(Chain); + (*new_target_group_tail)->name = new_target; + (*new_target_group_tail)->next = NULL; + new_target_group_tail = &(*new_target_group_tail)->next; + } + + /* now we gathered all dependencies and created target group */ + line->body.line.target_group = new_target_group; + + /* update properties for group members */ + for (group_member = new_target_group; group_member != NULL; group_member = group_member->next) { + if (group_member->name != target) { + group_member->name->prop = target->prop; + group_member->name->conditional_cnt = target->conditional_cnt; + } + } +} + +/* + * construct_string_from_pattern + * (pat_rule, percent, result) + * + * after pattern matched a target this routine is called to construct targets and dependencies + * strings from this matched pattern rule and a string (percent) with substitutes % sign in pattern. + * + * Return value: + * none + * + * Parameters: + * pat_rule matched pattern rule + * percent string containing matched % sign part. + * result holds the result of string construction. + * + */ +static void +construct_string_from_pattern(Percent pat_rule, String percent, String result) { + for (int i = 0; i < pat_rule->patterns_total; i++) { + if (pat_rule->patterns[i]->dollar) { + expand_value(pat_rule->patterns[i], + result, + false); + + } else { + append_string(pat_rule->patterns[i]->string_mb, + result, + pat_rule->patterns[i]->hash.length); + } + + if (i < pat_rule->patterns_total - 1) { + append_string(percent->buffer.start, + result, + percent->text.p - percent->buffer.start); + } + } + + if ((result->buffer.start[0] == (int) period_char) && + (result->buffer.start[1] == (int) slash_char)) { + result->buffer.start += 2; + } +} + +/* + * 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(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; +} + +void +add_target_to_chain(Name target, Chain * query) +{ + if (target->is_member && (get_prop(target->prop, member_prop) != NULL)) { + target = get_prop(target->prop, member_prop)->body.member.member; + } + Chain *query_tail; + for (query_tail = query; *query_tail != NULL; query_tail = &(*query_tail)->next) { + if ((*query_tail)->name == target) { + return; + } + } + *query_tail = ALLOC(Chain); + (*query_tail)->name = target; + (*query_tail)->next = NULL; +} + |