From: Joel Rosdahl Date: Thu, 26 Mar 2026 08:13:39 +0000 (+0100) Subject: fix: Disable base directory when using MSVC's /Yc option X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f0ef4adf142e4542855144cd28d239ffec532817;p=thirdparty%2Fccache.git fix: Disable base directory when using MSVC's /Yc option When creating a precompiled header (PCH), MSVC does not like relative paths for /Yc and /FI arguments, so don't rewrite paths to relative in that case. Fixes #1710. --- diff --git a/src/ccache/argprocessing.cpp b/src/ccache/argprocessing.cpp index 535c4a17..a130e907 100644 --- a/src/ccache/argprocessing.cpp +++ b/src/ccache/argprocessing.cpp @@ -1405,13 +1405,25 @@ process_arg(const Context& ctx, Config& config, util::Args& args, size_t& args_index, - ArgumentProcessingState& state) + ArgumentProcessingState& state, + bool& restart) { - const auto processed = + const auto statistic = process_option_arg(ctx, args_info, config, args, args_index, state); - if (processed) { - const auto& error = *processed; - return error; + + if (statistic && *statistic != Statistic::none) { + return *statistic; // error found + } + + if (state.found_Yc && config.is_compiler_group_msvc() + && !config.base_dirs().empty()) { + LOG("Creating PCH with MSVC, disabling base directory"); + config.set_base_dirs({}); + restart = true; + } + + if (statistic) { + return *statistic; // processed option without error } size_t& i = args_index; @@ -1461,19 +1473,34 @@ process_args(Context& ctx) ArgsInfo& args_info = ctx.args_info; Config& config = ctx.config; - // 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. - util::Args args = ctx.orig_args; ArgumentProcessingState state; - state.add_common_arg(args[0]); // Compiler - std::optional argument_error; - for (size_t i = 1; i < args.size(); i++) { - const auto error = process_arg(ctx, args_info, ctx.config, args, i, state); - if (error != Statistic::none && !argument_error) { - argument_error = error; + while (true) { + // args is a copy of the original arguments given to the compiler but where + // arguments from @file and similar constructs will be expanded. It's only + // used as a temporary data structure to loop over. + util::Args args = ctx.orig_args; + args_info = {}; + state = {}; + argument_error = std::nullopt; + + state.add_common_arg(args[0]); // Compiler + + bool restart = false; + for (size_t i = 1; i < args.size(); i++) { + const auto statistic = + process_arg(ctx, args_info, ctx.config, args, i, state, restart); + if (restart) { + break; + } + if (statistic != Statistic::none && !argument_error) { + argument_error = statistic; + } + } + + if (!restart) { + break; } } diff --git a/unittest/test_argprocessing.cpp b/unittest/test_argprocessing.cpp index 1b9f548f..f031edc8 100644 --- a/unittest/test_argprocessing.cpp +++ b/unittest/test_argprocessing.cpp @@ -765,6 +765,51 @@ TEST_CASE("MSVC PCH options") } } +TEST_CASE("MSVC /Yc in response file disables base_dir rewriting") +{ + TestContext test_context; + Context ctx; + ctx.config.set_compiler_type(CompilerType::msvc); + ctx.config.set_base_dir(get_root()); + REQUIRE(util::write_file("pch.h", "")); + REQUIRE(util::write_file("pch.cpp", "")); + + const auto pch_path = ctx.actual_cwd / "pch.cpp.pch"; + const auto include_path = ctx.actual_cwd / "pch.h"; + const auto output_path = ctx.actual_cwd / "pch.cpp.obj"; + const auto source_path = ctx.actual_cwd / "pch.cpp"; + REQUIRE(util::write_file("pch.rsp", + FMT("/Yc /Fp{} /FI{} /Fo{} /c {}\n", + pch_path, + include_path, + output_path, + source_path))); + + ctx.orig_args = Args::from_string("cl.exe @pch.rsp"); + const auto result = process_args(ctx); + + REQUIRE(result); + CHECK(ctx.args_info.generating_pch); + CHECK(ctx.args_info.output_obj == output_path); + CHECK(result->preprocessor_args.to_string() + == FMT("cl.exe /Yc -Fp{} -FI{}", pch_path, include_path)); +} + +TEST_CASE("MSVC /Yc with base_dir preserves later argument errors") +{ + TestContext test_context; + Context ctx; + ctx.config.set_compiler_type(CompilerType::msvc); + ctx.config.set_base_dir(get_root()); + REQUIRE(util::write_file("pch.cpp", "")); + + ctx.orig_args = Args::from_string("cl.exe /Yc /c pch.cpp /FI"); + + const auto result = process_args(ctx); + + CHECK(result.error() == Statistic::bad_compiler_arguments); +} + TEST_CASE("MSVC PCH options with empty -Yc") { TestContext test_context;