~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/scripts/mkdep.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.