Only in ccache-gsplit-dwarf-support: .dir-locals.el Only in ccache-gsplit-dwarf-support: TAGS Binary files ccache/ccache and ccache-gsplit-dwarf-support/ccache differ diff '--exclude=test.sh' '--exclude=*.o' '--exclude=.gitignore' '--exclude=config.status' '--exclude=autom4te.cache' '--exclude=.deps' '--exclude=.git' '--exclude=*.txt' '--exclude=*.in' '--exclude=Makefile*' -p -uibwr ccache/ccache.c ccache-gsplit-dwarf-support/ccache.c --- ccache/ccache.c 2014-12-26 00:16:41.837925058 +0900 +++ ccache-gsplit-dwarf-support/ccache.c 2015-03-04 03:44:03.679656658 +0900 @@ -1,3 +1,4 @@ +/* -*- mode: C; indent-tabs-mode:t; tab-width:2; fill-column:78 -*- */ /* * ccache -- a fast C/C++ compiler cache * @@ -95,9 +96,15 @@ static char *output_obj; /* The path to the dependency file (implicit or specified with -MF). */ static char *output_dep; -/* Diagnostic generation information (clang). */ +/* Diagnostic generation information (clang). Contains pathname if not NULL. */ static char *output_dia = NULL; +/* -gsplit-dwarf support: Split dwarf information (GCC 4.8 and up). Contains pathname if not NULL. */ +static char *output_dwo = NULL; + +/* in conjunction with -gsplit-dwarf, try to reduce copying */ +static int called_compiler = 0; + /* * Name (represented as a struct file_hash) of the file containing the cached * object code. @@ -129,6 +136,21 @@ static char *cached_dep; static char *cached_dia; /* + * -gsplit-dwarf support: + * Full path to the file containing the split dwarf (for GCC 4.8 and above) + * (cachedir/a/b/cdef[...]-size.dwo). + * + * contains NULL if -gsplit-dwarf is not given. + */ +static char *cached_dwo; + +/* + * -gsplit-dwarf support: + * split_dwarf_p is true if "-gsplit-dwarf" is given to the compiler (GCC 4.8 and up). + */ +bool split_dwarf_p = false; + +/* * Full path to the file containing the manifest * (cachedir/a/b/cdef[...]-size.manifest). */ @@ -167,6 +189,24 @@ char *stats_file = NULL; /* Whether the output is a precompiled header */ static bool output_is_precompiled_header = false; +/* + * -gsplit-dwarf support: + * Also used for profile support (?) + * + * Whether we should output to the real object first before saving + * into cache. + * This direct output to the real object first + * becomes necessary when a produced object file needs + * to contain a valid source pathname (or part of it) such as in the + * case of .o file containing the pathname of .dwo file when + * -gsplit-dwarf is specified. + * Unless output_to_real_object_first is set to true, the recorded .dwo + * filepath in .o file ends up as that of a temporary file which is + * removed after compilation. + */ + +static bool output_to_real_object_first = false; + /* Profile generation / usage information */ static char *profile_dir = NULL; static bool profile_use = false; @@ -261,6 +301,7 @@ failed(void) fatal("execv of %s failed: %s", orig_args->argv[0], strerror(errno)); } + static const char * temp_dir() { @@ -735,19 +776,90 @@ static void to_cache(struct args *args) { char *tmp_stdout, *tmp_stderr, *tmp_dia; + char *tmp_obj; /* for supporting -gsplit-dwarf */ + char *tmp_dwo; /* for supporting -gsplit-dwarf */ + char *cp; /* for supporting -gsplit-dwarf */ struct stat st; int status, tmp_stdout_fd, tmp_stderr_fd; + /* Here cached_obj contains a file name for object */ + tmp_stdout = format("%s.tmp.stdout", cached_obj); tmp_stdout_fd = create_tmp_fd(&tmp_stdout); tmp_stderr = format("%s.tmp.stderr", cached_obj); tmp_stderr_fd = create_tmp_fd(&tmp_stderr); + /* -gsplit-dwarf support: + * we ought to create tmp_dwo path name, too + * if -gsplit-dwarf is used. + * tmp_obj will contain a file path name. + */ + if (output_to_real_object_first) { + tmp_obj = x_strdup(output_obj); + cc_log("(tmp_obj) Outputting to final destination: %s", tmp_obj); + } else { + tmp_obj = format("%s.tmp.%s", cached_obj, tmp_string()); + cc_log("(tmp_obj) Outputting to temporary destination: %s", tmp_obj); + } + + /* -gsplit-dwarf support: creating .dwo file name + * + * What is the reliable way of creating the .dwo file name + * in the case of using |-o tmp_obj| to the compiler ? + * Heuristics based on one run of GCC 4.8 is placed below, + * and it works with gcc 4.9 as well. + * + * no matter whether -gsplit-warning is placed on the + * command line, or if so, whether it has been seen or not, + * we need to set tmp_dwo here to reflect the + * value of the current tmp_obj above to tmp_dwo. + * If -gsplit-dwarf is specified on the command line, this tmp_dwo + * will be used. + */ + + // In the extreme simple case, + //if (output_to_real_object_first) { + // tmp_obj = x_strdup(output_obj); + // cc_log("Outputting to final destination: %s", tmp_obj); + // Try replacing .o with .dwo. + // + // Not sure what .dwo file path name which GCC produces in + // the following case. + // + // Fact: gcc-4.8 produced the following .dwo file for + // the command below. + // t-test.o.tmp.dwo + // + // /usr/bin/gcc-4.8 -gsplit-dwarf -c t-test.c -o t-test.o.tmp.gazonk + // + // So here is the huristics. + // Strip anything after the final '.' and add "dwo" instead. + + cp = strrchr(tmp_obj, '.'); + assert(cp); + { + /* + * String is modified in place. Since we already created the string by + * x_strdup, and format, we should be relatively safe and not + * cause unintended change even if ccache becomes multi-threaded. + */ + *cp = '\0'; + tmp_dwo = format("%s.dwo", tmp_obj); + *cp = '.'; + } + cc_log("Setting tmp_dwo to %s", tmp_dwo); + args_add(args, "-o"); - args_add(args, output_obj); + + /* change mandated by -gsplit-dwarf support above: + Let's make the compiler output to |tmp_obj| instead of output_obj*/ + args_add(args, tmp_obj); if (output_dia) { - tmp_dia = x_strdup(output_dia); + tmp_dia = output_to_real_object_first ? + x_strdup(output_dia) : + format("%s.tmp.dia.%s", cached_obj, tmp_string()); + cc_log("(tmp_dia) Outputting to final destination: %s", tmp_dia); args_add(args, "--serialize-diagnostics"); args_add(args, tmp_dia); } else { @@ -777,6 +889,13 @@ to_cache(struct args *args) stats_update(STATS_MISSING); tmp_unlink(tmp_stdout); tmp_unlink(tmp_stderr); + /* -gsplit-dwarf support */ + tmp_unlink(tmp_obj); + if (tmp_dia) { /* CI ??? TODO/FIXME: don't we need this? */ + tmp_unlink(tmp_dia); + } + if (tmp_dwo) + tmp_unlink(tmp_dwo); failed(); } if (st.st_size != 0) { @@ -784,14 +903,23 @@ to_cache(struct args *args) stats_update(STATS_STDOUT); tmp_unlink(tmp_stdout); tmp_unlink(tmp_stderr); + tmp_unlink(tmp_obj); /* -gsplit-dwarf support */ if (tmp_dia) { tmp_unlink(tmp_dia); } + if (tmp_dwo) { /* -gsplit-dwarf support */ + tmp_unlink(tmp_dwo); + } failed(); } tmp_unlink(tmp_stdout); /* + * OBSERVATION: processing stderr does not have to be + * changed in the presence of "-gsplit-dwarf". + */ + + /* * Merge stderr from the preprocessor (if any) and stderr from the real * compiler into tmp_stderr. */ @@ -838,12 +966,19 @@ to_cache(struct args *args) fd = open(tmp_stderr, O_RDONLY | O_BINARY); if (fd != -1) { - if (str_eq(output_obj, "/dev/null") || errno == ENOENT) { + if ( str_eq(output_obj, "/dev/null") + || errno == ENOENT + ) { /* we can use a quick method of getting the failed output */ copy_fd(fd, 2); close(fd); tmp_unlink(tmp_stderr); + /* Copying of _dia file should be done + * here since when an error occurs, we + * may want to know the diagnostics. + */ + if (output_dia) { int ret; x_unlink(output_dia); @@ -866,31 +1001,61 @@ to_cache(struct args *args) cc_log("Created %s from %s", output_dia, tmp_dia); } } - exit(status); } } + cc_log("verbose: (tmp_stderr) %s being removed", tmp_stderr); tmp_unlink(tmp_stderr); + + cc_log("verbose: (tmp_obj) %s being removed", tmp_obj); + tmp_unlink(tmp_obj); + if (tmp_dia) { tmp_unlink(tmp_dia); } + if (tmp_dwo) { + tmp_unlink(tmp_dwo); + } failed(); } - if (stat(output_obj, &st) != 0) { - cc_log("Compiler didn't produce an object file"); + if (stat(tmp_obj, &st) != 0) { + cc_log("(tmp_obj) Compiler didn't produce an object file"); stats_update(STATS_NOOUTPUT); failed(); } if (st.st_size == 0) { - cc_log("Compiler produced an empty object file"); + cc_log("(tmp_obj) Compiler produced an empty object file"); stats_update(STATS_EMPTYOUTPUT); failed(); } + + /* -gsplit-dwarf support: + * We should also repeat the check for .dwo file + * in addition to tmp_obj when "--gsplit-dwarf is given. + * Because of the way tmp_dwo is produced when command line + * is scanned, + * we can have non-null tmp_dwo even when split_swarf_p is false. + * Check only when split_dwarf_p is true. + */ + if (tmp_dwo && split_dwarf_p) { + /* cc_log("tmp_dwo = %s", tmp_dwo); */ + if (stat(tmp_dwo, &st) != 0) { + cc_log("(tmp_dwo) Compiler didn't produce a split dwarf file"); + stats_update(STATS_NOOUTPUT); + failed(); + } + if (st.st_size == 0) { + cc_log("(tmp_dwo) Compiler produced an empty split dwarf file"); + stats_update(STATS_EMPTYOUTPUT); + failed(); + } + } + if (stat(tmp_stderr, &st) != 0) { - cc_log("Failed to stat %s: %s", tmp_stderr, strerror(errno)); + cc_log("(tmp_stderr) Failed to stat %s: %s", tmp_stderr, strerror(errno)); stats_update(STATS_ERROR); failed(); } @@ -903,11 +1068,24 @@ to_cache(struct args *args) stats_update(STATS_ERROR); failed(); } - cc_log("Stored in cache: %s", cached_stderr); + cc_log("(cached_stderr) Stored in cache: %s", cached_stderr); + /* + * Do not forget to check return value of stat() and act accordingly. + */ if (conf->compression) { - stat(cached_stderr, &st); + /* + * The file was compressed, + * so obtain the compressed size again. + */ + if ( stat(cached_stderr, &st) == 0) { + stats_update_size(file_size(&st), 1); + } else { + cc_log("stat on cached_stderr=%s failed (%s)", cached_stderr, strerror(errno)); } + } else { stats_update_size(file_size(&st), 1); + } + } else { tmp_unlink(tmp_stderr); if (conf->recache) { @@ -918,16 +1096,69 @@ to_cache(struct args *args) if (tmp_dia) { if (stat(tmp_dia, &st) != 0) { - cc_log("Failed to stat %s: %s", tmp_dia, strerror(errno)); + cc_log("(tmp_dia) Failed to stat %s: %s", tmp_dia, strerror(errno)); stats_update(STATS_ERROR); failed(); } if (st.st_size > 0) { put_file_in_cache(tmp_dia, cached_dia); + cc_log("(cached_dia) Stored in cache: %s", cached_dia); } } - put_file_in_cache(output_obj, cached_obj); + /* Description of processing below.: + * if (output_to_real_object_first) { + * Perform the extra copy of .dwo file if --gsplit-dwarf is used. + * } else if (move_uncompressed_file(...) != 0) { + * The above line of move_uncompressed_file() + * ought to be repeated for .dwo file if --gsplit-dwarf is used. + * } + */ + + /* use tmp_obj instead of output_obj */ + put_file_in_cache(tmp_obj, cached_obj); + + cc_log("(cached_obj) Stored in cache: %s", cached_obj); + + /* stats_update(STATS_TOCACHE) is now called AFTER the processing of + * .dwo file below. + */ + + /* + * Caution: if we output to real object file first, then + * tmp_obj *IS* the real object, and so we should not remove it! + * + * Also, we should NOT copy back the cached file to the final + * destination object. This is a waste of time. + * + * Same can be said of .dwo file: real and cached one below. + * Somehow dependency file was not copied this way. + */ + if (!output_to_real_object_first) + tmp_unlink(tmp_obj); + + /* -gsplit-dwarf support: + * if -gsplit-dwarf is given on the compiler command line, + * .dwo file ought to be put into cache as well. + */ + if (split_dwarf_p) + { + assert(tmp_dwo); + assert(cached_dwo); + put_file_in_cache(tmp_dwo, cached_dwo); + cc_log("(cached_dwo) Stored in cache: %s", cached_dwo); + + /* internal sanity check */ + if (!generating_dependencies) + assert(tmp_dwo && cached_dwo); + + /* Caution: if we output to real object file first, then + * tmp_dwo *IS* the real .dwo file, and so we should not remove it! + * The original code is left as a comment line to stress this point. + */ + /* tmp_unlink(tmp_dwo); */ + } + stats_update(STATS_TOCACHE); /* Make sure we have a CACHEDIR.TAG in the cache part of cache_dir. This can @@ -948,14 +1179,17 @@ to_cache(struct args *args) * previous ccache versions. */ if (getpid() % 1000 == 0) { char *path = format("%s/CACHEDIR.TAG", conf->cache_dir); - unlink(path); + x_unlink(path); free(path); } } + free(tmp_obj); free(tmp_stderr); free(tmp_stdout); free(tmp_dia); + if (tmp_dwo) + free(tmp_dwo); } /* @@ -986,13 +1220,16 @@ get_object_name_from_cpp(struct args *ar path_stderr = format("%s/tmp.cpp_stderr", temp_dir()); path_stderr_fd = create_tmp_fd(&path_stderr); + add_pending_tmp_file(path_stderr); time_of_compilation = time(NULL); if (direct_i_file) { - /* We are compiling a .i or .ii file - that means we can skip the cpp stage - * and directly form the correct i_tmpfile. */ + /* + * we are compiling a .i or .ii file - that means we can skip + * the cpp stage and directly construct the correct i_tmpfile + */ path_stdout = input_file; status = 0; } else { @@ -1016,8 +1253,10 @@ get_object_name_from_cpp(struct args *ar } if (conf->unify) { - /* When we are doing the unifying tricks we need to include the input file - * name in the hash to get the warnings right. */ + /* + * When we are doing the unifying tricks we need to include + * the input file name in the hash to get the warnings right. + */ hash_delimiter(hash, "unifyfilename"); hash_string(hash, input_file); @@ -1077,6 +1316,29 @@ update_cached_result_globals(struct file cached_stderr = get_path_in_cache(object_name, ".stderr"); cached_dep = get_path_in_cache(object_name, ".d"); cached_dia = get_path_in_cache(object_name, ".dia"); + + /* --gsplit-dwarf support. + * We set cached_dwo to NULL + * to signify --gsplit-dwarf is not used. + */ + if (split_dwarf_p) + cached_dwo = get_path_in_cache(object_name, ".dwo"); + else + cached_dwo = NULL; + + /* TODO/NOTE: if split_dwarf_p is not true and we get non-null + * get_path_in_cache(object_name, ".dwo"), we probably should purge + * that file! But this is not so critical. We will purge the file eventually + * by LRU algorithm. + */ + if (!split_dwarf_p) { + char *cp; + cp = get_path_in_cache(object_name, ".dwo"); + if (!cp) { + cc_log("We are not using split dwarf but, we have .dwo. Maybe we should purge it.:%s", cp); + } + } + stats_file = format("%s/%c/stats", conf->cache_dir, object_name[0]); free(object_name); } @@ -1193,7 +1455,6 @@ calculate_common_hash(struct args *args, } free(p); } - /* Possibly hash GCC_COLORS (for color diagnostics). */ if (compiler_is_gcc(args)) { const char *gcc_colors = getenv("GCC_COLORS"); @@ -1328,6 +1589,10 @@ calculate_object_hash(struct args *args, hash_string(hash, args->argv[i]); } + if (split_dwarf_p) { + cc_log("Setting output_to_real_object_first to true since split_dwarf_p is true."); + output_to_real_object_first = true; + } /* * For profile generation (-fprofile-arcs, -fprofile-generate): * - hash profile directory @@ -1348,6 +1613,7 @@ calculate_object_hash(struct args *args, * artifacts will be produced in the wrong place. */ if (profile_generate) { + output_to_real_object_first = true; if (!profile_dir) { profile_dir = get_cwd(); } @@ -1355,10 +1621,18 @@ calculate_object_hash(struct args *args, hash_delimiter(hash, "-fprofile-dir"); hash_string(hash, profile_dir); } + /* OBSERVATION: processing for profile_use is a good example + * which we can mimic to implement the support for + * --gsplit-dwarf. + * + * DONE: check the reference to profile_use and mimic its + * processing. + */ 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(); @@ -1440,6 +1714,7 @@ static void from_cache(enum fromcache_call_mode mode, bool put_object_in_manifest) { int fd_stderr; + int ret; struct stat st; bool produce_dep_file; @@ -1448,28 +1723,61 @@ from_cache(enum fromcache_call_mode mode return; } - /* Check if the object file is there. */ + /* + * Check if the object file is there. + * For -gsplit-dwarf support, + * check for .dwo as well. See below + * cached_obj contains the path for cached object file. + */ + if (stat(cached_obj, &st) != 0) { - cc_log("Object file %s not in cache", cached_obj); + cc_log("(cached_obj) Object file %s not in cache", cached_obj); return; } - /* Check if the diagnostic file is there. */ + /* Check if the diagnostic file is there. + * Notice the logic. We only check when output_dia is + * not NULL. + */ if (output_dia && stat(cached_dia, &st) != 0) { - cc_log("Diagnostic file %s not in cache", cached_dia); + cc_log("(cached_dia) Diagnostic file %s not in cache", cached_dia); return; } /* * Occasionally, e.g. on hard reset, our cache ends up as just filesystem - * meta-data with no content catch an easy case of this. + * meta-data with no content. Catch an easy case of this. */ if (st.st_size == 0) { - cc_log("Invalid (empty) object file %s in cache", cached_obj); + cc_log(" (cached_obj) Invalid (empty) object file %s in cache", cached_obj); x_unlink(cached_obj); return; } + /* -gsplit-dwarf support + * We should repeat the above check for cached_dwo + */ + if (split_dwarf_p && !generating_dependencies) + assert(output_dwo); + + if (output_dwo) + assert(cached_dwo); + + if (output_dwo) { + + if (stat(cached_dwo, &st) != 0) { + cc_log("(cached_dwo) Split dwarf file %s not in cache", cached_dwo); + return; + } + + if (st.st_size == 0) { + cc_log(" (cached_dwo) Invalid (empty) dwo file %s in cache", cached_dwo); + x_unlink(cached_dwo); + x_unlink(cached_obj); /* to really invalidate */ + return; + } + } + /* * (If mode != FROMCACHE_DIRECT_MODE, the dependency file is created by * gcc.) @@ -1482,20 +1790,119 @@ from_cache(enum fromcache_call_mode mode return; } - if (!str_eq(output_obj, "/dev/null")) { + /* + * Note: In the else clause, do a similar processing for + * FissionDwarf file, cached_dwo. in case -gsplit-dwarf is specified. + */ + + if (str_eq(output_obj, "/dev/null")) { + ret = 0; + } else { /* not /dev/null */ + /* when generating object in direct mode */ + if (output_to_real_object_first && mode == FROMCACHE_COMPILED_MODE /* called compier */) { + /* we don't need to since we have called the compiler and + left the object in the final destination.*/ + cc_log("[direct object generation]: skipped copy: (output_obj) %s from (cached_obj) %s", output_obj, cached_obj); + } else { + assert( (output_to_real_object_first && (mode == FROMCACHE_CPP_MODE || mode == FROMCACHE_DIRECT_MODE)) + || (!output_to_real_object_first) ); get_file_from_cache(cached_obj, output_obj); + cc_log("Created (output_obj) %s from (cached_obj) %s", output_obj, cached_obj); } + + /* + * if something failed internal to get_file_from_cache + * we may want to remove these files: + * if (output_dwo) x_unlink(output_dwo); + * if (cached_dwo) x_unlink(cached_dwo); + * x_unlink(output_obj); + * x_unlink(cached_stderr); + * x_unlink(cached_obj); + * x_unlink(cached_dep); + *x_unlink(cached_dia); + */ + ret = 0; + } + + assert(ret == 0); + if (split_dwarf_p) { + assert(output_dwo); + assert(output_to_real_object_first); + // we don't need to get file from cache + // when we called compiler in this run of ccache since + // the output_dwo would have been created by the compiler. + if (mode == FROMCACHE_CPP_MODE || mode == FROMCACHE_DIRECT_MODE ) { + /* did not call compiler */ + get_file_from_cache(cached_dwo, output_dwo); + } else { + /* sanity check */ + assert(mode == FROMCACHE_COMPILED_MODE); + cc_log("[direct object generation]: skipped the copy from cached_dwo=%s to output_dwo=%s", + cached_dwo, output_dwo); + } + /* TODO/FIXME: + * if something failed internal to get_file_from_cache + * we may want to remove some files: the following x_unlink calls were + * in the original code circa 2014 summer. + * + * Similar comments are repeated in code below. + * + * Does failed(), which is called when error exit is taken, handle this now? + * If so, this comment is superflous. + * + * if (output_dwo) x_unlink(output_dwo); + * if (cached_dwo) x_unlink(cached_dwo); + * x_unlink(output_obj); + * x_unlink(cached_stderr); + * x_unlink(cached_obj); + * x_unlink(cached_dep); + * x_unlink(cached_dia); + * x_unlink(output_dwo); + */ + } + + /* NOTE: The error processing above assumed we only + * do a copy/hardlink for cached_obj. + * We may need to repeat the copy and error processing for cached_dwo in a similar + * manner instead of doing the copy/link only. + * + * But do note that the unlinking of related files + * MUST BE REPEATED in the both cases of the failures of copy/link + * of cached_obj -> output_obj + * and cached_dwo -> output_dwo if (split_dwarf_p). + */ + if (produce_dep_file) { get_file_from_cache(cached_dep, output_dep); + cc_log("Created (output_dep) %s from (cached_dep) %s", output_dep, cached_dep); + /* + * Note: if something failed internal to get_file_from_cache + * we may want to remove a flurry of files. + * There were calls to x_unlinks in the original code circa 2014 summer. + */ } + if (output_dia) { get_file_from_cache(cached_dia, output_dia); + cc_log("Created (output_dia) %s from (cached_dia) %s", output_dia, cached_dia); + + /* + * Note: if something failed internal to get_file_from_cache + * we may want to remove a flurry of files. + * There were calls to x_unlinks in the original code circa 2014 summer. + */ } + + /* OBSERVATION: The above seems to be the best place where we + * can copy object file and dwo file safely. + */ + /* Update modification timestamps to save files from LRU cleanup. Also gives files a sensible mtime when hard-linking. */ update_mtime(cached_obj); update_mtime(cached_stderr); + if (produce_dep_file) { update_mtime(cached_dep); } @@ -1507,13 +1914,20 @@ from_cache(enum fromcache_call_mode mode put_file_in_cache(output_dep, cached_dep); } + /* -gsplit-dwarf support */ + if (cached_dwo) + update_mtime(cached_dwo); + /* Send the stderr, if any. */ fd_stderr = open(cached_stderr, O_RDONLY | O_BINARY); if (fd_stderr != -1) { + cc_log("Using stderr cache (cached_stderr): %s\n", cached_stderr); copy_fd(fd_stderr, 2); close(fd_stderr); } + /* Note: we do not need to put .dwo file in MANIFEST file. */ + /* Create or update the manifest file. */ if (conf->direct_mode && put_object_in_manifest @@ -1528,8 +1942,17 @@ from_cache(enum fromcache_call_mode mode if (manifest_put(manifest_path, cached_obj_hash, included_files)) { cc_log("Added object file hash to %s", manifest_path); update_mtime(manifest_path); - stat(manifest_path, &st); - stats_update_size(file_size(&st) - old_size, old_size == 0 ? 1 : 0); + + /* + * Don't forget to check the return value of stat and act accordingly. + */ + if (stat(manifest_path, &st) == 0) { + stats_update_size((file_size(&st) - old_size), + old_size == 0 ? 1 : 0); + } else { + cc_log("stat on manifest (manifest_path) %s failed (%s), so size statistics is incorrect.", + manifest_path, strerror(errno)); + } } else { cc_log("Failed to add object file hash to %s", manifest_path); } @@ -1641,6 +2064,7 @@ cc_process_args(struct args *args, struc bool result = true; bool found_color_diagnostics = false; + expanded_args = args_copy(args); stripped_args = args_init(0, NULL); dep_args = args_init(0, NULL); @@ -1679,6 +2103,7 @@ cc_process_args(struct args *args, struc if (argpath[-1] == '-') { ++argpath; } + file_args = args_init_from_gcc_atfile(argpath); if (!file_args) { cc_log("Couldn't read arg file %s", argpath); @@ -1775,6 +2200,12 @@ cc_process_args(struct args *args, struc goto out; } output_obj = make_relative_path(x_strdup(argv[i+1])); + + /* OBSERVATION: We need to create output_dwo + if -gsplit-dwarf is given. But we should + not do here YET since --gsplit-dwarf may be + given later on the command line !*/ + i++; continue; } @@ -1785,6 +2216,20 @@ cc_process_args(struct args *args, struc continue; } + /* -gsplit-dwarf support + * This place is chosen as the place to handle -gsplit-dwarf. + */ + + if (str_eq(argv[i], "-gsplit-dwarf")) { + cc_log("split_dwarf_p is set to true due to -gsplit-dwarf."); + split_dwarf_p = true; + output_to_real_object_first = true; + /* we should add this option to the compiler option + when the real compiler is invoked. */ + args_add(stripped_args, argv[i]); + continue; + } + /* debugging is handled specially, so that we know if we can strip line number info */ @@ -2174,6 +2619,19 @@ cc_process_args(struct args *args, struc /* Rewrite to relative to increase hit rate. */ input_file = make_relative_path(x_strdup(argv[i])); + } /* for */ + + /* found_S_opt needs to be handled with caution + * with split_dwarf_p + */ + if (found_S_opt /* || generating_dependencies*/ ) { + /* even if -gsplit-dwarf is given, .dwo file is not generated. + * So split_dwarf_p is set to false. + */ + split_dwarf_p = false; + output_to_real_object_first = false; + cc_log("split_dwarf_p is reset to false due to found_S_opt"); + cc_log("output_to_real_object_first is set to false, too"); } if (!input_file) { @@ -2212,7 +2670,7 @@ cc_process_args(struct args *args, struc } output_is_precompiled_header = - actual_language && strstr(actual_language, "-header"); + (actual_language && strstr(actual_language, "-header")); if (output_is_precompiled_header && !(conf->sloppiness & SLOPPY_PCH_DEFINES)) { @@ -2235,6 +2693,8 @@ cc_process_args(struct args *args, struc } else { stats_update(STATS_LINK); } + // git dev does not have the following line. Oct 10, 2014 + // stats_update(STATS_CANTUSEPCH); result = false; goto out; } @@ -2261,6 +2721,12 @@ cc_process_args(struct args *args, struc conf->cpp_extension = x_strdup(extension_for_language(p_language) + 1); } + /* Question: Is there an angle in which split_dwarf_p processing + * has anything to do with "-" output that is handled specialy below? + * For example, what do we want to do with .dwo file. + * We may find the answer in the long run. + */ + /* don't try to second guess the compilers heuristics for stdout handling */ if (output_obj && str_eq(output_obj, "-")) { stats_update(STATS_OUTSTDOUT); @@ -2269,6 +2735,56 @@ cc_process_args(struct args *args, struc goto out; } + /* -gsplit-dwarf support: + * We have probably already seen and check for + * -gsplit-dwarf by the time we reach here. (We did it somewhere above.) + * Here is the chance to create output_dwo based on the value of output_obj. + * The basic outline would be + * output_obj = basename(input_file) + * add ".dwo" to it with minor tweaks to handle special cases. + */ + + /* + * Special case 1: What do we do if we need to output .s file + * for output and -gsplit-dwarf is specified? + * What file(s) does GCC 4.8 produce exactly? + * Answer: + * /usr/bin/gcc-4.8 -gsplit-dwarf -c t-test.c -S + * generated + * t-test.s + * that contains assembler directives to generate data (dwarf data). + * This means that if we are only producing assembler source + * we do not need to handle ".dwo" file at all. + * + * Special case 2: + * /usr/bin/gcc-4.8 -gsplit-dwarf -c t-test.c -S -o t-test.s.gazonk + * produced + * t-test.s.gazonk + * + * DONE: + * The above special cases need to be handled. + * The modification below more or less assumed that .dwo file is produced + * always (together with the paired .o file) unless "-S" is specified. + * + * File-scope global variable |found_S_opt| is set to true + * when "-S" is specified. + * + * /usr/bin/gcc-4.8 -gsplit-dwarf -c t-test.s + * produced + * t-test.o + * t-test.o.dwo. + * + * So let us disable split_dwarf_p to false if + * found_S_opt is true. + * This is done at the end of a loop in argument processing. + */ + + /* + * This clarifies the change for -gsplit-dwarf. We always use + * output_obj instead of tmp_obj even in the case of "-gsplit-dwarf" + * in the code below. + */ + if (!output_obj) { if (output_is_precompiled_header) { output_obj = format("%s.gch", input_file); @@ -2287,6 +2803,31 @@ cc_process_args(struct args *args, struc } } + /* -gsplit-dwarf support: create output_dwo */ + if (split_dwarf_p && !found_S_opt) { + char *p; + p = strrchr(output_obj, '.'); + if (!p || !p[1]) { + cc_log("Badly formed object filename"); + stats_update(STATS_ARGS); + result = false; + goto out; + } + *p = '\0'; + output_dwo = format("%s.dwo", output_obj); + *p = '.'; + + cc_log("setting output_dwo to %s", output_dwo); + } + + + /* Long-term question: Do we need to cope with strange output_obj file + * name in case split_dwarf_p? + * "-gsplit-dwarf" support may encounter corner cases when strange + * file names are given. + * We may find the answer in the long run. + */ + /* cope with -o /dev/null */ if (!str_eq(output_obj,"/dev/null") && stat(output_obj, &st) == 0 @@ -2315,6 +2856,7 @@ cc_process_args(struct args *args, struc args_add(cpp_args, explicit_language); } + /* * Since output is redirected, compilers will not color their output by * default, so force it explicitly if it would be otherwise done. @@ -2337,6 +2879,20 @@ cc_process_args(struct args *args, struc } } + /* -gsplit-dwarf support: Ordering of dependency generation. + * + * -gsplit-dwarf processing should not affect dependency generation. + * + * Note, given the command line below, dependency file is generated + * first and then ccache.o is generated. + * Observing the ordering and take care of that. + * + * ccache /usr/bin/gcc-4.8 -gsplit-dwarf -DHAVE_CONFIG_H \ + * -DSYSCONFDIR=/usr/local/etc -I. -I. -MD -MP -MF .deps/ccache.c.d \ + * -g -O2 -Wall -W -Werror -c -o ccache.o ccache.c + * + */ + /* * Add flags for dependency generation only to the preprocessor command line. */ @@ -2469,10 +3025,12 @@ initialize(void) if (str_eq(conf->cache_dir, "")) { fatal("configuration setting \"cache_dir\" must not be the empty string"); } + if ((p = getenv("CCACHE_DIR"))) { free(conf->cache_dir); conf->cache_dir = strdup(p); } + if (str_eq(conf->cache_dir, "")) { fatal("CCACHE_DIR must not be the empty string"); } @@ -2509,6 +3067,7 @@ initialize(void) if (conf->umask != UINT_MAX) { umask(conf->umask); } + } /* Reset the global state. Used by the test suite. */ @@ -2524,10 +3083,12 @@ cc_reset(void) args_free(orig_args); orig_args = NULL; free(input_file); input_file = NULL; free(output_obj); output_obj = NULL; + if (output_dwo) free(output_dwo); output_dwo = NULL; free(output_dep); output_dep = NULL; free(output_dia); output_dia = NULL; free(cached_obj_hash); cached_obj_hash = NULL; free(cached_obj); cached_obj = NULL; + if (cached_dwo) free(cached_dwo); cached_dwo = NULL; free(cached_stderr); cached_stderr = NULL; free(cached_dep); cached_dep = NULL; free(cached_dia); cached_dia = NULL; @@ -2544,6 +3105,7 @@ cc_reset(void) output_is_precompiled_header = false; conf = conf_create(); + split_dwarf_p = false; } /* Make a copy of stderr that will not be cached, so things like @@ -2604,6 +3166,8 @@ ccache(int argc, char *argv[]) signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); + + /* this one added Oct 2014 */ if (str_eq(conf->temporary_dir, "")) { clean_up_internal_tempdir(); } @@ -2639,7 +3203,33 @@ ccache(int argc, char *argv[]) if (output_dia) { cc_log("Diagnostic file: %s", output_dia); } - cc_log("Object file: %s", output_obj); + + /* + * Note: cc_process_args ought to have generated output_dwo. But we + * may not want to do so before generating dependencies because it has + * been the implicit ordering that the dependency is generated first + * and then object file is generated. + * See a block comment that starts with + * "-gsplit-dwarf support: Ordering of dependency generation." + * in the earlier part of this file. + */ + + if (split_dwarf_p ) { + if (output_dia) + cc_log("output_dia = %s", output_dia); + if (output_dwo) + cc_log("output_dwo = %s", output_dwo); + fflush(stdout); + if (!generating_dependencies) + assert (output_dwo); + } else { + assert (!output_dwo); + } + + if (!generating_dependencies && output_dwo) { + cc_log("Split dwarf file: %s", output_dwo); + } + cc_log("(output_obj) Object file: %s", output_obj); hash_start(&common_hash); calculate_common_hash(preprocessor_args, &common_hash); @@ -2713,6 +3303,8 @@ ccache(int argc, char *argv[]) put_object_in_manifest = true; } + called_compiler = 0; + /* if we can return from cache at this point then do */ from_cache(FROMCACHE_CPP_MODE, put_object_in_manifest); @@ -2726,6 +3318,8 @@ ccache(int argc, char *argv[]) /* run real compiler, sending output to cache */ to_cache(compiler_args); + called_compiler = 1; + /* return from cache */ from_cache(FROMCACHE_COMPILED_MODE, put_object_in_manifest); @@ -2896,3 +3490,8 @@ ccache_main(int argc, char *argv[]) ccache(argc, argv); return 1; } +/* + * ;; Local Variables: + * ;; eval: (smart-tabs-mode) + * ;; End: + */ diff '--exclude=test.sh' '--exclude=*.o' '--exclude=.gitignore' '--exclude=config.status' '--exclude=autom4te.cache' '--exclude=.deps' '--exclude=.git' '--exclude=*.txt' '--exclude=*.in' '--exclude=Makefile*' -p -uibwr ccache/compopt.c ccache-gsplit-dwarf-support/compopt.c --- ccache/compopt.c 2014-12-26 00:16:41.857924683 +0900 +++ ccache-gsplit-dwarf-support/compopt.c 2014-10-31 01:23:27.861419530 +0900 @@ -60,7 +60,6 @@ static const struct compopt compopts[] = {"-frepo", TOO_HARD}, {"-ftest-coverage", TOO_HARD}, /* generates a .gcno file at the same time */ {"-fworking-directory", AFFECTS_CPP}, - {"-gsplit-dwarf", TOO_HARD}, /* generates a .dwo file at the same time */ {"-idirafter", AFFECTS_CPP | TAKES_ARG | TAKES_PATH}, {"-iframework", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH}, {"-imacros", AFFECTS_CPP | TAKES_ARG | TAKES_PATH}, Only in ccache-gsplit-dwarf-support: do-diff.sh Only in ccache-gsplit-dwarf-support: do-test.sh diff '--exclude=test.sh' '--exclude=*.o' '--exclude=.gitignore' '--exclude=config.status' '--exclude=autom4te.cache' '--exclude=.deps' '--exclude=.git' '--exclude=*.txt' '--exclude=*.in' '--exclude=Makefile*' -p -uibwr ccache/getopt_long.c ccache-gsplit-dwarf-support/getopt_long.c --- ccache/getopt_long.c 2014-10-12 00:17:29.047986193 +0900 +++ ccache-gsplit-dwarf-support/getopt_long.c 2015-03-04 02:58:03.069419670 +0900 @@ -88,7 +88,7 @@ getopt_long(int argc, char *const argv[] place++; namelen = strcspn(place, "="); - for (i = 0; longopts[i].name != NULL; i++) + for (i = 0; longopts[i].name; i++) { if (strlen(longopts[i].name) == namelen && strncmp(place, longopts[i].name, namelen) == 0) @@ -131,7 +131,7 @@ getopt_long(int argc, char *const argv[] place = EMSG; - if (longopts[i].flag == NULL) + if (!longopts[i].flag) return longopts[i].val; else { diff '--exclude=test.sh' '--exclude=*.o' '--exclude=.gitignore' '--exclude=config.status' '--exclude=autom4te.cache' '--exclude=.deps' '--exclude=.git' '--exclude=*.txt' '--exclude=*.in' '--exclude=Makefile*' -p -uibwr ccache/hash.c ccache-gsplit-dwarf-support/hash.c --- ccache/hash.c 2014-12-26 00:16:41.857924683 +0900 +++ ccache-gsplit-dwarf-support/hash.c 2015-03-04 03:36:51.011393317 +0900 @@ -128,6 +128,7 @@ hash_file(struct mdfour *md, const char fd = open(fname, O_RDONLY|O_BINARY); if (fd == -1) { + cc_log("hash file creation (%s) failed\n", fname); /* to catch strange errors */ return false; } diff '--exclude=test.sh' '--exclude=*.o' '--exclude=.gitignore' '--exclude=config.status' '--exclude=autom4te.cache' '--exclude=.deps' '--exclude=.git' '--exclude=*.txt' '--exclude=*.in' '--exclude=Makefile*' -p -uibwr ccache/language.c ccache-gsplit-dwarf-support/language.c --- ccache/language.c 2014-12-26 00:16:41.857924683 +0900 +++ ccache-gsplit-dwarf-support/language.c 2015-03-04 02:58:03.049416262 +0900 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010, 2013 Joel Rosdahl + * Copyright (C) 2010-2014 Joel Rosdahl * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -147,7 +147,7 @@ extension_for_language(const char *langu bool language_is_supported(const char *language) { - return p_language_for_language(language); + return p_language_for_language(language) != NULL; } bool diff '--exclude=test.sh' '--exclude=*.o' '--exclude=.gitignore' '--exclude=config.status' '--exclude=autom4te.cache' '--exclude=.deps' '--exclude=.git' '--exclude=*.txt' '--exclude=*.in' '--exclude=Makefile*' -p -uibwr ccache/manifest.c ccache-gsplit-dwarf-support/manifest.c --- ccache/manifest.c 2014-12-26 00:16:41.857924683 +0900 +++ ccache-gsplit-dwarf-support/manifest.c 2014-12-25 23:12:56.452006551 +0900 @@ -70,6 +70,7 @@ static const uint32_t MAGIC = 0x63436d46 static const uint32_t MAX_MANIFEST_ENTRIES = 100; static const uint32_t MAX_MANIFEST_FILE_INFO_ENTRIES = 10000; + #define ccache_static_assert(e) \ do { enum { ccache_static_assert__ = 1/(e) }; } while (false) @@ -598,11 +599,31 @@ add_object_entry(struct manifest *mf, obj = &mf->objects[n]; n = hashtable_count(included_files); +#if defined(CI_DEBUG) + { + char tmpbuf[128]; + snprintf(tmpbuf, 128, "add_object_entry: hashtable_count = %d", n); + cc_log(tmpbuf); + } +#endif + obj->n_file_info_indexes = n; obj->file_info_indexes = x_malloc(n * sizeof(*obj->file_info_indexes)); add_file_info_indexes(obj->file_info_indexes, n, mf, included_files); memcpy(obj->hash.hash, object_hash->hash, mf->hash_size); obj->hash.size = object_hash->size; +#if defined(CI_DEBUG) + { + int i; + static char tmpbuf[1024]; + unsigned char *cp = (unsigned char *) obj->hash.hash ; + n = snprintf(tmpbuf, 1024,"add_object_entry: "); + for(i = 0; i < mf->hash_size; i++) + snprintf(&tmpbuf[n+i*2], 1024 - n - i * 2, "%02x", cp[i]); + snprintf(&tmpbuf[1024 - n - i * 2 + 2], 1024, "\n"); + cc_log(tmpbuf); + } +#endif } /* diff '--exclude=test.sh' '--exclude=*.o' '--exclude=.gitignore' '--exclude=config.status' '--exclude=autom4te.cache' '--exclude=.deps' '--exclude=.git' '--exclude=*.txt' '--exclude=*.in' '--exclude=Makefile*' -p -uibwr ccache/snprintf.c ccache-gsplit-dwarf-support/snprintf.c --- ccache/snprintf.c 2014-10-12 00:17:29.047986193 +0900 +++ ccache-gsplit-dwarf-support/snprintf.c 2015-03-04 02:58:02.997407288 +0900 @@ -574,7 +574,7 @@ rpl_vsnprintf(char *str, size_t size, co * (Though some of these versions will write to a non-NULL buffer even * if a size of zero was specified, which violates the standard.) */ - if (str == NULL && size != 0) + if (!str && size != 0) size = 0; while (ch != '\0') @@ -856,7 +856,7 @@ rpl_vsnprintf(char *str, size_t size, co * characters, in an implementation-defined * manner." (C99: 7.19.6.1, 8) */ - if ((strvalue = va_arg(args, void *)) == NULL) + if (!(strvalue = va_arg(args, void *))) /* * We use the glibc format. BSD prints * "0x0", SysV "0". @@ -951,7 +951,7 @@ fmtstr(char *str, size_t *len, size_t si int padlen, strln; /* Amount to pad. */ int noprecision = (precision == -1); - if (value == NULL) /* We're forgiving. */ + if (!value) /* We're forgiving. */ value = "(null)"; /* If a precision was specified, don't read the string past it. */ @@ -1128,7 +1128,7 @@ fmtflt(char *str, size_t *len, size_t si else if (ISINF(fvalue)) infnan = (flags & PRINT_F_UP) ? "INF" : "inf"; - if (infnan != NULL) { + if (!infnan) { if (sign != 0) iconvert[ipos++] = sign; while (*infnan != '\0') @@ -1344,7 +1344,7 @@ again: } if (emitpoint) { /* Decimal point. */ #if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT - if (lc->decimal_point != NULL && *lc->decimal_point != '\0') + if (lc->decimal_point && *lc->decimal_point != '\0') OUTCHAR(str, *len, size, *lc->decimal_point); else /* We'll always print some decimal point character. */ #endif /* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */ @@ -1375,7 +1375,7 @@ printsep(char *str, size_t *len, size_t struct lconv *lc = localeconv(); int i; - if (lc->thousands_sep != NULL) + if (lc->thousands_sep) for (i = 0; lc->thousands_sep[i] != '\0'; i++) OUTCHAR(str, *len, size, lc->thousands_sep[i]); else @@ -1392,7 +1392,7 @@ getnumsep(int digits) struct lconv *lc = localeconv(); /* We support an arbitrary separator length (including zero). */ - if (lc->thousands_sep != NULL) { + if (lc->thousands_sep) { for (strln = 0; lc->thousands_sep[strln] != '\0'; strln++) continue; separators *= strln; @@ -1511,7 +1511,7 @@ rpl_vasprintf(char **ret, const char *fo VA_COPY(aq, ap); len = vsnprintf(NULL, 0, format, aq); VA_END_COPY(aq); - if (len < 0 || (*ret = malloc(size = len + 1)) == NULL) + if (len < 0 || !(*ret = malloc(size = len + 1))) return -1; return vsnprintf(*ret, size, format, ap); } @@ -2066,7 +2066,7 @@ main(void) #endif /* defined(TEST) */ #define TEST(fmt, val) \ do { \ - for (i = 0; fmt[i] != NULL; i++) \ + for (i = 0; fmt[i]; i++) \ for (j = 0; j == 0 || val[j - TEST_NILS] != 0; j++) { \ r1 = sprintf(buf1, fmt[i], val[j]); \ r2 = snprintf(buf2, sizeof(buf2), fmt[i], val[j]); \ diff '--exclude=test.sh' '--exclude=*.o' '--exclude=.gitignore' '--exclude=config.status' '--exclude=autom4te.cache' '--exclude=.deps' '--exclude=.git' '--exclude=*.txt' '--exclude=*.in' '--exclude=Makefile*' -p -uibwr ccache/system.h ccache-gsplit-dwarf-support/system.h --- ccache/system.h 2014-12-26 00:16:41.857924683 +0900 +++ ccache-gsplit-dwarf-support/system.h 2014-10-31 01:23:27.865419389 +0900 @@ -38,6 +38,7 @@ #include #include #include +/* strange: without signal.h, the compilation succeeded ? */ #include #include #include Binary files ccache/test/main and ccache-gsplit-dwarf-support/test/main differ Only in ccache: testdir.18714 Only in ccache: testdir.19069 Only in ccache: testdir.20915 Only in ccache: testdir.2264 Only in ccache-gsplit-dwarf-support: testdir.3089 Only in ccache-gsplit-dwarf-support: testdir.865 diff '--exclude=test.sh' '--exclude=*.o' '--exclude=.gitignore' '--exclude=config.status' '--exclude=autom4te.cache' '--exclude=.deps' '--exclude=.git' '--exclude=*.txt' '--exclude=*.in' '--exclude=Makefile*' -p -uibwr ccache/util.c ccache-gsplit-dwarf-support/util.c --- ccache/util.c 2014-12-26 00:16:41.857924683 +0900 +++ ccache-gsplit-dwarf-support/util.c 2015-03-04 03:37:09.043230760 +0900 @@ -108,15 +108,28 @@ path_max(const char *path) } static void +warn_log_fail() { + fprintf(stderr, + "Writing to logfile failed.\n" + "Check the permission and make sure there is enough room for writing to the filesystem.\n"); + /* maybe we should exit here? */ +} + +static void vlog(const char *format, va_list ap, bool log_updated_time) { + int rc1, rc2; if (!init_log()) { return; } log_prefix(log_updated_time); - vfprintf(logfile, format, ap); - fprintf(logfile, "\n"); + rc1 = vfprintf(logfile, format, ap); + rc2 = fprintf(logfile, "\n"); + if (rc1 < 0 || rc2 < 0) { + warn_log_fail(); + } + } /* @@ -153,6 +166,7 @@ cc_bulklog(const char *format, ...) void cc_log_argv(const char *prefix, char **argv) { + int rc; if (!init_log()) { return; } @@ -160,7 +174,9 @@ cc_log_argv(const char *prefix, char **a log_prefix(true); fputs(prefix, logfile); print_command(logfile, argv); - fflush(logfile); + rc = fflush(logfile); + if (rc) + warn_log_fail(); } /* something went badly wrong! */ @@ -245,7 +261,7 @@ get_umask(void) int copy_file(const char *src, const char *dest, int compress_level) { - int fd_in, fd_out; + int fd_in = -1, fd_out = -1; gzFile gz_in = NULL, gz_out = NULL; char buf[10240]; int n, written; @@ -769,7 +785,7 @@ traverse(const char *dir, void (*fn)(con fname = format("%s/%s", dir, de->d_name); if (lstat(fname, &st)) { if (errno != ENOENT) { - perror(fname); + cc_log("lstat on file %s failed.", fname); } free(fname); continue; @@ -1073,7 +1089,6 @@ create_tmp_fd(char **fname) if (fd == -1) { fatal("Failed to create file %s: %s", template, strerror(errno)); } - #ifndef _WIN32 fchmod(fd, 0666 & ~get_umask()); #endif @@ -1318,8 +1333,14 @@ x_rename(const char *oldpath, const char int tmp_unlink(const char *path) { - cc_log("Unlink %s", path); - return unlink(path); + /* verbose for debugging -gsplit-dwarf */ + int rc; + cc_log("tmp_unlink:Unlink %s", path); + rc = unlink(path); + if (rc) { + cc_log("tmp_unlink:Unlink failed: rc = %d", rc); + } + return rc; } /* @@ -1335,7 +1356,7 @@ x_unlink(const char *path) */ char *tmp_name = format("%s.rm.%s", path, tmp_string()); int result = 0; - cc_log("Unlink %s via %s", path, tmp_name); + cc_log("x_unlink: Unlink %s via %s", path, tmp_name); if (x_rename(path, tmp_name) == -1) { result = -1; goto out; @@ -1348,6 +1369,10 @@ x_unlink(const char *path) } out: free(tmp_name); + if (result) { + /* verbose for debugging -gsplit-dwarf */ + cc_log("x_unlink: failed result = %d", result); + } return result; } diff '--exclude=test.sh' '--exclude=*.o' '--exclude=.gitignore' '--exclude=config.status' '--exclude=autom4te.cache' '--exclude=.deps' '--exclude=.git' '--exclude=*.txt' '--exclude=*.in' '--exclude=Makefile*' -p -uibwr ccache/version.c ccache-gsplit-dwarf-support/version.c --- ccache/version.c 2014-12-26 00:10:38.346977900 +0900 +++ ccache-gsplit-dwarf-support/version.c 2015-03-04 03:40:12.201791019 +0900 @@ -1 +1 @@ -const char CCACHE_VERSION[] = "3.2.1+1_g090af0a"; +const char CCACHE_VERSION[] = "3.1.9+351_g6e8a023_dirty";