Пример #1
0
static void *
_gcry_secmem_malloc_internal (size_t size)
{
  memblock_t *mb;

  if (!pool_okay)
    {
      log_info (_
	("operation is not possible without initialized secure memory\n"));
      exit (2);
    }
  if (show_warning && !suspend_warning)
    {
      show_warning = 0;
      print_warn ();
    }

  /* Blocks are always a multiple of 32. */
  size = ((size + 31) / 32) * 32;

  mb = mb_get_new ((memblock_t *) pool, size);
  if (mb)
    stats_update (size, 0);

  return mb ? &mb->aligned.c : NULL;
}
Пример #2
0
/**
 * Called in the main thread after the database update is finished.
 */
static void update_finished_event(void)
{
	char *path;

	assert(progress == UPDATE_PROGRESS_DONE);

	g_thread_join(update_thr);

	idle_add(IDLE_UPDATE);

	if (modified) {
		/* send "idle" events */
		playlist_increment_version_all(&g_playlist);
		idle_add(IDLE_DATABASE);
	}

	path = update_queue_shift(&discard);
	if (path != NULL) {
		/* schedule the next path */
		spawn_update_task(path);
		g_free(path);
	} else {
		progress = UPDATE_PROGRESS_IDLE;

		stats_update();
	}
}
Пример #3
0
static void
_gcry_secmem_free_internal (void *a)
{
  memblock_t *mb;
  int size;

  if (!a)
    return;

  mb = ADDR_TO_BLOCK (a);
  size = mb->size;

  /* This does not make much sense: probably this memory is held in the
   * cache. We do it anyway: */
#define MB_WIPE_OUT(byte) \
  wipememory2 ((memblock_t *) ((char *) mb + BLOCK_HEAD_SIZE), (byte), size);

  MB_WIPE_OUT (0xff);
  MB_WIPE_OUT (0xaa);
  MB_WIPE_OUT (0x55);
  MB_WIPE_OUT (0x00);

  stats_update (0, size);

  mb->flags &= ~MB_FLAG_ACTIVE;

  /* Update stats.  */

  mb_merge (mb);
}
Пример #4
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);
	}
}
Пример #5
0
int stats_evaluate(stats_t inst, stats_data_t stats, time_t a, double b) {
	int rval = 0;
	time_t newtime = -1;
	struct tm* t;

	switch (stats->type) {
		case STATS_TYPE_HOURLY:
			t = localtime(&a);
			t->tm_sec = 0;
			t->tm_min = 0;
			newtime = mktime(t);
			break;
		case STATS_TYPE_DAILY:
			t = localtime(&a);
			t->tm_sec = 0;
			t->tm_min = 0;
			t->tm_hour = 0;
			newtime = mktime(t);
			break;
		case STATS_TYPE_WEEKLY:
			t = localtime(&a);
			t->tm_sec = 0;
			t->tm_min = 0;
			t->tm_hour = 0;
			t->tm_isdst = -1;
			a = mktime(t);
			while (t->tm_wday > 0) {
				a--;
				t = localtime(&a);
				t->tm_sec = 0;
				t->tm_min = 0;
				t->tm_hour = 0;
				t->tm_isdst = -1;
				a = mktime(t);
			}
			newtime = a;
			break;
	}

	assert(newtime != -1);
	if (stats->prevtime != 0) {
		if (stats->prevtime != newtime) {
			if (stats->prevvalue != 0) {
				char buf[256];
				t = localtime(&newtime);
				strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", t);
				//printf("%s - %f\n", buf, b);
				rval = stats_update(inst, stats->type, stats->name, stats->prevtime, b - stats->prevvalue);
			}
			stats->prevvalue = b;
		}
	}
	stats->prevtime = newtime;

	return rval;
}
Пример #6
0
void stats_add(stats_t* record, uint32_t element)
{
    /* Auto resize, just like std::vector in C++ STL */
    if (record->size >= record->capacity / 2) {
        stats_resize(record);
    }

    record->data[record->size] = element;
    record->size++;
    stats_update(record, element);
}
Пример #7
0
/* the main ccache driver function */
static void ccache(int argc, char *argv[])
{
	/* find the real compiler */
	find_compiler(argc, argv);

	/* use the real compiler if HOME is not set */
	if (!cache_dir) {
		cc_log("Unable to determine home directory\n");
		cc_log("ccache is disabled\n");
		failed();
	}
	
	/* we might be disabled */
	if (getenv("CCACHE_DISABLE")) {
		cc_log("ccache is disabled\n");
		failed();
	}

	if (getenv("CCACHE_STRIPC")) {
		strip_c_option = 1;
	}

	if (getenv("CCACHE_UNIFY")) {
		enable_unify = 1;
	}

	detect_swig();

	/* 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);

	if (getenv("CCACHE_READONLY")) {
		cc_log("read-only set - doing real compile\n");
		failed();
	}
	
	/* 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();
}
Пример #8
0
int cpuquiet_wake_cpu(unsigned int cpunumber)
{
	int err = -EPERM;

	if (cpuquiet_curr_driver && cpuquiet_curr_driver->wake_cpu)
		err = cpuquiet_curr_driver->wake_cpu(cpunumber);

	if (!err)
		stats_update(stats + cpunumber, 1);

	return err;
}
Пример #9
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");
		stats_update(STATS_ERROR);
		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");
		stats_update(STATS_ERROR);
		failed();
	}
}
Пример #10
0
// swap citem with inventory pos
int swap(int cn,int pos)
{
	int in,price;

	if (cn<1 || cn>=MAXCHARS) { error=ERR_ILLEGAL_CHARNO; return 0; }

	if (ch[cn].flags&(CF_DEAD)) { error=ERR_DEAD; return 0; }

	// no switching equipment while in teufel PK arena
	if (areaID==34 && (map[ch[cn].x+ch[cn].y*MAXMAP].flags&MF_ARENA) && pos!=WN_LHAND && pos<12) { error=ERR_ILLEGAL_ATTACK; return 0; }
	
	if ((in=ch[cn].citem)) {
		if (pos<0) {		// <0, illegal
			error=ERR_ILLEGAL_INVPOS;
			return 0;
		} else if (pos<12) {	// wear position
			if (!can_wear(cn,in,pos)) {
				error=ERR_REQUIREMENTS;
				return 0;
			}
		} else if (pos<30) {	// spell position
			error=ERR_ILLEGAL_INVPOS;
			return 0;
		} else if (pos<INVENTORYSIZE) {	// backpack
			;
		} else {		// >=INVENTORYSIZE, illegal
			error=ERR_ILLEGAL_INVPOS;
			return 0;
		}
	} else {
		if (pos<0 || (pos>=12 && pos<30) || pos>=INVENTORYSIZE) {
			error=ERR_ILLEGAL_INVPOS;
			return 0;
		}
	}

	// swap items
	ch[cn].citem=ch[cn].item[pos];
	
	if (it[in].flags&IF_MONEY) {
		if (ch[cn].flags&CF_PLAYER) dlog(cn,in,"dropped into goldbag");
		price=destroy_money_item(in);
		ch[cn].gold+=price; stats_update(cn,0,price);
                ch[cn].item[pos]=0;
	} else ch[cn].item[pos]=in;

	ch[cn].flags|=CF_ITEMS;

	if (pos<12) update_char(cn);

        return 1;
}
Пример #11
0
int cpuquiet_wake_cpu(unsigned int cpunumber, bool sync)
{
	int err = -EPERM;

	if (cpuquiet_curr_driver && cpuquiet_curr_driver->wake_cpu)
		err = cpuquiet_curr_driver->wake_cpu(cpunumber, sync);

#ifdef CONFIG_CPUQUIET_STATS
	if (!err)
		stats_update(stats + cpunumber, 1);
#endif

	return err;
}
Пример #12
0
/**
 * \brief Update RRD files if interval passed
 *
 * \param[in] conf plugin config
 * \param[in] force ignore interval, always update files
 */
void stats_flush_counters(plugin_conf *conf, bool force = false)
{
	/* Update stats */
	uint64_t now = time(NULL);
	for (auto st: conf->stats) {
		/* Some pointers can be NULL after unsuccessfull creation */
		if (!st.second) {
			continue;
		}

		if (force || ((st.second->last / conf->interval + 1) * conf->interval <= now)) {
			stats_update(st.second, conf->templ);
			st.second->last = now;
		}
	}
}
Пример #13
0
/* update cached file sizes and count helper function for to_cache() */
static void to_cache_stats_helper(struct stat *pstat, char *cached_filename, char *tmp_outfiles, int *files_size, int *cached_files_count)
{
#if ENABLE_ZLIB
	/* do an extra stat on the cache file for the size statistics */
	if (stat(cached_filename, pstat) != 0) {
		cc_log("failed to stat cache files - %s\n", strerror(errno));
		stats_update(STATS_ERROR);
		if (tmp_outfiles) {
			unlink(tmp_outfiles);
		}
		failed();
	}
#else
        (void)cached_filename;
        (void)tmp_outfiles;
#endif
	(*files_size) += file_size(pstat);
	(*cached_files_count)++;
}
Пример #14
0
static void *
_gcry_secmem_malloc_internal (size_t size)
{
  memblock_t *mb;

  if (!pool_okay)
    {
      /* Try to initialize the pool if the user forgot about it.  */
      secmem_init (STANDARD_POOL_SIZE);
      if (!pool_okay)
        {
          log_info (_("operation is not possible without "
                      "initialized secure memory\n"));
          gpg_err_set_errno (ENOMEM);
          return NULL;
        }
    }
  if (not_locked && fips_mode ())
    {
      log_info (_("secure memory pool is not locked while in FIPS mode\n"));
      gpg_err_set_errno (ENOMEM);
      return NULL;
    }
  if (show_warning && !suspend_warning)
    {
      show_warning = 0;
      print_warn ();
    }

  /* Blocks are always a multiple of 32. */
  size = ((size + 31) / 32) * 32;

  mb = mb_get_new ((memblock_t *) pool, size);
  if (mb)
    stats_update (size, 0);

  return mb ? &mb->aligned.c : NULL;
}
Пример #15
0
static ssize_t stats_sysfs_show(struct kobject *kobj,
			struct attribute *attr, char *buf)
{
	struct cpu_attribute *cattr =
		container_of(attr, struct cpu_attribute, attr);
	struct cpuquiet_cpu_stat *stat  =
		container_of(kobj, struct cpuquiet_cpu_stat, cpu_kobject);
	ssize_t len = 0;
	bool was_up = stat->up_down_count & 0x1;

	stats_update(stat, was_up);

	switch (cattr->type) {
	case up_down_count:
		len = sprintf(buf, "%u\n", stat->up_down_count);
		break;
	case time_up_total:
		len =  sprintf(buf, "%llu\n", stat->time_up_total);
		break;
	}

	return len;
}
Пример #16
0
/* hash a file that consists of preprocessor output, but remove any line 
   number information from the hash
*/
int unify_hash(const char *fname)
{
#ifdef _WIN32
	HANDLE file;
	HANDLE section;
	DWORD filesize_low;
	char *map;
	int ret = -1;

	file = CreateFileA(fname, GENERIC_READ, FILE_SHARE_READ, NULL,
	                   OPEN_EXISTING, 0, NULL);
	if (file != INVALID_HANDLE_VALUE) {
		filesize_low = GetFileSize(file, NULL);
		if (!(filesize_low == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)) {
			section = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL);
			CloseHandle(file);
			if (section != NULL) {
				map = MapViewOfFile(section, FILE_MAP_READ, 0, 0, 0);
				CloseHandle(section);
				if (map != NULL)
					ret = 0;
			}
		}
	}

	if (ret == -1) {
		cc_log("Failed to open preprocessor output %s\n", fname);
		stats_update(STATS_PREPROCESSOR);
		return -1;
	}

	/* pass it through the unifier */
	unify((unsigned char *)map, filesize_low);

	UnmapViewOfFile(map);

	return 0;
#else
	int fd;
	struct stat st;	
	char *map;

	fd = open(fname, O_RDONLY|O_BINARY);
	if (fd == -1 || fstat(fd, &st) != 0) {
		cc_log("Failed to open preprocessor output %s\n", fname);
		if (fd != -1) close(fd);
		stats_update(STATS_PREPROCESSOR);
		return -1;
	}

	/* we use mmap() to make it easy to handle arbitrarily long
           lines in preprocessor output. I have seen lines of over
           100k in length, so this is well worth it */
	map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
	close(fd);
	if (map == (char *)-1) {
		cc_log("Failed to mmap %s\n", fname);
		stats_update(STATS_PREPROCESSOR);
		return -1;
	}

	/* pass it through the unifier */
	unify((unsigned char *)map, st.st_size);

	munmap(map, st.st_size);

	return 0;
#endif
}
Пример #17
0
void ec_decode(u_char *param, const struct pcap_pkthdr *pkthdr, const u_char *pkt)
{
   FUNC_DECODER_PTR(packet_decoder);
   struct packet_object po;
   u_int len;
   u_char *data;
   u_int datalen;
   struct iface_env *iface;

   iface = (struct iface_env *)param;

   CANCELLATION_POINT();

   /* start the timer for the stats */
   stats_half_start(&GBL_STATS->bh);
  
   /* XXX -- remove this */
#if 0
   if (!GBL_OPTIONS->quiet)
      USER_MSG("CAPTURED: 0x%04x bytes form %s\n", pkthdr->caplen, iface->name );
#endif
   
   if (GBL_OPTIONS->read)
      /* update the offset pointer */
      GBL_PCAP->dump_off = ftell(pcap_file(GBL_IFACE->pcap));
   else {
      /* update the statistics */
      stats_update();
   }
   
   /* 
    * dump packet to file if specified on command line 
    * it dumps all the packets disregarding the filter
    *
    * do not perform the operation if we are reading from another
    * filedump. See below where the file is dumped when reading
    * form other files (useful for decription).
    */
   if (GBL_OPTIONS->write && !GBL_OPTIONS->read) {
      /* 
       * we need to lock this because in SM_BRIDGED the
       * packets are dumped in the log file by two threads
       */
      DUMP_LOCK;
      pcap_dump((u_char *)GBL_PCAP->dump, pkthdr, pkt);
      DUMP_UNLOCK;
   }
 
   /* bad packet */
   if (pkthdr->caplen > UINT16_MAX) {
      USER_MSG("Bad packet detected, skipping...\n");
      return;
   }
   
   /* 
    * copy the packet in a "safe" buffer 
    * we don't want other packets after the end of the packet (as in BPF)
    *
    * also keep the buffer aligned !
    * the alignment is set by the media decoder.
    */
   memcpy(GBL_PCAP->buffer + GBL_PCAP->align, pkt, pkthdr->caplen);
   
   /* extract data and datalen from pcap packet */
   data = (u_char *)GBL_PCAP->buffer + GBL_PCAP->align;
   datalen = pkthdr->caplen;

   /* 
    * deal with trucated packets:
    * if someone has created a pcap file with the snaplen
    * too small we have to skip the packet (is not interesting for us)
    */
   if (GBL_PCAP->snaplen <= datalen) {
      USER_MSG("Truncated packet detected, skipping...\n");
      return;
   }
   
   /* alloc the packet object structure to be passet through decoders */
   packet_create_object(&po, data, datalen);

   /* Be sure to NULL terminate our data buffer */
   *(data + datalen) = 0;
   
   /* set the po timestamp */
   memcpy(&po.ts, &pkthdr->ts, sizeof(struct timeval));
   /* set the interface where the packet was captured */
   if (GBL_OPTIONS->iface && !strcmp(iface->name, GBL_OPTIONS->iface))
      po.flags |= PO_FROMIFACE;
   else if (GBL_OPTIONS->iface_bridge && !strcmp(iface->name, GBL_OPTIONS->iface_bridge))
      po.flags |= PO_FROMBRIDGE;

   /* HOOK POINT: RECEIVED */ 
   hook_point(HOOK_RECEIVED, &po);
   
   /* 
    * by default the packet should not be processed by ettercap.
    * if the sniffing filter matches it, the flag will be reset.
    */
   po.flags |= PO_IGNORE;
  
   /* 
    * start the analysis through the decoders stack 
    *
    * if the packet can be handled it will reach the top of the stack
    * where the decoder_data will add it to the top_half queue,
    * else the packet will not be handled but it should be forwarded
    *
    * after this fuction the packet is completed (all flags set)
    */
   packet_decoder = get_decoder(LINK_LAYER, GBL_PCAP->dlt);
   BUG_IF(packet_decoder == NULL);
   packet_decoder(data, datalen, &len, &po);
  
   /* special case for bridged sniffing */
   if (GBL_SNIFF->type == SM_BRIDGED) {
      EXECUTE(GBL_SNIFF->check_forwarded, &po);
      EXECUTE(GBL_SNIFF->set_forwardable, &po);
   }
   
   /* XXX - BIG WARNING !!
    *
    * if the packet was filtered by the filtering engine
    * the state of the packet_object is inconsistent !
    * the fields in the structure may not reflect the real
    * packet fields...
    */
   
   /* use the sniffing method funcion to forward the packet */
   if ( (po.flags & PO_FORWARDABLE) && !(po.flags & PO_FORWARDED) ) {
      /* HOOK POINT: PRE_FORWARD */ 
      hook_point(HOOK_PRE_FORWARD, &po);
      EXECUTE(GBL_SNIFF->forward, &po);
   }


   /* 
    * dump packets to a file from another file.
    * this is useful when decrypting packets or applying filters
    * on pcapfile and we want to save the result in a file
    */
   if (GBL_OPTIONS->write && GBL_OPTIONS->read) {
      DUMP_LOCK;
      /* reuse the original pcap header, but with the modified packet */
      pcap_dump((u_char *)GBL_PCAP->dump, pkthdr, po.packet);
      DUMP_UNLOCK;
   }
   
   /* 
    * if it is the last packet set the flag 
    * and send the packet to the top half.
    * we have to do this because the last packet 
    * might be dropped by the filter.
    */
   if (GBL_OPTIONS->read && GBL_PCAP->dump_size == GBL_PCAP->dump_off) {
      po.flags |= PO_EOF;
      top_half_queue_add(&po);
   }
   
   /* free the structure */
   packet_destroy_object(&po);
   
   /* calculate the stats */
   stats_half_end(&GBL_STATS->bh, pkthdr->caplen);
   
   CANCELLATION_POINT();

   return;
}
Пример #18
0
/* run the real compiler and put the result in cache */
static void to_cache(ARGS *args)
{
	char *path_stderr;
	char *tmp_stdout, *tmp_stderr, *tmp_outfiles;
	struct stat st1;
	int status;
	int cached_files_count = 0;
	int files_size = 0;

	x_asprintf(&tmp_stdout, "%s/tmp.stdout.%s", temp_dir, tmp_string());
	x_asprintf(&tmp_stderr, "%s/tmp.stderr.%s", temp_dir, tmp_string());
	x_asprintf(&tmp_outfiles, "%s/tmp.outfiles.%s", temp_dir, tmp_string());

	if (strip_c_option && !swig) {
		args_add(stripped_args, "-c");
	}

	if (output_file) {
		args_add(args, "-o");
		args_add(args, output_file);
	}

	/* Turn off DEPENDENCIES_OUTPUT when running cc1, because
	 * otherwise it will emit a line like
	 *
	 *  tmp.stdout.vexed.732.o: /home/mbp/.ccache/tmp.stdout.vexed.732.i
	 *
	 * unsetenv() is on BSD and Linux but not portable. */
	putenv("DEPENDENCIES_OUTPUT");

	/* Give SWIG a filename for it to create and populate with a list of files that it generates */
	if (swig) {
		char *ccache_outfiles;
		x_asprintf(&ccache_outfiles, "CCACHE_OUTFILES=%s", tmp_outfiles);
		unlink(tmp_outfiles);
		if (getenv("CCACHE_OUTFILES") || putenv(ccache_outfiles) == -1) {
			cc_log("CCACHE_OUTFILES env variable already set or could not be set\n");
			stats_update(STATS_ERROR);
			failed();
		}
	}
	
	if (getenv("CCACHE_CPP2")) {
		args_add(args, input_file);
	} else {
		if (swig) {
			args_add(args, "-nopreprocess");
		}
		args_add(args, i_tmpfile);
	}
	status = execute(args->argv, tmp_stdout, tmp_stderr);
	args_pop(args, 3);

	if (stat(tmp_stdout, &st1) != 0 || st1.st_size != 0) {
		cc_log("compiler produced stdout for %s\n", input_file);
		stats_update(STATS_STDOUT);
		unlink(tmp_stdout);
		unlink(tmp_stderr);
		unlink(tmp_outfiles);
		if (!swig) unlink(output_file);
		failed();
	}
	unlink(tmp_stdout);

	if (status != 0) {
		int fd;
		cc_log("compile of %s gave status = %d\n", input_file, status);
		stats_update(STATS_STATUS);

		fd = open(tmp_stderr, O_RDONLY | O_BINARY);
		if (fd != -1) {
			if (cpp_stderr) {
				/* we might have some stderr from cpp */
				int fd2 = open(cpp_stderr, O_RDONLY | O_BINARY);
				if (fd2 != -1) {
					copy_fd(fd2, 2);
					close(fd2);
					unlink(cpp_stderr);
					cpp_stderr = NULL;
				}
			}

			/* we can use a quick method of
			   getting the failed output */
			copy_fd(fd, 2);
			close(fd);
			unlink(tmp_stderr);
			if (i_tmpfile && !direct_i_file) {
				unlink(i_tmpfile);
			}
			exit(status);
		}
		
		unlink(tmp_stderr);
		unlink(tmp_outfiles);
		if (!swig) unlink(output_file);
		failed();
	} else {
		int hardlink = (getenv("CCACHE_NOCOMPRESS") != 0) && (getenv("CCACHE_HARDLINK") != 0);
		if (swig) {
			/* read the list of generated files and copy each of them into the cache */
			FILE *file;
			file = fopen(tmp_outfiles, "r");
			if (file) {
				char out_filename[FILENAME_MAX + 1];
				char out_filename_cache[FILENAME_MAX + 1];
				while (fgets(out_filename, FILENAME_MAX, file)) {
					char *linefeed = strchr(out_filename, '\n');
					if (linefeed) {
						char *potential_cr = linefeed - 1;
						if (potential_cr >= out_filename && *potential_cr == '\r')
						  *potential_cr = 0;
						*linefeed = 0;

						if (cached_files_count == 0) {
							strcpy(out_filename_cache, hashname);
						} else {
							sprintf(out_filename_cache, "%s.%d", hashname, cached_files_count);
						}

						if (commit_to_cache(out_filename, out_filename_cache, hardlink) != 0) {
							fclose(file);
							unlink(tmp_outfiles);
							failed();
						}
						to_cache_stats_helper(&st1, out_filename_cache, tmp_outfiles, &files_size, &cached_files_count);
					} else {
						cached_files_count = 0;
						break;
					}
				}
				fclose(file);
				if (cached_files_count == 0) {
					cc_log("failed to copy output files to cache - internal error\n");
					stats_update(STATS_ERROR);
					unlink(tmp_outfiles);
					failed();
				}

				/* also copy the (uncompressed) file containing the list of generated files into the cache */
				sprintf(out_filename_cache, "%s.outfiles", hashname);
				if (stat(tmp_outfiles, &st1) != 0 ||
					safe_rename(tmp_outfiles, out_filename_cache) != 0) {
					cc_log("failed to copy outfiles file to cache - %s\n", strerror(errno));
					stats_update(STATS_ERROR);
					unlink(tmp_outfiles);
					failed();
				}
				to_cache_stats_helper(&st1, out_filename_cache, tmp_outfiles, &files_size, &cached_files_count);
				unlink(tmp_outfiles);
			} else {
				cc_log("failed to open temp outfiles file - %s\n", strerror(errno));
				stats_update(STATS_ERROR);
				failed();
			}
		} else {
			if (commit_to_cache(output_file, hashname, hardlink) != 0) {
				failed();
			}
			to_cache_stats_helper(&st1, hashname, 0, &files_size, &cached_files_count);
		}
	}

	x_asprintf(&path_stderr, "%s.stderr", hashname);

	if (stat(tmp_stderr, &st1) != 0 ||
		move_file(tmp_stderr, path_stderr) != 0) {
		cc_log("failed to rename tmp files - %s\n", strerror(errno));
		stats_update(STATS_ERROR);
		failed();
	}

	to_cache_stats_helper(&st1, path_stderr, 0, &files_size, &cached_files_count);

	cc_log("Placed %d files for %s into cache\n", cached_files_count, input_file);
	stats_tocache(files_size, cached_files_count);

	free(tmp_stderr);
	free(tmp_stdout);
	free(tmp_outfiles);
	free(path_stderr);
}
Пример #19
0
bool
hash_command_output(struct mdfour *hash, const char *command,
                    const char *compiler)
{
#ifdef _WIN32
	SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
	HANDLE pipe_out[2];
	PROCESS_INFORMATION pi;
	STARTUPINFO si;
	DWORD exitcode;
	bool cmd = false;
	char *sh = NULL;
	char *win32args;
	char *path;
	BOOL ret;
	bool ok;
	int fd;
#else
	pid_t pid;
	int pipefd[2];
#endif

#ifdef _WIN32
	/* trim leading space */
	while (isspace(*command)) {
		command++;
	}
	/* add "echo" command */
	if (str_startswith(command, "echo")) {
		command = format("cmd.exe /c \"%s\"", command);
		cmd = true;
	} else if (str_startswith(command,
	                          "%compiler%") && str_eq(compiler, "echo")) {
		command = format("cmd.exe /c \"%s%s\"", compiler, command + 10);
		cmd = true;
	} else {
		command = x_strdup(command);
	}
#endif
	struct args *args = args_init_from_string(command);
	int i;
	for (i = 0; i < args->argc; i++) {
		if (str_eq(args->argv[i], "%compiler%")) {
			args_set(args, i, compiler);
		}
	}
	cc_log_argv("Executing compiler check command ", args->argv);

#ifdef _WIN32
	memset(&pi, 0x00, sizeof(pi));
	memset(&si, 0x00, sizeof(si));

	path = find_executable(args->argv[0], NULL);
	if (!path) {
		path = args->argv[0];
	}
	sh = win32getshell(path);
	if (sh) {
		path = sh;
	}

	si.cb = sizeof(STARTUPINFO);
	CreatePipe(&pipe_out[0], &pipe_out[1], &sa, 0);
	SetHandleInformation(pipe_out[0], HANDLE_FLAG_INHERIT, 0);
	si.hStdOutput = pipe_out[1];
	si.hStdError = pipe_out[1];
	si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
	si.dwFlags = STARTF_USESTDHANDLES;
	if (!cmd) {
		win32args = win32argvtos(sh, args->argv);
	} else {
		win32args = (char *) command;  /* quoted */
	}
	ret = CreateProcess(path, win32args, NULL, NULL, 1, 0, NULL, NULL, &si, &pi);
	CloseHandle(pipe_out[1]);
	args_free(args);
	free(win32args);
	if (cmd) {
		free((char *) command);  /* original argument was replaced above */
	}
	if (ret == 0) {
		stats_update(STATS_COMPCHECK);
		return false;
	}
	fd = _open_osfhandle((intptr_t) pipe_out[0], O_BINARY);
	ok = hash_fd(hash, fd);
	if (!ok) {
		cc_log("Error hashing compiler check command output: %s", strerror(errno));
		stats_update(STATS_COMPCHECK);
	}
	WaitForSingleObject(pi.hProcess, INFINITE);
	GetExitCodeProcess(pi.hProcess, &exitcode);
	CloseHandle(pipe_out[0]);
	CloseHandle(pi.hProcess);
	CloseHandle(pi.hThread);
	if (exitcode != 0) {
		cc_log("Compiler check command returned %d", (int) exitcode);
		stats_update(STATS_COMPCHECK);
		return false;
	}
	return ok;
#else
	if (pipe(pipefd) == -1) {
		fatal("pipe failed");
	}
	pid = fork();
	if (pid == -1) {
		fatal("fork failed");
	}

	if (pid == 0) {
		/* Child. */
		close(pipefd[0]);
		close(0);
		dup2(pipefd[1], 1);
		dup2(pipefd[1], 2);
		_exit(execvp(args->argv[0], args->argv));
		return false; /* Never reached. */
	} else {
		/* Parent. */
		int status;
		bool ok;
		args_free(args);
		close(pipefd[1]);
		ok = hash_fd(hash, pipefd[0]);
		if (!ok) {
			cc_log("Error hashing compiler check command output: %s", strerror(errno));
			stats_update(STATS_COMPCHECK);
		}
		close(pipefd[0]);
		if (waitpid(pid, &status, 0) != pid) {
			cc_log("waitpid failed");
			return false;
		}
		if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
			cc_log("Compiler check command returned %d", WEXITSTATUS(status));
			stats_update(STATS_COMPCHECK);
			return false;
		}
		return ok;
	}
#endif
}
Пример #20
0
/*
 * Process the compiler options into options suitable for passing to the
 * preprocessor and the real compiler. The preprocessor options don't include
 * -E; this is added later. Returns true on success, otherwise false.
 */
bool
armcc_process_args(struct args *orig_args, struct args **preprocessor_args,
                struct args **compiler_args)
{
	int i;
	bool found_c_opt = false;
	bool found_S_opt = false;
	bool found_pch = false;
	bool found_fpch_preprocess = false;
	const char *actual_language;          /* Language to actually use. */
	const char *input_charset = NULL;
	struct stat st;
	/* is the dependency makefile name overridden with --depend? */
	bool dependency_filename_specified = false;
	/* is the dependency makefile target name specified ? */
	bool dependency_target_specified = false;
	char *dep_file = NULL, *dep_dir = NULL;
	struct args *stripped_args = NULL, *dep_args = NULL;
	int argc = orig_args->argc;
	char **argv = orig_args->argv;
	bool result = true;
	/* 0: Choose preprocessor type by the file extension.
	 * 1: Use c preprocessor.
	 * 2: Use c++ preprocessor.*/
	unsigned force_preprocessor_type = 0;

	stripped_args = args_init(0, NULL);
	dep_args = args_init(0, NULL);

	args_add(stripped_args, argv[0]);

	for (i = 1; i < argc; i++) {
		/* The user knows best: just swallow the next arg */
		if (str_eq(argv[i], "--ccache-skip")) {
			i++;
			if (i == argc) {
				cc_log("--ccache-skip lacks an argument");
				result = false;
				goto out;
			}
			args_add(stripped_args, argv[i]);
			continue;
		}

		/* Special case for -E. */
		if (str_eq(argv[i], "-E")) {
			stats_update(STATS_PREPROCESSING);
			result = false;
			goto out;
		}

		/* These are always too hard. */
		if (compopt_too_hard(argv[i])
		    || str_startswith(argv[i], "@")
		    || str_startswith(argv[i], "-fdump-")) {
			cc_log("Compiler option %s is unsupported", argv[i]);
			stats_update(STATS_UNSUPPORTED);
			result = false;
			goto out;
		}

		/* These are too hard in direct mode. */
		if (enable_direct) {
			if (compopt_too_hard_for_direct_mode(argv[i])) {
				cc_log("Unsupported compiler option for direct mode: %s", argv[i]);
				enable_direct = false;
			}
		}

		/* we must have -c */
		if (str_eq(argv[i], "-c")) {
			args_add(stripped_args, argv[i]);
			found_c_opt = true;
			continue;
		}

		/* -S changes the default extension */
		if (str_eq(argv[i], "-S")) {
			args_add(stripped_args, argv[i]);
			found_S_opt = true;
			continue;
		}

		/* we need to work out where the output was meant to go */
		if (str_eq(argv[i], "-o")) {
			if (i == argc-1) {
				cc_log("Missing argument to %s", argv[i]);
				stats_update(STATS_ARGS);
				result = false;
				goto out;
			}
			output_obj = argv[i+1];
			i++;
			continue;
		}

		/* alternate form of -o, with no space */
		if (str_startswith(argv[i], "-o")) {
			output_obj = &argv[i][2];
			continue;
		}


		/* If multiple source type options are there, the armcc will use the last one. */
		if (str_eq(argv[i], "--cpp")) { 
			force_preprocessor_type = 2;
			continue;
		}
		else if (str_eq(argv[i], "--c90") || str_eq(argv[i], "--c99")) { 
			force_preprocessor_type = 1;
			continue;
		}

		if (str_eq(argv[i], "--md")) { 
			generating_dependencies = true;
			continue;
		}

		/* The rvct started supporting --depend_target from 4.0.
		 * And there is a bug when using -E and --depend together with rvct which version is earlier than 4.0_697.
		 * That is too hard to support "--depend" for the earlier version of rvct.*/
		if (str_startswith(argv[i], "--depend_dir")) {
			/* We just concat the dir and the filename and pass the result 
			 * to --depend. */
			if (i >= argc - 1) {
				cc_log("Missing argument to %s", argv[i]);
				stats_update(STATS_ARGS);
				result = false;
				goto out;
			}
			dep_dir= x_strdup(argv[i+1]);
			i++;
			continue;
		}
		else if (str_startswith(argv[i], "--depend_target")) {
			if (i >= argc - 1) {
				cc_log("Missing argument to %s", argv[i]);
				stats_update(STATS_ARGS);
				result = false;
				goto out;
			}
			dependency_target_specified = true;
			args_add(dep_args, argv[i]);
			args_add(dep_args, argv[i+1]);
			i++;
			continue;
		}
		else if (str_startswith(argv[i], "--depend")) {
			dependency_filename_specified = true;
			generating_dependencies = true;

			if (i >= argc - 1) {
				cc_log("Missing argument to %s", argv[i]);
				stats_update(STATS_ARGS);
				result = false;
				goto out;
			}
			dep_file = x_strdup(argv[i + 1]);
			i++;
			continue;
		}


		/*
		 * Options taking an argument that that we may want to rewrite
		 * to relative paths to get better hit rate. A secondary effect
		 * is that paths in the standard error output produced by the
		 * compiler will be normalized.
		 */
		if (compopt_takes_path(argv[i])) {
			char *relpath;
			char *pchpath;
			if (i == argc-1) {
				cc_log("Missing argument to %s", argv[i]);
				stats_update(STATS_ARGS);
				result = false;
				goto out;
			}

			args_add(stripped_args, argv[i]);
			relpath = make_relative_path(x_strdup(argv[i+1]));
			args_add(stripped_args, relpath);

			/* Try to be smart about detecting precompiled headers */
			pchpath = format("%s.gch", argv[i+1]);
			if (stat(pchpath, &st) == 0) {
				cc_log("Detected use of precompiled header: %s", pchpath);
				found_pch = true;
			}

			free(pchpath);
			free(relpath);
			i++;
			continue;
		}

		/* Same as above but options with concatenated argument. */
		if (compopt_short(compopt_takes_path, argv[i])) {
			char *relpath;
			char *option;
			relpath = make_relative_path(x_strdup(argv[i] + 2));
			option = format("-%c%s", argv[i][1], relpath);
			args_add(stripped_args, option);
			free(relpath);
			free(option);
			continue;
		}

		/* options that take an argument */
		if (compopt_takes_arg(argv[i])) {
			if (i == argc-1) {
				cc_log("Missing argument to %s", argv[i]);
				stats_update(STATS_ARGS);
				result = false;
				goto out;
			}
			args_add(stripped_args, argv[i]);
			args_add(stripped_args, argv[i+1]);
			i++;
			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)) {
			cc_log("%s is not a regular file, not considering as input file",
			       argv[i]);
			args_add(stripped_args, argv[i]);
			continue;
		}

		if (input_file) {
			if (language_for_file(argv[i])) {
				cc_log("Multiple input files: %s and %s", input_file, argv[i]);
				stats_update(STATS_MULTIPLE);
			} else if (!found_c_opt) {
				cc_log("Called for link with %s", argv[i]);
				if (strstr(argv[i], "conftest.")) {
					stats_update(STATS_CONFTEST);
				} else {
					stats_update(STATS_LINK);
				}
			} else {
				cc_log("Unsupported source extension: %s", argv[i]);
				stats_update(STATS_SOURCELANG);
			}
			result = false;
			goto out;
		}

		/* Rewrite to relative to increase hit rate. */
		input_file = make_relative_path(x_strdup(argv[i]));
	}

	if (!input_file) {
		cc_log("No input file found");
		stats_update(STATS_NOINPUT);
		result = false;
		goto out;
	}

	if (found_pch || found_fpch_preprocess) {
		using_precompiled_header = true;
		if (!(sloppiness & SLOPPY_TIME_MACROS)) {
			cc_log("You have to specify \"time_macros\" sloppiness when using"
			       " precompiled headers to get direct hits");
			cc_log("Disabling direct mode");
			stats_update(STATS_CANTUSEPCH);
			result = false;
			goto out;
		}
	}

	if(force_preprocessor_type == 0) { 
		actual_language = language_for_file(input_file);
	} 
	else if(force_preprocessor_type == 2) { 
		actual_language = "c++";
	}
	else {
		actual_language = "c";
	}

	output_is_precompiled_header =
		actual_language && strstr(actual_language, "-header") != NULL;

	if (!found_c_opt && !output_is_precompiled_header) {
		cc_log("No -c option found");
		/* 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);
		}
		result = false;
		goto out;
	}

	if (!actual_language) {
		cc_log("Unsupported source extension: %s", input_file);
		stats_update(STATS_SOURCELANG);
		result = false;
		goto out;
	}

	direct_i_file = language_is_preprocessed(actual_language);

	if (output_is_precompiled_header) {
		/* It doesn't work to create the .gch from preprocessed source. */
		cc_log("Creating precompiled header; not compiling preprocessed code");
		compile_preprocessed_source_code = false;
	}

	/* don't try to second guess the compilers heuristics for stdout handling */
	if (output_obj && str_eq(output_obj, "-")) {
		stats_update(STATS_OUTSTDOUT);
		cc_log("Output file is -");
		result = false;
		goto out;
	}

	if (!output_obj) {
		if (output_is_precompiled_header) {
			output_obj = format("%s.gch", input_file);
		} else {
			char *p;
			output_obj = x_strdup(input_file);
			if ((p = strrchr(output_obj, '/'))) {
				output_obj = p+1;
			}
			p = strrchr(output_obj, '.');
			if (!p || !p[1]) {
				cc_log("Badly formed object filename");
				stats_update(STATS_ARGS);
				result = false;
				goto out;
			}
			p[1] = found_S_opt ? 's' : 'o';
			p[2] = 0;
		}
	}

	/* cope with -o /dev/null */
	if (!str_eq(output_obj,"/dev/null")
	    && stat(output_obj, &st) == 0
	    && !S_ISREG(st.st_mode)) {
		cc_log("Not a regular file: %s", output_obj);
		stats_update(STATS_DEVICE);
		result = false;
		goto out;
	}

	/*
	 * Some options shouldn't be passed to the real compiler when it compiles
	 * preprocessed code:
	 *
	 * -finput-charset=XXX (otherwise conversion happens twice)
	 * -x XXX (otherwise the wrong language is selected)
	 */
	*preprocessor_args = args_copy(stripped_args);
	if (input_charset) {
		args_add(*preprocessor_args, input_charset);
	}
	if (found_pch) {
		args_add(*preprocessor_args, "-fpch-preprocess");
	}

	/*
	 * Add flags for dependency generation only to the preprocessor command line.
	 */
	if (generating_dependencies) {
		char *dep_path;

		if(!dependency_filename_specified)
		{ 
			char *base_name;

			base_name = remove_extension(output_obj);
			dep_file = format("%s.d", base_name);
			free(base_name);
		}

		if (!dependency_target_specified) {
			args_add(dep_args, "--depend_target");
			args_add(dep_args, output_obj);
		}

		free(output_dep);
		
		if(dep_dir)
		{ 
#ifdef _WIN32
			dep_path = make_relative_path(format("%s\\%s", dep_dir, dep_file));
#else
			dep_path = make_relative_path(format("%s/%s", dep_dir, dep_file));
#endif
		}
		else
		{ 
			dep_path = x_strdup(dep_file);
		}

		args_add(dep_args, "--depend");
		args_add(dep_args, dep_path);
		/* dep_path will be free in make_relative_path */
		output_dep = make_relative_path(x_strdup(dep_path));
	}

	if (compile_preprocessed_source_code) {
		*compiler_args = args_copy(stripped_args);
	} else {
		*compiler_args = args_copy(*preprocessor_args);
	}

	i_extension = getenv("CCACHE_EXTENSION");
	if (!i_extension) {
		const char *p_language = p_language_for_language(actual_language);
		i_extension = extension_for_language(p_language) + 1;

	}
	/* Patch for preprocessed file extension for armcc 3.1.
	 * armcc 3.1 cannot recognize "i" or "ii" as the preprocessed source file 
	 * without --compile_all_input. */
	args_add(*compiler_args, "--compile_all_input");
	if (str_eq(i_extension, "ii")) { 
		args_add(*compiler_args, "--cpp");
	}

	/*
	 * Only pass dependency arguments to the preprocesor since Intel's C++
	 * compiler doesn't produce a correct .d file when compiling preprocessed
	 * source.
	 */
	args_extend(*preprocessor_args, dep_args);

out:
	free(dep_file);
	free(dep_dir);
	args_free(stripped_args);
	args_free(dep_args);
	return result;
}
Пример #21
0
/*
 * Process the compiler options into options suitable for passing to the
 * preprocessor and the real compiler. The preprocessor options don't include
 * -E; this is added later. Returns true on success, otherwise false.
 */
bool
c166_process_args(struct args *orig_args, struct args **preprocessor_args,
                struct args **compiler_args)
{
	int i;
	bool found_c_opt = false;
	bool found_S_opt = false;
	bool found_H_opt = false;
	/* 0: Choose preprocessor type by the file extension.
	 * 1: Use c preprocessor.
	 * 2: Use c++ preprocessor.*/
	unsigned force_preprocessor_type = 0;
	const char *actual_language;          /* Language to actually use. */
	struct stat st;
	/* is the dependency makefile name overridden with -MF? */
	bool dependency_filename_specified = false;
	/* is the dependency makefile target name specified with -MT or -MQ? */
	bool dependency_target_specified = false;
	struct args *stripped_args = NULL, *dep_args = NULL, *h_args;
	int argc = orig_args->argc;
	char **argv = orig_args->argv;
	bool result = true;

	stripped_args = args_init(0, NULL);
	dep_args = args_init(0, NULL);
	h_args = args_init(0, NULL);

	args_add(stripped_args, argv[0]);

	for (i = 1; i < argc; i++) {
		/* The user knows best: just swallow the next arg */
		if (str_eq(argv[i], "--ccache-skip")) {
			i++;
			if (i == argc) {
				cc_log("--ccache-skip lacks an argument");
				result = false;
				goto out;
			}
			args_add(stripped_args, argv[i]);
			continue;
		}

		/* Special case for -E. */
		if (str_eq(argv[i], "-E")) {
			stats_update(STATS_PREPROCESSING);
			result = false;
			goto out;
		}

		/* These are always too hard. */
		if (compopt_too_hard(argv[i])) {
			cc_log("Compiler option %s is unsupported", argv[i]);
			stats_update(STATS_UNSUPPORTED);
			result = false;
			goto out;
		}

		/* These are too hard in direct mode. */
		if (enable_direct) {
			if (compopt_too_hard_for_direct_mode(argv[i])) {
				cc_log("Unsupported compiler option for direct mode: %s", argv[i]);
				enable_direct = false;
			}
		}

		/* we must have -c */
		if (str_eq(argv[i], "-c")) {
			args_add(stripped_args, argv[i]);
			found_c_opt = true;
			continue;
		}

		/* -S changes the default extension */
		/* TODO: Check this -S out!
		if (str_eq(argv[i], "-S")) {
			args_add(stripped_args, argv[i]);
			found_S_opt = true;
			continue;
		}
		*/

		/* we need to work out where the output was meant to go */
		if (str_eq(argv[i], "-o")) {
			if (i == argc-1) {
				cc_log("Missing argument to %s", argv[i]);
				stats_update(STATS_ARGS);
				result = false;
				goto out;
			}
			output_obj = argv[i+1];
			i++;
			continue;
		}

		/* alternate form of -o, with no space */
		if (str_startswith(argv[i], "-o")) {
			output_obj = &argv[i][2];
			continue;
		}

		/* debugging is handled specially, so that we know if we
		   can strip line number info
		*/
		if (str_startswith(argv[i], "-g")) {
			args_add(stripped_args, argv[i]);
			if (enable_unify) {
				cc_log("%s used; disabling unify mode", argv[i]);
				enable_unify = false;
			}
			continue;
		}

		if (str_startswith(argv[i], "-H")) {
			cc_log("Detected -H %s", argv[i]);
			args_add(h_args, argv[i]);
			found_H_opt = true;
			continue;
		}

		/*
		 * Options taking an argument that that we may want to rewrite
		 * to relative paths to get better hit rate. A secondary effect
		 * is that paths in the standard error output produced by the
		 * compiler will be normalized.
		 */
		if (compopt_takes_path(argv[i])) {
			char *relpath;
			if (i == argc-1) {
				cc_log("Missing argument to %s", argv[i]);
				stats_update(STATS_ARGS);
				result = false;
				goto out;
			}

			args_add(stripped_args, argv[i]);
			relpath = make_relative_path(x_strdup(argv[i+1]));
			args_add(stripped_args, relpath);

			free(relpath);
			i++;
			continue;
		}

		/* Same as above but options with concatenated argument. */
		if (compopt_short(compopt_takes_path, argv[i])) {
			char *relpath;
			char *option;
			relpath = make_relative_path(x_strdup(argv[i] + 2));
			option = format("-%c%s", argv[i][1], relpath);
			args_add(stripped_args, option);
			free(relpath);
			free(option);
			continue;
		}

		/* options that take an argument */
		if (compopt_takes_arg(argv[i])) {
			if (i == argc-1) {
				cc_log("Missing argument to %s", argv[i]);
				stats_update(STATS_ARGS);
				result = false;
				goto out;
			}
			args_add(stripped_args, argv[i]);
			args_add(stripped_args, argv[i+1]);
			i++;
			continue;
		}

		if (str_eq(argv[i], "-c++")) {
			force_preprocessor_type = 2;
			args_add(stripped_args, argv[i]);
			continue;
		}
		if (str_eq(argv[i], "-noc++")) {
			force_preprocessor_type = 1;
			args_add(stripped_args, argv[i]);
			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)) {
			cc_log("%s is not a regular file, not considering as input file",
			       argv[i]);
			args_add(stripped_args, argv[i]);
			continue;
		}

		if (input_file) {
			if (language_for_file(argv[i])) {
				cc_log("Multiple input files: %s and %s", input_file, argv[i]);
				stats_update(STATS_MULTIPLE);
			} else if (!found_c_opt) {
				cc_log("Called for link with %s", argv[i]);
				if (strstr(argv[i], "conftest.")) {
					stats_update(STATS_CONFTEST);
				} else {
					stats_update(STATS_LINK);
				}
			} else {
				cc_log("Unsupported source extension: %s", argv[i]);
				stats_update(STATS_SOURCELANG);
			}
			result = false;
			goto out;
		}

		/* Rewrite to relative to increase hit rate. */
		input_file = make_relative_path(x_strdup(argv[i]));
	}

	if (!input_file) {
		cc_log("No input file found");
		stats_update(STATS_NOINPUT);
		result = false;
		goto out;
	}

	if(force_preprocessor_type == 0) { 
		actual_language = language_for_file(input_file);
	} 
	else if(force_preprocessor_type == 2) { 
		actual_language = "c++";
	}
	else {
		actual_language = "c";
	}
	
	output_is_precompiled_header =
		actual_language && strstr(actual_language, "-header") != NULL;

	if (!found_c_opt && !output_is_precompiled_header) {
		cc_log("No -c option found");
		/* 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);
		}
		result = false;
		goto out;
	}

	if (!actual_language) {
		cc_log("Unsupported source extension: %s", input_file);
		stats_update(STATS_SOURCELANG);
		result = false;
		goto out;
	}

	direct_i_file = language_is_preprocessed(actual_language);

	if (output_is_precompiled_header) {
		/* It doesn't work to create the .gch from preprocessed source. */
		cc_log("Creating precompiled header; not compiling preprocessed code");
		compile_preprocessed_source_code = false;
	}

	i_extension = getenv("CCACHE_EXTENSION");
	if (!i_extension) {
		const char *p_language = p_language_for_language(actual_language);
		if(str_eq(p_language, "c++-cpp-output")) { 
			/* Dirty fix for preprocessed file extension for cc166.
			 * The cp166 cannot handle cpp files with extension ii.*/
			i_extension = "ii.cpp";
		}
		else { 
			i_extension = extension_for_language(p_language) + 1;
		}
	}

	/* don't try to second guess the compilers heuristics for stdout handling */
	if (output_obj && str_eq(output_obj, "-")) {
		stats_update(STATS_OUTSTDOUT);
		cc_log("Output file is -");
		result = false;
		goto out;
	}

	if (!output_obj) {
		if (output_is_precompiled_header) {
			output_obj = format("%s.gch", input_file);
		} else {
			char *p;
			output_obj = x_strdup(input_file);
			if ((p = strrchr(output_obj, '/'))) {
				output_obj = p+1;
			}
			p = strrchr(output_obj, '.');
			if (!p || !p[1]) {
				cc_log("Badly formed object filename");
				stats_update(STATS_ARGS);
				result = false;
				goto out;
			}
			*p = 0;
			p = output_obj;
			if(found_S_opt)
			{ 
				output_obj = format("%s.s", p);
			}
			else
			{ /*The default extension of object file is obj for c166.*/
				output_obj = format("%s.obj", p);
			}
			free(p);
		}
	}

	/* cope with -o /dev/null */
	if (!str_eq(output_obj,"/dev/null")
	    && stat(output_obj, &st) == 0
	    && !S_ISREG(st.st_mode)) {
		cc_log("Not a regular file: %s", output_obj);
		stats_update(STATS_DEVICE);
		result = false;
		goto out;
	}

	/*
	 * Some options shouldn't be passed to the real compiler when it compiles
	 * preprocessed code:
	 */
	*preprocessor_args = args_copy(stripped_args);
	/* Args with -H has been already preprocessed.
	 * If it passed to the compiler again, some type redefined error will pop up.*/
	if (found_H_opt) {
		args_extend(*preprocessor_args, h_args);
	}

	/*
	 * Add flags for dependency generation only to the preprocessor command line.
	 */
	if (generating_dependencies) {
		if (!dependency_filename_specified) {
			char *default_depfile_name;
			char *base_name;

			base_name = remove_extension(output_obj);
			default_depfile_name = format("%s.d", base_name);
			free(base_name);
			args_add(dep_args, "-MF");
			args_add(dep_args, default_depfile_name);
			output_dep = make_relative_path(x_strdup(default_depfile_name));
		}

		if (!dependency_target_specified) {
			args_add(dep_args, "-MQ");
			args_add(dep_args, output_obj);
		}
	}

	if (compile_preprocessed_source_code) {
		*compiler_args = args_copy(stripped_args);
	} else {
		*compiler_args = args_copy(*preprocessor_args);
	}
	
	/* Due to bugs or cc166 v8.6r3, the behaviours of c/c++ preprocessor 
	 * are quite different.
	 * When using cpp preprocessor, the output will be directly send to stdout like gcc.
	 * When using c preprocessor, the output will be written to filename.i even without "-o".*/
	if(str_eq(actual_language, "c"))
	{ 
#ifdef _WIN32
#error Never test this in Windows.
#else
		args_add(*preprocessor_args, "-o/dev/stdout");
#endif
	}

	/*
	 * Only pass dependency arguments to the preprocesor since Intel's C++
	 * compiler doesn't produce a correct .d file when compiling preprocessed
	 * source.
	 */
	args_extend(*preprocessor_args, dep_args);

out:
	args_free(stripped_args);
	args_free(dep_args);
	args_free(h_args);

	return result;
}
Пример #22
0
/* 
   try to return the compile result from cache. If we can return from
   cache then this function exits with the correct status code,
   otherwise it returns */
static void from_cache(int first)
{
	int fd_stderr, fd_cpp_stderr;
	char *stderr_file;
	struct stat st;

	x_asprintf(&stderr_file, "%s.stderr", hashname);
	fd_stderr = open(stderr_file, O_RDONLY | O_BINARY);
	if (fd_stderr == -1) {
		/* it isn't in cache ... */
		free(stderr_file);
		return;
	}

	/* make sure the output is there too */
	if (stat(hashname, &st) != 0) {
		close(fd_stderr);
		unlink(stderr_file);
		free(stderr_file);
		return;
	}

	/* the user might be disabling cache hits */
#ifndef ENABLE_ZLIB
	/* if the cache file is compressed we must recache */
	if ((first && getenv("CCACHE_RECACHE")) ||
		test_if_compressed(hashname) == 1)
#else
	if (first && getenv("CCACHE_RECACHE"))
#endif
	{
		close(fd_stderr);
		unlink(stderr_file);
		free(stderr_file);
		return;
	}

	if (first) {
		int hardlink;
		int passfail = -1;

		/* update timestamps for LRU cleanup
		   also gives output_file a sensible mtime when hard-linking (for make) */
		x_utimes(stderr_file);

		hardlink = (getenv("CCACHE_HARDLINK") != 0);

		if (swig) {
			/* read the list of generated files and copy each of them out of the cache */
			FILE *file;
			char *outfiles;
			x_asprintf(&outfiles, "%s.outfiles", hashname);
			file = fopen(outfiles, "r");
			if (file) {
				char out_filename[FILENAME_MAX + 1];
				char out_filename_cache[FILENAME_MAX + 1];
				int retrieved_files_count = 0;
				x_utimes(outfiles);
				while (fgets(out_filename, FILENAME_MAX, file)) {
					char *linefeed = strchr(out_filename, '\n');
					if (linefeed) {
						char *potential_cr = linefeed - 1;
						if (potential_cr >= out_filename && *potential_cr == '\r')
						  *potential_cr = 0;
						*linefeed = 0;

						if (retrieved_files_count == 0) {
							strcpy(out_filename_cache, hashname);
						} else {
							sprintf(out_filename_cache, "%s.%d", hashname, retrieved_files_count);
						}

						passfail = retrieve_from_cache(out_filename_cache, out_filename, hardlink);
						if (passfail == -1) {
							break;
						}

						retrieved_files_count++;
					} else {
						cc_log("failed to copy output files from cache - internal error\n");
						stats_update(STATS_ERROR);
						passfail = -1;
						break;
					}
				}
				if (retrieved_files_count == 0) {
					cc_log("failed to copy output files from cache - internal error\n");
					stats_update(STATS_ERROR);
					passfail = -1;
				}
				fclose(file);
			} else {
				cc_log("failed to open cached outfiles file - %s\n", strerror(errno));
				stats_update(STATS_ERROR);
			}
		} else {
			passfail = retrieve_from_cache(hashname, output_file, hardlink);
		}

		if (passfail == -1) {
			close(fd_stderr);
			unlink(stderr_file);
			free(stderr_file);
			return;
		}
		free(stderr_file);
	}

	/* 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 | O_BINARY);
	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", input_file);
		stats_update(STATS_CACHED);
	}

	exit(0);
}
Пример #23
0
/* 
   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;
	/* is gcc being asked to output dependencies? */
	int generating_dependencies = 0;
	/* is the dependency makefile name overridden with -MF? */
	int dependency_filename_specified = 0;
	/* is the dependency makefile target name specified with -MQ or -MF? */
	int dependency_target_specified = 0;


	stripped_args = args_init(0, NULL);

	args_add(stripped_args, argv[0]);

	/* -c not required for SWIG */
	if (swig) {
		found_c_opt = 1;
	}

	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], "-fprofile-arcs") == 0 ||
		    strcmp(argv[i], "-ftest-coverage") == 0 ||
		    strcmp(argv[i], "--coverage") == 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) {
			if (!strip_c_option) {
				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 (!swig) { /* some of SWIG's arguments begin with -o */
			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;
		}

		/* These options require special handling, because they
		   behave differently with gcc -E, when the output
		   file is not specified. */

		if (strcmp(argv[i], "-MD") == 0 || strcmp(argv[i], "-MMD") == 0) {
			generating_dependencies = 1;
		} else if (strcmp(argv[i], "-MF") == 0) {
			dependency_filename_specified = 1;
		} else if (strcmp(argv[i], "-MQ") == 0 || strcmp(argv[i], "-MT") == 0) {
			dependency_target_specified = 1;
		}

		/* the input file is already preprocessed */
		if (swig && strcmp(argv[i], "-nopreprocess") == 0) {
			direct_i_file = 1;
			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();
	}

	if (swig) {
		i_extension = check_extension(input_file, NULL);
	} else {
		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 (!swig && !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;
	}

	/* If dependencies are generated, configure the preprocessor */

	if (generating_dependencies && output_file) {
		if (!dependency_filename_specified) {
			char *default_depfile_name = x_strdup(output_file);
			char *p = strrchr(default_depfile_name, '.');

			if (p) {
				if (strlen(p) < 2) {
					cc_log("badly formed dependency file %s\n", output_file);
					stats_update(STATS_ARGS);
					failed();
					return;
				}
				*p = 0;
			}
			else  {
				int len = p - default_depfile_name;
				
				p = x_malloc(len + 3);
				strncpy(default_depfile_name, p, len - 1);
				free(default_depfile_name);
				default_depfile_name = p;
			}

			strcat(default_depfile_name, ".d");
			args_add(stripped_args, "-MF");
			args_add(stripped_args, default_depfile_name);
		}

		if (!dependency_target_specified) {
			args_add(stripped_args, "-MT");
			args_add(stripped_args, output_file);
		}
	}

	/* cope with -o /dev/null */
	if (output_file && 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) {
			cc_log("could not find executable (%s)\n", e);
			stats_update(STATS_ENVIRONMMENT);
			perror(e);
			exit(1);
		}
		args_add_prefix(stripped_args, p);
	}
}
Пример #24
0
/* run the real compiler and put the result in cache */
static void to_cache(ARGS *args)
{
	char *path_stderr;
	char *tmp_stdout, *tmp_stderr, *tmp_hashname;
	struct stat st1, st2;
	int status;

	x_asprintf(&tmp_stdout, "%s/tmp.stdout.%s", temp_dir, tmp_string());
	x_asprintf(&tmp_stderr, "%s/tmp.stderr.%s", temp_dir, tmp_string());
	x_asprintf(&tmp_hashname, "%s/tmp.hash.%s.o", temp_dir, tmp_string());

	args_add(args, "-o");
	args_add(args, tmp_hashname);

	/* Turn off DEPENDENCIES_OUTPUT when running cc1, because
	 * otherwise it will emit a line like
	 *
	 *  tmp.stdout.vexed.732.o: /home/mbp/.ccache/tmp.stdout.vexed.732.i
	 *
	 * unsetenv() is on BSD and Linux but not portable. */
	putenv("DEPENDENCIES_OUTPUT");
	
	if (getenv("CCACHE_CPP2")) {
		args_add(args, input_file);
	} else {
		args_add(args, i_tmpfile);
	}
	status = execute(args->argv, tmp_stdout, tmp_stderr);
	args_pop(args, 3);

	if (stat(tmp_stdout, &st1) != 0 || st1.st_size != 0) {
		cc_log("compiler produced stdout for %s\n", output_file);
		stats_update(STATS_STDOUT);
		unlink(tmp_stdout);
		unlink(tmp_stderr);
		unlink(tmp_hashname);
		failed();
	}
	unlink(tmp_stdout);

	if (status != 0) {
		int fd;
		cc_log("compile of %s gave status = %d\n", output_file, status);
		stats_update(STATS_STATUS);

		fd = open(tmp_stderr, O_RDONLY | O_BINARY);
		if (fd != -1) {
			if (strcmp(output_file, "/dev/null") == 0 ||
			    rename(tmp_hashname, output_file) == 0 || errno == ENOENT) {
				if (cpp_stderr) {
					/* we might have some stderr from cpp */
					int fd2 = open(cpp_stderr, O_RDONLY | O_BINARY);
					if (fd2 != -1) {
						copy_fd(fd2, 2);
						close(fd2);
						unlink(cpp_stderr);
						cpp_stderr = NULL;
					}
				}

				/* we can use a quick method of
                                   getting the failed output */
				copy_fd(fd, 2);
				close(fd);
				unlink(tmp_stderr);
				if (i_tmpfile && !direct_i_file) {
					unlink(i_tmpfile);
				}
				exit(status);
			}
		}
		
		unlink(tmp_stderr);
		unlink(tmp_hashname);
		failed();
	}

	x_asprintf(&path_stderr, "%s.stderr", hashname);

	if (stat(tmp_stderr, &st1) != 0 ||
	    stat(tmp_hashname, &st2) != 0 ||
	    rename(tmp_hashname, hashname) != 0 ||
	    rename(tmp_stderr, path_stderr) != 0) {
		cc_log("failed to rename tmp files - %s\n", strerror(errno));
		stats_update(STATS_ERROR);
		failed();
	}

	cc_log("Placed %s into cache\n", output_file);
	stats_tocache(file_size(&st1) + file_size(&st2));

	free(tmp_hashname);
	free(tmp_stderr);
	free(tmp_stdout);
	free(path_stderr);
}
Пример #25
0
/* find the hash for a command. The hash includes all argument lists,
   plus the output from running the compiler with -E */
static void find_hash(ARGS *args)
{
	int i;
	char *path_stdout, *path_stderr;
	char *hash_dir;
	char *s;
	struct stat st;
	int status;
	int nlevels = 2;
	char *input_base;
	char *tmp;
	
	if ((s = getenv("CCACHE_NLEVELS"))) {
		nlevels = atoi(s);
		if (nlevels < 1) nlevels = 1;
		if (nlevels > 8) nlevels = 8;
	}

	hash_start();

	/* when we are doing the unifying tricks we need to include
           the input file name in the hash to get the warnings right */
	if (enable_unify) {
		hash_string(input_file);
	}

	/* we have to hash the extension, as a .i file isn't treated the same
	   by the compiler as a .ii file */
	hash_string(i_extension);

	/* first the arguments */
	for (i=1;i<args->argc;i++) {
		/* some arguments don't contribute to the hash. The
		   theory is that these arguments will change the
		   output of -E if they are going to have any effect
		   at all, or they only affect linking */
		if (i < args->argc-1) {
			if (strcmp(args->argv[i], "-I") == 0 ||
			    strcmp(args->argv[i], "-include") == 0 ||
			    strcmp(args->argv[i], "-L") == 0 ||
			    strcmp(args->argv[i], "-D") == 0 ||
			    strcmp(args->argv[i], "-idirafter") == 0 ||
			    strcmp(args->argv[i], "-isystem") == 0) {
				i++;
				continue;
			}
		}
		if (strncmp(args->argv[i], "-I", 2) == 0 ||
		    strncmp(args->argv[i], "-L", 2) == 0 ||
		    strncmp(args->argv[i], "-D", 2) == 0 ||
		    strncmp(args->argv[i], "-idirafter", 10) == 0 ||
		    strncmp(args->argv[i], "-isystem", 8) == 0) {
			continue;
		}

		if (strncmp(args->argv[i], "--specs=", 8) == 0 &&
		    stat(args->argv[i]+8, &st) == 0) {
			/* if given a explicit specs file, then hash that file, but
			   don't include the path to it in the hash */
			hash_file(args->argv[i]+8);
			continue;
		}

		/* all other arguments are included in the hash */
		hash_string(args->argv[i]);
	}

	/* 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!? (argv[0]='%s')\n", args->argv[0]);
		stats_update(STATS_COMPILER);
		failed();
	}

	/* also include the hash of the compiler name - as some compilers
	   use hard links and behave differently depending on the real name */
	if (st.st_nlink > 1) {
		hash_string(str_basename(args->argv[0]));
	}

	hash_int(st.st_size);
	hash_int(st.st_mtime);

	/* possibly hash the current working directory */
	if (getenv("CCACHE_HASHDIR")) {
		char *cwd = gnu_getcwd();
		if (cwd) {
			hash_string(cwd);
			free(cwd);
		}
	}

	/* ~/hello.c -> tmp.hello.123.i 
	   limit the basename to 10
	   characters in order to cope with filesystem with small
	   maximum filename length limits */
	input_base = str_basename(input_file);
	tmp = strchr(input_base, '.');
	if (tmp != NULL) {
		*tmp = 0;
	}
	if (strlen(input_base) > 10) {
		input_base[10] = 0;
	}

	/* now the run */
	x_asprintf(&path_stdout, "%s/%s.tmp.%s.%s", temp_dir,
		   input_base, tmp_string(), 
		   i_extension);
	x_asprintf(&path_stderr, "%s/tmp.cpp_stderr.%s", temp_dir, tmp_string());

	if (!direct_i_file) {
		/* run cpp on the input file to obtain the .i */
		args_add(args, "-E");
		args_add(args, input_file);
		status = execute(args->argv, path_stdout, path_stderr);
		args_pop(args, 2);
	} else {
		/* we are compiling a .i or .ii file - that means we
		   can skip the cpp stage and directly form the
		   correct i_tmpfile */
		path_stdout = input_file;
		if (create_empty_file(path_stderr) != 0) {
			stats_update(STATS_ERROR);
			cc_log("failed to create empty stderr file\n");
			failed();
		}
		status = 0;
	}

	if (status != 0) {
		if (!direct_i_file) {
			unlink(path_stdout);
		}
		unlink(path_stderr);
		cc_log("the preprocessor gave %d\n", status);
		stats_update(STATS_PREPROCESSOR);
		failed();
	}

	/* if the compilation is with -g then we have to include the whole of the
	   preprocessor output, which means we are sensitive to line number
	   information. Otherwise we can discard line number info, which makes
	   us less sensitive to reformatting changes 

	   Note! I have now disabled the unification code by default
	   as it gives the wrong line numbers for warnings. Pity.
	*/
	if (!enable_unify) {
		hash_file(path_stdout);
	} else {
		if (unify_hash(path_stdout) != 0) {
			stats_update(STATS_ERROR);
			failed();
		}
	}
	hash_file(path_stderr);

	i_tmpfile = path_stdout;

	if (!getenv("CCACHE_CPP2")) {
		/* if we are using the CPP trick then we need to remember this stderr
		   data and output it just before the main stderr from the compiler
		   pass */
		cpp_stderr = path_stderr;
	} else {	
		unlink(path_stderr);
		free(path_stderr);
	}

	/* we use a N level subdir for the cache path to reduce the impact
	   on filesystems which are slow for large directories
	*/
	s = hash_result();
	x_asprintf(&hash_dir, "%s/%c", cache_dir, s[0]);
	x_asprintf(&stats_file, "%s/stats", hash_dir);
	for (i=1; i<nlevels; i++) {
		char *p;
		if (create_dir(hash_dir) != 0) {
			cc_log("failed to create %s\n", hash_dir);
			failed();
		}
		x_asprintf(&p, "%s/%c", hash_dir, s[i]);
		free(hash_dir);
		hash_dir = p;
	}
	if (create_dir(hash_dir) != 0) {
		cc_log("failed to create %s\n", hash_dir);
		failed();
	}
	x_asprintf(&hashname, "%s/%s", hash_dir, s+nlevels);
	free(hash_dir);
}
Пример #26
0
/* 
   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);
	}
}
Пример #27
0
/* 
   try to return the compile result from cache. If we can return from
   cache then this function exits with the correct status code,
   otherwise it returns */
static void from_cache(int first)
{
	int fd_stderr, fd_cpp_stderr;
	char *stderr_file;
	int ret;
	struct stat st;

	x_asprintf(&stderr_file, "%s.stderr", hashname);
	fd_stderr = open(stderr_file, O_RDONLY | O_BINARY);
	if (fd_stderr == -1) {
		/* it isn't in cache ... */
		free(stderr_file);
		return;
	}

	/* make sure the output is there too */
	if (stat(hashname, &st) != 0) {
		close(fd_stderr);
		unlink(stderr_file);
		free(stderr_file);
		return;
	}

	/* the user might be disabling cache hits */
	if (first && getenv("CCACHE_RECACHE")) {
		close(fd_stderr);
		unlink(stderr_file);
		free(stderr_file);
		return;
	}

	utime(stderr_file, NULL);

	if (strcmp(output_file, "/dev/null") == 0) {
		ret = 0;
	} else {
		unlink(output_file);
		if (getenv("CCACHE_HARDLINK")) {
			ret = link(hashname, output_file);
		} else {
			ret = copy_file(hashname, output_file);
		}
	}

	/* the hash file might have been deleted by some external process */
	if (ret == -1 && errno == ENOENT) {
		cc_log("hashfile missing for %s\n", output_file);
		stats_update(STATS_MISSING);
		close(fd_stderr);
		unlink(stderr_file);
		return;
	}
	free(stderr_file);

	if (ret == -1) {
		ret = copy_file(hashname, output_file);
		if (ret == -1) {
			cc_log("failed to copy %s -> %s (%s)\n", 
			       hashname, output_file, strerror(errno));
			stats_update(STATS_ERROR);
			failed();
		}
	}
	if (ret == 0) {
		/* update the mtime on the file so that make doesn't get confused */
		utime(output_file, NULL);
	}

	/* 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 | O_BINARY);
	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);
}