]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
Support .d dependency file generation via environment variables 349/head
authorMaarten Maathuis <madman2003@shikahr.net>
Fri, 11 Jan 2019 23:29:36 +0000 (00:29 +0100)
committerMaarten Maathuis <madman2003@shikahr.net>
Sat, 12 Jan 2019 01:57:37 +0000 (02:57 +0100)
Previously "DEPENDENCIES_OUTPUT="test.d" gcc -c test.c" and
"SUNPRO_DEPENDENCIES="test.d" gcc -c test.c" would not cache
the .d dependency files.

configure.ac
src/ccache.c
src/ccache.h
src/util.c
test/run
test/suites/direct_gcc.bash [new file with mode: 0644]

index e8c34dbecf21d4f9871cee6edd69ff477d8e20fb..b44a7213b7a3a48c17b007a1064296a419683d9f 100644 (file)
@@ -85,6 +85,7 @@ AC_CHECK_FUNCS(getpwuid)
 AC_CHECK_FUNCS(gettimeofday)
 AC_CHECK_FUNCS(mkstemp)
 AC_CHECK_FUNCS(realpath)
+AC_CHECK_FUNCS(setenv)
 AC_CHECK_FUNCS(strndup)
 AC_CHECK_FUNCS(strtok_r)
 AC_CHECK_FUNCS(unsetenv)
index c7e949fe20a7a60bb6ad3525b826b11871f9c00c..af2461203284e036b595c0aa1b45cf3e5b4cbd3f 100644 (file)
@@ -1346,6 +1346,7 @@ to_cache(struct args *args, struct hash *depend_mode_hash)
        //
        //   tmp.stdout.vexed.732.o: /home/mbp/.ccache/tmp.stdout.vexed.732.i
        x_unsetenv("DEPENDENCIES_OUTPUT");
+       x_unsetenv("SUNPRO_DEPENDENCIES");
 
        if (conf->run_second_cpp) {
                args_add(args, input_file);
@@ -2384,6 +2385,9 @@ cc_process_args(struct args *args, struct args **preprocessor_args,
        bool dependency_filename_specified = false;
        // Is the dependency makefile target name specified with -MT or -MQ?
        bool dependency_target_specified = false;
+       // Is the dependency target name implicitly specified using
+       // DEPENDENCIES_OUTPUT or SUNPRO_DEPENDENCIES?
+       bool dependency_implicit_target_specified = false;
        // expanded_args is a copy of the original arguments given to the compiler
        // but with arguments from @file and similar constructs expanded. It's only
        // used as a temporary data structure to loop over.
@@ -3075,6 +3079,50 @@ cc_process_args(struct args *args, struct args **preprocessor_args,
                }
        } // for
 
+       // See http://gcc.gnu.org/onlinedocs/cpp/Environment-Variables.html
+       // Contrary to what the documentation seems to imply the compiler still
+       // creates object files with these defined (confirmed with GCC 8.2.1)
+       // These environment variables do nothing on CLANG
+       char *dependencies_env = getenv("DEPENDENCIES_OUTPUT");
+       bool using_sunpro_dependencies = false;
+       if (!dependencies_env) {
+               dependencies_env = getenv("SUNPRO_DEPENDENCIES");
+               using_sunpro_dependencies = true;
+       }
+       if (dependencies_env) {
+               generating_dependencies = true;
+               dependency_filename_specified = true;
+               char *saveptr = NULL;
+               char *abspath_file = strtok_r(dependencies_env, " ", &saveptr);
+
+               free(output_dep);
+               output_dep = make_relative_path(x_strdup(abspath_file));
+
+               // Specifying target object is optional
+               char *abspath_obj = strtok_r(NULL, " ", &saveptr);
+               if (abspath_obj) {
+                       dependency_target_specified = true;
+                       char *relpath_obj = make_relative_path(x_strdup(abspath_obj));
+                       // ensure compiler gets relative path
+                       char *relpath_both = format("%s %s", output_dep, relpath_obj);
+                       if (using_sunpro_dependencies) {
+                               x_setenv("SUNPRO_DEPENDENCIES", relpath_both);
+                       } else {
+                               x_setenv("DEPENDENCIES_OUTPUT", relpath_both);
+                       }
+                       free(relpath_obj);
+                       free(relpath_both);
+               } else {
+                       dependency_implicit_target_specified = true;
+                       // ensure compiler gets relative path
+                       if (using_sunpro_dependencies) {
+                               x_setenv("SUNPRO_DEPENDENCIES", output_dep);
+                       } else {
+                               x_setenv("DEPENDENCIES_OUTPUT", output_dep);
+                       }
+               }
+       }
+
        if (found_S_opt) {
                // Even if -gsplit-dwarf is given, the .dwo file is not generated when -S
                // is also given.
@@ -3270,6 +3318,7 @@ cc_process_args(struct args *args, struct args **preprocessor_args,
                }
 
                if (!dependency_target_specified
+                   && !dependency_implicit_target_specified
                    && !str_eq(get_extension(output_dep), ".o")) {
                        args_add(dep_args, "-MQ");
                        args_add(dep_args, output_obj);
index ab0469d1c16288fd9405aca2241b3f95b65c5de1..70c18b38da871e3c8ff45541216b2a72456956ec 100644 (file)
@@ -167,6 +167,7 @@ char *x_strndup(const char *s, size_t n);
 void *x_malloc(size_t size);
 void *x_calloc(size_t nmemb, size_t size);
 void *x_realloc(void *ptr, size_t size);
+void x_setenv(const char *name, const char *value);
 void x_unsetenv(const char *name);
 int x_fstat(int fd, struct stat *buf);
 int x_lstat(const char *pathname, struct stat *buf);
index 36d3b632319fdf7553647fed1f5f18fb744ca46b..e442cc42b9450db343371eef9b14cfba36c060a9 100644 (file)
@@ -780,6 +780,16 @@ x_realloc(void *ptr, size_t size)
        return p2;
 }
 
+// This is like setenv.
+void x_setenv(const char *name, const char *value)
+{
+#ifdef HAVE_SETENV
+       setenv(name, value, true);
+#else
+       putenv(format("%s=%s", name, value)); // Leak to environment.
+#endif
+}
+
 // This is like unsetenv.
 void x_unsetenv(const char *name)
 {
index fe39e662d7f74288a1488f119b314c9427b28d3e..10666c6a4977aadd6c26c89f8eb0e430ef3561b3 100755 (executable)
--- a/test/run
+++ b/test/run
@@ -378,6 +378,7 @@ debug_prefix_map
 masquerading
 hardlink
 direct
+direct_gcc
 depend
 basedir
 compression
diff --git a/test/suites/direct_gcc.bash b/test/suites/direct_gcc.bash
new file mode 100644 (file)
index 0000000..997b3f0
--- /dev/null
@@ -0,0 +1,142 @@
+SUITE_direct_gcc_PROBE() {
+    if [[ $REAL_COMPILER != *"gcc"* ]]; then
+        echo "Skipping GCC only test cases"
+    fi
+}
+
+SUITE_direct_gcc_SETUP() {
+    unset CCACHE_NODIRECT
+
+    cat <<EOF >test.c
+// test.c
+#include "test1.h"
+#include "test2.h"
+EOF
+    cat <<EOF >test1.h
+#include "test3.h"
+int test1;
+EOF
+    cat <<EOF >test2.h
+int test2;
+EOF
+    cat <<EOF >test3.h
+int test3;
+EOF
+    backdate test1.h test2.h test3.h
+
+    DEPENDENCIES_OUTPUT="expected_dependencies_output.d" $REAL_COMPILER -c test.c
+    DEPENDENCIES_OUTPUT="expected_dependencies_output_target.d target.o" $REAL_COMPILER -c test.c
+    SUNPRO_DEPENDENCIES="expected_sunpro_dependencies.d" $REAL_COMPILER -c test.c
+    SUNPRO_DEPENDENCIES="expected_sunpro_dependencies_target.d target.o" $REAL_COMPILER -c test.c
+    rm test.o
+}
+
+SUITE_direct_gcc() {
+    # -------------------------------------------------------------------------
+    TEST "DEPENDENCIES_OUTPUT environment variable"
+
+    DEPENDENCIES_OUTPUT="other.d" $CCACHE_COMPILE -c test.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache hit (preprocessed)' 0
+    expect_stat 'cache miss' 1
+    expect_equal_files other.d expected_dependencies_output.d
+
+    DEPENDENCIES_OUTPUT="other.d" $REAL_COMPILER -c test.c -o reference_test.o
+    expect_equal_object_files reference_test.o test.o
+
+    rm -f other.d
+    DEPENDENCIES_OUTPUT="other.d" $CCACHE_COMPILE -c test.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache hit (preprocessed)' 0
+    expect_stat 'cache miss' 1
+    expect_equal_files other.d expected_dependencies_output.d
+    expect_equal_object_files reference_test.o test.o
+
+    DEPENDENCIES_OUTPUT="different_name.d" $CCACHE_COMPILE -c test.c
+    expect_stat 'cache hit (direct)' 2
+    expect_stat 'cache hit (preprocessed)' 0
+    expect_stat 'cache miss' 1
+    expect_equal_files different_name.d expected_dependencies_output.d
+    expect_equal_object_files reference_test.o test.o
+
+    # -------------------------------------------------------------------------
+    TEST "DEPENDENCIES_OUTPUT environment variable with target"
+
+    DEPENDENCIES_OUTPUT="other.d target.o" $CCACHE_COMPILE -c test.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache hit (preprocessed)' 0
+    expect_stat 'cache miss' 1
+    expect_equal_files other.d expected_dependencies_output_target.d
+
+    DEPENDENCIES_OUTPUT="other.d target.o" $REAL_COMPILER -c test.c -o reference_test.o
+    expect_equal_object_files reference_test.o test.o
+
+    rm -f other.d
+    DEPENDENCIES_OUTPUT="other.d target.o" $CCACHE_COMPILE -c test.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache hit (preprocessed)' 0
+    expect_stat 'cache miss' 1
+    expect_equal_files other.d expected_dependencies_output_target.d
+    expect_equal_object_files reference_test.o test.o
+
+    DEPENDENCIES_OUTPUT="different_name.d target.o" $CCACHE_COMPILE -c test.c
+    expect_stat 'cache hit (direct)' 2
+    expect_stat 'cache hit (preprocessed)' 0
+    expect_stat 'cache miss' 1
+    expect_equal_files different_name.d expected_dependencies_output_target.d
+    expect_equal_object_files reference_test.o test.o
+
+    # -------------------------------------------------------------------------
+    TEST "SUNPRO_DEPENDENCIES environment variable"
+
+    SUNPRO_DEPENDENCIES="other.d" $CCACHE_COMPILE -c test.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache hit (preprocessed)' 0
+    expect_stat 'cache miss' 1
+    expect_equal_files other.d expected_sunpro_dependencies.d
+
+    SUNPRO_DEPENDENCIES="other.d" $REAL_COMPILER -c test.c -o reference_test.o
+    expect_equal_object_files reference_test.o test.o
+
+    rm -f other.d
+    SUNPRO_DEPENDENCIES="other.d" $CCACHE_COMPILE -c test.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache hit (preprocessed)' 0
+    expect_stat 'cache miss' 1
+    expect_equal_files other.d expected_sunpro_dependencies.d
+    expect_equal_object_files reference_test.o test.o
+
+    SUNPRO_DEPENDENCIES="different_name.d" $CCACHE_COMPILE -c test.c
+    expect_stat 'cache hit (direct)' 2
+    expect_stat 'cache hit (preprocessed)' 0
+    expect_stat 'cache miss' 1
+    expect_equal_files different_name.d expected_sunpro_dependencies.d
+    expect_equal_object_files reference_test.o test.o
+
+    # -------------------------------------------------------------------------
+    TEST "SUNPRO_DEPENDENCIES environment variable with target"
+
+    SUNPRO_DEPENDENCIES="other.d target.o" $CCACHE_COMPILE -c test.c
+    expect_stat 'cache hit (direct)' 0
+    expect_stat 'cache hit (preprocessed)' 0
+    expect_stat 'cache miss' 1
+    expect_equal_files other.d expected_sunpro_dependencies_target.d
+
+    SUNPRO_DEPENDENCIES="other.d target.o" $REAL_COMPILER -c test.c -o reference_test.o
+    expect_equal_object_files reference_test.o test.o
+
+    rm -f other.d
+    SUNPRO_DEPENDENCIES="other.d target.o" $CCACHE_COMPILE -c test.c
+    expect_stat 'cache hit (direct)' 1
+    expect_stat 'cache hit (preprocessed)' 0
+    expect_stat 'cache miss' 1
+    expect_equal_files other.d expected_sunpro_dependencies_target.d
+    expect_equal_object_files reference_test.o test.o
+
+    SUNPRO_DEPENDENCIES="different_name.d target.o" $CCACHE_COMPILE -c test.c
+    expect_stat 'cache hit (direct)' 2
+    expect_stat 'cache hit (preprocessed)' 0
+    expect_stat 'cache miss' 1
+    expect_equal_files different_name.d expected_sunpro_dependencies_target.d
+    expect_equal_object_files reference_test.o test.o
+}
\ No newline at end of file