linux-old/scripts/mkdep.c
<<
>>
Prefs
   1/*
   2 * Originally by Linus Torvalds.
   3 * Smart CONFIG_* processing by Werner Almesberger, Michael Chastain.
   4 *
   5 * Usage: mkdep file ...
   6 * 
   7 * Read source files and output makefile dependency lines for them.
   8 * I make simple dependency lines for #include <*.h> and #include "*.h".
   9 * I also find instances of CONFIG_FOO and generate dependencies
  10 *    like include/config/foo.h.
  11 *
  12 * 1 August 1999, Michael Elizabeth Chastain, <mec@shout.net>
  13 * - Keith Owens reported a bug in smart config processing.  There used
  14 *   to be an optimization for "#define CONFIG_FOO ... #ifdef CONFIG_FOO",
  15 *   so that the file would not depend on CONFIG_FOO because the file defines
  16 *   this symbol itself.  But this optimization is bogus!  Consider this code:
  17 *   "#if 0 \n #define CONFIG_FOO \n #endif ... #ifdef CONFIG_FOO".  Here
  18 *   the definition is inactivated, but I still used it.  It turns out this
  19 *   actually happens a few times in the kernel source.  The simple way to
  20 *   fix this problem is to remove this particular optimization.
  21 */
  22
  23#include <ctype.h>
  24#include <fcntl.h>
  25#include <stdio.h>
  26#include <stdlib.h>
  27#include <string.h>
  28#include <unistd.h>
  29
  30#include <sys/fcntl.h>
  31#include <sys/mman.h>
  32#include <sys/stat.h>
  33#include <sys/types.h>
  34
  35
  36
  37char __depname[512] = "\n\t@touch ";
  38#define depname (__depname+9)
  39int hasdep;
  40
  41struct path_struct {
  42        int len;
  43        char buffer[256-sizeof(int)];
  44} path_array[2] = {
  45        {  0, "" },
  46        {  0, "" }
  47};
  48
  49
  50
  51/*
  52 * This records all the configuration options seen.
  53 * In perl this would be a hash, but here it's a long string
  54 * of values separated by newlines.  This is simple and
  55 * extremely fast.
  56 */
  57char * str_config  = NULL;
  58int    size_config = 0;
  59int    len_config  = 0;
  60
  61
  62
  63/*
  64 * Grow the configuration string to a desired length.
  65 * Usually the first growth is plenty.
  66 */
  67void grow_config(int len)
  68{
  69        if (str_config == NULL) {
  70                len_config  = 0;
  71                size_config = 4096;
  72                str_config  = malloc(4096);
  73                if (str_config == NULL)
  74                        { perror("malloc"); exit(1); }
  75        }
  76
  77        while (len_config + len > size_config) {
  78                str_config = realloc(str_config, size_config *= 2);
  79                if (str_config == NULL)
  80                        { perror("malloc config"); exit(1); }
  81        }
  82}
  83
  84
  85
  86/*
  87 * Lookup a value in the configuration string.
  88 */
  89int is_defined_config(const char * name, int len)
  90{
  91        const char * pconfig;
  92        const char * plast = str_config + len_config - len;
  93        for ( pconfig = str_config + 1; pconfig < plast; pconfig++ ) {
  94                if (pconfig[ -1] == '\n'
  95                &&  pconfig[len] == '\n'
  96                &&  !memcmp(pconfig, name, len))
  97                        return 1;
  98        }
  99        return 0;
 100}
 101
 102
 103
 104/*
 105 * Add a new value to the configuration string.
 106 */
 107void define_config(const char * name, int len)
 108{
 109        grow_config(len + 1);
 110
 111        memcpy(str_config+len_config, name, len);
 112        len_config += len;
 113        str_config[len_config++] = '\n';
 114}
 115
 116
 117
 118/*
 119 * Clear the set of configuration strings.
 120 */
 121void clear_config(void)
 122{
 123        len_config = 0;
 124        define_config("", 0);
 125}
 126
 127
 128
 129/*
 130 * This records all the precious .h filenames.  No need for a hash,
 131 * it's a long string of values enclosed in tab and newline.
 132 */
 133char * str_precious  = NULL;
 134int    size_precious = 0;
 135int    len_precious  = 0;
 136
 137
 138
 139/*
 140 * Grow the precious string to a desired length.
 141 * Usually the first growth is plenty.
 142 */
 143void grow_precious(int len)
 144{
 145        if (str_precious == NULL) {
 146                len_precious  = 0;
 147                size_precious = 4096;
 148                str_precious  = malloc(4096);
 149                if (str_precious == NULL)
 150                        { perror("malloc precious"); exit(1); }
 151        }
 152
 153        while (len_precious + len > size_precious) {
 154                str_precious = realloc(str_precious, size_precious *= 2);
 155                if (str_precious == NULL)
 156                        { perror("malloc"); exit(1); }
 157        }
 158}
 159
 160
 161
 162/*
 163 * Add a new value to the precious string.
 164 */
 165void define_precious(const char * filename)
 166{
 167        int len = strlen(filename);
 168        grow_precious(len + 4);
 169        *(str_precious+len_precious++) = '\t';
 170        memcpy(str_precious+len_precious, filename, len);
 171        len_precious += len;
 172        memcpy(str_precious+len_precious, " \\\n", 3);
 173        len_precious += 3;
 174}
 175
 176
 177
 178/*
 179 * Handle an #include line.
 180 */
 181void handle_include(int type, const char * name, int len)
 182{
 183        struct path_struct *path = path_array+type;
 184
 185        if (len == 14 && !memcmp(name, "linux/config.h", len))
 186                return;
 187
 188        if (len >= 7 && !memcmp(name, "config/", 7))
 189                define_config(name+7, len-7-2);
 190
 191        memcpy(path->buffer+path->len, name, len);
 192        path->buffer[path->len+len] = '\0';
 193        if (access(path->buffer, F_OK) != 0)
 194                return;
 195
 196        if (!hasdep) {
 197                hasdep = 1;
 198                printf("%s:", depname);
 199        }
 200        printf(" \\\n   %s", path->buffer);
 201}
 202
 203
 204
 205/*
 206 * Record the use of a CONFIG_* word.
 207 */
 208void use_config(const char * name, int len)
 209{
 210        char *pc;
 211        int i;
 212
 213        pc = path_array[0].buffer + path_array[0].len;
 214        memcpy(pc, "config/", 7);
 215        pc += 7;
 216
 217        for (i = 0; i < len; i++) {
 218            char c = name[i];
 219            if (isupper(c)) c = tolower(c);
 220            if (c == '_')   c = '/';
 221            pc[i] = c;
 222        }
 223        pc[len] = '\0';
 224
 225        if (is_defined_config(pc, len))
 226            return;
 227
 228        define_config(pc, len);
 229
 230        if (!hasdep) {
 231                hasdep = 1;
 232                printf("%s: ", depname);
 233        }
 234        printf(" \\\n   $(wildcard %s.h)", path_array[0].buffer);
 235}
 236
 237
 238
 239/*
 240 * Macros for stunningly fast map-based character access.
 241 * __buf is a register which holds the current word of the input.
 242 * Thus, there is one memory access per sizeof(unsigned long) characters.
 243 */
 244
 245#if defined(__alpha__) || defined(__i386__) || defined(__ia64__) || defined(__MIPSEL__) \
 246    || defined(__arm__)
 247#define LE_MACHINE
 248#endif
 249
 250#ifdef LE_MACHINE
 251#define next_byte(x) (x >>= 8)
 252#define current ((unsigned char) __buf)
 253#else
 254#define next_byte(x) (x <<= 8)
 255#define current (__buf >> 8*(sizeof(unsigned long)-1))
 256#endif
 257
 258#define GETNEXT { \
 259        next_byte(__buf); \
 260        if ((unsigned long) next % sizeof(unsigned long) == 0) { \
 261                if (next >= end) \
 262                        break; \
 263                __buf = * (unsigned long *) next; \
 264        } \
 265        next++; \
 266}
 267
 268/*
 269 * State machine macros.
 270 */
 271#define CASE(c,label) if (current == c) goto label
 272#define NOTCASE(c,label) if (current != c) goto label
 273
 274/*
 275 * Yet another state machine speedup.
 276 */
 277#define MAX2(a,b) ((a)>(b)?(a):(b))
 278#define MIN2(a,b) ((a)<(b)?(a):(b))
 279#define MAX6(a,b,c,d,e,f) (MAX2(a,MAX2(b,MAX2(c,MAX2(d,MAX2(e,f))))))
 280#define MIN6(a,b,c,d,e,f) (MIN2(a,MIN2(b,MIN2(c,MIN2(d,MIN2(e,f))))))
 281
 282
 283
 284/*
 285 * The state machine looks for (approximately) these Perl regular expressions:
 286 *
 287 *    m|\/\*.*?\*\/|
 288 *    m|\/\/.*|
 289 *    m|'.*?'|
 290 *    m|".*?"|
 291 *    m|#\s*include\s*"(.*?)"|
 292 *    m|#\s*include\s*<(.*?>"|
 293 *    m|#\s*(?define|undef)\s*CONFIG_(\w*)|
 294 *    m|(?!\w)CONFIG_|
 295 *    m|__SMP__|
 296 *
 297 * About 98% of the CPU time is spent here, and most of that is in
 298 * the 'start' paragraph.  Because the current characters are
 299 * in a register, the start loop usually eats 4 or 8 characters
 300 * per memory read.  The MAX6 and MIN6 tests dispose of most
 301 * input characters with 1 or 2 comparisons.
 302 */
 303void state_machine(const char * map, const char * end)
 304{
 305        const char * next = map;
 306        const char * map_dot;
 307        unsigned long __buf = 0;
 308
 309        for (;;) {
 310start:
 311        GETNEXT
 312__start:
 313        if (current > MAX6('/','\'','"','#','C','_')) goto start;
 314        if (current < MIN6('/','\'','"','#','C','_')) goto start;
 315        CASE('/',  slash);
 316        CASE('\'', squote);
 317        CASE('"',  dquote);
 318        CASE('#',  pound);
 319        CASE('C',  cee);
 320        CASE('_',  underscore);
 321        goto start;
 322
 323/* // */
 324slash_slash:
 325        GETNEXT
 326        CASE('\n', start);
 327        NOTCASE('\\', slash_slash);
 328        GETNEXT
 329        goto slash_slash;
 330
 331/* / */
 332slash:
 333        GETNEXT
 334        CASE('/',  slash_slash);
 335        NOTCASE('*', __start);
 336slash_star_dot_star:
 337        GETNEXT
 338__slash_star_dot_star:
 339        NOTCASE('*', slash_star_dot_star);
 340        GETNEXT
 341        NOTCASE('/', __slash_star_dot_star);
 342        goto start;
 343
 344/* '.*?' */
 345squote:
 346        GETNEXT
 347        CASE('\'', start);
 348        NOTCASE('\\', squote);
 349        GETNEXT
 350        goto squote;
 351
 352/* ".*?" */
 353dquote:
 354        GETNEXT
 355        CASE('"', start);
 356        NOTCASE('\\', dquote);
 357        GETNEXT
 358        goto dquote;
 359
 360/* #\s* */
 361pound:
 362        GETNEXT
 363        CASE(' ',  pound);
 364        CASE('\t', pound);
 365        CASE('i',  pound_i);
 366        CASE('d',  pound_d);
 367        CASE('u',  pound_u);
 368        goto __start;
 369
 370/* #\s*i */
 371pound_i:
 372        GETNEXT NOTCASE('n', __start);
 373        GETNEXT NOTCASE('c', __start);
 374        GETNEXT NOTCASE('l', __start);
 375        GETNEXT NOTCASE('u', __start);
 376        GETNEXT NOTCASE('d', __start);
 377        GETNEXT NOTCASE('e', __start);
 378        goto pound_include;
 379
 380/* #\s*include\s* */
 381pound_include:
 382        GETNEXT
 383        CASE(' ',  pound_include);
 384        CASE('\t', pound_include);
 385        map_dot = next;
 386        CASE('"',  pound_include_dquote);
 387        CASE('<',  pound_include_langle);
 388        goto __start;
 389
 390/* #\s*include\s*"(.*)" */
 391pound_include_dquote:
 392        GETNEXT
 393        CASE('\n', start);
 394        NOTCASE('"', pound_include_dquote);
 395        handle_include(1, map_dot, next - map_dot - 1);
 396        goto start;
 397
 398/* #\s*include\s*<(.*)> */
 399pound_include_langle:
 400        GETNEXT
 401        CASE('\n', start);
 402        NOTCASE('>', pound_include_langle);
 403        handle_include(0, map_dot, next - map_dot - 1);
 404        goto start;
 405
 406/* #\s*d */
 407pound_d:
 408        GETNEXT NOTCASE('e', __start);
 409        GETNEXT NOTCASE('f', __start);
 410        GETNEXT NOTCASE('i', __start);
 411        GETNEXT NOTCASE('n', __start);
 412        GETNEXT NOTCASE('e', __start);
 413        goto pound_define_undef;
 414
 415/* #\s*u */
 416pound_u:
 417        GETNEXT NOTCASE('n', __start);
 418        GETNEXT NOTCASE('d', __start);
 419        GETNEXT NOTCASE('e', __start);
 420        GETNEXT NOTCASE('f', __start);
 421        goto pound_define_undef;
 422
 423/*
 424 * #\s*(define|undef)\s*CONFIG_(\w*)
 425 *
 426 * this does not define the word, because it could be inside another
 427 * conditional (#if 0).  But I do parse the word so that this instance
 428 * does not count as a use.  -- mec
 429 */
 430pound_define_undef:
 431        GETNEXT
 432        CASE(' ',  pound_define_undef);
 433        CASE('\t', pound_define_undef);
 434
 435                NOTCASE('C', __start);
 436        GETNEXT NOTCASE('O', __start);
 437        GETNEXT NOTCASE('N', __start);
 438        GETNEXT NOTCASE('F', __start);
 439        GETNEXT NOTCASE('I', __start);
 440        GETNEXT NOTCASE('G', __start);
 441        GETNEXT NOTCASE('_', __start);
 442
 443        map_dot = next;
 444pound_define_undef_CONFIG_word:
 445        GETNEXT
 446        if (isalnum(current) || current == '_')
 447                goto pound_define_undef_CONFIG_word;
 448        goto __start;
 449
 450/* \<CONFIG_(\w*) */
 451cee:
 452        if (next >= map+2 && (isalnum(next[-2]) || next[-2] == '_'))
 453                goto start;
 454        GETNEXT NOTCASE('O', __start);
 455        GETNEXT NOTCASE('N', __start);
 456        GETNEXT NOTCASE('F', __start);
 457        GETNEXT NOTCASE('I', __start);
 458        GETNEXT NOTCASE('G', __start);
 459        GETNEXT NOTCASE('_', __start);
 460
 461        map_dot = next;
 462cee_CONFIG_word:
 463        GETNEXT
 464        if (isalnum(current) || current == '_')
 465                goto cee_CONFIG_word;
 466        use_config(map_dot, next - map_dot - 1);
 467        goto __start;
 468
 469/* __SMP__ */
 470underscore:
 471        GETNEXT NOTCASE('_', __start);
 472        GETNEXT NOTCASE('S', __start);
 473        GETNEXT NOTCASE('M', __start);
 474        GETNEXT NOTCASE('P', __start);
 475        GETNEXT NOTCASE('_', __start);
 476        GETNEXT NOTCASE('_', __start);
 477        use_config("SMP", 3);
 478        goto __start;
 479
 480    }
 481}
 482
 483
 484
 485/*
 486 * Generate dependencies for one file.
 487 */
 488void do_depend(const char * filename, const char * command)
 489{
 490        int mapsize;
 491        int pagesizem1 = getpagesize()-1;
 492        int fd;
 493        struct stat st;
 494        char * map;
 495
 496        fd = open(filename, O_RDONLY);
 497        if (fd < 0) {
 498                perror(filename);
 499                return;
 500        }
 501
 502        fstat(fd, &st);
 503        if (st.st_size == 0) {
 504                fprintf(stderr,"%s is empty\n",filename);
 505                close(fd);
 506                return;
 507        }
 508
 509        mapsize = st.st_size;
 510        mapsize = (mapsize+pagesizem1) & ~pagesizem1;
 511        map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
 512        if ((long) map == -1) {
 513                perror("mkdep: mmap");
 514                close(fd);
 515                return;
 516        }
 517        if ((unsigned long) map % sizeof(unsigned long) != 0)
 518        {
 519                fprintf(stderr, "do_depend: map not aligned\n");
 520                exit(1);
 521        }
 522
 523        hasdep = 0;
 524        clear_config();
 525        state_machine(map, map+st.st_size);
 526        if (hasdep) {
 527                puts(command);
 528                if (*command)
 529                        define_precious(filename);
 530        }
 531
 532        munmap(map, mapsize);
 533        close(fd);
 534}
 535
 536
 537
 538/*
 539 * Generate dependencies for all files.
 540 */
 541int main(int argc, char **argv)
 542{
 543        int len;
 544        char *hpath;
 545
 546        hpath = getenv("HPATH");
 547        if (!hpath) {
 548                fputs("mkdep: HPATH not set in environment.  "
 549                      "Don't bypass the top level Makefile.\n", stderr);
 550                return 1;
 551        }
 552        len = strlen(hpath);
 553        memcpy(path_array[0].buffer, hpath, len);
 554        if (len && hpath[len-1] != '/')
 555                path_array[0].buffer[len++] = '/';
 556        path_array[0].buffer[len] = '\0';
 557        path_array[0].len = len;
 558
 559        while (--argc > 0) {
 560                const char * filename = *++argv;
 561                const char * command  = __depname;
 562                len = strlen(filename);
 563                memcpy(depname, filename, len+1);
 564                if (len > 2 && filename[len-2] == '.') {
 565                        if (filename[len-1] == 'c' || filename[len-1] == 'S') {
 566                            depname[len-1] = 'o';
 567                            command = "";
 568                        }
 569                }
 570                do_depend(filename, command);
 571        }
 572        if (len_precious) {
 573                *(str_precious+len_precious) = '\0';
 574                printf(".PRECIOUS:%s\n", str_precious);
 575        }
 576        return 0;
 577}
 578
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.