1 /*
2 * Originally by Linus Torvalds.
3 * Smart CONFIG_* processing by Werner Almesberger, Michael Chastain.
4 *
5 * Usage: mkdep cflags -- file ...
6 *
7 * Read source files and output makefile dependency lines for them.
8 * I make simple dependency lines for #include <*.h> and #include "*.h".
9 * I also find instances of CONFIG_FOO and generate dependencies
10 * like include/config/foo.h.
11 *
12 * 1 August 1999, Michael Elizabeth Chastain, <mec@shout.net>
13 * - Keith Owens reported a bug in smart config processing. There used
14 * to be an optimization for "#define CONFIG_FOO ... #ifdef CONFIG_FOO",
15 * so that the file would not depend on CONFIG_FOO because the file defines
16 * this symbol itself. But this optimization is bogus! Consider this code:
17 * "#if 0 \n #define CONFIG_FOO \n #endif ... #ifdef CONFIG_FOO". Here
18 * the definition is inactivated, but I still used it. It turns out this
19 * actually happens a few times in the kernel source. The simple way to
20 * fix this problem is to remove this particular optimization.
21 *
22 * 2.3.99-pre1, Andrew Morton <andrewm@uow.edu.au>
23 * - Changed so that 'filename.o' depends upon 'filename.[cS]'. This is so that
24 * missing source files are noticed, rather than silently ignored.
25 *
26 * 2.4.2-pre3, Keith Owens <kaos@ocs.com.au>
27 * - Accept cflags followed by '--' followed by filenames. mkdep extracts -I
28 * options from cflags and looks in the specified directories as well as the
29 * defaults. Only -I is supported, no attempt is made to handle -idirafter,
30 * -isystem, -I- etc.
31 */
32
33 #include <ctype.h>
34 #include <fcntl.h>
35 #include <limits.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40
41 #include <sys/fcntl.h>
42 #include <sys/mman.h>
43 #include <sys/stat.h>
44 #include <sys/types.h>
45
46
47
48 char __depname[512] = "\n\t@touch ";
49 #define depname (__depname+9)
50 int hasdep;
51
52 struct path_struct {
53 int len;
54 char *buffer;
55 };
56 struct path_struct *path_array;
57 int paths;
58
59
60 /* Current input file */
61 static const char *g_filename;
62
63 /*
64 * This records all the configuration options seen.
65 * In perl this would be a hash, but here it's a long string
66 * of values separated by newlines. This is simple and
67 * extremely fast.
68 */
69 char * str_config = NULL;
70 int size_config = 0;
71 int len_config = 0;
72
73 static void
do_depname(void)74 do_depname(void)
75 {
76 if (!hasdep) {
77 hasdep = 1;
78 printf("%s:", depname);
79 if (g_filename)
80 printf(" %s", g_filename);
81 }
82 }
83
84 /*
85 * Grow the configuration string to a desired length.
86 * Usually the first growth is plenty.
87 */
grow_config(int len)88 void grow_config(int len)
89 {
90 while (len_config + len > size_config) {
91 if (size_config == 0)
92 size_config = 2048;
93 str_config = realloc(str_config, size_config *= 2);
94 if (str_config == NULL)
95 { perror("malloc config"); exit(1); }
96 }
97 }
98
99
100
101 /*
102 * Lookup a value in the configuration string.
103 */
is_defined_config(const char * name,int len)104 int is_defined_config(const char * name, int len)
105 {
106 const char * pconfig;
107 const char * plast = str_config + len_config - len;
108 for ( pconfig = str_config + 1; pconfig < plast; pconfig++ ) {
109 if (pconfig[ -1] == '\n'
110 && pconfig[len] == '\n'
111 && !memcmp(pconfig, name, len))
112 return 1;
113 }
114 return 0;
115 }
116
117
118
119 /*
120 * Add a new value to the configuration string.
121 */
define_config(const char * name,int len)122 void define_config(const char * name, int len)
123 {
124 grow_config(len + 1);
125
126 memcpy(str_config+len_config, name, len);
127 len_config += len;
128 str_config[len_config++] = '\n';
129 }
130
131
132
133 /*
134 * Clear the set of configuration strings.
135 */
clear_config(void)136 void clear_config(void)
137 {
138 len_config = 0;
139 define_config("", 0);
140 }
141
142
143
144 /*
145 * This records all the precious .h filenames. No need for a hash,
146 * it's a long string of values enclosed in tab and newline.
147 */
148 char * str_precious = NULL;
149 int size_precious = 0;
150 int len_precious = 0;
151
152
153
154 /*
155 * Grow the precious string to a desired length.
156 * Usually the first growth is plenty.
157 */
grow_precious(int len)158 void grow_precious(int len)
159 {
160 while (len_precious + len > size_precious) {
161 if (size_precious == 0)
162 size_precious = 2048;
163 str_precious = realloc(str_precious, size_precious *= 2);
164 if (str_precious == NULL)
165 { perror("malloc"); exit(1); }
166 }
167 }
168
169
170
171 /*
172 * Add a new value to the precious string.
173 */
define_precious(const char * filename)174 void define_precious(const char * filename)
175 {
176 int len = strlen(filename);
177 grow_precious(len + 4);
178 *(str_precious+len_precious++) = '\t';
179 memcpy(str_precious+len_precious, filename, len);
180 len_precious += len;
181 memcpy(str_precious+len_precious, " \\\n", 3);
182 len_precious += 3;
183 }
184
185
186
187 /*
188 * Handle an #include line.
189 */
handle_include(int start,const char * name,int len)190 void handle_include(int start, const char * name, int len)
191 {
192 struct path_struct *path;
193 int i;
194
195 if (len == 14 && !memcmp(name, "linux/config.h", len))
196 return;
197
198 if (len >= 7 && !memcmp(name, "config/", 7))
199 define_config(name+7, len-7-2);
200
201 for (i = start, path = path_array+start; i < paths; ++i, ++path) {
202 memcpy(path->buffer+path->len, name, len);
203 path->buffer[path->len+len] = '\0';
204 if (access(path->buffer, F_OK) == 0) {
205 do_depname();
206 printf(" \\\n %s", path->buffer);
207 return;
208 }
209 }
210
211 }
212
213
214
215 /*
216 * Add a path to the list of include paths.
217 */
add_path(const char * name)218 void add_path(const char * name)
219 {
220 struct path_struct *path;
221 char resolved_path[PATH_MAX+1];
222 const char *name2;
223
224 if (strcmp(name, ".")) {
225 name2 = realpath(name, resolved_path);
226 if (!name2) {
227 fprintf(stderr, "realpath(%s) failed, %m\n", name);
228 exit(1);
229 }
230 }
231 else {
232 name2 = "";
233 }
234
235 path_array = realloc(path_array, (++paths)*sizeof(*path_array));
236 if (!path_array) {
237 fprintf(stderr, "cannot expand path_arry\n");
238 exit(1);
239 }
240
241 path = path_array+paths-1;
242 path->len = strlen(name2);
243 path->buffer = malloc(path->len+1+256+1);
244 if (!path->buffer) {
245 fprintf(stderr, "cannot allocate path buffer\n");
246 exit(1);
247 }
248 strcpy(path->buffer, name2);
249 if (path->len && *(path->buffer+path->len-1) != '/') {
250 *(path->buffer+path->len) = '/';
251 *(path->buffer+(++(path->len))) = '\0';
252 }
253 }
254
255
256
257 /*
258 * Record the use of a CONFIG_* word.
259 */
use_config(const char * name,int len)260 void use_config(const char * name, int len)
261 {
262 char *pc;
263 int i;
264
265 pc = path_array[paths-1].buffer + path_array[paths-1].len;
266 memcpy(pc, "config/", 7);
267 pc += 7;
268
269 for (i = 0; i < len; i++) {
270 char c = name[i];
271 if (isupper((int)c)) c = tolower((int)c);
272 if (c == '_') c = '/';
273 pc[i] = c;
274 }
275 pc[len] = '\0';
276
277 if (is_defined_config(pc, len))
278 return;
279
280 define_config(pc, len);
281
282 do_depname();
283 printf(" \\\n $(wildcard %s.h)", path_array[paths-1].buffer);
284 }
285
286
287
288 /*
289 * Macros for stunningly fast map-based character access.
290 * __buf is a register which holds the current word of the input.
291 * Thus, there is one memory access per sizeof(unsigned long) characters.
292 */
293
294 #if defined(__alpha__) || defined(__i386__) || defined(__ia64__) || defined(__x86_64__) || defined(__MIPSEL__) \
295 || defined(__arm__)
296 #define LE_MACHINE
297 #endif
298
299 #ifdef LE_MACHINE
300 #define next_byte(x) (x >>= 8)
301 #define current ((unsigned char) __buf)
302 #else
303 #define next_byte(x) (x <<= 8)
304 #define current (__buf >> 8*(sizeof(unsigned long)-1))
305 #endif
306
307 #define GETNEXT { \
308 next_byte(__buf); \
309 if ((unsigned long) next % sizeof(unsigned long) == 0) { \
310 if (next >= end) \
311 break; \
312 __buf = * (unsigned long *) next; \
313 } \
314 next++; \
315 }
316
317 /*
318 * State machine macros.
319 */
320 #define CASE(c,label) if (current == c) goto label
321 #define NOTCASE(c,label) if (current != c) goto label
322
323 /*
324 * Yet another state machine speedup.
325 */
326 #define MAX2(a,b) ((a)>(b)?(a):(b))
327 #define MIN2(a,b) ((a)<(b)?(a):(b))
328 #define MAX5(a,b,c,d,e) (MAX2(a,MAX2(b,MAX2(c,MAX2(d,e)))))
329 #define MIN5(a,b,c,d,e) (MIN2(a,MIN2(b,MIN2(c,MIN2(d,e)))))
330
331
332
333 /*
334 * The state machine looks for (approximately) these Perl regular expressions:
335 *
336 * m|\/\*.*?\*\/|
337 * m|\/\/.*|
338 * m|'.*?'|
339 * m|".*?"|
340 * m|#\s*include\s*"(.*?)"|
341 * m|#\s*include\s*<(.*?>"|
342 * m|#\s*(?define|undef)\s*CONFIG_(\w*)|
343 * m|(?!\w)CONFIG_|
344 *
345 * About 98% of the CPU time is spent here, and most of that is in
346 * the 'start' paragraph. Because the current characters are
347 * in a register, the start loop usually eats 4 or 8 characters
348 * per memory read. The MAX5 and MIN5 tests dispose of most
349 * input characters with 1 or 2 comparisons.
350 */
state_machine(const char * map,const char * end)351 void state_machine(const char * map, const char * end)
352 {
353 const char * next = map;
354 const char * map_dot;
355 unsigned long __buf = 0;
356
357 for (;;) {
358 start:
359 GETNEXT
360 __start:
361 if (current > MAX5('/','\'','"','#','C')) goto start;
362 if (current < MIN5('/','\'','"','#','C')) goto start;
363 CASE('/', slash);
364 CASE('\'', squote);
365 CASE('"', dquote);
366 CASE('#', pound);
367 CASE('C', cee);
368 goto start;
369
370 /* // */
371 slash_slash:
372 GETNEXT
373 CASE('\n', start);
374 NOTCASE('\\', slash_slash);
375 GETNEXT
376 goto slash_slash;
377
378 /* / */
379 slash:
380 GETNEXT
381 CASE('/', slash_slash);
382 NOTCASE('*', __start);
383 slash_star_dot_star:
384 GETNEXT
385 __slash_star_dot_star:
386 NOTCASE('*', slash_star_dot_star);
387 GETNEXT
388 NOTCASE('/', __slash_star_dot_star);
389 goto start;
390
391 /* '.*?' */
392 squote:
393 GETNEXT
394 CASE('\'', start);
395 NOTCASE('\\', squote);
396 GETNEXT
397 goto squote;
398
399 /* ".*?" */
400 dquote:
401 GETNEXT
402 CASE('"', start);
403 NOTCASE('\\', dquote);
404 GETNEXT
405 goto dquote;
406
407 /* #\s* */
408 pound:
409 GETNEXT
410 CASE(' ', pound);
411 CASE('\t', pound);
412 CASE('i', pound_i);
413 CASE('d', pound_d);
414 CASE('u', pound_u);
415 goto __start;
416
417 /* #\s*i */
418 pound_i:
419 GETNEXT NOTCASE('n', __start);
420 GETNEXT NOTCASE('c', __start);
421 GETNEXT NOTCASE('l', __start);
422 GETNEXT NOTCASE('u', __start);
423 GETNEXT NOTCASE('d', __start);
424 GETNEXT NOTCASE('e', __start);
425 goto pound_include;
426
427 /* #\s*include\s* */
428 pound_include:
429 GETNEXT
430 CASE(' ', pound_include);
431 CASE('\t', pound_include);
432 map_dot = next;
433 CASE('"', pound_include_dquote);
434 CASE('<', pound_include_langle);
435 goto __start;
436
437 /* #\s*include\s*"(.*)" */
438 pound_include_dquote:
439 GETNEXT
440 CASE('\n', start);
441 NOTCASE('"', pound_include_dquote);
442 handle_include(0, map_dot, next - map_dot - 1);
443 goto start;
444
445 /* #\s*include\s*<(.*)> */
446 pound_include_langle:
447 GETNEXT
448 CASE('\n', start);
449 NOTCASE('>', pound_include_langle);
450 handle_include(1, map_dot, next - map_dot - 1);
451 goto start;
452
453 /* #\s*d */
454 pound_d:
455 GETNEXT NOTCASE('e', __start);
456 GETNEXT NOTCASE('f', __start);
457 GETNEXT NOTCASE('i', __start);
458 GETNEXT NOTCASE('n', __start);
459 GETNEXT NOTCASE('e', __start);
460 goto pound_define_undef;
461
462 /* #\s*u */
463 pound_u:
464 GETNEXT NOTCASE('n', __start);
465 GETNEXT NOTCASE('d', __start);
466 GETNEXT NOTCASE('e', __start);
467 GETNEXT NOTCASE('f', __start);
468 goto pound_define_undef;
469
470 /*
471 * #\s*(define|undef)\s*CONFIG_(\w*)
472 *
473 * this does not define the word, because it could be inside another
474 * conditional (#if 0). But I do parse the word so that this instance
475 * does not count as a use. -- mec
476 */
477 pound_define_undef:
478 GETNEXT
479 CASE(' ', pound_define_undef);
480 CASE('\t', pound_define_undef);
481
482 NOTCASE('C', __start);
483 GETNEXT NOTCASE('O', __start);
484 GETNEXT NOTCASE('N', __start);
485 GETNEXT NOTCASE('F', __start);
486 GETNEXT NOTCASE('I', __start);
487 GETNEXT NOTCASE('G', __start);
488 GETNEXT NOTCASE('_', __start);
489
490 map_dot = next;
491 pound_define_undef_CONFIG_word:
492 GETNEXT
493 if (isalnum(current) || current == '_')
494 goto pound_define_undef_CONFIG_word;
495 goto __start;
496
497 /* \<CONFIG_(\w*) */
498 cee:
499 if (next >= map+2 && (isalnum((int)next[-2]) || next[-2] == '_'))
500 goto start;
501 GETNEXT NOTCASE('O', __start);
502 GETNEXT NOTCASE('N', __start);
503 GETNEXT NOTCASE('F', __start);
504 GETNEXT NOTCASE('I', __start);
505 GETNEXT NOTCASE('G', __start);
506 GETNEXT NOTCASE('_', __start);
507
508 map_dot = next;
509 cee_CONFIG_word:
510 GETNEXT
511 if (isalnum(current) || current == '_')
512 goto cee_CONFIG_word;
513 use_config(map_dot, next - map_dot - 1);
514 goto __start;
515 }
516 }
517
518
519
520 /*
521 * Generate dependencies for one file.
522 */
do_depend(const char * filename,const char * command)523 void do_depend(const char * filename, const char * command)
524 {
525 int mapsize;
526 int pagesizem1 = getpagesize()-1;
527 int fd;
528 struct stat st;
529 char * map;
530
531 fd = open(filename, O_RDONLY);
532 if (fd < 0) {
533 perror(filename);
534 return;
535 }
536
537 fstat(fd, &st);
538 if (st.st_size == 0) {
539 fprintf(stderr,"%s is empty\n",filename);
540 close(fd);
541 return;
542 }
543
544 mapsize = st.st_size;
545 mapsize = (mapsize+pagesizem1) & ~pagesizem1;
546 map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
547 if ((long) map == -1) {
548 perror("mkdep: mmap");
549 close(fd);
550 return;
551 }
552 if ((unsigned long) map % sizeof(unsigned long) != 0)
553 {
554 fprintf(stderr, "do_depend: map not aligned\n");
555 exit(1);
556 }
557
558 hasdep = 0;
559 clear_config();
560 state_machine(map, map+st.st_size);
561 if (hasdep) {
562 puts(command);
563 if (*command)
564 define_precious(filename);
565 }
566
567 munmap(map, mapsize);
568 close(fd);
569 }
570
571
572
573 /*
574 * Generate dependencies for all files.
575 */
main(int argc,char ** argv)576 int main(int argc, char **argv)
577 {
578 int len;
579 const char *hpath;
580
581 hpath = getenv("HPATH");
582 if (!hpath) {
583 fputs("mkdep: HPATH not set in environment. "
584 "Don't bypass the top level Makefile.\n", stderr);
585 return 1;
586 }
587
588 add_path("."); /* for #include "..." */
589
590 while (++argv, --argc > 0) {
591 if (strncmp(*argv, "-I", 2) == 0) {
592 if (*((*argv)+2)) {
593 add_path((*argv)+2);
594 }
595 else {
596 ++argv;
597 --argc;
598 add_path(*argv);
599 }
600 }
601 else if (strcmp(*argv, "--") == 0) {
602 break;
603 }
604 }
605
606 add_path(hpath); /* must be last entry, for config files */
607
608 while (--argc > 0) {
609 const char * filename = *++argv;
610 const char * command = __depname;
611 g_filename = 0;
612 len = strlen(filename);
613 memcpy(depname, filename, len+1);
614 if (len > 2 && filename[len-2] == '.') {
615 if (filename[len-1] == 'c' || filename[len-1] == 'S') {
616 depname[len-1] = 'o';
617 g_filename = filename;
618 command = "";
619 }
620 }
621 do_depend(filename, command);
622 }
623 if (len_precious) {
624 *(str_precious+len_precious) = '\0';
625 printf(".PRECIOUS:%s\n", str_precious);
626 }
627 return 0;
628 }
629