⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ccache.c

📁 ccache 是一个快速的编译器缓存。当您编译一个程序的时候
💻 C
📖 第 1 页 / 共 2 页
字号:
	}	/* get rid of the intermediate preprocessor file */	if (i_tmpfile) {		if (!direct_i_file) {			unlink(i_tmpfile);		}		free(i_tmpfile);		i_tmpfile = NULL;	}	/* send the cpp stderr, if applicable */	fd_cpp_stderr = open(cpp_stderr, O_RDONLY);	if (fd_cpp_stderr != -1) {		copy_fd(fd_cpp_stderr, 2);		close(fd_cpp_stderr);		unlink(cpp_stderr);		free(cpp_stderr);		cpp_stderr = NULL;	}	/* send the stderr */	copy_fd(fd_stderr, 2);	close(fd_stderr);	/* and exit with the right status code */	if (first) {		cc_log("got cached result for %s\n", output_file);		stats_update(STATS_CACHED);	}	exit(0);}/* find the real compiler. We just search the PATH to find a executable of the    same name that isn't a link to ourselves */static void find_compiler(int argc, char **argv){	char *base;	char *path;	orig_args = args_init(argc, argv);	base = str_basename(argv[0]);	/* we might be being invoked like "ccache gcc -c foo.c" */	if (strcmp(base, MYNAME) == 0) {		args_remove_first(orig_args);		free(base);		if (strchr(argv[1],'/')) {			/* a full path was given */			return;		}		base = str_basename(argv[1]);	}	/* support user override of the compiler */	if ((path=getenv("CCACHE_CC"))) {		base = strdup(path);	}	orig_args->argv[0] = find_executable(base, MYNAME);	/* can't find the compiler! */	if (!orig_args->argv[0]) {		stats_update(STATS_COMPILER);		perror(base);		exit(1);	}}/* check a filename for C/C++ extension. Return the pre-processor   extension */static const char *check_extension(const char *fname, int *direct_i){	int i;	const char *p;	if (direct_i) {		*direct_i = 0;	}	p = strrchr(fname, '.');	if (!p) return NULL;	p++;	for (i=0; extensions[i].extension; i++) {		if (strcmp(p, extensions[i].extension) == 0) {			if (direct_i && strcmp(p, extensions[i].i_extension) == 0) {				*direct_i = 1;			}			p = getenv("CCACHE_EXTENSION");			if (p) return p;			return extensions[i].i_extension;		}	}	return NULL;}/*    process the compiler options to form the correct set of options    for obtaining the preprocessor output*/static void process_args(int argc, char **argv){	int i;	int found_c_opt = 0;	int found_S_opt = 0;	struct stat st;	char *e;	stripped_args = args_init(0, NULL);	args_add(stripped_args, argv[0]);	for (i=1; i<argc; i++) {		/* some options will never work ... */		if (strcmp(argv[i], "-E") == 0) {			failed();		}		/* these are too hard */		if (strcmp(argv[i], "-fbranch-probabilities")==0 ||		    strcmp(argv[i], "-M") == 0 ||		    strcmp(argv[i], "-MM") == 0 ||		    strcmp(argv[i], "-x") == 0) {			cc_log("argument %s is unsupported\n", argv[i]);			stats_update(STATS_UNSUPPORTED);			failed();			continue;		}		/* we must have -c */		if (strcmp(argv[i], "-c") == 0) {			args_add(stripped_args, argv[i]);			found_c_opt = 1;			continue;		}		/* -S changes the default extension */		if (strcmp(argv[i], "-S") == 0) {			args_add(stripped_args, argv[i]);			found_S_opt = 1;			continue;		}				/* we need to work out where the output was meant to go */		if (strcmp(argv[i], "-o") == 0) {			if (i == argc-1) {				cc_log("missing argument to %s\n", argv[i]);				stats_update(STATS_ARGS);				failed();			}			output_file = argv[i+1];			i++;			continue;		}				/* alternate form of -o, with no space */		if (strncmp(argv[i], "-o", 2) == 0) {			output_file = &argv[i][2];			continue;		}		/* debugging is handled specially, so that we know if we		   can strip line number info 		*/		if (strncmp(argv[i], "-g", 2) == 0) {			args_add(stripped_args, argv[i]);			if (strcmp(argv[i], "-g0") != 0) {				enable_unify = 0;			}			continue;		}		/* The user knows best: just swallow the next arg */		if (strcmp(argv[i], "--ccache-skip") == 0) {			i++;			if (i == argc) {				failed();			}			args_add(stripped_args, argv[i]);			continue;		}		/* options that take an argument */		{			const char *opts[] = {"-I", "-include", "-imacros", "-iprefix",					      "-iwithprefix", "-iwithprefixbefore",					      "-L", "-D", "-U", "-x", "-MF", 					      "-MT", "-MQ", "-isystem", "-aux-info",					      "--param", "-A", "-Xlinker", "-u",					      "-idirafter", 					      NULL};			int j;			for (j=0;opts[j];j++) {				if (strcmp(argv[i], opts[j]) == 0) {					if (i == argc-1) {						cc_log("missing argument to %s\n", 						       argv[i]);						stats_update(STATS_ARGS);						failed();					}											args_add(stripped_args, argv[i]);					args_add(stripped_args, argv[i+1]);					i++;					break;				}			}			if (opts[j]) continue;		}		/* other options */		if (argv[i][0] == '-') {			args_add(stripped_args, argv[i]);			continue;		}		/* if an argument isn't a plain file then assume its		   an option, not an input file. This allows us to		   cope better with unusual compiler options */		if (stat(argv[i], &st) != 0 || !S_ISREG(st.st_mode)) {			args_add(stripped_args, argv[i]);			continue;					}		if (input_file) {			if (check_extension(argv[i], NULL)) {				cc_log("multiple input files (%s and %s)\n",				       input_file, argv[i]);				stats_update(STATS_MULTIPLE);			} else if (!found_c_opt) {				cc_log("called for link with %s\n", argv[i]);				if (strstr(argv[i], "conftest.")) {					stats_update(STATS_CONFTEST);				} else {					stats_update(STATS_LINK);				}			} else {				cc_log("non C/C++ file %s\n", argv[i]);				stats_update(STATS_NOTC);			}			failed();		}		input_file = argv[i];	}	if (!input_file) {		cc_log("No input file found\n");		stats_update(STATS_NOINPUT);		failed();	}	i_extension = check_extension(input_file, &direct_i_file);	if (i_extension == NULL) {		cc_log("Not a C/C++ file - %s\n", input_file);		stats_update(STATS_NOTC);		failed();	}	if (!found_c_opt) {		cc_log("No -c option found for %s\n", input_file);		/* I find that having a separate statistic for autoconf tests is useful,		   as they are the dominant form of "called for link" in many cases */		if (strstr(input_file, "conftest.")) {			stats_update(STATS_CONFTEST);		} else {			stats_update(STATS_LINK);		}		failed();	}	/* don't try to second guess the compilers heuristics for stdout handling */	if (output_file && strcmp(output_file, "-") == 0) {		stats_update(STATS_OUTSTDOUT);		failed();	}	if (!output_file) {		char *p;		output_file = x_strdup(input_file);		if ((p = strrchr(output_file, '/'))) {			output_file = p+1;		}		p = strrchr(output_file, '.');		if (!p || !p[1]) {			cc_log("badly formed output_file %s\n", output_file);			stats_update(STATS_ARGS);			failed();		}		p[1] = found_S_opt ? 's' : 'o';		p[2] = 0;	}	/* cope with -o /dev/null */	if (strcmp(output_file,"/dev/null") != 0 && stat(output_file, &st) == 0 && !S_ISREG(st.st_mode)) {		cc_log("Not a regular file %s\n", output_file);		stats_update(STATS_DEVICE);		failed();	}	if ((e=getenv("CCACHE_PREFIX"))) {		char *p = find_executable(e, MYNAME);		if (!p) {			perror(e);			exit(1);		}		args_add_prefix(stripped_args, p);	}}/* the main ccache driver function */static void ccache(int argc, char *argv[]){	/* find the real compiler */	find_compiler(argc, argv);		/* we might be disabled */	if (getenv("CCACHE_DISABLE")) {		cc_log("ccache is disabled\n");		failed();	}	if (getenv("CCACHE_UNIFY")) {		enable_unify = 1;	}	/* process argument list, returning a new set of arguments for pre-processing */	process_args(orig_args->argc, orig_args->argv);	/* run with -E to find the hash */	find_hash(stripped_args);	/* if we can return from cache at this point then do */	from_cache(1);		/* run real compiler, sending output to cache */	to_cache(stripped_args);	/* return from cache */	from_cache(0);	/* oh oh! */	cc_log("secondary from_cache failed!\n");	stats_update(STATS_ERROR);	failed();}static void usage(void){	printf("ccache, a compiler cache. Version %s\n", CCACHE_VERSION);	printf("Copyright Andrew Tridgell, 2002\n\n");		printf("Usage:\n");	printf("\tccache [options]\n");	printf("\tccache compiler [compile options]\n");	printf("\tcompiler [compile options]    (via symbolic link)\n");	printf("\nOptions:\n");	printf("-s                      show statistics summary\n");	printf("-z                      zero statistics\n");	printf("-c                      run a cache cleanup\n");	printf("-C                      clear the cache completely\n");	printf("-F <maxfiles>           set maximum files in cache\n");	printf("-M <maxsize>            set maximum size of cache (use G, M or K)\n");	printf("-h                      this help page\n");	printf("-V                      print version number\n");}/* the main program when not doing a compile */static int ccache_main(int argc, char *argv[]){	extern int optind;	int c;	size_t v;	while ((c = getopt(argc, argv, "hszcCF:M:V")) != -1) {		switch (c) {		case 'V':			printf("ccache version %s\n", CCACHE_VERSION);			printf("Copyright Andrew Tridgell 2002\n");			printf("Released under the GNU GPL v2 or later\n");			exit(0);		case 'h':			usage();			exit(0);					case 's':			stats_summary();			break;		case 'c':			cleanup_all(cache_dir);			printf("Cleaned cache\n");			break;		case 'C':			wipe_all(cache_dir);			printf("Cleared cache\n");			break;		case 'z':			stats_zero();			printf("Statistics cleared\n");			break;		case 'F':			v = atoi(optarg);			stats_set_limits(v, -1);			printf("Set cache file limit to %u\n", (unsigned)v);			break;		case 'M':			v = value_units(optarg);			stats_set_limits(-1, v);			printf("Set cache size limit to %uk\n", (unsigned)v);			break;		default:			usage();			exit(1);		}	}	return 0;}/* Make a copy of stderr that will not be cached, so things like   distcc can send networking errors to it. */static void setup_uncached_err(void){	char *buf;	int uncached_fd;		uncached_fd = dup(2);	if (uncached_fd == -1) {		cc_log("dup(2) failed\n");		failed();	}	/* leak a pointer to the environment */	x_asprintf(&buf, "UNCACHED_ERR_FD=%d", uncached_fd);	if (putenv(buf) == -1) {		cc_log("putenv failed\n");		failed();	}}int main(int argc, char *argv[]){	char *p;	cache_dir = getenv("CCACHE_DIR");	if (!cache_dir) {		x_asprintf(&cache_dir, "%s/.ccache", getenv("HOME"));	}	cache_logfile = getenv("CCACHE_LOGFILE");	setup_uncached_err();		/* the user might have set CCACHE_UMASK */	p = getenv("CCACHE_UMASK");	if (p) {		mode_t mask;		errno = 0;		mask = strtol(p, NULL, 8);		if (errno == 0) {			umask(mask);		}	}	/* check if we are being invoked as "ccache" */	if (strlen(argv[0]) >= strlen(MYNAME) &&	    strcmp(argv[0] + strlen(argv[0]) - strlen(MYNAME), MYNAME) == 0) {		if (argc < 2) {			usage();			exit(1);		}		/* if the first argument isn't an option, then assume we are		   being passed a compiler name and options */		if (argv[1][0] == '-') {			return ccache_main(argc, argv);		}	}	/* make sure the cache dir exists */	if (create_dir(cache_dir) != 0) {		fprintf(stderr,"ccache: failed to create %s (%s)\n", 			cache_dir, strerror(errno));		exit(1);	}	ccache(argc, argv);	return 1;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -