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::svh::Svh;
7use rustc_errors::timings::TimingSection;
8use rustc_hir::def_id::LOCAL_CRATE;
9use rustc_metadata::EncodedMetadata;
10use rustc_middle::dep_graph::{DepGraph, WorkProduct, WorkProductMap};
11use rustc_middle::ty::TyCtxt;
12use rustc_session::config::{self, OutputFilenames, OutputType};
13use rustc_session::{IncrCompSession, Session};
14
15use crate::diagnostics::FailedWritingFile;
16use crate::passes;
17
18pub struct Linker {
19 dep_graph: DepGraph,
20 output_filenames: Arc<OutputFilenames>,
21 crate_hash: Option<Svh>,
23 crate_info: CrateInfo,
24 metadata: EncodedMetadata,
25 ongoing_codegen: Box<dyn Any>,
26}
27
28impl Linker {
29 pub fn codegen_and_build_linker(
30 tcx: TyCtxt<'_>,
31 codegen_backend: &dyn CodegenBackend,
32 ) -> Linker {
33 let (ongoing_codegen, crate_info, metadata) = passes::start_codegen(codegen_backend, tcx);
34
35 Linker {
36 dep_graph: tcx.dep_graph.clone(),
37 output_filenames: Arc::clone(tcx.output_filenames(())),
38 crate_hash: if tcx.sess.opts.incremental.is_some() {
39 Some(tcx.crate_hash(LOCAL_CRATE))
40 } else {
41 None
42 },
43 crate_info,
44 metadata,
45 ongoing_codegen,
46 }
47 }
48
49 pub fn link(
50 self,
51 sess: &Session,
52 incr_comp_session: Option<IncrCompSession>,
53 codegen_backend: &dyn CodegenBackend,
54 ) {
55 let (compiled_modules, mut work_products) = sess.time("finish_ongoing_codegen", || {
56 match self.ongoing_codegen.downcast::<CompiledModules>() {
57 Ok(compiled_modules) => (*compiled_modules, WorkProductMap::default()),
59
60 Err(ongoing_codegen) => codegen_backend.join_codegen(
61 ongoing_codegen,
62 sess,
63 incr_comp_session.as_ref(),
64 &self.output_filenames,
65 &self.crate_info,
66 ),
67 }
68 });
69
70 if sess.codegen_units().as_usize() == 1 && sess.opts.unstable_opts.time_llvm_passes {
71 codegen_backend.print_pass_timings()
72 }
73
74 if sess.print_llvm_stats() {
75 codegen_backend.print_statistics()
76 }
77
78 if let Some(out_path) = sess.print_llvm_stats_json() {
79 let llvm_stats_json = codegen_backend.print_statistics_json();
80
81 if !llvm_stats_json.is_empty() {
82 if let Err(e) = std::fs::write(&out_path, llvm_stats_json) {
83 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));
84 }
85 } else {
86 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!(
87 "requested to print LLVM statistics to JSON file {}, but the codegen backend \
88 did not provide any statistics",
89 out_path,
90 ));
91 }
92 }
93
94 sess.timings.end_section(sess.dcx(), TimingSection::Codegen);
95
96 if sess.opts.incremental.is_some()
97 && let Some(path) = self.metadata.path()
98 {
99 let (id, product) = rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
100 sess,
101 incr_comp_session.as_ref().unwrap(),
102 WorkProduct::METADATA_WORKPRODUCT_CGU_NAME,
103 &[(OutputType::Metadata.extension(), path)],
104 );
105 work_products.insert(id, product);
106 }
107
108 if let Some(guar) = sess.dcx().has_errors_or_delayed_bugs() {
109 guar.raise_fatal();
110 }
111
112 let _timer = sess.timer("link");
113
114 sess.time("serialize_work_products", || {
115 rustc_incremental::save_work_product_index(
116 sess,
117 incr_comp_session.as_ref(),
118 &self.dep_graph,
119 work_products,
120 )
121 });
122
123 let prof = sess.prof.clone();
124 prof.generic_activity("drop_dep_graph").run(move || drop(self.dep_graph));
125
126 rustc_incremental::finalize_session_directory(sess, incr_comp_session, self.crate_hash);
129
130 if sess
133 .opts
134 .unstable_opts
135 .offload
136 .iter()
137 .any(|o| #[allow(non_exhaustive_omitted_patterns)] match o {
config::Offload::HostMetadata(_) => true,
_ => false,
}matches!(o, config::Offload::HostMetadata(_)))
138 {
139 return;
140 }
141
142 if !sess
143 .opts
144 .output_types
145 .keys()
146 .any(|&i| i == OutputType::Exe || i == OutputType::Metadata)
147 {
148 return;
149 }
150
151 if sess.opts.unstable_opts.no_link {
152 let rlink_file = self.output_filenames.with_extension(config::RLINK_EXT);
153 CompiledModules::serialize_rlink(
154 sess,
155 &rlink_file,
156 &compiled_modules,
157 &self.crate_info,
158 &self.metadata,
159 &self.output_filenames,
160 )
161 .unwrap_or_else(|error| {
162 sess.dcx().emit_fatal(FailedWritingFile { path: &rlink_file, error })
163 });
164 return;
165 }
166
167 let _timer = sess.prof.verbose_generic_activity("link_crate");
168 let _timing = sess.timings.section_guard(sess.dcx(), TimingSection::Linking);
169 codegen_backend.link(
170 sess,
171 compiled_modules,
172 self.crate_info,
173 self.metadata,
174 &self.output_filenames,
175 )
176 }
177}