1use std::env;
5use std::io::IsTerminal;
6use std::sync::{Arc, OnceLock};
7
8use camino::{Utf8Path, Utf8PathBuf};
9use clap::Parser;
10
11use crate::common::{CodegenBackend, CompareMode, Config, ForcePassMode, TestMode, TestSuite};
12use crate::edition::Edition;
13use crate::{debuggers, directives, early_config_check, run_tests};
14
15pub fn main() {
16 tracing_subscriber::fmt::init();
17
18 if std::io::stderr().is_terminal()
21 && matches!(std::env::var("NO_COLOR").as_deref(), Err(_) | Ok("0"))
22 {
23 colored::control::set_override(true);
24 }
25
26 let config = Arc::new(parse_config(env::args().collect()));
27
28 early_config_check(&config);
29
30 run_tests(config);
31}
32
33#[derive(clap::Parser)]
35struct Args {
36 #[arg(long)]
39 compile_lib_path: Utf8PathBuf,
40 #[arg(long)]
42 run_lib_path: Utf8PathBuf,
43 #[arg(long)]
45 rustc_path: Utf8PathBuf,
46 #[arg(long)]
48 python: String,
49 #[arg(long)]
51 src_root: Utf8PathBuf,
52 #[arg(long)]
54 src_test_suite_root: Utf8PathBuf,
55 #[arg(long)]
57 build_root: Utf8PathBuf,
58 #[arg(long)]
60 build_test_suite_root: Utf8PathBuf,
61 #[arg(long)]
63 sysroot_base: Utf8PathBuf,
64 #[arg(long)]
66 stage: u32,
67 #[arg(long)]
69 stage_id: String,
70 #[arg(long)]
72 mode: TestMode,
73 #[arg(long)]
75 suite: TestSuite,
76 #[arg(long)]
78 cc: String,
79 #[arg(long)]
81 cxx: String,
82 #[arg(long, allow_hyphen_values = true)]
84 cflags: String,
85 #[arg(long, allow_hyphen_values = true)]
87 cxxflags: String,
88 #[arg(long)]
90 llvm_components: String,
91 #[arg(long)]
93 channel: String,
94 #[arg(long)]
96 nightly_branch: String,
97 #[arg(long)]
99 git_merge_commit_email: String,
100 #[arg(long)]
102 minicore_path: Utf8PathBuf,
103 #[arg(long)]
105 jobs: u32,
106 #[arg(long)]
108 host: String,
109 #[arg(long)]
111 target: String,
112
113 #[arg(long)]
116 cargo_path: Option<Utf8PathBuf>,
117 #[arg(long)]
119 stage0_rustc_path: Option<Utf8PathBuf>,
120 #[arg(long)]
122 run_make_support_rlib: Option<Utf8PathBuf>,
123 #[arg(long)]
125 run_make_support_rmeta: Option<Utf8PathBuf>,
126 #[arg(long)]
128 query_rustc_path: Option<Utf8PathBuf>,
129 #[arg(long)]
131 rustdoc_path: Option<Utf8PathBuf>,
132 #[arg(long)]
134 coverage_dump_path: Option<Utf8PathBuf>,
135 #[arg(long)]
137 jsondocck_path: Option<Utf8PathBuf>,
138 #[arg(long)]
140 jsondoclint_path: Option<Utf8PathBuf>,
141 #[arg(long)]
143 run_clang_based_tests_with: Option<Utf8PathBuf>,
144 #[arg(long)]
146 llvm_filecheck: Option<Utf8PathBuf>,
147 #[arg(long)]
149 llvm_bin_dir: Option<Utf8PathBuf>,
150 #[arg(long)]
152 nodejs: Option<Utf8PathBuf>,
153 #[arg(long)]
155 npm: Option<Utf8PathBuf>,
156 #[arg(long)]
158 remote_test_client: Option<Utf8PathBuf>,
159 #[arg(long)]
161 cdb: Option<Utf8PathBuf>,
162 #[arg(long)]
164 gdb: Option<Utf8PathBuf>,
165 #[arg(long)]
167 lldb: Option<Utf8PathBuf>,
168 #[arg(long)]
170 lldb_version: Option<String>,
171 #[arg(long)]
173 llvm_version: Option<String>,
174 #[arg(long)]
176 android_cross_path: Option<Utf8PathBuf>,
177 #[arg(long)]
179 adb_path: Option<Utf8PathBuf>,
180 #[arg(long)]
182 adb_test_dir: Option<Utf8PathBuf>,
183 #[arg(long, default_value = "ar")]
185 ar: String,
186 #[arg(long)]
188 target_linker: Option<String>,
189 #[arg(long)]
191 host_linker: Option<String>,
192 #[arg(long)]
194 pass: Option<ForcePassMode>,
195 #[arg(long)]
197 run: Option<String>,
198 #[arg(long)]
200 runner: Option<String>,
201 #[arg(long)]
203 compare_mode: Option<CompareMode>,
204 #[arg(long)]
206 edition: Option<Edition>,
207 #[arg(long)]
209 default_codegen_backend: Option<CodegenBackend>,
210 #[arg(long)]
212 override_codegen_backend: Option<String>,
213 #[arg(long)]
215 compiletest_diff_tool: Option<String>,
216 #[arg(long)]
218 parallel_frontend_threads: Option<u32>,
219 #[arg(long)]
221 iteration_count: Option<u32>,
222
223 #[arg(long)]
226 bless: bool,
227 #[arg(long)]
229 fail_fast: bool,
230 #[arg(long)]
232 ignored: bool,
233 #[arg(long)]
235 has_enzyme: bool,
236 #[arg(long)]
238 has_offload: bool,
239 #[arg(long)]
241 with_rustc_debug_assertions: bool,
242 #[arg(long)]
244 with_std_debug_assertions: bool,
245 #[arg(long)]
247 with_std_remap_debuginfo: bool,
248 #[arg(long)]
250 exact: bool,
251 #[arg(long)]
253 rust_randomized_layout: bool,
254 #[arg(long)]
256 optimize_tests: bool,
257 #[arg(long)]
259 verbose: bool,
260 #[arg(long)]
262 verbose_run_make_subprocess_output: bool,
263 #[arg(long)]
265 system_llvm: bool,
266 #[arg(long)]
268 force_rerun: bool,
269 #[arg(long)]
271 only_modified: bool,
272 #[arg(long, hide = true)]
274 nocapture: bool,
275 #[arg(long)]
277 no_capture: bool,
278 #[arg(long)]
280 profiler_runtime: bool,
281 #[arg(long)]
283 git_hash: bool,
284 #[arg(long)]
286 rustfix_coverage: bool,
287 #[arg(long)]
289 bypass_ignore_backends: bool,
290 #[arg(long)]
293 wasm_proc_macros: bool,
294
295 #[arg(long)]
299 skip: Vec<String>,
300 #[arg(long, allow_hyphen_values = true)]
302 host_rustcflags: Vec<String>,
303 #[arg(long, allow_hyphen_values = true)]
305 target_rustcflags: Vec<String>,
306
307 filters: Vec<String>,
311}
312
313pub(crate) fn parse_config(args: Vec<String>) -> Config {
314 let args = Args::parse_from(args);
315
316 fn make_absolute(path: Utf8PathBuf) -> Utf8PathBuf {
317 if path.is_relative() {
318 Utf8PathBuf::try_from(env::current_dir().unwrap()).unwrap().join(path)
319 } else {
320 path
321 }
322 }
323
324 if args.nocapture {
325 panic!("`--nocapture` is deprecated; please use `--no-capture`");
326 }
327
328 let adb_device_status = args.target.contains("android") && args.adb_test_dir.is_some();
329
330 let cdb_version = args.cdb.as_deref().and_then(debuggers::query_cdb_version);
332 let gdb_version = args.gdb.as_deref().and_then(debuggers::query_gdb_version);
334 let lldb_version = args.lldb_version.as_deref().and_then(debuggers::extract_lldb_version);
336 let llvm_version =
340 args.llvm_version.as_deref().map(directives::extract_llvm_version).or_else(|| {
341 directives::extract_llvm_version_from_binary(args.llvm_filecheck.as_ref()?.as_str())
342 });
343
344 let default_codegen_backend = args.default_codegen_backend.unwrap_or(CodegenBackend::Llvm);
345
346 let mode = args.mode;
347 let filters = if mode == TestMode::RunMake {
348 args.filters
349 .iter()
350 .map(|f| {
351 let path = Utf8Path::new(f);
357 let mut iter = path.iter().skip(1);
358
359 if iter.next().is_some_and(|s| s == "rmake.rs") && iter.next().is_none() {
360 path.parent().unwrap().to_string()
363 } else {
364 f.to_string()
365 }
366 })
367 .collect::<Vec<_>>()
368 } else {
369 args.filters.clone()
376 };
377
378 let compare_mode = args.compare_mode;
379
380 let src_root = args.src_root;
381 let src_test_suite_root = args.src_test_suite_root;
382 assert!(
383 src_test_suite_root.starts_with(&src_root),
384 "`src-root` must be a parent of `src-test-suite-root`: `src-root`=`{}`, `src-test-suite-root` = `{}`",
385 src_root,
386 src_test_suite_root
387 );
388
389 let build_root = args.build_root;
390 let build_test_suite_root = args.build_test_suite_root;
391 assert!(build_test_suite_root.starts_with(&build_root));
392
393 let parallel_frontend_threads =
394 args.parallel_frontend_threads.unwrap_or(Config::DEFAULT_PARALLEL_FRONTEND_THREADS);
395 let iteration_count = args.iteration_count.unwrap_or(Config::DEFAULT_ITERATION_COUNT);
396 assert!(iteration_count > 0, "`--iteration-count` must be a positive integer");
397
398 let gcc_supported_target_tuples = match default_codegen_backend {
399 CodegenBackend::Gcc => {
400 directives::find_gcc_supported_targets(&args.sysroot_base, &args.host)
401 }
402 CodegenBackend::Llvm | CodegenBackend::Cranelift => vec![],
403 };
404
405 let run = args.run.and_then(|mode| match mode.as_str() {
407 "auto" => None,
408 "always" => Some(true),
409 "never" => Some(false),
410 _ => panic!("unknown `--run` option `{}` given", mode),
411 });
412
413 Config {
414 adb_device_status,
416 adb_path: args.adb_path,
417 adb_test_dir: args.adb_test_dir,
418 android_cross_path: args.android_cross_path,
419 ar: args.ar,
420 bless: args.bless,
421 build_root,
422 build_test_suite_root,
423
424 builtin_cfg_names: OnceLock::new(),
425 bypass_ignore_backends: args.bypass_ignore_backends,
426
427 capture: !args.no_capture,
428
429 cargo_path: args.cargo_path,
430 cc: args.cc,
431 cdb: args.cdb,
432 cdb_version,
433 cflags: args.cflags,
434 channel: args.channel,
435 compare_mode,
436 coverage_dump_path: args.coverage_dump_path,
437 cxx: args.cxx,
438 cxxflags: args.cxxflags,
439 default_codegen_backend,
440 diff_command: args.compiletest_diff_tool,
441
442 edition: args.edition,
443
444 fail_fast: args.fail_fast || env::var_os("RUSTC_TEST_FAIL_FAST").is_some(),
445
446 filter_exact: args.exact,
447 filters,
448 force_pass_mode: args.pass,
449 force_rerun: args.force_rerun,
450
451 gcc_supported_target_tuples,
452
453 gdb: args.gdb,
454 gdb_version,
455 git_hash: args.git_hash,
456 git_merge_commit_email: args.git_merge_commit_email,
457
458 has_enzyme: args.has_enzyme,
459 has_offload: args.has_offload,
460 host: args.host,
461 host_compile_lib_path: make_absolute(args.compile_lib_path),
462 host_linker: args.host_linker,
463 host_rustcflags: args.host_rustcflags,
464 iteration_count,
465 jobs: args.jobs,
466
467 jsondocck_path: args.jsondocck_path,
468 jsondoclint_path: args.jsondoclint_path,
469 lldb: args.lldb,
470 lldb_version,
471 llvm_bin_dir: args.llvm_bin_dir,
472
473 llvm_components: args.llvm_components,
474 llvm_filecheck: args.llvm_filecheck,
475 llvm_version,
476 minicore_path: args.minicore_path,
477
478 mode,
479 nightly_branch: args.nightly_branch,
480 nodejs: args.nodejs,
481
482 only_modified: args.only_modified,
483 optimize_tests: args.optimize_tests,
484 override_codegen_backend: args.override_codegen_backend,
485 parallel_frontend_threads,
486 profiler_runtime: args.profiler_runtime,
487
488 python: args.python,
489 query_rustc_path: args.query_rustc_path,
490 remote_test_client: args.remote_test_client,
491 run,
492 run_clang_based_tests_with: args.run_clang_based_tests_with,
493 run_ignored: args.ignored,
494 run_make_support_rlib: args.run_make_support_rlib,
495 run_make_support_rmeta: args.run_make_support_rmeta,
496 runner: args.runner,
497 rust_randomized_layout: args.rust_randomized_layout,
498 rustc_path: args.rustc_path,
499 rustdoc_path: args.rustdoc_path,
500 rustfix_coverage: args.rustfix_coverage,
501 skip: args.skip,
502 src_root,
503 src_test_suite_root,
504
505 stage0_rustc_path: args.stage0_rustc_path,
506 stage: args.stage,
507 stage_id: args.stage_id,
508
509 suite: args.suite,
510 supported_crate_types: OnceLock::new(),
511
512 sysroot_base: args.sysroot_base,
513
514 system_llvm: args.system_llvm,
515 target: args.target,
516 target_cfgs: OnceLock::new(),
517 target_linker: args.target_linker,
518 target_run_lib_path: make_absolute(args.run_lib_path),
519 target_rustcflags: args.target_rustcflags,
520 verbose: args.verbose,
521 verbose_run_make_subprocess_output: args.verbose_run_make_subprocess_output,
522 wasm_proc_macros: args.wasm_proc_macros,
523
524 with_rustc_debug_assertions: args.with_rustc_debug_assertions,
525 with_std_debug_assertions: args.with_std_debug_assertions,
526 with_std_remap_debuginfo: args.with_std_remap_debuginfo,
527 }
529}