} else {
tmp_unlink(tmp_stderr);
}
- if (move_uncompressed_file(tmp_obj, cached_obj, conf->compression) != 0) {
+
+ if (output_to_real_object_first) {
+ int ret;
- if (getenv("CCACHE_HARDLINK") && !enable_compression) {
++ if (getenv("CCACHE_HARDLINK") && !conf->compression) {
+ ret = link(tmp_obj, cached_obj);
+ } else {
- ret = copy_file(tmp_obj, cached_obj, enable_compression);
++ ret = copy_file(tmp_obj, cached_obj, conf->compression);
+ }
+ if (ret != 0) {
+ cc_log("Failed to copy/link %s to %s: %s", tmp_obj, cached_obj, strerror(errno));
+ stats_update(STATS_ERROR);
+ failed();
+ }
- } else if (move_uncompressed_file(tmp_obj, cached_obj, enable_compression) != 0) {
++ } else if (move_uncompressed_file(tmp_obj, cached_obj, conf->compression) != 0) {
cc_log("Failed to move %s to %s: %s", tmp_obj, cached_obj, strerror(errno));
stats_update(STATS_ERROR);
failed();
hash_string(hash, args->argv[i]);
}
+ /*
+ * For profile generation (-fprofile-arcs, -fprofile-generate):
+ * - hash profile directory
+ * - output to the real file first
+ *
+ * For profile usage (-fprofile-use):
+ * - hash profile data
+ *
+ * -fbranch-probabilities and -fvpt usage is covered by
+ * -fprofile-generate/-fprofile-use.
+ *
+ * The profile directory can be specified as an argument to
+ * -fprofile-generate=, -fprofile-use=, or -fprofile-dir=.
+ */
+
+ /*
+ * We need to output to the real object first here, otherwise runtime
+ * artifacts will be produced in the wrong place.
+ */
+ if (profile_generate) {
+ output_to_real_object_first = true;
+ if (!profile_dir) {
+ profile_dir = get_cwd();
+ }
+ cc_log("Adding profile directory %s to our hash", profile_dir);
+ hash_delimiter(hash, "-fprofile-dir");
+ hash_string(hash, profile_dir);
+ }
+ if (profile_use) {
+ /* Calculate gcda name */
+ char *gcda_name;
+ char *base_name;
+ output_to_real_object_first = true;
+ base_name = remove_extension(output_obj);
+ if (!profile_dir) {
+ profile_dir = get_cwd();
+ }
+ gcda_name = format("%s/%s.gcda", profile_dir, base_name);
+ cc_log("Adding profile data %s to our hash", gcda_name);
+ /* Add the gcda to our hash */
+ hash_delimiter(hash, "-fprofile-use");
+ hash_file(hash, gcda_name);
+ free(base_name);
+ free(gcda_name);
+ }
+
if (direct_mode) {
- if (!(sloppiness & SLOPPY_FILE_MACRO)) {
+ if (!(conf->sloppiness & SLOPPY_FILE_MACRO)) {
/*
* The source code file or an include file may contain
* __FILE__, so make sure that the hash is unique for
void
cc_reset(void)
{
+ conf_free(conf); conf = NULL;
+ free(primary_config_path); primary_config_path = NULL;
+ free(secondary_config_path); secondary_config_path = NULL;
free(current_working_dir); current_working_dir = NULL;
- free(cache_dir); cache_dir = NULL;
- cache_logfile = NULL;
- base_dir = NULL;
+ free(profile_dir); profile_dir = NULL;
+ args_free(orig_args); orig_args = NULL;
free(input_file); input_file = NULL;
free(output_obj); output_obj = NULL;
free(output_dep); output_dep = NULL;
}
#endif
}
+ #endif /* !_WIN32 */
+static void
+vlog(const char *format, va_list ap, bool log_updated_time)
+{
+ if (!init_log()) {
+ return;
+ }
+
+ log_prefix(log_updated_time);
+ vfprintf(logfile, format, ap);
+ fprintf(logfile, "\n");
+}
+
/*
- * Write a message to the CCACHE_LOGFILE location (adding a newline).
+ * Write a message to the log file (adding a newline) and flush.
+ */
+void
+cc_vlog(const char *format, va_list ap)
+{
+ vlog(format, ap, true);
+}
+
+/*
+ * Write a message to the log file (adding a newline) and flush.
*/
void
cc_log(const char *format, ...)
return s;
}
-/* return a value in multiples of 1024 give a string that can end
- in K, M or G
-*/
-size_t
-value_units(const char *s)
+/* Format a size as a parsable string. Caller frees. */
+char *
+format_parsable_size_with_suffix(uint64_t size)
{
- char m;
- double v = atof(s);
- m = s[strlen(s)-1];
- switch (m) {
- case 'G':
- case 'g':
- default:
- v *= 1024*1024;
- break;
- case 'M':
- case 'm':
- v *= 1024;
- break;
- case 'K':
- case 'k':
- v *= 1;
- break;
- }
- return (size_t)v;
+ char *s;
+ if (size >= 1000*1000*1000) {
+ s = format("%.1fG", size / ((double)(1000*1000*1000)));
+ } else if (size >= 1000*1000) {
+ s = format("%.1fM", size / ((double)(1000*1000)));
+ } else if (size >= 1000) {
+ s = format("%.1fk", size / ((double)(1000)));
+ } else {
+ s = format("%u", (unsigned)size);
+ }
+ return s;
+}
+
+/*
+ * Parse a "size value", i.e. a string that can end in k, M, G, T (10-based
+ * suffixes) or Ki, Mi, Gi, Ti (2-based suffixes). For backward compatibility,
+ * K is also recognized as a synonym of k.
+ */
+bool
+parse_size_with_suffix(const char *str, uint64_t *size)
+{
+ char *p;
+ double x;
+
+ errno = 0;
+ x = strtod(str, &p);
+ if (errno != 0 || x < 0 || p == str || *str == '\0') {
+ return false;
+ }
+
+ while (isspace(*p)) {
+ ++p;
+ }
+
+ if (*p != '\0') {
+ unsigned multiplier;
+ if (*(p+1) == 'i') {
+ multiplier = 1024;
+ } else {
+ multiplier = 1000;
+ }
+ switch (*p) {
+ case 'T':
+ x *= multiplier;
+ case 'G':
+ x *= multiplier;
+ case 'M':
+ x *= multiplier;
+ case 'K':
+ case 'k':
+ x *= multiplier;
+ break;
+ default:
+ return false;
+ }
+ }
+ *size = x;
+ return true;
}
+ #ifndef _WIN32
/*
a sane realpath() function, trying to cope with stupid path limits and
a broken API