1use std::env;
5use std::io::IsTerminal;
6use std::sync::{Arc, OnceLock};
7
8use camino::{Utf8Path, Utf8PathBuf};
9use clap::Parser;
10
11use crate::common::{
12 CodegenBackend, CompareMode, Config, Debugger, ForcePassMode, TestMode, TestSuite,
13};
14use crate::edition::Edition;
15use crate::{debuggers, directives, early_config_check, run_tests};
16
17pub fn main() {
18 tracing_subscriber::fmt::init();
19
20 if std::io::stderr().is_terminal()
23 && matches!(std::env::var("NO_COLOR").as_deref(), Err(_) | Ok("0"))
24 {
25 colored::control::set_override(true);
26 }
27
28 let config = Arc::new(parse_config(env::args().collect()));
29
30 early_config_check(&config);
31
32 run_tests(config);
33}
34
35#[derive(clap::Parser)]
37struct Args {
38 #[arg(long)]
41 compile_lib_path: Utf8PathBuf,
42 #[arg(long)]
44 run_lib_path: Utf8PathBuf,
45 #[arg(long)]
47 rustc_path: Utf8PathBuf,
48 #[arg(long)]
50 python: String,
51 #[arg(long)]
53 src_root: Utf8PathBuf,
54 #[arg(long)]
56 src_test_suite_root: Utf8PathBuf,
57 #[arg(long)]
59 build_root: Utf8PathBuf,
60 #[arg(long)]
62 build_test_suite_root: Utf8PathBuf,
63 #[arg(long)]
65 sysroot_base: Utf8PathBuf,
66 #[arg(long)]
68 stage: u32,
69 #[arg(long)]
71 stage_id: String,
72 #[arg(long)]
74 mode: TestMode,
75 #[arg(long)]
77 suite: TestSuite,
78 #[arg(long)]
80 cc: String,
81 #[arg(long)]
83 cxx: String,
84 #[arg(long, allow_hyphen_values = true)]
86 cflags: String,
87 #[arg(long, allow_hyphen_values = true)]
89 cxxflags: String,
90 #[arg(long)]
92 llvm_components: String,
93 #[arg(long)]
95 channel: String,
96 #[arg(long)]
98 nightly_branch: String,
99 #[arg(long)]
101 git_merge_commit_email: String,
102 #[arg(long)]
104 minicore_path: Utf8PathBuf,
105 #[arg(long)]
107 jobs: u32,
108 #[arg(long)]
110 host: String,
111 #[arg(long)]
113 target: String,
114
115 #[arg(long)]
118 cargo_path: Option<Utf8PathBuf>,
119 #[arg(long)]
121 stage0_rustc_path: Option<Utf8PathBuf>,
122 #[arg(long)]
124 query_rustc_path: Option<Utf8PathBuf>,
125 #[arg(long)]
127 rustdoc_path: Option<Utf8PathBuf>,
128 #[arg(long)]
130 coverage_dump_path: Option<Utf8PathBuf>,
131 #[arg(long)]
133 jsondocck_path: Option<Utf8PathBuf>,
134 #[arg(long)]
136 jsondoclint_path: Option<Utf8PathBuf>,
137 #[arg(long)]
139 run_clang_based_tests_with: Option<Utf8PathBuf>,
140 #[arg(long)]
142 llvm_filecheck: Option<Utf8PathBuf>,
143 #[arg(long)]
145 llvm_bin_dir: Option<Utf8PathBuf>,
146 #[arg(long)]
148 nodejs: Option<Utf8PathBuf>,
149 #[arg(long)]
151 npm: Option<Utf8PathBuf>,
152 #[arg(long)]
154 remote_test_client: Option<Utf8PathBuf>,
155 #[arg(long)]
157 cdb: Option<Utf8PathBuf>,
158 #[arg(long)]
160 gdb: Option<Utf8PathBuf>,
161 #[arg(long)]
163 lldb: Option<Utf8PathBuf>,
164 #[arg(long)]
166 lldb_version: Option<String>,
167 #[arg(long)]
169 llvm_version: Option<String>,
170 #[arg(long)]
172 android_cross_path: Option<Utf8PathBuf>,
173 #[arg(long)]
175 adb_path: Option<Utf8PathBuf>,
176 #[arg(long)]
178 adb_test_dir: Option<Utf8PathBuf>,
179 #[arg(long, default_value = "ar")]
181 ar: String,
182 #[arg(long)]
184 target_linker: Option<String>,
185 #[arg(long)]
187 host_linker: Option<String>,
188 #[arg(long)]
190 pass: Option<ForcePassMode>,
191 #[arg(long)]
193 run: Option<String>,
194 #[arg(long)]
196 runner: Option<String>,
197 #[arg(long)]
199 compare_mode: Option<CompareMode>,
200 #[arg(long)]
202 edition: Option<Edition>,
203 #[arg(long)]
205 debugger: Option<String>,
206 #[arg(long)]
208 default_codegen_backend: Option<CodegenBackend>,
209 #[arg(long)]
211 override_codegen_backend: Option<String>,
212 #[arg(long)]
214 compiletest_diff_tool: Option<String>,
215 #[arg(long)]
217 parallel_frontend_threads: Option<u32>,
218 #[arg(long)]
220 iteration_count: Option<u32>,
221
222 #[arg(long)]
225 bless: bool,
226 #[arg(long)]
228 fail_fast: bool,
229 #[arg(long)]
231 ignored: bool,
232 #[arg(long)]
234 has_enzyme: bool,
235 #[arg(long)]
237 has_offload: bool,
238 #[arg(long)]
240 with_rustc_debug_assertions: bool,
241 #[arg(long)]
243 with_std_debug_assertions: bool,
244 #[arg(long)]
246 with_std_remap_debuginfo: bool,
247 #[arg(long)]
249 exact: bool,
250 #[arg(long)]
252 rust_randomized_layout: bool,
253 #[arg(long)]
255 optimize_tests: bool,
256 #[arg(long)]
258 verbose: bool,
259 #[arg(long)]
261 verbose_run_make_subprocess_output: bool,
262 #[arg(long)]
264 system_llvm: bool,
265 #[arg(long)]
267 force_rerun: bool,
268 #[arg(long)]
270 only_modified: bool,
271 #[arg(long, hide = true)]
273 nocapture: bool,
274 #[arg(long)]
276 no_capture: bool,
277 #[arg(long)]
279 profiler_runtime: bool,
280 #[arg(long)]
282 git_hash: bool,
283 #[arg(long)]
285 rustfix_coverage: bool,
286 #[arg(long)]
288 bypass_ignore_backends: bool,
289
290 #[arg(long)]
294 skip: Vec<String>,
295 #[arg(long, allow_hyphen_values = true)]
297 host_rustcflags: Vec<String>,
298 #[arg(long, allow_hyphen_values = true)]
300 target_rustcflags: Vec<String>,
301
302 filters: Vec<String>,
306}
307
308pub(crate) fn parse_config(args: Vec<String>) -> Config {
309 let args = Args::parse_from(args);
310
311 fn make_absolute(path: Utf8PathBuf) -> Utf8PathBuf {
312 if path.is_relative() {
313 Utf8PathBuf::try_from(env::current_dir().unwrap()).unwrap().join(path)
314 } else {
315 path
316 }
317 }
318
319 if args.nocapture {
320 panic!("`--nocapture` is deprecated; please use `--no-capture`");
321 }
322
323 let adb_device_status = args.target.contains("android") && args.adb_test_dir.is_some();
324
325 let cdb_version = args.cdb.as_deref().and_then(debuggers::query_cdb_version);
327 let gdb_version = args.gdb.as_deref().and_then(debuggers::query_gdb_version);
329 let lldb_version = args.lldb_version.as_deref().and_then(debuggers::extract_lldb_version);
331 let llvm_version =
335 args.llvm_version.as_deref().map(directives::extract_llvm_version).or_else(|| {
336 directives::extract_llvm_version_from_binary(args.llvm_filecheck.as_ref()?.as_str())
337 });
338
339 let default_codegen_backend = args.default_codegen_backend.unwrap_or(CodegenBackend::Llvm);
340
341 let mode = args.mode;
342 let filters = if mode == TestMode::RunMake {
343 args.filters
344 .iter()
345 .map(|f| {
346 let path = Utf8Path::new(f);
352 let mut iter = path.iter().skip(1);
353
354 if iter.next().is_some_and(|s| s == "rmake.rs") && iter.next().is_none() {
355 path.parent().unwrap().to_string()
358 } else {
359 f.to_string()
360 }
361 })
362 .collect::<Vec<_>>()
363 } else {
364 args.filters.clone()
371 };
372
373 let compare_mode = args.compare_mode;
374
375 let src_root = args.src_root;
376 let src_test_suite_root = args.src_test_suite_root;
377 assert!(
378 src_test_suite_root.starts_with(&src_root),
379 "`src-root` must be a parent of `src-test-suite-root`: `src-root`=`{}`, `src-test-suite-root` = `{}`",
380 src_root,
381 src_test_suite_root
382 );
383
384 let build_root = args.build_root;
385 let build_test_suite_root = args.build_test_suite_root;
386 assert!(build_test_suite_root.starts_with(&build_root));
387
388 let parallel_frontend_threads =
389 args.parallel_frontend_threads.unwrap_or(Config::DEFAULT_PARALLEL_FRONTEND_THREADS);
390 let iteration_count = args.iteration_count.unwrap_or(Config::DEFAULT_ITERATION_COUNT);
391 assert!(iteration_count > 0, "`--iteration-count` must be a positive integer");
392
393 Config {
394 bless: args.bless,
395 fail_fast: args.fail_fast || env::var_os("RUSTC_TEST_FAIL_FAST").is_some(),
396
397 host_compile_lib_path: make_absolute(args.compile_lib_path),
398 target_run_lib_path: make_absolute(args.run_lib_path),
399 rustc_path: args.rustc_path,
400 cargo_path: args.cargo_path,
401 stage0_rustc_path: args.stage0_rustc_path,
402 query_rustc_path: args.query_rustc_path,
403 rustdoc_path: args.rustdoc_path,
404 coverage_dump_path: args.coverage_dump_path,
405 python: args.python,
406 jsondocck_path: args.jsondocck_path,
407 jsondoclint_path: args.jsondoclint_path,
408 run_clang_based_tests_with: args.run_clang_based_tests_with,
409 llvm_filecheck: args.llvm_filecheck,
410 llvm_bin_dir: args.llvm_bin_dir,
411
412 src_root,
413 src_test_suite_root,
414
415 build_root,
416 build_test_suite_root,
417
418 sysroot_base: args.sysroot_base,
419
420 stage: args.stage,
421 stage_id: args.stage_id,
422
423 mode,
424 suite: args.suite,
425 debugger: args.debugger.map(|debugger| {
426 debugger
427 .parse::<Debugger>()
428 .unwrap_or_else(|_| panic!("unknown `--debugger` option `{debugger}` given"))
429 }),
430 run_ignored: args.ignored,
431 with_rustc_debug_assertions: args.with_rustc_debug_assertions,
432 with_std_debug_assertions: args.with_std_debug_assertions,
433 with_std_remap_debuginfo: args.with_std_remap_debuginfo,
434 filters,
435 skip: args.skip,
436 filter_exact: args.exact,
437 force_pass_mode: args.pass,
438 run: args.run.and_then(|mode| match mode.as_str() {
440 "auto" => None,
441 "always" => Some(true),
442 "never" => Some(false),
443 _ => panic!("unknown `--run` option `{}` given", mode),
444 }),
445 runner: args.runner,
446 host_rustcflags: args.host_rustcflags,
447 target_rustcflags: args.target_rustcflags,
448 optimize_tests: args.optimize_tests,
449 rust_randomized_layout: args.rust_randomized_layout,
450 target: args.target,
451 host: args.host,
452 cdb: args.cdb,
453 cdb_version,
454 gdb: args.gdb,
455 gdb_version,
456 lldb: args.lldb,
457 lldb_version,
458 llvm_version,
459 system_llvm: args.system_llvm,
460 android_cross_path: args.android_cross_path,
461 adb_path: args.adb_path,
462 adb_test_dir: args.adb_test_dir,
463 adb_device_status,
464 verbose: args.verbose,
465 verbose_run_make_subprocess_output: args.verbose_run_make_subprocess_output,
466 only_modified: args.only_modified,
467 remote_test_client: args.remote_test_client,
468 compare_mode,
469 rustfix_coverage: args.rustfix_coverage,
470 has_enzyme: args.has_enzyme,
471 has_offload: args.has_offload,
472 channel: args.channel,
473 git_hash: args.git_hash,
474 edition: args.edition,
475
476 cc: args.cc,
477 cxx: args.cxx,
478 cflags: args.cflags,
479 cxxflags: args.cxxflags,
480 ar: args.ar,
481 target_linker: args.target_linker,
482 host_linker: args.host_linker,
483 llvm_components: args.llvm_components,
484 nodejs: args.nodejs,
485
486 force_rerun: args.force_rerun,
487
488 target_cfgs: OnceLock::new(),
489 builtin_cfg_names: OnceLock::new(),
490 supported_crate_types: OnceLock::new(),
491
492 capture: !args.no_capture,
493
494 nightly_branch: args.nightly_branch,
495 git_merge_commit_email: args.git_merge_commit_email,
496
497 profiler_runtime: args.profiler_runtime,
498
499 diff_command: args.compiletest_diff_tool,
500
501 minicore_path: args.minicore_path,
502
503 default_codegen_backend,
504 override_codegen_backend: args.override_codegen_backend,
505 bypass_ignore_backends: args.bypass_ignore_backends,
506
507 jobs: args.jobs,
508
509 parallel_frontend_threads,
510 iteration_count,
511 }
512}