mkdep.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:13k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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