Merge tag 'kbuild-v6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy...
[sfrench/cifs-2.6.git] / scripts / basic / fixdep.c
index f932aeaba71a2e7696c9083896ac441d06ca08fa..fa562806c2bebed28b9bf68d251880dd1252d47d 100644 (file)
@@ -70,7 +70,7 @@
  *
  * It first generates a line
  *
- *   cmd_<target> = <cmdline>
+ *   savedcmd_<target> = <cmdline>
  *
  * and then basically copies the .<target>.d file to stdout, in the
  * process filtering out the dependency on autoconf.h and adding
@@ -94,6 +94,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <string.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <ctype.h>
@@ -112,7 +113,7 @@ struct item {
 };
 
 #define HASHSZ 256
-static struct item *hashtab[HASHSZ];
+static struct item *config_hashtab[HASHSZ], *file_hashtab[HASHSZ];
 
 static unsigned int strhash(const char *str, unsigned int sz)
 {
@@ -124,25 +125,11 @@ static unsigned int strhash(const char *str, unsigned int sz)
        return hash;
 }
 
-/*
- * Lookup a value in the configuration string.
- */
-static int is_defined_config(const char *name, int len, unsigned int hash)
-{
-       struct item *aux;
-
-       for (aux = hashtab[hash % HASHSZ]; aux; aux = aux->next) {
-               if (aux->hash == hash && aux->len == len &&
-                   memcmp(aux->name, name, len) == 0)
-                       return 1;
-       }
-       return 0;
-}
-
 /*
  * Add a new value to the configuration string.
  */
-static void define_config(const char *name, int len, unsigned int hash)
+static void add_to_hashtable(const char *name, int len, unsigned int hash,
+                            struct item *hashtab[])
 {
        struct item *aux = malloc(sizeof(*aux) + len);
 
@@ -157,17 +144,34 @@ static void define_config(const char *name, int len, unsigned int hash)
        hashtab[hash % HASHSZ] = aux;
 }
 
+/*
+ * Lookup a string in the hash table. If found, just return true.
+ * If not, add it to the hashtable and return false.
+ */
+static bool in_hashtable(const char *name, int len, struct item *hashtab[])
+{
+       struct item *aux;
+       unsigned int hash = strhash(name, len);
+
+       for (aux = hashtab[hash % HASHSZ]; aux; aux = aux->next) {
+               if (aux->hash == hash && aux->len == len &&
+                   memcmp(aux->name, name, len) == 0)
+                       return true;
+       }
+
+       add_to_hashtable(name, len, hash, hashtab);
+
+       return false;
+}
+
 /*
  * Record the use of a CONFIG_* word.
  */
 static void use_config(const char *m, int slen)
 {
-       unsigned int hash = strhash(m, slen);
-
-       if (is_defined_config(m, slen, hash))
-           return;
+       if (in_hashtable(m, slen, config_hashtab))
+               return;
 
-       define_config(m, slen, hash);
        /* Print out a dependency path from a symbol name. */
        printf("    $(wildcard include/config/%.*s) \\\n", slen, m);
 }
@@ -246,80 +250,158 @@ static int is_ignored_file(const char *s, int len)
               str_ends_with(s, len, "include/generated/autoksyms.h");
 }
 
+/* Do not parse these files */
+static int is_no_parse_file(const char *s, int len)
+{
+       /* rustc may list binary files in dep-info */
+       return str_ends_with(s, len, ".rlib") ||
+              str_ends_with(s, len, ".rmeta") ||
+              str_ends_with(s, len, ".so");
+}
+
 /*
  * Important: The below generated source_foo.o and deps_foo.o variable
  * assignments are parsed not only by make, but also by the rather simple
  * parser in scripts/mod/sumversion.c.
  */
-static void parse_dep_file(char *m, const char *target)
+static void parse_dep_file(char *p, const char *target)
 {
-       char *p;
-       int is_last, is_target;
-       int saw_any_target = 0;
-       int is_first_dep = 0;
-       void *buf;
-
-       while (1) {
-               /* Skip any "white space" */
-               while (*m == ' ' || *m == '\\' || *m == '\n')
-                       m++;
-
-               if (!*m)
+       bool saw_any_target = false;
+       bool is_target = true;
+       bool is_source = false;
+       bool need_parse;
+       char *q, saved_c;
+
+       while (*p) {
+               /* handle some special characters first. */
+               switch (*p) {
+               case '#':
+                       /*
+                        * skip comments.
+                        * rustc may emit comments to dep-info.
+                        */
+                       p++;
+                       while (*p != '\0' && *p != '\n') {
+                               /*
+                                * escaped newlines continue the comment across
+                                * multiple lines.
+                                */
+                               if (*p == '\\')
+                                       p++;
+                               p++;
+                       }
+                       continue;
+               case ' ':
+               case '\t':
+                       /* skip whitespaces */
+                       p++;
+                       continue;
+               case '\\':
+                       /*
+                        * backslash/newline combinations continue the
+                        * statement. Skip it just like a whitespace.
+                        */
+                       if (*(p + 1) == '\n') {
+                               p += 2;
+                               continue;
+                       }
                        break;
-
-               /* Find next "white space" */
-               p = m;
-               while (*p && *p != ' ' && *p != '\\' && *p != '\n')
+               case '\n':
+                       /*
+                        * Makefiles use a line-based syntax, where the newline
+                        * is the end of a statement. After seeing a newline,
+                        * we expect the next token is a target.
+                        */
                        p++;
-               is_last = (*p == '\0');
-               /* Is the token we found a target name? */
-               is_target = (*(p-1) == ':');
-               /* Don't write any target names into the dependency file */
-               if (is_target) {
-                       /* The /next/ file is the first dependency */
-                       is_first_dep = 1;
-               } else if (!is_ignored_file(m, p - m)) {
-                       *p = '\0';
-
+                       is_target = true;
+                       continue;
+               case ':':
                        /*
-                        * Do not list the source file as dependency, so that
-                        * kbuild is not confused if a .c file is rewritten
-                        * into .S or vice versa. Storing it in source_* is
-                        * needed for modpost to compute srcversions.
+                        * assume the first dependency after a colon as the
+                        * source file.
                         */
-                       if (is_first_dep) {
+                       p++;
+                       is_target = false;
+                       is_source = true;
+                       continue;
+               }
+
+               /* find the end of the token */
+               q = p;
+               while (*q != ' ' && *q != '\t' && *q != '\n' && *q != '#' && *q != ':') {
+                       if (*q == '\\') {
                                /*
-                                * If processing the concatenation of multiple
-                                * dependency files, only process the first
-                                * target name, which will be the original
-                                * source name, and ignore any other target
-                                * names, which will be intermediate temporary
-                                * files.
+                                * backslash/newline combinations work like as
+                                * a whitespace, so this is the end of token.
                                 */
-                               if (!saw_any_target) {
-                                       saw_any_target = 1;
-                                       printf("source_%s := %s\n\n",
-                                              target, m);
-                                       printf("deps_%s := \\\n", target);
+                               if (*(q + 1) == '\n')
+                                       break;
+
+                               /* escaped special characters */
+                               if (*(q + 1) == '#' || *(q + 1) == ':') {
+                                       memmove(p + 1, p, q - p);
+                                       p++;
                                }
-                               is_first_dep = 0;
-                       } else {
-                               printf("  %s \\\n", m);
+
+                               q++;
                        }
 
-                       buf = read_file(m);
-                       parse_config_file(buf);
-                       free(buf);
+                       if (*q == '\0')
+                               break;
+                       q++;
                }
 
-               if (is_last)
-                       break;
+               /* Just discard the target */
+               if (is_target) {
+                       p = q;
+                       continue;
+               }
+
+               saved_c = *q;
+               *q = '\0';
+               need_parse = false;
 
                /*
-                * Start searching for next token immediately after the first
-                * "whitespace" character that follows this token.
+                * Do not list the source file as dependency, so that kbuild is
+                * not confused if a .c file is rewritten into .S or vice versa.
+                * Storing it in source_* is needed for modpost to compute
+                * srcversions.
                 */
-               m = p + 1;
+               if (is_source) {
+                       /*
+                        * The DT build rule concatenates multiple dep files.
+                        * When processing them, only process the first source
+                        * name, which will be the original one, and ignore any
+                        * other source names, which will be intermediate
+                        * temporary files.
+                        *
+                        * rustc emits the same dependency list for each
+                        * emission type. It is enough to list the source name
+                        * just once.
+                        */
+                       if (!saw_any_target) {
+                               saw_any_target = true;
+                               printf("source_%s := %s\n\n", target, p);
+                               printf("deps_%s := \\\n", target);
+                               need_parse = true;
+                       }
+               } else if (!is_ignored_file(p, q - p) &&
+                          !in_hashtable(p, q - p, file_hashtab)) {
+                       printf("  %s \\\n", p);
+                       need_parse = true;
+               }
+
+               if (need_parse && !is_no_parse_file(p, q - p)) {
+                       void *buf;
+
+                       buf = read_file(p);
+                       parse_config_file(buf);
+                       free(buf);
+               }
+
+               is_source = false;
+               *q = saved_c;
+               p = q;
        }
 
        if (!saw_any_target) {
@@ -343,7 +425,7 @@ int main(int argc, char *argv[])
        target = argv[2];
        cmdline = argv[3];
 
-       printf("cmd_%s := %s\n\n", target, cmdline);
+       printf("savedcmd_%s := %s\n\n", target, cmdline);
 
        buf = read_file(depfile);
        parse_dep_file(buf, target);