source: MondoRescue/branches/3.3/mindi-busybox/scripts/basic/fixdep.c@ 3901

Last change on this file since 3901 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

  • Property svn:eol-style set to native
File size: 9.7 KB
Line 
1/*
2 * "Optimize" a list of dependencies as spit out by gcc -MD
3 * for the kernel build
4 * ===========================================================================
5 *
6 * Author Kai Germaschewski
7 * Copyright 2002 by Kai Germaschewski <kai.germaschewski@gmx.de>
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
11 *
12 *
13 * Introduction:
14 *
15 * gcc produces a very nice and correct list of dependencies which
16 * tells make when to remake a file.
17 *
18 * To use this list as-is however has the drawback that virtually
19 * every file in the kernel includes <linux/config.h> which then again
20 * includes <linux/autoconf.h>
21 *
22 * If the user re-runs make *config, linux/autoconf.h will be
23 * regenerated. make notices that and will rebuild every file which
24 * includes autoconf.h, i.e. basically all files. This is extremely
25 * annoying if the user just changed CONFIG_HIS_DRIVER from n to m.
26 *
27 * So we play the same trick that "mkdep" played before. We replace
28 * the dependency on linux/autoconf.h by a dependency on every config
29 * option which is mentioned in any of the listed prequisites.
30 *
31 * To be exact, split-include populates a tree in include/config/,
32 * e.g. include/config/his/driver.h, which contains the #define/#undef
33 * for the CONFIG_HIS_DRIVER option.
34 *
35 * So if the user changes his CONFIG_HIS_DRIVER option, only the objects
36 * which depend on "include/linux/config/his/driver.h" will be rebuilt,
37 * so most likely only his driver ;-)
38 *
39 * The idea above dates, by the way, back to Michael E Chastain, AFAIK.
40 *
41 * So to get dependencies right, there are two issues:
42 * o if any of the files the compiler read changed, we need to rebuild
43 * o if the command line given to the compile the file changed, we
44 * better rebuild as well.
45 *
46 * The former is handled by using the -MD output, the later by saving
47 * the command line used to compile the old object and comparing it
48 * to the one we would now use.
49 *
50 * Again, also this idea is pretty old and has been discussed on
51 * kbuild-devel a long time ago. I don't have a sensibly working
52 * internet connection right now, so I rather don't mention names
53 * without double checking.
54 *
55 * This code here has been based partially based on mkdep.c, which
56 * says the following about its history:
57 *
58 * Copyright abandoned, Michael Chastain, <mailto:mec@shout.net>.
59 * This is a C version of syncdep.pl by Werner Almesberger.
60 *
61 *
62 * It is invoked as
63 *
64 * fixdep <depfile> <target> <cmdline>
65 *
66 * and will read the dependency file <depfile>
67 *
68 * The transformed dependency snipped is written to stdout.
69 *
70 * It first generates a line
71 *
72 * cmd_<target> = <cmdline>
73 *
74 * and then basically copies the .<target>.d file to stdout, in the
75 * process filtering out the dependency on linux/autoconf.h and adding
76 * dependencies on include/config/my/option.h for every
77 * CONFIG_MY_OPTION encountered in any of the prequisites.
78 *
79 * It will also filter out all the dependencies on *.ver. We need
80 * to make sure that the generated version checksum are globally up
81 * to date before even starting the recursive build, so it's too late
82 * at this point anyway.
83 *
84 * The algorithm to grep for "CONFIG_..." is bit unusual, but should
85 * be fast ;-) We don't even try to really parse the header files, but
86 * merely grep, i.e. if CONFIG_FOO is mentioned in a comment, it will
87 * be picked up as well. It's not a problem with respect to
88 * correctness, since that can only give too many dependencies, thus
89 * we cannot miss a rebuild. Since people tend to not mention totally
90 * unrelated CONFIG_ options all over the place, it's not an
91 * efficiency problem either.
92 *
93 * (Note: it'd be easy to port over the complete mkdep state machine,
94 * but I don't think the added complexity is worth it)
95 */
96/*
97 * Note 2: if somebody writes HELLO_CONFIG_BOOM in a file, it will depend onto
98 * CONFIG_BOOM. This could seem a bug (not too hard to fix), but please do not
99 * fix it! Some UserModeLinux files (look at arch/um/) call CONFIG_BOOM as
100 * UML_CONFIG_BOOM, to avoid conflicts with /usr/include/linux/autoconf.h,
101 * through arch/um/include/uml-config.h; this fixdep "bug" makes sure that
102 * those files will have correct dependencies.
103 */
104
105#include <sys/types.h>
106#include <sys/stat.h>
107#include <sys/mman.h>
108#include <unistd.h>
109#include <fcntl.h>
110#include <string.h>
111#include <stdlib.h>
112#include <stdio.h>
113#include <limits.h>
114#include <ctype.h>
115#include <arpa/inet.h>
116//bbox disabled: #include <alloca.h>
117
118/* bbox: not needed
119#define INT_CONF ntohl(0x434f4e46)
120#define INT_ONFI ntohl(0x4f4e4649)
121#define INT_NFIG ntohl(0x4e464947)
122#define INT_FIG_ ntohl(0x4649475f)
123*/
124
125char *target;
126char *depfile;
127char *cmdline;
128
129void usage(void)
130
131{
132 fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n");
133 exit(1);
134}
135
136/*
137 * Print out the commandline prefixed with cmd_<target filename> :=
138 */
139void print_cmdline(void)
140{
141 printf("cmd_%s := %s\n\n", target, cmdline);
142}
143
144char * str_config = NULL;
145int size_config = 0;
146int len_config = 0;
147
148/*
149 * Grow the configuration string to a desired length.
150 * Usually the first growth is plenty.
151 */
152void grow_config(int len)
153{
154 while (len_config + len > size_config) {
155 if (size_config == 0)
156 size_config = 2048;
157 str_config = realloc(str_config, size_config *= 2);
158 if (str_config == NULL)
159 { perror("fixdep:malloc"); exit(1); }
160 }
161}
162
163
164
165/*
166 * Lookup a value in the configuration string.
167 */
168int is_defined_config(const char * name, int len)
169{
170 const char * pconfig;
171 const char * plast = str_config + len_config - len;
172 for ( pconfig = str_config + 1; pconfig < plast; pconfig++ ) {
173 if (pconfig[ -1] == '\n'
174 && pconfig[len] == '\n'
175 && !memcmp(pconfig, name, len))
176 return 1;
177 }
178 return 0;
179}
180
181/*
182 * Add a new value to the configuration string.
183 */
184void define_config(const char * name, int len)
185{
186 grow_config(len + 1);
187
188 memcpy(str_config+len_config, name, len);
189 len_config += len;
190 str_config[len_config++] = '\n';
191}
192
193/*
194 * Clear the set of configuration strings.
195 */
196void clear_config(void)
197{
198 len_config = 0;
199 define_config("", 0);
200}
201
202/*
203 * Record the use of a CONFIG_* word.
204 */
205void use_config(char *m, int slen)
206{
207 char *s = alloca(slen+1);
208 char *p;
209
210 if (is_defined_config(m, slen))
211 return;
212
213 define_config(m, slen);
214
215 memcpy(s, m, slen); s[slen] = 0;
216
217 for (p = s; p < s + slen; p++) {
218 if (*p == '_')
219 *p = '/';
220 else
221 *p = tolower((int)*p);
222 }
223 printf(" $(wildcard include/config/%s.h) \\\n", s);
224}
225
226void parse_config_file(char *map, size_t len)
227{
228 /* modified for bbox */
229 char *end_3 = map + len - 3; /* 3 == length of "IF_" */
230 char *end_7 = map + len - 7;
231 char *p = map;
232 char *q;
233 int off;
234
235 for (; p <= end_3; p++) {
236 /* Find next identifier's beginning */
237 if (!(isalnum(*p) || *p == '_'))
238 continue;
239
240 /* Check it */
241 if (p < end_7 && p[6] == '_') {
242 if (!memcmp(p, "CONFIG", 6)) goto conf7;
243 if (!memcmp(p, "ENABLE", 6)) goto conf7;
244 if (!memcmp(p, "IF_NOT", 6)) goto conf7;
245 }
246 /* we have at least 3 chars because of p <= end_3 */
247 /*if (!memcmp(p, "IF_", 3)) ...*/
248 if (p[0] == 'I' && p[1] == 'F' && p[2] == '_') {
249 off = 3;
250 goto conf;
251 }
252
253 /* This identifier is not interesting, skip it */
254 while (p <= end_3 && (isalnum(*p) || *p == '_'))
255 p++;
256 continue;
257
258 conf7: off = 7;
259 conf:
260 p += off;
261 for (q = p; q < end_3+3; q++) {
262 if (!(isalnum(*q) || *q == '_'))
263 break;
264 }
265 if (q != p) {
266 use_config(p, q-p);
267 }
268 }
269}
270
271/* test is s ends in sub */
272int strrcmp(char *s, char *sub)
273{
274 int slen = strlen(s);
275 int sublen = strlen(sub);
276
277 if (sublen > slen)
278 return 1;
279
280 return memcmp(s + slen - sublen, sub, sublen);
281}
282
283void do_config_file(char *filename)
284{
285 struct stat st;
286 int fd;
287 void *map;
288
289 fd = open(filename, O_RDONLY);
290 if (fd < 0) {
291 fprintf(stderr, "fixdep: ");
292 perror(filename);
293 exit(2);
294 }
295 fstat(fd, &st);
296 if (st.st_size == 0) {
297 close(fd);
298 return;
299 }
300 map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
301 if ((long) map == -1) {
302 perror("fixdep: mmap");
303 close(fd);
304 return;
305 }
306
307 parse_config_file(map, st.st_size);
308
309 munmap(map, st.st_size);
310
311 close(fd);
312}
313
314void parse_dep_file(void *map, size_t len)
315{
316 char *m = map;
317 char *end = m + len;
318 char *p;
319 char *s = alloca(len);
320
321 p = memchr(m, ':', len);
322 if (!p) {
323 fprintf(stderr, "fixdep: parse error\n");
324 exit(1);
325 }
326 memcpy(s, m, p-m); s[p-m] = 0;
327 printf("deps_%s := \\\n", target);
328 m = p+1;
329
330 clear_config();
331
332 while (m < end) {
333 while (m < end && (*m == ' ' || *m == '\\' || *m == '\n' || *m == '\r'))
334 m++;
335 p = m;
336 while (p < end && *p != ' ') p++;
337 if (p == end) {
338 do p--; while (!isalnum(*p));
339 p++;
340 }
341 memcpy(s, m, p-m); s[p-m] = 0;
342 if (strrcmp(s, "include/autoconf.h") &&
343 strrcmp(s, "arch/um/include/uml-config.h") &&
344 strrcmp(s, ".ver")) {
345 printf(" %s \\\n", s);
346 do_config_file(s);
347 }
348 m = p + 1;
349 }
350 printf("\n%s: $(deps_%s)\n\n", target, target);
351 printf("$(deps_%s):\n", target);
352}
353
354void print_deps(void)
355{
356 struct stat st;
357 int fd;
358 void *map;
359
360 fd = open(depfile, O_RDONLY);
361 if (fd < 0) {
362 fprintf(stderr, "fixdep: ");
363 perror(depfile);
364 exit(2);
365 }
366 fstat(fd, &st);
367 if (st.st_size == 0) {
368 fprintf(stderr,"fixdep: %s is empty\n",depfile);
369 close(fd);
370 return;
371 }
372 map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
373 if ((long) map == -1) {
374 perror("fixdep: mmap");
375 close(fd);
376 return;
377 }
378
379 parse_dep_file(map, st.st_size);
380
381 munmap(map, st.st_size);
382
383 close(fd);
384}
385
386void traps(void)
387{
388/* bbox: not needed
389 static char test[] __attribute__((aligned(sizeof(int)))) = "CONF";
390
391 if (*(int *)test != INT_CONF) {
392 fprintf(stderr, "fixdep: sizeof(int) != 4 or wrong endianess? %#x\n",
393 *(int *)test);
394 exit(2);
395 }
396*/
397}
398
399int main(int argc, char **argv)
400{
401 traps();
402
403 if (argc != 4)
404 usage();
405
406 depfile = argv[1];
407 target = argv[2];
408 cmdline = argv[3];
409
410 print_cmdline();
411 print_deps();
412
413 return 0;
414}
Note: See TracBrowser for help on using the repository browser.