Mercurial > mm7
comparison lib/swig/swigwin-2.0.11/CCache/ccache.c @ 1899:b3009adc0e2f
Adding swig, gitignore, hgignore
author | Nomad |
---|---|
date | Mon, 21 Oct 2013 10:42:27 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
1867:eb580660bbbb | 1899:b3009adc0e2f |
---|---|
1 /* | |
2 a re-implementation of the compilercache scripts in C | |
3 | |
4 The idea is based on the shell-script compilercache by Erik Thiele <erikyyy@erikyyy.de> | |
5 | |
6 Copyright (C) Andrew Tridgell 2002 | |
7 Copyright (C) Martin Pool 2003 | |
8 | |
9 This program is free software; you can redistribute it and/or modify | |
10 it under the terms of the GNU General Public License as published by | |
11 the Free Software Foundation; either version 2 of the License, or | |
12 (at your option) any later version. | |
13 | |
14 This program is distributed in the hope that it will be useful, | |
15 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 GNU General Public License for more details. | |
18 | |
19 You should have received a copy of the GNU General Public License | |
20 along with this program; if not, write to the Free Software | |
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
22 */ | |
23 | |
24 #include "ccache.h" | |
25 | |
26 /* verbose mode */ | |
27 int ccache_verbose = 0; | |
28 | |
29 /* the base cache directory */ | |
30 char *cache_dir = NULL; | |
31 | |
32 /* the directory for temporary files */ | |
33 static char *temp_dir = NULL; | |
34 | |
35 /* the debug logfile name, if set */ | |
36 char *cache_logfile = NULL; | |
37 | |
38 /* the argument list after processing */ | |
39 static ARGS *stripped_args; | |
40 | |
41 /* the original argument list */ | |
42 static ARGS *orig_args; | |
43 | |
44 /* the output filename being compiled to */ | |
45 static char *output_file; | |
46 | |
47 /* the source file */ | |
48 static char *input_file; | |
49 | |
50 /* the name of the file containing the cached object code */ | |
51 static char *hashname; | |
52 | |
53 /* the extension of the file after pre-processing */ | |
54 static const char *i_extension; | |
55 | |
56 /* the name of the temporary pre-processor file */ | |
57 static char *i_tmpfile; | |
58 | |
59 /* are we compiling a .i or .ii file directly? */ | |
60 static int direct_i_file; | |
61 | |
62 /* the name of the cpp stderr file */ | |
63 static char *cpp_stderr; | |
64 | |
65 /* the name of the statistics file */ | |
66 char *stats_file = NULL; | |
67 | |
68 /* can we safely use the unification hashing backend? */ | |
69 static int enable_unify; | |
70 | |
71 /* should we strip -c when running the preprocessor only? */ | |
72 static int strip_c_option; | |
73 | |
74 /* customisation for using the SWIG compiler */ | |
75 static int swig; | |
76 | |
77 /* a list of supported file extensions, and the equivalent | |
78 extension for code that has been through the pre-processor | |
79 */ | |
80 static struct { | |
81 char *extension; | |
82 char *i_extension; | |
83 } extensions[] = { | |
84 {"c", "i"}, | |
85 {"C", "ii"}, | |
86 {"m", "mi"}, | |
87 {"cc", "ii"}, | |
88 {"CC", "ii"}, | |
89 {"cpp", "ii"}, | |
90 {"CPP", "ii"}, | |
91 {"cxx", "ii"}, | |
92 {"CXX", "ii"}, | |
93 {"c++", "ii"}, | |
94 {"C++", "ii"}, | |
95 {"i", "i"}, | |
96 {"ii", "ii"}, | |
97 {NULL, NULL}}; | |
98 | |
99 /* | |
100 something went badly wrong - just execute the real compiler | |
101 */ | |
102 static void failed(void) | |
103 { | |
104 char *e; | |
105 | |
106 /* delete intermediate pre-processor file if needed */ | |
107 if (i_tmpfile) { | |
108 if (!direct_i_file) { | |
109 unlink(i_tmpfile); | |
110 } | |
111 free(i_tmpfile); | |
112 i_tmpfile = NULL; | |
113 } | |
114 | |
115 /* delete the cpp stderr file if necessary */ | |
116 if (cpp_stderr) { | |
117 unlink(cpp_stderr); | |
118 free(cpp_stderr); | |
119 cpp_stderr = NULL; | |
120 } | |
121 | |
122 /* strip any local args */ | |
123 args_strip(orig_args, "--ccache-"); | |
124 | |
125 if ((e=getenv("CCACHE_PREFIX"))) { | |
126 char *p = find_executable(e, MYNAME); | |
127 if (!p) { | |
128 cc_log("could not find executable (%s)\n", e); | |
129 perror(e); | |
130 exit(1); | |
131 } | |
132 args_add_prefix(orig_args, p); | |
133 } | |
134 | |
135 if (ccache_verbose) { | |
136 display_execute_args(orig_args->argv); | |
137 } | |
138 | |
139 if (swig) { | |
140 putenv("CCACHE_OUTFILES"); | |
141 } | |
142 | |
143 #ifndef _WIN32 | |
144 execv(orig_args->argv[0], orig_args->argv); | |
145 cc_log("execv returned (%s)!\n", strerror(errno)); | |
146 perror(orig_args->argv[0]); | |
147 exit(1); | |
148 #else | |
149 /* execv on Windows causes the 'non-regular' testcase to fail, so use Win32 API instead */ | |
150 { | |
151 PROCESS_INFORMATION pinfo; | |
152 STARTUPINFO sinfo; | |
153 BOOL ret; | |
154 DWORD exitcode; | |
155 char *args; | |
156 | |
157 ZeroMemory(&pinfo, sizeof(PROCESS_INFORMATION)); | |
158 ZeroMemory(&sinfo, sizeof(STARTUPINFO)); | |
159 sinfo.cb = sizeof(STARTUPINFO); | |
160 args = argvtos(orig_args->argv); | |
161 ret = CreateProcessA(orig_args->argv[0], args, NULL, NULL, TRUE, 0, NULL, NULL, | |
162 &sinfo, &pinfo); | |
163 if (!ret) { | |
164 exitcode = 1; | |
165 cc_log("CreateProcessA failed starting %s\n", orig_args->argv[0]); | |
166 perror_win32(orig_args->argv[0]); | |
167 } else { | |
168 WaitForSingleObject(pinfo.hProcess, INFINITE); | |
169 GetExitCodeProcess(pinfo.hProcess, &exitcode); | |
170 CloseHandle(pinfo.hProcess); | |
171 CloseHandle(pinfo.hThread); | |
172 } | |
173 free(args); | |
174 exit(exitcode); | |
175 } | |
176 #endif | |
177 } | |
178 | |
179 | |
180 /* return a string to be used to distinguish temporary files | |
181 this also tries to cope with NFS by adding the local hostname | |
182 */ | |
183 static const char *tmp_string(void) | |
184 { | |
185 static char *ret; | |
186 | |
187 if (!ret) { | |
188 char hostname[200]; | |
189 strcpy(hostname, "unknown"); | |
190 #if HAVE_GETHOSTNAME | |
191 gethostname(hostname, sizeof(hostname)-1); | |
192 #endif | |
193 hostname[sizeof(hostname)-1] = 0; | |
194 if (asprintf(&ret, "%s.%u", hostname, (unsigned)getpid()) == -1) { | |
195 fatal("could not allocate tmp_string"); | |
196 } | |
197 } | |
198 | |
199 return ret; | |
200 } | |
201 | |
202 /* update cached file sizes and count helper function for to_cache() */ | |
203 static void to_cache_stats_helper(struct stat *pstat, char *cached_filename, char *tmp_outfiles, int *files_size, int *cached_files_count) | |
204 { | |
205 #if ENABLE_ZLIB | |
206 /* do an extra stat on the cache file for the size statistics */ | |
207 if (stat(cached_filename, pstat) != 0) { | |
208 cc_log("failed to stat cache files - %s\n", strerror(errno)); | |
209 stats_update(STATS_ERROR); | |
210 if (tmp_outfiles) { | |
211 unlink(tmp_outfiles); | |
212 } | |
213 failed(); | |
214 } | |
215 #else | |
216 (void)cached_filename; | |
217 (void)tmp_outfiles; | |
218 #endif | |
219 (*files_size) += file_size(pstat); | |
220 (*cached_files_count)++; | |
221 } | |
222 | |
223 /* run the real compiler and put the result in cache */ | |
224 static void to_cache(ARGS *args) | |
225 { | |
226 char *path_stderr; | |
227 char *tmp_stdout, *tmp_stderr, *tmp_outfiles; | |
228 struct stat st1; | |
229 int status; | |
230 int cached_files_count = 0; | |
231 int files_size = 0; | |
232 | |
233 x_asprintf(&tmp_stdout, "%s/tmp.stdout.%s", temp_dir, tmp_string()); | |
234 x_asprintf(&tmp_stderr, "%s/tmp.stderr.%s", temp_dir, tmp_string()); | |
235 x_asprintf(&tmp_outfiles, "%s/tmp.outfiles.%s", temp_dir, tmp_string()); | |
236 | |
237 if (strip_c_option && !swig) { | |
238 args_add(stripped_args, "-c"); | |
239 } | |
240 | |
241 if (output_file) { | |
242 args_add(args, "-o"); | |
243 args_add(args, output_file); | |
244 } | |
245 | |
246 /* Turn off DEPENDENCIES_OUTPUT when running cc1, because | |
247 * otherwise it will emit a line like | |
248 * | |
249 * tmp.stdout.vexed.732.o: /home/mbp/.ccache/tmp.stdout.vexed.732.i | |
250 * | |
251 * unsetenv() is on BSD and Linux but not portable. */ | |
252 putenv("DEPENDENCIES_OUTPUT"); | |
253 | |
254 /* Give SWIG a filename for it to create and populate with a list of files that it generates */ | |
255 if (swig) { | |
256 char *ccache_outfiles; | |
257 x_asprintf(&ccache_outfiles, "CCACHE_OUTFILES=%s", tmp_outfiles); | |
258 unlink(tmp_outfiles); | |
259 if (getenv("CCACHE_OUTFILES") || putenv(ccache_outfiles) == -1) { | |
260 cc_log("CCACHE_OUTFILES env variable already set or could not be set\n"); | |
261 stats_update(STATS_ERROR); | |
262 failed(); | |
263 } | |
264 } | |
265 | |
266 if (getenv("CCACHE_CPP2")) { | |
267 args_add(args, input_file); | |
268 } else { | |
269 if (swig) { | |
270 args_add(args, "-nopreprocess"); | |
271 } | |
272 args_add(args, i_tmpfile); | |
273 } | |
274 status = execute(args->argv, tmp_stdout, tmp_stderr); | |
275 args_pop(args, 3); | |
276 | |
277 if (stat(tmp_stdout, &st1) != 0 || st1.st_size != 0) { | |
278 cc_log("compiler produced stdout for %s\n", input_file); | |
279 stats_update(STATS_STDOUT); | |
280 unlink(tmp_stdout); | |
281 unlink(tmp_stderr); | |
282 unlink(tmp_outfiles); | |
283 if (!swig) unlink(output_file); | |
284 failed(); | |
285 } | |
286 unlink(tmp_stdout); | |
287 | |
288 if (status != 0) { | |
289 int fd; | |
290 cc_log("compile of %s gave status = %d\n", input_file, status); | |
291 stats_update(STATS_STATUS); | |
292 | |
293 fd = open(tmp_stderr, O_RDONLY | O_BINARY); | |
294 if (fd != -1) { | |
295 if (cpp_stderr) { | |
296 /* we might have some stderr from cpp */ | |
297 int fd2 = open(cpp_stderr, O_RDONLY | O_BINARY); | |
298 if (fd2 != -1) { | |
299 copy_fd(fd2, 2); | |
300 close(fd2); | |
301 unlink(cpp_stderr); | |
302 cpp_stderr = NULL; | |
303 } | |
304 } | |
305 | |
306 /* we can use a quick method of | |
307 getting the failed output */ | |
308 copy_fd(fd, 2); | |
309 close(fd); | |
310 unlink(tmp_stderr); | |
311 if (i_tmpfile && !direct_i_file) { | |
312 unlink(i_tmpfile); | |
313 } | |
314 exit(status); | |
315 } | |
316 | |
317 unlink(tmp_stderr); | |
318 unlink(tmp_outfiles); | |
319 if (!swig) unlink(output_file); | |
320 failed(); | |
321 } else { | |
322 int hardlink = (getenv("CCACHE_NOCOMPRESS") != 0) && (getenv("CCACHE_HARDLINK") != 0); | |
323 if (swig) { | |
324 /* read the list of generated files and copy each of them into the cache */ | |
325 FILE *file; | |
326 file = fopen(tmp_outfiles, "r"); | |
327 if (file) { | |
328 char out_filename[FILENAME_MAX + 1]; | |
329 char out_filename_cache[FILENAME_MAX + 1]; | |
330 while (fgets(out_filename, FILENAME_MAX, file)) { | |
331 char *linefeed = strchr(out_filename, '\n'); | |
332 if (linefeed) { | |
333 char *potential_cr = linefeed - 1; | |
334 if (potential_cr >= out_filename && *potential_cr == '\r') | |
335 *potential_cr = 0; | |
336 *linefeed = 0; | |
337 | |
338 if (cached_files_count == 0) { | |
339 strcpy(out_filename_cache, hashname); | |
340 } else { | |
341 sprintf(out_filename_cache, "%s.%d", hashname, cached_files_count); | |
342 } | |
343 | |
344 if (commit_to_cache(out_filename, out_filename_cache, hardlink) != 0) { | |
345 fclose(file); | |
346 unlink(tmp_outfiles); | |
347 failed(); | |
348 } | |
349 to_cache_stats_helper(&st1, out_filename_cache, tmp_outfiles, &files_size, &cached_files_count); | |
350 } else { | |
351 cached_files_count = 0; | |
352 break; | |
353 } | |
354 } | |
355 fclose(file); | |
356 if (cached_files_count == 0) { | |
357 cc_log("failed to copy output files to cache - internal error\n"); | |
358 stats_update(STATS_ERROR); | |
359 unlink(tmp_outfiles); | |
360 failed(); | |
361 } | |
362 | |
363 /* also copy the (uncompressed) file containing the list of generated files into the cache */ | |
364 sprintf(out_filename_cache, "%s.outfiles", hashname); | |
365 if (stat(tmp_outfiles, &st1) != 0 || | |
366 safe_rename(tmp_outfiles, out_filename_cache) != 0) { | |
367 cc_log("failed to copy outfiles file to cache - %s\n", strerror(errno)); | |
368 stats_update(STATS_ERROR); | |
369 unlink(tmp_outfiles); | |
370 failed(); | |
371 } | |
372 to_cache_stats_helper(&st1, out_filename_cache, tmp_outfiles, &files_size, &cached_files_count); | |
373 unlink(tmp_outfiles); | |
374 } else { | |
375 cc_log("failed to open temp outfiles file - %s\n", strerror(errno)); | |
376 stats_update(STATS_ERROR); | |
377 failed(); | |
378 } | |
379 } else { | |
380 if (commit_to_cache(output_file, hashname, hardlink) != 0) { | |
381 failed(); | |
382 } | |
383 to_cache_stats_helper(&st1, hashname, 0, &files_size, &cached_files_count); | |
384 } | |
385 } | |
386 | |
387 x_asprintf(&path_stderr, "%s.stderr", hashname); | |
388 | |
389 if (stat(tmp_stderr, &st1) != 0 || | |
390 move_file(tmp_stderr, path_stderr) != 0) { | |
391 cc_log("failed to rename tmp files - %s\n", strerror(errno)); | |
392 stats_update(STATS_ERROR); | |
393 failed(); | |
394 } | |
395 | |
396 to_cache_stats_helper(&st1, path_stderr, 0, &files_size, &cached_files_count); | |
397 | |
398 cc_log("Placed %d files for %s into cache\n", cached_files_count, input_file); | |
399 stats_tocache(files_size, cached_files_count); | |
400 | |
401 free(tmp_stderr); | |
402 free(tmp_stdout); | |
403 free(tmp_outfiles); | |
404 free(path_stderr); | |
405 } | |
406 | |
407 /* find the hash for a command. The hash includes all argument lists, | |
408 plus the output from running the compiler with -E */ | |
409 static void find_hash(ARGS *args) | |
410 { | |
411 int i; | |
412 char *path_stdout, *path_stderr; | |
413 char *hash_dir; | |
414 char *s; | |
415 struct stat st; | |
416 int status; | |
417 int nlevels = 2; | |
418 char *input_base; | |
419 char *tmp; | |
420 | |
421 if ((s = getenv("CCACHE_NLEVELS"))) { | |
422 nlevels = atoi(s); | |
423 if (nlevels < 1) nlevels = 1; | |
424 if (nlevels > 8) nlevels = 8; | |
425 } | |
426 | |
427 hash_start(); | |
428 | |
429 /* when we are doing the unifying tricks we need to include | |
430 the input file name in the hash to get the warnings right */ | |
431 if (enable_unify || swig) { | |
432 hash_string(input_file); | |
433 } | |
434 | |
435 if (swig) { | |
436 if (output_file) { | |
437 hash_string(output_file); | |
438 } | |
439 } else { | |
440 /* we have to hash the extension, as a .i file isn't treated the same | |
441 by the compiler as a .ii file */ | |
442 hash_string(i_extension); | |
443 } | |
444 | |
445 /* first the arguments */ | |
446 for (i=1;i<args->argc;i++) { | |
447 /* some arguments don't contribute to the hash. The | |
448 theory is that these arguments will change the | |
449 output of -E if they are going to have any effect | |
450 at all, or they only affect linking */ | |
451 if (i < args->argc-1) { | |
452 if (strcmp(args->argv[i], "-I") == 0 || | |
453 strcmp(args->argv[i], "-include") == 0 || | |
454 strcmp(args->argv[i], "-L") == 0 || | |
455 strcmp(args->argv[i], "-D") == 0 || | |
456 strcmp(args->argv[i], "-idirafter") == 0 || | |
457 strcmp(args->argv[i], "-isystem") == 0) { | |
458 i++; | |
459 continue; | |
460 } | |
461 } | |
462 if (strncmp(args->argv[i], "-I", 2) == 0 || | |
463 strncmp(args->argv[i], "-L", 2) == 0 || | |
464 strncmp(args->argv[i], "-D", 2) == 0 || | |
465 strncmp(args->argv[i], "-idirafter", 10) == 0 || | |
466 strncmp(args->argv[i], "-isystem", 8) == 0) { | |
467 continue; | |
468 } | |
469 | |
470 if (strncmp(args->argv[i], "--specs=", 8) == 0 && | |
471 stat(args->argv[i]+8, &st) == 0) { | |
472 /* if given a explicit specs file, then hash that file, but | |
473 don't include the path to it in the hash */ | |
474 hash_file(args->argv[i]+8); | |
475 continue; | |
476 } | |
477 | |
478 /* all other arguments are included in the hash */ | |
479 hash_string(args->argv[i]); | |
480 } | |
481 | |
482 /* the compiler driver size and date. This is a simple minded way | |
483 to try and detect compiler upgrades. It is not 100% reliable */ | |
484 if (stat(args->argv[0], &st) != 0) { | |
485 cc_log("Couldn't stat the compiler!? (argv[0]='%s')\n", args->argv[0]); | |
486 stats_update(STATS_COMPILER); | |
487 failed(); | |
488 } | |
489 | |
490 /* also include the hash of the compiler name - as some compilers | |
491 use hard links and behave differently depending on the real name */ | |
492 if (st.st_nlink > 1) { | |
493 hash_string(str_basename(args->argv[0])); | |
494 } | |
495 | |
496 hash_int(st.st_size); | |
497 hash_int(st.st_mtime); | |
498 | |
499 /* possibly hash the current working directory */ | |
500 if (getenv("CCACHE_HASHDIR")) { | |
501 char *cwd = gnu_getcwd(); | |
502 if (cwd) { | |
503 hash_string(cwd); | |
504 free(cwd); | |
505 } | |
506 } | |
507 | |
508 /* ~/hello.c -> tmp.hello.123.i | |
509 limit the basename to 10 | |
510 characters in order to cope with filesystem with small | |
511 maximum filename length limits */ | |
512 input_base = str_basename(input_file); | |
513 tmp = strchr(input_base, '.'); | |
514 if (tmp != NULL) { | |
515 *tmp = 0; | |
516 } | |
517 if (strlen(input_base) > 10) { | |
518 input_base[10] = 0; | |
519 } | |
520 | |
521 /* now the run */ | |
522 x_asprintf(&path_stdout, "%s/%s.tmp.%s.%s", temp_dir, | |
523 input_base, tmp_string(), | |
524 i_extension); | |
525 x_asprintf(&path_stderr, "%s/tmp.cpp_stderr.%s", temp_dir, tmp_string()); | |
526 | |
527 if (!direct_i_file) { | |
528 /* run cpp on the input file to obtain the .i */ | |
529 args_add(args, "-E"); | |
530 args_add(args, input_file); | |
531 status = execute(args->argv, path_stdout, path_stderr); | |
532 args_pop(args, 2); | |
533 } else { | |
534 /* we are compiling a .i or .ii file - that means we | |
535 can skip the cpp stage and directly form the | |
536 correct i_tmpfile */ | |
537 path_stdout = x_strdup(input_file); | |
538 if (create_empty_file(path_stderr) != 0) { | |
539 cc_log("failed to create empty stderr file\n"); | |
540 stats_update(STATS_ERROR); | |
541 failed(); | |
542 } | |
543 status = 0; | |
544 } | |
545 | |
546 if (status != 0) { | |
547 if (!direct_i_file) { | |
548 unlink(path_stdout); | |
549 } | |
550 unlink(path_stderr); | |
551 cc_log("the preprocessor gave %d\n", status); | |
552 stats_update(STATS_PREPROCESSOR); | |
553 failed(); | |
554 } | |
555 | |
556 /* if the compilation is with -g then we have to include the whole of the | |
557 preprocessor output, which means we are sensitive to line number | |
558 information. Otherwise we can discard line number info, which makes | |
559 us less sensitive to reformatting changes | |
560 | |
561 Note! I have now disabled the unification code by default | |
562 as it gives the wrong line numbers for warnings. Pity. | |
563 */ | |
564 if (!enable_unify) { | |
565 hash_file(path_stdout); | |
566 } else { | |
567 if (unify_hash(path_stdout) != 0) { | |
568 stats_update(STATS_ERROR); | |
569 failed(); | |
570 } | |
571 } | |
572 hash_file(path_stderr); | |
573 | |
574 i_tmpfile = path_stdout; | |
575 | |
576 if (!getenv("CCACHE_CPP2")) { | |
577 /* if we are using the CPP trick then we need to remember this stderr | |
578 data and output it just before the main stderr from the compiler | |
579 pass */ | |
580 cpp_stderr = path_stderr; | |
581 } else { | |
582 unlink(path_stderr); | |
583 free(path_stderr); | |
584 } | |
585 | |
586 /* we use a N level subdir for the cache path to reduce the impact | |
587 on filesystems which are slow for large directories | |
588 */ | |
589 s = hash_result(); | |
590 x_asprintf(&hash_dir, "%s/%c", cache_dir, s[0]); | |
591 x_asprintf(&stats_file, "%s/stats", hash_dir); | |
592 for (i=1; i<nlevels; i++) { | |
593 char *p; | |
594 if (create_dir(hash_dir) != 0) { | |
595 cc_log("failed to create %s\n", hash_dir); | |
596 stats_update(STATS_ERROR); | |
597 failed(); | |
598 } | |
599 x_asprintf(&p, "%s/%c", hash_dir, s[i]); | |
600 free(hash_dir); | |
601 hash_dir = p; | |
602 } | |
603 if (create_dir(hash_dir) != 0) { | |
604 cc_log("failed to create %s\n", hash_dir); | |
605 stats_update(STATS_ERROR); | |
606 failed(); | |
607 } | |
608 x_asprintf(&hashname, "%s/%s", hash_dir, s+nlevels); | |
609 free(hash_dir); | |
610 } | |
611 | |
612 /* | |
613 try to return the compile result from cache. If we can return from | |
614 cache then this function exits with the correct status code, | |
615 otherwise it returns */ | |
616 static void from_cache(int first) | |
617 { | |
618 int fd_stderr, fd_cpp_stderr; | |
619 char *stderr_file; | |
620 struct stat st; | |
621 | |
622 x_asprintf(&stderr_file, "%s.stderr", hashname); | |
623 fd_stderr = open(stderr_file, O_RDONLY | O_BINARY); | |
624 if (fd_stderr == -1) { | |
625 /* it isn't in cache ... */ | |
626 free(stderr_file); | |
627 return; | |
628 } | |
629 | |
630 /* make sure the output is there too */ | |
631 if (stat(hashname, &st) != 0) { | |
632 close(fd_stderr); | |
633 unlink(stderr_file); | |
634 free(stderr_file); | |
635 return; | |
636 } | |
637 | |
638 /* the user might be disabling cache hits */ | |
639 #ifndef ENABLE_ZLIB | |
640 /* if the cache file is compressed we must recache */ | |
641 if ((first && getenv("CCACHE_RECACHE")) || | |
642 test_if_compressed(hashname) == 1) | |
643 #else | |
644 if (first && getenv("CCACHE_RECACHE")) | |
645 #endif | |
646 { | |
647 close(fd_stderr); | |
648 unlink(stderr_file); | |
649 free(stderr_file); | |
650 return; | |
651 } | |
652 | |
653 if (first) { | |
654 int hardlink; | |
655 int passfail = -1; | |
656 | |
657 /* update timestamps for LRU cleanup | |
658 also gives output_file a sensible mtime when hard-linking (for make) */ | |
659 x_utimes(stderr_file); | |
660 | |
661 hardlink = (getenv("CCACHE_HARDLINK") != 0); | |
662 | |
663 if (swig) { | |
664 /* read the list of generated files and copy each of them out of the cache */ | |
665 FILE *file; | |
666 char *outfiles; | |
667 x_asprintf(&outfiles, "%s.outfiles", hashname); | |
668 file = fopen(outfiles, "r"); | |
669 if (file) { | |
670 char out_filename[FILENAME_MAX + 1]; | |
671 char out_filename_cache[FILENAME_MAX + 1]; | |
672 int retrieved_files_count = 0; | |
673 x_utimes(outfiles); | |
674 while (fgets(out_filename, FILENAME_MAX, file)) { | |
675 char *linefeed = strchr(out_filename, '\n'); | |
676 if (linefeed) { | |
677 char *potential_cr = linefeed - 1; | |
678 if (potential_cr >= out_filename && *potential_cr == '\r') | |
679 *potential_cr = 0; | |
680 *linefeed = 0; | |
681 | |
682 if (retrieved_files_count == 0) { | |
683 strcpy(out_filename_cache, hashname); | |
684 } else { | |
685 sprintf(out_filename_cache, "%s.%d", hashname, retrieved_files_count); | |
686 } | |
687 | |
688 passfail = retrieve_from_cache(out_filename_cache, out_filename, hardlink); | |
689 if (passfail == -1) { | |
690 break; | |
691 } | |
692 | |
693 retrieved_files_count++; | |
694 } else { | |
695 cc_log("failed to copy output files from cache - internal error\n"); | |
696 stats_update(STATS_ERROR); | |
697 passfail = -1; | |
698 break; | |
699 } | |
700 } | |
701 if (retrieved_files_count == 0) { | |
702 cc_log("failed to copy output files from cache - internal error\n"); | |
703 stats_update(STATS_ERROR); | |
704 passfail = -1; | |
705 } | |
706 fclose(file); | |
707 } else { | |
708 cc_log("failed to open cached outfiles file - %s\n", strerror(errno)); | |
709 stats_update(STATS_ERROR); | |
710 } | |
711 } else { | |
712 passfail = retrieve_from_cache(hashname, output_file, hardlink); | |
713 } | |
714 | |
715 if (passfail == -1) { | |
716 close(fd_stderr); | |
717 unlink(stderr_file); | |
718 free(stderr_file); | |
719 return; | |
720 } | |
721 free(stderr_file); | |
722 } | |
723 | |
724 /* get rid of the intermediate preprocessor file */ | |
725 if (i_tmpfile) { | |
726 if (!direct_i_file) { | |
727 unlink(i_tmpfile); | |
728 } | |
729 free(i_tmpfile); | |
730 i_tmpfile = NULL; | |
731 } | |
732 | |
733 /* send the cpp stderr, if applicable */ | |
734 fd_cpp_stderr = open(cpp_stderr, O_RDONLY | O_BINARY); | |
735 if (fd_cpp_stderr != -1) { | |
736 copy_fd(fd_cpp_stderr, 2); | |
737 close(fd_cpp_stderr); | |
738 unlink(cpp_stderr); | |
739 free(cpp_stderr); | |
740 cpp_stderr = NULL; | |
741 } | |
742 | |
743 /* send the stderr */ | |
744 copy_fd(fd_stderr, 2); | |
745 close(fd_stderr); | |
746 | |
747 /* and exit with the right status code */ | |
748 if (first) { | |
749 cc_log("got cached result for %s\n", input_file); | |
750 stats_update(STATS_CACHED); | |
751 } | |
752 | |
753 exit(0); | |
754 } | |
755 | |
756 /* find the real compiler. We just search the PATH to find a executable of the | |
757 same name that isn't a link to ourselves */ | |
758 static void find_compiler(int argc, char **argv) | |
759 { | |
760 char *base; | |
761 char *path; | |
762 | |
763 orig_args = args_init(argc, argv); | |
764 | |
765 base = str_basename(argv[0]); | |
766 | |
767 /* we might be being invoked like "ccache gcc -c foo.c" */ | |
768 if (strcmp(base, MYNAME) == 0) { | |
769 args_remove_first(orig_args); | |
770 free(base); | |
771 if (strchr(argv[1],'/') | |
772 #ifdef _WIN32 | |
773 || strchr(argv[1],'\\') | |
774 #endif | |
775 ) { | |
776 /* a full path was given */ | |
777 return; | |
778 } | |
779 base = str_basename(argv[1]); | |
780 } | |
781 | |
782 /* support user override of the compiler */ | |
783 if ((path=getenv("CCACHE_CC"))) { | |
784 base = x_strdup(path); | |
785 } | |
786 | |
787 orig_args->argv[0] = find_executable(base, MYNAME); | |
788 | |
789 /* can't find the compiler! */ | |
790 if (!orig_args->argv[0]) { | |
791 stats_update(STATS_COMPILER); | |
792 cc_log("could not find compiler (%s)\n", base); | |
793 perror(base); | |
794 exit(1); | |
795 } | |
796 } | |
797 | |
798 | |
799 /* check a filename for C/C++ extension. Return the pre-processor | |
800 extension */ | |
801 static const char *check_extension(const char *fname, int *direct_i) | |
802 { | |
803 int i; | |
804 const char *p; | |
805 | |
806 if (direct_i) { | |
807 *direct_i = 0; | |
808 } | |
809 | |
810 if (swig) return "ii"; /* any file extension is acceptable as input for SWIG */ | |
811 | |
812 p = strrchr(fname, '.'); | |
813 if (!p) return NULL; | |
814 p++; | |
815 for (i=0; extensions[i].extension; i++) { | |
816 if (strcmp(p, extensions[i].extension) == 0) { | |
817 if (direct_i && strcmp(p, extensions[i].i_extension) == 0) { | |
818 *direct_i = 1; | |
819 } | |
820 p = getenv("CCACHE_EXTENSION"); | |
821 if (p) return p; | |
822 return extensions[i].i_extension; | |
823 } | |
824 } | |
825 return NULL; | |
826 } | |
827 | |
828 | |
829 /* | |
830 process the compiler options to form the correct set of options | |
831 for obtaining the preprocessor output | |
832 */ | |
833 static void process_args(int argc, char **argv) | |
834 { | |
835 int i; | |
836 int found_c_opt = 0; | |
837 int found_S_opt = 0; | |
838 struct stat st; | |
839 char *e; | |
840 /* is gcc being asked to output dependencies? */ | |
841 int generating_dependencies = 0; | |
842 /* is the dependency makefile name overridden with -MF? */ | |
843 int dependency_filename_specified = 0; | |
844 /* is the dependency makefile target name specified with -MQ or -MF? */ | |
845 int dependency_target_specified = 0; | |
846 | |
847 | |
848 stripped_args = args_init(0, NULL); | |
849 | |
850 args_add(stripped_args, argv[0]); | |
851 | |
852 /* -c not required for SWIG */ | |
853 if (swig) { | |
854 found_c_opt = 1; | |
855 } | |
856 | |
857 for (i=1; i<argc; i++) { | |
858 /* some options will never work ... */ | |
859 if (strcmp(argv[i], "-E") == 0) { | |
860 failed(); | |
861 } | |
862 | |
863 /* these are too hard */ | |
864 if (strcmp(argv[i], "-fbranch-probabilities")==0 || | |
865 strcmp(argv[i], "-fprofile-arcs") == 0 || | |
866 strcmp(argv[i], "-ftest-coverage") == 0 || | |
867 strcmp(argv[i], "--coverage") == 0 || | |
868 strcmp(argv[i], "-M") == 0 || | |
869 strcmp(argv[i], "-MM") == 0 || | |
870 strcmp(argv[i], "-x") == 0) { | |
871 cc_log("argument %s is unsupported\n", argv[i]); | |
872 stats_update(STATS_UNSUPPORTED); | |
873 failed(); | |
874 continue; | |
875 } | |
876 | |
877 /* we must have -c */ | |
878 if (strcmp(argv[i], "-c") == 0) { | |
879 if (!strip_c_option) { | |
880 args_add(stripped_args, argv[i]); | |
881 } | |
882 found_c_opt = 1; | |
883 continue; | |
884 } | |
885 | |
886 /* -S changes the default extension */ | |
887 if (strcmp(argv[i], "-S") == 0) { | |
888 args_add(stripped_args, argv[i]); | |
889 found_S_opt = 1; | |
890 continue; | |
891 } | |
892 | |
893 /* we need to work out where the output was meant to go */ | |
894 if (strcmp(argv[i], "-o") == 0) { | |
895 if (i == argc-1) { | |
896 cc_log("missing argument to %s\n", argv[i]); | |
897 stats_update(STATS_ARGS); | |
898 failed(); | |
899 } | |
900 output_file = argv[i+1]; | |
901 i++; | |
902 continue; | |
903 } | |
904 | |
905 /* alternate form of -o, with no space */ | |
906 if (!swig) { /* some of SWIG's arguments begin with -o */ | |
907 if (strncmp(argv[i], "-o", 2) == 0) { | |
908 output_file = &argv[i][2]; | |
909 continue; | |
910 } | |
911 } | |
912 | |
913 /* debugging is handled specially, so that we know if we | |
914 can strip line number info | |
915 */ | |
916 if (strncmp(argv[i], "-g", 2) == 0) { | |
917 args_add(stripped_args, argv[i]); | |
918 if (strcmp(argv[i], "-g0") != 0) { | |
919 enable_unify = 0; | |
920 } | |
921 continue; | |
922 } | |
923 | |
924 /* The user knows best: just swallow the next arg */ | |
925 if (strcmp(argv[i], "--ccache-skip") == 0) { | |
926 i++; | |
927 if (i == argc) { | |
928 failed(); | |
929 } | |
930 args_add(stripped_args, argv[i]); | |
931 continue; | |
932 } | |
933 | |
934 /* These options require special handling, because they | |
935 behave differently with gcc -E, when the output | |
936 file is not specified. */ | |
937 | |
938 if (strcmp(argv[i], "-MD") == 0 || strcmp(argv[i], "-MMD") == 0) { | |
939 generating_dependencies = 1; | |
940 } else if (strcmp(argv[i], "-MF") == 0) { | |
941 dependency_filename_specified = 1; | |
942 } else if (strcmp(argv[i], "-MQ") == 0 || strcmp(argv[i], "-MT") == 0) { | |
943 dependency_target_specified = 1; | |
944 } | |
945 | |
946 /* the input file is already preprocessed */ | |
947 if (swig && strcmp(argv[i], "-nopreprocess") == 0) { | |
948 direct_i_file = 1; | |
949 continue; | |
950 } | |
951 | |
952 /* options that take an argument */ | |
953 { | |
954 const char *opts[] = {"-I", "-include", "-imacros", "-iprefix", | |
955 "-iwithprefix", "-iwithprefixbefore", | |
956 "-L", "-D", "-U", "-x", "-MF", | |
957 "-MT", "-MQ", "-isystem", "-aux-info", | |
958 "--param", "-A", "-Xlinker", "-u", | |
959 "-idirafter", | |
960 NULL}; | |
961 int j; | |
962 for (j=0;opts[j];j++) { | |
963 if (strcmp(argv[i], opts[j]) == 0) { | |
964 if (i == argc-1) { | |
965 cc_log("missing argument to %s\n", | |
966 argv[i]); | |
967 stats_update(STATS_ARGS); | |
968 failed(); | |
969 } | |
970 | |
971 args_add(stripped_args, argv[i]); | |
972 args_add(stripped_args, argv[i+1]); | |
973 i++; | |
974 break; | |
975 } | |
976 } | |
977 if (opts[j]) continue; | |
978 } | |
979 | |
980 /* other options */ | |
981 if (argv[i][0] == '-') { | |
982 args_add(stripped_args, argv[i]); | |
983 continue; | |
984 } | |
985 | |
986 /* if an argument isn't a plain file then assume its | |
987 an option, not an input file. This allows us to | |
988 cope better with unusual compiler options */ | |
989 if (stat(argv[i], &st) != 0 || !S_ISREG(st.st_mode)) { | |
990 args_add(stripped_args, argv[i]); | |
991 continue; | |
992 } | |
993 | |
994 if (input_file) { | |
995 if (check_extension(argv[i], NULL)) { | |
996 cc_log("multiple input files (%s and %s)\n", | |
997 input_file, argv[i]); | |
998 stats_update(STATS_MULTIPLE); | |
999 } else if (!found_c_opt) { | |
1000 cc_log("called for link with %s\n", argv[i]); | |
1001 if (strstr(argv[i], "conftest.")) { | |
1002 stats_update(STATS_CONFTEST); | |
1003 } else { | |
1004 stats_update(STATS_LINK); | |
1005 } | |
1006 } else { | |
1007 cc_log("non C/C++ file %s\n", argv[i]); | |
1008 stats_update(STATS_NOTC); | |
1009 } | |
1010 failed(); | |
1011 } | |
1012 | |
1013 input_file = argv[i]; | |
1014 } | |
1015 | |
1016 if (!input_file) { | |
1017 cc_log("No input file found\n"); | |
1018 stats_update(STATS_NOINPUT); | |
1019 failed(); | |
1020 } | |
1021 | |
1022 if (swig) { | |
1023 i_extension = check_extension(input_file, NULL); | |
1024 } else { | |
1025 i_extension = check_extension(input_file, &direct_i_file); | |
1026 } | |
1027 if (i_extension == NULL) { | |
1028 cc_log("Not a C/C++ file - %s\n", input_file); | |
1029 stats_update(STATS_NOTC); | |
1030 failed(); | |
1031 } | |
1032 | |
1033 if (!found_c_opt) { | |
1034 cc_log("No -c option found for %s\n", input_file); | |
1035 /* I find that having a separate statistic for autoconf tests is useful, | |
1036 as they are the dominant form of "called for link" in many cases */ | |
1037 if (strstr(input_file, "conftest.")) { | |
1038 stats_update(STATS_CONFTEST); | |
1039 } else { | |
1040 stats_update(STATS_LINK); | |
1041 } | |
1042 failed(); | |
1043 } | |
1044 | |
1045 | |
1046 /* don't try to second guess the compilers heuristics for stdout handling */ | |
1047 if (output_file && strcmp(output_file, "-") == 0) { | |
1048 stats_update(STATS_OUTSTDOUT); | |
1049 failed(); | |
1050 } | |
1051 | |
1052 if (!swig && !output_file) { | |
1053 char *p; | |
1054 output_file = x_strdup(input_file); | |
1055 if ((p = strrchr(output_file, '/'))) { | |
1056 output_file = p+1; | |
1057 } | |
1058 p = strrchr(output_file, '.'); | |
1059 if (!p || !p[1]) { | |
1060 cc_log("badly formed output_file %s\n", output_file); | |
1061 stats_update(STATS_ARGS); | |
1062 failed(); | |
1063 } | |
1064 p[1] = found_S_opt ? 's' : 'o'; | |
1065 p[2] = 0; | |
1066 } | |
1067 | |
1068 /* If dependencies are generated, configure the preprocessor */ | |
1069 | |
1070 if (generating_dependencies && output_file) { | |
1071 if (!dependency_filename_specified) { | |
1072 char *default_depfile_name = x_strdup(output_file); | |
1073 char *p = strrchr(default_depfile_name, '.'); | |
1074 | |
1075 if (p) { | |
1076 if (strlen(p) < 2) { | |
1077 cc_log("badly formed dependency file %s\n", output_file); | |
1078 stats_update(STATS_ARGS); | |
1079 failed(); | |
1080 return; | |
1081 } | |
1082 *p = 0; | |
1083 } | |
1084 else { | |
1085 int len = p - default_depfile_name; | |
1086 | |
1087 p = x_malloc(len + 3); | |
1088 strncpy(default_depfile_name, p, len - 1); | |
1089 free(default_depfile_name); | |
1090 default_depfile_name = p; | |
1091 } | |
1092 | |
1093 strcat(default_depfile_name, ".d"); | |
1094 args_add(stripped_args, "-MF"); | |
1095 args_add(stripped_args, default_depfile_name); | |
1096 } | |
1097 | |
1098 if (!dependency_target_specified) { | |
1099 args_add(stripped_args, "-MT"); | |
1100 args_add(stripped_args, output_file); | |
1101 } | |
1102 } | |
1103 | |
1104 /* cope with -o /dev/null */ | |
1105 if (output_file && strcmp(output_file,"/dev/null") != 0 && stat(output_file, &st) == 0 && !S_ISREG(st.st_mode)) { | |
1106 cc_log("Not a regular file %s\n", output_file); | |
1107 stats_update(STATS_DEVICE); | |
1108 failed(); | |
1109 } | |
1110 | |
1111 if ((e=getenv("CCACHE_PREFIX"))) { | |
1112 char *p = find_executable(e, MYNAME); | |
1113 if (!p) { | |
1114 cc_log("could not find executable (%s)\n", e); | |
1115 stats_update(STATS_ENVIRONMMENT); | |
1116 perror(e); | |
1117 exit(1); | |
1118 } | |
1119 args_add_prefix(stripped_args, p); | |
1120 } | |
1121 } | |
1122 | |
1123 static void detect_swig() | |
1124 { | |
1125 char *basename = str_basename(orig_args->argv[0]); | |
1126 if (strstr(basename, "swig") || getenv("CCACHE_SWIG")) { | |
1127 swig = 1; | |
1128 } | |
1129 free(basename); | |
1130 } | |
1131 | |
1132 /* the main ccache driver function */ | |
1133 static void ccache(int argc, char *argv[]) | |
1134 { | |
1135 /* find the real compiler */ | |
1136 find_compiler(argc, argv); | |
1137 | |
1138 /* use the real compiler if HOME is not set */ | |
1139 if (!cache_dir) { | |
1140 cc_log("Unable to determine home directory\n"); | |
1141 cc_log("ccache is disabled\n"); | |
1142 failed(); | |
1143 } | |
1144 | |
1145 /* we might be disabled */ | |
1146 if (getenv("CCACHE_DISABLE")) { | |
1147 cc_log("ccache is disabled\n"); | |
1148 failed(); | |
1149 } | |
1150 | |
1151 if (getenv("CCACHE_STRIPC")) { | |
1152 strip_c_option = 1; | |
1153 } | |
1154 | |
1155 if (getenv("CCACHE_UNIFY")) { | |
1156 enable_unify = 1; | |
1157 } | |
1158 | |
1159 detect_swig(); | |
1160 | |
1161 /* process argument list, returning a new set of arguments for pre-processing */ | |
1162 process_args(orig_args->argc, orig_args->argv); | |
1163 | |
1164 /* run with -E to find the hash */ | |
1165 find_hash(stripped_args); | |
1166 | |
1167 /* if we can return from cache at this point then do */ | |
1168 from_cache(1); | |
1169 | |
1170 if (getenv("CCACHE_READONLY")) { | |
1171 cc_log("read-only set - doing real compile\n"); | |
1172 failed(); | |
1173 } | |
1174 | |
1175 /* run real compiler, sending output to cache */ | |
1176 to_cache(stripped_args); | |
1177 | |
1178 /* return from cache */ | |
1179 from_cache(0); | |
1180 | |
1181 /* oh oh! */ | |
1182 cc_log("secondary from_cache failed!\n"); | |
1183 stats_update(STATS_ERROR); | |
1184 failed(); | |
1185 } | |
1186 | |
1187 | |
1188 static void usage(void) | |
1189 { | |
1190 printf("%s, a compiler cache including support for SWIG. Version %s\n", MYNAME, CCACHE_VERSION); | |
1191 printf("Copyright Andrew Tridgell, 2002\n\n"); | |
1192 | |
1193 printf("Usage:\n"); | |
1194 printf("\t" MYNAME " [options]\n"); | |
1195 printf("\t" MYNAME " compiler [compile options]\n"); | |
1196 printf("\tcompiler [compile options] (via symbolic link)\n"); | |
1197 printf("\nOptions:\n"); | |
1198 | |
1199 printf("-s show statistics summary\n"); | |
1200 printf("-z zero statistics\n"); | |
1201 printf("-c run a cache cleanup\n"); | |
1202 printf("-C clear the cache completely\n"); | |
1203 printf("-F <maxfiles> set maximum files in cache\n"); | |
1204 printf("-M <maxsize> set maximum size of cache (use G, M or K)\n"); | |
1205 printf("-h this help page\n"); | |
1206 printf("-V print version number\n"); | |
1207 } | |
1208 | |
1209 static void check_cache_dir(void) | |
1210 { | |
1211 if (!cache_dir) { | |
1212 fatal("Unable to determine home directory"); | |
1213 } | |
1214 } | |
1215 | |
1216 /* the main program when not doing a compile */ | |
1217 static int ccache_main(int argc, char *argv[]) | |
1218 { | |
1219 int c; | |
1220 size_t v; | |
1221 | |
1222 while ((c = getopt(argc, argv, "hszcCF:M:V")) != -1) { | |
1223 switch (c) { | |
1224 case 'V': | |
1225 printf("%s version %s\n", MYNAME, CCACHE_VERSION); | |
1226 printf("Copyright Andrew Tridgell 2002\n"); | |
1227 printf("Released under the GNU GPL v2 or later\n"); | |
1228 exit(0); | |
1229 | |
1230 case 'h': | |
1231 usage(); | |
1232 exit(0); | |
1233 | |
1234 case 's': | |
1235 check_cache_dir(); | |
1236 stats_summary(); | |
1237 break; | |
1238 | |
1239 case 'c': | |
1240 check_cache_dir(); | |
1241 cleanup_all(cache_dir); | |
1242 printf("Cleaned cache\n"); | |
1243 break; | |
1244 | |
1245 case 'C': | |
1246 check_cache_dir(); | |
1247 wipe_all(cache_dir); | |
1248 printf("Cleared cache\n"); | |
1249 break; | |
1250 | |
1251 case 'z': | |
1252 check_cache_dir(); | |
1253 stats_zero(); | |
1254 printf("Statistics cleared\n"); | |
1255 break; | |
1256 | |
1257 case 'F': | |
1258 check_cache_dir(); | |
1259 v = atoi(optarg); | |
1260 if (stats_set_limits(v, -1) == 0) { | |
1261 printf("Set cache file limit to %u\n", (unsigned)v); | |
1262 } else { | |
1263 printf("Could not set cache file limit.\n"); | |
1264 exit(1); | |
1265 } | |
1266 break; | |
1267 | |
1268 case 'M': | |
1269 check_cache_dir(); | |
1270 v = value_units(optarg); | |
1271 if (stats_set_limits(-1, v) == 0) { | |
1272 printf("Set cache size limit to %uk\n", (unsigned)v); | |
1273 } else { | |
1274 printf("Could not set cache size limit.\n"); | |
1275 exit(1); | |
1276 } | |
1277 break; | |
1278 | |
1279 default: | |
1280 usage(); | |
1281 exit(1); | |
1282 } | |
1283 } | |
1284 | |
1285 return 0; | |
1286 } | |
1287 | |
1288 | |
1289 /* Make a copy of stderr that will not be cached, so things like | |
1290 distcc can send networking errors to it. */ | |
1291 static void setup_uncached_err(void) | |
1292 { | |
1293 char *buf; | |
1294 int uncached_fd; | |
1295 | |
1296 uncached_fd = dup(2); | |
1297 if (uncached_fd == -1) { | |
1298 cc_log("dup(2) failed\n"); | |
1299 stats_update(STATS_ERROR); | |
1300 failed(); | |
1301 } | |
1302 | |
1303 /* leak a pointer to the environment */ | |
1304 x_asprintf(&buf, "UNCACHED_ERR_FD=%d", uncached_fd); | |
1305 | |
1306 if (putenv(buf) == -1) { | |
1307 cc_log("putenv failed\n"); | |
1308 stats_update(STATS_ERROR); | |
1309 failed(); | |
1310 } | |
1311 } | |
1312 | |
1313 | |
1314 int main(int argc, char *argv[]) | |
1315 { | |
1316 char *p; | |
1317 | |
1318 cache_dir = getenv("CCACHE_DIR"); | |
1319 if (!cache_dir) { | |
1320 const char *home_directory = get_home_directory(); | |
1321 if (home_directory) { | |
1322 x_asprintf(&cache_dir, "%s/.ccache", home_directory); | |
1323 } | |
1324 } | |
1325 | |
1326 cache_logfile = getenv("CCACHE_LOGFILE"); | |
1327 | |
1328 if (getenv("CCACHE_VERBOSE")) { | |
1329 ccache_verbose = 1; | |
1330 } | |
1331 | |
1332 setup_uncached_err(); | |
1333 | |
1334 | |
1335 /* the user might have set CCACHE_UMASK */ | |
1336 p = getenv("CCACHE_UMASK"); | |
1337 if (p) { | |
1338 mode_t mask; | |
1339 errno = 0; | |
1340 mask = strtol(p, NULL, 8); | |
1341 if (errno == 0) { | |
1342 umask(mask); | |
1343 } | |
1344 } | |
1345 | |
1346 | |
1347 /* check if we are being invoked as "ccache" */ | |
1348 if (strlen(argv[0]) >= strlen(MYNAME) && | |
1349 strcmp(argv[0] + strlen(argv[0]) - strlen(MYNAME), MYNAME) == 0) { | |
1350 if (argc < 2) { | |
1351 usage(); | |
1352 exit(1); | |
1353 } | |
1354 /* if the first argument isn't an option, then assume we are | |
1355 being passed a compiler name and options */ | |
1356 if (argv[1][0] == '-') { | |
1357 return ccache_main(argc, argv); | |
1358 } | |
1359 } | |
1360 | |
1361 /* make sure the cache dir exists */ | |
1362 if (cache_dir && (create_dir(cache_dir) != 0)) { | |
1363 fprintf(stderr,"ccache: failed to create %s (%s)\n", | |
1364 cache_dir, strerror(errno)); | |
1365 exit(1); | |
1366 } | |
1367 | |
1368 temp_dir = getenv("CCACHE_TEMPDIR"); | |
1369 if (!temp_dir) { | |
1370 x_asprintf(&temp_dir, "%s/temp", cache_dir); | |
1371 /* make sure temp dir exists if not supplied by user */ | |
1372 if (temp_dir && create_dir(temp_dir) != 0) { | |
1373 fprintf(stderr,"ccache: failed to create %s (%s)\n", | |
1374 temp_dir, strerror(errno)); | |
1375 exit(1); | |
1376 } | |
1377 } | |
1378 | |
1379 if (!getenv("CCACHE_READONLY")) { | |
1380 if (create_cachedirtag(cache_dir) != 0) { | |
1381 fprintf(stderr,"ccache: failed to create %s/CACHEDIR.TAG (%s)\n", | |
1382 cache_dir, strerror(errno)); | |
1383 exit(1); | |
1384 } | |
1385 } | |
1386 | |
1387 ccache(argc, argv); | |
1388 return 1; | |
1389 } |