162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * "Optimize" a list of dependencies as spit out by gcc -MD
462306a36Sopenharmony_ci * for the build framework.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Original author:
762306a36Sopenharmony_ci *   Copyright    2002 by Kai Germaschewski  <kai.germaschewski@gmx.de>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * This code has been borrowed from kbuild's fixdep (scripts/basic/fixdep.c),
1062306a36Sopenharmony_ci * Please check it for detailed explanation. This fixdep borow only the
1162306a36Sopenharmony_ci * base transformation of dependecies without the CONFIG mangle.
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <sys/types.h>
1562306a36Sopenharmony_ci#include <sys/stat.h>
1662306a36Sopenharmony_ci#include <sys/mman.h>
1762306a36Sopenharmony_ci#include <unistd.h>
1862306a36Sopenharmony_ci#include <fcntl.h>
1962306a36Sopenharmony_ci#include <string.h>
2062306a36Sopenharmony_ci#include <stdlib.h>
2162306a36Sopenharmony_ci#include <stdio.h>
2262306a36Sopenharmony_ci#include <limits.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cichar *target;
2562306a36Sopenharmony_cichar *depfile;
2662306a36Sopenharmony_cichar *cmdline;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic void usage(void)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n");
3162306a36Sopenharmony_ci	exit(1);
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/*
3562306a36Sopenharmony_ci * Print out the commandline prefixed with cmd_<target filename> :=
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_cistatic void print_cmdline(void)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	printf("cmd_%s := %s\n\n", target, cmdline);
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/*
4362306a36Sopenharmony_ci * Important: The below generated source_foo.o and deps_foo.o variable
4462306a36Sopenharmony_ci * assignments are parsed not only by make, but also by the rather simple
4562306a36Sopenharmony_ci * parser in scripts/mod/sumversion.c.
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_cistatic void parse_dep_file(void *map, size_t len)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	char *m = map;
5062306a36Sopenharmony_ci	char *end = m + len;
5162306a36Sopenharmony_ci	char *p;
5262306a36Sopenharmony_ci	char s[PATH_MAX];
5362306a36Sopenharmony_ci	int is_target, has_target = 0;
5462306a36Sopenharmony_ci	int saw_any_target = 0;
5562306a36Sopenharmony_ci	int is_first_dep = 0;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	while (m < end) {
5862306a36Sopenharmony_ci		/* Skip any "white space" */
5962306a36Sopenharmony_ci		while (m < end && (*m == ' ' || *m == '\\' || *m == '\n'))
6062306a36Sopenharmony_ci			m++;
6162306a36Sopenharmony_ci		/* Find next "white space" */
6262306a36Sopenharmony_ci		p = m;
6362306a36Sopenharmony_ci		while (p < end && *p != ' ' && *p != '\\' && *p != '\n')
6462306a36Sopenharmony_ci			p++;
6562306a36Sopenharmony_ci		/* Is the token we found a target name? */
6662306a36Sopenharmony_ci		is_target = (*(p-1) == ':');
6762306a36Sopenharmony_ci		/* Don't write any target names into the dependency file */
6862306a36Sopenharmony_ci		if (is_target) {
6962306a36Sopenharmony_ci			/* The /next/ file is the first dependency */
7062306a36Sopenharmony_ci			is_first_dep = 1;
7162306a36Sopenharmony_ci			has_target = 1;
7262306a36Sopenharmony_ci		} else if (has_target) {
7362306a36Sopenharmony_ci			/* Save this token/filename */
7462306a36Sopenharmony_ci			memcpy(s, m, p-m);
7562306a36Sopenharmony_ci			s[p - m] = 0;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci			/*
7862306a36Sopenharmony_ci			 * Do not list the source file as dependency,
7962306a36Sopenharmony_ci			 * so that kbuild is not confused if a .c file
8062306a36Sopenharmony_ci			 * is rewritten into .S or vice versa. Storing
8162306a36Sopenharmony_ci			 * it in source_* is needed for modpost to
8262306a36Sopenharmony_ci			 * compute srcversions.
8362306a36Sopenharmony_ci			 */
8462306a36Sopenharmony_ci			if (is_first_dep) {
8562306a36Sopenharmony_ci				/*
8662306a36Sopenharmony_ci				 * If processing the concatenation of
8762306a36Sopenharmony_ci				 * multiple dependency files, only
8862306a36Sopenharmony_ci				 * process the first target name, which
8962306a36Sopenharmony_ci				 * will be the original source name,
9062306a36Sopenharmony_ci				 * and ignore any other target names,
9162306a36Sopenharmony_ci				 * which will be intermediate temporary
9262306a36Sopenharmony_ci				 * files.
9362306a36Sopenharmony_ci				 */
9462306a36Sopenharmony_ci				if (!saw_any_target) {
9562306a36Sopenharmony_ci					saw_any_target = 1;
9662306a36Sopenharmony_ci					printf("source_%s := %s\n\n",
9762306a36Sopenharmony_ci						target, s);
9862306a36Sopenharmony_ci					printf("deps_%s := \\\n",
9962306a36Sopenharmony_ci						target);
10062306a36Sopenharmony_ci				}
10162306a36Sopenharmony_ci				is_first_dep = 0;
10262306a36Sopenharmony_ci			} else
10362306a36Sopenharmony_ci				printf("  %s \\\n", s);
10462306a36Sopenharmony_ci		}
10562306a36Sopenharmony_ci		/*
10662306a36Sopenharmony_ci		 * Start searching for next token immediately after the first
10762306a36Sopenharmony_ci		 * "whitespace" character that follows this token.
10862306a36Sopenharmony_ci		 */
10962306a36Sopenharmony_ci		m = p + 1;
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	if (!saw_any_target) {
11362306a36Sopenharmony_ci		fprintf(stderr, "fixdep: parse error; no targets found\n");
11462306a36Sopenharmony_ci		exit(1);
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	printf("\n%s: $(deps_%s)\n\n", target, target);
11862306a36Sopenharmony_ci	printf("$(deps_%s):\n", target);
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic void print_deps(void)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	struct stat st;
12462306a36Sopenharmony_ci	int fd;
12562306a36Sopenharmony_ci	void *map;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	fd = open(depfile, O_RDONLY);
12862306a36Sopenharmony_ci	if (fd < 0) {
12962306a36Sopenharmony_ci		fprintf(stderr, "fixdep: error opening depfile: ");
13062306a36Sopenharmony_ci		perror(depfile);
13162306a36Sopenharmony_ci		exit(2);
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci	if (fstat(fd, &st) < 0) {
13462306a36Sopenharmony_ci		fprintf(stderr, "fixdep: error fstat'ing depfile: ");
13562306a36Sopenharmony_ci		perror(depfile);
13662306a36Sopenharmony_ci		exit(2);
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci	if (st.st_size == 0) {
13962306a36Sopenharmony_ci		fprintf(stderr, "fixdep: %s is empty\n", depfile);
14062306a36Sopenharmony_ci		close(fd);
14162306a36Sopenharmony_ci		return;
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci	map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
14462306a36Sopenharmony_ci	if ((long) map == -1) {
14562306a36Sopenharmony_ci		perror("fixdep: mmap");
14662306a36Sopenharmony_ci		close(fd);
14762306a36Sopenharmony_ci		return;
14862306a36Sopenharmony_ci	}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	parse_dep_file(map, st.st_size);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	munmap(map, st.st_size);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	close(fd);
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ciint main(int argc, char **argv)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	if (argc != 4)
16062306a36Sopenharmony_ci		usage();
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	depfile = argv[1];
16362306a36Sopenharmony_ci	target  = argv[2];
16462306a36Sopenharmony_ci	cmdline = argv[3];
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	print_cmdline();
16762306a36Sopenharmony_ci	print_deps();
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	return 0;
17062306a36Sopenharmony_ci}
171