#include "ccache.h"
-ARGS *args_init(void)
+ARGS *args_init(int init_argc, char **init_args)
{
ARGS *args;
+ int i;
args = (ARGS *)malloc(sizeof(ARGS));
args->argc = 0;
args->argv = (char **)malloc(sizeof(char *));
args->argv[0] = NULL;
+ for (i=0;i<init_argc;i++) {
+ args_add(args, init_args[i]);
+ }
return args;
}
args->argv[args->argc] = NULL;
}
+/* pop the last element off the args list */
void args_pop(ARGS *args, int n)
{
while (n--) {
}
}
+/* remove the first element of the argument list */
+void args_remove_first(ARGS *args)
+{
+ free(args->argv[0]);
+ memmove(&args->argv[0],
+ &args->argv[1],
+ args->argc * sizeof(args->argv[0]));
+ args->argc--;
+}
+
+/* add an argument into the front of the argument list */
+void args_add_prefix(ARGS *args, const char *s)
+{
+ args->argv = (char**)realloc(args->argv, (args->argc + 2) * sizeof(char *));
+ memmove(&args->argv[1], &args->argv[0],
+ (args->argc+1) * sizeof(args->argv[0]));
+ args->argv[0] = strdup(s);
+ args->argc++;
+}
+
/* strip any arguments beginning with the specified prefix */
void args_strip(ARGS *args, const char *prefix)
{
int i;
for (i=0; i<args->argc; ) {
if (strncmp(args->argv[i], prefix, strlen(prefix)) == 0) {
- if (i < args->argc-1) {
- /* note that we can't free the entry we are removing
- as it may be part of the original argc/argv passed
- to main() */
- memmove(&args->argv[i],
- &args->argv[i+1],
- (args->argc-1) * sizeof(args->argv[i]));
- }
+ free(args->argv[i]);
+ memmove(&args->argv[i],
+ &args->argv[i+1],
+ args->argc * sizeof(args->argv[i]));
args->argc--;
} else {
i++;
*/
static void failed(void)
{
+ char *e;
+
/* delete intermediate pre-processor file if needed */
if (i_tmpfile) {
unlink(i_tmpfile);
/* strip any local args */
args_strip(orig_args, "--ccache-");
+ if ((e=getenv("CCACHE_PREFIX"))) {
+ char *p = find_executable(e, MYNAME);
+ if (!p) {
+ perror(e);
+ exit(1);
+ }
+ args_add_prefix(orig_args, p);
+ }
+
execv(orig_args->argv[0], orig_args->argv);
cc_log("execv returned (%s)!\n", strerror(errno));
perror(orig_args->argv[0]);
/* the compiler driver size and date. This is a simple minded way
to try and detect compiler upgrades. It is not 100% reliable */
if (stat(args->argv[0], &st) != 0) {
- cc_log("Couldn't stat the compiler!?\n");
+ cc_log("Couldn't stat the compiler!? (argv[0]='%s')\n", args->argv[0]);
stats_update(STATS_COMPILER);
failed();
}
static void find_compiler(int argc, char **argv)
{
char *base;
- char *path, *tok;
- struct stat st1, st2;
-
- orig_args = args_init();
- free(orig_args->argv);
+ char *path;
- orig_args->argv = argv;
- orig_args->argc = argc;
+ orig_args = args_init(argc, argv);
base = basename(argv[0]);
/* we might be being invoked like "ccache gcc -c foo.c" */
if (strcmp(base, MYNAME) == 0) {
- orig_args->argv++;
- orig_args->argc--;
+ args_remove_first(orig_args);
free(base);
if (strchr(argv[1],'/')) {
/* a full path was given */
base = strdup(path);
}
- path = getenv("CCACHE_PATH");
- if (!path) {
- path = getenv("PATH");
- }
- if (!path) {
- cc_log("no PATH variable!?\n");
- failed();
- }
-
- path = x_strdup(path);
-
- /* search the path looking for the first compiler of the right name
- that isn't us */
- for (tok=strtok(path,":"); tok; tok = strtok(NULL, ":")) {
- char *fname;
- x_asprintf(&fname, "%s/%s", tok, base);
- /* look for a normal executable file */
- if (access(fname, X_OK) == 0 &&
- lstat(fname, &st1) == 0 &&
- stat(fname, &st2) == 0 &&
- S_ISREG(st2.st_mode)) {
- /* if its a symlink then ensure it doesn't
- point at something called "ccache" */
- if (S_ISLNK(st1.st_mode)) {
- char *buf = x_realpath(fname);
- if (buf) {
- char *p = basename(buf);
- if (strcmp(p, MYNAME) == 0) {
- /* its a link to "ccache" ! */
- free(p);
- free(buf);
- continue;
- }
- free(buf);
- free(p);
- }
- }
-
-
- /* found it! */
- free(path);
- orig_args->argv[0] = fname;
- free(base);
- return;
- }
- free(fname);
- }
+ orig_args->argv[0] = find_executable(base, MYNAME);
/* can't find the compiler! */
- perror(base);
- exit(1);
+ if (!argv[0]) {
+ perror(base);
+ exit(1);
+ }
}
int found_c_opt = 0;
int found_S_opt = 0;
struct stat st;
+ char *e;
- stripped_args = args_init();
+ stripped_args = args_init(0, NULL);
args_add(stripped_args, argv[0]);
}
p[1] = found_S_opt ? 's' : 'o';
p[2] = 0;
-#if 0
- cc_log("Formed output file %s from input_file %s\n",
- output_file, input_file);
-#endif
}
/* cope with -o /dev/null */
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 */
int execute(char **argv,
const char *path_stdout,
const char *path_stderr);
+char *find_executable(const char *name, const char *exclude_name);
typedef struct {
char **argv;
} ARGS;
-ARGS *args_init(void);
+ARGS *args_init(int , char **);
void args_add(ARGS *args, const char *s);
+void args_add_prefix(ARGS *args, const char *s);
void args_pop(ARGS *args, int n);
void args_strip(ARGS *args, const char *prefix);
+void args_remove_first(ARGS *args);
#if HAVE_COMPAR_FN_T
#define COMPAR_FN_T __compar_fn_t
return WEXITSTATUS(status);
}
+
+
+/*
+ find an executable by name in $PATH. Exclude any that are links to exclude_name
+*/
+char *find_executable(const char *name, const char *exclude_name)
+{
+ char *path;
+ char *tok;
+ struct stat st1, st2;
+
+ path = getenv("CCACHE_PATH");
+ if (!path) {
+ path = getenv("PATH");
+ }
+ if (!path) {
+ cc_log("no PATH variable!?\n");
+ return NULL;
+ }
+
+ path = x_strdup(path);
+
+ /* search the path looking for the first compiler of the right name
+ that isn't us */
+ for (tok=strtok(path,":"); tok; tok = strtok(NULL, ":")) {
+ char *fname;
+ x_asprintf(&fname, "%s/%s", tok, name);
+ /* look for a normal executable file */
+ if (access(fname, X_OK) == 0 &&
+ lstat(fname, &st1) == 0 &&
+ stat(fname, &st2) == 0 &&
+ S_ISREG(st2.st_mode)) {
+ /* if its a symlink then ensure it doesn't
+ point at something called exclude_name */
+ if (S_ISLNK(st1.st_mode)) {
+ char *buf = x_realpath(fname);
+ if (buf) {
+ char *p = basename(buf);
+ if (strcmp(p, exclude_name) == 0) {
+ /* its a link to "ccache" ! */
+ free(p);
+ free(buf);
+ continue;
+ }
+ free(buf);
+ free(p);
+ }
+ }
+
+ /* found it! */
+ free(path);
+ return fname;
+ }
+ free(fname);
+ }
+
+ return NULL;
+}