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