/*1* "Optimize" a list of dependencies as spit out by gcc -MD2* for the kernel build3* ===========================================================================4*5* Author Kai Germaschewski6* Copyright 2002 by Kai Germaschewski <[email protected]>7*8* This software may be used and distributed according to the terms9* of the GNU General Public License, incorporated herein by reference.10*11*12* Introduction:13*14* gcc produces a very nice and correct list of dependencies which15* tells make when to remake a file.16*17* To use this list as-is however has the drawback that virtually18* every file in the kernel includes autoconf.h.19*20* If the user re-runs make *config, autoconf.h will be21* regenerated. make notices that and will rebuild every file which22* includes autoconf.h, i.e. basically all files. This is extremely23* annoying if the user just changed CONFIG_HIS_DRIVER from n to m.24*25* So we play the same trick that "mkdep" played before. We replace26* the dependency on autoconf.h by a dependency on every config27* option which is mentioned in any of the listed prequisites.28*29* kconfig populates a tree in include/config/ with an empty file30* for each config symbol and when the configuration is updated31* the files representing changed config options are touched32* which then let make pick up the changes and the files that use33* the config symbols are rebuilt.34*35* So if the user changes his CONFIG_HIS_DRIVER option, only the objects36* 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 rebuild43* o if the command line given to the compile the file changed, we44* better rebuild as well.45*46* The former is handled by using the -MD output, the later by saving47* the command line used to compile the old object and comparing it48* to the one we would now use.49*50* Again, also this idea is pretty old and has been discussed on51* kbuild-devel a long time ago. I don't have a sensibly working52* internet connection right now, so I rather don't mention names53* without double checking.54*55* This code here has been based partially based on mkdep.c, which56* says the following about its history:57*58* Copyright abandoned, Michael Chastain, <mailto:[email protected]>.59* This is a C version of syncdep.pl by Werner Almesberger.60*61*62* It is invoked as63*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 line71*72* cmd_<target> = <cmdline>73*74* and then basically copies the .<target>.d file to stdout, in the75* process filtering out the dependency on autoconf.h and adding76* dependencies on include/config/my/option.h for every77* CONFIG_MY_OPTION encountered in any of the prequisites.78*79* It will also filter out all the dependencies on *.ver. We need80* to make sure that the generated version checksum are globally up81* to date before even starting the recursive build, so it's too late82* at this point anyway.83*84* The algorithm to grep for "CONFIG_..." is bit unusual, but should85* be fast ;-) We don't even try to really parse the header files, but86* merely grep, i.e. if CONFIG_FOO is mentioned in a comment, it will87* be picked up as well. It's not a problem with respect to88* correctness, since that can only give too many dependencies, thus89* we cannot miss a rebuild. Since people tend to not mention totally90* unrelated CONFIG_ options all over the place, it's not an91* 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 onto98* CONFIG_BOOM. This could seem a bug (not too hard to fix), but please do not99* fix it! Some UserModeLinux files (look at arch/um/) call CONFIG_BOOM as100* 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 that102* those files will have correct dependencies.103*/104105#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>116117#define INT_CONF ntohl(0x434f4e46)118#define INT_ONFI ntohl(0x4f4e4649)119#define INT_NFIG ntohl(0x4e464947)120#define INT_FIG_ ntohl(0x4649475f)121122char *target;123char *depfile;124char *cmdline;125126static void usage(void)127{128fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n");129exit(1);130}131132/*133* Print out the commandline prefixed with cmd_<target filename> :=134*/135static void print_cmdline(void)136{137printf("cmd_%s := %s\n\n", target, cmdline);138}139140struct item {141struct item *next;142unsigned int len;143unsigned int hash;144char name[0];145};146147#define HASHSZ 256148static struct item *hashtab[HASHSZ];149150static unsigned int strhash(const char *str, unsigned int sz)151{152/* fnv32 hash */153unsigned int i, hash = 2166136261U;154155for (i = 0; i < sz; i++)156hash = (hash ^ str[i]) * 0x01000193;157return hash;158}159160/*161* Lookup a value in the configuration string.162*/163static int is_defined_config(const char *name, int len, unsigned int hash)164{165struct item *aux;166167for (aux = hashtab[hash % HASHSZ]; aux; aux = aux->next) {168if (aux->hash == hash && aux->len == len &&169memcmp(aux->name, name, len) == 0)170return 1;171}172return 0;173}174175/*176* Add a new value to the configuration string.177*/178static void define_config(const char *name, int len, unsigned int hash)179{180struct item *aux = malloc(sizeof(*aux) + len);181182if (!aux) {183perror("fixdep:malloc");184exit(1);185}186memcpy(aux->name, name, len);187aux->len = len;188aux->hash = hash;189aux->next = hashtab[hash % HASHSZ];190hashtab[hash % HASHSZ] = aux;191}192193/*194* Clear the set of configuration strings.195*/196static void clear_config(void)197{198struct item *aux, *next;199unsigned int i;200201for (i = 0; i < HASHSZ; i++) {202for (aux = hashtab[i]; aux; aux = next) {203next = aux->next;204free(aux);205}206hashtab[i] = NULL;207}208}209210/*211* Record the use of a CONFIG_* word.212*/213static void use_config(const char *m, int slen)214{215unsigned int hash = strhash(m, slen);216int c, i;217218if (is_defined_config(m, slen, hash))219return;220221define_config(m, slen, hash);222223printf(" $(wildcard include/config/");224for (i = 0; i < slen; i++) {225c = m[i];226if (c == '_')227c = '/';228else229c = tolower(c);230putchar(c);231}232printf(".h) \\\n");233}234235static void parse_config_file(const char *map, size_t len)236{237const int *end = (const int *) (map + len);238/* start at +1, so that p can never be < map */239const int *m = (const int *) map + 1;240const char *p, *q;241242for (; m < end; m++) {243if (*m == INT_CONF) { p = (char *) m ; goto conf; }244if (*m == INT_ONFI) { p = (char *) m-1; goto conf; }245if (*m == INT_NFIG) { p = (char *) m-2; goto conf; }246if (*m == INT_FIG_) { p = (char *) m-3; goto conf; }247continue;248conf:249if (p > map + len - 7)250continue;251if (memcmp(p, "CONFIG_", 7))252continue;253for (q = p + 7; q < map + len; q++) {254if (!(isalnum(*q) || *q == '_'))255goto found;256}257continue;258259found:260if (!memcmp(q - 7, "_MODULE", 7))261q -= 7;262if( (q-p-7) < 0 )263continue;264use_config(p+7, q-p-7);265}266}267268/* test is s ends in sub */269static int strrcmp(char *s, char *sub)270{271int slen = strlen(s);272int sublen = strlen(sub);273274if (sublen > slen)275return 1;276277return memcmp(s + slen - sublen, sub, sublen);278}279280static void do_config_file(const char *filename)281{282struct stat st;283int fd;284void *map;285286fd = open(filename, O_RDONLY);287if (fd < 0) {288fprintf(stderr, "fixdep: error opening config file: ");289perror(filename);290exit(2);291}292fstat(fd, &st);293if (st.st_size == 0) {294close(fd);295return;296}297map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);298if ((long) map == -1) {299perror("fixdep: mmap");300close(fd);301return;302}303304parse_config_file(map, st.st_size);305306munmap(map, st.st_size);307308close(fd);309}310311/*312* Important: The below generated source_foo.o and deps_foo.o variable313* assignments are parsed not only by make, but also by the rather simple314* parser in scripts/mod/sumversion.c.315*/316static void parse_dep_file(void *map, size_t len)317{318char *m = map;319char *end = m + len;320char *p;321char s[PATH_MAX];322int first;323324p = strchr(m, ':');325if (!p) {326fprintf(stderr, "fixdep: parse error\n");327exit(1);328}329memcpy(s, m, p-m); s[p-m] = 0;330m = p+1;331332clear_config();333334first = 1;335while (m < end) {336while (m < end && (*m == ' ' || *m == '\\' || *m == '\n'))337m++;338p = m;339while (p < end && *p != ' ') p++;340if (p == end) {341do p--; while (!isalnum(*p));342p++;343}344memcpy(s, m, p-m); s[p-m] = 0;345if (strrcmp(s, "include/generated/autoconf.h") &&346strrcmp(s, "arch/um/include/uml-config.h") &&347strrcmp(s, ".ver")) {348/*349* Do not list the source file as dependency, so that350* kbuild is not confused if a .c file is rewritten351* into .S or vice versa. Storing it in source_* is352* needed for modpost to compute srcversions.353*/354if (first) {355printf("source_%s := %s\n\n", target, s);356printf("deps_%s := \\\n", target);357} else358printf(" %s \\\n", s);359do_config_file(s);360}361first = 0;362m = p + 1;363}364printf("\n%s: $(deps_%s)\n\n", target, target);365printf("$(deps_%s):\n", target);366}367368static void print_deps(void)369{370struct stat st;371int fd;372void *map;373374fd = open(depfile, O_RDONLY);375if (fd < 0) {376fprintf(stderr, "fixdep: error opening depfile: ");377perror(depfile);378exit(2);379}380if (fstat(fd, &st) < 0) {381fprintf(stderr, "fixdep: error fstat'ing depfile: ");382perror(depfile);383exit(2);384}385if (st.st_size == 0) {386fprintf(stderr,"fixdep: %s is empty\n",depfile);387close(fd);388return;389}390map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);391if ((long) map == -1) {392perror("fixdep: mmap");393close(fd);394return;395}396397parse_dep_file(map, st.st_size);398399munmap(map, st.st_size);400401close(fd);402}403404static void traps(void)405{406static char test[] __attribute__((aligned(sizeof(int)))) = "CONF";407int *p = (int *)test;408409if (*p != INT_CONF) {410fprintf(stderr, "fixdep: sizeof(int) != 4 or wrong endianess? %#x\n",411*p);412exit(2);413}414}415416int main(int argc, char *argv[])417{418traps();419420if (argc != 4)421usage();422423depfile = argv[1];424target = argv[2];425cmdline = argv[3];426427print_cmdline();428print_deps();429430return 0;431}432433434