/*
* 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 2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Included files
*/
#include <mk/defs.h>
#include <mksh/misc.h> /* get_prop() */
/*
* File table of contents
*/
void print_dependencies(register Name target, register Property line);
static void print_deps(register Name target, register Property line);
static void print_more_deps(Name target, Name name);
static void print_filename(Name name);
static Boolean should_print_dep(Property line);
static void print_forest(Name target);
static void print_deplist(Dependency head);
void print_value(register Name value, Daemon daemon);
static void print_rule(register Name target);
static void print_rec_info(Name target);
static Boolean is_out_of_date(Property line);
extern void depvar_print_results (void);
/*
* print_dependencies(target, line)
*
* Print all the dependencies of a target. First print all the Makefiles.
* Then print all the dependencies. Finally, print all the .INIT
* dependencies.
*
* Parameters:
* target The target we print dependencies for
* line We get the dependency list from here
*
* Global variables used:
* done The Name ".DONE"
* init The Name ".INIT"
* makefiles_used List of all makefiles read
*/
void
print_dependencies(register Name target, register Property line)
{
Dependency dp;
static Boolean makefiles_printed = false;
if (target_variants) {
depvar_print_results();
}
if (!makefiles_printed) {
/*
* Search the makefile list for the primary makefile,
* then print it and its inclusions. After that go back
* and print the default.mk file and its inclusions.
*/
for (dp = makefiles_used; dp != NULL; dp = dp->next) {
if (dp->name == primary_makefile) {
break;
}
}
if (dp) {
print_deplist(dp);
for (dp = makefiles_used; dp != NULL; dp = dp->next) {
if (dp->name == primary_makefile) {
break;
}
(void)printf(" %s", dp->name->string_mb);
}
}
(void) printf("\n");
makefiles_printed = true;
}
print_deps(target, line);
/*
print_more_deps(target, init);
print_more_deps(target, done);
*/
if (target_variants) {
print_forest(target);
}
}
/*
* print_more_deps(target, name)
*
* Print some special dependencies.
* These are the dependencies for the .INIT and .DONE targets.
*
* Parameters:
* target Target built during make run
* name Special target to print dependencies for
*
* Global variables used:
*/
static void
print_more_deps(Name target, Name name)
{
Property line;
register Dependency dependencies;
line = get_prop(name->prop, line_prop);
if (line != NULL && line->body.line.dependencies != NULL) {
(void) printf("%s:\t", target->string_mb);
print_deplist(line->body.line.dependencies);
(void) printf("\n");
for (dependencies= line->body.line.dependencies;
dependencies != NULL;
dependencies= dependencies->next) {
print_deps(dependencies->name,
get_prop(dependencies->name->prop, line_prop));
}
}
}
/*
* print_deps(target, line, go_recursive)
*
* Print a regular dependency list. Append to this information which
* indicates whether or not the target is recursive.
*
* Parameters:
* target target to print dependencies for
* line We get the dependency list from here
* go_recursive Should we show all dependencies recursively?
*
* Global variables used:
* recursive_name The Name ".RECURSIVE", printed
*/
static void
print_deps(register Name target, register Property line)
{
register Dependency dep;
if ((target->dependency_printed) ||
(target == force)) {
return;
}
target->dependency_printed = true;
/* only print entries that are actually derived and are not leaf
* files and are not the result of sccs get.
*/
if (should_print_dep(line)) {
if ((report_dependencies_level == 2) ||
(report_dependencies_level == 4)) {
if (is_out_of_date(line)) {
(void) printf("1 ");
} else {
(void) printf("0 ");
}
}
print_filename(target);
(void) printf(":\t");
print_deplist(line->body.line.dependencies);
print_rec_info(target);
(void) printf("\n");
for (dep = line->body.line.dependencies;
dep != NULL;
dep = dep->next) {
print_deps(dep->name,
get_prop(dep->name->prop, line_prop));
}
}
}
static Boolean
is_out_of_date(Property line)
{
Dependency dep;
Property line2;
if (line == NULL) {
return false;
}
if (line->body.line.is_out_of_date) {
return true;
}
for (dep = line->body.line.dependencies;
dep != NULL;
dep = dep->next) {
line2 = get_prop(dep->name->prop, line_prop);
if (is_out_of_date(line2)) {
line->body.line.is_out_of_date = true;
return true;
}
}
return false;
}
/*
* Given a dependency print it and all its siblings.
*/
static void
print_deplist(Dependency head)
{
Dependency dp;
for (dp = head; dp != NULL; dp = dp->next) {
if ((report_dependencies_level != 2) ||
((!dp->automatic) ||
(dp->name->is_double_colon))) {
if (dp->name != force) {
putwchar(' ');
print_filename(dp->name);
}
}
}
}
/*
* Print the name of a file for the -P option.
* If the file is a directory put on a trailing slash.
*/
static void
print_filename(Name name)
{
(void) printf("%s", name->string_mb);
/*
if (name->stat.is_dir) {
putwchar('/');
}
*/
}
/*
* should_print_dep(line)
*
* Test if we should print the dependencies of this target.
* The line must exist and either have children dependencies
* or have a command that is not an SCCS command.
*
* Return value:
* true if the dependencies should be printed
*
* Parameters:
* line We get the dependency list from here
*
* Global variables used:
*/
static Boolean
should_print_dep(Property line)
{
if (line == NULL) {
return false;
}
if (line->body.line.dependencies != NULL) {
return true;
}
if (line->body.line.sccs_command) {
return false;
}
return true;
}
/*
* Print out the root nodes of all the dependency trees
* in this makefile.
*/
static void
print_forest(Name target)
{
Name_set::iterator np, e;
Property line;
for (np = hashtab.begin(), e = hashtab.end(); np != e; np++) {
if (np->is_target && !np->has_parent && np != target) {
(void) doname_check(np, true, false, false);
line = get_prop(np->prop, line_prop);
printf("-\n");
print_deps(np, line);
}
}
}
/*
* This is a set of routines for dumping the internal make state
* Used for the -p option
*/
void
print_value(register Name value, Daemon daemon)
{
Chain cp;
if (value == NULL)
(void)printf("=\n");
else
switch (daemon) {
case no_daemon:
(void)printf("= %s\n", value->string_mb);
break;
case chain_daemon:
for (cp= (Chain) value; cp != NULL; cp= cp->next)
(void)printf(cp->next == NULL ? "%s" : "%s ",
cp->name->string_mb);
(void)printf("\n");
break;
};
}
static void
print_rule(register Name target)
{
register Cmd_line rule;
register Property line;
if (((line= get_prop(target->prop, line_prop)) == NULL) ||
((line->body.line.command_template == NULL) &&
(line->body.line.dependencies == NULL)))
return;
print_dependencies(target, line);
for (rule= line->body.line.command_template; rule != NULL; rule= rule->next)
(void)printf("\t%s\n", rule->command_line->string_mb);
}
/*
* If target is recursive, print the following to standard out:
* .RECURSIVE subdir targ Makefile
*/
static void
print_rec_info(Name target)
{
Recursive_make rp;
wchar_t *colon;
report_recursive_init();
rp = find_recursive_target(target);
if (rp) {
/*
* if found, print starting with the space after the ':'
*/
colon = (wchar_t *) wcschr(rp->oldline, (int) colon_char);
(void) printf("%s", colon + 1);
}
}