[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Minios-devel] [UNIKRAFT PATCH v3 07/23] kconfig: Import fixdep from Linux kernel



Hi Sharan,

This patch looks ok.

-- Felipe

Reviewed-by: Felipe Huici <felipe.huici@xxxxxxxxx>

On 19.09.19, 11:17, "Minios-devel on behalf of Sharan Santhanam" 
<minios-devel-bounces@xxxxxxxxxxxxxxxxxxxx on behalf of 
Sharan.Santhanam@xxxxxxxxx> wrote:

    Import fixdep from the linux kernel.
    Tag v5.2
    
    Signed-off-by: Sharan Santhanam <sharan.santhanam@xxxxxxxxx>
    ---
     support/kconfig.new/Makefile.br |   7 +
     support/kconfig.new/fixdep.c    | 379 
++++++++++++++++++++++++++++++++++++++++
     2 files changed, 386 insertions(+)
     create mode 100644 support/kconfig.new/fixdep.c
    
    diff --git a/support/kconfig.new/Makefile.br 
b/support/kconfig.new/Makefile.br
    index c11f297..58e6e75 100644
    --- a/support/kconfig.new/Makefile.br
    +++ b/support/kconfig.new/Makefile.br
    @@ -19,6 +19,7 @@ host-cxxmulti := $(foreach m,$(__hostprogs),\
                $(if $($(m)-cxxobjs),$(m),$(if $($(m)-objs),)))
     host-cobjs := $(addprefix $(obj)/,$(sort $(foreach 
m,$(__hostprogs),$($(m)-objs))))
     host-cxxobjs := $(addprefix $(obj)/,$(sort $(foreach 
m,$(__hostprogs),$($(m)-cxxobjs))))
    +fixdep-objs := $(obj)/fixdep.o
     
     HOST_EXTRACFLAGS += -I$(obj) -DCONFIG_=\"\"
     
    @@ -31,6 +32,12 @@ $(host-cmulti): %: $(host-cobjs) $(host-cshlib)
     $(host-cxxmulti): %: $(host-cxxobjs) $(host-cobjs) $(host-cshlib)
        $(HOSTCXX) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCXXFLAGS_$@) 
$(addprefix $(obj)/,$($(@F)-objs) $($(@F)-cxxobjs)) $(HOSTLOADLIBES_$(@F)) -o 
$(obj)/$@
     
    +$(obj)/fixdep: $(fixdep-objs)
    +   $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCFLAGS_$(@F)) $< -o $@
    +
    +$(fixdep-objs): $(src)/fixdep.c
    +   $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTCFLAGS) $(HOSTCFLAGS_$(@F)) -c $< 
-o $@
    +
     clean:
        $(Q)rm -f $(addprefix $(obj)/,$(clean-files))
     distclean: clean
    diff --git a/support/kconfig.new/fixdep.c b/support/kconfig.new/fixdep.c
    new file mode 100644
    index 0000000..facbd60
    --- /dev/null
    +++ b/support/kconfig.new/fixdep.c
    @@ -0,0 +1,379 @@
    +/*
    + * "Optimize" a list of dependencies as spit out by gcc -MD
    + * for the kernel build
    + * 
===========================================================================
    + *
    + * Author       Kai Germaschewski
    + * Copyright    2002 by Kai Germaschewski  <kai.germaschewski@xxxxxx>
    + *
    + * This software may be used and distributed according to the terms
    + * of the GNU General Public License, incorporated herein by reference.
    + *
    + *
    + * Introduction:
    + *
    + * gcc produces a very nice and correct list of dependencies which
    + * tells make when to remake a file.
    + *
    + * To use this list as-is however has the drawback that virtually
    + * every file in the kernel includes autoconf.h.
    + *
    + * If the user re-runs make *config, autoconf.h will be
    + * regenerated.  make notices that and will rebuild every file which
    + * includes autoconf.h, i.e. basically all files. This is extremely
    + * annoying if the user just changed CONFIG_HIS_DRIVER from n to m.
    + *
    + * So we play the same trick that "mkdep" played before. We replace
    + * the dependency on autoconf.h by a dependency on every config
    + * option which is mentioned in any of the listed prerequisites.
    + *
    + * kconfig populates a tree in include/config/ with an empty file
    + * for each config symbol and when the configuration is updated
    + * the files representing changed config options are touched
    + * which then let make pick up the changes and the files that use
    + * the config symbols are rebuilt.
    + *
    + * So if the user changes his CONFIG_HIS_DRIVER option, only the objects
    + * which depend on "include/config/his/driver.h" will be rebuilt,
    + * so most likely only his driver ;-)
    + *
    + * The idea above dates, by the way, back to Michael E Chastain, AFAIK.
    + *
    + * So to get dependencies right, there are two issues:
    + * o if any of the files the compiler read changed, we need to rebuild
    + * o if the command line given to the compile the file changed, we
    + *   better rebuild as well.
    + *
    + * The former is handled by using the -MD output, the later by saving
    + * the command line used to compile the old object and comparing it
    + * to the one we would now use.
    + *
    + * Again, also this idea is pretty old and has been discussed on
    + * kbuild-devel a long time ago. I don't have a sensibly working
    + * internet connection right now, so I rather don't mention names
    + * without double checking.
    + *
    + * This code here has been based partially based on mkdep.c, which
    + * says the following about its history:
    + *
    + *   Copyright abandoned, Michael Chastain, <mailto:mec@xxxxxxxxx>.
    + *   This is a C version of syncdep.pl by Werner Almesberger.
    + *
    + *
    + * It is invoked as
    + *
    + *   fixdep <depfile> <target> <cmdline>
    + *
    + * and will read the dependency file <depfile>
    + *
    + * The transformed dependency snipped is written to stdout.
    + *
    + * It first generates a line
    + *
    + *   cmd_<target> = <cmdline>
    + *
    + * and then basically copies the .<target>.d file to stdout, in the
    + * process filtering out the dependency on autoconf.h and adding
    + * dependencies on include/config/my/option.h for every
    + * CONFIG_MY_OPTION encountered in any of the prerequisites.
    + *
    + * It will also filter out all the dependencies on *.ver. We need
    + * to make sure that the generated version checksum are globally up
    + * to date before even starting the recursive build, so it's too late
    + * at this point anyway.
    + *
    + * We don't even try to really parse the header files, but
    + * merely grep, i.e. if CONFIG_FOO is mentioned in a comment, it will
    + * be picked up as well. It's not a problem with respect to
    + * correctness, since that can only give too many dependencies, thus
    + * we cannot miss a rebuild. Since people tend to not mention totally
    + * unrelated CONFIG_ options all over the place, it's not an
    + * efficiency problem either.
    + *
    + * (Note: it'd be easy to port over the complete mkdep state machine,
    + *  but I don't think the added complexity is worth it)
    + */
    +
    +#include <sys/types.h>
    +#include <sys/stat.h>
    +#include <unistd.h>
    +#include <fcntl.h>
    +#include <string.h>
    +#include <stdlib.h>
    +#include <stdio.h>
    +#include <ctype.h>
    +
    +static void usage(void)
    +{
    +   fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n");
    +   exit(1);
    +}
    +
    +/*
    + * Print out a dependency path from a symbol name
    + */
    +static void print_dep(const char *m, int slen, const char *dir)
    +{
    +   int c, prev_c = '/', i;
    +
    +   printf("    $(wildcard %s/", dir);
    +   for (i = 0; i < slen; i++) {
    +           c = m[i];
    +           if (c == '_')
    +                   c = '/';
    +           else
    +                   c = tolower(c);
    +           if (c != '/' || prev_c != '/')
    +                   putchar(c);
    +           prev_c = c;
    +   }
    +   printf(".h) \\\n");
    +}
    +
    +struct item {
    +   struct item     *next;
    +   unsigned int    len;
    +   unsigned int    hash;
    +   char            name[0];
    +};
    +
    +#define HASHSZ 256
    +static struct item *hashtab[HASHSZ];
    +
    +static unsigned int strhash(const char *str, unsigned int sz)
    +{
    +   /* fnv32 hash */
    +   unsigned int i, hash = 2166136261U;
    +
    +   for (i = 0; i < sz; i++)
    +           hash = (hash ^ str[i]) * 0x01000193;
    +   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)
    +{
    +   struct item *aux = malloc(sizeof(*aux) + len);
    +
    +   if (!aux) {
    +           perror("fixdep:malloc");
    +           exit(1);
    +   }
    +   memcpy(aux->name, name, len);
    +   aux->len = len;
    +   aux->hash = hash;
    +   aux->next = hashtab[hash % HASHSZ];
    +   hashtab[hash % HASHSZ] = aux;
    +}
    +
    +/*
    + * 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;
    +
    +   define_config(m, slen, hash);
    +   print_dep(m, slen, "include/config");
    +}
    +
    +/* test if s ends in sub */
    +static int str_ends_with(const char *s, int slen, const char *sub)
    +{
    +   int sublen = strlen(sub);
    +
    +   if (sublen > slen)
    +           return 0;
    +
    +   return !memcmp(s + slen - sublen, sub, sublen);
    +}
    +
    +static void parse_config_file(const char *p)
    +{
    +   const char *q, *r;
    +   const char *start = p;
    +
    +   while ((p = strstr(p, "CONFIG_"))) {
    +           if (p > start && (isalnum(p[-1]) || p[-1] == '_')) {
    +                   p += 7;
    +                   continue;
    +           }
    +           p += 7;
    +           q = p;
    +           while (*q && (isalnum(*q) || *q == '_'))
    +                   q++;
    +           if (str_ends_with(p, q - p, "_MODULE"))
    +                   r = q - 7;
    +           else
    +                   r = q;
    +           if (r > p)
    +                   use_config(p, r - p);
    +           p = q;
    +   }
    +}
    +
    +static void *read_file(const char *filename)
    +{
    +   struct stat st;
    +   int fd;
    +   char *buf;
    +
    +   fd = open(filename, O_RDONLY);
    +   if (fd < 0) {
    +           fprintf(stderr, "fixdep: error opening file: ");
    +           perror(filename);
    +           exit(2);
    +   }
    +   if (fstat(fd, &st) < 0) {
    +           fprintf(stderr, "fixdep: error fstat'ing file: ");
    +           perror(filename);
    +           exit(2);
    +   }
    +   buf = malloc(st.st_size + 1);
    +   if (!buf) {
    +           perror("fixdep: malloc");
    +           exit(2);
    +   }
    +   if (read(fd, buf, st.st_size) != st.st_size) {
    +           perror("fixdep: read");
    +           exit(2);
    +   }
    +   buf[st.st_size] = '\0';
    +   close(fd);
    +
    +   return buf;
    +}
    +
    +/* Ignore certain dependencies */
    +static int is_ignored_file(const char *s, int len)
    +{
    +   return str_ends_with(s, len, "include/generated/autoconf.h") ||
    +          str_ends_with(s, len, "include/generated/autoksyms.h") ||
    +          str_ends_with(s, len, ".ver");
    +}
    +
    +/*
    + * 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)
    +{
    +   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)
    +                   break;
    +
    +           /* Find next "white space" */
    +           p = m;
    +           while (*p && *p != ' ' && *p != '\\' && *p != '\n')
    +                   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';
    +
    +                   /*
    +                    * 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.
    +                    */
    +                   if (is_first_dep) {
    +                           /*
    +                            * 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.
    +                            */
    +                           if (!saw_any_target) {
    +                                   saw_any_target = 1;
    +                                   printf("source_%s := %s\n\n",
    +                                          target, m);
    +                                   printf("deps_%s := \\\n", target);
    +                           }
    +                           is_first_dep = 0;
    +                   } else {
    +                           printf("  %s \\\n", m);
    +                   }
    +
    +                   buf = read_file(m);
    +                   parse_config_file(buf);
    +                   free(buf);
    +           }
    +
    +           if (is_last)
    +                   break;
    +
    +           /*
    +            * Start searching for next token immediately after the first
    +            * "whitespace" character that follows this token.
    +            */
    +           m = p + 1;
    +   }
    +
    +   if (!saw_any_target) {
    +           fprintf(stderr, "fixdep: parse error; no targets found\n");
    +           exit(1);
    +   }
    +
    +   printf("\n%s: $(deps_%s)\n\n", target, target);
    +   printf("$(deps_%s):\n", target);
    +}
    +
    +int main(int argc, char *argv[])
    +{
    +   const char *depfile, *target, *cmdline;
    +   void *buf;
    +
    +   if (argc != 4)
    +           usage();
    +
    +   depfile = argv[1];
    +   target = argv[2];
    +   cmdline = argv[3];
    +
    +   printf("cmd_%s := %s\n\n", target, cmdline);
    +
    +   buf = read_file(depfile);
    +   parse_dep_file(buf, target);
    +   free(buf);
    +
    +   return 0;
    +}
    -- 
    2.7.4
    
    
    _______________________________________________
    Minios-devel mailing list
    Minios-devel@xxxxxxxxxxxxxxxxxxxx
    https://lists.xenproject.org/mailman/listinfo/minios-devel

_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.