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::svh::Svh;
7use rustc_errors::timings::TimingSection;
8use rustc_hir::def_id::LOCAL_CRATE;
9use rustc_metadata::EncodedMetadata;
10use rustc_middle::dep_graph::DepGraph;
11use rustc_middle::ty::TyCtxt;
12use rustc_session::Session;
13use rustc_session::config::{self, OutputFilenames, OutputType};
14
15use crate::errors::FailedWritingFile;
16use crate::passes;
17
18pub struct Linker {
19    dep_graph: DepGraph,
20    output_filenames: Arc<OutputFilenames>,
21    // Only present when incr. comp. is enabled.
22    crate_hash: Option<Svh>,
23    metadata: EncodedMetadata,
24    ongoing_codegen: Box<dyn Any>,
25}
26
27impl Linker {
28    pub fn codegen_and_build_linker(
29        tcx: TyCtxt<'_>,
30        codegen_backend: &dyn CodegenBackend,
31    ) -> Linker {
32        let (ongoing_codegen, metadata) = passes::start_codegen(codegen_backend, tcx);
33
34        Linker {
35            dep_graph: tcx.dep_graph.clone(),
36            output_filenames: Arc::clone(tcx.output_filenames(())),
37            crate_hash: if tcx.needs_crate_hash() {
38                Some(tcx.crate_hash(LOCAL_CRATE))
39            } else {
40                None
41            },
42            metadata,
43            ongoing_codegen,
44        }
45    }
46
47    pub fn link(self, sess: &Session, codegen_backend: &dyn CodegenBackend) {
48        let (codegen_results, mut work_products) = sess.time("finish_ongoing_codegen", || {
49            codegen_backend.join_codegen(self.ongoing_codegen, sess, &self.output_filenames)
50        });
51        sess.timings.end_section(sess.dcx(), TimingSection::Codegen);
52
53        if sess.opts.incremental.is_some()
54            && let Some(path) = self.metadata.path()
55            && let Some((id, product)) =
56                rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
57                    sess,
58                    "metadata",
59                    &[("rmeta", path)],
60                    &[],
61                )
62        {
63            work_products.insert(id, product);
64        }
65
66        sess.dcx().abort_if_errors();
67
68        let _timer = sess.timer("link");
69
70        sess.time("serialize_work_products", || {
71            rustc_incremental::save_work_product_index(sess, &self.dep_graph, work_products)
72        });
73
74        let prof = sess.prof.clone();
75        prof.generic_activity("drop_dep_graph").run(move || drop(self.dep_graph));
76
77        // Now that we won't touch anything in the incremental compilation directory
78        // any more, we can finalize it (which involves renaming it)
79        rustc_incremental::finalize_session_directory(sess, self.crate_hash);
80
81        if !sess
82            .opts
83            .output_types
84            .keys()
85            .any(|&i| i == OutputType::Exe || i == OutputType::Metadata)
86        {
87            return;
88        }
89
90        if sess.opts.unstable_opts.no_link {
91            let rlink_file = self.output_filenames.with_extension(config::RLINK_EXT);
92            CodegenResults::serialize_rlink(
93                sess,
94                &rlink_file,
95                &codegen_results,
96                &self.metadata,
97                &*self.output_filenames,
98            )
99            .unwrap_or_else(|error| {
100                sess.dcx().emit_fatal(FailedWritingFile { path: &rlink_file, error })
101            });
102            return;
103        }
104
105        let _timer = sess.prof.verbose_generic_activity("link_crate");
106        let _timing = sess.timings.section_guard(sess.dcx(), TimingSection::Linking);
107        codegen_backend.link(sess, codegen_results, self.metadata, &self.output_filenames)
108    }
109}