From 5d8585b588fb9f81e741b765603053e4cadcf1ac Mon Sep 17 00:00:00 2001 From: Joel Rosdahl Date: Fri, 19 Jul 2019 09:22:04 +0200 Subject: [PATCH] =?utf8?q?Don=E2=80=99t=20pass=20-Werror=20and=20compilati?= =?utf8?q?on-only=20options=20to=20the=20preprocessor?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Clang emits warnings when it sees unused options, so when ccache runs the Clang preprocessor separately, options that are not used by the preprocessor will produce warnings. This means that the user may get warnings which would not be present when not using ccache. And if -Werror is present then the preprocessing step fails, which needless to say is not optimal. To work around this: * Options known to have the above mentioned problem are not passed to the preprocessor. * In addition, -Werror is also not passed to the preprocessor so that options not properly marked as “compiler only” will only trigger warnings, not errors. Fixes #312. --- src/ccache.c | 37 +++++++++++++++++++--- src/compopt.c | 48 +++++++++++++++++++++++++++-- src/compopt.h | 2 ++ unittest/test_argument_processing.c | 20 +++++++++++- 4 files changed, 99 insertions(+), 8 deletions(-) diff --git a/src/ccache.c b/src/ccache.c index 75e74310b..ca3b961ab 100644 --- a/src/ccache.c +++ b/src/ccache.c @@ -2513,9 +2513,11 @@ cc_process_args(struct args *args, struct args **preprocessor_args, // used as a temporary data structure to loop over. struct args *expanded_args = args_copy(args); - // common_args essentially contains all original arguments except those that - // only should be passed to the preprocessor (if run_second_cpp is false) and - // except dependency options (like -MD and friends). + // common_args contains all original arguments except: + // * those that never should be passed to the preprocessor, + // * those that only should be passed to the preprocessor (if run_second_cpp + // is false), and + // * dependency options (like -MD and friends). struct args *common_args = args_init(0, NULL); // cpp_args contains arguments that were not added to common_args, i.e. those @@ -2523,12 +2525,15 @@ cc_process_args(struct args *args, struct args **preprocessor_args, // If run_second_cpp is true, they will be passed to the compiler as well. struct args *cpp_args = args_init(0, NULL); - // dep_args contains dependency options like -MD. They only passed to the + // dep_args contains dependency options like -MD. They are only passed to the // preprocessor, never to the compiler. struct args *dep_args = args_init(0, NULL); - bool found_color_diagnostics = false; + // compiler_only_args contains arguments that should only be passed to the + // compiler, not the preprocessor. + struct args *compiler_only_args = args_init(0, NULL); + bool found_color_diagnostics = false; bool found_directives_only = false; bool found_rewrite_includes = false; @@ -2662,6 +2667,26 @@ cc_process_args(struct args *args, struct args **preprocessor_args, continue; } + // Handle options that should not be passed to the preprocessor. + if (compopt_affects_comp(argv[i])) { + args_add(compiler_only_args, argv[i]); + if (compopt_takes_arg(argv[i])) { + if (i == argc - 1) { + cc_log("Missing argument to %s", argv[i]); + stats_update(STATS_ARGS); + result = false; + goto out; + } + args_add(compiler_only_args, argv[i + 1]); + ++i; + } + continue; + } + if (compopt_prefix_affects_comp(argv[i])) { + args_add(compiler_only_args, argv[i]); + continue; + } + if (str_eq(argv[i], "-fpch-preprocess") || str_eq(argv[i], "-emit-pch") || str_eq(argv[i], "-emit-pth")) { @@ -3498,6 +3523,8 @@ cc_process_args(struct args *args, struct args **preprocessor_args, } *compiler_args = args_copy(common_args); + args_extend(*compiler_args, compiler_only_args); + if (conf->run_second_cpp) { args_extend(*compiler_args, cpp_args); } else if (found_directives_only || found_rewrite_includes) { diff --git a/src/compopt.c b/src/compopt.c index 8940cfcd8..413a1b37a 100644 --- a/src/compopt.c +++ b/src/compopt.c @@ -17,13 +17,29 @@ #include "ccache.h" #include "compopt.h" +// The option it too hard to handle at all. #define TOO_HARD (1 << 0) + +// The option it too hard for the direct mode. #define TOO_HARD_DIRECT (1 << 1) + +// The option takes a separate argument, e.g. "-D FOO=1". #define TAKES_ARG (1 << 2) + +// The option takes a concatenated argument, e.g. "-DFOO=1". #define TAKES_CONCAT_ARG (1 << 3) + +// The argument to the option is a path that may be rewritten if base_dir is +// used. #define TAKES_PATH (1 << 4) + +// The option only affects preprocessing; not passed to the compiler if +// run_second_cpp is false. #define AFFECTS_CPP (1 << 5) +// The option only affects compilation; not passed to the preprocesor. +#define AFFECTS_COMP (1 << 6) + struct compopt { const char *name; int type; @@ -56,14 +72,20 @@ static const struct compopt compopts[] = { {"-P", TOO_HARD}, {"-U", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG}, {"-V", TAKES_ARG}, - {"-Xassembler", TAKES_ARG}, + {"-Wa,", TAKES_CONCAT_ARG | AFFECTS_COMP}, + {"-Werror", AFFECTS_COMP}, // don't exit with error when preprocessing + {"-Wl,", TAKES_CONCAT_ARG | AFFECTS_COMP}, + {"-Xassembler", TAKES_ARG | TAKES_CONCAT_ARG | AFFECTS_COMP}, {"-Xclang", TAKES_ARG}, - {"-Xlinker", TAKES_ARG}, + {"-Xlinker", TAKES_ARG | TAKES_CONCAT_ARG | AFFECTS_COMP}, {"-Xpreprocessor", AFFECTS_CPP | TOO_HARD_DIRECT | TAKES_ARG}, + {"-all_load", AFFECTS_COMP}, {"-analyze", TOO_HARD}, // clang {"-arch", TAKES_ARG}, {"-aux-info", TAKES_ARG}, {"-b", TAKES_ARG}, + {"-bind_at_load", AFFECTS_COMP}, + {"-bundle", AFFECTS_COMP}, {"-ccbin", AFFECTS_CPP | TAKES_ARG}, // nvcc {"-fmodules", TOO_HARD}, {"-fno-working-directory", AFFECTS_CPP}, @@ -87,9 +109,14 @@ static const struct compopt compopts[] = { {"-iwithprefixbefore", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH}, {"-ldir", AFFECTS_CPP | TAKES_ARG}, // nvcc + {"-nolibc", AFFECTS_COMP}, {"-nostdinc", AFFECTS_CPP}, {"-nostdinc++", AFFECTS_CPP}, {"-odir", AFFECTS_CPP | TAKES_ARG}, // nvcc + {"-pie", AFFECTS_COMP}, + {"-prebind", AFFECTS_COMP}, + {"-preload", AFFECTS_COMP}, + {"-rdynamic", AFFECTS_COMP}, {"-remap", AFFECTS_CPP}, {"-save-temps", TOO_HARD}, {"-save-temps=cwd", TOO_HARD}, @@ -172,6 +199,13 @@ compopt_affects_cpp(const char *option) return co && (co->type & AFFECTS_CPP); } +bool +compopt_affects_comp(const char *option) +{ + const struct compopt *co = find(option); + return co && (co->type & AFFECTS_COMP); +} + bool compopt_too_hard(const char *option) { @@ -216,3 +250,13 @@ compopt_prefix_affects_cpp(const char *option) const struct compopt *co = find_prefix(option); return co && (co->type & TAKES_CONCAT_ARG) && (co->type & AFFECTS_CPP); } + +// Determines if the prefix of the option matches any option and affects the +// preprocessor. +bool +compopt_prefix_affects_comp(const char *option) +{ + // Prefix options have to take concatenated args. + const struct compopt *co = find_prefix(option); + return co && (co->type & TAKES_CONCAT_ARG) && (co->type & AFFECTS_COMP); +} diff --git a/src/compopt.h b/src/compopt.h index d72639fe4..4f1f760e9 100644 --- a/src/compopt.h +++ b/src/compopt.h @@ -5,11 +5,13 @@ bool compopt_short(bool (*fn)(const char *option), const char *option); bool compopt_affects_cpp(const char *option); +bool compopt_affects_comp(const char *option); bool compopt_too_hard(const char *option); bool compopt_too_hard_for_direct_mode(const char *option); bool compopt_takes_path(const char *option); bool compopt_takes_arg(const char *option); bool compopt_takes_concat_arg(const char *option); bool compopt_prefix_affects_cpp(const char *option); +bool compopt_prefix_affects_comp(const char *option); #endif // CCACHE_COMPOPT_H diff --git a/unittest/test_argument_processing.c b/unittest/test_argument_processing.c index 8d40a511f..7974f8a76 100644 --- a/unittest/test_argument_processing.c +++ b/unittest/test_argument_processing.c @@ -1,4 +1,4 @@ -// Copyright (C) 2010-2018 Joel Rosdahl +// Copyright (C) 2010-2019 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 @@ -494,4 +494,22 @@ TEST(debug_flag_order_with_known_option_last) args_free(orig); } +TEST(options_not_to_be_passed_to_the_preprocesor) +{ + struct args *orig = args_init_from_string( + "cc -Wa,foo foo.c -g -Xlinker fie -Xlinker,fum -c -Werror"); + struct args *exp_cpp = args_init_from_string("cc -g"); + struct args *exp_cc = args_init_from_string( + "cc -g -Wa,foo -Xlinker fie -Xlinker,fum -Werror -c"); + struct args *act_cpp = NULL; + struct args *act_cc = NULL; + + create_file("foo.c", ""); + 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_SUITE_END -- 2.47.2