diff -ur make-3.82/file.c make-wch/file.c --- make-3.82/file.c 2010-07-12 21:20:39.000000000 -0400 +++ make-wch/file.c 2010-08-19 23:28:20.162660391 -0400 @@ -1021,6 +1021,129 @@ hash_print_stats (&files, stdout); } +/* Dump the dependency graph to a Graphviz file (on stdout) */ + +void +print_graph_prereqs (const char *filename, const struct dep *deps) +{ + const struct dep *ood = 0; + + /* Print all normal dependencies; note any order-only deps. */ + for (; deps != 0; deps = deps->next) + if (! deps->ignore_mtime) + printf (" \"%s\" -> \"%s\";\n", filename, dep_name (deps)); + + /* Print order-only deps, if we have any. */ + if (ood) + { + for (ood = ood->next; ood != 0; ood = ood->next) + if (ood->ignore_mtime) + printf (" %s -> %s [style=dotted];\n", filename, dep_name (ood)); + /* XXX: we need to distinguish these some how. + * Is dotting them the right way? */ + } +} + +static void +print_graph_file (const void *item) +{ + const struct file *f = item; + + int built_in_special_target=( + (0==strcmp(f->name,".PHONY")) + || (0==strcmp(f->name,".SUFFIXES")) + || (0==strcmp(f->name,".DEFAULT")) + || (0==strcmp(f->name,".PRECIOUS")) + || (0==strcmp(f->name,".INTERMEDIATE")) + || (0==strcmp(f->name,".SECONDARY")) + || (0==strcmp(f->name,".SECONDEXPANSION")) + || (0==strcmp(f->name,".DELETE_ON_ERROR")) + || (0==strcmp(f->name,".IGNORE")) + || (0==strcmp(f->name,".LOW_RESOLUTION_TIME")) + || (0==strcmp(f->name,".SILENT")) + || (0==strcmp(f->name,".EXPORT_ALL_VARIABLES")) + || (0==strcmp(f->name,".NOTPARALLEL")) + || (0==strcmp(f->name,".ONESHELL")) + || (0==strcmp(f->name,".POSIX")) + ); + if ((f->is_target) && (!built_in_special_target)) + { + printf (" \"%s\" [", f->name); + /* XXX some of these should be attached to the nodes in some way; + * though I'm not sure what style changes should be made for which ones. + * ~ LukeShu + if (f->double_colon) puts (_("// Double-colon rule.")); + if (f->precious) puts (_("// Precious file (prerequisite of .PRECIOUS).")); + */if (f->phony) puts (_(" color=blue "));/* + if (f->cmd_target) puts (_("// Command line target.")); + if (f->dontcare) puts (_("// A default, MAKEFILES, or -include/sinclude makefile.")); + if (f->tried_implicit) puts (_("// Implicit rule search has been done.")); + else puts (_("// Implicit rule search has not been done.")); + if (f->stem != 0) printf (_("// Implicit/static pattern stem: `%s'\n"), f->stem); + if (f->intermediate) puts (_("// File is an intermediate prerequisite.")); + if (f->also_make != 0) + { + const struct dep *d; + fputs (_("# Also makes:"), stdout); + for (d = f->also_make; d != 0; d = d->next) + printf (" %s\n", dep_name (d)); + } + if (f->last_mtime == UNKNOWN_MTIME) puts (_("// Modification time never checked.")); + else if (f->last_mtime == NONEXISTENT_MTIME) puts (_("// File does not exist.")); + else if (f->last_mtime == OLD_MTIME) puts (_("// File is very old.")); + else + { + char buf[FILE_TIMESTAMP_PRINT_LEN_BOUND + 1]; + file_timestamp_sprintf (buf, f->last_mtime); + printf (_("// Last modified %s\n"), buf); + } + if (f->updated) puts (_("// File has been updated.")); + else puts (_("// File has not been updated.")); + switch (f->command_state) + { + case cs_running: puts (_("// Update: Running (THIS IS A BUG).")); break; + case cs_deps_running: puts (_("// Update: Dependencies running (THIS IS A BUG).")); break; + case cs_not_started: + case cs_finished: + switch (f->update_status) + { + case -1: break; + case 0: puts (_("// Update: Successfully")); break; + case 1: assert (question_flag); + puts (_("// Update: Needs to be (-q is set)")); break; + case 2: puts (_("// Update: Failed")); break; + default: puts (_("// Update: Invalid `update_status' value)); + fflush (stdout); + fflush (stderr); + abort (); + } + break; + default: puts (_("// Update: Invalid `command_state' value")); + fflush (stdout); + fflush (stderr); + abort (); + } + if (f->variables != 0) print_file_variables (f); + if (f->cmds != 0) print_commands (f->cmds); + */ + puts("];"); + print_graph_prereqs (f->name, f->deps); + } + + if (f->prev) + print_graph_file ((const void *) f->prev); +} + +void +print_graph (void) +{ + printf ("%sgraph make%i {\n", + (makelevel==0)?"di":"sub", + getpid()); + hash_map (&files, print_graph_file); + puts ("}"); +} + /* Verify the integrity of the data base of files. */ #define VERIFY_CACHED(_p,_n) \ diff -ur make-3.82/filedef.h make-wch/filedef.h --- make-3.82/filedef.h 2010-07-12 21:20:39.000000000 -0400 +++ make-wch/filedef.h 2010-08-19 21:09:34.314660209 -0400 @@ -116,6 +116,7 @@ char *build_target_list (char *old_list); void print_prereqs (const struct dep *deps); void print_file_data_base (void); +void print_graph (void); #if FILE_TIMESTAMP_HI_RES # define FILE_TIMESTAMP_STAT_MODTIME(fname, st) \ diff -ur make-3.82/main.c make-wch/main.c --- make-3.82/main.c 2010-07-19 03:10:53.000000000 -0400 +++ make-wch/main.c 2010-08-21 22:32:56.818417305 -0400 @@ -175,6 +175,11 @@ int print_data_base_flag = 0; +/* Nonzero means don't remake anything, just print the dependency graph + that results from reading the makefile (-g). */ + +int print_graph_flag = 0; + /* Nonzero means don't remake anything; just return a nonzero status if the specified targets are not up to date (-q). */ @@ -321,6 +326,9 @@ -f FILE, --file=FILE, --makefile=FILE\n\ Read FILE as a makefile.\n"), N_("\ + -g, --graph Print make's internal dependency graph\n\ + in Graphviz format, without remaking makefiles.\n"), + N_("\ -h, --help Print this message and exit.\n"), N_("\ -i, --ignore-errors Ignore errors from recipes.\n"), @@ -385,6 +393,7 @@ #endif { 'e', flag, &env_overrides, 1, 1, 0, 0, 0, "environment-overrides", }, { 'f', filename, &makefiles, 0, 0, 0, 0, 0, "file" }, + { 'g', flag, &print_graph_flag, 1, 1, 0, 0, 0, "graph" }, { 'h', flag, &print_usage_flag, 0, 0, 0, 0, 0, "help" }, { 'i', flag, &ignore_errors_flag, 1, 1, 0, 0, 0, "ignore-errors" }, { 'I', filename, &include_directories, 1, 1, 0, 0, 0, @@ -1946,7 +1955,10 @@ define_makeflags (1, 1); rebuilding_makefiles = 1; - status = update_goal_chain (read_makefiles); + if (print_graph_flag) + status = -1; + else + status = update_goal_chain (read_makefiles); rebuilding_makefiles = 0; switch (status) @@ -2278,33 +2290,37 @@ { int status; + if (print_graph_flag) + status=0; + else + { + switch (update_goal_chain (goals)) + { + case -1: + /* Nothing happened. */ + case 0: + /* Updated successfully. */ + status = makefile_status; + break; + case 1: + /* We are under -q and would run some commands. */ + status = MAKE_TROUBLE; + break; + case 2: + /* Updating failed. POSIX.2 specifies exit status >1 for this; + but in VMS, there is only success and failure. */ + status = MAKE_FAILURE; + break; + default: + abort (); + } - switch (update_goal_chain (goals)) - { - case -1: - /* Nothing happened. */ - case 0: - /* Updated successfully. */ - status = makefile_status; - break; - case 1: - /* We are under -q and would run some commands. */ - status = MAKE_TROUBLE; - break; - case 2: - /* Updating failed. POSIX.2 specifies exit status >1 for this; - but in VMS, there is only success and failure. */ - status = MAKE_FAILURE; - break; - default: - abort (); - } - - /* If we detected some clock skew, generate one last warning */ - if (clock_skew_detected) - error (NILF, - _("warning: Clock skew detected. Your build may be incomplete.")); - + /* If we detected some clock skew, generate one last warning */ + if (clock_skew_detected) + error (NILF, + _("warning: Clock skew detected. Your build may be incomplete.")); + } + /* Exit. */ die (status); } @@ -3042,7 +3058,7 @@ { static int printed_version = 0; - char *precede = print_data_base_flag ? "# " : ""; + char *precede = (print_data_base_flag||print_graph_flag) ? "# " : ""; if (printed_version) /* Do it only once. */ @@ -3188,6 +3204,10 @@ if (print_data_base_flag) print_data_base (); + + if (print_graph_flag) + print_graph (); + verify_file_data_base (); clean_jobserver (status);