From 7e6b620e25f4241293f10701c51ba94a57bcfab6 Mon Sep 17 00:00:00 2001 From: Lorenzo Di Gregorio Date: Tue, 19 Oct 2010 13:34:10 +0200 Subject: [PATCH] Support for GNU make dependency generation. all files on the command line are targets and all read files are prerequisites. The dependency information gets generated in the form: target1 : prerequisiteA ... target2 : prerequisiteX ... of course, targets can be prerequisites of other targets. All prerequisites which are not listed as targets already, become phony targets like: prerequisiteJ : prerequisiteK : the option to generate dependency information is -X,--depend=FILE. --- m4/input.c | 58 +++++++++++++++++++++++++++++- m4/m4module.h | 5 ++- m4/m4private.h | 5 +++ modules/m4.c | 2 +- src/main.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 173 insertions(+), 6 deletions(-) diff --git a/m4/input.c b/m4/input.c index 3804b66..85a5ff5 100644 --- a/m4/input.c +++ b/m4/input.c @@ -428,6 +428,48 @@ file_consume (m4_input_block *me, m4 *context, size_t len) assert (false); } +/* m4_add_dep () adds new files to the list of prerequisites or to the list of + target files. The list entries consist of a pointer to the next entry + followed by a zero-terminated C string. */ + +void m4_add_dep(void **list, const char *title) +{ + void *this; + void *last; + void *buffer; + + last = NULL; + this = *list; + + while(this != NULL) + { + if (strcmp((char *) (((void **) this)+1),title) == 0) return; + last = this; + this = *((void **) this); + } + + buffer = malloc(sizeof(void *)+strlen(title)); + + if (buffer == NULL) + { + assert (!"ERROR: failed to allocate memory."); + abort (); + } + + strcpy((char *) (((void **) buffer)+1),title); + *((void **) buffer) = NULL; + + if (last == NULL) + { + *list = buffer; + return; + } + + *((void **) last) = buffer; + return; + +} + /* m4_push_file () pushes an input file FP with name TITLE on the input stack, saving the current file name and line number. If next is non-NULL, this push invalidates a call to m4_push_string_init (), @@ -439,7 +481,7 @@ file_consume (m4_input_block *me, m4 *context, size_t len) alone is taken as belonging to the line it ends, and the current line number is not incremented until the next character is read. */ void -m4_push_file (m4 *context, FILE *fp, const char *title, bool close_file) +m4_push_file (m4 *context, FILE *fp, const char *title, bool close_file, bool prereq, bool target) { m4_input_block *i; @@ -449,6 +491,20 @@ m4_push_file (m4 *context, FILE *fp, const char *title, bool close_file) next = NULL; } + if (context->dep_file != NULL) + { + if (prereq == true) + { + m4_add_dep(&(context->prereqs), title); + m4_add_dep(&(context->all_prereqs), title); + } + if (target == true) + { + m4_add_dep(&(context->targets), title); + m4_add_dep(&(context->all_targets), title); + } + } + m4_debug_message (context, M4_DEBUG_TRACE_INPUT, _("input read from %s"), quotearg_style (locale_quoting_style, title)); diff --git a/m4/m4module.h b/m4/m4module.h index fa245ec..d61a02a 100644 --- a/m4/m4module.h +++ b/m4/m4module.h @@ -522,13 +522,16 @@ extern void m4_skip_line (m4 *context, const m4_call_info *); /* push back input */ -extern void m4_push_file (m4 *, FILE *, const char *, bool); +extern void m4_push_file (m4 *, FILE *, const char *, bool, bool, bool); extern void m4_push_builtin (m4 *, m4_obstack *, m4_symbol_value *); extern m4_obstack *m4_push_string_init (m4 *, const char *, int); extern void m4_push_string_finish (void); extern bool m4_pop_wrapup (m4 *); extern void m4_input_print (m4 *, m4_obstack *, int); +/* dependencies */ + +extern void m4_add_dep (void **, const char *); /* --- OUTPUT MANAGEMENT --- */ diff --git a/m4/m4private.h b/m4/m4private.h index f7b47f8..a205435 100644 --- a/m4/m4private.h +++ b/m4/m4private.h @@ -65,6 +65,11 @@ struct m4 { int output_line; /* Current output line. */ FILE * debug_file; /* File for debugging output. */ + FILE * dep_file; + void * prereqs; + void * all_prereqs; + void * targets; + void * all_targets; m4_obstack trace_messages; int exit_status; /* Cumulative exit status. */ int current_diversion; /* Current output diversion. */ diff --git a/modules/m4.c b/modules/m4.c index 9091d81..9696320 100644 --- a/modules/m4.c +++ b/modules/m4.c @@ -684,7 +684,7 @@ include (m4 *context, int argc, m4_macro_args *argv, bool silent) return; } - m4_push_file (context, fp, name, true); + m4_push_file (context, fp, name, true, true, false); free (name); } diff --git a/src/main.c b/src/main.c index 240e241..148c830 100644 --- a/src/main.c +++ b/src/main.c @@ -101,6 +101,7 @@ Operation modes:\n\ -r, --regexp-syntax[=SPEC] set default regexp syntax to SPEC [GNU_M4]\n\ --safer disable potentially unsafe builtins\n\ -W, --warnings enable all warnings\n\ + -X, --depend=FILE output makefile dependencies into FILE\n\ "), stdout); puts (""); fputs (_("\ @@ -247,6 +248,7 @@ static const struct option long_options[] = {"traditional", no_argument, NULL, 'G'}, {"undefine", required_argument, NULL, 'U'}, {"warnings", no_argument, NULL, 'W'}, + {"depend", required_argument, NULL, 'X'}, {"arglength", required_argument, NULL, ARGLENGTH_OPTION}, {"debugfile", optional_argument, NULL, DEBUGFILE_OPTION}, @@ -272,7 +274,7 @@ static const struct option long_options[] = behavior also handles -s between files. Starting OPTSTRING with '-' forces getopt_long to hand back file names as arguments to opt '\1', rather than reordering the command line. */ -#define OPTSTRING "-B:D:EF:GH:I:L:M:PQR:S:T:U:Wbcd::egil:m:o:p:r::st:" +#define OPTSTRING "-B:D:EF:GH:I:L:M:PQR:S:T:U:X:Wbcd::egil:m:o:p:r::st:" /* For determining whether to be interactive. */ enum interactive_choice @@ -304,7 +306,7 @@ process_file (m4 *context, const char *name) if (STREQ (name, "-")) /* TRANSLATORS: This is a short name for `standard input', used when a command line file was given as `-'. */ - m4_push_file (context, stdin, _("stdin"), false); + m4_push_file (context, stdin, _("stdin"), false, false, false); else { char *full_name; @@ -315,10 +317,43 @@ process_file (m4 *context, const char *name) quotearg_style (locale_quoting_style, name)); return; } - m4_push_file (context, fp, full_name, true); + m4_push_file (context, fp, full_name, true, false, true); free (full_name); } m4_macro_expand_input (context); + + /* Dump the dependencies */ + + if (context->dep_file != NULL) + { + void *last; + void *this; + + this = context->targets; + while(this != NULL) + { + fprintf(context->dep_file,"%s ",(char *) (((void **) this)+1)); + last = this; + this = *((void **) this); + free(last); + } + + fprintf(context->dep_file,":", name); + + this = context->prereqs; + while(this != NULL) + { + fprintf(context->dep_file," %s",(char *) (((void **) this)+1)); + last = this; + this = *((void **) this); + free(last); + } + + fprintf(context->dep_file,"\n"); + + } + context->targets = NULL; + context->prereqs = NULL; } @@ -357,6 +392,12 @@ main (int argc, char *const *argv, char *const *envp) m4__module_init (context); + context->dep_file = NULL; + context->prereqs = NULL; + context->all_prereqs = NULL; + context->targets = NULL; + context->all_targets = NULL; + #ifdef USE_STACKOVF setup_stackovf_trap (argv, envp, stackovf_handler); #endif @@ -501,6 +542,15 @@ main (int argc, char *const *argv, char *const *envp) } break; + case 'X': + if ((context->dep_file = fopen (optarg,"w")) == NULL) + { + m4_error (context, EXIT_FAILURE, 0, NULL, + _("failed to open dependency file %s for writing"), + quotearg_style (locale_quoting_style, optarg)); + } + break; + case 'P': m4_set_prefix_builtins_opt (context, true); break; @@ -772,6 +822,59 @@ main (int argc, char *const *argv, char *const *envp) for (; optind < argc; optind++) process_file (context, argv[optind]); + /* Dump the dependencies (phony targets) */ + + if (context->dep_file != NULL) + { + void *last; + void *this; + void *that; + bool seen; + + this = context->all_prereqs; + while (this != NULL) + { + /* check whether the file in 'this' is contained in context->all_targets */ + seen = false; + that = context->all_targets; + while (that != NULL) + if (strcmp((char *) (((void **) this)+1),(char *) (((void **) that)+1)) == 0) + { + seen = true; + break; + } + else + that = *((void **) that); + + if (seen == false) + fprintf(context->dep_file,"%s :\n",(char *) (((void **) this)+1)); + + last = this; + this = *((void **) this); + free(last); + } + } + context->all_prereqs = NULL; + + /* free all_targets */ + + void *that; + void *last; + that = context->all_targets; + while (that != NULL) + { + last = that; + that = *((void **) that); + free(last); + } + context->all_targets = NULL; + + if (fclose(context->dep_file) != 0) + { + assert (!"INTERNAL ERROR: cannot close dependency file."); + abort (); + } + /* Now handle wrapup text. FIXME - when -F is in effect, should wrapped text be frozen? */ while (m4_pop_wrapup (context)) -- 1.7.0.4