Skip to main content

rustc_interface/
queries.rs

1use 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    // Only present when incr. comp. is enabled.
23    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.needs_crate_hash() {
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                // This was a check only build
54                Ok(compiled_modules) => (*compiled_modules, IndexMap::default()),
55
56                Err(ongoing_codegen) => {
57                    codegen_backend.join_codegen(ongoing_codegen, sess, &self.output_filenames)
58                }
59            }
60        });
61
62        if sess.codegen_units().as_usize() == 1 && sess.opts.unstable_opts.time_llvm_passes {
63            codegen_backend.print_pass_timings()
64        }
65
66        if sess.print_llvm_stats() {
67            codegen_backend.print_statistics()
68        }
69
70        sess.timings.end_section(sess.dcx(), TimingSection::Codegen);
71
72        if sess.opts.incremental.is_some()
73            && let Some(path) = self.metadata.path()
74            && let Some((id, product)) =
75                rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
76                    sess,
77                    "metadata",
78                    &[("rmeta", path)],
79                    &[],
80                )
81        {
82            work_products.insert(id, product);
83        }
84
85        sess.dcx().abort_if_errors();
86
87        let _timer = sess.timer("link");
88
89        sess.time("serialize_work_products", || {
90            rustc_incremental::save_work_product_index(sess, &self.dep_graph, work_products)
91        });
92
93        let prof = sess.prof.clone();
94        prof.generic_activity("drop_dep_graph").run(move || drop(self.dep_graph));
95
96        // Now that we won't touch anything in the incremental compilation directory
97        // any more, we can finalize it (which involves renaming it)
98        rustc_incremental::finalize_session_directory(sess, self.crate_hash);
99
100        if !sess
101            .opts
102            .output_types
103            .keys()
104            .any(|&i| i == OutputType::Exe || i == OutputType::Metadata)
105        {
106            return;
107        }
108
109        if sess.opts.unstable_opts.no_link {
110            let rlink_file = self.output_filenames.with_extension(config::RLINK_EXT);
111            CompiledModules::serialize_rlink(
112                sess,
113                &rlink_file,
114                &compiled_modules,
115                &self.crate_info,
116                &self.metadata,
117                &self.output_filenames,
118            )
119            .unwrap_or_else(|error| {
120                sess.dcx().emit_fatal(FailedWritingFile { path: &rlink_file, error })
121            });
122            return;
123        }
124
125        let _timer = sess.prof.verbose_generic_activity("link_crate");
126        let _timing = sess.timings.section_guard(sess.dcx(), TimingSection::Linking);
127        codegen_backend.link(
128            sess,
129            compiled_modules,
130            self.crate_info,
131            self.metadata,
132            &self.output_filenames,
133        )
134    }
135}