Import 2.2.8pre4
[davej-history.git] / scripts / mkdep.c
blob9d889ca5165606d194d074ce3700fa60539daa9a
1 /*
2 * Originally by Linus Torvalds.
3 * Smart CONFIG_* processing by Werner Almesberger, Michael Chastain.
5 * Usage: mkdep 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.
13 #include <ctype.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
19 #include <sys/fcntl.h>
20 #include <sys/mman.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
26 char __depname[512] = "\n\t@touch ";
27 #define depname (__depname+9)
28 int hasdep;
30 struct path_struct {
31 int len;
32 char buffer[256-sizeof(int)];
33 } path_array[2] = {
34 { 0, "" },
35 { 0, "" }
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
44 * extremely fast.
46 char * str_config = NULL;
47 int size_config = 0;
48 int len_config = 0;
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) {
59 len_config = 0;
60 size_config = 4096;
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)
80 const char * pconfig;
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))
86 return 1;
88 return 0;
94 * Add a new value to the configuration string.
96 void define_config(int convert, const char * name, int len)
98 grow_config(len + 1);
100 memcpy(str_config+len_config, name, len);
102 if (convert) {
103 int i;
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;
112 len_config += len;
113 str_config[len_config++] = '\n';
119 * Clear the set of configuration strings.
121 void clear_config(void)
123 len_config = 0;
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))
137 return;
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)
145 return;
147 if (!hasdep) {
148 hasdep = 1;
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)
161 char *pc;
162 int i;
164 pc = path_array[0].buffer + path_array[0].len;
165 memcpy(pc, "config/", 7);
166 pc += 7;
168 for (i = 0; i < len; i++) {
169 char c = name[i];
170 if (isupper(c)) c = tolower(c);
171 if (c == '_') c = '/';
172 pc[i] = c;
174 pc[len] = '\0';
176 if (is_defined_config(pc, len))
177 return;
179 define_config(0, pc, len);
181 if (!hasdep) {
182 hasdep = 1;
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__)
197 #define LE_MACHINE
198 #endif
200 #ifdef LE_MACHINE
201 #define next_byte(x) (x >>= 8)
202 #define current ((unsigned char) __buf)
203 #else
204 #define next_byte(x) (x <<= 8)
205 #define current (__buf >> 8*(sizeof(unsigned long)-1))
206 #endif
208 #define GETNEXT { \
209 next_byte(__buf); \
210 if ((unsigned long) next % sizeof(unsigned long) == 0) { \
211 if (next >= end) \
212 break; \
213 __buf = * (unsigned long *) next; \
215 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:
237 * m|\/\*.*?\*\/|
238 * m|'.*?'|
239 * m|".*?"|
240 * m|#\s*include\s*"(.*?)"|
241 * m|#\s*include\s*<(.*?>"|
242 * m|#\s*(?define|undef)\s*CONFIG_(\w*)|
243 * m|(?!\w)CONFIG_|
244 * m|__SMP__|
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;
258 for (;;) {
259 start:
260 GETNEXT
261 __start:
262 if (current > MAX6('/','\'','"','#','C','_')) goto start;
263 if (current < MIN6('/','\'','"','#','C','_')) goto start;
264 CASE('/', slash);
265 CASE('\'', squote);
266 CASE('"', dquote);
267 CASE('#', pound);
268 CASE('C', cee);
269 CASE('_', underscore);
270 goto start;
272 /* / */
273 slash:
274 GETNEXT
275 NOTCASE('*', __start);
276 slash_star_dot_star:
277 GETNEXT
278 __slash_star_dot_star:
279 NOTCASE('*', slash_star_dot_star);
280 GETNEXT
281 NOTCASE('/', __slash_star_dot_star);
282 goto start;
284 /* '.*?' */
285 squote:
286 GETNEXT
287 CASE('\'', start);
288 NOTCASE('\\', squote);
289 GETNEXT
290 goto squote;
292 /* ".*?" */
293 dquote:
294 GETNEXT
295 CASE('"', start);
296 NOTCASE('\\', dquote);
297 GETNEXT
298 goto dquote;
300 /* #\s* */
301 pound:
302 GETNEXT
303 CASE(' ', pound);
304 CASE('\t', pound);
305 CASE('i', pound_i);
306 CASE('d', pound_d);
307 CASE('u', pound_u);
308 goto __start;
310 /* #\s*i */
311 pound_i:
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);
318 goto pound_include;
320 /* #\s*include\s* */
321 pound_include:
322 GETNEXT
323 CASE(' ', pound_include);
324 CASE('\t', pound_include);
325 map_dot = next;
326 CASE('"', pound_include_dquote);
327 CASE('<', pound_include_langle);
328 goto __start;
330 /* #\s*include\s*"(.*)" */
331 pound_include_dquote:
332 GETNEXT
333 CASE('\n', start);
334 NOTCASE('"', pound_include_dquote);
335 handle_include(1, map_dot, next - map_dot - 1);
336 goto start;
338 /* #\s*include\s*<(.*)> */
339 pound_include_langle:
340 GETNEXT
341 CASE('\n', start);
342 NOTCASE('>', pound_include_langle);
343 handle_include(0, map_dot, next - map_dot - 1);
344 goto start;
346 /* #\s*d */
347 pound_d:
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;
355 /* #\s*u */
356 pound_u:
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*) */
364 pound_define_undef:
365 GETNEXT
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);
377 map_dot = next;
378 pound_define_undef_CONFIG_word:
379 GETNEXT
380 if (isalnum(current) || current == '_')
381 goto pound_define_undef_CONFIG_word;
382 define_config(1, map_dot, next - map_dot - 1);
383 goto __start;
385 /* \<CONFIG_(\w*) */
386 cee:
387 if (next >= map+2 && (isalnum(next[-2]) || next[-2] == '_'))
388 goto start;
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);
396 map_dot = next;
397 cee_CONFIG_word:
398 GETNEXT
399 if (isalnum(current) || current == '_')
400 goto cee_CONFIG_word;
401 use_config(map_dot, next - map_dot - 1);
402 goto __start;
404 /* __SMP__ */
405 underscore:
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);
413 goto __start;
421 * Generate dependencies for one file.
423 void do_depend(const char * filename, const char * command)
425 int mapsize;
426 int pagesizem1 = getpagesize()-1;
427 int fd;
428 struct stat st;
429 char * map;
431 fd = open(filename, O_RDONLY);
432 if (fd < 0) {
433 perror(filename);
434 return;
437 fstat(fd, &st);
438 if (st.st_size == 0) {
439 fprintf(stderr,"%s is empty\n",filename);
440 close(fd);
441 return;
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");
449 close(fd);
450 return;
452 if ((unsigned long) map % sizeof(unsigned long) != 0)
454 fprintf(stderr, "do_depend: map not aligned\n");
455 exit(1);
458 hasdep = 0;
459 clear_config();
460 state_machine(map, map+st.st_size);
461 if (hasdep)
462 puts(command);
464 munmap(map, mapsize);
465 close(fd);
471 * Generate dependencies for all files.
473 int main(int argc, char **argv)
475 int len;
476 char *hpath;
478 hpath = getenv("HPATH");
479 if (!hpath) {
480 fputs("mkdep: HPATH not set in environment. "
481 "Don't bypass the top level Makefile.\n", stderr);
482 return 1;
484 len = strlen(hpath);
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;
491 while (--argc > 0) {
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';
499 command = "";
502 do_depend(filename, command);
504 return 0;