2 * Originally by Linus Torvalds.
3 * Smart CONFIG_* processing by Werner Almesberger, Michael Chastain.
5 * Usage: mkdep file ...
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.
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.
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.
34 #include <sys/fcntl.h>
37 #include <sys/types.h>
41 char __depname
[512] = "\n\t@touch ";
42 #define depname (__depname+9)
47 char buffer
[256-sizeof(int)];
54 /* Current input file */
55 static const char *g_filename
;
58 * This records all the configuration options seen.
59 * In perl this would be a hash, but here it's a long string
60 * of values separated by newlines. This is simple and
63 char * str_config
= NULL
;
72 printf("%s:", depname
);
74 printf(" %s", g_filename
);
79 * Grow the configuration string to a desired length.
80 * Usually the first growth is plenty.
82 void grow_config(int len
)
84 if (str_config
== NULL
) {
87 str_config
= malloc(4096);
88 if (str_config
== NULL
)
89 { perror("malloc"); exit(1); }
92 while (len_config
+ len
> size_config
) {
93 str_config
= realloc(str_config
, size_config
*= 2);
94 if (str_config
== NULL
)
95 { perror("malloc config"); exit(1); }
102 * Lookup a value in the configuration string.
104 int is_defined_config(const char * name
, int len
)
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
))
120 * Add a new value to the configuration string.
122 void define_config(const char * name
, int len
)
124 grow_config(len
+ 1);
126 memcpy(str_config
+len_config
, name
, len
);
128 str_config
[len_config
++] = '\n';
134 * Clear the set of configuration strings.
136 void clear_config(void)
139 define_config("", 0);
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.
148 char * str_precious
= NULL
;
149 int size_precious
= 0;
150 int len_precious
= 0;
155 * Grow the precious string to a desired length.
156 * Usually the first growth is plenty.
158 void grow_precious(int len
)
160 if (str_precious
== NULL
) {
162 size_precious
= 4096;
163 str_precious
= malloc(4096);
164 if (str_precious
== NULL
)
165 { perror("malloc precious"); exit(1); }
168 while (len_precious
+ len
> size_precious
) {
169 str_precious
= realloc(str_precious
, size_precious
*= 2);
170 if (str_precious
== NULL
)
171 { perror("malloc"); exit(1); }
178 * Add a new value to the precious string.
180 void define_precious(const char * filename
)
182 int len
= strlen(filename
);
183 grow_precious(len
+ 4);
184 *(str_precious
+len_precious
++) = '\t';
185 memcpy(str_precious
+len_precious
, filename
, len
);
187 memcpy(str_precious
+len_precious
, " \\\n", 3);
194 * Handle an #include line.
196 void handle_include(int type
, const char * name
, int len
)
198 struct path_struct
*path
= path_array
+type
;
200 if (len
== 14 && !memcmp(name
, "linux/config.h", len
))
203 if (len
>= 7 && !memcmp(name
, "config/", 7))
204 define_config(name
+7, len
-7-2);
206 memcpy(path
->buffer
+path
->len
, name
, len
);
207 path
->buffer
[path
->len
+len
] = '\0';
208 if (access(path
->buffer
, F_OK
) != 0)
212 printf(" \\\n %s", path
->buffer
);
218 * Record the use of a CONFIG_* word.
220 void use_config(const char * name
, int len
)
225 pc
= path_array
[0].buffer
+ path_array
[0].len
;
226 memcpy(pc
, "config/", 7);
229 for (i
= 0; i
< len
; i
++) {
231 if (isupper(c
)) c
= tolower(c
);
232 if (c
== '_') c
= '/';
237 if (is_defined_config(pc
, len
))
240 define_config(pc
, len
);
243 printf(" \\\n $(wildcard %s.h)", path_array
[0].buffer
);
249 * Macros for stunningly fast map-based character access.
250 * __buf is a register which holds the current word of the input.
251 * Thus, there is one memory access per sizeof(unsigned long) characters.
254 #if defined(__alpha__) || defined(__i386__) || defined(__ia64__) || defined(__MIPSEL__) \
260 #define next_byte(x) (x >>= 8)
261 #define current ((unsigned char) __buf)
263 #define next_byte(x) (x <<= 8)
264 #define current (__buf >> 8*(sizeof(unsigned long)-1))
269 if ((unsigned long) next % sizeof(unsigned long) == 0) { \
272 __buf = * (unsigned long *) next; \
278 * State machine macros.
280 #define CASE(c,label) if (current == c) goto label
281 #define NOTCASE(c,label) if (current != c) goto label
284 * Yet another state machine speedup.
286 #define MAX2(a,b) ((a)>(b)?(a):(b))
287 #define MIN2(a,b) ((a)<(b)?(a):(b))
288 #define MAX5(a,b,c,d,e) (MAX2(a,MAX2(b,MAX2(c,MAX2(d,e)))))
289 #define MIN5(a,b,c,d,e) (MIN2(a,MIN2(b,MIN2(c,MIN2(d,e)))))
294 * The state machine looks for (approximately) these Perl regular expressions:
299 * m|#\s*include\s*"(.*?)"|
300 * m|#\s*include\s*<(.*?>"|
301 * m|#\s*(?define|undef)\s*CONFIG_(\w*)|
304 * About 98% of the CPU time is spent here, and most of that is in
305 * the 'start' paragraph. Because the current characters are
306 * in a register, the start loop usually eats 4 or 8 characters
307 * per memory read. The MAX5 and MIN5 tests dispose of most
308 * input characters with 1 or 2 comparisons.
310 void state_machine(const char * map
, const char * end
)
312 const char * next
= map
;
313 const char * map_dot
;
314 unsigned long __buf
= 0;
320 if (current
> MAX5('/','\'','"','#','C')) goto start
;
321 if (current
< MIN5('/','\'','"','#','C')) goto start
;
332 NOTCASE('*', __start
);
335 __slash_star_dot_star
:
336 NOTCASE('*', slash_star_dot_star
);
338 NOTCASE('/', __slash_star_dot_star
);
345 NOTCASE('\\', squote
);
353 NOTCASE('\\', dquote
);
369 GETNEXT
NOTCASE('n', __start
);
370 GETNEXT
NOTCASE('c', __start
);
371 GETNEXT
NOTCASE('l', __start
);
372 GETNEXT
NOTCASE('u', __start
);
373 GETNEXT
NOTCASE('d', __start
);
374 GETNEXT
NOTCASE('e', __start
);
380 CASE(' ', pound_include
);
381 CASE('\t', pound_include
);
383 CASE('"', pound_include_dquote
);
384 CASE('<', pound_include_langle
);
387 /* #\s*include\s*"(.*)" */
388 pound_include_dquote
:
391 NOTCASE('"', pound_include_dquote
);
392 handle_include(1, map_dot
, next
- map_dot
- 1);
395 /* #\s*include\s*<(.*)> */
396 pound_include_langle
:
399 NOTCASE('>', pound_include_langle
);
400 handle_include(0, map_dot
, next
- map_dot
- 1);
405 GETNEXT
NOTCASE('e', __start
);
406 GETNEXT
NOTCASE('f', __start
);
407 GETNEXT
NOTCASE('i', __start
);
408 GETNEXT
NOTCASE('n', __start
);
409 GETNEXT
NOTCASE('e', __start
);
410 goto pound_define_undef
;
414 GETNEXT
NOTCASE('n', __start
);
415 GETNEXT
NOTCASE('d', __start
);
416 GETNEXT
NOTCASE('e', __start
);
417 GETNEXT
NOTCASE('f', __start
);
418 goto pound_define_undef
;
421 * #\s*(define|undef)\s*CONFIG_(\w*)
423 * this does not define the word, because it could be inside another
424 * conditional (#if 0). But I do parse the word so that this instance
425 * does not count as a use. -- mec
429 CASE(' ', pound_define_undef
);
430 CASE('\t', pound_define_undef
);
432 NOTCASE('C', __start
);
433 GETNEXT
NOTCASE('O', __start
);
434 GETNEXT
NOTCASE('N', __start
);
435 GETNEXT
NOTCASE('F', __start
);
436 GETNEXT
NOTCASE('I', __start
);
437 GETNEXT
NOTCASE('G', __start
);
438 GETNEXT
NOTCASE('_', __start
);
441 pound_define_undef_CONFIG_word
:
443 if (isalnum(current
) || current
== '_')
444 goto pound_define_undef_CONFIG_word
;
449 if (next
>= map
+2 && (isalnum(next
[-2]) || next
[-2] == '_'))
451 GETNEXT
NOTCASE('O', __start
);
452 GETNEXT
NOTCASE('N', __start
);
453 GETNEXT
NOTCASE('F', __start
);
454 GETNEXT
NOTCASE('I', __start
);
455 GETNEXT
NOTCASE('G', __start
);
456 GETNEXT
NOTCASE('_', __start
);
461 if (isalnum(current
) || current
== '_')
462 goto cee_CONFIG_word
;
463 use_config(map_dot
, next
- map_dot
- 1);
471 * Generate dependencies for one file.
473 void do_depend(const char * filename
, const char * command
)
476 int pagesizem1
= getpagesize()-1;
481 fd
= open(filename
, O_RDONLY
);
488 if (st
.st_size
== 0) {
489 fprintf(stderr
,"%s is empty\n",filename
);
494 mapsize
= st
.st_size
;
495 mapsize
= (mapsize
+pagesizem1
) & ~pagesizem1
;
496 map
= mmap(NULL
, mapsize
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
497 if ((long) map
== -1) {
498 perror("mkdep: mmap");
502 if ((unsigned long) map
% sizeof(unsigned long) != 0)
504 fprintf(stderr
, "do_depend: map not aligned\n");
510 state_machine(map
, map
+st
.st_size
);
514 define_precious(filename
);
517 munmap(map
, mapsize
);
524 * Generate dependencies for all files.
526 int main(int argc
, char **argv
)
531 hpath
= getenv("HPATH");
533 fputs("mkdep: HPATH not set in environment. "
534 "Don't bypass the top level Makefile.\n", stderr
);
538 memcpy(path_array
[0].buffer
, hpath
, len
);
539 if (len
&& hpath
[len
-1] != '/')
540 path_array
[0].buffer
[len
++] = '/';
541 path_array
[0].buffer
[len
] = '\0';
542 path_array
[0].len
= len
;
545 const char * filename
= *++argv
;
546 const char * command
= __depname
;
548 len
= strlen(filename
);
549 memcpy(depname
, filename
, len
+1);
550 if (len
> 2 && filename
[len
-2] == '.') {
551 if (filename
[len
-1] == 'c' || filename
[len
-1] == 'S') {
552 depname
[len
-1] = 'o';
553 g_filename
= filename
;
557 do_depend(filename
, command
);
560 *(str_precious
+len_precious
) = '\0';
561 printf(".PRECIOUS:%s\n", str_precious
);