]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
Probe whether the compiler produces a .dwo
authorJoel Rosdahl <joel@rosdahl.net>
Tue, 2 Jul 2019 11:57:11 +0000 (13:57 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Tue, 2 Jul 2019 11:57:11 +0000 (13:57 +0200)
GCC and Clang behave differently when given e.g. “-gsplit-dwarf -g1”:
GCC produces a .dwo file but Clang doesn’t. Trying to guess how the
different options behave for each compiler is complex and error prone.

Instead, Ccache now probes whether the compiler produced a .dwo and only
stores it if it was produced. On a cache hit, the .dwo is restored if it
exists in the previous result – if it doesn’t exist in the result, it
means that the compilation didn’t produce a .dwo.

Fixes #393.

src/ccache.c
test/suites/split_dwarf.bash

index ad32278efbb25bc95d92c66c67564a50d01a0e15..cb4845a974de0ed6613da1eadd46fbc5ae6c43a3 100644 (file)
@@ -183,9 +183,8 @@ static bool generating_stackusage;
 // (--serialize-diagnostics)?
 static bool generating_diagnostics;
 
-// Is the compiler being asked to separate dwarf debug info into a separate
-// file (-gsplit-dwarf)"?
-static bool using_split_dwarf;
+// Have we seen -gsplit-dwarf?
+static bool seen_split_dwarf;
 
 // Relocating debuginfo in the format old=new.
 static char **debug_prefix_maps = NULL;
@@ -1237,6 +1236,12 @@ to_cache(struct args *args, struct hash *depend_mode_hash)
                args_add(args, i_tmpfile);
        }
 
+       if (seen_split_dwarf) {
+               // Remove any preexisting .dwo since we want to check if the compiler
+               // produced one.
+               x_unlink(output_dwo);
+       }
+
        cc_log("Running real compiler");
        MTR_BEGIN("execute", "compiler");
        char *tmp_stdout;
@@ -1396,7 +1401,9 @@ to_cache(struct args *args, struct hash *depend_mode_hash)
        if (generating_diagnostics) {
                result_files_add(result_files, output_dia, ".dia");
        }
-       if (using_split_dwarf) {
+       if (seen_split_dwarf && stat(output_dwo, &st) == 0) {
+               // Only copy .dwo file if it was created by the compiler (GCC and Clang
+               // behave differently e.g. for "-gsplit-dwarf -g1").
                result_files_add(result_files, output_dwo, ".dwo");
        }
        struct stat orig_dest_st;
@@ -1725,7 +1732,7 @@ hash_common_info(struct args *args, struct hash *hash)
                }
        }
 
-       if (using_split_dwarf) {
+       if (seen_split_dwarf) {
                // When using -gsplit-dwarf, object files include a link to the
                // corresponding .dwo file based on the target object filename, so we need
                // to include the target filename in the hash to avoid handing out an
@@ -2135,7 +2142,7 @@ from_cache(enum fromcache_call_mode mode, bool put_result_in_manifest)
        struct result_files *result_files = result_files_init();
        if (!str_eq(output_obj, "/dev/null")) {
                result_files_add(result_files, output_obj, ".o");
-               if (using_split_dwarf) {
+               if (seen_split_dwarf) {
                        result_files_add(result_files, output_dwo, ".dwo");
                }
        }
@@ -2156,7 +2163,6 @@ from_cache(enum fromcache_call_mode mode, bool put_result_in_manifest)
        result_files_free(result_files);
        if (!ok) {
                cc_log("Failed to get result from cache");
-               // TODO: Add new STATS_CORRUPT statistics value and increment here?
                tmp_unlink(tmp_stderr);
                free(tmp_stderr);
                return;
@@ -2549,7 +2555,6 @@ cc_process_args(struct args *args, struct args **preprocessor_args,
                        char last_char = argv[i][strlen(argv[i]) - 1];
                        if (last_char == '0') {
                                // "-g0", "-ggdb0" or similar: All debug information disabled.
-                               // "-gsplit-dwarf" is still in effect if given previously, though.
                                generating_debuginfo = false;
                                generating_debuginfo_level_3 = false;
                        } else {
@@ -2558,7 +2563,7 @@ cc_process_args(struct args *args, struct args **preprocessor_args,
                                        generating_debuginfo_level_3 = true;
                                }
                                if (str_eq(argv[i], "-gsplit-dwarf")) {
-                                       using_split_dwarf = true;
+                                       seen_split_dwarf = true;
                                }
                        }
                        continue;
@@ -3073,13 +3078,6 @@ cc_process_args(struct args *args, struct args **preprocessor_args,
                }
        }
 
-       if (found_S_opt) {
-               // Even if -gsplit-dwarf is given, the .dwo file is not generated when -S
-               // is also given.
-               using_split_dwarf = false;
-               cc_log("Disabling caching of dwarf files since -S is used");
-       }
-
        if (!input_file) {
                cc_log("No input file found");
                stats_update(STATS_NOINPUT);
@@ -3196,7 +3194,7 @@ cc_process_args(struct args *args, struct args **preprocessor_args,
                }
        }
 
-       if (using_split_dwarf) {
+       if (seen_split_dwarf) {
                char *p = strrchr(output_obj, '.');
                if (!p || !p[1]) {
                        cc_log("Badly formed object filename");
@@ -3592,7 +3590,7 @@ cc_reset(void)
        output_is_precompiled_header = false;
 
        conf = conf_create();
-       using_split_dwarf = false;
+       seen_split_dwarf = false;
 }
 
 // Make a copy of stderr that will not be cached, so things like distcc can
index e9609879b213a0181e9e92a6709e6aaad48469c4..f912aa6167d7ba9568bac95b2b85f9065a49e8c9 100644 (file)
@@ -9,6 +9,8 @@ SUITE_split_dwarf_PROBE() {
 SUITE_split_dwarf_SETUP() {
     unset CCACHE_NODIRECT
 
+    touch test.c
+
     mkdir -p dir1/src dir1/include
     cat <<EOF >dir1/src/test.c
 #include <stdarg.h>
@@ -104,7 +106,7 @@ SUITE_split_dwarf() {
     expect_stat 'cache hit (preprocessed)' 0
     expect_stat 'cache miss' 1
     expect_stat 'files in cache' 2
-    if objdump_cmd test.o | grep_cmd "$(pwd)" >/dev/null 2>&1; then
+    if objdump_cmd test.o 2>/dev/null | grep_cmd "$(pwd)" >/dev/null 2>&1; then
         test_failed "Source dir ($(pwd)) found in test.o"
     fi
 
@@ -114,7 +116,32 @@ SUITE_split_dwarf() {
     expect_stat 'cache hit (preprocessed)' 0
     expect_stat 'cache miss' 1
     expect_stat 'files in cache' 2
-    if objdump_cmd test.o | grep_cmd "$(pwd)" >/dev/null 2>&1; then
+    if objdump_cmd test.o 2>/dev/null | grep_cmd "$(pwd)" >/dev/null 2>&1; then
         test_failed "Source dir ($(pwd)) found in test.o"
     fi
+
+    # -------------------------------------------------------------------------
+    TEST "-gsplit-dwarf -g1"
+
+    # "gcc -gsplit-dwarf -g1" produces a .dwo file, but "clang -gsplit-dwarf
+    # -g1" doesn't, so test that ccache handles it gracefully either way.
+
+    $REAL_COMPILER -gsplit-dwarf -g1 -c test.c -o reference.o
+
+    $CCACHE_COMPILE -gsplit-dwarf -g1 -c test.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache hit (preprocessed)' 0
+    expect_stat 'cache miss' 1
+    rm -f test.dwo
+
+    $CCACHE_COMPILE -gsplit-dwarf -g1 -c test.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache hit (preprocessed)' 0
+    expect_stat 'cache miss' 1
+
+    if [ -f reference.dwo ] && [ ! -f test.dwo ]; then
+        test_failed ".dwo missing"
+    elif [ ! -f reference.dwo ] && [ -f test.dwo ]; then
+        test_failed ".dwo not missing"
+    fi
 }