162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * "Optimize" a list of dependencies as spit out by gcc -MD 362306a36Sopenharmony_ci * for the kernel build 462306a36Sopenharmony_ci * =========================================================================== 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Author Kai Germaschewski 762306a36Sopenharmony_ci * Copyright 2002 by Kai Germaschewski <kai.germaschewski@gmx.de> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * This software may be used and distributed according to the terms 1062306a36Sopenharmony_ci * of the GNU General Public License, incorporated herein by reference. 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Introduction: 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * gcc produces a very nice and correct list of dependencies which 1662306a36Sopenharmony_ci * tells make when to remake a file. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * To use this list as-is however has the drawback that virtually 1962306a36Sopenharmony_ci * every file in the kernel includes autoconf.h. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * If the user re-runs make *config, autoconf.h will be 2262306a36Sopenharmony_ci * regenerated. make notices that and will rebuild every file which 2362306a36Sopenharmony_ci * includes autoconf.h, i.e. basically all files. This is extremely 2462306a36Sopenharmony_ci * annoying if the user just changed CONFIG_HIS_DRIVER from n to m. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * So we play the same trick that "mkdep" played before. We replace 2762306a36Sopenharmony_ci * the dependency on autoconf.h by a dependency on every config 2862306a36Sopenharmony_ci * option which is mentioned in any of the listed prerequisites. 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * kconfig populates a tree in include/config/ with an empty file 3162306a36Sopenharmony_ci * for each config symbol and when the configuration is updated 3262306a36Sopenharmony_ci * the files representing changed config options are touched 3362306a36Sopenharmony_ci * which then let make pick up the changes and the files that use 3462306a36Sopenharmony_ci * the config symbols are rebuilt. 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * So if the user changes his CONFIG_HIS_DRIVER option, only the objects 3762306a36Sopenharmony_ci * which depend on "include/config/HIS_DRIVER" will be rebuilt, 3862306a36Sopenharmony_ci * so most likely only his driver ;-) 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci * The idea above dates, by the way, back to Michael E Chastain, AFAIK. 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci * So to get dependencies right, there are two issues: 4362306a36Sopenharmony_ci * o if any of the files the compiler read changed, we need to rebuild 4462306a36Sopenharmony_ci * o if the command line given to the compile the file changed, we 4562306a36Sopenharmony_ci * better rebuild as well. 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * The former is handled by using the -MD output, the later by saving 4862306a36Sopenharmony_ci * the command line used to compile the old object and comparing it 4962306a36Sopenharmony_ci * to the one we would now use. 5062306a36Sopenharmony_ci * 5162306a36Sopenharmony_ci * Again, also this idea is pretty old and has been discussed on 5262306a36Sopenharmony_ci * kbuild-devel a long time ago. I don't have a sensibly working 5362306a36Sopenharmony_ci * internet connection right now, so I rather don't mention names 5462306a36Sopenharmony_ci * without double checking. 5562306a36Sopenharmony_ci * 5662306a36Sopenharmony_ci * This code here has been based partially based on mkdep.c, which 5762306a36Sopenharmony_ci * says the following about its history: 5862306a36Sopenharmony_ci * 5962306a36Sopenharmony_ci * Copyright abandoned, Michael Chastain, <mailto:mec@shout.net>. 6062306a36Sopenharmony_ci * This is a C version of syncdep.pl by Werner Almesberger. 6162306a36Sopenharmony_ci * 6262306a36Sopenharmony_ci * 6362306a36Sopenharmony_ci * It is invoked as 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * fixdep <depfile> <target> <cmdline> 6662306a36Sopenharmony_ci * 6762306a36Sopenharmony_ci * and will read the dependency file <depfile> 6862306a36Sopenharmony_ci * 6962306a36Sopenharmony_ci * The transformed dependency snipped is written to stdout. 7062306a36Sopenharmony_ci * 7162306a36Sopenharmony_ci * It first generates a line 7262306a36Sopenharmony_ci * 7362306a36Sopenharmony_ci * savedcmd_<target> = <cmdline> 7462306a36Sopenharmony_ci * 7562306a36Sopenharmony_ci * and then basically copies the .<target>.d file to stdout, in the 7662306a36Sopenharmony_ci * process filtering out the dependency on autoconf.h and adding 7762306a36Sopenharmony_ci * dependencies on include/config/MY_OPTION for every 7862306a36Sopenharmony_ci * CONFIG_MY_OPTION encountered in any of the prerequisites. 7962306a36Sopenharmony_ci * 8062306a36Sopenharmony_ci * We don't even try to really parse the header files, but 8162306a36Sopenharmony_ci * merely grep, i.e. if CONFIG_FOO is mentioned in a comment, it will 8262306a36Sopenharmony_ci * be picked up as well. It's not a problem with respect to 8362306a36Sopenharmony_ci * correctness, since that can only give too many dependencies, thus 8462306a36Sopenharmony_ci * we cannot miss a rebuild. Since people tend to not mention totally 8562306a36Sopenharmony_ci * unrelated CONFIG_ options all over the place, it's not an 8662306a36Sopenharmony_ci * efficiency problem either. 8762306a36Sopenharmony_ci * 8862306a36Sopenharmony_ci * (Note: it'd be easy to port over the complete mkdep state machine, 8962306a36Sopenharmony_ci * but I don't think the added complexity is worth it) 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci#include <sys/types.h> 9362306a36Sopenharmony_ci#include <sys/stat.h> 9462306a36Sopenharmony_ci#include <unistd.h> 9562306a36Sopenharmony_ci#include <fcntl.h> 9662306a36Sopenharmony_ci#include <string.h> 9762306a36Sopenharmony_ci#include <stdbool.h> 9862306a36Sopenharmony_ci#include <stdlib.h> 9962306a36Sopenharmony_ci#include <stdio.h> 10062306a36Sopenharmony_ci#include <ctype.h> 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic void usage(void) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n"); 10562306a36Sopenharmony_ci exit(1); 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistruct item { 10962306a36Sopenharmony_ci struct item *next; 11062306a36Sopenharmony_ci unsigned int len; 11162306a36Sopenharmony_ci unsigned int hash; 11262306a36Sopenharmony_ci char name[]; 11362306a36Sopenharmony_ci}; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci#define HASHSZ 256 11662306a36Sopenharmony_cistatic struct item *config_hashtab[HASHSZ], *file_hashtab[HASHSZ]; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic unsigned int strhash(const char *str, unsigned int sz) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci /* fnv32 hash */ 12162306a36Sopenharmony_ci unsigned int i, hash = 2166136261U; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci for (i = 0; i < sz; i++) 12462306a36Sopenharmony_ci hash = (hash ^ str[i]) * 0x01000193; 12562306a36Sopenharmony_ci return hash; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci/* 12962306a36Sopenharmony_ci * Add a new value to the configuration string. 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_cistatic void add_to_hashtable(const char *name, int len, unsigned int hash, 13262306a36Sopenharmony_ci struct item *hashtab[]) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci struct item *aux = malloc(sizeof(*aux) + len); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (!aux) { 13762306a36Sopenharmony_ci perror("fixdep:malloc"); 13862306a36Sopenharmony_ci exit(1); 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci memcpy(aux->name, name, len); 14162306a36Sopenharmony_ci aux->len = len; 14262306a36Sopenharmony_ci aux->hash = hash; 14362306a36Sopenharmony_ci aux->next = hashtab[hash % HASHSZ]; 14462306a36Sopenharmony_ci hashtab[hash % HASHSZ] = aux; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci/* 14862306a36Sopenharmony_ci * Lookup a string in the hash table. If found, just return true. 14962306a36Sopenharmony_ci * If not, add it to the hashtable and return false. 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_cistatic bool in_hashtable(const char *name, int len, struct item *hashtab[]) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct item *aux; 15462306a36Sopenharmony_ci unsigned int hash = strhash(name, len); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci for (aux = hashtab[hash % HASHSZ]; aux; aux = aux->next) { 15762306a36Sopenharmony_ci if (aux->hash == hash && aux->len == len && 15862306a36Sopenharmony_ci memcmp(aux->name, name, len) == 0) 15962306a36Sopenharmony_ci return true; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci add_to_hashtable(name, len, hash, hashtab); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci return false; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci/* 16862306a36Sopenharmony_ci * Record the use of a CONFIG_* word. 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_cistatic void use_config(const char *m, int slen) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci if (in_hashtable(m, slen, config_hashtab)) 17362306a36Sopenharmony_ci return; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* Print out a dependency path from a symbol name. */ 17662306a36Sopenharmony_ci printf(" $(wildcard include/config/%.*s) \\\n", slen, m); 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/* test if s ends in sub */ 18062306a36Sopenharmony_cistatic int str_ends_with(const char *s, int slen, const char *sub) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci int sublen = strlen(sub); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (sublen > slen) 18562306a36Sopenharmony_ci return 0; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci return !memcmp(s + slen - sublen, sub, sublen); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic void parse_config_file(const char *p) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci const char *q, *r; 19362306a36Sopenharmony_ci const char *start = p; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci while ((p = strstr(p, "CONFIG_"))) { 19662306a36Sopenharmony_ci if (p > start && (isalnum(p[-1]) || p[-1] == '_')) { 19762306a36Sopenharmony_ci p += 7; 19862306a36Sopenharmony_ci continue; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci p += 7; 20162306a36Sopenharmony_ci q = p; 20262306a36Sopenharmony_ci while (isalnum(*q) || *q == '_') 20362306a36Sopenharmony_ci q++; 20462306a36Sopenharmony_ci if (str_ends_with(p, q - p, "_MODULE")) 20562306a36Sopenharmony_ci r = q - 7; 20662306a36Sopenharmony_ci else 20762306a36Sopenharmony_ci r = q; 20862306a36Sopenharmony_ci if (r > p) 20962306a36Sopenharmony_ci use_config(p, r - p); 21062306a36Sopenharmony_ci p = q; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic void *read_file(const char *filename) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci struct stat st; 21762306a36Sopenharmony_ci int fd; 21862306a36Sopenharmony_ci char *buf; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci fd = open(filename, O_RDONLY); 22162306a36Sopenharmony_ci if (fd < 0) { 22262306a36Sopenharmony_ci fprintf(stderr, "fixdep: error opening file: "); 22362306a36Sopenharmony_ci perror(filename); 22462306a36Sopenharmony_ci exit(2); 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci if (fstat(fd, &st) < 0) { 22762306a36Sopenharmony_ci fprintf(stderr, "fixdep: error fstat'ing file: "); 22862306a36Sopenharmony_ci perror(filename); 22962306a36Sopenharmony_ci exit(2); 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci buf = malloc(st.st_size + 1); 23262306a36Sopenharmony_ci if (!buf) { 23362306a36Sopenharmony_ci perror("fixdep: malloc"); 23462306a36Sopenharmony_ci exit(2); 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci if (read(fd, buf, st.st_size) != st.st_size) { 23762306a36Sopenharmony_ci perror("fixdep: read"); 23862306a36Sopenharmony_ci exit(2); 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci buf[st.st_size] = '\0'; 24162306a36Sopenharmony_ci close(fd); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci return buf; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci/* Ignore certain dependencies */ 24762306a36Sopenharmony_cistatic int is_ignored_file(const char *s, int len) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci return str_ends_with(s, len, "include/generated/autoconf.h"); 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci/* Do not parse these files */ 25362306a36Sopenharmony_cistatic int is_no_parse_file(const char *s, int len) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci /* rustc may list binary files in dep-info */ 25662306a36Sopenharmony_ci return str_ends_with(s, len, ".rlib") || 25762306a36Sopenharmony_ci str_ends_with(s, len, ".rmeta") || 25862306a36Sopenharmony_ci str_ends_with(s, len, ".so"); 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci/* 26262306a36Sopenharmony_ci * Important: The below generated source_foo.o and deps_foo.o variable 26362306a36Sopenharmony_ci * assignments are parsed not only by make, but also by the rather simple 26462306a36Sopenharmony_ci * parser in scripts/mod/sumversion.c. 26562306a36Sopenharmony_ci */ 26662306a36Sopenharmony_cistatic void parse_dep_file(char *p, const char *target) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci bool saw_any_target = false; 26962306a36Sopenharmony_ci bool is_target = true; 27062306a36Sopenharmony_ci bool is_source = false; 27162306a36Sopenharmony_ci bool need_parse; 27262306a36Sopenharmony_ci char *q, saved_c; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci while (*p) { 27562306a36Sopenharmony_ci /* handle some special characters first. */ 27662306a36Sopenharmony_ci switch (*p) { 27762306a36Sopenharmony_ci case '#': 27862306a36Sopenharmony_ci /* 27962306a36Sopenharmony_ci * skip comments. 28062306a36Sopenharmony_ci * rustc may emit comments to dep-info. 28162306a36Sopenharmony_ci */ 28262306a36Sopenharmony_ci p++; 28362306a36Sopenharmony_ci while (*p != '\0' && *p != '\n') { 28462306a36Sopenharmony_ci /* 28562306a36Sopenharmony_ci * escaped newlines continue the comment across 28662306a36Sopenharmony_ci * multiple lines. 28762306a36Sopenharmony_ci */ 28862306a36Sopenharmony_ci if (*p == '\\') 28962306a36Sopenharmony_ci p++; 29062306a36Sopenharmony_ci p++; 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci continue; 29362306a36Sopenharmony_ci case ' ': 29462306a36Sopenharmony_ci case '\t': 29562306a36Sopenharmony_ci /* skip whitespaces */ 29662306a36Sopenharmony_ci p++; 29762306a36Sopenharmony_ci continue; 29862306a36Sopenharmony_ci case '\\': 29962306a36Sopenharmony_ci /* 30062306a36Sopenharmony_ci * backslash/newline combinations continue the 30162306a36Sopenharmony_ci * statement. Skip it just like a whitespace. 30262306a36Sopenharmony_ci */ 30362306a36Sopenharmony_ci if (*(p + 1) == '\n') { 30462306a36Sopenharmony_ci p += 2; 30562306a36Sopenharmony_ci continue; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci break; 30862306a36Sopenharmony_ci case '\n': 30962306a36Sopenharmony_ci /* 31062306a36Sopenharmony_ci * Makefiles use a line-based syntax, where the newline 31162306a36Sopenharmony_ci * is the end of a statement. After seeing a newline, 31262306a36Sopenharmony_ci * we expect the next token is a target. 31362306a36Sopenharmony_ci */ 31462306a36Sopenharmony_ci p++; 31562306a36Sopenharmony_ci is_target = true; 31662306a36Sopenharmony_ci continue; 31762306a36Sopenharmony_ci case ':': 31862306a36Sopenharmony_ci /* 31962306a36Sopenharmony_ci * assume the first dependency after a colon as the 32062306a36Sopenharmony_ci * source file. 32162306a36Sopenharmony_ci */ 32262306a36Sopenharmony_ci p++; 32362306a36Sopenharmony_ci is_target = false; 32462306a36Sopenharmony_ci is_source = true; 32562306a36Sopenharmony_ci continue; 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci /* find the end of the token */ 32962306a36Sopenharmony_ci q = p; 33062306a36Sopenharmony_ci while (*q != ' ' && *q != '\t' && *q != '\n' && *q != '#' && *q != ':') { 33162306a36Sopenharmony_ci if (*q == '\\') { 33262306a36Sopenharmony_ci /* 33362306a36Sopenharmony_ci * backslash/newline combinations work like as 33462306a36Sopenharmony_ci * a whitespace, so this is the end of token. 33562306a36Sopenharmony_ci */ 33662306a36Sopenharmony_ci if (*(q + 1) == '\n') 33762306a36Sopenharmony_ci break; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* escaped special characters */ 34062306a36Sopenharmony_ci if (*(q + 1) == '#' || *(q + 1) == ':') { 34162306a36Sopenharmony_ci memmove(p + 1, p, q - p); 34262306a36Sopenharmony_ci p++; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci q++; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (*q == '\0') 34962306a36Sopenharmony_ci break; 35062306a36Sopenharmony_ci q++; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci /* Just discard the target */ 35462306a36Sopenharmony_ci if (is_target) { 35562306a36Sopenharmony_ci p = q; 35662306a36Sopenharmony_ci continue; 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci saved_c = *q; 36062306a36Sopenharmony_ci *q = '\0'; 36162306a36Sopenharmony_ci need_parse = false; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* 36462306a36Sopenharmony_ci * Do not list the source file as dependency, so that kbuild is 36562306a36Sopenharmony_ci * not confused if a .c file is rewritten into .S or vice versa. 36662306a36Sopenharmony_ci * Storing it in source_* is needed for modpost to compute 36762306a36Sopenharmony_ci * srcversions. 36862306a36Sopenharmony_ci */ 36962306a36Sopenharmony_ci if (is_source) { 37062306a36Sopenharmony_ci /* 37162306a36Sopenharmony_ci * The DT build rule concatenates multiple dep files. 37262306a36Sopenharmony_ci * When processing them, only process the first source 37362306a36Sopenharmony_ci * name, which will be the original one, and ignore any 37462306a36Sopenharmony_ci * other source names, which will be intermediate 37562306a36Sopenharmony_ci * temporary files. 37662306a36Sopenharmony_ci * 37762306a36Sopenharmony_ci * rustc emits the same dependency list for each 37862306a36Sopenharmony_ci * emission type. It is enough to list the source name 37962306a36Sopenharmony_ci * just once. 38062306a36Sopenharmony_ci */ 38162306a36Sopenharmony_ci if (!saw_any_target) { 38262306a36Sopenharmony_ci saw_any_target = true; 38362306a36Sopenharmony_ci printf("source_%s := %s\n\n", target, p); 38462306a36Sopenharmony_ci printf("deps_%s := \\\n", target); 38562306a36Sopenharmony_ci need_parse = true; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci } else if (!is_ignored_file(p, q - p) && 38862306a36Sopenharmony_ci !in_hashtable(p, q - p, file_hashtab)) { 38962306a36Sopenharmony_ci printf(" %s \\\n", p); 39062306a36Sopenharmony_ci need_parse = true; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci if (need_parse && !is_no_parse_file(p, q - p)) { 39462306a36Sopenharmony_ci void *buf; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci buf = read_file(p); 39762306a36Sopenharmony_ci parse_config_file(buf); 39862306a36Sopenharmony_ci free(buf); 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci is_source = false; 40262306a36Sopenharmony_ci *q = saved_c; 40362306a36Sopenharmony_ci p = q; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci if (!saw_any_target) { 40762306a36Sopenharmony_ci fprintf(stderr, "fixdep: parse error; no targets found\n"); 40862306a36Sopenharmony_ci exit(1); 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci printf("\n%s: $(deps_%s)\n\n", target, target); 41262306a36Sopenharmony_ci printf("$(deps_%s):\n", target); 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ciint main(int argc, char *argv[]) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci const char *depfile, *target, *cmdline; 41862306a36Sopenharmony_ci void *buf; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci if (argc != 4) 42162306a36Sopenharmony_ci usage(); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci depfile = argv[1]; 42462306a36Sopenharmony_ci target = argv[2]; 42562306a36Sopenharmony_ci cmdline = argv[3]; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci printf("savedcmd_%s := %s\n\n", target, cmdline); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci buf = read_file(depfile); 43062306a36Sopenharmony_ci parse_dep_file(buf, target); 43162306a36Sopenharmony_ci free(buf); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci fflush(stdout); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci /* 43662306a36Sopenharmony_ci * In the intended usage, the stdout is redirected to .*.cmd files. 43762306a36Sopenharmony_ci * Call ferror() to catch errors such as "No space left on device". 43862306a36Sopenharmony_ci */ 43962306a36Sopenharmony_ci if (ferror(stdout)) { 44062306a36Sopenharmony_ci fprintf(stderr, "fixdep: not all data was written to the output\n"); 44162306a36Sopenharmony_ci exit(1); 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci return 0; 44562306a36Sopenharmony_ci} 446