rustc_interface/
queries.rs1use std::any::Any;
2use std::sync::Arc;
3
4use rustc_codegen_ssa::traits::CodegenBackend;
5use rustc_codegen_ssa::{CompiledModules, CrateInfo};
6use rustc_data_structures::indexmap::IndexMap;
7use rustc_data_structures::svh::Svh;
8use rustc_errors::timings::TimingSection;
9use rustc_hir::def_id::LOCAL_CRATE;
10use rustc_metadata::EncodedMetadata;
11use rustc_middle::dep_graph::DepGraph;
12use rustc_middle::ty::TyCtxt;
13use rustc_session::Session;
14use rustc_session::config::{self, OutputFilenames, OutputType};
15
16use crate::errors::FailedWritingFile;
17use crate::passes;
18
19pub struct Linker {
20 dep_graph: DepGraph,
21 output_filenames: Arc<OutputFilenames>,
22 crate_hash: Option<Svh>,
24 crate_info: CrateInfo,
25 metadata: EncodedMetadata,
26 ongoing_codegen: Box<dyn Any>,
27}
28
29impl Linker {
30 pub fn codegen_and_build_linker(
31 tcx: TyCtxt<'_>,
32 codegen_backend: &dyn CodegenBackend,
33 ) -> Linker {
34 let (ongoing_codegen, crate_info, metadata) = passes::start_codegen(codegen_backend, tcx);
35
36 Linker {
37 dep_graph: tcx.dep_graph.clone(),
38 output_filenames: Arc::clone(tcx.output_filenames(())),
39 crate_hash: if tcx.sess.opts.incremental.is_some() {
40 Some(tcx.crate_hash(LOCAL_CRATE))
41 } else {
42 None
43 },
44 crate_info,
45 metadata,
46 ongoing_codegen,
47 }
48 }
49
50 pub fn link(self, sess: &Session, codegen_backend: &dyn CodegenBackend) {
51 let (compiled_modules, mut work_products) = sess.time("finish_ongoing_codegen", || {
52 match self.ongoing_codegen.downcast::<CompiledModules>() {
53 Ok(compiled_modules) => (*compiled_modules, IndexMap::default()),
55
56 Err(ongoing_codegen) => codegen_backend.join_codegen(
57 ongoing_codegen,
58 sess,
59 &self.output_filenames,
60 &self.crate_info,
61 ),
62 }
63 });
64
65 if sess.codegen_units().as_usize() == 1 && sess.opts.unstable_opts.time_llvm_passes {
66 codegen_backend.print_pass_timings()
67 }
68
69 if sess.print_llvm_stats() {
70 codegen_backend.print_statistics()
71 }
72
73 if let Some(out_path) = sess.print_llvm_stats_json() {
74 let llvm_stats_json = codegen_backend.print_statistics_json();
75
76 if !llvm_stats_json.is_empty() {
77 if let Err(e) = std::fs::write(&out_path, llvm_stats_json) {
78 sess.dcx().err(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("failed to write stats to {0}: {1}",
out_path, e))
})format!("failed to write stats to {}: {}", out_path, e));
79 }
80 } else {
81 sess.dcx().warn(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("requested to print LLVM statistics to JSON file {0}, but the codegen backend did not provide any statistics",
out_path))
})format!(
82 "requested to print LLVM statistics to JSON file {}, but the codegen backend \
83 did not provide any statistics",
84 out_path,
85 ));
86 }
87 }
88
89 sess.timings.end_section(sess.dcx(), TimingSection::Codegen);
90
91 if sess.opts.incremental.is_some()
92 && let Some(path) = self.metadata.path()
93 && let Some((id, product)) =
94 rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
95 sess,
96 "metadata",
97 &[("rmeta", path)],
98 &[],
99 )
100 {
101 work_products.insert(id, product);
102 }
103
104 sess.dcx().abort_if_errors();
105
106 let _timer = sess.timer("link");
107
108 sess.time("serialize_work_products", || {
109 rustc_incremental::save_work_product_index(sess, &self.dep_graph, work_products)
110 });
111
112 let prof = sess.prof.clone();
113 prof.generic_activity("drop_dep_graph").run(move || drop(self.dep_graph));
114
115 rustc_incremental::finalize_session_directory(sess, self.crate_hash);
118
119 if !sess
120 .opts
121 .output_types
122 .keys()
123 .any(|&i| i == OutputType::Exe || i == OutputType::Metadata)
124 {
125 return;
126 }
127
128 if sess.opts.unstable_opts.no_link {
129 let rlink_file = self.output_filenames.with_extension(config::RLINK_EXT);
130 CompiledModules::serialize_rlink(
131 sess,
132 &rlink_file,
133 &compiled_modules,
134 &self.crate_info,
135 &self.metadata,
136 &self.output_filenames,
137 )
138 .unwrap_or_else(|error| {
139 sess.dcx().emit_fatal(FailedWritingFile { path: &rlink_file, error })
140 });
141 return;
142 }
143
144 let _timer = sess.prof.verbose_generic_activity("link_crate");
145 let _timing = sess.timings.section_guard(sess.dcx(), TimingSection::Linking);
146 codegen_backend.link(
147 sess,
148 compiled_modules,
149 self.crate_info,
150 self.metadata,
151 &self.output_filenames,
152 )
153 }
154}