18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * "Optimize" a list of dependencies as spit out by gcc -MD
48c2ecf20Sopenharmony_ci * for the build framework.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Original author:
78c2ecf20Sopenharmony_ci *   Copyright    2002 by Kai Germaschewski  <kai.germaschewski@gmx.de>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * This code has been borrowed from kbuild's fixdep (scripts/basic/fixdep.c),
108c2ecf20Sopenharmony_ci * Please check it for detailed explanation. This fixdep borow only the
118c2ecf20Sopenharmony_ci * base transformation of dependecies without the CONFIG mangle.
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <sys/types.h>
158c2ecf20Sopenharmony_ci#include <sys/stat.h>
168c2ecf20Sopenharmony_ci#include <sys/mman.h>
178c2ecf20Sopenharmony_ci#include <unistd.h>
188c2ecf20Sopenharmony_ci#include <fcntl.h>
198c2ecf20Sopenharmony_ci#include <string.h>
208c2ecf20Sopenharmony_ci#include <stdlib.h>
218c2ecf20Sopenharmony_ci#include <stdio.h>
228c2ecf20Sopenharmony_ci#include <limits.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cichar *target;
258c2ecf20Sopenharmony_cichar *depfile;
268c2ecf20Sopenharmony_cichar *cmdline;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic void usage(void)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n");
318c2ecf20Sopenharmony_ci	exit(1);
328c2ecf20Sopenharmony_ci}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/*
358c2ecf20Sopenharmony_ci * Print out the commandline prefixed with cmd_<target filename> :=
368c2ecf20Sopenharmony_ci */
378c2ecf20Sopenharmony_cistatic void print_cmdline(void)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	printf("cmd_%s := %s\n\n", target, cmdline);
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/*
438c2ecf20Sopenharmony_ci * Important: The below generated source_foo.o and deps_foo.o variable
448c2ecf20Sopenharmony_ci * assignments are parsed not only by make, but also by the rather simple
458c2ecf20Sopenharmony_ci * parser in scripts/mod/sumversion.c.
468c2ecf20Sopenharmony_ci */
478c2ecf20Sopenharmony_cistatic void parse_dep_file(void *map, size_t len)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	char *m = map;
508c2ecf20Sopenharmony_ci	char *end = m + len;
518c2ecf20Sopenharmony_ci	char *p;
528c2ecf20Sopenharmony_ci	char s[PATH_MAX];
538c2ecf20Sopenharmony_ci	int is_target, has_target = 0;
548c2ecf20Sopenharmony_ci	int saw_any_target = 0;
558c2ecf20Sopenharmony_ci	int is_first_dep = 0;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	while (m < end) {
588c2ecf20Sopenharmony_ci		/* Skip any "white space" */
598c2ecf20Sopenharmony_ci		while (m < end && (*m == ' ' || *m == '\\' || *m == '\n'))
608c2ecf20Sopenharmony_ci			m++;
618c2ecf20Sopenharmony_ci		/* Find next "white space" */
628c2ecf20Sopenharmony_ci		p = m;
638c2ecf20Sopenharmony_ci		while (p < end && *p != ' ' && *p != '\\' && *p != '\n')
648c2ecf20Sopenharmony_ci			p++;
658c2ecf20Sopenharmony_ci		/* Is the token we found a target name? */
668c2ecf20Sopenharmony_ci		is_target = (*(p-1) == ':');
678c2ecf20Sopenharmony_ci		/* Don't write any target names into the dependency file */
688c2ecf20Sopenharmony_ci		if (is_target) {
698c2ecf20Sopenharmony_ci			/* The /next/ file is the first dependency */
708c2ecf20Sopenharmony_ci			is_first_dep = 1;
718c2ecf20Sopenharmony_ci			has_target = 1;
728c2ecf20Sopenharmony_ci		} else if (has_target) {
738c2ecf20Sopenharmony_ci			/* Save this token/filename */
748c2ecf20Sopenharmony_ci			memcpy(s, m, p-m);
758c2ecf20Sopenharmony_ci			s[p - m] = 0;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci			/*
788c2ecf20Sopenharmony_ci			 * Do not list the source file as dependency,
798c2ecf20Sopenharmony_ci			 * so that kbuild is not confused if a .c file
808c2ecf20Sopenharmony_ci			 * is rewritten into .S or vice versa. Storing
818c2ecf20Sopenharmony_ci			 * it in source_* is needed for modpost to
828c2ecf20Sopenharmony_ci			 * compute srcversions.
838c2ecf20Sopenharmony_ci			 */
848c2ecf20Sopenharmony_ci			if (is_first_dep) {
858c2ecf20Sopenharmony_ci				/*
868c2ecf20Sopenharmony_ci				 * If processing the concatenation of
878c2ecf20Sopenharmony_ci				 * multiple dependency files, only
888c2ecf20Sopenharmony_ci				 * process the first target name, which
898c2ecf20Sopenharmony_ci				 * will be the original source name,
908c2ecf20Sopenharmony_ci				 * and ignore any other target names,
918c2ecf20Sopenharmony_ci				 * which will be intermediate temporary
928c2ecf20Sopenharmony_ci				 * files.
938c2ecf20Sopenharmony_ci				 */
948c2ecf20Sopenharmony_ci				if (!saw_any_target) {
958c2ecf20Sopenharmony_ci					saw_any_target = 1;
968c2ecf20Sopenharmony_ci					printf("source_%s := %s\n\n",
978c2ecf20Sopenharmony_ci						target, s);
988c2ecf20Sopenharmony_ci					printf("deps_%s := \\\n",
998c2ecf20Sopenharmony_ci						target);
1008c2ecf20Sopenharmony_ci				}
1018c2ecf20Sopenharmony_ci				is_first_dep = 0;
1028c2ecf20Sopenharmony_ci			} else
1038c2ecf20Sopenharmony_ci				printf("  %s \\\n", s);
1048c2ecf20Sopenharmony_ci		}
1058c2ecf20Sopenharmony_ci		/*
1068c2ecf20Sopenharmony_ci		 * Start searching for next token immediately after the first
1078c2ecf20Sopenharmony_ci		 * "whitespace" character that follows this token.
1088c2ecf20Sopenharmony_ci		 */
1098c2ecf20Sopenharmony_ci		m = p + 1;
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	if (!saw_any_target) {
1138c2ecf20Sopenharmony_ci		fprintf(stderr, "fixdep: parse error; no targets found\n");
1148c2ecf20Sopenharmony_ci		exit(1);
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	printf("\n%s: $(deps_%s)\n\n", target, target);
1188c2ecf20Sopenharmony_ci	printf("$(deps_%s):\n", target);
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic void print_deps(void)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	struct stat st;
1248c2ecf20Sopenharmony_ci	int fd;
1258c2ecf20Sopenharmony_ci	void *map;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	fd = open(depfile, O_RDONLY);
1288c2ecf20Sopenharmony_ci	if (fd < 0) {
1298c2ecf20Sopenharmony_ci		fprintf(stderr, "fixdep: error opening depfile: ");
1308c2ecf20Sopenharmony_ci		perror(depfile);
1318c2ecf20Sopenharmony_ci		exit(2);
1328c2ecf20Sopenharmony_ci	}
1338c2ecf20Sopenharmony_ci	if (fstat(fd, &st) < 0) {
1348c2ecf20Sopenharmony_ci		fprintf(stderr, "fixdep: error fstat'ing depfile: ");
1358c2ecf20Sopenharmony_ci		perror(depfile);
1368c2ecf20Sopenharmony_ci		exit(2);
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci	if (st.st_size == 0) {
1398c2ecf20Sopenharmony_ci		fprintf(stderr, "fixdep: %s is empty\n", depfile);
1408c2ecf20Sopenharmony_ci		close(fd);
1418c2ecf20Sopenharmony_ci		return;
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci	map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
1448c2ecf20Sopenharmony_ci	if ((long) map == -1) {
1458c2ecf20Sopenharmony_ci		perror("fixdep: mmap");
1468c2ecf20Sopenharmony_ci		close(fd);
1478c2ecf20Sopenharmony_ci		return;
1488c2ecf20Sopenharmony_ci	}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	parse_dep_file(map, st.st_size);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	munmap(map, st.st_size);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	close(fd);
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ciint main(int argc, char **argv)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	if (argc != 4)
1608c2ecf20Sopenharmony_ci		usage();
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	depfile = argv[1];
1638c2ecf20Sopenharmony_ci	target  = argv[2];
1648c2ecf20Sopenharmony_ci	cmdline = argv[3];
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	print_cmdline();
1678c2ecf20Sopenharmony_ci	print_deps();
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	return 0;
1708c2ecf20Sopenharmony_ci}
171