Add the -MP option to emit phony targets
authorH. Peter Anvin <hpa@zytor.com>
Fri, 30 May 2008 04:38:00 +0000 (21:38 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Fri, 30 May 2008 04:38:00 +0000 (21:38 -0700)
Add the -MP option to emit phony targets.  Since this means each
header file has to be visited more than once, change the
implementation to use an internal list of all the dependencies, and
centralize the emission of the dependency files.

CHANGES
doc/nasmdoc.src
nasm.c
nasm.h
preproc.c

diff --git a/CHANGES b/CHANGES
index e60fbc7..f4f480b 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -13,7 +13,7 @@
 * SAFESEH support for Win32, IMAGEREL for Win64 (SEH).
 * %? and %?? to refer to the name of a macro itself.  In particular,
   "%idefine keyword $%?" can be used to make a keyword "disappear".
-* New options for dependency generation: -MD, -MF, -MT, -MQ.
+* New options for dependency generation: -MD, -MF, -MP, -MT, -MQ.
 
 2.02
 ----
index cff4096..6b19199 100644 (file)
@@ -19,6 +19,7 @@
 \IR{-MD} \c{-MD} option
 \IR{-MF} \c{-MF} option
 \IR{-MG} \c{-MG} option
+\IR{-MP} \c{-MP} option
 \IR{-MQ} \c{-MQ} option
 \IR{-MT} \c{-MT} option
 \IR{-On} \c{-On} option
@@ -609,6 +610,14 @@ is not foolproof, as not all characters with special meaning are
 quotable in Make.
 
 
+\S{opt-MP} The \i\c{-MP} Option: Emit phony targets
+
+When used with any of the dependency generation options, the \c{-MP}
+option causes NASM to emit a phony target without dependencies for
+each header file.  This prevents Make from complaining if a header
+file has been removed.
+
+
 \S{opt-F} The \i\c{-F} Option: Selecting a \i{Debug Information Format}
 
 This option is used to select the format of the debug information emitted 
diff --git a/nasm.c b/nasm.c
index 766248e..1eb5e4f 100644 (file)
--- a/nasm.c
+++ b/nasm.c
@@ -38,7 +38,7 @@ struct forwrefinfo {            /* info held on forward refs. */
 static int get_bits(char *value);
 static uint32_t get_cpu(char *cpu_str);
 static void parse_cmdline(int, char **);
-static void assemble_file(char *, FILE *);
+static void assemble_file(char *, StrList **);
 static void register_output_formats(void);
 static void report_error_gnu(int severity, const char *fmt, ...);
 static void report_error_vc(int severity, const char *fmt, ...);
@@ -91,6 +91,7 @@ enum op_type {
 };
 static enum op_type operating_mode;
 /* Dependency flags */
+static bool depend_emit_phony = false;
 static bool depend_missing_ok = false;
 static const char *depend_target = NULL;
 static const char *depend_file = NULL;
@@ -136,7 +137,7 @@ static const char *suppressed_what[ERR_WARN_MAX+1] = {
  * not preprocess their source file.
  */
 
-static void no_pp_reset(char *, int, efunc, evalfunc, ListGen *, FILE *);
+static void no_pp_reset(char *, int, efunc, evalfunc, ListGen *, StrList **);
 static char *no_pp_getline(void);
 static void no_pp_cleanup(int);
 static Preproc no_pp = {
@@ -242,9 +243,50 @@ static void define_macros_late(void)
     pp_pre_define(temp);
 }
 
+static void emit_dependencies(StrList *list)
+{
+    FILE *deps;
+    int linepos, len;
+    StrList *l, *nl;
+
+    if (depend_file && strcmp(depend_file, "-")) {
+       deps = fopen(depend_file, "w");
+       if (!deps) {
+           report_error(ERR_NONFATAL|ERR_NOFILE|ERR_USAGE,
+                        "unable to write dependency file `%s'", depend_file);
+           return;
+       }
+    } else {
+       deps = stdout;
+    }
+    
+    linepos = fprintf(deps, "%s:", depend_target);
+    for (l = list; l; l = l->next) {
+       len = strlen(l->str);
+       if (linepos + len > 62) {
+           fprintf(deps, " \\\n ");
+           linepos = 1;
+       }
+       fprintf(deps, " %s", l->str);
+       linepos += len+1;
+    }
+    fprintf(deps, "\n\n");
+    
+    for (l = list; l; l = nl) {
+       if (depend_emit_phony)
+           fprintf(deps, "%s:\n\n", l->str);
+           
+       nl = l->next;
+       nasm_free(l);
+    }
+
+    if (deps != stdout)
+       fclose(deps);
+}
+
 int main(int argc, char **argv)
 {
-    FILE *depends;
+    StrList *depend_list = NULL, **depend_ptr;
 
     time(&official_compile_time);
 
@@ -289,16 +331,8 @@ int main(int argc, char **argv)
     /* define some macros dependent of command-line */
     define_macros_late();
 
-    depends = NULL;
-    if (depend_file) {
-       depends = fopen(depend_file, "w");
-       if (!depends) {
-           report_error(ERR_FATAL | ERR_NOFILE,
-                        "unable to open dependencies file `%s'",
-                        depend_file);
-       }
-    }
-
+    depend_ptr = (depend_file || (operating_mode == op_depend))
+       ? &depend_list : NULL;
     if (!depend_target)
        depend_target = outname;
 
@@ -307,18 +341,14 @@ int main(int argc, char **argv)
         {
             char *line;
 
-           if (!depends)
-               depends = stdout;
-
            if (depend_missing_ok)
                pp_include_path(NULL);  /* "assume generated" */
 
             preproc->reset(inname, 0, report_error, evaluate, &nasmlist,
-                          depends);
+                          depend_ptr);
             if (outname[0] == '\0')
                 ofmt->filename(inname, outname, report_error);
             ofile = NULL;
-            fprintf(depends, "%s: %s", depend_target, inname);
             while ((line = preproc->getline()))
                 nasm_free(line);
             preproc->cleanup(0);
@@ -345,9 +375,7 @@ int main(int argc, char **argv)
 
            /* pass = 1; */
             preproc->reset(inname, 2, report_error, evaluate, &nasmlist,
-                          depends);
-           if (depends)
-               fprintf(depends, "%s: %s", depend_target, inname);
+                          depend_ptr);
 
             while ((line = preproc->getline())) {
                 /*
@@ -404,7 +432,7 @@ int main(int argc, char **argv)
 
             ofmt->init(ofile, report_error, define_label, evaluate);
 
-            assemble_file(inname, depends);
+            assemble_file(inname, depend_ptr);
 
             if (!terminate_after_phase) {
                 ofmt->cleanup(using_debug_info);
@@ -424,11 +452,8 @@ int main(int argc, char **argv)
         break;
     }
 
-    if (depends) {
-       putc('\n', depends);
-       if (depends != stdout)
-           fclose(depends);
-    }
+    if (depend_list)
+       emit_dependencies(depend_list);
 
     if (want_usage)
         usage();
@@ -825,13 +850,15 @@ static bool process_arg(char *p, char *q)
         case 'M':
            switch (p[2]) {
            case 0:
-           case 'M':
                operating_mode = op_depend;
                break;
            case 'G':
                operating_mode = op_depend;
                depend_missing_ok = true;
                break;
+           case 'P':
+               depend_emit_phony = true;
+               break;
            case 'D':
                depend_file = q;
                advance = true;
@@ -1085,8 +1112,10 @@ static void parse_cmdline(int argc, char **argv)
     if (!*inname)
         report_error(ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
                      "no input file specified");
-    else if (!strcmp(inname, errname) || !strcmp(inname, outname) ||
-       !strcmp(inname, listname))
+    else if (!strcmp(inname, errname) ||
+            !strcmp(inname, outname) ||
+            !strcmp(inname, listname) ||
+            (depend_file && !strcmp(inname, depend_file)))
        report_error(ERR_FATAL | ERR_NOFILE | ERR_USAGE,
                     "file `%s' is both input and output file",
                     inname);
@@ -1113,7 +1142,7 @@ static const char *directives[] = {
 };
 static enum directives getkw(char **directive, char **value);
 
-static void assemble_file(char *fname, FILE *depends)
+static void assemble_file(char *fname, StrList **depend_ptr)
 {
     char *directive, *value, *p, *q, *special, *line, debugid[80];
     insn output_ins;
@@ -1158,9 +1187,7 @@ static void assemble_file(char *fname, FILE *depends)
             offsets = raa_init();
         }
         preproc->reset(fname, pass1, report_error, evaluate, &nasmlist,
-                      pass1 == 2 ? depends : NULL);
-       if (pass1 == 2 && depends)
-           fprintf(depends, "%s: %s", depend_target, inname);
+                      pass1 == 2 ? depend_ptr : NULL);
            
         globallineno = 0;
         if (passn == 1)
@@ -1950,7 +1977,7 @@ static ListGen *no_pp_list;
 static int32_t no_pp_lineinc;
 
 static void no_pp_reset(char *file, int pass, efunc error, evalfunc eval,
-                        ListGen * listgen, FILE *depends)
+                        ListGen * listgen, StrList **deplist)
 {
     src_set_fname(nasm_strdup(file));
     src_set_linnum(0);
@@ -1963,7 +1990,13 @@ static void no_pp_reset(char *file, int pass, efunc error, evalfunc eval,
     no_pp_list = listgen;
     (void)pass;                 /* placate compilers */
     (void)eval;                 /* placate compilers */
-    (void)depends;              /* placate compilers */
+
+    if (deplist) {
+       StrList *sl = nasm_malloc(strlen(file)+1+sizeof sl->next);
+       sl->next = NULL;
+       strcpy(sl->str, file);
+       *deplist = sl;
+    }
 }
 
 static char *no_pp_getline(void)
diff --git a/nasm.h b/nasm.h
index 4c7b338..384fb65 100644 (file)
--- a/nasm.h
+++ b/nasm.h
@@ -291,6 +291,14 @@ typedef expr *(*evalfunc) (scanner sc, void *scprivate,
 #define EXPR_SEGBASE   (EXPR_REG_END+4)
 
 /*
+ * Linked list of strings...
+ */
+typedef struct string_list {
+    struct string_list *next;
+    char str[1];
+} StrList;
+
+/*
  * preprocessors ought to look like this:
  */
 typedef struct preproc_ops {
@@ -299,7 +307,7 @@ typedef struct preproc_ops {
      * of the pass, an error reporting function, an evaluator
      * function, and a listing generator to talk to.
      */
-    void (*reset) (char *, int, efunc, evalfunc, ListGen *, FILE *);
+    void (*reset) (char *, int, efunc, evalfunc, ListGen *, StrList **);
 
     /*
      * Called to fetch a line of preprocessed source. The line
index 7a305b3..c42cdfd 100644 (file)
--- a/preproc.c
+++ b/preproc.c
@@ -327,7 +327,7 @@ static efunc _error;            /* Pointer to client-provided error reporting fu
 static evalfunc evaluate;
 
 static int pass;                /* HACK: pass 0 = generate dependencies only */
-static FILE *deplist;          /* Write dependencies to this FILE */
+static StrList **dephead, **deptail; /* Dependency list */
 
 static uint64_t unique;    /* unique identifier numbers */
 
@@ -1257,51 +1257,63 @@ static Context *get_ctx(char *name, bool all_contexts)
 }
 
 /*
+ * Check to see if a file is already in a string list
+ */
+static bool in_list(const StrList *list, const char *str)
+{
+    while (list) {
+       if (!strcmp(list->str, str))
+           return true;
+       list = list->next;
+    }
+    return false;
+}
+
+/*
  * Open an include file. This routine must always return a valid
  * file pointer if it returns - it's responsible for throwing an
  * ERR_FATAL and bombing out completely if not. It should also try
  * the include path one by one until it finds the file or reaches
  * the end of the path.
  */
-static FILE *inc_fopen(char *file)
+static FILE *inc_fopen(const char *file)
 {
     FILE *fp;
-    char *prefix = "", *combine;
+    char *prefix = "";
     IncPath *ip = ipath;
-    static int namelen = 0;
     int len = strlen(file);
+    size_t prefix_len = 0;
+    StrList *sl;
 
     while (1) {
-        combine = nasm_malloc(strlen(prefix) + len + 1);
-        strcpy(combine, prefix);
-        strcat(combine, file);
-        fp = fopen(combine, "r");
-       if (fp && deplist) {
-            namelen += strlen(combine) + 1;
-            if (namelen > 62) {
-                fprintf(deplist, " \\\n  ");
-                namelen = 2;
-            }
-            fprintf(deplist, " %s", combine);
-        }
-        nasm_free(combine);
+        sl = nasm_malloc(prefix_len+len+1+sizeof sl->next);
+       memcpy(sl->str, prefix, prefix_len);
+       memcpy(sl->str+prefix_len, file, len+1);
+        fp = fopen(sl->str, "r");
+       if (fp && dephead && !in_list(*dephead, sl->str)) {
+           sl->next = NULL;
+           *deptail = sl;
+           deptail = &sl->next;
+        } else {
+           nasm_free(sl);
+       }
         if (fp)
             return fp;
         if (!ip)
             break;
         prefix = ip->path;
         ip = ip->next;
-
-       if (!prefix) {
-               /* -MG given and file not found */
-               if (deplist) {
-                       namelen += strlen(file) + 1;
-                       if (namelen > 62) {
-                           fprintf(deplist, " \\\n  ");
-                           namelen = 2;
-                       }
-                       fprintf(deplist, " %s", file);
-               }
+       if (prefix) {
+           prefix_len = strlen(prefix);
+       } else {
+           /* -MG given and file not found */
+           if (dephead && !in_list(*dephead, file)) {
+               sl = nasm_malloc(len+1+sizeof sl->next);
+               sl->next = NULL;
+               strcpy(sl->str, file);
+               *deptail = sl;
+               deptail = &sl->next;
+           }
            return NULL;
        }
     }
@@ -3734,7 +3746,7 @@ static void error(int severity, const char *fmt, ...)
 
 static void
 pp_reset(char *file, int apass, efunc errfunc, evalfunc eval,
-         ListGen * listgen, FILE * adeplist)
+         ListGen * listgen, StrList **deplist)
 {
     _error = errfunc;
     cstk = NULL;
@@ -3763,7 +3775,14 @@ pp_reset(char *file, int apass, efunc errfunc, evalfunc eval,
     list = listgen;
     evaluate = eval;
     pass = apass;
-    deplist = adeplist;
+    dephead = deptail = deplist;
+    if (deplist) {
+       StrList *sl = nasm_malloc(strlen(file)+1+sizeof sl->next);
+       sl->next = NULL;
+       strcpy(sl->str, file);
+       *deptail = sl;
+       deptail = &sl->next;
+    }
 }
 
 static char *pp_getline(void)