From c85562e7f65cccc9ba1490b2fd7c79324507bde7 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sat, 12 Jan 2019 00:29:36 +0100 Subject: [PATCH] Support .d dependency file generation via environment variables 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 | 1 + src/ccache.c | 49 +++++++++++++ src/ccache.h | 1 + src/util.c | 10 +++ test/run | 1 + test/suites/direct_gcc.bash | 142 ++++++++++++++++++++++++++++++++++++ 6 files changed, 204 insertions(+) create mode 100644 test/suites/direct_gcc.bash diff --git a/configure.ac b/configure.ac index e8c34dbec..b44a7213b 100644 --- a/configure.ac +++ b/configure.ac @@ -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) diff --git a/src/ccache.c b/src/ccache.c index c7e949fe2..af2461203 100644 --- a/src/ccache.c +++ b/src/ccache.c @@ -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); diff --git a/src/ccache.h b/src/ccache.h index ab0469d1c..70c18b38d 100644 --- a/src/ccache.h +++ b/src/ccache.h @@ -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); diff --git a/src/util.c b/src/util.c index 36d3b6323..e442cc42b 100644 --- a/src/util.c +++ b/src/util.c @@ -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) { diff --git a/test/run b/test/run index fe39e662d..10666c6a4 100755 --- 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 index 000000000..997b3f0bc --- /dev/null +++ b/test/suites/direct_gcc.bash @@ -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 <test.c +// test.c +#include "test1.h" +#include "test2.h" +EOF + cat <test1.h +#include "test3.h" +int test1; +EOF + cat <test2.h +int test2; +EOF + cat <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 -- 2.47.2