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;
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<Statistic> 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;
}
}
}
}
+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;