mkdep.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /*
  42. * Originally by Linus Torvalds.
  43. * Smart CONFIG_* processing by Werner Almesberger, Michael Chastain.
  44. * Lobotomized by Robey Pointer.
  45. *
  46. * Usage: mkdep file ...
  47. *
  48. * Read source files and output makefile dependency lines for them.
  49. * I make simple dependency lines for #include "*.h".
  50. */
  51. #include <ctype.h>
  52. #include <stdio.h>
  53. #include <stdlib.h>
  54. #include <string.h>
  55. #ifdef WINNT
  56. #include <windows.h>
  57. #include <winbase.h>
  58. #include <io.h>
  59. #else
  60. #include <unistd.h>
  61. #include <fcntl.h>
  62. #include <sys/mman.h>
  63. #include <sys/stat.h>
  64. #include <sys/types.h>
  65. #endif
  66. char __depname[512] = "\n\t@touch ";
  67. #define depname (__depname+9)
  68. int hasdep;
  69. char *outdir = ".";
  70. struct path_struct {
  71. int len;
  72. char buffer[256-sizeof(int)];
  73. } path = { 0, "" };
  74. #ifdef WINNT
  75. #define EXISTS(_fn) _access(_fn, 00)
  76. #else
  77. #define EXISTS(_fn) access(_fn, F_OK)
  78. #endif
  79. /*
  80. * Handle an #include line.
  81. */
  82. void handle_include(const char * name, int len)
  83. {
  84. memcpy(path.buffer+path.len, name, len);
  85. path.buffer[path.len+len] = '\0';
  86. if (EXISTS(path.buffer))
  87. return;
  88. if (!hasdep) {
  89. hasdep = 1;
  90. /* don't use outdir if it's a .h file */
  91. if ((strlen(depname) > 2) &&
  92. (strcmp(depname + strlen(depname) - 2, ".h") == 0)) {
  93. /* skip using the outdir */
  94. } else {
  95. if (outdir)
  96. printf("%s/", outdir);
  97. }
  98. printf("%s:", depname);
  99. }
  100. printf(" \\\n %s", path.buffer);
  101. }
  102. /* --- removed weird functions to try to emulate asm ---
  103. * (turns out it's faster just to scan thru a char*)
  104. */
  105. #define GETNEXT { current = *next++; if (next >= end) break; }
  106. /*
  107. * State machine macros.
  108. */
  109. #define CASE(c,label) if (current == c) goto label
  110. #define NOTCASE(c,label) if (current != c) goto label
  111. /*
  112. * Yet another state machine speedup.
  113. */
  114. #define MAX2(a,b) ((a)>(b)?(a):(b))
  115. #define MIN2(a,b) ((a)<(b)?(a):(b))
  116. #define MAX4(a,b,c,d) (MAX2(a,MAX2(b,MAX2(c,d))))
  117. #define MIN4(a,b,c,d) (MIN2(a,MIN2(b,MIN2(c,d))))
  118. /*
  119. * The state machine looks for (approximately) these Perl regular expressions:
  120. *
  121. * m|\/\*.*?\*\/|
  122. * m|'.*?'|
  123. * m|".*?"|
  124. * m|#\s*include\s*"(.*?)"|
  125. *
  126. * About 98% of the CPU time is spent here, and most of that is in
  127. * the 'start' paragraph. Because the current characters are
  128. * in a register, the start loop usually eats 4 or 8 characters
  129. * per memory read. The MAX6 and MIN6 tests dispose of most
  130. * input characters with 1 or 2 comparisons.
  131. */
  132. void state_machine(const char * map, const char * end)
  133. {
  134. register const char * next = map;
  135. register const char * map_dot;
  136. register unsigned char current;
  137. for (;;) {
  138. start:
  139. GETNEXT
  140. __start:
  141. if (current > MAX4('/','\'','"','#')) goto start;
  142. if (current < MIN4('/','\'','"','#')) goto start;
  143. CASE('/', slash);
  144. CASE('\'', squote);
  145. CASE('"', dquote);
  146. CASE('#', pound);
  147. goto start;
  148. /* / */
  149. slash:
  150. GETNEXT
  151. NOTCASE('*', __start);
  152. slash_star_dot_star:
  153. GETNEXT
  154. __slash_star_dot_star:
  155. NOTCASE('*', slash_star_dot_star);
  156. GETNEXT
  157. NOTCASE('/', __slash_star_dot_star);
  158. goto start;
  159. /* '.*?' */
  160. squote:
  161. GETNEXT
  162. CASE('\'', start);
  163. NOTCASE('\\', squote);
  164. GETNEXT
  165. goto squote;
  166. /* ".*?" */
  167. dquote:
  168. GETNEXT
  169. CASE('"', start);
  170. NOTCASE('\\', dquote);
  171. GETNEXT
  172. goto dquote;
  173. /* #\s* */
  174. pound:
  175. GETNEXT
  176. CASE(' ', pound);
  177. CASE('\t', pound);
  178. CASE('i', pound_i);
  179. goto __start;
  180. /* #\s*i */
  181. pound_i:
  182. GETNEXT NOTCASE('n', __start);
  183. GETNEXT NOTCASE('c', __start);
  184. GETNEXT NOTCASE('l', __start);
  185. GETNEXT NOTCASE('u', __start);
  186. GETNEXT NOTCASE('d', __start);
  187. GETNEXT NOTCASE('e', __start);
  188. goto pound_include;
  189. /* #\s*include\s* */
  190. pound_include:
  191. GETNEXT
  192. CASE(' ', pound_include);
  193. CASE('\t', pound_include);
  194. map_dot = next;
  195. CASE('"', pound_include_dquote);
  196. goto __start;
  197. /* #\s*include\s*"(.*)" */
  198. pound_include_dquote:
  199. GETNEXT
  200. CASE('\n', start);
  201. NOTCASE('"', pound_include_dquote);
  202. handle_include(map_dot, next - map_dot - 1);
  203. goto start;
  204. }
  205. }
  206. #ifdef WINNT
  207. /*
  208. * Alternate implementation of do_depend() for NT
  209. * (NT has its own wacky versions of open/mmap/close)
  210. */
  211. void do_depend(const char *filename, const char *command)
  212. {
  213. HANDLE fd, mapfd;
  214. BY_HANDLE_FILE_INFORMATION st;
  215. char *map;
  216. fd = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
  217. OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  218. if (fd == INVALID_HANDLE_VALUE) {
  219. fprintf(stderr, "NT error opening '%s'\n", filename);
  220. return;
  221. }
  222. if (! GetFileInformationByHandle(fd, &st)) {
  223. fprintf(stderr, "NT error getting stat on '%s'\n", filename);
  224. CloseHandle(fd);
  225. return;
  226. }
  227. if (st.nFileSizeLow == 0) {
  228. fprintf(stderr, "%s is empty\n", filename);
  229. CloseHandle(fd);
  230. return;
  231. }
  232. mapfd = CreateFileMapping(fd, NULL, PAGE_READONLY, st.nFileSizeHigh,
  233. st.nFileSizeLow, NULL);
  234. if (mapfd == NULL) {
  235. fprintf(stderr, "NT error creating file mapping of '%s'\n",
  236. filename);
  237. CloseHandle(fd);
  238. return;
  239. }
  240. map = MapViewOfFile(mapfd, FILE_MAP_READ, 0, 0, 0);
  241. if (map == NULL) {
  242. fprintf(stderr, "NT error creating mapped view of '%s'\n",
  243. filename);
  244. CloseHandle(mapfd);
  245. CloseHandle(fd);
  246. return;
  247. }
  248. hasdep = 0;
  249. state_machine(map, map+st.nFileSizeLow);
  250. if (hasdep)
  251. puts(command);
  252. UnmapViewOfFile(map);
  253. CloseHandle(mapfd);
  254. CloseHandle(fd);
  255. }
  256. #else
  257. /*
  258. * Generate dependencies for one file.
  259. */
  260. void do_depend(const char * filename, const char * command)
  261. {
  262. int mapsize;
  263. int pagesizem1 = getpagesize()-1;
  264. int fd;
  265. struct stat st;
  266. char * map;
  267. fd = open(filename, O_RDONLY);
  268. if (fd < 0) {
  269. perror(filename);
  270. return;
  271. }
  272. fstat(fd, &st);
  273. if (st.st_size == 0) {
  274. fprintf(stderr,"%s is empty\n",filename);
  275. close(fd);
  276. return;
  277. }
  278. mapsize = st.st_size;
  279. mapsize = (mapsize+pagesizem1) & ~pagesizem1;
  280. map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
  281. if ((long) map == -1) {
  282. perror("mkdep: mmap");
  283. close(fd);
  284. return;
  285. }
  286. if ((unsigned long) map % sizeof(unsigned long) != 0)
  287. {
  288. fprintf(stderr, "do_depend: map not aligned\n");
  289. exit(1);
  290. }
  291. hasdep = 0;
  292. state_machine(map, map+st.st_size);
  293. if (hasdep)
  294. puts(command);
  295. munmap(map, mapsize);
  296. close(fd);
  297. }
  298. #endif
  299. /*
  300. * Generate dependencies for all files.
  301. */
  302. int main(int argc, char **argv)
  303. {
  304. int len;
  305. while (--argc > 0) {
  306. const char *filename = *++argv;
  307. const char *command = __depname;
  308. if (strcmp(filename, "-o") == 0) {
  309. outdir = *++argv;
  310. argc--;
  311. continue;
  312. }
  313. len = strlen(filename);
  314. memcpy(depname, filename, len+1);
  315. if (len > 2 && filename[len-2] == '.') {
  316. if (filename[len-1] == 'c' || filename[len-1] == 'S') {
  317. depname[len-1] = 'o';
  318. command = "";
  319. }
  320. }
  321. do_depend(filename, command);
  322. }
  323. return 0;
  324. }