1 |
|
|
/* $OpenBSD: dump.c,v 1.9 2016/10/21 16:12:38 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 & SPECIAL_MASK)) { |
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->unmade); |
120 |
|
|
if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) { |
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 |
|
|
} |