Home | History | Annotate | Line # | Download | only in mkdep
mkdep.c revision 1.20
      1  1.20      dsl /* $NetBSD: mkdep.c,v 1.20 2003/11/11 10:55:24 dsl Exp $ */
      2   1.1     tron 
      3   1.1     tron /*-
      4   1.1     tron  * Copyright (c) 1999 The NetBSD Foundation, Inc.
      5   1.1     tron  * All rights reserved.
      6   1.1     tron  *
      7   1.1     tron  * This code is derived from software contributed to The NetBSD Foundation
      8   1.1     tron  * by Matthias Scheler.
      9   1.1     tron  *
     10   1.1     tron  * Redistribution and use in source and binary forms, with or without
     11   1.1     tron  * modification, are permitted provided that the following conditions
     12   1.1     tron  * are met:
     13   1.1     tron  * 1. Redistributions of source code must retain the above copyright
     14   1.1     tron  *    notice, this list of conditions and the following disclaimer.
     15   1.1     tron  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.1     tron  *    notice, this list of conditions and the following disclaimer in the
     17   1.1     tron  *    documentation and/or other materials provided with the distribution.
     18   1.1     tron  * 3. All advertising materials mentioning features or use of this software
     19   1.1     tron  *    must display the following acknowledgement:
     20   1.1     tron  *	This product includes software developed by the NetBSD
     21   1.1     tron  *	Foundation, Inc. and its contributors.
     22   1.1     tron  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23   1.1     tron  *    contributors may be used to endorse or promote products derived
     24   1.1     tron  *    from this software without specific prior written permission.
     25   1.1     tron  *
     26   1.1     tron  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27   1.1     tron  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28   1.1     tron  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29   1.8      cgd  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30   1.1     tron  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31   1.1     tron  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32   1.1     tron  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33   1.1     tron  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34   1.1     tron  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35   1.1     tron  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36   1.1     tron  * POSSIBILITY OF SUCH DAMAGE.
     37   1.1     tron  */
     38   1.1     tron 
     39  1.17    lukem #if HAVE_NBTOOL_CONFIG_H
     40  1.17    lukem #include "nbtool_config.h"
     41  1.17    lukem #endif
     42  1.17    lukem 
     43   1.1     tron #include <sys/cdefs.h>
     44  1.17    lukem #if !defined(lint)
     45   1.1     tron __COPYRIGHT("@(#) Copyright (c) 1999 The NetBSD Foundation, Inc.\n\
     46   1.1     tron 	All rights reserved.\n");
     47  1.20      dsl __RCSID("$NetBSD: mkdep.c,v 1.20 2003/11/11 10:55:24 dsl Exp $");
     48   1.1     tron #endif /* not lint */
     49  1.10       tv 
     50  1.18      dsl #include <sys/mman.h>
     51   1.1     tron #include <sys/param.h>
     52   1.1     tron #include <sys/wait.h>
     53   1.1     tron #include <ctype.h>
     54  1.10       tv #include <err.h>
     55  1.18      dsl #include <fcntl.h>
     56   1.1     tron #include <locale.h>
     57   1.1     tron #include <paths.h>
     58  1.12  msaitoh #include <signal.h>
     59   1.1     tron #include <stdio.h>
     60   1.1     tron #include <stdlib.h>
     61   1.1     tron #include <string.h>
     62   1.1     tron #include <unistd.h>
     63   1.1     tron 
     64  1.11   simonb #include "findcc.h"
     65  1.11   simonb 
     66   1.1     tron #define DEFAULT_PATH		_PATH_DEFPATH
     67   1.1     tron #define DEFAULT_FILENAME	".depend"
     68   1.1     tron 
     69  1.12  msaitoh 
     70  1.18      dsl static inline void *
     71  1.18      dsl deconst(const void *p)
     72  1.18      dsl {
     73  1.18      dsl 	return (const char *)p - (const char *)0 + (char *)0;
     74  1.18      dsl }
     75   1.1     tron 
     76   1.3   kleink static void
     77  1.18      dsl usage(void)
     78   1.1     tron {
     79   1.1     tron 	(void)fprintf(stderr,
     80  1.19      dsl 	    "usage: %s [-adopq] [-f file] [-s suffix_list] flags file ...\n",
     81   1.6      cgd 	    getprogname());
     82   1.1     tron 	exit(EXIT_FAILURE);
     83   1.1     tron }
     84   1.1     tron 
     85  1.18      dsl static int
     86  1.18      dsl run_cc(int argc, char **argv, const char **fname)
     87  1.12  msaitoh {
     88  1.18      dsl 	const char *CC, *pathname, *tmpdir;
     89  1.18      dsl 	static char tmpfilename[MAXPATHLEN];
     90  1.18      dsl 	char **args;
     91  1.18      dsl 	int tmpfd;
     92  1.18      dsl 	pid_t pid, cpid;
     93  1.18      dsl 	int status;
     94   1.1     tron 
     95   1.1     tron 	if ((CC = getenv("CC")) == NULL)
     96   1.1     tron 		CC = DEFAULT_CC;
     97   1.1     tron 	if ((pathname = findcc(CC)) == NULL)
     98   1.1     tron 		if (!setenv("PATH", DEFAULT_PATH, 1))
     99   1.1     tron 			pathname = findcc(CC);
    100  1.18      dsl 	if (pathname == NULL)
    101  1.18      dsl 		err(EXIT_FAILURE, "%s: not found", CC);
    102  1.18      dsl 	if ((args = malloc((argc + 3) * sizeof(char *))) == NULL)
    103  1.18      dsl 		err(EXIT_FAILURE, "malloc");
    104   1.1     tron 
    105  1.18      dsl 	args[0] = deconst(CC);
    106  1.18      dsl 	args[1] = deconst("-M");
    107   1.1     tron 	(void)memcpy(&args[2], argv, (argc + 1) * sizeof(char *));
    108   1.1     tron 
    109   1.4   kleink 	if ((tmpdir = getenv("TMPDIR")) == NULL)
    110   1.4   kleink 		tmpdir = _PATH_TMP;
    111   1.4   kleink 	(void)snprintf(tmpfilename, sizeof (tmpfilename), "%s/%s", tmpdir,
    112   1.4   kleink 	    "mkdepXXXXXX");
    113  1.18      dsl 	if ((tmpfd = mkstemp(tmpfilename)) < 0) {
    114   1.1     tron 		warn("unable to create temporary file %s", tmpfilename);
    115   1.7      cgd 		exit(EXIT_FAILURE);
    116   1.1     tron 	}
    117  1.18      dsl 	(void)unlink(tmpfilename);
    118  1.18      dsl 	*fname = tmpfilename;
    119   1.1     tron 
    120   1.1     tron 	switch (cpid = vfork()) {
    121   1.1     tron 	case 0:
    122   1.7      cgd 		(void)dup2(tmpfd, STDOUT_FILENO);
    123   1.7      cgd 		(void)close(tmpfd);
    124   1.1     tron 
    125   1.7      cgd 		(void)execv(pathname, args);
    126   1.7      cgd 		_exit(EXIT_FAILURE);
    127   1.7      cgd 		/* NOTREACHED */
    128   1.1     tron 
    129   1.1     tron 	case -1:
    130  1.18      dsl 		err(EXIT_FAILURE, "unable to fork");
    131   1.1     tron 	}
    132   1.1     tron 
    133   1.7      cgd 	while (((pid = wait(&status)) != cpid) && (pid >= 0))
    134   1.7      cgd 		continue;
    135   1.1     tron 
    136  1.18      dsl 	if (status)
    137  1.18      dsl 		errx(EXIT_FAILURE, "compile failed.");
    138  1.18      dsl 
    139  1.18      dsl 	return tmpfd;
    140  1.18      dsl }
    141  1.18      dsl 
    142  1.18      dsl int
    143  1.18      dsl main(int argc, char **argv)
    144  1.18      dsl {
    145  1.18      dsl 	int 	aflag, dflag, oflag, qflag;
    146  1.18      dsl 	const char *filename;
    147  1.18      dsl 	int	dependfile;
    148  1.20      dsl 	char	*buf, *lim, *ptr, *line, *suf, *colon, *eol;
    149  1.18      dsl 	int	ok_ind, ch;
    150  1.18      dsl 	int	sz;
    151  1.18      dsl 	int	fd;
    152  1.18      dsl 	const char *fname;
    153  1.18      dsl 	const char *suffixes = NULL, *s, *s1;
    154  1.18      dsl 
    155  1.18      dsl 	setlocale(LC_ALL, "");
    156  1.18      dsl 	setprogname(argv[0]);
    157   1.1     tron 
    158  1.18      dsl 	aflag = O_WRONLY | O_APPEND | O_CREAT | O_TRUNC;
    159  1.18      dsl 	dflag = 0;
    160  1.18      dsl 	oflag = 0;
    161  1.18      dsl 	qflag = 0;
    162  1.18      dsl 	filename = DEFAULT_FILENAME;
    163  1.18      dsl 	dependfile = -1;
    164   1.1     tron 
    165  1.18      dsl 	opterr = 0;	/* stop getopt() bleating about errors. */
    166  1.20      dsl 	for (;;) {
    167  1.20      dsl 		ok_ind = optind;
    168  1.20      dsl 		ch = getopt(argc, argv, "adf:opqs:");
    169  1.18      dsl 		switch (ch) {
    170  1.20      dsl 		case -1:
    171  1.20      dsl 			ok_ind = optind;
    172  1.20      dsl 			break;
    173  1.18      dsl 		case 'a':	/* Append to output file */
    174  1.18      dsl 			aflag &= ~O_TRUNC;
    175  1.18      dsl 			continue;
    176  1.18      dsl 		case 'd':	/* Process *.d files (don't run cc -M) */
    177  1.18      dsl 			dflag = 1;
    178  1.18      dsl 			opterr = 1;
    179  1.18      dsl 			continue;
    180  1.18      dsl 		case 'f':	/* Name of output file */
    181  1.18      dsl 			filename = optarg;
    182  1.18      dsl 			continue;
    183  1.18      dsl 		case 'o':	/* Mark dependant files .OPTIONAL */
    184  1.18      dsl 			oflag = 1;
    185  1.18      dsl 			continue;
    186  1.18      dsl 		case 'p':	/* Program mode (x.o: -> x:) */
    187  1.18      dsl 			suffixes = "";
    188  1.18      dsl 			continue;
    189  1.18      dsl 		case 'q':	/* Quiet */
    190  1.18      dsl 			qflag = 1;
    191  1.18      dsl 			continue;
    192  1.18      dsl 		case 's':	/* Suffix list */
    193  1.18      dsl 			suffixes = optarg;
    194  1.18      dsl 			continue;
    195  1.18      dsl 		default:
    196  1.18      dsl 			if (dflag)
    197  1.18      dsl 				usage();
    198  1.18      dsl 			/* Unknown arguments are passed to "${CC} -M" */
    199  1.18      dsl 			break;
    200  1.18      dsl 		}
    201  1.18      dsl 		break;
    202   1.1     tron 	}
    203   1.1     tron 
    204  1.18      dsl 	argc -= ok_ind;
    205  1.18      dsl 	argv += ok_ind;
    206  1.18      dsl 	if (argc == 0 && !dflag)
    207  1.18      dsl 		usage();
    208   1.1     tron 
    209  1.18      dsl 	dependfile = open(filename, aflag, 0666);
    210  1.18      dsl 	if (dependfile == -1)
    211  1.18      dsl 		err(EXIT_FAILURE, "unable to %s to file %s\n",
    212  1.18      dsl 		    aflag & O_TRUNC ? "write" : "append", filename);
    213  1.18      dsl 
    214  1.18      dsl 	for (; *argv != NULL; argv++) {
    215  1.18      dsl 		if (dflag) {
    216  1.18      dsl 			fname = *argv;
    217  1.18      dsl 			fd = open(fname, O_RDONLY, 0);
    218  1.18      dsl 			if (fd == -1) {
    219  1.18      dsl 				if (!qflag)
    220  1.18      dsl 					warn("ignoring %s", fname);
    221  1.18      dsl 				continue;
    222  1.18      dsl 			}
    223  1.18      dsl 		} else {
    224  1.18      dsl 			fd = run_cc(argc, argv, &fname);
    225  1.18      dsl 			/* consume all args... */
    226  1.18      dsl 			argv += argc - 1;
    227  1.18      dsl 		}
    228   1.1     tron 
    229  1.18      dsl 		sz = lseek(fd, 0, SEEK_END);
    230  1.18      dsl 		if (sz == 0) {
    231  1.18      dsl 			close(fd);
    232  1.18      dsl 			continue;
    233   1.1     tron 		}
    234  1.18      dsl 		buf = mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
    235  1.18      dsl 		close(fd);
    236   1.1     tron 
    237  1.18      dsl 		if (buf == MAP_FAILED)
    238  1.20      dsl 			err(EXIT_FAILURE, "unable to mmap file %s", *argv);
    239  1.20      dsl 		lim = buf + sz - 1;
    240  1.18      dsl 
    241  1.18      dsl 		/* Remove leading "./" from filenames */
    242  1.20      dsl 		for (ptr = buf; ptr < lim; ptr++) {
    243  1.20      dsl 			if (ptr[1] != '.' || ptr[2] != '/'
    244  1.20      dsl 			    || !isspace((unsigned char)ptr[0]))
    245  1.18      dsl 				continue;
    246  1.18      dsl 			ptr[1] = ' ';
    247  1.20      dsl 			ptr[2] = ' ';
    248   1.7      cgd 		}
    249   1.1     tron 
    250  1.20      dsl 		for (line = eol = buf; eol <= lim;) {
    251  1.20      dsl 			while (eol <= lim && *eol++ != '\n')
    252  1.20      dsl 				continue;
    253  1.19      dsl 			if (line == eol - 1) {
    254  1.18      dsl 				/* empty line - ignore */
    255  1.19      dsl 				line = eol;
    256  1.18      dsl 				continue;
    257  1.19      dsl 			}
    258  1.18      dsl 			if (eol[-2] == '\\')
    259  1.18      dsl 				/* Assemble continuation lines */
    260  1.18      dsl 				continue;
    261  1.20      dsl 			for (colon = line; *colon != ':'; colon++) {
    262  1.20      dsl 				if (colon >= eol) {
    263  1.20      dsl 					colon = NULL;
    264  1.20      dsl 					break;
    265  1.20      dsl 				}
    266  1.20      dsl 			}
    267  1.18      dsl 			if (colon != NULL && suffixes != NULL) {
    268  1.18      dsl 				/* Find the .o: */
    269  1.18      dsl 				for (suf = colon - 2; ; suf--) {
    270  1.18      dsl 					if (suf <= line) {
    271  1.18      dsl 						colon = NULL;
    272  1.18      dsl 						break;
    273  1.18      dsl 					}
    274  1.18      dsl 					if (isspace((unsigned char)suf[1]))
    275  1.18      dsl 						continue;
    276  1.18      dsl 					if (suf[0] != '.' || suf[1] != 'o')
    277  1.18      dsl 						/* not a file.o: line */
    278  1.18      dsl 						colon = NULL;
    279  1.18      dsl 					break;
    280  1.18      dsl 				}
    281  1.18      dsl 			}
    282  1.18      dsl 			if (colon == NULL) {
    283  1.18      dsl 				/* No dependency - just transcribe line */
    284  1.18      dsl 				write(dependfile, line, eol - line);
    285  1.18      dsl 				line = eol;
    286  1.18      dsl 				continue;
    287  1.18      dsl 			}
    288  1.18      dsl 			if (suffixes != NULL) {
    289  1.18      dsl 				for (s = suffixes; ; s = s1 + 1) {
    290  1.18      dsl 					s1 = strpbrk(s, ", ");
    291  1.18      dsl 					if (s1 == NULL)
    292  1.18      dsl 						s1 = s + strlen(s);
    293  1.18      dsl 					write(dependfile, line, suf - line);
    294  1.18      dsl 					write(dependfile, s, s1 - s);
    295  1.18      dsl 					if (*s1 == 0)
    296  1.18      dsl 						break;
    297  1.18      dsl 					write(dependfile, " ", 1);
    298  1.18      dsl 				}
    299  1.18      dsl 				write(dependfile, colon, eol - colon);
    300  1.18      dsl 			} else
    301  1.18      dsl 				write(dependfile, line, eol - line);
    302  1.18      dsl 
    303  1.18      dsl 			if (oflag) {
    304  1.18      dsl 				write(dependfile, ".OPTIONAL", 9);
    305  1.18      dsl 				write(dependfile, colon, eol - colon);
    306  1.18      dsl 			}
    307  1.19      dsl 			line = eol;
    308  1.18      dsl 		}
    309  1.18      dsl 		munmap(buf, sz);
    310   1.1     tron 	}
    311  1.18      dsl 	close(dependfile);
    312   1.1     tron 
    313   1.7      cgd 	exit(EXIT_SUCCESS);
    314   1.1     tron }
    315