]>
Commit | Line | Data |
---|---|---|
00fe1341 | 1 | // Copyright (C) 2020-2023 Joel Rosdahl and other contributors |
756e03d1 JR |
2 | // |
3 | // See doc/AUTHORS.adoc for a complete list of contributors. | |
4 | // | |
5 | // This program is free software; you can redistribute it and/or modify it | |
6 | // under the terms of the GNU General Public License as published by the Free | |
7 | // Software Foundation; either version 3 of the License, or (at your option) | |
8 | // any later version. | |
9 | // | |
10 | // This program is distributed in the hope that it will be useful, but WITHOUT | |
11 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
13 | // more details. | |
14 | // | |
15 | // You should have received a copy of the GNU General Public License along with | |
16 | // this program; if not, write to the Free Software Foundation, Inc., 51 | |
17 | // Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
18 | ||
19 | #include "argprocessing.hpp" | |
20 | ||
21 | #include "Context.hpp" | |
22 | #include "compopt.hpp" | |
23 | #include "language.hpp" | |
756e03d1 | 24 | |
fec40553 | 25 | #include <Depfile.hpp> |
5e171ed8 | 26 | #include <Util.hpp> |
e4d64b4b | 27 | #include <util/assertions.hpp> |
7f77c031 | 28 | #include <util/filesystem.hpp> |
ef96a84a | 29 | #include <util/fmtmacros.hpp> |
13cb56cd | 30 | #include <util/logging.hpp> |
c86a4628 | 31 | #include <util/path.hpp> |
303c82fe | 32 | #include <util/string.hpp> |
7f034685 | 33 | #include <util/wincompat.hpp> |
ca9ec9cf JR |
34 | |
35 | #ifdef HAVE_UNISTD_H | |
36 | # include <unistd.h> | |
37 | #endif | |
38 | ||
d32b0012 | 39 | #include <cassert> |
7f77c031 | 40 | #include <vector> |
d32b0012 | 41 | |
7f77c031 | 42 | namespace fs = util::filesystem; |
c24446f5 | 43 | using core::Statistic; |
c86a4628 | 44 | using util::DirEntry; |
756e03d1 JR |
45 | |
46 | namespace { | |
47 | ||
8932157a | 48 | enum class ColorDiagnostics : int8_t { never, automatic, always }; |
1c6ccf18 | 49 | |
fec40553 JR |
50 | // The dependency target in the dependency file is taken from the highest |
51 | // priority source. | |
52 | enum class OutputDepOrigin : uint8_t { | |
53 | // Not set | |
54 | none = 0, | |
55 | // From -MF target | |
56 | mf = 1, | |
57 | // From -Wp,-MD,target or -Wp,-MMD,target | |
58 | wp = 2 | |
59 | }; | |
60 | ||
756e03d1 JR |
61 | struct ArgumentProcessingState |
62 | { | |
63 | bool found_c_opt = false; | |
64 | bool found_dc_opt = false; | |
65 | bool found_S_opt = false; | |
67da9633 | 66 | bool found_analyze_opt = false; |
756e03d1 JR |
67 | bool found_pch = false; |
68 | bool found_fpch_preprocess = false; | |
13fcafe3 OS |
69 | bool found_Yu = false; |
70 | bool found_valid_Fp = false; | |
5cfd4b9c | 71 | bool found_syntax_only = false; |
1c6ccf18 | 72 | ColorDiagnostics color_diagnostics = ColorDiagnostics::automatic; |
6e77c16a JR |
73 | bool found_directives_only = false; |
74 | bool found_rewrite_includes = false; | |
ab7dd6ff | 75 | std::unordered_map<std::string, std::vector<std::string>> xarch_args; |
fec40553 JR |
76 | bool found_mf_opt = false; |
77 | bool found_wp_md_or_mmd_opt = false; | |
78 | bool found_md_or_mmd_opt = false; | |
0d95687b | 79 | bool found_Wa_a_opt = false; |
6e77c16a | 80 | |
6ee19c33 JR |
81 | std::string explicit_language; // As specified with -x. |
82 | std::string input_charset_option; // -finput-charset=... | |
83 | std::string last_seen_msvc_z_debug_option; // /Z7, /Zi or /ZI | |
756e03d1 | 84 | |
fec40553 JR |
85 | // Is the dependency file set via -Wp,-M[M]D,target or -MFtarget? |
86 | OutputDepOrigin output_dep_origin = OutputDepOrigin::none; | |
756e03d1 JR |
87 | |
88 | // Is the compiler being asked to output debug info on level 3? | |
89 | bool generating_debuginfo_level_3 = false; | |
90 | ||
7f77c031 JR |
91 | // Arguments classified as input files. |
92 | std::vector<fs::path> input_files; | |
93 | ||
756e03d1 JR |
94 | // common_args contains all original arguments except: |
95 | // * those that never should be passed to the preprocessor, | |
96 | // * those that only should be passed to the preprocessor (if run_second_cpp | |
97 | // is false), and | |
98 | // * dependency options (like -MD and friends). | |
99 | Args common_args; | |
100 | ||
101 | // cpp_args contains arguments that were not added to common_args, i.e. those | |
102 | // that should only be passed to the preprocessor if run_second_cpp is false. | |
103 | // If run_second_cpp is true, they will be passed to the compiler as well. | |
104 | Args cpp_args; | |
105 | ||
106 | // dep_args contains dependency options like -MD. They are only passed to the | |
107 | // preprocessor, never to the compiler. | |
108 | Args dep_args; | |
109 | ||
110 | // compiler_only_args contains arguments that should only be passed to the | |
111 | // compiler, not the preprocessor. | |
112 | Args compiler_only_args; | |
50e8d229 JR |
113 | |
114 | // compiler_only_args_no_hash contains arguments that should only be passed to | |
115 | // the compiler, not the preprocessor, and that also should not be part of the | |
116 | // hash identifying the result. | |
117 | Args compiler_only_args_no_hash; | |
0492eb74 JR |
118 | |
119 | // Whether to include the full command line in the hash. | |
120 | bool hash_full_command_line = false; | |
195011ad JR |
121 | |
122 | // Whether to include the actual CWD in the hash. | |
123 | bool hash_actual_cwd = false; | |
756e03d1 JR |
124 | }; |
125 | ||
126 | bool | |
127 | color_output_possible() | |
128 | { | |
129 | const char* term_env = getenv("TERM"); | |
ca9ec9cf | 130 | return isatty(STDERR_FILENO) && term_env |
b8c704b7 | 131 | && util::to_lowercase(term_env) != "dumb"; |
756e03d1 JR |
132 | } |
133 | ||
134 | bool | |
e1260404 | 135 | detect_pch(const std::string& option, |
d32b0012 | 136 | const std::string& arg, |
e1260404 | 137 | std::string& included_pch_file, |
3ec58dbc | 138 | bool is_cc1_option, |
13fcafe3 | 139 | ArgumentProcessingState& state) |
756e03d1 JR |
140 | { |
141 | // Try to be smart about detecting precompiled headers. | |
3ec58dbc AH |
142 | // If the option is an option for Clang (is_cc1_option), don't accept |
143 | // anything just because it has a corresponding precompiled header, | |
144 | // because Clang doesn't behave that way either. | |
d32b0012 | 145 | std::string pch_file; |
13fcafe3 OS |
146 | if (option == "-Yu") { |
147 | state.found_Yu = true; | |
148 | if (state.found_valid_Fp) { // Use file set by -Fp. | |
149 | LOG("Detected use of precompiled header: {}", included_pch_file); | |
150 | pch_file = included_pch_file; | |
e8aef251 | 151 | included_pch_file.clear(); // reset pch file set from /Fp |
13fcafe3 OS |
152 | } else { |
153 | std::string file = Util::change_extension(arg, ".pch"); | |
c86a4628 | 154 | if (DirEntry(file).is_regular_file()) { |
13fcafe3 OS |
155 | LOG("Detected use of precompiled header: {}", file); |
156 | pch_file = file; | |
157 | } | |
158 | } | |
159 | } else if (option == "-Fp") { | |
160 | std::string file = arg; | |
161 | if (Util::get_extension(file).empty()) { | |
162 | file += ".pch"; | |
163 | } | |
c86a4628 | 164 | if (DirEntry(file).is_regular_file()) { |
13fcafe3 OS |
165 | state.found_valid_Fp = true; |
166 | if (!state.found_Yu) { | |
167 | LOG("Precompiled header file specified: {}", file); | |
168 | included_pch_file = file; // remember file | |
169 | return true; // -Fp does not turn on PCH | |
170 | } | |
171 | LOG("Detected use of precompiled header: {}", file); | |
172 | pch_file = file; | |
173 | included_pch_file.clear(); // reset pch file set from /Yu | |
174 | // continue and set as if the file was passed to -Yu | |
175 | } | |
176 | } else if (option == "-include-pch" || option == "-include-pth") { | |
c86a4628 | 177 | if (DirEntry(arg).is_regular_file()) { |
60904e7b | 178 | LOG("Detected use of precompiled header: {}", arg); |
d32b0012 | 179 | pch_file = arg; |
756e03d1 | 180 | } |
3ec58dbc | 181 | } else if (!is_cc1_option) { |
45100a84 JR |
182 | for (const auto& extension : {".gch", ".pch", ".pth"}) { |
183 | std::string path = arg + extension; | |
c86a4628 JR |
184 | DirEntry de(path); |
185 | if (de.is_regular_file() || de.is_directory()) { | |
60904e7b | 186 | LOG("Detected use of precompiled header: {}", path); |
45100a84 | 187 | pch_file = path; |
756e03d1 | 188 | } |
756e03d1 | 189 | } |
756e03d1 JR |
190 | } |
191 | ||
d32b0012 | 192 | if (!pch_file.empty()) { |
e1260404 | 193 | if (!included_pch_file.empty()) { |
60904e7b | 194 | LOG("Multiple precompiled headers used: {} and {}", |
e1260404 | 195 | included_pch_file, |
b8a69ab8 | 196 | pch_file); |
756e03d1 JR |
197 | return false; |
198 | } | |
e1260404 | 199 | included_pch_file = pch_file; |
13fcafe3 | 200 | state.found_pch = true; |
756e03d1 JR |
201 | } |
202 | return true; | |
203 | } | |
204 | ||
205 | bool | |
6cbd17cd JR |
206 | process_profiling_option(const Context& ctx, |
207 | ArgsInfo& args_info, | |
208 | const std::string& arg) | |
756e03d1 | 209 | { |
58895dcf JR |
210 | static const std::vector<std::string> known_simple_options = { |
211 | "-fprofile-correction", | |
212 | "-fprofile-reorder-functions", | |
213 | "-fprofile-sample-accurate", | |
214 | "-fprofile-values", | |
215 | }; | |
216 | ||
217 | if (std::find(known_simple_options.begin(), known_simple_options.end(), arg) | |
218 | != known_simple_options.end()) { | |
219 | return true; | |
220 | } | |
221 | ||
756e03d1 JR |
222 | std::string new_profile_path; |
223 | bool new_profile_use = false; | |
224 | ||
ec94a399 | 225 | if (util::starts_with(arg, "-fprofile-dir=")) { |
756e03d1 JR |
226 | new_profile_path = arg.substr(arg.find('=') + 1); |
227 | } else if (arg == "-fprofile-generate" || arg == "-fprofile-instr-generate") { | |
6cbd17cd | 228 | args_info.profile_generate = true; |
32c70852 | 229 | if (ctx.config.is_compiler_group_clang()) { |
756e03d1 JR |
230 | new_profile_path = "."; |
231 | } else { | |
232 | // GCC uses $PWD/$(basename $obj). | |
233 | new_profile_path = ctx.apparent_cwd; | |
234 | } | |
ec94a399 JR |
235 | } else if (util::starts_with(arg, "-fprofile-generate=") |
236 | || util::starts_with(arg, "-fprofile-instr-generate=")) { | |
6cbd17cd | 237 | args_info.profile_generate = true; |
756e03d1 JR |
238 | new_profile_path = arg.substr(arg.find('=') + 1); |
239 | } else if (arg == "-fprofile-use" || arg == "-fprofile-instr-use" | |
4b1b7d4b OL |
240 | || arg == "-fprofile-sample-use" || arg == "-fbranch-probabilities" |
241 | || arg == "-fauto-profile") { | |
756e03d1 | 242 | new_profile_use = true; |
6cbd17cd | 243 | if (args_info.profile_path.empty()) { |
756e03d1 JR |
244 | new_profile_path = "."; |
245 | } | |
ec94a399 JR |
246 | } else if (util::starts_with(arg, "-fprofile-use=") |
247 | || util::starts_with(arg, "-fprofile-instr-use=") | |
248 | || util::starts_with(arg, "-fprofile-sample-use=") | |
249 | || util::starts_with(arg, "-fauto-profile=")) { | |
756e03d1 JR |
250 | new_profile_use = true; |
251 | new_profile_path = arg.substr(arg.find('=') + 1); | |
252 | } else { | |
60904e7b | 253 | LOG("Unknown profiling option: {}", arg); |
756e03d1 JR |
254 | return false; |
255 | } | |
256 | ||
257 | if (new_profile_use) { | |
6cbd17cd | 258 | if (args_info.profile_use) { |
60904e7b | 259 | LOG_RAW("Multiple profiling options not supported"); |
756e03d1 JR |
260 | return false; |
261 | } | |
6cbd17cd | 262 | args_info.profile_use = true; |
756e03d1 JR |
263 | } |
264 | ||
265 | if (!new_profile_path.empty()) { | |
6cbd17cd JR |
266 | args_info.profile_path = new_profile_path; |
267 | LOG("Set profile directory to {}", args_info.profile_path); | |
756e03d1 JR |
268 | } |
269 | ||
6cbd17cd | 270 | if (args_info.profile_generate && args_info.profile_use) { |
756e03d1 | 271 | // Too hard to figure out what the compiler will do. |
60904e7b | 272 | LOG_RAW("Both generating and using profile info, giving up"); |
756e03d1 JR |
273 | return false; |
274 | } | |
275 | ||
276 | return true; | |
277 | } | |
278 | ||
3781f256 JR |
279 | std::string |
280 | make_dash_option(const Config& config, const std::string& arg) | |
281 | { | |
282 | std::string new_arg = arg; | |
d45a5588 | 283 | if (config.is_compiler_group_msvc() && util::starts_with(arg, "/")) { |
3781f256 JR |
284 | // MSVC understands both /option and -option, so convert all /option to |
285 | // -option to simplify our handling. | |
286 | new_arg[0] = '-'; | |
287 | } | |
288 | return new_arg; | |
289 | } | |
290 | ||
6ee19c33 JR |
291 | bool |
292 | is_msvc_z_debug_option(std::string_view arg) | |
293 | { | |
294 | static const char* debug_options[] = {"-Z7", "-ZI", "-Zi"}; | |
295 | return std::find(std::begin(debug_options), std::end(debug_options), arg) | |
296 | != std::end(debug_options); | |
297 | } | |
298 | ||
62f3217e JR |
299 | // Returns std::nullopt if the option wasn't recognized, otherwise the error |
300 | // code (with Statistic::none for "no error"). | |
eea89d4a | 301 | std::optional<Statistic> |
62f3217e JR |
302 | process_option_arg(const Context& ctx, |
303 | ArgsInfo& args_info, | |
304 | Config& config, | |
305 | Args& args, | |
306 | size_t& args_index, | |
307 | ArgumentProcessingState& state) | |
756e03d1 | 308 | { |
756e03d1 | 309 | size_t& i = args_index; |
2737d79e JR |
310 | |
311 | if (option_should_be_ignored(args[i], ctx.ignore_options())) { | |
312 | LOG("Not processing ignored option: {}", args[i]); | |
313 | state.common_args.push_back(args[i]); | |
314 | return Statistic::none; | |
315 | } | |
316 | ||
f441bc13 | 317 | if (args[i] == "--ccache-skip") { |
756e03d1 | 318 | i++; |
f441bc13 | 319 | if (i == args.size()) { |
60904e7b | 320 | LOG_RAW("--ccache-skip lacks an argument"); |
c0248cf7 | 321 | return Statistic::bad_compiler_arguments; |
756e03d1 | 322 | } |
f441bc13 | 323 | state.common_args.push_back(args[i]); |
62f3217e | 324 | return Statistic::none; |
756e03d1 JR |
325 | } |
326 | ||
3781f256 JR |
327 | // arg should only be used when detecting options. It should not be added to |
328 | // state.*_args since it's potentially != args[i]. | |
329 | std::string arg = make_dash_option(ctx.config, args[i]); | |
330 | ||
331 | // Exit early if we notice a non-option argument right away. | |
d45a5588 | 332 | if (arg.empty() || (arg[0] != '-' && arg[0] != '@')) { |
3781f256 | 333 | return std::nullopt; |
0a644e6e LL |
334 | } |
335 | ||
3781f256 | 336 | if (arg == "-ivfsoverlay" |
03023ee7 | 337 | && !(config.sloppiness().contains(core::Sloppy::ivfsoverlay))) { |
97f42b96 YN |
338 | LOG_RAW( |
339 | "You have to specify \"ivfsoverlay\" sloppiness when using" | |
340 | " -ivfsoverlay to get hits"); | |
930d3b67 | 341 | ++i; |
97f42b96 YN |
342 | return Statistic::unsupported_compiler_option; |
343 | } | |
344 | ||
756e03d1 | 345 | // Special case for -E. |
3781f256 | 346 | if (arg == "-E") { |
0a644e6e LL |
347 | return Statistic::called_for_preprocessing; |
348 | } | |
349 | // MSVC -P is -E with output to a file. | |
3781f256 | 350 | if (arg == "-P" && ctx.config.is_compiler_group_msvc()) { |
c0248cf7 | 351 | return Statistic::called_for_preprocessing; |
756e03d1 JR |
352 | } |
353 | ||
354 | // Handle "@file" argument. | |
3781f256 JR |
355 | if (util::starts_with(arg, "@") || util::starts_with(arg, "-@")) { |
356 | const char* argpath = arg.c_str() + 1; | |
756e03d1 JR |
357 | |
358 | if (argpath[-1] == '-') { | |
359 | ++argpath; | |
360 | } | |
80ba758c JR |
361 | auto file_args = Args::from_atfile(argpath, |
362 | config.is_compiler_group_msvc() | |
363 | ? Args::AtFileFormat::msvc | |
364 | : Args::AtFileFormat::gcc); | |
756e03d1 | 365 | if (!file_args) { |
60904e7b | 366 | LOG("Couldn't read arg file {}", argpath); |
c0248cf7 | 367 | return Statistic::bad_compiler_arguments; |
756e03d1 JR |
368 | } |
369 | ||
f441bc13 | 370 | args.replace(i, *file_args); |
756e03d1 | 371 | i--; |
62f3217e | 372 | return Statistic::none; |
756e03d1 JR |
373 | } |
374 | ||
375 | // Handle cuda "-optf" and "--options-file" argument. | |
e2ab1352 | 376 | if (config.compiler_type() == CompilerType::nvcc |
3781f256 | 377 | && (arg == "-optf" || arg == "--options-file")) { |
c88ead97 | 378 | if (i == args.size() - 1) { |
60904e7b | 379 | LOG("Expected argument after {}", args[i]); |
c0248cf7 | 380 | return Statistic::bad_compiler_arguments; |
756e03d1 JR |
381 | } |
382 | ++i; | |
383 | ||
384 | // Argument is a comma-separated list of files. | |
32970d78 | 385 | auto paths = util::split_into_strings(args[i], ","); |
c88ead97 | 386 | for (auto it = paths.rbegin(); it != paths.rend(); ++it) { |
56c18b0d | 387 | auto file_args = Args::from_atfile(*it); |
756e03d1 | 388 | if (!file_args) { |
60904e7b | 389 | LOG("Couldn't read CUDA options file {}", *it); |
c0248cf7 | 390 | return Statistic::bad_compiler_arguments; |
756e03d1 JR |
391 | } |
392 | ||
c88ead97 | 393 | args.insert(i + 1, *file_args); |
756e03d1 JR |
394 | } |
395 | ||
62f3217e | 396 | return Statistic::none; |
756e03d1 JR |
397 | } |
398 | ||
399 | // These are always too hard. | |
3781f256 | 400 | if (compopt_too_hard(arg) || util::starts_with(arg, "-fdump-") |
27043359 JR |
401 | || util::starts_with(arg, "-MJ") || util::starts_with(arg, "-Yc") |
402 | || util::starts_with(arg, "--config-system-dir=") | |
403 | || util::starts_with(arg, "--config-user-dir=")) { | |
60904e7b | 404 | LOG("Compiler option {} is unsupported", args[i]); |
c0248cf7 | 405 | return Statistic::unsupported_compiler_option; |
756e03d1 JR |
406 | } |
407 | ||
408 | // These are too hard in direct mode. | |
3781f256 | 409 | if (config.direct_mode() && compopt_too_hard_for_direct_mode(arg)) { |
60904e7b | 410 | LOG("Unsupported compiler option for direct mode: {}", args[i]); |
756e03d1 JR |
411 | config.set_direct_mode(false); |
412 | } | |
413 | ||
36e914f8 | 414 | // Handle -Xarch_* options. |
3781f256 | 415 | if (util::starts_with(arg, "-Xarch_")) { |
b9a810af JR |
416 | if (i == args.size() - 1) { |
417 | LOG("Missing argument to {}", args[i]); | |
418 | return Statistic::bad_compiler_arguments; | |
419 | } | |
3781f256 | 420 | const auto arch = arg.substr(7); |
36e914f8 | 421 | auto it = state.xarch_args.emplace(arch, std::vector<std::string>()).first; |
ab7dd6ff TN |
422 | it->second.emplace_back(args[i + 1]); |
423 | ++i; | |
62f3217e | 424 | return Statistic::none; |
756e03d1 JR |
425 | } |
426 | ||
427 | // Handle -arch options. | |
3781f256 | 428 | if (arg == "-arch") { |
756e03d1 | 429 | ++i; |
4cf3d79f | 430 | args_info.arch_args.emplace_back(args[i]); |
7ca8fd6c | 431 | if (args_info.arch_args.size() == 2) { |
756e03d1 JR |
432 | config.set_run_second_cpp(true); |
433 | } | |
62f3217e | 434 | return Statistic::none; |
756e03d1 JR |
435 | } |
436 | ||
3ec58dbc AH |
437 | // Some arguments that clang passes directly to cc1 (related to precompiled |
438 | // headers) need the usual ccache handling. In those cases, the -Xclang | |
439 | // prefix is skipped and the cc1 argument is handled instead. | |
3781f256 | 440 | if (arg == "-Xclang" && i + 1 < args.size() |
3ec58dbc AH |
441 | && (args[i + 1] == "-emit-pch" || args[i + 1] == "-emit-pth" |
442 | || args[i + 1] == "-include-pch" || args[i + 1] == "-include-pth" | |
d31ab958 | 443 | || args[i + 1] == "-include" || args[i + 1] == "--include" |
3ec58dbc | 444 | || args[i + 1] == "-fno-pch-timestamp")) { |
27f00db4 | 445 | if (compopt_affects_compiler_output(args[i + 1])) { |
3ec58dbc | 446 | state.compiler_only_args.push_back(args[i]); |
27f00db4 | 447 | } else if (compopt_affects_cpp_output(args[i + 1])) { |
3ec58dbc AH |
448 | state.cpp_args.push_back(args[i]); |
449 | } else { | |
450 | state.common_args.push_back(args[i]); | |
451 | } | |
452 | ++i; | |
3781f256 | 453 | arg = make_dash_option(ctx.config, args[i]); |
3ec58dbc AH |
454 | } |
455 | ||
3781f256 JR |
456 | if (util::starts_with(arg, "-Wa,")) { |
457 | for (const auto part : util::Tokenizer(&arg[4], ",")) { | |
b4dfd7b5 | 458 | if (util::starts_with(part, "-a")) { |
0d95687b | 459 | if (state.found_Wa_a_opt) { |
b4dfd7b5 JR |
460 | LOG_RAW( |
461 | "Multiple assembler listing options (-Wa,-a) are not supported"); | |
462 | return Statistic::unsupported_compiler_option; | |
463 | } | |
0d95687b | 464 | state.found_Wa_a_opt = true; |
b4dfd7b5 JR |
465 | |
466 | const auto eq_pos = part.find('='); | |
467 | if (eq_pos != std::string_view::npos) { | |
468 | args_info.output_al = part.substr(eq_pos + 1); | |
469 | } | |
470 | } | |
471 | } | |
b36a8189 JR |
472 | } |
473 | ||
756e03d1 | 474 | // Handle options that should not be passed to the preprocessor. |
78b2ed08 JR |
475 | if (compopt_affects_compiler_output(arg) |
476 | || (i + 1 < args.size() && arg == "-Xclang" | |
477 | && compopt_affects_compiler_output(args[i + 1]))) { | |
478 | if (i + 1 < args.size() && arg == "-Xclang") { | |
479 | state.compiler_only_args.push_back(args[i]); | |
480 | ++i; | |
481 | arg = make_dash_option(ctx.config, args[i]); | |
482 | } | |
4cf3d79f | 483 | state.compiler_only_args.push_back(args[i]); |
78b2ed08 JR |
484 | // Note: "-Xclang -option-that-takes-arg -Xclang arg" is not handled below |
485 | // yet. | |
3781f256 JR |
486 | if (compopt_takes_arg(arg) |
487 | || (config.compiler_type() == CompilerType::nvcc && arg == "-Werror")) { | |
4cf3d79f | 488 | if (i == args.size() - 1) { |
60904e7b | 489 | LOG("Missing argument to {}", args[i]); |
c0248cf7 | 490 | return Statistic::bad_compiler_arguments; |
756e03d1 | 491 | } |
4cf3d79f | 492 | state.compiler_only_args.push_back(args[i + 1]); |
756e03d1 JR |
493 | ++i; |
494 | } | |
62f3217e | 495 | return Statistic::none; |
756e03d1 | 496 | } |
78b2ed08 JR |
497 | if (compopt_prefix_affects_compiler_output(arg) |
498 | || (i + 1 < args.size() && arg == "-Xclang" | |
499 | && compopt_prefix_affects_compiler_output(args[i + 1]))) { | |
500 | if (i + 1 < args.size() && arg == "-Xclang") { | |
501 | state.compiler_only_args.push_back(args[i]); | |
502 | ++i; | |
503 | } | |
4cf3d79f | 504 | state.compiler_only_args.push_back(args[i]); |
62f3217e | 505 | return Statistic::none; |
756e03d1 JR |
506 | } |
507 | ||
4cf3d79f JR |
508 | // Modules are handled on demand as necessary in the background, so there is |
509 | // no need to cache them, they can in practice be ignored. All that is needed | |
510 | // is to correctly depend also on module.modulemap files, and those are | |
511 | // included only in depend mode (preprocessed output does not list them). | |
512 | // Still, not including the modules themselves in the hash could possibly | |
513 | // result in an object file that would be different from the actual | |
514 | // compilation (even though it should be compatible), so require a sloppiness | |
515 | // flag. | |
3781f256 | 516 | if (arg == "-fmodules") { |
756e03d1 | 517 | if (!config.depend_mode() || !config.direct_mode()) { |
60904e7b | 518 | LOG("Compiler option {} is unsupported without direct depend mode", |
b8a69ab8 | 519 | args[i]); |
c0248cf7 | 520 | return Statistic::could_not_use_modules; |
03023ee7 | 521 | } else if (!(config.sloppiness().contains(core::Sloppy::modules))) { |
60904e7b | 522 | LOG_RAW( |
756e03d1 JR |
523 | "You have to specify \"modules\" sloppiness when using" |
524 | " -fmodules to get hits"); | |
c0248cf7 | 525 | return Statistic::could_not_use_modules; |
756e03d1 JR |
526 | } |
527 | } | |
528 | ||
529 | // We must have -c. | |
3781f256 | 530 | if (arg == "-c") { |
756e03d1 | 531 | state.found_c_opt = true; |
62f3217e | 532 | return Statistic::none; |
756e03d1 JR |
533 | } |
534 | ||
0a644e6e | 535 | // MSVC -Fo with no space. |
3781f256 JR |
536 | if (util::starts_with(arg, "-Fo") && config.is_compiler_group_msvc()) { |
537 | args_info.output_obj = arg.substr(3); | |
62f3217e | 538 | return Statistic::none; |
56c18b0d CA |
539 | } |
540 | ||
756e03d1 | 541 | // when using nvcc with separable compilation, -dc implies -c |
3781f256 | 542 | if ((arg == "-dc" || arg == "--device-c") |
e2ab1352 | 543 | && config.compiler_type() == CompilerType::nvcc) { |
756e03d1 | 544 | state.found_dc_opt = true; |
62f3217e | 545 | return Statistic::none; |
756e03d1 JR |
546 | } |
547 | ||
548 | // -S changes the default extension. | |
3781f256 | 549 | if (arg == "-S") { |
4cf3d79f | 550 | state.common_args.push_back(args[i]); |
756e03d1 | 551 | state.found_S_opt = true; |
62f3217e | 552 | return Statistic::none; |
756e03d1 JR |
553 | } |
554 | ||
67da9633 M |
555 | // --analyze changes the default extension too |
556 | if (arg == "--analyze") { | |
557 | state.common_args.push_back(args[i]); | |
558 | state.found_analyze_opt = true; | |
559 | return Statistic::none; | |
560 | } | |
561 | ||
3781f256 JR |
562 | if (util::starts_with(arg, "-x")) { |
563 | if (arg.length() >= 3 && !islower(arg[2])) { | |
841593b6 AL |
564 | // -xCODE (where CODE can be e.g. Host or CORE-AVX2, always starting with |
565 | // an uppercase letter) is an ordinary Intel compiler option, not a | |
566 | // language specification. (GCC's "-x" language argument is always | |
567 | // lowercase.) | |
568 | state.common_args.push_back(args[i]); | |
62f3217e | 569 | return Statistic::none; |
756e03d1 | 570 | } |
841593b6 AL |
571 | |
572 | // Special handling for -x: remember the last specified language before the | |
573 | // input file and strip all -x options from the arguments. | |
3781f256 | 574 | if (arg.length() == 2) { |
841593b6 | 575 | if (i == args.size() - 1) { |
60904e7b | 576 | LOG("Missing argument to {}", args[i]); |
841593b6 AL |
577 | return Statistic::bad_compiler_arguments; |
578 | } | |
7f77c031 | 579 | if (state.input_files.empty()) { |
841593b6 AL |
580 | state.explicit_language = args[i + 1]; |
581 | } | |
582 | i++; | |
62f3217e | 583 | return Statistic::none; |
756e03d1 | 584 | } |
b2c18fa6 | 585 | |
3781f256 | 586 | DEBUG_ASSERT(arg.length() >= 3); |
7f77c031 | 587 | if (state.input_files.empty()) { |
3781f256 | 588 | state.explicit_language = arg.substr(2); |
756e03d1 | 589 | } |
62f3217e | 590 | return Statistic::none; |
756e03d1 JR |
591 | } |
592 | ||
593 | // We need to work out where the output was meant to go. | |
3781f256 | 594 | if (arg == "-o") { |
4cf3d79f | 595 | if (i == args.size() - 1) { |
60904e7b | 596 | LOG("Missing argument to {}", args[i]); |
c0248cf7 | 597 | return Statistic::bad_compiler_arguments; |
756e03d1 | 598 | } |
fec40553 | 599 | args_info.output_obj = args[i + 1]; |
756e03d1 | 600 | i++; |
62f3217e | 601 | return Statistic::none; |
756e03d1 JR |
602 | } |
603 | ||
604 | // Alternate form of -o with no space. Nvcc does not support this. | |
b02c0012 OS |
605 | // Cl does support it as deprecated, but also has -openmp or -link -out |
606 | // which can confuse this and cause incorrect output_obj (and thus | |
607 | // ccache debug file location), so better ignore it. | |
3781f256 | 608 | if (util::starts_with(arg, "-o") |
b02c0012 OS |
609 | && config.compiler_type() != CompilerType::nvcc |
610 | && config.compiler_type() != CompilerType::msvc) { | |
3781f256 | 611 | args_info.output_obj = arg.substr(2); |
62f3217e | 612 | return Statistic::none; |
756e03d1 JR |
613 | } |
614 | ||
3781f256 JR |
615 | if (util::starts_with(arg, "-fdebug-prefix-map=") |
616 | || util::starts_with(arg, "-ffile-prefix-map=")) { | |
617 | std::string map = arg.substr(arg.find('=') + 1); | |
0d805579 JR |
618 | args_info.debug_prefix_maps.push_back(map); |
619 | state.common_args.push_back(args[i]); | |
62f3217e | 620 | return Statistic::none; |
756e03d1 JR |
621 | } |
622 | ||
623 | // Debugging is handled specially, so that we know if we can strip line | |
624 | // number info. | |
3781f256 | 625 | if (util::starts_with(arg, "-g")) { |
4cf3d79f | 626 | state.common_args.push_back(args[i]); |
756e03d1 | 627 | |
3781f256 | 628 | if (util::starts_with(arg, "-gdwarf")) { |
756e03d1 JR |
629 | // Selection of DWARF format (-gdwarf or -gdwarf-<version>) enables |
630 | // debug info on level 2. | |
631 | args_info.generating_debuginfo = true; | |
62f3217e | 632 | return Statistic::none; |
756e03d1 JR |
633 | } |
634 | ||
3781f256 | 635 | if (util::starts_with(arg, "-gz")) { |
756e03d1 | 636 | // -gz[=type] neither disables nor enables debug info. |
62f3217e | 637 | return Statistic::none; |
756e03d1 JR |
638 | } |
639 | ||
3781f256 | 640 | char last_char = arg.back(); |
756e03d1 JR |
641 | if (last_char == '0') { |
642 | // "-g0", "-ggdb0" or similar: All debug information disabled. | |
643 | args_info.generating_debuginfo = false; | |
644 | state.generating_debuginfo_level_3 = false; | |
645 | } else { | |
646 | args_info.generating_debuginfo = true; | |
647 | if (last_char == '3') { | |
648 | state.generating_debuginfo_level_3 = true; | |
649 | } | |
3781f256 | 650 | if (arg == "-gsplit-dwarf") { |
756e03d1 JR |
651 | args_info.seen_split_dwarf = true; |
652 | } | |
653 | } | |
62f3217e | 654 | return Statistic::none; |
756e03d1 JR |
655 | } |
656 | ||
e9d33e4f | 657 | if (config.is_compiler_group_msvc() && !config.is_compiler_group_clang() |
6ee19c33 JR |
658 | && is_msvc_z_debug_option(arg)) { |
659 | state.last_seen_msvc_z_debug_option = args[i]; | |
660 | state.common_args.push_back(args[i]); | |
661 | return Statistic::none; | |
d099c180 JR |
662 | } |
663 | ||
908ca1e2 HQJ |
664 | if (config.is_compiler_group_msvc() && util::starts_with(arg, "-Fd")) { |
665 | state.compiler_only_args_no_hash.push_back(args[i]); | |
666 | return Statistic::none; | |
667 | } | |
668 | ||
669 | if (config.is_compiler_group_msvc() | |
670 | && (util::starts_with(arg, "-MP") || arg == "-FS")) { | |
671 | state.compiler_only_args_no_hash.push_back(args[i]); | |
672 | return Statistic::none; | |
673 | } | |
674 | ||
756e03d1 JR |
675 | // These options require special handling, because they behave differently |
676 | // with gcc -E, when the output file is not specified. | |
3781f256 | 677 | if ((arg == "-MD" || arg == "-MMD") && !config.is_compiler_group_msvc()) { |
fec40553 | 678 | state.found_md_or_mmd_opt = true; |
756e03d1 | 679 | args_info.generating_dependencies = true; |
4cf3d79f | 680 | state.dep_args.push_back(args[i]); |
62f3217e | 681 | return Statistic::none; |
756e03d1 | 682 | } |
4cf3d79f | 683 | |
3781f256 | 684 | if (util::starts_with(arg, "-MF")) { |
fec40553 | 685 | state.found_mf_opt = true; |
756e03d1 | 686 | |
4cf3d79f | 687 | std::string dep_file; |
3781f256 | 688 | bool separate_argument = (arg.size() == 3); |
756e03d1 JR |
689 | if (separate_argument) { |
690 | // -MF arg | |
4cf3d79f | 691 | if (i == args.size() - 1) { |
60904e7b | 692 | LOG("Missing argument to {}", args[i]); |
c0248cf7 | 693 | return Statistic::bad_compiler_arguments; |
756e03d1 | 694 | } |
4cf3d79f | 695 | dep_file = args[i + 1]; |
756e03d1 JR |
696 | i++; |
697 | } else { | |
698 | // -MFarg or -MF=arg (EDG-based compilers) | |
3781f256 | 699 | dep_file = arg.substr(arg[3] == '=' ? 4 : 3); |
756e03d1 | 700 | } |
fec40553 JR |
701 | |
702 | if (state.output_dep_origin <= OutputDepOrigin::mf) { | |
703 | state.output_dep_origin = OutputDepOrigin::mf; | |
704 | args_info.output_dep = Util::make_relative_path(ctx, dep_file); | |
705 | } | |
756e03d1 JR |
706 | // Keep the format of the args the same. |
707 | if (separate_argument) { | |
4cf3d79f | 708 | state.dep_args.push_back("-MF"); |
756e03d1 JR |
709 | state.dep_args.push_back(args_info.output_dep); |
710 | } else { | |
4cf3d79f | 711 | state.dep_args.push_back("-MF" + args_info.output_dep); |
756e03d1 | 712 | } |
62f3217e | 713 | return Statistic::none; |
756e03d1 | 714 | } |
4cf3d79f | 715 | |
3781f256 | 716 | if ((util::starts_with(arg, "-MQ") || util::starts_with(arg, "-MT")) |
caa5bcbb | 717 | && !config.is_compiler_group_msvc()) { |
3781f256 | 718 | const bool is_mq = arg[2] == 'Q'; |
756e03d1 | 719 | |
fec40553 | 720 | std::string_view dep_target; |
3781f256 | 721 | if (arg.size() == 3) { |
756e03d1 | 722 | // -MQ arg or -MT arg |
4cf3d79f | 723 | if (i == args.size() - 1) { |
60904e7b | 724 | LOG("Missing argument to {}", args[i]); |
c0248cf7 | 725 | return Statistic::bad_compiler_arguments; |
756e03d1 | 726 | } |
4cf3d79f | 727 | state.dep_args.push_back(args[i]); |
fec40553 JR |
728 | state.dep_args.push_back(args[i + 1]); |
729 | dep_target = args[i + 1]; | |
756e03d1 JR |
730 | i++; |
731 | } else { | |
fec40553 | 732 | // -MQarg or -MTarg |
3781f256 | 733 | const std::string_view arg_view(arg); |
fec40553 JR |
734 | const auto arg_opt = arg_view.substr(0, 3); |
735 | dep_target = arg_view.substr(3); | |
736 | state.dep_args.push_back(FMT("{}{}", arg_opt, dep_target)); | |
756e03d1 | 737 | } |
fec40553 JR |
738 | |
739 | if (args_info.dependency_target) { | |
740 | args_info.dependency_target->push_back(' '); | |
741 | } else { | |
742 | args_info.dependency_target = ""; | |
743 | } | |
744 | *args_info.dependency_target += | |
745 | is_mq ? Depfile::escape_filename(dep_target) : dep_target; | |
746 | ||
62f3217e | 747 | return Statistic::none; |
756e03d1 | 748 | } |
4cf3d79f | 749 | |
b6e841c0 LL |
750 | // MSVC -MD[d], -MT[d] and -LT[d] options are something different than GCC's |
751 | // -MD etc. | |
caa5bcbb | 752 | if (config.is_compiler_group_msvc() |
3781f256 JR |
753 | && (util::starts_with(arg, "-MD") || util::starts_with(arg, "-MT") |
754 | || util::starts_with(arg, "-LD"))) { | |
b6e841c0 LL |
755 | // These affect compiler but also #define some things. |
756 | state.cpp_args.push_back(args[i]); | |
757 | state.common_args.push_back(args[i]); | |
62f3217e | 758 | return Statistic::none; |
b6e841c0 LL |
759 | } |
760 | ||
3781f256 | 761 | if (arg == "-showIncludes") { |
b1348e5f OS |
762 | args_info.generating_includes = true; |
763 | state.dep_args.push_back(args[i]); | |
764 | return Statistic::none; | |
765 | } | |
766 | ||
3781f256 | 767 | if (arg == "-fprofile-arcs") { |
756e03d1 | 768 | args_info.profile_arcs = true; |
6cb3973a | 769 | state.common_args.push_back(args[i]); |
62f3217e | 770 | return Statistic::none; |
756e03d1 | 771 | } |
6cb3973a | 772 | |
3781f256 | 773 | if (arg == "-ftest-coverage") { |
756e03d1 | 774 | args_info.generating_coverage = true; |
6cb3973a | 775 | state.common_args.push_back(args[i]); |
62f3217e | 776 | return Statistic::none; |
756e03d1 | 777 | } |
6cb3973a | 778 | |
3781f256 | 779 | if (arg == "-fstack-usage") { |
756e03d1 | 780 | args_info.generating_stackusage = true; |
6cb3973a | 781 | state.common_args.push_back(args[i]); |
62f3217e | 782 | return Statistic::none; |
756e03d1 | 783 | } |
6cb3973a | 784 | |
5cfd4b9c | 785 | // -Zs is MSVC's -fsyntax-only equivalent |
3781f256 | 786 | if (arg == "-fsyntax-only" || arg == "-Zs") { |
f258b70e AL |
787 | args_info.expect_output_obj = false; |
788 | state.compiler_only_args.push_back(args[i]); | |
5cfd4b9c | 789 | state.found_syntax_only = true; |
62f3217e | 790 | return Statistic::none; |
f258b70e AL |
791 | } |
792 | ||
3781f256 JR |
793 | if (arg == "--coverage" // = -fprofile-arcs -ftest-coverage |
794 | || arg == "-coverage") { // Undocumented but still works. | |
756e03d1 JR |
795 | args_info.profile_arcs = true; |
796 | args_info.generating_coverage = true; | |
6cb3973a | 797 | state.common_args.push_back(args[i]); |
62f3217e | 798 | return Statistic::none; |
756e03d1 | 799 | } |
6cb3973a | 800 | |
3781f256 | 801 | if (arg == "-fprofile-abs-path") { |
03023ee7 | 802 | if (!config.sloppiness().contains(core::Sloppy::gcno_cwd)) { |
195011ad JR |
803 | // -fprofile-abs-path makes the compiler include absolute paths based on |
804 | // the actual CWD in the .gcno file. | |
805 | state.hash_actual_cwd = true; | |
806 | } | |
807 | return Statistic::none; | |
808 | } | |
809 | ||
3781f256 JR |
810 | if (util::starts_with(arg, "-fprofile-") |
811 | || util::starts_with(arg, "-fauto-profile") | |
812 | || arg == "-fbranch-probabilities") { | |
813 | if (!process_profiling_option(ctx, args_info, arg)) { | |
756e03d1 | 814 | // The failure is logged by process_profiling_option. |
c0248cf7 | 815 | return Statistic::unsupported_compiler_option; |
756e03d1 | 816 | } |
6cb3973a | 817 | state.common_args.push_back(args[i]); |
62f3217e | 818 | return Statistic::none; |
756e03d1 | 819 | } |
6cb3973a | 820 | |
3781f256 | 821 | if (util::starts_with(arg, "-fsanitize-blacklist=")) { |
6cb3973a JR |
822 | args_info.sanitize_blacklists.emplace_back(args[i].substr(21)); |
823 | state.common_args.push_back(args[i]); | |
62f3217e | 824 | return Statistic::none; |
756e03d1 | 825 | } |
6cb3973a | 826 | |
3781f256 JR |
827 | if (util::starts_with(arg, "--sysroot=")) { |
828 | auto path = std::string_view(arg).substr(10); | |
6cb3973a JR |
829 | auto relpath = Util::make_relative_path(ctx, path); |
830 | state.common_args.push_back("--sysroot=" + relpath); | |
62f3217e | 831 | return Statistic::none; |
756e03d1 | 832 | } |
6cb3973a | 833 | |
756e03d1 | 834 | // Alternate form of specifying sysroot without = |
3781f256 | 835 | if (arg == "--sysroot") { |
6cb3973a | 836 | if (i == args.size() - 1) { |
60904e7b | 837 | LOG("Missing argument to {}", args[i]); |
c0248cf7 | 838 | return Statistic::bad_compiler_arguments; |
756e03d1 | 839 | } |
6cb3973a JR |
840 | state.common_args.push_back(args[i]); |
841 | auto relpath = Util::make_relative_path(ctx, args[i + 1]); | |
756e03d1 JR |
842 | state.common_args.push_back(relpath); |
843 | i++; | |
62f3217e | 844 | return Statistic::none; |
756e03d1 | 845 | } |
6cb3973a | 846 | |
756e03d1 | 847 | // Alternate form of specifying target without = |
3781f256 | 848 | if (arg == "-target") { |
6cb3973a | 849 | if (i == args.size() - 1) { |
60904e7b | 850 | LOG("Missing argument to {}", args[i]); |
c0248cf7 | 851 | return Statistic::bad_compiler_arguments; |
756e03d1 | 852 | } |
6cb3973a JR |
853 | state.common_args.push_back(args[i]); |
854 | state.common_args.push_back(args[i + 1]); | |
756e03d1 | 855 | i++; |
62f3217e | 856 | return Statistic::none; |
756e03d1 | 857 | } |
6cb3973a | 858 | |
3781f256 | 859 | if (arg == "-P" || arg == "-Wp,-P") { |
0b9c3a2d JR |
860 | // Avoid passing -P to the preprocessor since it removes preprocessor |
861 | // information we need. | |
862 | state.compiler_only_args.push_back(args[i]); | |
863 | LOG("{} used; not compiling preprocessed code", args[i]); | |
864 | config.set_run_second_cpp(true); | |
62f3217e | 865 | return Statistic::none; |
0b9c3a2d JR |
866 | } |
867 | ||
3781f256 JR |
868 | if (util::starts_with(arg, "-Wp,")) { |
869 | if (arg.find(",-P,") != std::string::npos || util::ends_with(arg, ",-P")) { | |
1ae1ae2b JR |
870 | LOG("-P together with other preprocessor options is too hard: {}", |
871 | args[i]); | |
c0248cf7 | 872 | return Statistic::unsupported_compiler_option; |
3781f256 JR |
873 | } else if (util::starts_with(arg, "-Wp,-MD,") |
874 | && arg.find(',', 8) == std::string::npos) { | |
fec40553 | 875 | state.found_wp_md_or_mmd_opt = true; |
756e03d1 | 876 | args_info.generating_dependencies = true; |
fec40553 JR |
877 | if (state.output_dep_origin <= OutputDepOrigin::wp) { |
878 | state.output_dep_origin = OutputDepOrigin::wp; | |
3781f256 | 879 | args_info.output_dep = arg.substr(8); |
fec40553 | 880 | } |
6cb3973a | 881 | state.dep_args.push_back(args[i]); |
62f3217e | 882 | return Statistic::none; |
3781f256 JR |
883 | } else if (util::starts_with(arg, "-Wp,-MMD,") |
884 | && arg.find(',', 9) == std::string::npos) { | |
fec40553 | 885 | state.found_wp_md_or_mmd_opt = true; |
756e03d1 | 886 | args_info.generating_dependencies = true; |
fec40553 JR |
887 | if (state.output_dep_origin <= OutputDepOrigin::wp) { |
888 | state.output_dep_origin = OutputDepOrigin::wp; | |
3781f256 | 889 | args_info.output_dep = arg.substr(9); |
fec40553 | 890 | } |
6cb3973a | 891 | state.dep_args.push_back(args[i]); |
62f3217e | 892 | return Statistic::none; |
3781f256 JR |
893 | } else if ((util::starts_with(arg, "-Wp,-D") |
894 | || util::starts_with(arg, "-Wp,-U")) | |
895 | && arg.find(',', 6) == std::string::npos) { | |
00fe1341 | 896 | state.cpp_args.push_back(args[i]); |
62f3217e | 897 | return Statistic::none; |
3781f256 JR |
898 | } else if (arg == "-Wp,-MP" |
899 | || (arg.size() > 8 && util::starts_with(arg, "-Wp,-M") | |
900 | && arg[7] == ',' | |
901 | && (arg[6] == 'F' || arg[6] == 'Q' || arg[6] == 'T') | |
902 | && arg.find(',', 8) == std::string::npos)) { | |
6cb3973a | 903 | state.dep_args.push_back(args[i]); |
62f3217e | 904 | return Statistic::none; |
756e03d1 JR |
905 | } else if (config.direct_mode()) { |
906 | // -Wp, can be used to pass too hard options to the preprocessor. | |
907 | // Hence, disable direct mode. | |
60904e7b | 908 | LOG("Unsupported compiler option for direct mode: {}", args[i]); |
756e03d1 JR |
909 | config.set_direct_mode(false); |
910 | } | |
911 | ||
912 | // Any other -Wp,* arguments are only relevant for the preprocessor. | |
6cb3973a | 913 | state.cpp_args.push_back(args[i]); |
62f3217e | 914 | return Statistic::none; |
756e03d1 | 915 | } |
6cb3973a | 916 | |
3781f256 | 917 | if (arg == "-MP") { |
6cb3973a | 918 | state.dep_args.push_back(args[i]); |
62f3217e | 919 | return Statistic::none; |
756e03d1 JR |
920 | } |
921 | ||
922 | // Input charset needs to be handled specially. | |
3781f256 | 923 | if (util::starts_with(arg, "-finput-charset=")) { |
9915191f | 924 | state.input_charset_option = args[i]; |
62f3217e | 925 | return Statistic::none; |
756e03d1 JR |
926 | } |
927 | ||
3781f256 | 928 | if (arg == "--serialize-diagnostics") { |
6cb3973a | 929 | if (i == args.size() - 1) { |
60904e7b | 930 | LOG("Missing argument to {}", args[i]); |
c0248cf7 | 931 | return Statistic::bad_compiler_arguments; |
756e03d1 JR |
932 | } |
933 | args_info.generating_diagnostics = true; | |
6cb3973a | 934 | args_info.output_dia = Util::make_relative_path(ctx, args[i + 1]); |
756e03d1 | 935 | i++; |
62f3217e | 936 | return Statistic::none; |
756e03d1 JR |
937 | } |
938 | ||
96ec6c9d | 939 | if (config.compiler_type() == CompilerType::gcc) { |
3781f256 | 940 | if (arg == "-fdiagnostics-color" || arg == "-fdiagnostics-color=always") { |
96ec6c9d JR |
941 | state.color_diagnostics = ColorDiagnostics::always; |
942 | state.compiler_only_args_no_hash.push_back(args[i]); | |
943 | return Statistic::none; | |
3781f256 JR |
944 | } else if (arg == "-fno-diagnostics-color" |
945 | || arg == "-fdiagnostics-color=never") { | |
96ec6c9d JR |
946 | state.color_diagnostics = ColorDiagnostics::never; |
947 | state.compiler_only_args_no_hash.push_back(args[i]); | |
948 | return Statistic::none; | |
3781f256 | 949 | } else if (arg == "-fdiagnostics-color=auto") { |
96ec6c9d JR |
950 | state.color_diagnostics = ColorDiagnostics::automatic; |
951 | state.compiler_only_args_no_hash.push_back(args[i]); | |
952 | return Statistic::none; | |
953 | } | |
954 | } else if (config.is_compiler_group_clang()) { | |
955 | // In the "-Xclang -fcolor-diagnostics" form, -Xclang is skipped and the | |
956 | // -fcolor-diagnostics argument which is passed to cc1 is handled below. | |
3781f256 | 957 | if (arg == "-Xclang" && i + 1 < args.size() |
96ec6c9d JR |
958 | && args[i + 1] == "-fcolor-diagnostics") { |
959 | state.compiler_only_args_no_hash.push_back(args[i]); | |
960 | ++i; | |
3781f256 | 961 | arg = make_dash_option(ctx.config, args[i]); |
96ec6c9d | 962 | } |
3781f256 | 963 | if (arg == "-fcolor-diagnostics") { |
96ec6c9d JR |
964 | state.color_diagnostics = ColorDiagnostics::always; |
965 | state.compiler_only_args_no_hash.push_back(args[i]); | |
966 | return Statistic::none; | |
3781f256 | 967 | } else if (arg == "-fno-color-diagnostics") { |
96ec6c9d JR |
968 | state.color_diagnostics = ColorDiagnostics::never; |
969 | state.compiler_only_args_no_hash.push_back(args[i]); | |
970 | return Statistic::none; | |
971 | } | |
756e03d1 JR |
972 | } |
973 | ||
974 | // GCC | |
3781f256 | 975 | if (arg == "-fdirectives-only") { |
756e03d1 | 976 | state.found_directives_only = true; |
62f3217e | 977 | return Statistic::none; |
756e03d1 | 978 | } |
6cb3973a | 979 | |
756e03d1 | 980 | // Clang |
3781f256 | 981 | if (arg == "-frewrite-includes") { |
756e03d1 | 982 | state.found_rewrite_includes = true; |
62f3217e | 983 | return Statistic::none; |
756e03d1 JR |
984 | } |
985 | ||
3781f256 | 986 | if (arg == "-fno-pch-timestamp") { |
3ec58dbc AH |
987 | args_info.fno_pch_timestamp = true; |
988 | state.common_args.push_back(args[i]); | |
62f3217e | 989 | return Statistic::none; |
3ec58dbc AH |
990 | } |
991 | ||
3781f256 | 992 | if (arg == "-fpch-preprocess") { |
3ec58dbc AH |
993 | state.found_fpch_preprocess = true; |
994 | state.common_args.push_back(args[i]); | |
62f3217e | 995 | return Statistic::none; |
3ec58dbc AH |
996 | } |
997 | ||
03023ee7 | 998 | if (config.sloppiness().contains(core::Sloppy::clang_index_store) |
3781f256 | 999 | && arg == "-index-store-path") { |
6cb3973a JR |
1000 | // Xcode 9 or later calls Clang with this option. The given path includes a |
1001 | // UUID that might lead to cache misses, especially when cache is shared | |
1002 | // among multiple users. | |
756e03d1 | 1003 | i++; |
6cb3973a | 1004 | if (i <= args.size() - 1) { |
60904e7b | 1005 | LOG("Skipping argument -index-store-path {}", args[i]); |
756e03d1 | 1006 | } |
62f3217e | 1007 | return Statistic::none; |
756e03d1 JR |
1008 | } |
1009 | ||
3781f256 | 1010 | if (arg == "-frecord-gcc-switches") { |
0492eb74 | 1011 | state.hash_full_command_line = true; |
dff6db77 JR |
1012 | LOG_RAW( |
1013 | "Found -frecord-gcc-switches, hashing original command line unmodified"); | |
0492eb74 JR |
1014 | } |
1015 | ||
0a644e6e | 1016 | // MSVC -u is something else than GCC -u, handle it specially. |
3781f256 | 1017 | if (arg == "-u" && ctx.config.is_compiler_group_msvc()) { |
0a644e6e | 1018 | state.cpp_args.push_back(args[i]); |
62f3217e | 1019 | return Statistic::none; |
0a644e6e LL |
1020 | } |
1021 | ||
3781f256 | 1022 | if (compopt_takes_path(arg)) { |
6cb3973a | 1023 | if (i == args.size() - 1) { |
60904e7b | 1024 | LOG("Missing argument to {}", args[i]); |
c0248cf7 | 1025 | return Statistic::bad_compiler_arguments; |
756e03d1 JR |
1026 | } |
1027 | ||
3ec58dbc AH |
1028 | // In the -Xclang -include-(pch/pth) -Xclang <path> case, the path is one |
1029 | // index further behind. | |
c8fb5395 | 1030 | const size_t next = args[i + 1] == "-Xclang" && i + 2 < args.size() ? 2 : 1; |
3ec58dbc | 1031 | |
3781f256 JR |
1032 | if (!detect_pch( |
1033 | arg, args[i + next], args_info.included_pch_file, next == 2, state)) { | |
c0248cf7 | 1034 | return Statistic::bad_compiler_arguments; |
756e03d1 JR |
1035 | } |
1036 | ||
c8fb5395 JR |
1037 | // Potentially rewrite path argument to relative path to get better hit |
1038 | // rate. A secondary effect is that paths in the standard error output | |
1039 | // produced by the compiler will be normalized. | |
3ec58dbc AH |
1040 | std::string relpath = Util::make_relative_path(ctx, args[i + next]); |
1041 | auto& dest_args = | |
3781f256 | 1042 | compopt_affects_cpp_output(arg) ? state.cpp_args : state.common_args; |
3ec58dbc AH |
1043 | dest_args.push_back(args[i]); |
1044 | if (next == 2) { | |
1045 | dest_args.push_back(args[i + 1]); | |
756e03d1 | 1046 | } |
3ec58dbc | 1047 | dest_args.push_back(relpath); |
756e03d1 | 1048 | |
3ec58dbc | 1049 | i += next; |
62f3217e | 1050 | return Statistic::none; |
756e03d1 JR |
1051 | } |
1052 | ||
b4d25746 | 1053 | // Detect PCH for options with concatenated path (relative or absolute). |
3781f256 JR |
1054 | if (util::starts_with(arg, "-include") || util::starts_with(arg, "-Fp") |
1055 | || util::starts_with(arg, "-Yu")) { | |
1056 | const size_t path_pos = util::starts_with(arg, "-include") ? 8 : 3; | |
1057 | if (!detect_pch(arg.substr(0, path_pos), | |
1058 | arg.substr(path_pos), | |
b4d25746 JR |
1059 | args_info.included_pch_file, |
1060 | false, | |
1061 | state)) { | |
1062 | return Statistic::bad_compiler_arguments; | |
1063 | } | |
1064 | ||
1065 | // Fall through to the next section, so intentionally not returning here. | |
1066 | } | |
1067 | ||
c8fb5395 | 1068 | // Potentially rewrite concatenated absolute path argument to relative. |
3781f256 JR |
1069 | if (arg[0] == '-') { |
1070 | const auto path_pos = Util::is_absolute_path_with_prefix(arg); | |
09dea223 JR |
1071 | if (path_pos) { |
1072 | const std::string option = args[i].substr(0, *path_pos); | |
756e03d1 | 1073 | if (compopt_takes_concat_arg(option) && compopt_takes_path(option)) { |
60005c83 | 1074 | const auto relpath = Util::make_relative_path( |
3781f256 | 1075 | ctx, std::string_view(arg).substr(*path_pos)); |
6cb3973a | 1076 | std::string new_option = option + relpath; |
27f00db4 | 1077 | if (compopt_affects_cpp_output(option)) { |
6cb3973a | 1078 | state.cpp_args.push_back(new_option); |
756e03d1 | 1079 | } else { |
6cb3973a | 1080 | state.common_args.push_back(new_option); |
756e03d1 | 1081 | } |
62f3217e | 1082 | return Statistic::none; |
756e03d1 JR |
1083 | } |
1084 | } | |
1085 | } | |
1086 | ||
1087 | // Options that take an argument. | |
3781f256 | 1088 | if (compopt_takes_arg(arg)) { |
6cb3973a | 1089 | if (i == args.size() - 1) { |
60904e7b | 1090 | LOG("Missing argument to {}", args[i]); |
c0248cf7 | 1091 | return Statistic::bad_compiler_arguments; |
756e03d1 JR |
1092 | } |
1093 | ||
3781f256 | 1094 | if (compopt_affects_cpp_output(arg)) { |
6cb3973a JR |
1095 | state.cpp_args.push_back(args[i]); |
1096 | state.cpp_args.push_back(args[i + 1]); | |
756e03d1 | 1097 | } else { |
6cb3973a JR |
1098 | state.common_args.push_back(args[i]); |
1099 | state.common_args.push_back(args[i + 1]); | |
756e03d1 JR |
1100 | } |
1101 | ||
1102 | i++; | |
62f3217e | 1103 | return Statistic::none; |
756e03d1 JR |
1104 | } |
1105 | ||
dfc7a901 JR |
1106 | if (args[i] == "--") { |
1107 | args_info.seen_double_dash = true; | |
1108 | return Statistic::none; | |
1109 | } | |
1110 | ||
756e03d1 | 1111 | // Other options. |
3781f256 JR |
1112 | if (arg[0] == '-') { |
1113 | if (compopt_affects_cpp_output(arg) | |
1114 | || compopt_prefix_affects_cpp_output(arg)) { | |
6cb3973a | 1115 | state.cpp_args.push_back(args[i]); |
3781f256 JR |
1116 | return Statistic::none; |
1117 | } else if (ctx.config.is_compiler_group_msvc() | |
1118 | && args[i][0] == '/' // Intentionally not checking arg here | |
c86a4628 | 1119 | && DirEntry(args[i]).is_regular_file()) { |
3781f256 | 1120 | // Likely the input file, which is handled in process_arg later. |
756e03d1 | 1121 | } else { |
6cb3973a | 1122 | state.common_args.push_back(args[i]); |
3781f256 | 1123 | return Statistic::none; |
756e03d1 | 1124 | } |
756e03d1 JR |
1125 | } |
1126 | ||
15e315eb | 1127 | // It was not a known option. |
62f3217e JR |
1128 | return std::nullopt; |
1129 | } | |
1130 | ||
1131 | Statistic | |
1132 | process_arg(const Context& ctx, | |
1133 | ArgsInfo& args_info, | |
1134 | Config& config, | |
1135 | Args& args, | |
1136 | size_t& args_index, | |
1137 | ArgumentProcessingState& state) | |
1138 | { | |
1139 | const auto processed = | |
1140 | process_option_arg(ctx, args_info, config, args, args_index, state); | |
1141 | if (processed) { | |
1142 | const auto& error = *processed; | |
1143 | return error; | |
1144 | } | |
1145 | ||
1146 | size_t& i = args_index; | |
1147 | ||
20ab91b3 | 1148 | // If an argument isn't a plain file then assume it's an option, not an input |
6cb3973a | 1149 | // file. This allows us to cope better with unusual compiler options. |
756e03d1 JR |
1150 | // |
1151 | // Note that "/dev/null" is an exception that is sometimes used as an input | |
1152 | // file when code is testing compiler flags. | |
c86a4628 JR |
1153 | if (!util::is_dev_null_path(args[i])) { |
1154 | if (!DirEntry(args[i]).is_regular_file()) { | |
60904e7b | 1155 | LOG("{} is not a regular file, not considering as input file", args[i]); |
6cb3973a | 1156 | state.common_args.push_back(args[i]); |
62f3217e | 1157 | return Statistic::none; |
756e03d1 JR |
1158 | } |
1159 | } | |
1160 | ||
7f77c031 JR |
1161 | if (fs::exists(args[i])) { |
1162 | LOG("Detected input file: {}", args[i]); | |
1163 | state.input_files.emplace_back(args[i]); | |
1164 | } else { | |
1165 | LOG("Not considering {} an input file since it doesn't exist", args[i]); | |
1166 | state.common_args.push_back(args[i]); | |
756e03d1 | 1167 | } |
62f3217e | 1168 | return Statistic::none; |
756e03d1 JR |
1169 | } |
1170 | ||
fec40553 JR |
1171 | const char* |
1172 | get_default_object_file_extension(const Config& config) | |
025f0d03 | 1173 | { |
fec40553 | 1174 | return config.is_compiler_group_msvc() ? ".obj" : ".o"; |
025f0d03 JR |
1175 | } |
1176 | ||
756e03d1 JR |
1177 | } // namespace |
1178 | ||
225497c0 AL |
1179 | ProcessArgsResult |
1180 | process_args(Context& ctx) | |
756e03d1 | 1181 | { |
706f7443 | 1182 | ASSERT(!ctx.orig_args.empty()); |
756e03d1 JR |
1183 | |
1184 | ArgsInfo& args_info = ctx.args_info; | |
1185 | Config& config = ctx.config; | |
1186 | ||
1187 | // args is a copy of the original arguments given to the compiler but with | |
1188 | // arguments from @file and similar constructs expanded. It's only used as a | |
1189 | // temporary data structure to loop over. | |
1190 | Args args = ctx.orig_args; | |
1191 | ArgumentProcessingState state; | |
1192 | ||
1193 | state.common_args.push_back(args[0]); // Compiler | |
1194 | ||
eea89d4a | 1195 | std::optional<Statistic> argument_error; |
756e03d1 | 1196 | for (size_t i = 1; i < args.size(); i++) { |
e04705a5 | 1197 | const auto error = process_arg(ctx, args_info, ctx.config, args, i, state); |
62f3217e | 1198 | if (error != Statistic::none && !argument_error) { |
9f19f94b | 1199 | argument_error = error; |
756e03d1 JR |
1200 | } |
1201 | } | |
1202 | ||
7f77c031 JR |
1203 | const bool is_link = |
1204 | !(state.found_c_opt || state.found_dc_opt || state.found_S_opt | |
1205 | || state.found_syntax_only || state.found_analyze_opt); | |
1206 | ||
1207 | if (state.input_files.empty()) { | |
1208 | LOG_RAW("No input file found"); | |
1209 | return Statistic::no_input_file; | |
1210 | } | |
1211 | if (state.input_files.size() > 1) { | |
1212 | if (is_link) { | |
1213 | LOG_RAW("Called for link"); | |
1214 | return state.input_files.front().string().find("conftest.") | |
1215 | != std::string::npos | |
1216 | ? Statistic::autoconf_test | |
1217 | : Statistic::called_for_link; | |
1218 | } else { | |
1219 | LOG_RAW("Multiple input files"); | |
1220 | return Statistic::multiple_source_files; | |
1221 | } | |
1222 | } | |
1223 | ||
1224 | args_info.orig_input_file = state.input_files.front().string(); | |
1225 | // Rewrite to relative to increase hit rate. | |
1226 | args_info.input_file = | |
1227 | Util::make_relative_path(ctx, args_info.orig_input_file); | |
1228 | args_info.normalized_input_file = | |
1229 | Util::normalize_concrete_absolute_path(args_info.input_file); | |
1230 | ||
fec40553 JR |
1231 | // Bail out on too hard combinations of options. |
1232 | if (state.found_mf_opt && state.found_wp_md_or_mmd_opt) { | |
1233 | // GCC and Clang behave differently when "-Wp,-M[M]D,wp.d" and "-MF mf.d" | |
1234 | // are used: GCC writes to wp.d but Clang writes to mf.d. We could | |
1235 | // potentially support this by behaving differently depending on the | |
1236 | // compiler type, but let's just bail out for now. | |
1237 | LOG_RAW("-Wp,-M[M]D in combination with -MF is not supported"); | |
1238 | return Statistic::unsupported_compiler_option; | |
d099c180 JR |
1239 | } |
1240 | ||
6ee19c33 JR |
1241 | if (!state.last_seen_msvc_z_debug_option.empty() |
1242 | && state.last_seen_msvc_z_debug_option.substr(2) != "7") { | |
d099c180 | 1243 | // /Zi and /ZI are unsupported, but /Z7 is fine. |
6ee19c33 JR |
1244 | LOG("Compiler option {} is unsupported", |
1245 | state.last_seen_msvc_z_debug_option); | |
d099c180 | 1246 | return Statistic::unsupported_compiler_option; |
fec40553 | 1247 | } |
fec40553 | 1248 | |
9f19f94b JR |
1249 | // Don't try to second guess the compiler's heuristics for stdout handling. |
1250 | if (args_info.output_obj == "-") { | |
1251 | LOG_RAW("Output file is -"); | |
1252 | return Statistic::output_to_stdout; | |
1253 | } | |
1254 | ||
1255 | // Determine output object file. | |
cfda479f OS |
1256 | bool output_obj_by_source = args_info.output_obj.empty(); |
1257 | if (!output_obj_by_source && ctx.config.is_compiler_group_msvc()) { | |
1258 | if (*args_info.output_obj.rbegin() == '\\') { | |
1259 | output_obj_by_source = true; | |
c86a4628 JR |
1260 | } else if (DirEntry(args_info.output_obj).is_directory()) { |
1261 | args_info.output_obj.append("\\"); | |
1262 | output_obj_by_source = true; | |
cfda479f OS |
1263 | } |
1264 | } | |
1265 | ||
1266 | if (output_obj_by_source && !args_info.input_file.empty()) { | |
67da9633 M |
1267 | std::string_view extension; |
1268 | if (state.found_analyze_opt) { | |
1269 | extension = ".plist"; | |
1270 | } else if (state.found_S_opt) { | |
1271 | extension = ".s"; | |
1272 | } else { | |
1273 | extension = get_default_object_file_extension(ctx.config); | |
1274 | } | |
e026c786 JR |
1275 | args_info.output_obj += |
1276 | Util::change_extension(Util::base_name(args_info.input_file), extension); | |
9f19f94b JR |
1277 | } |
1278 | ||
fec40553 JR |
1279 | args_info.orig_output_obj = args_info.output_obj; |
1280 | args_info.output_obj = Util::make_relative_path(ctx, args_info.output_obj); | |
1281 | ||
1282 | // Determine output dependency file. | |
1283 | ||
9f19f94b JR |
1284 | // On argument processing error, return now since we have determined |
1285 | // args_info.output_obj which is needed to determine the log filename in | |
1286 | // CCACHE_DEBUG mode. | |
1287 | if (argument_error) { | |
1288 | return *argument_error; | |
1289 | } | |
1290 | ||
756e03d1 | 1291 | if (state.generating_debuginfo_level_3 && !config.run_second_cpp()) { |
19fa063b JR |
1292 | // Debug level 3 makes line number information incorrect when compiling |
1293 | // preprocessed code. | |
60904e7b | 1294 | LOG_RAW("Generating debug info level 3; not compiling preprocessed code"); |
756e03d1 JR |
1295 | config.set_run_second_cpp(true); |
1296 | } | |
1297 | ||
19fa063b JR |
1298 | #ifdef __APPLE__ |
1299 | // Newer Clang versions on macOS are known to produce different debug | |
1300 | // information when compiling preprocessed code. | |
1301 | if (args_info.generating_debuginfo && !config.run_second_cpp()) { | |
1302 | LOG_RAW("Generating debug info; not compiling preprocessed code"); | |
1303 | config.set_run_second_cpp(true); | |
1304 | } | |
1305 | #endif | |
1306 | ||
756e03d1 JR |
1307 | if (state.found_pch || state.found_fpch_preprocess) { |
1308 | args_info.using_precompiled_header = true; | |
03023ee7 | 1309 | if (!(config.sloppiness().contains(core::Sloppy::time_macros))) { |
60904e7b | 1310 | LOG_RAW( |
756e03d1 JR |
1311 | "You have to specify \"time_macros\" sloppiness when using" |
1312 | " precompiled headers to get direct hits"); | |
60904e7b | 1313 | LOG_RAW("Disabling direct mode"); |
c0248cf7 | 1314 | return Statistic::could_not_use_precompiled_header; |
756e03d1 JR |
1315 | } |
1316 | } | |
1317 | ||
1318 | if (args_info.profile_path.empty()) { | |
1319 | args_info.profile_path = ctx.apparent_cwd; | |
1320 | } | |
1321 | ||
55507575 JR |
1322 | if (!state.explicit_language.empty() && state.explicit_language == "none") { |
1323 | state.explicit_language.clear(); | |
756e03d1 | 1324 | } |
55507575 | 1325 | if (!state.explicit_language.empty()) { |
9fac7eee | 1326 | if (!language_is_supported(state.explicit_language)) { |
60904e7b | 1327 | LOG("Unsupported language: {}", state.explicit_language); |
c0248cf7 | 1328 | return Statistic::unsupported_source_language; |
756e03d1 | 1329 | } |
55507575 | 1330 | args_info.actual_language = state.explicit_language; |
756e03d1 | 1331 | } else { |
50737d3f JR |
1332 | args_info.actual_language = |
1333 | language_for_file(args_info.input_file, config.compiler_type()); | |
756e03d1 JR |
1334 | } |
1335 | ||
1336 | args_info.output_is_precompiled_header = | |
3ec58dbc | 1337 | args_info.actual_language.find("-header") != std::string::npos |
e8b54fc8 | 1338 | || is_precompiled_header(args_info.output_obj); |
756e03d1 | 1339 | |
cfda479f | 1340 | if (args_info.output_is_precompiled_header && output_obj_by_source) { |
fec40553 JR |
1341 | args_info.orig_output_obj = args_info.orig_input_file + ".gch"; |
1342 | args_info.output_obj = | |
1343 | Util::make_relative_path(ctx, args_info.orig_output_obj); | |
9f19f94b JR |
1344 | } |
1345 | ||
756e03d1 | 1346 | if (args_info.output_is_precompiled_header |
03023ee7 | 1347 | && !(config.sloppiness().contains(core::Sloppy::pch_defines))) { |
60904e7b | 1348 | LOG_RAW( |
756e03d1 JR |
1349 | "You have to specify \"pch_defines,time_macros\" sloppiness when" |
1350 | " creating precompiled headers"); | |
c0248cf7 | 1351 | return Statistic::could_not_use_precompiled_header; |
756e03d1 JR |
1352 | } |
1353 | ||
7f77c031 | 1354 | if (is_link) { |
756e03d1 | 1355 | if (args_info.output_is_precompiled_header) { |
cf71924a | 1356 | state.common_args.push_back("-c"); |
756e03d1 | 1357 | } else { |
60904e7b | 1358 | LOG_RAW("No -c option found"); |
cf71924a JR |
1359 | // Having a separate statistic for autoconf tests is useful, as they are |
1360 | // the dominant form of "called for link" in many cases. | |
1361 | return args_info.input_file.find("conftest.") != std::string::npos | |
c0248cf7 AL |
1362 | ? Statistic::autoconf_test |
1363 | : Statistic::called_for_link; | |
756e03d1 JR |
1364 | } |
1365 | } | |
1366 | ||
1367 | if (args_info.actual_language.empty()) { | |
60904e7b | 1368 | LOG("Unsupported source extension: {}", args_info.input_file); |
c0248cf7 | 1369 | return Statistic::unsupported_source_language; |
756e03d1 JR |
1370 | } |
1371 | ||
b53afeb5 JR |
1372 | if (args_info.actual_language == "assembler") { |
1373 | // -MD/-MMD for assembler file does not produce a dependency file. | |
1374 | args_info.generating_dependencies = false; | |
1375 | } | |
1376 | ||
50737d3f JR |
1377 | if (!config.run_second_cpp() |
1378 | && (args_info.actual_language == "cu" | |
1379 | || args_info.actual_language == "cuda")) { | |
1380 | LOG("Source language is \"{}\"; not compiling preprocessed code", | |
1381 | args_info.actual_language); | |
756e03d1 JR |
1382 | config.set_run_second_cpp(true); |
1383 | } | |
1384 | ||
9fac7eee | 1385 | args_info.direct_i_file = language_is_preprocessed(args_info.actual_language); |
756e03d1 JR |
1386 | |
1387 | if (args_info.output_is_precompiled_header && !config.run_second_cpp()) { | |
1388 | // It doesn't work to create the .gch from preprocessed source. | |
60904e7b | 1389 | LOG_RAW("Creating precompiled header; not compiling preprocessed code"); |
756e03d1 JR |
1390 | config.set_run_second_cpp(true); |
1391 | } | |
1392 | ||
1393 | if (config.cpp_extension().empty()) { | |
9fac7eee JR |
1394 | std::string p_language = p_language_for_language(args_info.actual_language); |
1395 | config.set_cpp_extension(extension_for_language(p_language).substr(1)); | |
756e03d1 JR |
1396 | } |
1397 | ||
756e03d1 | 1398 | if (args_info.seen_split_dwarf) { |
c86a4628 | 1399 | if (util::is_dev_null_path(args_info.output_obj)) { |
4caef178 JR |
1400 | // Outputting to /dev/null -> compiler won't write a .dwo, so just pretend |
1401 | // we haven't seen the -gsplit-dwarf option. | |
1402 | args_info.seen_split_dwarf = false; | |
1403 | } else { | |
1404 | args_info.output_dwo = | |
1405 | Util::change_extension(args_info.output_obj, ".dwo"); | |
1406 | } | |
756e03d1 JR |
1407 | } |
1408 | ||
c86a4628 JR |
1409 | if (!util::is_dev_null_path(args_info.output_obj)) { |
1410 | DirEntry entry(args_info.output_obj); | |
1411 | if (entry.exists() && !entry.is_regular_file()) { | |
60904e7b | 1412 | LOG("Not a regular file: {}", args_info.output_obj); |
c0248cf7 | 1413 | return Statistic::bad_output_file; |
756e03d1 JR |
1414 | } |
1415 | } | |
1416 | ||
c86a4628 JR |
1417 | if (util::is_dev_null_path(args_info.output_dep)) { |
1418 | args_info.generating_dependencies = false; | |
1419 | } | |
1420 | ||
1421 | auto output_dir = Util::dir_name(args_info.output_obj); | |
1422 | if (!DirEntry(output_dir).is_directory()) { | |
60904e7b | 1423 | LOG("Directory does not exist: {}", output_dir); |
c0248cf7 | 1424 | return Statistic::bad_output_file; |
756e03d1 JR |
1425 | } |
1426 | ||
1427 | // Some options shouldn't be passed to the real compiler when it compiles | |
1428 | // preprocessed code: | |
1429 | // | |
61648752 JR |
1430 | // -finput-charset=CHARSET (otherwise conversion happens twice) |
1431 | // -x CHARSET (otherwise the wrong language is selected) | |
9915191f JR |
1432 | if (!state.input_charset_option.empty()) { |
1433 | state.cpp_args.push_back(state.input_charset_option); | |
756e03d1 | 1434 | } |
b763420f | 1435 | if (state.found_pch && !ctx.config.is_compiler_group_msvc()) { |
cf71924a | 1436 | state.cpp_args.push_back("-fpch-preprocess"); |
756e03d1 | 1437 | } |
55507575 | 1438 | if (!state.explicit_language.empty()) { |
cf71924a JR |
1439 | state.cpp_args.push_back("-x"); |
1440 | state.cpp_args.push_back(state.explicit_language); | |
756e03d1 JR |
1441 | } |
1442 | ||
1c6ccf18 MW |
1443 | args_info.strip_diagnostics_colors = |
1444 | state.color_diagnostics != ColorDiagnostics::automatic | |
1445 | ? state.color_diagnostics == ColorDiagnostics::never | |
1446 | : !color_output_possible(); | |
50e8d229 | 1447 | |
756e03d1 | 1448 | // Since output is redirected, compilers will not color their output by |
1c6ccf18 | 1449 | // default, so force it explicitly. |
eea89d4a | 1450 | std::optional<std::string> diagnostics_color_arg; |
32c70852 | 1451 | if (config.is_compiler_group_clang()) { |
0c17dfbb JR |
1452 | // Don't pass -fcolor-diagnostics when compiling assembler to avoid an |
1453 | // "argument unused during compilation" warning. | |
1c6ccf18 | 1454 | if (args_info.actual_language != "assembler") { |
50e8d229 | 1455 | diagnostics_color_arg = "-fcolor-diagnostics"; |
1c6ccf18 | 1456 | } |
e2ab1352 | 1457 | } else if (config.compiler_type() == CompilerType::gcc) { |
50e8d229 | 1458 | diagnostics_color_arg = "-fdiagnostics-color"; |
1c6ccf18 MW |
1459 | } else { |
1460 | // Other compilers shouldn't output color, so no need to strip it. | |
1461 | args_info.strip_diagnostics_colors = false; | |
756e03d1 JR |
1462 | } |
1463 | ||
1464 | if (args_info.generating_dependencies) { | |
fec40553 JR |
1465 | if (state.output_dep_origin == OutputDepOrigin::none) { |
1466 | args_info.output_dep = Util::change_extension(args_info.output_obj, ".d"); | |
756e03d1 JR |
1467 | if (!config.run_second_cpp()) { |
1468 | // If we're compiling preprocessed code we're sending dep_args to the | |
1469 | // preprocessor so we need to use -MF to write to the correct .d file | |
1470 | // location since the preprocessor doesn't know the final object path. | |
cf71924a | 1471 | state.dep_args.push_back("-MF"); |
fec40553 | 1472 | state.dep_args.push_back(args_info.output_dep); |
756e03d1 JR |
1473 | } |
1474 | } | |
1475 | ||
fec40553 | 1476 | if (!args_info.dependency_target && !config.run_second_cpp()) { |
756e03d1 JR |
1477 | // If we're compiling preprocessed code we're sending dep_args to the |
1478 | // preprocessor so we need to use -MQ to get the correct target object | |
1479 | // file in the .d file. | |
cf71924a | 1480 | state.dep_args.push_back("-MQ"); |
756e03d1 JR |
1481 | state.dep_args.push_back(args_info.output_obj); |
1482 | } | |
fec40553 JR |
1483 | |
1484 | if (!args_info.dependency_target) { | |
84c58a57 JR |
1485 | std::string dep_target = args_info.orig_output_obj; |
1486 | ||
1487 | // GCC and Clang behave differently when "-Wp,-M[M]D,wp.d" is used with | |
1488 | // "-o" but with neither "-MMD" nor "-MT"/"-MQ": GCC uses a dependency | |
1489 | // target based on the source filename but Clang bases it on the output | |
1490 | // filename. | |
1491 | if (state.found_wp_md_or_mmd_opt && !args_info.output_obj.empty() | |
1492 | && !state.found_md_or_mmd_opt) { | |
1493 | if (config.compiler_type() == CompilerType::clang) { | |
1494 | // Clang does the sane thing: the dependency target is the output file | |
1495 | // so that the dependency file actually makes sense. | |
1496 | } else if (config.compiler_type() == CompilerType::gcc) { | |
1497 | // GCC strangely uses the base name of the source file but with a .o | |
1498 | // extension. | |
1499 | dep_target = Util::change_extension( | |
1500 | Util::base_name(args_info.orig_input_file), | |
1501 | get_default_object_file_extension(ctx.config)); | |
1502 | } else { | |
1503 | // How other compilers behave is currently unknown, so bail out. | |
1504 | LOG_RAW( | |
1505 | "-Wp,-M[M]D with -o without -MMD, -MQ or -MT is only supported for" | |
1506 | " GCC or Clang"); | |
1507 | return Statistic::unsupported_compiler_option; | |
1508 | } | |
1509 | } | |
1510 | ||
1511 | args_info.dependency_target = Depfile::escape_filename(dep_target); | |
fec40553 | 1512 | } |
756e03d1 | 1513 | } |
cf71924a | 1514 | |
756e03d1 | 1515 | if (args_info.generating_stackusage) { |
cf71924a | 1516 | auto default_sufile_name = |
756e03d1 JR |
1517 | Util::change_extension(args_info.output_obj, ".su"); |
1518 | args_info.output_su = Util::make_relative_path(ctx, default_sufile_name); | |
1519 | } | |
1520 | ||
225497c0 | 1521 | Args compiler_args = state.common_args; |
50e8d229 | 1522 | compiler_args.push_back(state.compiler_only_args_no_hash); |
cf71924a | 1523 | compiler_args.push_back(state.compiler_only_args); |
756e03d1 JR |
1524 | |
1525 | if (config.run_second_cpp()) { | |
cf71924a | 1526 | compiler_args.push_back(state.cpp_args); |
756e03d1 JR |
1527 | } else if (state.found_directives_only || state.found_rewrite_includes) { |
1528 | // Need to pass the macros and any other preprocessor directives again. | |
cf71924a | 1529 | compiler_args.push_back(state.cpp_args); |
756e03d1 | 1530 | if (state.found_directives_only) { |
cf71924a | 1531 | state.cpp_args.push_back("-fdirectives-only"); |
756e03d1 | 1532 | // The preprocessed source code still needs some more preprocessing. |
cf71924a JR |
1533 | compiler_args.push_back("-fpreprocessed"); |
1534 | compiler_args.push_back("-fdirectives-only"); | |
756e03d1 JR |
1535 | } |
1536 | if (state.found_rewrite_includes) { | |
cf71924a | 1537 | state.cpp_args.push_back("-frewrite-includes"); |
756e03d1 | 1538 | // The preprocessed source code still needs some more preprocessing. |
cf71924a | 1539 | compiler_args.push_back("-x"); |
756e03d1 JR |
1540 | compiler_args.push_back(args_info.actual_language); |
1541 | } | |
55507575 | 1542 | } else if (!state.explicit_language.empty()) { |
756e03d1 JR |
1543 | // Workaround for a bug in Apple's patched distcc -- it doesn't properly |
1544 | // reset the language specified with -x, so if -x is given, we have to | |
1545 | // specify the preprocessed language explicitly. | |
cf71924a JR |
1546 | compiler_args.push_back("-x"); |
1547 | compiler_args.push_back(p_language_for_language(state.explicit_language)); | |
756e03d1 JR |
1548 | } |
1549 | ||
1550 | if (state.found_c_opt) { | |
cf71924a | 1551 | compiler_args.push_back("-c"); |
756e03d1 JR |
1552 | } |
1553 | ||
1554 | if (state.found_dc_opt) { | |
cf71924a | 1555 | compiler_args.push_back("-dc"); |
756e03d1 JR |
1556 | } |
1557 | ||
ab7dd6ff TN |
1558 | if (!state.xarch_args.empty()) { |
1559 | for (const auto& arch : args_info.arch_args) { | |
1560 | auto it = state.xarch_args.find(arch); | |
1561 | if (it != state.xarch_args.end()) { | |
1562 | args_info.xarch_args.emplace(arch, it->second); | |
1563 | } | |
b9a810af JR |
1564 | } |
1565 | } | |
1566 | ||
7ca8fd6c | 1567 | for (const auto& arch : args_info.arch_args) { |
cf71924a JR |
1568 | compiler_args.push_back("-arch"); |
1569 | compiler_args.push_back(arch); | |
ab7dd6ff TN |
1570 | |
1571 | auto it = args_info.xarch_args.find(arch); | |
1572 | if (it != args_info.xarch_args.end()) { | |
1573 | args_info.xarch_args.emplace(arch, it->second); | |
1574 | ||
1575 | for (const auto& xarch : it->second) { | |
1576 | compiler_args.push_back("-Xarch_" + arch); | |
1577 | compiler_args.push_back(xarch); | |
1578 | } | |
1579 | } | |
756e03d1 JR |
1580 | } |
1581 | ||
225497c0 | 1582 | Args preprocessor_args = state.common_args; |
cf71924a | 1583 | preprocessor_args.push_back(state.cpp_args); |
756e03d1 JR |
1584 | |
1585 | if (config.run_second_cpp()) { | |
1586 | // When not compiling the preprocessed source code, only pass dependency | |
1587 | // arguments to the compiler to avoid having to add -MQ, supporting e.g. | |
1588 | // EDG-based compilers which don't support -MQ. | |
cf71924a | 1589 | compiler_args.push_back(state.dep_args); |
756e03d1 JR |
1590 | } else { |
1591 | // When compiling the preprocessed source code, pass dependency arguments to | |
1592 | // the preprocessor since the compiler doesn't produce a .d file when | |
1593 | // compiling preprocessed source code. | |
cf71924a | 1594 | preprocessor_args.push_back(state.dep_args); |
756e03d1 JR |
1595 | } |
1596 | ||
225497c0 | 1597 | Args extra_args_to_hash = state.compiler_only_args; |
756e03d1 | 1598 | if (config.run_second_cpp()) { |
cf71924a | 1599 | extra_args_to_hash.push_back(state.dep_args); |
756e03d1 | 1600 | } |
0492eb74 JR |
1601 | if (state.hash_full_command_line) { |
1602 | extra_args_to_hash.push_back(ctx.orig_args); | |
1603 | } | |
756e03d1 | 1604 | |
50e8d229 JR |
1605 | if (diagnostics_color_arg) { |
1606 | compiler_args.push_back(*diagnostics_color_arg); | |
1607 | if (!config.run_second_cpp()) { | |
1608 | // If we're compiling preprocessed code we're keeping any warnings from | |
1609 | // the preprocessor, so we need to make sure that they are in color. | |
1610 | preprocessor_args.push_back(*diagnostics_color_arg); | |
1611 | } | |
1612 | if (ctx.config.depend_mode()) { | |
1613 | // The compiler is invoked with the original arguments in the depend mode. | |
e04705a5 | 1614 | args_info.depend_extra_args.push_back(*diagnostics_color_arg); |
50e8d229 JR |
1615 | } |
1616 | } | |
1617 | ||
bda468cf OS |
1618 | if (ctx.config.depend_mode() && !args_info.generating_includes |
1619 | && ctx.config.compiler_type() == CompilerType::msvc) { | |
1620 | ctx.auto_depend_mode = true; | |
1621 | args_info.generating_includes = true; | |
4ad17e89 | 1622 | args_info.depend_extra_args.push_back("/showIncludes"); |
bda468cf OS |
1623 | } |
1624 | ||
195011ad JR |
1625 | return { |
1626 | preprocessor_args, | |
1627 | extra_args_to_hash, | |
1628 | compiler_args, | |
1629 | state.hash_actual_cwd, | |
1630 | }; | |
756e03d1 | 1631 | } |
2737d79e | 1632 | |
e8b54fc8 JR |
1633 | bool |
1634 | is_precompiled_header(std::string_view path) | |
1635 | { | |
1636 | std::string_view ext = Util::get_extension(path); | |
1637 | return ext == ".gch" || ext == ".pch" || ext == ".pth" | |
1638 | || Util::get_extension(Util::dir_name(path)) == ".gch"; | |
1639 | } | |
1640 | ||
2737d79e JR |
1641 | bool |
1642 | option_should_be_ignored(const std::string& arg, | |
1643 | const std::vector<std::string>& patterns) | |
1644 | { | |
1645 | return std::any_of( | |
1646 | patterns.cbegin(), patterns.cend(), [&arg](const auto& pattern) { | |
1647 | const auto& prefix = | |
1648 | std::string_view(pattern).substr(0, pattern.length() - 1); | |
1649 | return ( | |
1650 | pattern == arg | |
1651 | || (util::ends_with(pattern, "*") && util::starts_with(arg, prefix))); | |
1652 | }); | |
1653 | } |