From eb3148ca25cb90ef74570c8503d91dc1fe30904d Mon Sep 17 00:00:00 2001 From: Joel Rosdahl Date: Wed, 27 Jul 2016 20:49:00 +0200 Subject: [PATCH] Let run_second_cpp default to true ccache has since day 1 (OK, actually day 13: 5f6f5010) relied on the fact that GCC and similar enough compilers are able to compile their own preprocessed output with the same outcome as if they compiled the real source code directly. However, newer versions of GCC no longer quite work this way since they perform an increasing amount of diagnostics analysis only if the source code is compiled directly. The same goes for Clang. It's impossible for ccache to work around this changed behavior in a good way. Closes #116. --- MANUAL.txt | 26 +++++++++------------ NEWS.txt | 5 +++++ ccache.c | 4 ++-- conf.c | 2 +- test.sh | 40 +++++++++++---------------------- test/test_argument_processing.c | 29 +++++++++++++++++++++++- test/test_conf.c | 10 ++++----- 7 files changed, 65 insertions(+), 51 deletions(-) diff --git a/MANUAL.txt b/MANUAL.txt index a2108b0e7..0fe67e502 100644 --- a/MANUAL.txt +++ b/MANUAL.txt @@ -447,12 +447,17 @@ WRAPPERS>>. *run_second_cpp* (*CCACHE_CPP2* or *CCACHE_NOCPP2*, see <<_boolean_values,Boolean values>> above):: - If true, ccache will not use the optimisation of avoiding the second call - to the preprocessor by compiling the preprocessed output that was used for - finding the hash in the case of a cache miss. This is primarily a debugging - option, although it is possible that some unusual compilers will have - problems with compiling the preprocessed output, in which case this option - could allow ccache to be used anyway. + If true, ccache will first run the preprocessor to preprocess the source + code (see <<_the_preprocessor_mode,THE PREPROCESSOR MODE>>) and then on a + cache miss run the compiler on the source code to get hold of the object + file. This is the default. + + If false, ccache will first run preprocessor to preprocess the source code + and then on a cache miss run the compiler on the _preprocessed source code_ + instead of the original source code. This makes cache misses slightly + faster since the source code only has to be preprocessed once. The downside + is that some compilers won't produce the same result (for instance + diagnostics warnings) when compiling preprocessed source code. *sloppiness* (*CCACHE_SLOPPINESS*):: @@ -885,15 +890,6 @@ problems and what may be done to increase the hit rate: <<_precompiled_headers,PRECOMPILED HEADERS>>. -Errors when compiling with ccache -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If compilation doesn't work with ccache, but it works without it, one possible -reason is that the compiler can't compile preprocessed output correctly. A -workaround that may work is to enable *run_second_cpp*. This will make cache -misses slower, though, so it is better to find and fix the root cause. - - Corrupt object files ~~~~~~~~~~~~~~~~~~~~ diff --git a/NEWS.txt b/NEWS.txt index d7930c89e..4b16b7acc 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -14,6 +14,11 @@ Notes New features and improvements ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +- The configuration option `run_second_cpp` (`CCACHE_CPP2`) now defaults to + true. This improves ccache's out-of-the-box experience for compilers that + can't compile their own preprocessed output with the same outcome as if they + compiled the real source code directly, e.g. newer versions of GCC and Clang. + - Added support for cuda including the -optf/--options-file option. - Added new sloppiness option `no_system_headers`, which tells ccache not to diff --git a/ccache.c b/ccache.c index 2cb95bb65..263c077b8 100644 --- a/ccache.c +++ b/ccache.c @@ -2676,7 +2676,7 @@ cc_process_args(struct args *args, struct args **preprocessor_args, cc_log("%s used; disabling unify mode", debug_argument); conf->unify = false; } - if (debug_level >= 3) { + if (debug_level >= 3 && !conf->run_second_cpp) { cc_log("%s used; not compiling preprocessed code", debug_argument); conf->run_second_cpp = true; } @@ -2762,7 +2762,7 @@ cc_process_args(struct args *args, struct args **preprocessor_args, direct_i_file = language_is_preprocessed(actual_language); - if (output_is_precompiled_header) { + if (output_is_precompiled_header && !conf->run_second_cpp) { // It doesn't work to create the .gch from preprocessed source. cc_log("Creating precompiled header; not compiling preprocessed code"); conf->run_second_cpp = true; diff --git a/conf.c b/conf.c index 6b80e37ed..f72bca12d 100644 --- a/conf.c +++ b/conf.c @@ -318,7 +318,7 @@ conf_create(void) conf->read_only = false; conf->read_only_direct = false; conf->recache = false; - conf->run_second_cpp = false; + conf->run_second_cpp = true; conf->sloppiness = 0; conf->stats = true; conf->temporary_dir = x_strdup(""); diff --git a/test.sh b/test.sh index df9170b75..d1f071a04 100755 --- a/test.sh +++ b/test.sh @@ -176,9 +176,9 @@ TEST() { unset CCACHE_BASEDIR unset CCACHE_CC + unset CCACHE_COMMENTS unset CCACHE_COMPILERCHECK unset CCACHE_COMPRESS - unset CCACHE_COMMENTS unset CCACHE_CPP2 unset CCACHE_DIR unset CCACHE_DISABLE @@ -189,6 +189,7 @@ TEST() { unset CCACHE_IGNOREHEADERS unset CCACHE_LOGFILE unset CCACHE_NLEVELS + unset CCACHE_NOCPP2 unset CCACHE_NOSTATS unset CCACHE_PATH unset CCACHE_PREFIX @@ -387,20 +388,6 @@ base_tests() { $UNCACHED_COMPILE -c -o reference_test1.o test1.c expect_equal_object_files reference_test1.o test1.o - # ------------------------------------------------------------------------- - TEST "CCACHE_CPP2" - - CCACHE_CPP2=1 $CCACHE_COMPILE -c test1.c - expect_stat 'cache hit (preprocessed)' 0 - expect_stat 'cache miss' 1 - - CCACHE_CPP2=1 $CCACHE_COMPILE -c test1.c - expect_stat 'cache hit (preprocessed)' 1 - expect_stat 'cache miss' 1 - - $UNCACHED_COMPILE -c -o reference_test1.o test1.c - expect_equal_object_files reference_test1.o test1.o - # ------------------------------------------------------------------------- TEST "CCACHE_NOSTATS" @@ -1097,12 +1084,12 @@ SUITE_base() { # ============================================================================= -SUITE_cpp2_SETUP() { - export CCACHE_CPP2=1 +SUITE_nocpp2_SETUP() { + export CCACHE_NOCPP2=1 generate_code 1 test1.c } -SUITE_cpp2() { +SUITE_nocpp2() { base_tests } @@ -1150,8 +1137,7 @@ SUITE_serialize_diagnostics() { $UNCACHED_COMPILE -c --serialize-diagnostics expected.dia test1.c - # Run with CCACHE_CPP2 to ensure the same diagnostics output as above - CCACHE_CPP2=1 $CCACHE_COMPILE -c --serialize-diagnostics test.dia test1.c + $CCACHE_COMPILE -c --serialize-diagnostics test.dia test1.c expect_stat 'cache hit (preprocessed)' 0 expect_stat 'cache miss' 1 expect_stat 'files in cache' 2 @@ -1159,7 +1145,7 @@ SUITE_serialize_diagnostics() { rm test.dia - CCACHE_CPP2=1 $CCACHE_COMPILE -c --serialize-diagnostics test.dia test1.c + $CCACHE_COMPILE -c --serialize-diagnostics test.dia test1.c expect_stat 'cache hit (preprocessed)' 1 expect_stat 'cache miss' 1 expect_stat 'files in cache' 2 @@ -1173,7 +1159,7 @@ SUITE_serialize_diagnostics() { test_failed "Expected an error compiling error.c" fi - CCACHE_CPP2=1 $CCACHE_COMPILE -c --serialize-diagnostics test.dia error.c 2>test.stderr + $CCACHE_COMPILE -c --serialize-diagnostics test.dia error.c 2>test.stderr expect_stat 'compile failed' 1 expect_stat 'cache hit (preprocessed)' 0 expect_stat 'cache miss' 0 @@ -3182,19 +3168,19 @@ SUITE_input_charset() { printf '#include \nwchar_t foo[] = L"\xbf";\n' >latin1.c - CCACHE_CPP2=1 $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c + $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c expect_stat 'cache hit (preprocessed)' 0 expect_stat 'cache miss' 1 - CCACHE_CPP2=1 $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c + $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c expect_stat 'cache hit (preprocessed)' 1 expect_stat 'cache miss' 1 - $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c + CCACHE_NOCPP2=1 $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c expect_stat 'cache hit (preprocessed)' 1 expect_stat 'cache miss' 2 - $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c + CCACHE_NOCPP2=1 $CCACHE_COMPILE -c -finput-charset=latin1 latin1.c expect_stat 'cache hit (preprocessed)' 2 expect_stat 'cache miss' 2 } @@ -3307,7 +3293,7 @@ cd $TESTDIR || exit 1 all_suites=" base -cpp2 +nocpp2 multi_arch serialize_diagnostics debug_prefix_map diff --git a/test/test_argument_processing.c b/test/test_argument_processing.c index 5fb244a33..7dba4934e 100644 --- a/test/test_argument_processing.c +++ b/test/test_argument_processing.c @@ -105,7 +105,7 @@ TEST(dependency_flags_should_only_be_sent_to_the_preprocessor) args_free(orig); } -TEST(preprocessor_only_flags_should_only_be_sent_to_the_preprocessor) +TEST(cpp_only_flags_to_preprocessor_if_run_second_cpp_is_false) { #define CMD \ "cc -I. -idirafter . -iframework. -imacros . -imultilib ." \ @@ -121,6 +121,33 @@ TEST(preprocessor_only_flags_should_only_be_sent_to_the_preprocessor) struct args *act_cpp = NULL, *act_cc = NULL; create_file("foo.c", ""); + conf->run_second_cpp = false; + CHECK(cc_process_args(orig, &act_cpp, &act_cc)); + CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp); + CHECK_ARGS_EQ_FREE12(exp_cc, act_cc); + + args_free(orig); +} + +TEST(cpp_only_flags_to_preprocessor_and_compiler_if_run_second_cpp_is_true) +{ +#define CMD \ + "cc -I. -idirafter . -iframework. -imacros . -imultilib ." \ + " -include test.h -include-pch test.pch -iprefix . -iquote ." \ + " -isysroot . -isystem . -iwithprefix . -iwithprefixbefore ." \ + " -DTEST_MACRO -DTEST_MACRO2=1 -F. -trigraphs -fworking-directory" \ + " -fno-working-directory" +#define DEP_OPTS \ + " -MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 " \ + " -MQ mq1 -MQ mq2 -Wp,-MD,wpmd -Wp,-MMD,wpmmd" + struct args *orig = args_init_from_string(CMD DEP_OPTS " -c foo.c -o foo.o"); + struct args *exp_cpp = args_init_from_string(CMD DEP_OPTS); + struct args *exp_cc = args_init_from_string(CMD " -c"); +#undef CMD + struct args *act_cpp = NULL, *act_cc = NULL; + create_file("foo.c", ""); + + conf->run_second_cpp = true; CHECK(cc_process_args(orig, &act_cpp, &act_cc)); CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp); CHECK_ARGS_EQ_FREE12(exp_cc, act_cc); diff --git a/test/test_conf.c b/test/test_conf.c index 90f99fd93..ea809ac0a 100644 --- a/test/test_conf.c +++ b/test/test_conf.c @@ -73,7 +73,7 @@ TEST(conf_create) CHECK(!conf->read_only); CHECK(!conf->read_only_direct); CHECK(!conf->recache); - CHECK(!conf->run_second_cpp); + CHECK(conf->run_second_cpp); CHECK_INT_EQ(0, conf->sloppiness); CHECK(conf->stats); CHECK_STR_EQ("", conf->temporary_dir); @@ -123,7 +123,7 @@ TEST(conf_read_valid_config) "read_only = true\n" "read_only_direct = true\n" "recache = true\n" - "run_second_cpp = true\n" + "run_second_cpp = false\n" "sloppiness = file_macro ,time_macros, include_file_mtime,include_file_ctime,file_stat_matches,pch_defines , no_system_headers \n" "stats = false\n" "temporary_dir = ${USER}_foo\n" @@ -160,7 +160,7 @@ TEST(conf_read_valid_config) CHECK(conf->read_only); CHECK(conf->read_only_direct); CHECK(conf->recache); - CHECK(conf->run_second_cpp); + CHECK(!conf->run_second_cpp); CHECK_INT_EQ(SLOPPY_INCLUDE_FILE_MTIME|SLOPPY_INCLUDE_FILE_CTIME| SLOPPY_FILE_MACRO|SLOPPY_TIME_MACROS| SLOPPY_FILE_STAT_MATCHES|SLOPPY_NO_SYSTEM_HEADERS| @@ -385,7 +385,7 @@ TEST(conf_print_items) true, true, true, - true, + .run_second_cpp = false, SLOPPY_FILE_MACRO|SLOPPY_INCLUDE_FILE_MTIME| SLOPPY_INCLUDE_FILE_CTIME|SLOPPY_TIME_MACROS| SLOPPY_FILE_STAT_MATCHES|SLOPPY_PCH_DEFINES| @@ -434,7 +434,7 @@ TEST(conf_print_items) CHECK_STR_EQ("read_only = true", received_conf_items[n++].descr); CHECK_STR_EQ("read_only_direct = true", received_conf_items[n++].descr); CHECK_STR_EQ("recache = true", received_conf_items[n++].descr); - CHECK_STR_EQ("run_second_cpp = true", received_conf_items[n++].descr); + CHECK_STR_EQ("run_second_cpp = false", received_conf_items[n++].descr); CHECK_STR_EQ("sloppiness = file_macro, include_file_mtime," " include_file_ctime, time_macros, pch_defines," " file_stat_matches, no_system_headers", -- 2.47.2