|  | // SPDX-License-Identifier: GPL-2.0 | 
|  | /* | 
|  | * "Optimize" a list of dependencies as spit out by gcc -MD | 
|  | * for the build framework. | 
|  | * | 
|  | * Original author: | 
|  | *   Copyright    2002 by Kai Germaschewski  <kai.germaschewski@gmx.de> | 
|  | * | 
|  | * This code has been borrowed from kbuild's fixdep (scripts/basic/fixdep.c), | 
|  | * Please check it for detailed explanation. This fixdep borow only the | 
|  | * base transformation of dependecies without the CONFIG mangle. | 
|  | */ | 
|  |  | 
|  | #include <sys/types.h> | 
|  | #include <sys/stat.h> | 
|  | #include <sys/mman.h> | 
|  | #include <unistd.h> | 
|  | #include <fcntl.h> | 
|  | #include <string.h> | 
|  | #include <stdlib.h> | 
|  | #include <stdio.h> | 
|  | #include <limits.h> | 
|  |  | 
|  | char *target; | 
|  | char *depfile; | 
|  | char *cmdline; | 
|  |  | 
|  | static void usage(void) | 
|  | { | 
|  | fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n"); | 
|  | exit(1); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Print out the commandline prefixed with cmd_<target filename> := | 
|  | */ | 
|  | static void print_cmdline(void) | 
|  | { | 
|  | printf("cmd_%s := %s\n\n", target, cmdline); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * 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(void *map, size_t len) | 
|  | { | 
|  | char *m = map; | 
|  | char *end = m + len; | 
|  | char *p; | 
|  | char s[PATH_MAX]; | 
|  | int is_target, has_target = 0; | 
|  | int saw_any_target = 0; | 
|  | int is_first_dep = 0; | 
|  |  | 
|  | while (m < end) { | 
|  | /* Skip any "white space" */ | 
|  | while (m < end && (*m == ' ' || *m == '\\' || *m == '\n')) | 
|  | m++; | 
|  | /* Find next "white space" */ | 
|  | p = m; | 
|  | while (p < end && *p != ' ' && *p != '\\' && *p != '\n') | 
|  | p++; | 
|  | /* 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; | 
|  | has_target = 1; | 
|  | } else if (has_target) { | 
|  | /* Save this token/filename */ | 
|  | memcpy(s, m, p-m); | 
|  | s[p - m] = 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, s); | 
|  | printf("deps_%s := \\\n", | 
|  | target); | 
|  | } | 
|  | is_first_dep = 0; | 
|  | } else | 
|  | printf("  %s \\\n", s); | 
|  | } | 
|  | /* | 
|  | * 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); | 
|  | } | 
|  |  | 
|  | static void print_deps(void) | 
|  | { | 
|  | struct stat st; | 
|  | int fd; | 
|  | void *map; | 
|  |  | 
|  | fd = open(depfile, O_RDONLY); | 
|  | if (fd < 0) { | 
|  | fprintf(stderr, "fixdep: error opening depfile: "); | 
|  | perror(depfile); | 
|  | exit(2); | 
|  | } | 
|  | if (fstat(fd, &st) < 0) { | 
|  | fprintf(stderr, "fixdep: error fstat'ing depfile: "); | 
|  | perror(depfile); | 
|  | exit(2); | 
|  | } | 
|  | if (st.st_size == 0) { | 
|  | fprintf(stderr, "fixdep: %s is empty\n", depfile); | 
|  | close(fd); | 
|  | return; | 
|  | } | 
|  | map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); | 
|  | if ((long) map == -1) { | 
|  | perror("fixdep: mmap"); | 
|  | close(fd); | 
|  | return; | 
|  | } | 
|  |  | 
|  | parse_dep_file(map, st.st_size); | 
|  |  | 
|  | munmap(map, st.st_size); | 
|  |  | 
|  | close(fd); | 
|  | } | 
|  |  | 
|  | int main(int argc, char **argv) | 
|  | { | 
|  | if (argc != 4) | 
|  | usage(); | 
|  |  | 
|  | depfile = argv[1]; | 
|  | target  = argv[2]; | 
|  | cmdline = argv[3]; | 
|  |  | 
|  | print_cmdline(); | 
|  | print_deps(); | 
|  |  | 
|  | return 0; | 
|  | } |