// (--serialize-diagnostics)?
bool generating_diagnostics = false;
+ // Are we generating a pch file (msvc -Yc)?
+ bool generating_pch = false;
+
// Whether to strip color codes from diagnostic messages on output.
bool strip_diagnostics_colors = false;
bool found_pch = false;
bool found_fpch_preprocess = false;
bool found_Yu = false;
+ bool found_Yc = false;
+ std::string found_Fp_file;
bool found_valid_Fp = false;
bool found_syntax_only = false;
ColorDiagnostics color_diagnostics = ColorDiagnostics::automatic;
// anything just because it has a corresponding precompiled header,
// because Clang doesn't behave that way either.
std::string pch_file;
+ if (option == "-Yc") {
+ state.found_Yc = true;
+ if (!state.found_Fp_file.empty()) {
+ included_pch_file = state.found_Fp_file;
+ return true;
+ }
+ }
if (option == "-Yu") {
state.found_Yu = true;
if (state.found_valid_Fp) { // Use file set by -Fp.
if (!fs::path(file).has_extension()) {
file += ".pch";
}
+
+ state.found_Fp_file = file;
+
+ if (state.found_Yc) {
+ included_pch_file = state.found_Fp_file;
+ return true;
+ }
if (DirEntry(file).is_regular_file()) {
state.found_valid_Fp = true;
if (!state.found_Yu) {
// These are always too hard.
if (compopt_too_hard(arg) || util::starts_with(arg, "-fdump-")
- || util::starts_with(arg, "-MJ") || util::starts_with(arg, "-Yc")
+ || util::starts_with(arg, "-MJ")
|| util::starts_with(arg, "--config-system-dir=")
|| util::starts_with(arg, "--config-user-dir=")) {
LOG("Compiler option {} is unsupported", args[i]);
// Detect PCH for options with concatenated path (relative or absolute).
if (util::starts_with(arg, "-include") || util::starts_with(arg, "-Fp")
- || util::starts_with(arg, "-Yu")) {
+ || util::starts_with(arg, "-Yu") || util::starts_with(arg, "-Yc")) {
const size_t path_pos = util::starts_with(arg, "-include") ? 8 : 3;
if (!detect_pch(arg.substr(0, path_pos),
arg.substr(path_pos),
return Statistic::bad_compiler_arguments;
}
+ if (state.found_Yc) {
+ args_info.generating_pch = true;
+ }
// Fall through to the next section, so intentionally not returning here.
}
Hash::Digest file_digest;
const bool is_pch = is_precompiled_header(path);
- if (is_pch) {
+ if (is_pch && !ctx.args_info.generating_pch) {
if (ctx.args_info.included_pch_file.empty()) {
LOG("Detected use of precompiled header: {}", path);
}
// Explicitly check the .gch/.pch/.pth file as Clang does not include any
// mention of it in the preprocessed output.
- if (!ctx.args_info.included_pch_file.empty()) {
+ if (!ctx.args_info.included_pch_file.empty()
+ && !ctx.args_info.generating_pch) {
std::string pch_path =
Util::make_relative_path(ctx, ctx.args_info.included_pch_file);
hash.hash(pch_path);
// Explicitly check the .gch/.pch/.pth file as it may not be mentioned in the
// dependencies output.
- if (!ctx.args_info.included_pch_file.empty()) {
+ if (!ctx.args_info.included_pch_file.empty()
+ && !ctx.args_info.generating_pch) {
std::string pch_path =
Util::make_relative_path(ctx, ctx.args_info.included_pch_file);
hash.hash(pch_path);
// Explicitly check the .pch file as it is not mentioned in the
// includes output.
- if (!ctx.args_info.included_pch_file.empty()) {
+ if (!ctx.args_info.included_pch_file.empty()
+ && !ctx.args_info.generating_pch) {
std::string pch_path =
Util::make_relative_path(ctx, ctx.args_info.included_pch_file);
hash.hash(pch_path);
LOG("Object file {} missing", ctx.args_info.output_obj);
return false;
}
+ if (ctx.args_info.generating_pch
+ && !serializer.add_file(core::Result::FileType::included_pch_file,
+ ctx.args_info.included_pch_file)) {
+ LOG("PCH file {} missing", ctx.args_info.included_pch_file);
+ }
if (ctx.args_info.generating_dependencies
&& !serializer.add_file(core::Result::FileType::dependency,
ctx.args_info.output_dep)) {
{"-Xcompiler", AFFECTS_CPP | TAKES_ARG}, // nvcc
{"-Xlinker", TAKES_ARG | TAKES_CONCAT_ARG | AFFECTS_COMP},
{"-Xpreprocessor", AFFECTS_CPP | TOO_HARD_DIRECT | TAKES_ARG},
- {"-Yc", TAKES_ARG | TOO_HARD}, // msvc
+ {"-Yc", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH}, // msvc
{"-Yu", AFFECTS_CPP | TAKES_ARG | TAKES_CONCAT_ARG | TAKES_PATH}, // msvc
{"-all_load", AFFECTS_COMP},
{"-analyze", TOO_HARD}, // Clang
case FileType::assembler_listing:
return ".al";
+
+ case FileType::included_pch_file:
+ return ".pch";
}
return k_unknown_file_type;
// Assembler listing file from -Wa,-a=file.
assembler_listing = 9,
+
+ // PCH file created by msvc additionally to the obj file
+ included_pch_file = 10,
};
const char* file_type_to_string(FileType type);
case FileType::assembler_listing:
return m_ctx.args_info.output_al;
+
+ case FileType::included_pch_file:
+ return m_ctx.args_info.included_pch_file;
}
return {};
CHECK(result.compiler_args.to_string() == "cl.exe /foobar -c");
}
+TEST_CASE("MSVC PCH options")
+{
+ TestContext test_context;
+ Context ctx;
+ ctx.config.set_compiler_type(CompilerType::msvc);
+ util::write_file("foo.cpp", "");
+ util::write_file("pch.h", "");
+ util::write_file("pch.cpp", "");
+
+ SUBCASE("Create PCH")
+ {
+ ctx.orig_args = Args::from_string(
+ "cl.exe /Ycpch.h /Fppch.cpp.pch /FIpch.h /Fopch.cpp.obj /c pch.cpp");
+ const ProcessArgsResult result = process_args(ctx);
+ REQUIRE(!result.error);
+ CHECK(ctx.args_info.generating_pch);
+ CHECK(ctx.args_info.included_pch_file == "pch.cpp.pch");
+ CHECK(ctx.args_info.output_obj == "pch.cpp.obj");
+ CHECK(result.preprocessor_args.to_string()
+ == "cl.exe /Ycpch.h /Fppch.cpp.pch /FIpch.h");
+ CHECK(result.compiler_args.to_string()
+ == "cl.exe /Ycpch.h /Fppch.cpp.pch /FIpch.h -c");
+ }
+
+ util::write_file("pch.cpp.pch", "");
+ ctx.config.update_from_map({{"sloppiness", "pch_defines,time_macros"}});
+
+ SUBCASE("Consume PCH")
+ {
+ ctx.orig_args = Args::from_string(
+ "cl.exe /Yupch.h /Fppch.cpp.pch /FIpch.h /Fofoo.cpp.obj /c foo.cpp");
+ const ProcessArgsResult result = process_args(ctx);
+ REQUIRE(!result.error);
+ CHECK(!ctx.args_info.generating_pch);
+ CHECK(ctx.args_info.included_pch_file == "pch.cpp.pch");
+ CHECK(ctx.args_info.output_obj == "foo.cpp.obj");
+ CHECK(result.preprocessor_args.to_string()
+ == "cl.exe /Yupch.h /Fppch.cpp.pch /FIpch.h");
+ CHECK(result.compiler_args.to_string()
+ == "cl.exe /Yupch.h /Fppch.cpp.pch /FIpch.h -c");
+ }
+}
+
TEST_CASE("MSVC debug information format options")
{
TestContext test_context;