busybox/scripts/basic/fixdep.c
<<
>>
Prefs
   1/*
   2 * "Optimize" a list of dependencies as spit out by gcc -MD
   3 * for the kernel build
   4 * ===========================================================================
   5 *
   6 * Author       Kai Germaschewski
   7 * Copyright    2002 by Kai Germaschewski  <kai.germaschewski@gmx.de>
   8 *
   9 * This software may be used and distributed according to the terms
  10 * of the GNU General Public License, incorporated herein by reference.
  11 *
  12 *
  13 * Introduction:
  14 *
  15 * gcc produces a very nice and correct list of dependencies which
  16 * tells make when to remake a file.
  17 *
  18 * To use this list as-is however has the drawback that virtually
  19 * every file in the kernel includes <linux/config.h> which then again
  20 * includes <linux/autoconf.h>
  21 *
  22 * If the user re-runs make *config, linux/autoconf.h will be
  23 * regenerated.  make notices that and will rebuild every file which
  24 * includes autoconf.h, i.e. basically all files. This is extremely
  25 * annoying if the user just changed CONFIG_HIS_DRIVER from n to m.
  26 *
  27 * So we play the same trick that "mkdep" played before. We replace
  28 * the dependency on linux/autoconf.h by a dependency on every config
  29 * option which is mentioned in any of the listed prequisites.
  30 *
  31 * To be exact, split-include populates a tree in include/config/,
  32 * e.g. include/config/his/driver.h, which contains the #define/#undef
  33 * for the CONFIG_HIS_DRIVER option.
  34 *
  35 * So if the user changes his CONFIG_HIS_DRIVER option, only the objects
  36 * which depend on "include/linux/config/his/driver.h" will be rebuilt,
  37 * so most likely only his driver ;-)
  38 *
  39 * The idea above dates, by the way, back to Michael E Chastain, AFAIK.
  40 *
  41 * So to get dependencies right, there are two issues:
  42 * o if any of the files the compiler read changed, we need to rebuild
  43 * o if the command line given to the compile the file changed, we
  44 *   better rebuild as well.
  45 *
  46 * The former is handled by using the -MD output, the later by saving
  47 * the command line used to compile the old object and comparing it
  48 * to the one we would now use.
  49 *
  50 * Again, also this idea is pretty old and has been discussed on
  51 * kbuild-devel a long time ago. I don't have a sensibly working
  52 * internet connection right now, so I rather don't mention names
  53 * without double checking.
  54 *
  55 * This code here has been based partially based on mkdep.c, which
  56 * says the following about its history:
  57 *
  58 *   Copyright abandoned, Michael Chastain, <mailto:mec@shout.net>.
  59 *   This is a C version of syncdep.pl by Werner Almesberger.
  60 *
  61 *
  62 * It is invoked as
  63 *
  64 *   fixdep <depfile> <target> <cmdline>
  65 *
  66 * and will read the dependency file <depfile>
  67 *
  68 * The transformed dependency snipped is written to stdout.
  69 *
  70 * It first generates a line
  71 *
  72 *   cmd_<target> = <cmdline>
  73 *
  74 * and then basically copies the .<target>.d file to stdout, in the
  75 * process filtering out the dependency on linux/autoconf.h and adding
  76 * dependencies on include/config/my/option.h for every
  77 * CONFIG_MY_OPTION encountered in any of the prequisites.
  78 *
  79 * It will also filter out all the dependencies on *.ver. We need
  80 * to make sure that the generated version checksum are globally up
  81 * to date before even starting the recursive build, so it's too late
  82 * at this point anyway.
  83 *
  84 * The algorithm to grep for "CONFIG_..." is bit unusual, but should
  85 * be fast ;-) We don't even try to really parse the header files, but
  86 * merely grep, i.e. if CONFIG_FOO is mentioned in a comment, it will
  87 * be picked up as well. It's not a problem with respect to
  88 * correctness, since that can only give too many dependencies, thus
  89 * we cannot miss a rebuild. Since people tend to not mention totally
  90 * unrelated CONFIG_ options all over the place, it's not an
  91 * efficiency problem either.
  92 *
  93 * (Note: it'd be easy to port over the complete mkdep state machine,
  94 *  but I don't think the added complexity is worth it)
  95 */
  96/*
  97 * Note 2: if somebody writes HELLO_CONFIG_BOOM in a file, it will depend onto
  98 * CONFIG_BOOM. This could seem a bug (not too hard to fix), but please do not
  99 * fix it! Some UserModeLinux files (look at arch/um/) call CONFIG_BOOM as
 100 * UML_CONFIG_BOOM, to avoid conflicts with /usr/include/linux/autoconf.h,
 101 * through arch/um/include/uml-config.h; this fixdep "bug" makes sure that
 102 * those files will have correct dependencies.
 103 */
 104
 105#include <sys/types.h>
 106#include <sys/stat.h>
 107#include <sys/mman.h>
 108#include <unistd.h>
 109#include <fcntl.h>
 110#include <string.h>
 111#include <stdlib.h>
 112#include <stdio.h>
 113#include <limits.h>
 114#include <ctype.h>
 115#include <arpa/inet.h>
 116//bbox disabled: #include <alloca.h>
 117
 118/* bbox: not needed
 119#define INT_CONF ntohl(0x434f4e46)
 120#define INT_ONFI ntohl(0x4f4e4649)
 121#define INT_NFIG ntohl(0x4e464947)
 122#define INT_FIG_ ntohl(0x4649475f)
 123*/
 124
 125char *target;
 126char *depfile;
 127char *cmdline;
 128
 129void usage(void)
 130
 131{
 132        fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n");
 133        exit(1);
 134}
 135
 136/*
 137 * Print out the commandline prefixed with cmd_<target filename> :=
 138 */
 139void print_cmdline(void)
 140{
 141        printf("cmd_%s := %s\n\n", target, cmdline);
 142}
 143
 144char * str_config  = NULL;
 145int    size_config = 0;
 146int    len_config  = 0;
 147
 148/*
 149 * Grow the configuration string to a desired length.
 150 * Usually the first growth is plenty.
 151 */
 152void grow_config(int len)
 153{
 154        while (len_config + len > size_config) {
 155                if (size_config == 0)
 156                        size_config = 2048;
 157                str_config = realloc(str_config, size_config *= 2);
 158                if (str_config == NULL)
 159                        { perror("fixdep:malloc"); exit(1); }
 160        }
 161}
 162
 163
 164
 165/*
 166 * Lookup a value in the configuration string.
 167 */
 168int is_defined_config(const char * name, int len)
 169{
 170        const char * pconfig;
 171        const char * plast = str_config + len_config - len;
 172        for ( pconfig = str_config + 1; pconfig < plast; pconfig++ ) {
 173                if (pconfig[ -1] == '\n'
 174                &&  pconfig[len] == '\n'
 175                &&  !memcmp(pconfig, name, len))
 176                        return 1;
 177        }
 178        return 0;
 179}
 180
 181/*
 182 * Add a new value to the configuration string.
 183 */
 184void define_config(const char * name, int len)
 185{
 186        grow_config(len + 1);
 187
 188        memcpy(str_config+len_config, name, len);
 189        len_config += len;
 190        str_config[len_config++] = '\n';
 191}
 192
 193/*
 194 * Clear the set of configuration strings.
 195 */
 196void clear_config(void)
 197{
 198        len_config = 0;
 199        define_config("", 0);
 200}
 201
 202/*
 203 * Record the use of a CONFIG_* word.
 204 */
 205void use_config(char *m, int slen)
 206{
 207        char *s = alloca(slen+1);
 208        char *p;
 209
 210        if (is_defined_config(m, slen))
 211            return;
 212
 213        define_config(m, slen);
 214
 215        memcpy(s, m, slen); s[slen] = 0;
 216
 217        for (p = s; p < s + slen; p++) {
 218                if (*p == '_')
 219                        *p = '/';
 220                else
 221                        *p = tolower((int)*p);
 222        }
 223        printf("    $(wildcard include/config/%s.h) \\\n", s);
 224}
 225
 226void parse_config_file(char *map, size_t len)
 227{
 228        /* modified for bbox */
 229        char *end_3 = map + len - 3; /* 3 == length of "IF_" */
 230        char *end_7 = map + len - 7;
 231        char *p = map;
 232        char *q;
 233        int off;
 234
 235        for (; p <= end_3; p++) {
 236                /* Find next identifier's beginning */
 237                if (!(isalnum(*p) || *p == '_'))
 238                        continue;
 239
 240                /* Check it */
 241                if (p < end_7 && p[6] == '_') {
 242                        if (!memcmp(p, "CONFIG", 6)) goto conf7;
 243                        if (!memcmp(p, "ENABLE", 6)) goto conf7;
 244                        if (!memcmp(p, "IF_NOT", 6)) goto conf7;
 245                }
 246                /* we have at least 3 chars because of p <= end_3 */
 247                /*if (!memcmp(p, "IF_", 3)) ...*/
 248                if (p[0] == 'I' && p[1] == 'F' && p[2] == '_') {
 249                        off = 3;
 250                        goto conf;
 251                }
 252
 253                /* This identifier is not interesting, skip it */
 254                while (p <= end_3 && (isalnum(*p) || *p == '_'))
 255                        p++;
 256                continue;
 257
 258        conf7:  off = 7;
 259        conf:
 260                p += off;
 261                for (q = p; q < end_3+3; q++) {
 262                        if (!(isalnum(*q) || *q == '_'))
 263                                break;
 264                }
 265                if (q != p) {
 266                        use_config(p, q-p);
 267                }
 268        }
 269}
 270
 271/* test is s ends in sub */
 272int strrcmp(char *s, char *sub)
 273{
 274        int slen = strlen(s);
 275        int sublen = strlen(sub);
 276
 277        if (sublen > slen)
 278                return 1;
 279
 280        return memcmp(s + slen - sublen, sub, sublen);
 281}
 282
 283void do_config_file(char *filename)
 284{
 285        struct stat st;
 286        int fd;
 287        void *map;
 288
 289        fd = open(filename, O_RDONLY);
 290        if (fd < 0) {
 291                fprintf(stderr, "fixdep: ");
 292                perror(filename);
 293                exit(2);
 294        }
 295        fstat(fd, &st);
 296        if (st.st_size == 0) {
 297                close(fd);
 298                return;
 299        }
 300        map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
 301        if ((long) map == -1) {
 302                perror("fixdep: mmap");
 303                close(fd);
 304                return;
 305        }
 306
 307        parse_config_file(map, st.st_size);
 308
 309        munmap(map, st.st_size);
 310
 311        close(fd);
 312}
 313
 314void parse_dep_file(void *map, size_t len)
 315{
 316        char *m = map;
 317        char *end = m + len;
 318        char *p;
 319        char *s = alloca(len);
 320
 321        p = memchr(m, ':', len);
 322        if (!p) {
 323                fprintf(stderr, "fixdep: parse error\n");
 324                exit(1);
 325        }
 326        memcpy(s, m, p-m); s[p-m] = 0;
 327        printf("deps_%s := \\\n", target);
 328        m = p+1;
 329
 330        clear_config();
 331
 332        while (m < end) {
 333                while (m < end && (*m == ' ' || *m == '\\' || *m == '\n' || *m == '\r'))
 334                        m++;
 335                p = m;
 336                while (p < end && *p != ' ') p++;
 337                if (p == end) {
 338                        do p--; while (!isalnum(*p));
 339                        p++;
 340                }
 341                memcpy(s, m, p-m); s[p-m] = 0;
 342                if (strrcmp(s, "include/autoconf.h") &&
 343                    strrcmp(s, "arch/um/include/uml-config.h") &&
 344                    strrcmp(s, ".ver")) {
 345                        printf("  %s \\\n", s);
 346                        do_config_file(s);
 347                }
 348                m = p + 1;
 349        }
 350        printf("\n%s: $(deps_%s)\n\n", target, target);
 351        printf("$(deps_%s):\n", target);
 352}
 353
 354void print_deps(void)
 355{
 356        struct stat st;
 357        int fd;
 358        void *map;
 359
 360        fd = open(depfile, O_RDONLY);
 361        if (fd < 0) {
 362                fprintf(stderr, "fixdep: ");
 363                perror(depfile);
 364                exit(2);
 365        }
 366        fstat(fd, &st);
 367        if (st.st_size == 0) {
 368                fprintf(stderr,"fixdep: %s is empty\n",depfile);
 369                close(fd);
 370                return;
 371        }
 372        map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
 373        if ((long) map == -1) {
 374                perror("fixdep: mmap");
 375                close(fd);
 376                return;
 377        }
 378
 379        parse_dep_file(map, st.st_size);
 380
 381        munmap(map, st.st_size);
 382
 383        close(fd);
 384}
 385
 386void traps(void)
 387{
 388/* bbox: not needed
 389        static char test[] __attribute__((aligned(sizeof(int)))) = "CONF";
 390
 391        if (*(int *)test != INT_CONF) {
 392                fprintf(stderr, "fixdep: sizeof(int) != 4 or wrong endianess? %#x\n",
 393                        *(int *)test);
 394                exit(2);
 395        }
 396*/
 397}
 398
 399int main(int argc, char **argv)
 400{
 401        traps();
 402
 403        if (argc != 4)
 404                usage();
 405
 406        depfile = argv[1];
 407        target = argv[2];
 408        cmdline = argv[3];
 409
 410        print_cmdline();
 411        print_deps();
 412
 413        return 0;
 414}
 415