rustc_interface/
queries.rs

1use std::any::Any;
2use std::sync::Arc;
3
4use rustc_codegen_ssa::CodegenResults;
5use rustc_codegen_ssa::traits::CodegenBackend;
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    // Only present when incr. comp. is enabled.
23    crate_hash: Option<Svh>,
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, 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.needs_crate_hash() {
39                Some(tcx.crate_hash(LOCAL_CRATE))
40            } else {
41                None
42            },
43            metadata,
44            ongoing_codegen,
45        }
46    }
47
48    pub fn link(self, sess: &Session, codegen_backend: &dyn CodegenBackend) {
49        let (codegen_results, mut work_products) = sess.time("finish_ongoing_codegen", || {
50            match self.ongoing_codegen.downcast::<CodegenResults>() {
51                // This was a check only build
52                Ok(codegen_results) => (*codegen_results, IndexMap::default()),
53
54                Err(ongoing_codegen) => {
55                    codegen_backend.join_codegen(ongoing_codegen, sess, &self.output_filenames)
56                }
57            }
58        });
59        sess.timings.end_section(sess.dcx(), TimingSection::Codegen);
60
61        if sess.opts.incremental.is_some()
62            && let Some(path) = self.metadata.path()
63            && let Some((id, product)) =
64                rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
65                    sess,
66                    "metadata",
67                    &[("rmeta", path)],
68                    &[],
69                )
70        {
71            work_products.insert(id, product);
72        }
73
74        sess.dcx().abort_if_errors();
75
76        let _timer = sess.timer("link");
77
78        sess.time("serialize_work_products", || {
79            rustc_incremental::save_work_product_index(sess, &self.dep_graph, work_products)
80        });
81
82        let prof = sess.prof.clone();
83        prof.generic_activity("drop_dep_graph").run(move || drop(self.dep_graph));
84
85        // Now that we won't touch anything in the incremental compilation directory
86        // any more, we can finalize it (which involves renaming it)
87        rustc_incremental::finalize_session_directory(sess, self.crate_hash);
88
89        if !sess
90            .opts
91            .output_types
92            .keys()
93            .any(|&i| i == OutputType::Exe || i == OutputType::Metadata)
94        {
95            return;
96        }
97
98        if sess.opts.unstable_opts.no_link {
99            let rlink_file = self.output_filenames.with_extension(config::RLINK_EXT);
100            CodegenResults::serialize_rlink(
101                sess,
102                &rlink_file,
103                &codegen_results,
104                &self.metadata,
105                &self.output_filenames,
106            )
107            .unwrap_or_else(|error| {
108                sess.dcx().emit_fatal(FailedWritingFile { path: &rlink_file, error })
109            });
110            return;
111        }
112
113        let _timer = sess.prof.verbose_generic_activity("link_crate");
114        let _timing = sess.timings.section_guard(sess.dcx(), TimingSection::Linking);
115        codegen_backend.link(sess, codegen_results, self.metadata, &self.output_filenames)
116    }
117}