xref: /openbsd/usr.bin/make/dump.c (revision 76d0caae)
1 /* $OpenBSD: dump.c,v 1.12 2020/01/26 12:41:21 espie Exp $ */
2 /*
3  * Copyright (c) 2012 Marc Espie.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
15  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OPENBSD
18  * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 #include <limits.h>
27 #include <stddef.h>
28 #include <stdint.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <ohash.h>
33 #include "defines.h"
34 #include "gnode.h"
35 #include "dump.h"
36 #include "targ.h"
37 #include "var.h"
38 #include "memory.h"
39 #include "suff.h"
40 #include "lst.h"
41 #include "timestamp.h"
42 #include "dir.h"
43 
44 /* since qsort doesn't have user data, this needs to be a global... */
45 static ptrdiff_t cmp_offset;
46 static void targ_dump(bool);
47 
48 static int
49 compare_names(const void *a, const void *b)
50 {
51 	const char **pa = (const char **)a;
52 	const char **pb = (const char **)b;
53 	return strcmp((*pa) + cmp_offset, (*pb) + cmp_offset);
54 }
55 
56 void *
57 sort_ohash_by_name(struct ohash *h)
58 {
59 	cmp_offset = h->info.key_offset;
60 
61 	return sort_ohash(h, compare_names);
62 }
63 
64 void *
65 sort_ohash(struct ohash *h, int (*comparison)(const void *, const void *))
66 {
67 	unsigned int i, j;
68 	void *e;
69 	size_t n = ohash_entries(h);
70 	void **t = ereallocarray(NULL, n+1, sizeof(void *));
71 	cmp_offset = h->info.key_offset;
72 
73 	for (i = 0, e = ohash_first(h, &j); e != NULL; e = ohash_next(h, &j))
74 	    	t[i++] = e;
75 	qsort(t, n, sizeof(void *), comparison);
76 	/* add an extra entry to be able to figure out the end without needing
77 	 * to keep a counter */
78 	t[n] = NULL;
79 	return t;
80 }
81 
82 static void
83 TargPrintName(void *gnp)
84 {
85 	const GNode *gn = gnp;
86 	printf("%s ", gn->name);
87 }
88 
89 static void
90 TargPrintOnlySrc(GNode *gn)
91 {
92 	if (OP_NOP(gn->type) && gn->special == SPECIAL_NONE &&
93 	    !(gn->type & OP_DUMMY)) {
94 	    	if (gn->path != NULL)
95 			printf("#\t%s [%s]\n", gn->name,
96 			    strcmp(gn->path, gn->name) == 0 ? "=" : gn->path);
97 		else
98 			printf("#\t%s\n", gn->name);
99     	}
100 }
101 
102 static void
103 TargPrintNode(GNode *gn, bool full)
104 {
105 	if (OP_NOP(gn->type))
106 		return;
107 	switch(gn->special) {
108 	case SPECIAL_SUFFIXES:
109 	case SPECIAL_PHONY:
110 	case SPECIAL_ORDER:
111 	case SPECIAL_NOTHING:
112 	case SPECIAL_MAIN:
113 	case SPECIAL_IGNORE:
114 		return;
115 	default:
116 		break;
117 	}
118 	if (full) {
119 		printf("# %d unmade prerequisites\n", gn->children_left);
120 		if (! (gn->type & OP_USE)) {
121 			if (!is_out_of_date(gn->mtime)) {
122 				printf("# last modified %s: %s\n",
123 				      time_to_string(&gn->mtime),
124 				      status_to_string(gn));
125 			} else if (gn->built_status != UNKNOWN) {
126 				printf("# non-existent (maybe): %s\n",
127 				    status_to_string(gn));
128 			} else {
129 				printf("# unmade\n");
130 			}
131 		}
132 	}
133 	if (!Lst_IsEmpty(&gn->parents)) {
134 		printf("# parent targets: ");
135 		Lst_Every(&gn->parents, TargPrintName);
136 		fputc('\n', stdout);
137 	}
138 	if (gn->impliedsrc)
139 		printf("# implied prerequisite: %s\n", gn->impliedsrc->name);
140 
141 	printf("%-16s", gn->name);
142 	switch (gn->type & OP_OPMASK) {
143 	case OP_DEPENDS:
144 		printf(": "); break;
145 	case OP_FORCE:
146 		printf("! "); break;
147 	case OP_DOUBLEDEP:
148 		printf(":: "); break;
149 	}
150 	Targ_PrintType(gn->type);
151 	Lst_Every(&gn->children, TargPrintName);
152 	fputc('\n', stdout);
153 	Lst_Every(&gn->commands, Targ_PrintCmd);
154 	printf("\n\n");
155 	if (gn->type & OP_DOUBLEDEP) {
156 		LstNode ln;
157 
158 		for (ln = Lst_First(&gn->cohorts); ln != NULL; ln = Lst_Adv(ln))
159 			TargPrintNode(Lst_Datum(ln), full);
160 	}
161 }
162 
163 static void
164 dump_special(GNode **t, const char *name, int prop)
165 {
166 	unsigned int i;
167 	bool first = true;
168 
169 	for (i = 0; t[i] != NULL; i++)
170 		if (t[i]->type & prop) {
171 			if (first) {
172 				printf("%s:", name);
173 				first = false;
174 			}
175 			printf(" %s", t[i]->name);
176 	    	}
177 	if (!first)
178 		printf("\n\n");
179 }
180 
181 static void
182 targ_dump(bool full)
183 {
184 	GNode **t = sort_ohash_by_name(targets_hash());
185 	unsigned int i;
186 
187 	printf("#   Input graph:\n");
188 	for (i = 0; t[i] != NULL; i++)
189 		TargPrintNode(t[i], full);
190 	printf("\n\n");
191 
192 	dump_special(t, ".PHONY", OP_PHONY);
193 	dump_special(t, ".PRECIOUS", OP_PRECIOUS);
194 	dump_special(t, ".SILENT", OP_SILENT);
195 	dump_special(t, ".IGNORE", OP_IGNORE);
196 	printf("#   Other target names:\n");
197 	for (i = 0; t[i] != NULL; i++)
198 		TargPrintOnlySrc(t[i]);
199 	printf("\n");
200 	free(t);
201 }
202 
203 static bool dumped_once = false;
204 
205 void
206 dump_data(void)
207 {
208 	Var_Dump();
209 	Suff_PrintAll();
210 	targ_dump(false);
211 	dumped_once = true;
212 }
213 
214 void
215 post_mortem(void)
216 {
217 	if (!dumped_once) {
218 		Var_Dump();
219 		Suff_PrintAll();
220 	}
221 	targ_dump(true);
222 }
223