Hello, I'm following up on this ( http://lists.gnu.org/archive/html/m4-discuss/2010-10/msg00003.html) post, because I've managed to find some time and write a patch for supporting dependency generation with M4, which is something I've been really missing for my makefiles. You find the patch enclosed here as attachment.
To use the patched m4, you just call: m4 -X depfile file1 file2 ... this -X is equivalent to gcc's '-MD -MP -MF'. -MT becomes unnecessary because m4 outputs on stdout and you must set a rule with target and prerequisites in the makefile. If stdin is used, it does not get listed as dependency, of course. Since multiple target files are processed, dependencies are listed for every target. Only prerequisites which have not been listed as targets are listed as phony targets. Internally, I've augmented m4* context with four lists: prereqs, targets, all_prereqs and all_targets. They get allocated and filled by m4_add_dep(), dumped and freed in main(). I've extended m4_push_file() with a few flags to signal how to call m4_add_dep(). Hope the feature is ok and you like it: I'd be happy to see it within the tool. Of course corrections/suggestions/changes/improvements are always welcome! Best Regards, Lorenzo
From 7e6b620e25f4241293f10701c51ba94a57bcfab6 Mon Sep 17 00:00:00 2001 From: Lorenzo Di Gregorio <lorenzo.digrego...@gmail.com> 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
_______________________________________________ M4-patches mailing list M4-patches@gnu.org http://lists.gnu.org/mailman/listinfo/m4-patches