From: Joel Rosdahl Date: Sun, 20 Jul 2025 13:41:44 +0000 (+0200) Subject: fix: Keep original order of compiler arguments X-Git-Tag: v4.12~77 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a7c2455ab7eb005d00e0fdff0776474f239747d1;p=thirdparty%2Fccache.git fix: Keep original order of compiler arguments Now when CCACHE_NOCPP2 (run_second_cpp = false) has been removed (see fd9de83446aeaf1eb1b33a2d900ea1ff757c4509) we can simplify compiler argument juggling: instead of partitioning arguments into different lists and reassemble them later, we can build up the preprocessor and compiler command lines while we go, thus keeping the original order of arguments. Fixes #738. --- diff --git a/src/ccache/argprocessing.cpp b/src/ccache/argprocessing.cpp index ffff647f..7122d294 100644 --- a/src/ccache/argprocessing.cpp +++ b/src/ccache/argprocessing.cpp @@ -69,10 +69,11 @@ enum class OutputDepOrigin : uint8_t { wp = 2 }; -struct ArgumentProcessingState +class ArgumentProcessingState { - bool found_c_opt = false; - bool found_dc_opt = false; +public: + std::optional found_c_opt; + std::optional found_dc_opt; bool found_S_opt = false; bool found_analyze_opt = false; bool found_pch = false; @@ -102,32 +103,57 @@ struct ArgumentProcessingState // Arguments classified as input files. std::vector input_files; - // common_args contains all original arguments except: - // * those that never should be passed to the preprocessor, and - // * dependency options (like -MD and friends). - Args common_args; + // Whether to include the full command line in the hash. + bool hash_full_command_line = false; - // cpp_args contains arguments that were not added to common_args. - Args cpp_args; + // Whether to include the actual CWD in the hash. + bool hash_actual_cwd = false; - // dep_args contains dependency options like -MD. They are only passed to the - // preprocessor, never to the compiler. - Args dep_args; + template + void + add_common_arg(T&& arg) + { + m_preprocessor_args.push_back(std::forward(arg)); + m_compiler_args.push_back(std::forward(arg)); + } - // compiler_only_args contains arguments that should only be passed to the - // compiler, not the preprocessor. - Args compiler_only_args; + template + void + add_compiler_only_arg(T&& arg) + { + m_compiler_args.push_back(std::forward(arg)); + m_extra_args_to_hash.push_back(std::forward(arg)); + } - // compiler_only_args_no_hash contains arguments that should only be passed to - // the compiler, not the preprocessor, and that also should not be part of the - // hash identifying the result. - Args compiler_only_args_no_hash; + template + void + add_compiler_only_arg_no_hash(T&& arg) + { + m_compiler_args.push_back(std::forward(arg)); + } - // Whether to include the full command line in the hash. - bool hash_full_command_line = false; + template + void + add_extra_args_to_hash(T&& args) + { + m_extra_args_to_hash.push_back(std::forward(args)); + } - // Whether to include the actual CWD in the hash. - bool hash_actual_cwd = false; + ProcessArgsResult + to_result() + { + return { + m_preprocessor_args, + m_compiler_args, + m_extra_args_to_hash, + hash_actual_cwd, + }; + } + +private: + Args m_preprocessor_args; + Args m_compiler_args; + Args m_extra_args_to_hash; }; bool @@ -345,7 +371,7 @@ process_option_arg(const Context& ctx, if (option_should_be_ignored(args[i], ctx.ignore_options())) { LOG("Not processing ignored option: {}", args[i]); - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } @@ -355,7 +381,7 @@ process_option_arg(const Context& ctx, LOG_RAW("--ccache-skip lacks an argument"); return Statistic::bad_compiler_arguments; } - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } @@ -432,7 +458,7 @@ process_option_arg(const Context& ctx, if (arg == "-fdump-ipa-clones") { args_info.generating_ipa_clones = true; - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } @@ -498,11 +524,9 @@ process_option_arg(const Context& ctx, || args[i + 1] == "-include" || args[i + 1] == "--include" || args[i + 1] == "-fno-pch-timestamp")) { if (compopt_affects_compiler_output(args[i + 1])) { - state.compiler_only_args.push_back(args[i]); - } else if (compopt_affects_cpp_output(args[i + 1])) { - state.cpp_args.push_back(args[i]); + state.add_compiler_only_arg(args[i]); } else { - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); } ++i; arg = make_dash_option(ctx.config, args[i]); @@ -531,11 +555,11 @@ process_option_arg(const Context& ctx, || (i + 1 < args.size() && arg == "-Xclang" && compopt_affects_compiler_output(args[i + 1]))) { if (i + 1 < args.size() && arg == "-Xclang") { - state.compiler_only_args.push_back(args[i]); + state.add_compiler_only_arg(args[i]); ++i; arg = make_dash_option(ctx.config, args[i]); } - state.compiler_only_args.push_back(args[i]); + state.add_compiler_only_arg(args[i]); // Note: "-Xclang -option-that-takes-arg -Xclang arg" is not handled below // yet. if (compopt_takes_arg(arg) @@ -544,7 +568,7 @@ process_option_arg(const Context& ctx, LOG("Missing argument to {}", args[i]); return Statistic::bad_compiler_arguments; } - state.compiler_only_args.push_back(args[i + 1]); + state.add_compiler_only_arg(args[i + 1]); ++i; } return Statistic::none; @@ -553,10 +577,10 @@ process_option_arg(const Context& ctx, || (i + 1 < args.size() && arg == "-Xclang" && compopt_prefix_affects_compiler_output(args[i + 1]))) { if (i + 1 < args.size() && arg == "-Xclang") { - state.compiler_only_args.push_back(args[i]); + state.add_compiler_only_arg(args[i]); ++i; } - state.compiler_only_args.push_back(args[i]); + state.add_compiler_only_arg(args[i]); return Statistic::none; } @@ -581,9 +605,8 @@ process_option_arg(const Context& ctx, } } - // We must have -c. if (arg == "-c" || arg == "--compile") { // --compile is NVCC - state.found_c_opt = true; + state.found_c_opt = args[i]; return Statistic::none; } @@ -604,34 +627,34 @@ process_option_arg(const Context& ctx, if (arg == "-TC") { args_info.actual_language = "c"; - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } if (arg == "-TP") { args_info.actual_language = "c++"; - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } } - // when using nvcc with separable compilation, -dc implies -c + // -dc implies -c when using NVCC with separable compilation. if ((arg == "-dc" || arg == "--device-c") && config.compiler_type() == CompilerType::nvcc) { - state.found_dc_opt = true; + state.found_dc_opt = args[i]; return Statistic::none; } // -S changes the default extension. if (arg == "-S") { - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); state.found_S_opt = true; return Statistic::none; } // --analyze changes the default extension too if (arg == "--analyze") { - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); state.found_analyze_opt = true; return Statistic::none; } @@ -642,7 +665,7 @@ process_option_arg(const Context& ctx, // 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]); + state.add_common_arg(args[i]); return Statistic::none; } @@ -693,7 +716,7 @@ process_option_arg(const Context& ctx, || util::starts_with(arg, "-ffile-prefix-map=")) { std::string map = arg.substr(arg.find('=') + 1); args_info.debug_prefix_maps.push_back(map); - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } @@ -706,7 +729,7 @@ process_option_arg(const Context& ctx, LOG("Missing argument to {}", args[i]); return Statistic::bad_compiler_arguments; } - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); compilation_dir = args[i + 1]; i++; } else { @@ -716,14 +739,14 @@ process_option_arg(const Context& ctx, } } args_info.compilation_dir = std::move(compilation_dir); - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } // Debugging is handled specially, so that we know if we can strip line // number info. if (util::starts_with(arg, "-g")) { - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); if (util::starts_with(arg, "-gdwarf")) { // Selection of DWARF format (-gdwarf or -gdwarf-) enables @@ -757,18 +780,18 @@ process_option_arg(const Context& ctx, if (config.is_compiler_group_msvc() && !config.is_compiler_group_clang() && is_msvc_z_debug_option(arg)) { state.last_seen_msvc_z_debug_option = args[i]; - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } if (config.is_compiler_group_msvc() && util::starts_with(arg, "-Fd")) { - state.compiler_only_args_no_hash.push_back(args[i]); + state.add_compiler_only_arg_no_hash(args[i]); return Statistic::none; } if (config.is_compiler_group_msvc() && (util::starts_with(arg, "-MP") || arg == "-FS")) { - state.compiler_only_args_no_hash.push_back(args[i]); + state.add_compiler_only_arg_no_hash(args[i]); return Statistic::none; } @@ -777,7 +800,7 @@ process_option_arg(const Context& ctx, if ((arg == "-MD" || arg == "-MMD") && !config.is_compiler_group_msvc()) { state.found_md_or_mmd_opt = true; args_info.generating_dependencies = true; - state.dep_args.push_back(args[i]); + state.add_compiler_only_arg(args[i]); return Statistic::none; } @@ -805,10 +828,10 @@ process_option_arg(const Context& ctx, } // Keep the format of the args the same. if (separate_argument) { - state.dep_args.push_back("-MF"); - state.dep_args.push_back(args_info.output_dep); + state.add_compiler_only_arg("-MF"); + state.add_compiler_only_arg(args_info.output_dep); } else { - state.dep_args.push_back(FMT("-MF{}", args_info.output_dep)); + state.add_compiler_only_arg(FMT("-MF{}", args_info.output_dep)); } return Statistic::none; } @@ -824,8 +847,8 @@ process_option_arg(const Context& ctx, LOG("Missing argument to {}", args[i]); return Statistic::bad_compiler_arguments; } - state.dep_args.push_back(args[i]); - state.dep_args.push_back(args[i + 1]); + state.add_compiler_only_arg(args[i]); + state.add_compiler_only_arg(args[i + 1]); dep_target = args[i + 1]; i++; } else { @@ -833,7 +856,7 @@ process_option_arg(const Context& ctx, const std::string_view arg_view(arg); const auto arg_opt = arg_view.substr(0, 3); dep_target = arg_view.substr(3); - state.dep_args.push_back(FMT("{}{}", arg_opt, dep_target)); + state.add_compiler_only_arg(FMT("{}{}", arg_opt, dep_target)); } if (args_info.dependency_target) { @@ -853,8 +876,7 @@ process_option_arg(const Context& ctx, && (util::starts_with(arg, "-MD") || util::starts_with(arg, "-MT") || util::starts_with(arg, "-LD"))) { // These affect compiler but also #define some things. - state.cpp_args.push_back(args[i]); - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } @@ -862,39 +884,39 @@ process_option_arg(const Context& ctx, // clang-cl: || arg == "-showIncludes:user") { args_info.generating_includes = true; - state.dep_args.push_back(args[i]); + state.add_compiler_only_arg(args[i]); return Statistic::none; } if (arg == "-fprofile-arcs") { args_info.profile_arcs = true; - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } if (arg == "-ftest-coverage") { args_info.generating_coverage = true; - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } if (arg == "-fstack-usage") { args_info.generating_stackusage = true; - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } // This covers all the different marker cases if (util::starts_with(arg, "-fcallgraph-info")) { args_info.generating_callgraphinfo = true; - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } // -Zs is MSVC's -fsyntax-only equivalent if (arg == "-fsyntax-only" || arg == "-Zs") { args_info.expect_output_obj = false; - state.compiler_only_args.push_back(args[i]); + state.add_compiler_only_arg(args[i]); state.found_syntax_only = true; return Statistic::none; } @@ -903,7 +925,7 @@ process_option_arg(const Context& ctx, || arg == "-coverage") { // Undocumented but still works. args_info.profile_arcs = true; args_info.generating_coverage = true; - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } @@ -913,7 +935,7 @@ process_option_arg(const Context& ctx, // the actual CWD in the .gcno file. state.hash_actual_cwd = true; } - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } @@ -924,20 +946,20 @@ process_option_arg(const Context& ctx, // The failure is logged by process_profiling_option. return Statistic::unsupported_compiler_option; } - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } if (util::starts_with(arg, "-fsanitize-blacklist=")) { args_info.sanitize_blacklists.emplace_back(args[i].substr(21)); - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } if (util::starts_with(arg, "--sysroot=")) { auto path = std::string_view(arg).substr(10); auto relpath = core::make_relative_path(ctx, path); - state.common_args.push_back(FMT("--sysroot={}", relpath)); + state.add_common_arg(FMT("--sysroot={}", relpath)); return Statistic::none; } @@ -947,9 +969,9 @@ process_option_arg(const Context& ctx, LOG("Missing argument to {}", args[i]); return Statistic::bad_compiler_arguments; } - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); auto relpath = core::make_relative_path(ctx, args[i + 1]); - state.common_args.push_back(relpath); + state.add_common_arg(relpath); i++; return Statistic::none; } @@ -960,8 +982,8 @@ process_option_arg(const Context& ctx, LOG("Missing argument to {}", args[i]); return Statistic::bad_compiler_arguments; } - state.common_args.push_back(args[i]); - state.common_args.push_back(args[i + 1]); + state.add_common_arg(args[i]); + state.add_common_arg(args[i + 1]); i++; return Statistic::none; } @@ -969,7 +991,7 @@ process_option_arg(const Context& ctx, if (arg == "-P" || arg == "-Wp,-P") { // Avoid passing -P to the preprocessor since it removes preprocessor // information we need. - state.compiler_only_args.push_back(args[i]); + state.add_compiler_only_arg(args[i]); return Statistic::none; } @@ -986,7 +1008,7 @@ process_option_arg(const Context& ctx, state.output_dep_origin = OutputDepOrigin::wp; args_info.output_dep = arg.substr(8); } - state.dep_args.push_back(args[i]); + state.add_compiler_only_arg(args[i]); return Statistic::none; } else if (util::starts_with(arg, "-Wp,-MMD,") && arg.find(',', 9) == std::string::npos) { @@ -996,19 +1018,19 @@ process_option_arg(const Context& ctx, state.output_dep_origin = OutputDepOrigin::wp; args_info.output_dep = arg.substr(9); } - state.dep_args.push_back(args[i]); + state.add_compiler_only_arg(args[i]); return Statistic::none; } else if ((util::starts_with(arg, "-Wp,-D") || util::starts_with(arg, "-Wp,-U")) && arg.find(',', 6) == std::string::npos) { - state.cpp_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } else if (arg == "-Wp,-MP" || (arg.size() > 8 && util::starts_with(arg, "-Wp,-M") && arg[7] == ',' && (arg[6] == 'F' || arg[6] == 'Q' || arg[6] == 'T') && arg.find(',', 8) == std::string::npos)) { - state.dep_args.push_back(args[i]); + state.add_compiler_only_arg(args[i]); return Statistic::none; } else if (config.direct_mode()) { // -Wp, can be used to pass too hard options to the preprocessor. @@ -1018,12 +1040,12 @@ process_option_arg(const Context& ctx, } // Any other -Wp,* arguments are only relevant for the preprocessor. - state.cpp_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } if (arg == "-MP") { - state.dep_args.push_back(args[i]); + state.add_compiler_only_arg(args[i]); return Statistic::none; } @@ -1047,16 +1069,16 @@ process_option_arg(const Context& ctx, if (config.compiler_type() == CompilerType::gcc) { if (arg == "-fdiagnostics-color" || arg == "-fdiagnostics-color=always") { state.color_diagnostics = ColorDiagnostics::always; - state.compiler_only_args_no_hash.push_back(args[i]); + state.add_compiler_only_arg_no_hash(args[i]); return Statistic::none; } else if (arg == "-fno-diagnostics-color" || arg == "-fdiagnostics-color=never") { state.color_diagnostics = ColorDiagnostics::never; - state.compiler_only_args_no_hash.push_back(args[i]); + state.add_compiler_only_arg_no_hash(args[i]); return Statistic::none; } else if (arg == "-fdiagnostics-color=auto") { state.color_diagnostics = ColorDiagnostics::automatic; - state.compiler_only_args_no_hash.push_back(args[i]); + state.add_compiler_only_arg_no_hash(args[i]); return Statistic::none; } } else if (config.is_compiler_group_clang()) { @@ -1064,33 +1086,33 @@ process_option_arg(const Context& ctx, // -fcolor-diagnostics argument which is passed to cc1 is handled below. if (arg == "-Xclang" && i + 1 < args.size() && args[i + 1] == "-fcolor-diagnostics") { - state.compiler_only_args_no_hash.push_back(args[i]); + state.add_compiler_only_arg_no_hash(args[i]); ++i; arg = make_dash_option(ctx.config, args[i]); } if (arg == "-fdiagnostics-color" || arg == "-fdiagnostics-color=always" || arg == "-fcolor-diagnostics") { state.color_diagnostics = ColorDiagnostics::always; - state.compiler_only_args_no_hash.push_back(args[i]); + state.add_compiler_only_arg_no_hash(args[i]); return Statistic::none; } else if (arg == "-fno-diagnostics-color" || arg == "-fdiagnostics-color=never" || arg == "-fno-color-diagnostics") { state.color_diagnostics = ColorDiagnostics::never; - state.compiler_only_args_no_hash.push_back(args[i]); + state.add_compiler_only_arg_no_hash(args[i]); return Statistic::none; } } if (arg == "-fno-pch-timestamp") { args_info.fno_pch_timestamp = true; - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } if (arg == "-fpch-preprocess") { state.found_fpch_preprocess = true; - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } @@ -1119,7 +1141,7 @@ process_option_arg(const Context& ctx, // MSVC -u is something else than GCC -u, handle it specially. if (arg == "-u" && ctx.config.is_compiler_group_msvc()) { - state.cpp_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } @@ -1141,13 +1163,11 @@ process_option_arg(const Context& ctx, // rate. A secondary effect is that paths in the standard error output // produced by the compiler will be normalized. fs::path relpath = core::make_relative_path(ctx, args[i + next]); - auto& dest_args = - compopt_affects_cpp_output(arg) ? state.cpp_args : state.common_args; - dest_args.push_back(args[i]); + state.add_common_arg(args[i]); if (next == 2) { - dest_args.push_back(args[i + 1]); + state.add_common_arg(args[i + 1]); } - dest_args.push_back(relpath); + state.add_common_arg(relpath); i += next; return Statistic::none; @@ -1175,9 +1195,9 @@ process_option_arg(const Context& ctx, const auto relpath = core::make_relative_path(ctx, *path); std::string new_option = FMT("{}{}", option, relpath); if (compopt_affects_cpp_output(option)) { - state.cpp_args.push_back(std::move(new_option)); + state.add_common_arg(std::move(new_option)); } else { - state.common_args.push_back(std::move(new_option)); + state.add_common_arg(std::move(new_option)); } return Statistic::none; } @@ -1191,11 +1211,11 @@ process_option_arg(const Context& ctx, } if (compopt_affects_cpp_output(arg)) { - state.cpp_args.push_back(args[i]); - state.cpp_args.push_back(args[i + 1]); + state.add_common_arg(args[i]); + state.add_common_arg(args[i + 1]); } else { - state.common_args.push_back(args[i]); - state.common_args.push_back(args[i + 1]); + state.add_common_arg(args[i]); + state.add_common_arg(args[i + 1]); } i++; @@ -1211,14 +1231,14 @@ process_option_arg(const Context& ctx, if (arg[0] == '-') { if (compopt_affects_cpp_output(arg) || compopt_prefix_affects_cpp_output(arg)) { - state.cpp_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } else if (ctx.config.is_compiler_group_msvc() && args[i][0] == '/' // Intentionally not checking arg here && DirEntry(args[i]).is_regular_file()) { // Likely the input file, which is handled in process_arg later. } else { - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } } @@ -1252,7 +1272,7 @@ process_arg(const Context& ctx, if (!util::is_dev_null_path(args[i])) { if (!DirEntry(args[i]).is_regular_file()) { LOG("{} is not a regular file, not considering as input file", args[i]); - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); return Statistic::none; } } @@ -1262,7 +1282,7 @@ process_arg(const Context& ctx, state.input_files.emplace_back(args[i]); } else { LOG("Not considering {} an input file since it doesn't exist", args[i]); - state.common_args.push_back(args[i]); + state.add_common_arg(args[i]); } return Statistic::none; } @@ -1295,7 +1315,7 @@ process_args(Context& ctx) Args args = ctx.orig_args; ArgumentProcessingState state; - state.common_args.push_back(args[0]); // Compiler + state.add_common_arg(args[0]); // Compiler std::optional argument_error; for (size_t i = 1; i < args.size(); i++) { @@ -1464,7 +1484,7 @@ process_args(Context& ctx) if (is_link) { if (args_info.output_is_precompiled_header) { - state.common_args.push_back("-c"); + state.add_common_arg("-c"); } else { LOG_RAW("No -c option found"); // Having a separate statistic for autoconf tests is useful, as they are @@ -1528,14 +1548,14 @@ process_args(Context& ctx) // -finput-charset=CHARSET (otherwise conversion happens twice) // -x CHARSET (otherwise the wrong language is selected) if (!state.input_charset_option.empty()) { - state.cpp_args.push_back(state.input_charset_option); + state.add_common_arg(state.input_charset_option); } if (state.found_pch && !ctx.config.is_compiler_group_msvc()) { - state.cpp_args.push_back("-fpch-preprocess"); + state.add_common_arg("-fpch-preprocess"); } if (!state.explicit_language.empty()) { - state.cpp_args.push_back("-x"); - state.cpp_args.push_back(state.explicit_language); + state.add_common_arg("-x"); + state.add_common_arg(state.explicit_language); } args_info.strip_diagnostics_colors = @@ -1613,19 +1633,6 @@ process_args(Context& ctx) ctx, util::add_extension(args_info.orig_input_file, ".000i.ipa-clones")); } - Args compiler_args = state.common_args; - compiler_args.push_back(state.compiler_only_args_no_hash); - compiler_args.push_back(state.compiler_only_args); - compiler_args.push_back(state.cpp_args); - - if (state.found_c_opt) { - compiler_args.push_back("-c"); - } - - if (state.found_dc_opt) { - compiler_args.push_back("-dc"); - } - if (!state.xarch_args.empty()) { for (const auto& arch : args_info.arch_args) { auto it = state.xarch_args.find(arch); @@ -1636,47 +1643,44 @@ process_args(Context& ctx) } for (const auto& arch : args_info.arch_args) { - compiler_args.push_back("-arch"); - compiler_args.push_back(arch); + state.add_compiler_only_arg_no_hash("-arch"); + state.add_compiler_only_arg_no_hash(arch); auto it = args_info.xarch_args.find(arch); if (it != args_info.xarch_args.end()) { args_info.xarch_args.emplace(arch, it->second); for (const auto& xarch : it->second) { - compiler_args.push_back("-Xarch_" + arch); - compiler_args.push_back(xarch); + state.add_compiler_only_arg_no_hash("-Xarch_" + arch); + state.add_compiler_only_arg_no_hash(xarch); } } } - Args preprocessor_args = state.common_args; - preprocessor_args.push_back(state.cpp_args); - compiler_args.push_back(state.dep_args); - - Args extra_args_to_hash = state.compiler_only_args; - extra_args_to_hash.push_back(state.dep_args); if (state.hash_full_command_line) { - extra_args_to_hash.push_back(ctx.orig_args); + state.add_extra_args_to_hash(ctx.orig_args); } if (diagnostics_color_arg) { - compiler_args.push_back(*diagnostics_color_arg); + state.add_compiler_only_arg_no_hash(*diagnostics_color_arg); } if (ctx.config.depend_mode() && !args_info.generating_includes && ctx.config.compiler_type() == CompilerType::msvc) { ctx.auto_depend_mode = true; args_info.generating_includes = true; - compiler_args.push_back("/showIncludes"); + state.add_compiler_only_arg_no_hash("/showIncludes"); } - return ProcessArgsResult{ - preprocessor_args, - extra_args_to_hash, - compiler_args, - state.hash_actual_cwd, - }; + if (state.found_c_opt) { + state.add_compiler_only_arg_no_hash(*state.found_c_opt); + } + + if (state.found_dc_opt) { + state.add_compiler_only_arg_no_hash(*state.found_dc_opt); + } + + return state.to_result(); } bool diff --git a/src/ccache/argprocessing.hpp b/src/ccache/argprocessing.hpp index 61edd690..6ffc3459 100644 --- a/src/ccache/argprocessing.hpp +++ b/src/ccache/argprocessing.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020-2024 Joel Rosdahl and other contributors +// Copyright (C) 2020-2025 Joel Rosdahl and other contributors // // See doc/AUTHORS.adoc for a complete list of contributors. // @@ -32,16 +32,17 @@ class Context; struct ProcessArgsResult { - // Arguments (except -E) to send to the preprocessor. + // Arguments (except "-E -o output.i") to send to the preprocessor. These are + // part of the input hash (except those marked as AFFECTS_CPP in compopt.cpp). Args preprocessor_args; - // Arguments not sent to the preprocessor but that should be part of the hash. - Args extra_args_to_hash; - - // Arguments to send to the real compiler. + // Arguments to send to the real compiler. Not part of the input hash. Args compiler_args; - // Whether to include the actual CWD in the hash. + // Arguments not sent to the preprocessor but added to the input hash anyway. + Args extra_args_to_hash; + + // Whether to include the actual CWD in the input hash. bool hash_actual_cwd = false; }; diff --git a/test/suites/base.bash b/test/suites/base.bash index ab1bd9cb..2c954280 100644 --- a/test/suites/base.bash +++ b/test/suites/base.bash @@ -1666,6 +1666,19 @@ EOF expect_content_pattern compiler.args "(-E -o * test1.c)(-Werror -rdynamic -c -o test1.o test1.c)" rm compiler.args + # ------------------------------------------------------------------------- + if $COMPILER -Wdelete-non-virtual-dtor -c test1.c 2>/dev/null && ! $COMPILER -Werror -Wdelete-non-virtual-dtor -c test1.c 2>/dev/null; then + TEST "Ordering of warning options" + + if $CCACHE_COMPILE -Werror -Wdelete-non-virtual-dtor -c test1.c 2>stderr.txt; then + test_failed "-Werror -Wdelete-non-virtual-dtor did not result in an error; stderr: [$(stderr.txt; then + test_failed "-Wdelete-non-virtual-dtor -Werror resulted in an error; stderr: [$(preprocessor_args.to_string() == "cc"); CHECK(result->extra_args_to_hash.to_string() == dep_args); - CHECK(result->compiler_args.to_string() == "cc -c " + dep_args); + CHECK(result->compiler_args.to_string() == "cc " + dep_args + " -c"); } TEST_CASE("cpp_only_args_to_preprocessor_and_compiler") @@ -135,7 +135,7 @@ TEST_CASE("cpp_only_args_to_preprocessor_and_compiler") CHECK(result->preprocessor_args.to_string() == "cc " + cpp_args); CHECK(result->extra_args_to_hash.to_string() == dep_args); CHECK(result->compiler_args.to_string() - == "cc " + cpp_args + " -c " + dep_args); + == "cc " + cpp_args + " " + dep_args + " -c"); } TEST_CASE( @@ -152,7 +152,7 @@ TEST_CASE( CHECK(result); CHECK(result->preprocessor_args.to_string() == "cc"); CHECK(result->extra_args_to_hash.to_string() == dep_args); - CHECK(result->compiler_args.to_string() == "cc -c " + dep_args); + CHECK(result->compiler_args.to_string() == "cc " + dep_args + " -c"); } TEST_CASE("equal_sign_after_MF_should_be_removed") @@ -167,7 +167,7 @@ TEST_CASE("equal_sign_after_MF_should_be_removed") CHECK(result); CHECK(result->preprocessor_args.to_string() == "cc"); CHECK(result->extra_args_to_hash.to_string() == "-MFpath"); - CHECK(result->compiler_args.to_string() == "cc -c -MFpath"); + CHECK(result->compiler_args.to_string() == "cc -MFpath -c"); } TEST_CASE("sysroot_should_be_rewritten_if_basedir_is_used") @@ -318,7 +318,7 @@ TEST_CASE("MF_flag_with_immediate_argument_should_work_as_last_argument") CHECK(result); CHECK(result->preprocessor_args.to_string() == "cc"); CHECK(result->extra_args_to_hash.to_string() == "-MMD -MT bar -MFfoo.d"); - CHECK(result->compiler_args.to_string() == "cc -c -MMD -MT bar -MFfoo.d"); + CHECK(result->compiler_args.to_string() == "cc -MMD -MT bar -MFfoo.d -c"); } TEST_CASE("MT_flag_with_immediate_argument_should_work_as_last_argument") @@ -337,7 +337,7 @@ TEST_CASE("MT_flag_with_immediate_argument_should_work_as_last_argument") CHECK(result->extra_args_to_hash.to_string() == "-MMD -MFfoo.d -MT foo -MTbar"); CHECK(result->compiler_args.to_string() - == "cc -c -MMD -MFfoo.d -MT foo -MTbar"); + == "cc -MMD -MFfoo.d -MT foo -MTbar -c"); } TEST_CASE("MQ_flag_with_immediate_argument_should_work_as_last_argument") @@ -356,7 +356,7 @@ TEST_CASE("MQ_flag_with_immediate_argument_should_work_as_last_argument") CHECK(result->extra_args_to_hash.to_string() == "-MMD -MFfoo.d -MQ foo -MQbar"); CHECK(result->compiler_args.to_string() - == "cc -c -MMD -MFfoo.d -MQ foo -MQbar"); + == "cc -MMD -MFfoo.d -MQ foo -MQbar -c"); } TEST_CASE("MQ_flag_without_immediate_argument_should_not_add_MQobj") @@ -372,7 +372,7 @@ TEST_CASE("MQ_flag_without_immediate_argument_should_not_add_MQobj") CHECK(result->preprocessor_args.to_string() == "gcc"); CHECK(result->extra_args_to_hash.to_string() == "-MD -MP -MFfoo.d -MQ foo.d"); CHECK(result->compiler_args.to_string() - == "gcc -c -MD -MP -MFfoo.d -MQ foo.d"); + == "gcc -MD -MP -MFfoo.d -MQ foo.d -c"); } TEST_CASE("MT_flag_without_immediate_argument_should_not_add_MTobj") @@ -388,7 +388,7 @@ TEST_CASE("MT_flag_without_immediate_argument_should_not_add_MTobj") CHECK(result->preprocessor_args.to_string() == "gcc"); CHECK(result->extra_args_to_hash.to_string() == "-MD -MP -MFfoo.d -MT foo.d"); CHECK(result->compiler_args.to_string() - == "gcc -c -MD -MP -MFfoo.d -MT foo.d"); + == "gcc -MD -MP -MFfoo.d -MT foo.d -c"); } TEST_CASE("MQ_flag_with_immediate_argument_should_not_add_MQobj") @@ -404,7 +404,7 @@ TEST_CASE("MQ_flag_with_immediate_argument_should_not_add_MQobj") CHECK(result->preprocessor_args.to_string() == "gcc"); CHECK(result->extra_args_to_hash.to_string() == "-MD -MP -MFfoo.d -MQfoo.d"); CHECK(result->compiler_args.to_string() - == "gcc -c -MD -MP -MFfoo.d -MQfoo.d"); + == "gcc -MD -MP -MFfoo.d -MQfoo.d -c"); } TEST_CASE("MT_flag_with_immediate_argument_should_not_add_MQobj") @@ -420,7 +420,7 @@ TEST_CASE("MT_flag_with_immediate_argument_should_not_add_MQobj") CHECK(result->preprocessor_args.to_string() == "gcc"); CHECK(result->extra_args_to_hash.to_string() == "-MD -MP -MFfoo.d -MTfoo.d"); CHECK(result->compiler_args.to_string() - == "gcc -c -MD -MP -MFfoo.d -MTfoo.d"); + == "gcc -MD -MP -MFfoo.d -MTfoo.d -c"); } TEST_CASE( @@ -521,7 +521,7 @@ TEST_CASE("options_not_to_be_passed_to_the_preprocessor") CHECK(result->extra_args_to_hash.to_string() == "-Wa,foo -Werror -Xlinker fie -Xlinker,fum -Wno-error"); CHECK(result->compiler_args.to_string() - == "cc -g -Wa,foo -Werror -Xlinker fie -Xlinker,fum -Wno-error -DX -c"); + == "cc -Wa,foo -g -DX -Werror -Xlinker fie -Xlinker,fum -Wno-error -c"); } TEST_CASE("cuda_option_file") @@ -611,7 +611,7 @@ TEST_CASE("-Xclang") CHECK(result->extra_args_to_hash.to_string() == extra_args); CHECK(result->compiler_args.to_string() == "clang " + common_args + " " + color_diag + " " + extra_args + " " - + pch_pth_variants + " -c -fcolor-diagnostics"); + + pch_pth_variants + " -fcolor-diagnostics -c"); } TEST_CASE("-x") @@ -706,7 +706,7 @@ TEST_CASE("MSVC options" const auto result = process_args(ctx); CHECK(result); CHECK(result->preprocessor_args.to_string() == "cl.exe /foobar"); - CHECK(result->compiler_args.to_string() == "cl.exe /foobar -c"); + CHECK(result->compiler_args.to_string() == "cl.exe /foobar /c"); } TEST_CASE("MSVC PCH options") @@ -730,7 +730,7 @@ TEST_CASE("MSVC PCH options") 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"); + == "cl.exe /Ycpch.h /Fppch.cpp.pch /FIpch.h /c"); } util::write_file("pch.cpp.pch", ""); @@ -750,7 +750,7 @@ TEST_CASE("MSVC PCH options") 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"); + == "cl.exe /Yupch.h /Fppch.cpp.pch /FIpch.h /c"); } } @@ -775,7 +775,7 @@ TEST_CASE("MSVC PCH options with empty -Yc") CHECK(result->preprocessor_args.to_string() == "cl.exe /Yc /Fppch.cpp.pch /FIpch.h"); CHECK(result->compiler_args.to_string() - == "cl.exe /Yc /Fppch.cpp.pch /FIpch.h -c"); + == "cl.exe /Yc /Fppch.cpp.pch /FIpch.h /c"); } util::write_file("pch.cpp.pch", ""); @@ -795,7 +795,7 @@ TEST_CASE("MSVC PCH options with empty -Yc") 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"); + == "cl.exe /Yupch.h /Fppch.cpp.pch /FIpch.h /c"); } } @@ -817,7 +817,7 @@ TEST_CASE("MSVC PCH options with empty -Yc and without -Fp") CHECK(ctx.args_info.included_pch_file == "pch.pch"); CHECK(ctx.args_info.output_obj == "pch.cpp.obj"); CHECK(result->preprocessor_args.to_string() == "cl.exe /Yc"); - CHECK(result->compiler_args.to_string() == "cl.exe /Yc -c"); + CHECK(result->compiler_args.to_string() == "cl.exe /Yc /c"); } util::write_file("pch.pch", ""); @@ -837,7 +837,7 @@ TEST_CASE("MSVC PCH options with empty -Yc and without -Fp") CHECK(result->preprocessor_args.to_string() == "cl.exe /Yupch.h /Fppch.pch /FIpch.h"); CHECK(result->compiler_args.to_string() - == "cl.exe /Yupch.h /Fppch.pch /FIpch.h -c"); + == "cl.exe /Yupch.h /Fppch.pch /FIpch.h /c"); } } @@ -859,7 +859,7 @@ TEST_CASE("MSVC PCH options with empty -Yc and without -Fp and -Fo") CHECK(ctx.args_info.included_pch_file == "pch.pch"); CHECK(ctx.args_info.output_obj == "pch.obj"); CHECK(result->preprocessor_args.to_string() == "cl.exe /Yc"); - CHECK(result->compiler_args.to_string() == "cl.exe /Yc -c"); + CHECK(result->compiler_args.to_string() == "cl.exe /Yc /c"); } util::write_file("pch.pch", ""); @@ -879,7 +879,7 @@ TEST_CASE("MSVC PCH options with empty -Yc and without -Fp and -Fo") CHECK(result->preprocessor_args.to_string() == "cl.exe /Yupch.h /Fppch.pch /FIpch.h"); CHECK(result->compiler_args.to_string() - == "cl.exe /Yupch.h /Fppch.pch /FIpch.h -c"); + == "cl.exe /Yupch.h /Fppch.pch /FIpch.h /c"); } } @@ -926,7 +926,7 @@ TEST_CASE("MSVC debug information format options") const auto result = process_args(ctx); REQUIRE(result); CHECK(result->preprocessor_args.to_string() == "cl.exe /Z7"); - CHECK(result->compiler_args.to_string() == "cl.exe /Z7 -c"); + CHECK(result->compiler_args.to_string() == "cl.exe /Z7 /c"); } SUBCASE("Only /Zi") @@ -956,7 +956,7 @@ TEST_CASE("MSVC debug information format options") const auto result = process_args(ctx); REQUIRE(result); CHECK(result->preprocessor_args.to_string() == "cl.exe /Zi /Z7"); - CHECK(result->compiler_args.to_string() == "cl.exe /Zi /Z7 -c"); + CHECK(result->compiler_args.to_string() == "cl.exe /Zi /Z7 /c"); } }