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.
19 #include <sys/fcntl.h>
22 #include <sys/types.h>
26 char __depname
[512] = "\n\t@touch ";
27 #define depname (__depname+9)
32 char buffer
[256-sizeof(int)];
41 * This records all the configuration options seen.
42 * In perl this would be a hash, but here it's a long string
43 * of values separated by newlines. This is simple and
46 char * str_config
= NULL
;
53 * Grow the configuration string to a desired length.
54 * Usually the first growth is plenty.
56 void grow_config(int len
)
58 if (str_config
== NULL
) {
61 str_config
= malloc(4096);
62 if (str_config
== NULL
)
63 { perror("malloc"); exit(1); }
66 while (len_config
+ len
> size_config
) {
67 str_config
= realloc(str_config
, size_config
*= 2);
68 if (str_config
== NULL
)
69 { perror("malloc"); exit(1); }
76 * Lookup a value in the configuration string.
78 int is_defined_config(const char * name
, int len
)
81 const char * plast
= str_config
+ len_config
- len
;
82 for ( pconfig
= str_config
+ 1; pconfig
< plast
; pconfig
++ ) {
83 if (pconfig
[ -1] == '\n'
84 && pconfig
[len
] == '\n'
85 && !memcmp(pconfig
, name
, len
))
94 * Add a new value to the configuration string.
96 void define_config(int convert
, const char * name
, int len
)
100 memcpy(str_config
+len_config
, name
, len
);
104 for (i
= 0; i
< len
; i
++) {
105 char c
= str_config
[len_config
+i
];
106 if (isupper(c
)) c
= tolower(c
);
107 if (c
== '_') c
= '/';
108 str_config
[len_config
+i
] = c
;
113 str_config
[len_config
++] = '\n';
119 * Clear the set of configuration strings.
121 void clear_config(void)
124 define_config(0, "", 0);
130 * Handle an #include line.
132 void handle_include(int type
, const char * name
, int len
)
134 struct path_struct
*path
= path_array
+type
;
136 if (len
== 14 && !memcmp(name
, "linux/config.h", len
))
139 if (len
>= 7 && !memcmp(name
, "config/", 7))
140 define_config(0, name
+7, len
-7-2);
142 memcpy(path
->buffer
+path
->len
, name
, len
);
143 path
->buffer
[path
->len
+len
] = '\0';
144 if (access(path
->buffer
, F_OK
) != 0)
149 printf("%s:", depname
);
151 printf(" \\\n %s", path
->buffer
);
157 * Record the use of a CONFIG_* word.
159 void use_config(const char * name
, int len
)
164 pc
= path_array
[0].buffer
+ path_array
[0].len
;
165 memcpy(pc
, "config/", 7);
168 for (i
= 0; i
< len
; i
++) {
170 if (isupper(c
)) c
= tolower(c
);
171 if (c
== '_') c
= '/';
176 if (is_defined_config(pc
, len
))
179 define_config(0, pc
, len
);
183 printf("%s: ", depname
);
185 printf(" \\\n $(wildcard %s.h)", path_array
[0].buffer
);
191 * Macros for stunningly fast map-based character access.
192 * __buf is a register which holds the current word of the input.
193 * Thus, there is one memory access per sizeof(unsigned long) characters.
196 #if defined(__alpha__) || defined(__i386__) || defined(__arm__)
201 #define next_byte(x) (x >>= 8)
202 #define current ((unsigned char) __buf)
204 #define next_byte(x) (x <<= 8)
205 #define current (__buf >> 8*(sizeof(unsigned long)-1))
210 if ((unsigned long) next % sizeof(unsigned long) == 0) { \
213 __buf = * (unsigned long *) next; \
219 * State machine macros.
221 #define CASE(c,label) if (current == c) goto label
222 #define NOTCASE(c,label) if (current != c) goto label
225 * Yet another state machine speedup.
227 #define MAX2(a,b) ((a)>(b)?(a):(b))
228 #define MIN2(a,b) ((a)<(b)?(a):(b))
229 #define MAX6(a,b,c,d,e,f) (MAX2(a,MAX2(b,MAX2(c,MAX2(d,MAX2(e,f))))))
230 #define MIN6(a,b,c,d,e,f) (MIN2(a,MIN2(b,MIN2(c,MIN2(d,MIN2(e,f))))))
235 * The state machine looks for (approximately) these Perl regular expressions:
240 * m|#\s*include\s*"(.*?)"|
241 * m|#\s*include\s*<(.*?>"|
242 * m|#\s*(?define|undef)\s*CONFIG_(\w*)|
246 * About 98% of the CPU time is spent here, and most of that is in
247 * the 'start' paragraph. Because the current characters are
248 * in a register, the start loop usually eats 4 or 8 characters
249 * per memory read. The MAX6 and MIN6 tests dispose of most
250 * input characters with 1 or 2 comparisons.
252 void state_machine(const char * map
, const char * end
)
254 const char * next
= map
;
255 const char * map_dot
;
256 unsigned long __buf
= 0;
262 if (current
> MAX6('/','\'','"','#','C','_')) goto start
;
263 if (current
< MIN6('/','\'','"','#','C','_')) goto start
;
269 CASE('_', underscore
);
275 NOTCASE('*', __start
);
278 __slash_star_dot_star
:
279 NOTCASE('*', slash_star_dot_star
);
281 NOTCASE('/', __slash_star_dot_star
);
288 NOTCASE('\\', squote
);
296 NOTCASE('\\', dquote
);
312 GETNEXT
NOTCASE('n', __start
);
313 GETNEXT
NOTCASE('c', __start
);
314 GETNEXT
NOTCASE('l', __start
);
315 GETNEXT
NOTCASE('u', __start
);
316 GETNEXT
NOTCASE('d', __start
);
317 GETNEXT
NOTCASE('e', __start
);
323 CASE(' ', pound_include
);
324 CASE('\t', pound_include
);
326 CASE('"', pound_include_dquote
);
327 CASE('<', pound_include_langle
);
330 /* #\s*include\s*"(.*)" */
331 pound_include_dquote
:
334 NOTCASE('"', pound_include_dquote
);
335 handle_include(1, map_dot
, next
- map_dot
- 1);
338 /* #\s*include\s*<(.*)> */
339 pound_include_langle
:
342 NOTCASE('>', pound_include_langle
);
343 handle_include(0, map_dot
, next
- map_dot
- 1);
348 GETNEXT
NOTCASE('e', __start
);
349 GETNEXT
NOTCASE('f', __start
);
350 GETNEXT
NOTCASE('i', __start
);
351 GETNEXT
NOTCASE('n', __start
);
352 GETNEXT
NOTCASE('e', __start
);
353 goto pound_define_undef
;
357 GETNEXT
NOTCASE('n', __start
);
358 GETNEXT
NOTCASE('d', __start
);
359 GETNEXT
NOTCASE('e', __start
);
360 GETNEXT
NOTCASE('f', __start
);
361 goto pound_define_undef
;
363 /* #\s*(define|undef)\s*CONFIG_(\w*) */
366 CASE(' ', pound_define_undef
);
367 CASE('\t', pound_define_undef
);
369 NOTCASE('C', __start
);
370 GETNEXT
NOTCASE('O', __start
);
371 GETNEXT
NOTCASE('N', __start
);
372 GETNEXT
NOTCASE('F', __start
);
373 GETNEXT
NOTCASE('I', __start
);
374 GETNEXT
NOTCASE('G', __start
);
375 GETNEXT
NOTCASE('_', __start
);
378 pound_define_undef_CONFIG_word
:
380 if (isalnum(current
) || current
== '_')
381 goto pound_define_undef_CONFIG_word
;
382 define_config(1, map_dot
, next
- map_dot
- 1);
387 if (next
>= map
+2 && (isalnum(next
[-2]) || next
[-2] == '_'))
389 GETNEXT
NOTCASE('O', __start
);
390 GETNEXT
NOTCASE('N', __start
);
391 GETNEXT
NOTCASE('F', __start
);
392 GETNEXT
NOTCASE('I', __start
);
393 GETNEXT
NOTCASE('G', __start
);
394 GETNEXT
NOTCASE('_', __start
);
399 if (isalnum(current
) || current
== '_')
400 goto cee_CONFIG_word
;
401 use_config(map_dot
, next
- map_dot
- 1);
406 GETNEXT
NOTCASE('_', __start
);
407 GETNEXT
NOTCASE('S', __start
);
408 GETNEXT
NOTCASE('M', __start
);
409 GETNEXT
NOTCASE('P', __start
);
410 GETNEXT
NOTCASE('_', __start
);
411 GETNEXT
NOTCASE('_', __start
);
412 use_config("SMP", 3);
421 * Generate dependencies for one file.
423 void do_depend(const char * filename
, const char * command
)
426 int pagesizem1
= getpagesize()-1;
431 fd
= open(filename
, O_RDONLY
);
438 if (st
.st_size
== 0) {
439 fprintf(stderr
,"%s is empty\n",filename
);
444 mapsize
= st
.st_size
;
445 mapsize
= (mapsize
+pagesizem1
) & ~pagesizem1
;
446 map
= mmap(NULL
, mapsize
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
447 if ((long) map
== -1) {
448 perror("mkdep: mmap");
452 if ((unsigned long) map
% sizeof(unsigned long) != 0)
454 fprintf(stderr
, "do_depend: map not aligned\n");
460 state_machine(map
, map
+st
.st_size
);
464 munmap(map
, mapsize
);
471 * Generate dependencies for all files.
473 int main(int argc
, char **argv
)
478 hpath
= getenv("HPATH");
480 fputs("mkdep: HPATH not set in environment. "
481 "Don't bypass the top level Makefile.\n", stderr
);
485 memcpy(path_array
[0].buffer
, hpath
, len
);
486 if (len
&& hpath
[len
-1] != '/')
487 path_array
[0].buffer
[len
++] = '/';
488 path_array
[0].buffer
[len
] = '\0';
489 path_array
[0].len
= len
;
492 const char * filename
= *++argv
;
493 const char * command
= __depname
;
494 len
= strlen(filename
);
495 memcpy(depname
, filename
, len
+1);
496 if (len
> 2 && filename
[len
-2] == '.') {
497 if (filename
[len
-1] == 'c' || filename
[len
-1] == 'S') {
498 depname
[len
-1] = 'o';
502 do_depend(filename
, command
);