From 62606b3196cdaf1c11cc51e3991169924d4213d1 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Sat, 6 Feb 2021 17:35:50 +0100 Subject: [PATCH] Visual C/C++ compiler support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I picked only the compiler commits from: https://github.com/ccache/ccache/pull/162 The following commits I've adapted to the latest ccache C++ code: 375fe24: Add compiler_is_msvc() and MSVC specific option table. 7e01763: Add handling of /Fo option (replaces -o, but shall have no space) 0c5cd25: Manage /E, /c equivalence. -g is gcc only. -O or /O is msvc only. 4f61b59: MSVC send part of the error/warning messages to STDOUT, so concat wit… --- src/argprocessing.cpp | 98 +++++++++++++++++++++++-------------------- src/compopt.cpp | 14 +++++++ 2 files changed, 66 insertions(+), 46 deletions(-) diff --git a/src/argprocessing.cpp b/src/argprocessing.cpp index a83dc597b5..27e34da423 100644 --- a/src/argprocessing.cpp +++ b/src/argprocessing.cpp @@ -261,7 +261,7 @@ process_arg(const Context& ctx, } // Special case for -E. - if (args[i] == "-E") { + if (args[i] == "-E" || args[i] == "/E") { return Statistic::called_for_preprocessing; } // MSVC -P is -E with output to a file. @@ -314,11 +314,12 @@ process_arg(const Context& ctx, // These are always too hard. if (compopt_too_hard(args[i]) || util::starts_with(args[i], "-fdump-") - || util::starts_with(args[i], "-MJ") - || util::starts_with(args[i], "-Yc")) { - LOG("Compiler option {} is unsupported", args[i]); - return Statistic::unsupported_compiler_option; - } + || util::starts_with(args[i], "-MJ") || util::starts_with(args[i], "/Yc")) + || util::starts_with(args[i], "-Yc")) + { + LOG("Compiler option {} is unsupported", args[i]); + return Statistic::unsupported_compiler_option; + } // These are too hard in direct mode. if (config.direct_mode() && compopt_too_hard_for_direct_mode(args[i])) { @@ -355,9 +356,9 @@ process_arg(const Context& ctx, return nullopt; } - // Some arguments that clang passes directly to cc1 (related to precompiled - // headers) need the usual ccache handling. In those cases, the -Xclang - // prefix is skipped and the cc1 argument is handled instead. + // Some arguments that clang passes directly to cc1 (related to + // precompiled headers) need the usual ccache handling. In those cases, + // the -Xclang prefix is skipped and the cc1 argument is handled instead. if (args[i] == "-Xclang" && i + 1 < args.size() && (args[i + 1] == "-emit-pch" || args[i + 1] == "-emit-pth" || args[i + 1] == "-include-pch" || args[i + 1] == "-include-pth" @@ -392,14 +393,14 @@ process_arg(const Context& ctx, return nullopt; } - // Modules are handled on demand as necessary in the background, so there is - // no need to cache them, they can in practice be ignored. All that is needed - // is to correctly depend also on module.modulemap files, and those are - // included only in depend mode (preprocessed output does not list them). - // Still, not including the modules themselves in the hash could possibly - // result in an object file that would be different from the actual - // compilation (even though it should be compatible), so require a sloppiness - // flag. + // Modules are handled on demand as necessary in the background, so there + // is no need to cache them, they can in practice be ignored. All that is + // needed is to correctly depend also on module.modulemap files, and those + // are included only in depend mode (preprocessed output does not list + // them). Still, not including the modules themselves in the hash could + // possibly result in an object file that would be different from the + // actual compilation (even though it should be compatible), so require a + // sloppiness flag. if (args[i] == "-fmodules") { if (!config.depend_mode() || !config.direct_mode()) { LOG("Compiler option {} is unsupported without direct depend mode", @@ -414,13 +415,13 @@ process_arg(const Context& ctx, } // We must have -c. - if (args[i] == "-c") { + if (args[i] == "-c" || args[i] == "/c") { state.found_c_opt = true; return nullopt; } // MSVC -Fo with no space. - if (util::starts_with(args[i], "-Fo") + if ((util::starts_with(args[i], "-Fo") || util::starts_with(args[i], "/Fo")) && config.compiler_type() == CompilerType::cl) { args_info.output_obj = Util::make_relative_path(ctx, string_view(args[i]).substr(3)); @@ -443,16 +444,16 @@ process_arg(const Context& ctx, if (util::starts_with(args[i], "-x")) { if (args[i].length() >= 3 && !islower(args[i][2])) { - // -xCODE (where CODE can be e.g. Host or CORE-AVX2, always starting with - // an uppercase letter) is an ordinary Intel compiler option, not a - // language specification. (GCC's "-x" language argument is always + // -xCODE (where CODE can be e.g. Host or CORE-AVX2, always starting + // with an uppercase letter) is an ordinary Intel compiler option, not + // a language specification. (GCC's "-x" language argument is always // lowercase.) state.common_args.push_back(args[i]); return nullopt; } - // Special handling for -x: remember the last specified language before the - // input file and strip all -x options from the arguments. + // Special handling for -x: remember the last specified language before + // the input file and strip all -x options from the arguments. if (args[i].length() == 2) { if (i == args.size() - 1) { LOG("Missing argument to {}", args[i]); @@ -594,8 +595,8 @@ process_arg(const Context& ctx, return nullopt; } - // MSVC -MD[d], -MT[d] and -LT[d] options are something different than GCC's - // -MD etc. + // MSVC -MD[d], -MT[d] and -LT[d] options are something different than + // GCC's -MD etc. if (config.compiler_type() == CompilerType::cl && (util::starts_with(args[i], "-MD") || util::starts_with(args[i], "-MT") || util::starts_with(args[i], "-LD"))) { @@ -767,13 +768,15 @@ process_arg(const Context& ctx, if (config.compiler_type() == CompilerType::gcc && (args[i] == "-fcolor-diagnostics" || args[i] == "-fno-color-diagnostics")) { - // Special case: If a GCC compiler gets -f(no-)color-diagnostics we'll bail - // out and just execute the compiler. The reason is that we don't include - // -f(no-)color-diagnostics in the hash so there can be a false cache hit in - // the following scenario: + // Special case: If a GCC compiler gets -f(no-)color-diagnostics we'll + // bail out and just execute the compiler. The reason is that we don't + // include -f(no-)color-diagnostics in the hash so there can be a false + // cache hit in the following scenario: // - // 1. ccache gcc -c example.c # adds a cache entry - // 2. ccache gcc -c example.c -fcolor-diagnostics # unexpectedly succeeds + // 1. ccache gcc -c example.c # adds a cache + // entry + // 2. ccache gcc -c example.c -fcolor-diagnostics # unexpectedly + // succeeds return Statistic::unsupported_compiler_option; } @@ -829,9 +832,9 @@ process_arg(const Context& ctx, if (config.sloppiness().is_enabled(core::Sloppy::clang_index_store) && args[i] == "-index-store-path") { - // Xcode 9 or later calls Clang with this option. The given path includes a - // UUID that might lead to cache misses, especially when cache is shared - // among multiple users. + // Xcode 9 or later calls Clang with this option. The given path + // includes a UUID that might lead to cache misses, especially when + // cache is shared among multiple users. i++; if (i <= args.size() - 1) { LOG("Skipping argument -index-store-path {}", args[i]); @@ -849,17 +852,17 @@ process_arg(const Context& ctx, return nullopt; } - // Options taking an argument that we may want to rewrite to relative paths to - // get better hit rate. A secondary effect is that paths in the standard error - // output produced by the compiler will be normalized. + // Options taking an argument that we may want to rewrite to relative + // paths to get better hit rate. A secondary effect is that paths in the + // standard error output produced by the compiler will be normalized. if (compopt_takes_path(args[i])) { if (i == args.size() - 1) { LOG("Missing argument to {}", args[i]); return Statistic::bad_compiler_arguments; } - // In the -Xclang -include-(pch/pth) -Xclang case, the path is one - // index further behind. + // In the -Xclang -include-(pch/pth) -Xclang case, the path is + // one index further behind. int next = 1; if (args[i + 1] == "-Xclang" && i + 2 < args.size()) { next = 2; @@ -888,7 +891,8 @@ process_arg(const Context& ctx, // Same as above but options with concatenated argument beginning with a // slash. - if (args[i][0] == '-') { + if (args[i][0] == '-' + || (config.compiler_type() == CompilerType::cl && args[i][0] == '/')) { size_t slash_pos = args[i].find('/'); if (slash_pos != std::string::npos) { std::string option = args[i].substr(0, slash_pos); @@ -926,7 +930,8 @@ process_arg(const Context& ctx, } // Other options. - if (args[i][0] == '-') { + if (args[i][0] == '-' + || (config.compiler_type() == CompilerType::cl && args[i][0] == '/')) { if (compopt_affects_cpp_output(args[i]) || compopt_prefix_affects_cpp_output(args[i])) { state.cpp_args.push_back(args[i]); @@ -941,11 +946,12 @@ process_arg(const Context& ctx, args[i][0] = '/'; } - // If an argument isn't a plain file then assume its an option, not an input - // file. This allows us to cope better with unusual compiler options. + // If an argument isn't a plain file then assume its an option, not an + // input file. This allows us to cope better with unusual compiler + // options. // - // Note that "/dev/null" is an exception that is sometimes used as an input - // file when code is testing compiler flags. + // Note that "/dev/null" is an exception that is sometimes used as an + // input file when code is testing compiler flags. if (args[i] != "/dev/null") { auto st = Stat::stat(args[i]); if (!st || !st.is_regular()) { diff --git a/src/compopt.cpp b/src/compopt.cpp index 732b5a4d45..2c432416a2 100644 --- a/src/compopt.cpp +++ b/src/compopt.cpp @@ -150,6 +150,20 @@ const CompOpt compopts[] = { {"-stdlib=", AFFECTS_CPP | TAKES_CONCAT_ARG}, {"-trigraphs", AFFECTS_CPP}, {"-u", TAKES_ARG | TAKES_CONCAT_ARG}, + {"/AI", TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH}, // msvc + {"/D", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG}, // msvc + {"/E", TOO_HARD}, // msvc + {"/EP", TOO_HARD}, // msvc + {"/FI", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH}, // msvc + {"/FU", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH}, // msvc + {"/I", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH}, // msvc + {"/L", TAKES_ARG}, // msvc + {"/P", TOO_HARD}, // msvc + {"/U", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG}, // msvc + {"/Yc", TAKES_ARG | TOO_HARD}, // msvc + {"/ZI", TOO_HARD}, // msvc + {"/Zi", TOO_HARD}, // msvc + {"/u", AFFECTS_CPP}, // msvc }; static int