~ubuntu-branches/ubuntu/saucy/ccache/saucy

« back to all changes in this revision

Viewing changes to ccache.c

  • Committer: Bazaar Package Importer
  • Author(s): Frank Lichtenheld
  • Date: 2004-03-19 11:14:50 UTC
  • Revision ID: james.westby@ubuntu.com-20040319111450-s80t5r15j817edtn
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
/* the base cache directory */
 
27
char *cache_dir = NULL;
 
28
 
 
29
/* the debug logfile name, if set */
 
30
char *cache_logfile = NULL;
 
31
 
 
32
/* the argument list after processing */
 
33
static ARGS *stripped_args;
 
34
 
 
35
/* the original argument list */
 
36
static ARGS *orig_args;
 
37
 
 
38
/* the output filename being compiled to */
 
39
static char *output_file;
 
40
 
 
41
/* the source file */
 
42
static char *input_file;
 
43
 
 
44
/* the name of the file containing the cached object code */
 
45
static char *hashname;
 
46
 
 
47
/* the extension of the file after pre-processing */
 
48
static const char *i_extension;
 
49
 
 
50
/* the name of the temporary pre-processor file */
 
51
static char *i_tmpfile;
 
52
 
 
53
/* are we compiling a .i or .ii file directly? */
 
54
static int direct_i_file;
 
55
 
 
56
/* the name of the cpp stderr file */
 
57
static char *cpp_stderr;
 
58
 
 
59
/* the name of the statistics file */
 
60
char *stats_file = NULL;
 
61
 
 
62
/* can we safely use the unification hashing backend? */
 
63
static int enable_unify;
 
64
 
 
65
/* a list of supported file extensions, and the equivalent
 
66
   extension for code that has been through the pre-processor
 
67
*/
 
68
static struct {
 
69
        char *extension;
 
70
        char *i_extension;
 
71
} extensions[] = {
 
72
        {"c", "i"},
 
73
        {"C", "ii"},
 
74
        {"m", "mi"},
 
75
        {"cc", "ii"},
 
76
        {"CC", "ii"},
 
77
        {"cpp", "ii"},
 
78
        {"CPP", "ii"},
 
79
        {"cxx", "ii"},
 
80
        {"CXX", "ii"},
 
81
        {"c++", "ii"},
 
82
        {"C++", "ii"},
 
83
        {"i", "i"},
 
84
        {"ii", "ii"},
 
85
        {NULL, NULL}};
 
86
 
 
87
/*
 
88
  something went badly wrong - just execute the real compiler
 
89
*/
 
90
static void failed(void)
 
91
{
 
92
        char *e;
 
93
 
 
94
        /* delete intermediate pre-processor file if needed */
 
95
        if (i_tmpfile) {
 
96
                if (!direct_i_file) {
 
97
                        unlink(i_tmpfile);
 
98
                }
 
99
                free(i_tmpfile);
 
100
                i_tmpfile = NULL;
 
101
        }
 
102
 
 
103
        /* delete the cpp stderr file if necessary */
 
104
        if (cpp_stderr) {
 
105
                unlink(cpp_stderr);
 
106
                free(cpp_stderr);
 
107
                cpp_stderr = NULL;
 
108
        }
 
109
 
 
110
        /* strip any local args */
 
111
        args_strip(orig_args, "--ccache-");
 
112
 
 
113
        if ((e=getenv("CCACHE_PREFIX"))) {
 
114
                char *p = find_executable(e, MYNAME);
 
115
                if (!p) {
 
116
                        perror(e);
 
117
                        exit(1);
 
118
                }
 
119
                args_add_prefix(orig_args, p);
 
120
        }
 
121
 
 
122
        execv(orig_args->argv[0], orig_args->argv);
 
123
        cc_log("execv returned (%s)!\n", strerror(errno));
 
124
        perror(orig_args->argv[0]);
 
125
        exit(1);
 
126
}
 
127
 
 
128
 
 
129
/* return a string to be used to distinguish temporary files 
 
130
   this also tries to cope with NFS by adding the local hostname 
 
131
*/
 
132
static const char *tmp_string(void)
 
133
{
 
134
        static char *ret;
 
135
 
 
136
        if (!ret) {
 
137
                char hostname[200];
 
138
                strcpy(hostname, "unknown");
 
139
#if HAVE_GETHOSTNAME
 
140
                gethostname(hostname, sizeof(hostname)-1);
 
141
#endif
 
142
                hostname[sizeof(hostname)-1] = 0;
 
143
                asprintf(&ret, "%s.%u", hostname, (unsigned)getpid());
 
144
        }
 
145
 
 
146
        return ret;
 
147
}
 
148
 
 
149
 
 
150
/* run the real compiler and put the result in cache */
 
151
static void to_cache(ARGS *args)
 
152
{
 
153
        char *path_stderr;
 
154
        char *tmp_stdout, *tmp_stderr, *tmp_hashname;
 
155
        struct stat st1, st2;
 
156
        int status;
 
157
 
 
158
        x_asprintf(&tmp_stdout, "%s/tmp.stdout.%s", cache_dir, tmp_string());
 
159
        x_asprintf(&tmp_stderr, "%s/tmp.stderr.%s", cache_dir, tmp_string());
 
160
        x_asprintf(&tmp_hashname, "%s/tmp.hash.%s.o", cache_dir, tmp_string());
 
161
 
 
162
        args_add(args, "-o");
 
163
        args_add(args, tmp_hashname);
 
164
 
 
165
        /* Turn off DEPENDENCIES_OUTPUT when running cc1, because
 
166
         * otherwise it will emit a line like
 
167
         *
 
168
         *  tmp.stdout.vexed.732.o: /home/mbp/.ccache/tmp.stdout.vexed.732.i
 
169
         *
 
170
         * unsetenv() is on BSD and Linux but not portable. */
 
171
        putenv("DEPENDENCIES_OUTPUT");
 
172
        
 
173
        if (getenv("CCACHE_CPP2")) {
 
174
                args_add(args, input_file);
 
175
        } else {
 
176
                args_add(args, i_tmpfile);
 
177
        }
 
178
        status = execute(args->argv, tmp_stdout, tmp_stderr);
 
179
        args_pop(args, 3);
 
180
 
 
181
        if (stat(tmp_stdout, &st1) != 0 || st1.st_size != 0) {
 
182
                cc_log("compiler produced stdout for %s\n", output_file);
 
183
                stats_update(STATS_STDOUT);
 
184
                unlink(tmp_stdout);
 
185
                unlink(tmp_stderr);
 
186
                unlink(tmp_hashname);
 
187
                failed();
 
188
        }
 
189
        unlink(tmp_stdout);
 
190
 
 
191
        if (status != 0) {
 
192
                int fd;
 
193
                cc_log("compile of %s gave status = %d\n", output_file, status);
 
194
                stats_update(STATS_STATUS);
 
195
 
 
196
                fd = open(tmp_stderr, O_RDONLY);
 
197
                if (fd != -1) {
 
198
                        if (strcmp(output_file, "/dev/null") == 0 ||
 
199
                            rename(tmp_hashname, output_file) == 0 || errno == ENOENT) {
 
200
                                if (cpp_stderr) {
 
201
                                        /* we might have some stderr from cpp */
 
202
                                        int fd2 = open(cpp_stderr, O_RDONLY);
 
203
                                        if (fd2 != -1) {
 
204
                                                copy_fd(fd2, 2);
 
205
                                                close(fd2);
 
206
                                                unlink(cpp_stderr);
 
207
                                                cpp_stderr = NULL;
 
208
                                        }
 
209
                                }
 
210
 
 
211
                                /* we can use a quick method of
 
212
                                   getting the failed output */
 
213
                                copy_fd(fd, 2);
 
214
                                close(fd);
 
215
                                unlink(tmp_stderr);
 
216
                                if (i_tmpfile && !direct_i_file) {
 
217
                                        unlink(i_tmpfile);
 
218
                                }
 
219
                                exit(status);
 
220
                        }
 
221
                }
 
222
                
 
223
                unlink(tmp_stderr);
 
224
                unlink(tmp_hashname);
 
225
                failed();
 
226
        }
 
227
 
 
228
        x_asprintf(&path_stderr, "%s.stderr", hashname);
 
229
 
 
230
        if (stat(tmp_stderr, &st1) != 0 ||
 
231
            stat(tmp_hashname, &st2) != 0 ||
 
232
            rename(tmp_hashname, hashname) != 0 ||
 
233
            rename(tmp_stderr, path_stderr) != 0) {
 
234
                cc_log("failed to rename tmp files - %s\n", strerror(errno));
 
235
                stats_update(STATS_ERROR);
 
236
                failed();
 
237
        }
 
238
 
 
239
        cc_log("Placed %s into cache\n", output_file);
 
240
        stats_tocache(file_size(&st1) + file_size(&st2));
 
241
 
 
242
        free(tmp_hashname);
 
243
        free(tmp_stderr);
 
244
        free(tmp_stdout);
 
245
        free(path_stderr);
 
246
}
 
247
 
 
248
/* find the hash for a command. The hash includes all argument lists,
 
249
   plus the output from running the compiler with -E */
 
250
static void find_hash(ARGS *args)
 
251
{
 
252
        int i;
 
253
        char *path_stdout, *path_stderr;
 
254
        char *hash_dir;
 
255
        char *s;
 
256
        struct stat st;
 
257
        int status;
 
258
        int nlevels = 2;
 
259
        char *input_base;
 
260
        char *tmp;
 
261
        
 
262
        if ((s = getenv("CCACHE_NLEVELS"))) {
 
263
                nlevels = atoi(s);
 
264
                if (nlevels < 1) nlevels = 1;
 
265
                if (nlevels > 8) nlevels = 8;
 
266
        }
 
267
 
 
268
        hash_start();
 
269
 
 
270
        /* when we are doing the unifying tricks we need to include
 
271
           the input file name in the hash to get the warnings right */
 
272
        if (enable_unify) {
 
273
                hash_string(input_file);
 
274
        }
 
275
 
 
276
        /* we have to hash the extension, as a .i file isn't treated the same
 
277
           by the compiler as a .ii file */
 
278
        hash_string(i_extension);
 
279
 
 
280
        /* first the arguments */
 
281
        for (i=1;i<args->argc;i++) {
 
282
                /* some arguments don't contribute to the hash. The
 
283
                   theory is that these arguments will change the
 
284
                   output of -E if they are going to have any effect
 
285
                   at all, or they only affect linking */
 
286
                if (i < args->argc-1) {
 
287
                        if (strcmp(args->argv[i], "-I") == 0 ||
 
288
                            strcmp(args->argv[i], "-include") == 0 ||
 
289
                            strcmp(args->argv[i], "-L") == 0 ||
 
290
                            strcmp(args->argv[i], "-D") == 0 ||
 
291
                            strcmp(args->argv[i], "-idirafter") == 0 ||
 
292
                            strcmp(args->argv[i], "-isystem") == 0) {
 
293
                                i++;
 
294
                                continue;
 
295
                        }
 
296
                }
 
297
                if (strncmp(args->argv[i], "-I", 2) == 0 ||
 
298
                    strncmp(args->argv[i], "-L", 2) == 0 ||
 
299
                    strncmp(args->argv[i], "-D", 2) == 0 ||
 
300
                    strncmp(args->argv[i], "-idirafter", 10) == 0 ||
 
301
                    strncmp(args->argv[i], "-isystem", 8) == 0) {
 
302
                        continue;
 
303
                }
 
304
 
 
305
                if (strncmp(args->argv[i], "--specs=", 8) == 0 &&
 
306
                    stat(args->argv[i]+8, &st) == 0) {
 
307
                        /* if given a explicit specs file, then hash that file, but
 
308
                           don't include the path to it in the hash */
 
309
                        hash_file(args->argv[i]+8);
 
310
                        continue;
 
311
                }
 
312
 
 
313
                /* all other arguments are included in the hash */
 
314
                hash_string(args->argv[i]);
 
315
        }
 
316
 
 
317
        /* the compiler driver size and date. This is a simple minded way
 
318
           to try and detect compiler upgrades. It is not 100% reliable */
 
319
        if (stat(args->argv[0], &st) != 0) {
 
320
                cc_log("Couldn't stat the compiler!? (argv[0]='%s')\n", args->argv[0]);
 
321
                stats_update(STATS_COMPILER);
 
322
                failed();
 
323
        }
 
324
        hash_int(st.st_size);
 
325
        hash_int(st.st_mtime);
 
326
 
 
327
        /* possibly hash the current working directory */
 
328
        if (getenv("CCACHE_HASHDIR")) {
 
329
                char *cwd = gnu_getcwd();
 
330
                if (cwd) {
 
331
                        hash_string(cwd);
 
332
                        free(cwd);
 
333
                }
 
334
        }
 
335
 
 
336
        /* ~/hello.c -> tmp.hello.123.i 
 
337
           limit the basename to 10
 
338
           characters in order to cope with filesystem with small
 
339
           maximum filename length limits */
 
340
        input_base = str_basename(input_file);
 
341
        tmp = strchr(input_base, '.');
 
342
        if (tmp != NULL) {
 
343
                *tmp = 0;
 
344
        }
 
345
        if (strlen(input_base) > 10) {
 
346
                input_base[10] = 0;
 
347
        }
 
348
 
 
349
        /* now the run */
 
350
        x_asprintf(&path_stdout, "%s/%s.tmp.%s.%s", cache_dir,
 
351
                   input_base, tmp_string(), 
 
352
                   i_extension);
 
353
        x_asprintf(&path_stderr, "%s/tmp.cpp_stderr.%s", cache_dir, tmp_string());
 
354
 
 
355
        if (!direct_i_file) {
 
356
                /* run cpp on the input file to obtain the .i */
 
357
                args_add(args, "-E");
 
358
                args_add(args, input_file);
 
359
                status = execute(args->argv, path_stdout, path_stderr);
 
360
                args_pop(args, 2);
 
361
        } else {
 
362
                /* we are compiling a .i or .ii file - that means we
 
363
                   can skip the cpp stage and directly form the
 
364
                   correct i_tmpfile */
 
365
                path_stdout = input_file;
 
366
                if (create_empty_file(path_stderr) != 0) {
 
367
                        stats_update(STATS_ERROR);
 
368
                        cc_log("failed to create empty stderr file\n");
 
369
                        failed();
 
370
                }
 
371
                status = 0;
 
372
        }
 
373
 
 
374
        if (status != 0) {
 
375
                if (!direct_i_file) {
 
376
                        unlink(path_stdout);
 
377
                }
 
378
                unlink(path_stderr);
 
379
                cc_log("the preprocessor gave %d\n", status);
 
380
                stats_update(STATS_PREPROCESSOR);
 
381
                failed();
 
382
        }
 
383
 
 
384
        /* if the compilation is with -g then we have to include the whole of the
 
385
           preprocessor output, which means we are sensitive to line number
 
386
           information. Otherwise we can discard line number info, which makes
 
387
           us less sensitive to reformatting changes 
 
388
 
 
389
           Note! I have now disabled the unification code by default
 
390
           as it gives the wrong line numbers for warnings. Pity.
 
391
        */
 
392
        if (!enable_unify) {
 
393
                hash_file(path_stdout);
 
394
        } else {
 
395
                if (unify_hash(path_stdout) != 0) {
 
396
                        stats_update(STATS_ERROR);
 
397
                        failed();
 
398
                }
 
399
        }
 
400
        hash_file(path_stderr);
 
401
 
 
402
        i_tmpfile = path_stdout;
 
403
 
 
404
        if (!getenv("CCACHE_CPP2")) {
 
405
                /* if we are using the CPP trick then we need to remember this stderr
 
406
                   data and output it just before the main stderr from the compiler
 
407
                   pass */
 
408
                cpp_stderr = path_stderr;
 
409
        } else {        
 
410
                unlink(path_stderr);
 
411
                free(path_stderr);
 
412
        }
 
413
 
 
414
        /* we use a N level subdir for the cache path to reduce the impact
 
415
           on filesystems which are slow for large directories
 
416
        */
 
417
        s = hash_result();
 
418
        x_asprintf(&hash_dir, "%s/%c", cache_dir, s[0]);
 
419
        x_asprintf(&stats_file, "%s/stats", hash_dir);
 
420
        for (i=1; i<nlevels; i++) {
 
421
                char *p;
 
422
                if (create_dir(hash_dir) != 0) {
 
423
                        cc_log("failed to create %s\n", hash_dir);
 
424
                        failed();
 
425
                }
 
426
                x_asprintf(&p, "%s/%c", hash_dir, s[i]);
 
427
                free(hash_dir);
 
428
                hash_dir = p;
 
429
        }
 
430
        if (create_dir(hash_dir) != 0) {
 
431
                cc_log("failed to create %s\n", hash_dir);
 
432
                failed();
 
433
        }
 
434
        x_asprintf(&hashname, "%s/%s", hash_dir, s+nlevels);
 
435
        free(hash_dir);
 
436
}
 
437
 
 
438
 
 
439
/* 
 
440
   try to return the compile result from cache. If we can return from
 
441
   cache then this function exits with the correct status code,
 
442
   otherwise it returns */
 
443
static void from_cache(int first)
 
444
{
 
445
        int fd_stderr, fd_cpp_stderr;
 
446
        char *stderr_file;
 
447
        int ret;
 
448
        struct stat st;
 
449
 
 
450
        x_asprintf(&stderr_file, "%s.stderr", hashname);
 
451
        fd_stderr = open(stderr_file, O_RDONLY);
 
452
        if (fd_stderr == -1) {
 
453
                /* it isn't in cache ... */
 
454
                free(stderr_file);
 
455
                return;
 
456
        }
 
457
 
 
458
        /* make sure the output is there too */
 
459
        if (stat(hashname, &st) != 0) {
 
460
                close(fd_stderr);
 
461
                unlink(stderr_file);
 
462
                free(stderr_file);
 
463
                return;
 
464
        }
 
465
 
 
466
        /* the user might be disabling cache hits */
 
467
        if (first && getenv("CCACHE_RECACHE")) {
 
468
                close(fd_stderr);
 
469
                unlink(stderr_file);
 
470
                free(stderr_file);
 
471
                return;
 
472
        }
 
473
 
 
474
        utime(stderr_file, NULL);
 
475
 
 
476
        if (strcmp(output_file, "/dev/null") == 0) {
 
477
                ret = 0;
 
478
        } else {
 
479
                unlink(output_file);
 
480
                if (getenv("CCACHE_HARDLINK")) {
 
481
                        ret = link(hashname, output_file);
 
482
                } else {
 
483
                        ret = copy_file(hashname, output_file);
 
484
                }
 
485
        }
 
486
 
 
487
        /* the hash file might have been deleted by some external process */
 
488
        if (ret == -1 && errno == ENOENT) {
 
489
                cc_log("hashfile missing for %s\n", output_file);
 
490
                stats_update(STATS_MISSING);
 
491
                close(fd_stderr);
 
492
                unlink(stderr_file);
 
493
                return;
 
494
        }
 
495
        free(stderr_file);
 
496
 
 
497
        if (ret == -1) {
 
498
                ret = copy_file(hashname, output_file);
 
499
                if (ret == -1) {
 
500
                        cc_log("failed to copy %s -> %s (%s)\n", 
 
501
                               hashname, output_file, strerror(errno));
 
502
                        stats_update(STATS_ERROR);
 
503
                        failed();
 
504
                }
 
505
        }
 
506
        if (ret == 0) {
 
507
                /* update the mtime on the file so that make doesn't get confused */
 
508
                utime(output_file, NULL);
 
509
        }
 
510
 
 
511
        /* get rid of the intermediate preprocessor file */
 
512
        if (i_tmpfile) {
 
513
                if (!direct_i_file) {
 
514
                        unlink(i_tmpfile);
 
515
                }
 
516
                free(i_tmpfile);
 
517
                i_tmpfile = NULL;
 
518
        }
 
519
 
 
520
        /* send the cpp stderr, if applicable */
 
521
        fd_cpp_stderr = open(cpp_stderr, O_RDONLY);
 
522
        if (fd_cpp_stderr != -1) {
 
523
                copy_fd(fd_cpp_stderr, 2);
 
524
                close(fd_cpp_stderr);
 
525
                unlink(cpp_stderr);
 
526
                free(cpp_stderr);
 
527
                cpp_stderr = NULL;
 
528
        }
 
529
 
 
530
        /* send the stderr */
 
531
        copy_fd(fd_stderr, 2);
 
532
        close(fd_stderr);
 
533
 
 
534
        /* and exit with the right status code */
 
535
        if (first) {
 
536
                cc_log("got cached result for %s\n", output_file);
 
537
                stats_update(STATS_CACHED);
 
538
        }
 
539
 
 
540
        exit(0);
 
541
}
 
542
 
 
543
/* find the real compiler. We just search the PATH to find a executable of the 
 
544
   same name that isn't a link to ourselves */
 
545
static void find_compiler(int argc, char **argv)
 
546
{
 
547
        char *base;
 
548
        char *path;
 
549
 
 
550
        orig_args = args_init(argc, argv);
 
551
 
 
552
        base = str_basename(argv[0]);
 
553
 
 
554
        /* we might be being invoked like "ccache gcc -c foo.c" */
 
555
        if (strcmp(base, MYNAME) == 0) {
 
556
                args_remove_first(orig_args);
 
557
                free(base);
 
558
                if (strchr(argv[1],'/')) {
 
559
                        /* a full path was given */
 
560
                        return;
 
561
                }
 
562
                base = str_basename(argv[1]);
 
563
        }
 
564
 
 
565
        /* support user override of the compiler */
 
566
        if ((path=getenv("CCACHE_CC"))) {
 
567
                base = strdup(path);
 
568
        }
 
569
 
 
570
        orig_args->argv[0] = find_executable(base, MYNAME);
 
571
 
 
572
        /* can't find the compiler! */
 
573
        if (!orig_args->argv[0]) {
 
574
                stats_update(STATS_COMPILER);
 
575
                perror(base);
 
576
                exit(1);
 
577
        }
 
578
}
 
579
 
 
580
 
 
581
/* check a filename for C/C++ extension. Return the pre-processor
 
582
   extension */
 
583
static const char *check_extension(const char *fname, int *direct_i)
 
584
{
 
585
        int i;
 
586
        const char *p;
 
587
 
 
588
        if (direct_i) {
 
589
                *direct_i = 0;
 
590
        }
 
591
 
 
592
        p = strrchr(fname, '.');
 
593
        if (!p) return NULL;
 
594
        p++;
 
595
        for (i=0; extensions[i].extension; i++) {
 
596
                if (strcmp(p, extensions[i].extension) == 0) {
 
597
                        if (direct_i && strcmp(p, extensions[i].i_extension) == 0) {
 
598
                                *direct_i = 1;
 
599
                        }
 
600
                        p = getenv("CCACHE_EXTENSION");
 
601
                        if (p) return p;
 
602
                        return extensions[i].i_extension;
 
603
                }
 
604
        }
 
605
        return NULL;
 
606
}
 
607
 
 
608
 
 
609
/* 
 
610
   process the compiler options to form the correct set of options 
 
611
   for obtaining the preprocessor output
 
612
*/
 
613
static void process_args(int argc, char **argv)
 
614
{
 
615
        int i;
 
616
        int found_c_opt = 0;
 
617
        int found_S_opt = 0;
 
618
        struct stat st;
 
619
        char *e;
 
620
 
 
621
        stripped_args = args_init(0, NULL);
 
622
 
 
623
        args_add(stripped_args, argv[0]);
 
624
 
 
625
        for (i=1; i<argc; i++) {
 
626
                /* some options will never work ... */
 
627
                if (strcmp(argv[i], "-E") == 0) {
 
628
                        failed();
 
629
                }
 
630
 
 
631
                /* these are too hard */
 
632
                if (strcmp(argv[i], "-fbranch-probabilities")==0 ||
 
633
                    strcmp(argv[i], "-M") == 0 ||
 
634
                    strcmp(argv[i], "-MM") == 0 ||
 
635
                    strcmp(argv[i], "-x") == 0) {
 
636
                        cc_log("argument %s is unsupported\n", argv[i]);
 
637
                        stats_update(STATS_UNSUPPORTED);
 
638
                        failed();
 
639
                        continue;
 
640
                }
 
641
 
 
642
                /* we must have -c */
 
643
                if (strcmp(argv[i], "-c") == 0) {
 
644
                        args_add(stripped_args, argv[i]);
 
645
                        found_c_opt = 1;
 
646
                        continue;
 
647
                }
 
648
 
 
649
                /* -S changes the default extension */
 
650
                if (strcmp(argv[i], "-S") == 0) {
 
651
                        args_add(stripped_args, argv[i]);
 
652
                        found_S_opt = 1;
 
653
                        continue;
 
654
                }
 
655
                
 
656
                /* we need to work out where the output was meant to go */
 
657
                if (strcmp(argv[i], "-o") == 0) {
 
658
                        if (i == argc-1) {
 
659
                                cc_log("missing argument to %s\n", argv[i]);
 
660
                                stats_update(STATS_ARGS);
 
661
                                failed();
 
662
                        }
 
663
                        output_file = argv[i+1];
 
664
                        i++;
 
665
                        continue;
 
666
                }
 
667
                
 
668
                /* alternate form of -o, with no space */
 
669
                if (strncmp(argv[i], "-o", 2) == 0) {
 
670
                        output_file = &argv[i][2];
 
671
                        continue;
 
672
                }
 
673
 
 
674
                /* debugging is handled specially, so that we know if we
 
675
                   can strip line number info 
 
676
                */
 
677
                if (strncmp(argv[i], "-g", 2) == 0) {
 
678
                        args_add(stripped_args, argv[i]);
 
679
                        if (strcmp(argv[i], "-g0") != 0) {
 
680
                                enable_unify = 0;
 
681
                        }
 
682
                        continue;
 
683
                }
 
684
 
 
685
                /* The user knows best: just swallow the next arg */
 
686
                if (strcmp(argv[i], "--ccache-skip") == 0) {
 
687
                        i++;
 
688
                        if (i == argc) {
 
689
                                failed();
 
690
                        }
 
691
                        args_add(stripped_args, argv[i]);
 
692
                        continue;
 
693
                }
 
694
 
 
695
                /* options that take an argument */
 
696
                {
 
697
                        const char *opts[] = {"-I", "-include", "-imacros", "-iprefix",
 
698
                                              "-iwithprefix", "-iwithprefixbefore",
 
699
                                              "-L", "-D", "-U", "-x", "-MF", 
 
700
                                              "-MT", "-MQ", "-isystem", "-aux-info",
 
701
                                              "--param", "-A", "-Xlinker", "-u",
 
702
                                              "-idirafter", 
 
703
                                              NULL};
 
704
                        int j;
 
705
                        for (j=0;opts[j];j++) {
 
706
                                if (strcmp(argv[i], opts[j]) == 0) {
 
707
                                        if (i == argc-1) {
 
708
                                                cc_log("missing argument to %s\n", 
 
709
                                                       argv[i]);
 
710
                                                stats_update(STATS_ARGS);
 
711
                                                failed();
 
712
                                        }
 
713
                                                
 
714
                                        args_add(stripped_args, argv[i]);
 
715
                                        args_add(stripped_args, argv[i+1]);
 
716
                                        i++;
 
717
                                        break;
 
718
                                }
 
719
                        }
 
720
                        if (opts[j]) continue;
 
721
                }
 
722
 
 
723
                /* other options */
 
724
                if (argv[i][0] == '-') {
 
725
                        args_add(stripped_args, argv[i]);
 
726
                        continue;
 
727
                }
 
728
 
 
729
                /* if an argument isn't a plain file then assume its
 
730
                   an option, not an input file. This allows us to
 
731
                   cope better with unusual compiler options */
 
732
                if (stat(argv[i], &st) != 0 || !S_ISREG(st.st_mode)) {
 
733
                        args_add(stripped_args, argv[i]);
 
734
                        continue;                       
 
735
                }
 
736
 
 
737
                if (input_file) {
 
738
                        if (check_extension(argv[i], NULL)) {
 
739
                                cc_log("multiple input files (%s and %s)\n",
 
740
                                       input_file, argv[i]);
 
741
                                stats_update(STATS_MULTIPLE);
 
742
                        } else if (!found_c_opt) {
 
743
                                cc_log("called for link with %s\n", argv[i]);
 
744
                                if (strstr(argv[i], "conftest.")) {
 
745
                                        stats_update(STATS_CONFTEST);
 
746
                                } else {
 
747
                                        stats_update(STATS_LINK);
 
748
                                }
 
749
                        } else {
 
750
                                cc_log("non C/C++ file %s\n", argv[i]);
 
751
                                stats_update(STATS_NOTC);
 
752
                        }
 
753
                        failed();
 
754
                }
 
755
 
 
756
                input_file = argv[i];
 
757
        }
 
758
 
 
759
        if (!input_file) {
 
760
                cc_log("No input file found\n");
 
761
                stats_update(STATS_NOINPUT);
 
762
                failed();
 
763
        }
 
764
 
 
765
        i_extension = check_extension(input_file, &direct_i_file);
 
766
        if (i_extension == NULL) {
 
767
                cc_log("Not a C/C++ file - %s\n", input_file);
 
768
                stats_update(STATS_NOTC);
 
769
                failed();
 
770
        }
 
771
 
 
772
        if (!found_c_opt) {
 
773
                cc_log("No -c option found for %s\n", input_file);
 
774
                /* I find that having a separate statistic for autoconf tests is useful,
 
775
                   as they are the dominant form of "called for link" in many cases */
 
776
                if (strstr(input_file, "conftest.")) {
 
777
                        stats_update(STATS_CONFTEST);
 
778
                } else {
 
779
                        stats_update(STATS_LINK);
 
780
                }
 
781
                failed();
 
782
        }
 
783
 
 
784
 
 
785
        /* don't try to second guess the compilers heuristics for stdout handling */
 
786
        if (output_file && strcmp(output_file, "-") == 0) {
 
787
                stats_update(STATS_OUTSTDOUT);
 
788
                failed();
 
789
        }
 
790
 
 
791
        if (!output_file) {
 
792
                char *p;
 
793
                output_file = x_strdup(input_file);
 
794
                if ((p = strrchr(output_file, '/'))) {
 
795
                        output_file = p+1;
 
796
                }
 
797
                p = strrchr(output_file, '.');
 
798
                if (!p || !p[1]) {
 
799
                        cc_log("badly formed output_file %s\n", output_file);
 
800
                        stats_update(STATS_ARGS);
 
801
                        failed();
 
802
                }
 
803
                p[1] = found_S_opt ? 's' : 'o';
 
804
                p[2] = 0;
 
805
        }
 
806
 
 
807
        /* cope with -o /dev/null */
 
808
        if (strcmp(output_file,"/dev/null") != 0 && stat(output_file, &st) == 0 && !S_ISREG(st.st_mode)) {
 
809
                cc_log("Not a regular file %s\n", output_file);
 
810
                stats_update(STATS_DEVICE);
 
811
                failed();
 
812
        }
 
813
 
 
814
        if ((e=getenv("CCACHE_PREFIX"))) {
 
815
                char *p = find_executable(e, MYNAME);
 
816
                if (!p) {
 
817
                        perror(e);
 
818
                        exit(1);
 
819
                }
 
820
                args_add_prefix(stripped_args, p);
 
821
        }
 
822
}
 
823
 
 
824
/* the main ccache driver function */
 
825
static void ccache(int argc, char *argv[])
 
826
{
 
827
        /* find the real compiler */
 
828
        find_compiler(argc, argv);
 
829
        
 
830
        /* we might be disabled */
 
831
        if (getenv("CCACHE_DISABLE")) {
 
832
                cc_log("ccache is disabled\n");
 
833
                failed();
 
834
        }
 
835
 
 
836
        if (getenv("CCACHE_UNIFY")) {
 
837
                enable_unify = 1;
 
838
        }
 
839
 
 
840
        /* process argument list, returning a new set of arguments for pre-processing */
 
841
        process_args(orig_args->argc, orig_args->argv);
 
842
 
 
843
        /* run with -E to find the hash */
 
844
        find_hash(stripped_args);
 
845
 
 
846
        /* if we can return from cache at this point then do */
 
847
        from_cache(1);
 
848
        
 
849
        /* run real compiler, sending output to cache */
 
850
        to_cache(stripped_args);
 
851
 
 
852
        /* return from cache */
 
853
        from_cache(0);
 
854
 
 
855
        /* oh oh! */
 
856
        cc_log("secondary from_cache failed!\n");
 
857
        stats_update(STATS_ERROR);
 
858
        failed();
 
859
}
 
860
 
 
861
 
 
862
static void usage(void)
 
863
{
 
864
        printf("ccache, a compiler cache. Version %s\n", CCACHE_VERSION);
 
865
        printf("Copyright Andrew Tridgell, 2002\n\n");
 
866
        
 
867
        printf("Usage:\n");
 
868
        printf("\tccache [options]\n");
 
869
        printf("\tccache compiler [compile options]\n");
 
870
        printf("\tcompiler [compile options]    (via symbolic link)\n");
 
871
        printf("\nOptions:\n");
 
872
 
 
873
        printf("-s                      show statistics summary\n");
 
874
        printf("-z                      zero statistics\n");
 
875
        printf("-c                      run a cache cleanup\n");
 
876
        printf("-C                      clear the cache completely\n");
 
877
        printf("-F <maxfiles>           set maximum files in cache\n");
 
878
        printf("-M <maxsize>            set maximum size of cache (use G, M or K)\n");
 
879
        printf("-h                      this help page\n");
 
880
        printf("-V                      print version number\n");
 
881
}
 
882
 
 
883
/* the main program when not doing a compile */
 
884
static int ccache_main(int argc, char *argv[])
 
885
{
 
886
        extern int optind;
 
887
        int c;
 
888
        size_t v;
 
889
 
 
890
        while ((c = getopt(argc, argv, "hszcCF:M:V")) != -1) {
 
891
                switch (c) {
 
892
                case 'V':
 
893
                        printf("ccache version %s\n", CCACHE_VERSION);
 
894
                        printf("Copyright Andrew Tridgell 2002\n");
 
895
                        printf("Released under the GNU GPL v2 or later\n");
 
896
                        exit(0);
 
897
 
 
898
                case 'h':
 
899
                        usage();
 
900
                        exit(0);
 
901
                        
 
902
                case 's':
 
903
                        stats_summary();
 
904
                        break;
 
905
 
 
906
                case 'c':
 
907
                        cleanup_all(cache_dir);
 
908
                        printf("Cleaned cache\n");
 
909
                        break;
 
910
 
 
911
                case 'C':
 
912
                        wipe_all(cache_dir);
 
913
                        printf("Cleared cache\n");
 
914
                        break;
 
915
 
 
916
                case 'z':
 
917
                        stats_zero();
 
918
                        printf("Statistics cleared\n");
 
919
                        break;
 
920
 
 
921
                case 'F':
 
922
                        v = atoi(optarg);
 
923
                        stats_set_limits(v, -1);
 
924
                        printf("Set cache file limit to %u\n", (unsigned)v);
 
925
                        break;
 
926
 
 
927
                case 'M':
 
928
                        v = value_units(optarg);
 
929
                        stats_set_limits(-1, v);
 
930
                        printf("Set cache size limit to %uk\n", (unsigned)v);
 
931
                        break;
 
932
 
 
933
                default:
 
934
                        usage();
 
935
                        exit(1);
 
936
                }
 
937
        }
 
938
 
 
939
        return 0;
 
940
}
 
941
 
 
942
 
 
943
/* Make a copy of stderr that will not be cached, so things like
 
944
   distcc can send networking errors to it. */
 
945
static void setup_uncached_err(void)
 
946
{
 
947
        char *buf;
 
948
        int uncached_fd;
 
949
        
 
950
        uncached_fd = dup(2);
 
951
        if (uncached_fd == -1) {
 
952
                cc_log("dup(2) failed\n");
 
953
                failed();
 
954
        }
 
955
 
 
956
        /* leak a pointer to the environment */
 
957
        x_asprintf(&buf, "UNCACHED_ERR_FD=%d", uncached_fd);
 
958
 
 
959
        if (putenv(buf) == -1) {
 
960
                cc_log("putenv failed\n");
 
961
                failed();
 
962
        }
 
963
}
 
964
 
 
965
 
 
966
int main(int argc, char *argv[])
 
967
{
 
968
        char *p;
 
969
 
 
970
        cache_dir = getenv("CCACHE_DIR");
 
971
        if (!cache_dir) {
 
972
                x_asprintf(&cache_dir, "%s/.ccache", getenv("HOME"));
 
973
        }
 
974
 
 
975
        cache_logfile = getenv("CCACHE_LOGFILE");
 
976
 
 
977
        setup_uncached_err();
 
978
        
 
979
 
 
980
        /* the user might have set CCACHE_UMASK */
 
981
        p = getenv("CCACHE_UMASK");
 
982
        if (p) {
 
983
                mode_t mask;
 
984
                errno = 0;
 
985
                mask = strtol(p, NULL, 8);
 
986
                if (errno == 0) {
 
987
                        umask(mask);
 
988
                }
 
989
        }
 
990
 
 
991
 
 
992
        /* check if we are being invoked as "ccache" */
 
993
        if (strlen(argv[0]) >= strlen(MYNAME) &&
 
994
            strcmp(argv[0] + strlen(argv[0]) - strlen(MYNAME), MYNAME) == 0) {
 
995
                if (argc < 2) {
 
996
                        usage();
 
997
                        exit(1);
 
998
                }
 
999
                /* if the first argument isn't an option, then assume we are
 
1000
                   being passed a compiler name and options */
 
1001
                if (argv[1][0] == '-') {
 
1002
                        return ccache_main(argc, argv);
 
1003
                }
 
1004
        }
 
1005
 
 
1006
        /* make sure the cache dir exists */
 
1007
        if (create_dir(cache_dir) != 0) {
 
1008
                fprintf(stderr,"ccache: failed to create %s (%s)\n", 
 
1009
                        cache_dir, strerror(errno));
 
1010
                exit(1);
 
1011
        }
 
1012
 
 
1013
        ccache(argc, argv);
 
1014
        return 1;
 
1015
}