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