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::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    // Only present when incr. comp. is enabled.
22    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                // This was a check only build
58                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        sess.timings.end_section(sess.dcx(), TimingSection::Codegen);
71
72        if sess.opts.incremental.is_some()
73            && let Some(path) = self.metadata.path()
74        {
75            let (id, product) = rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
76                sess,
77                incr_comp_session.as_ref().unwrap(),
78                WorkProduct::METADATA_WORKPRODUCT_CGU_NAME,
79                &[(OutputType::Metadata.extension(), path)],
80            );
81            work_products.insert(id, product);
82        }
83
84        if let Some(guar) = sess.dcx().has_errors_or_delayed_bugs() {
85            guar.raise_fatal();
86        }
87
88        let _timer = sess.timer("link");
89
90        sess.time("serialize_work_products", || {
91            rustc_incremental::save_work_product_index(
92                sess,
93                incr_comp_session.as_ref(),
94                &self.dep_graph,
95                work_products,
96            )
97        });
98
99        let prof = sess.prof.clone();
100        prof.generic_activity("drop_dep_graph").run(move || drop(self.dep_graph));
101
102        // Now that we won't touch anything in the incremental compilation directory
103        // any more, we can finalize it (which involves renaming it)
104        rustc_incremental::finalize_session_directory(sess, incr_comp_session, self.crate_hash);
105
106        // The `HostMetadata` offload pass only writes the kernel manifest.
107        // Codegen was already skipped so there are no files to link.
108        if sess
109            .opts
110            .unstable_opts
111            .offload
112            .iter()
113            .any(|o| #[allow(non_exhaustive_omitted_patterns)] match o {
    config::Offload::HostMetadata(_) => true,
    _ => false,
}matches!(o, config::Offload::HostMetadata(_)))
114        {
115            return;
116        }
117
118        if !sess
119            .opts
120            .output_types
121            .keys()
122            .any(|&i| i == OutputType::Exe || i == OutputType::Metadata)
123        {
124            return;
125        }
126
127        if sess.opts.unstable_opts.no_link {
128            let rlink_file = self.output_filenames.with_extension(config::RLINK_EXT);
129            CompiledModules::serialize_rlink(
130                sess,
131                &rlink_file,
132                &compiled_modules,
133                &self.crate_info,
134                &self.metadata,
135                &self.output_filenames,
136            )
137            .unwrap_or_else(|error| {
138                sess.dcx().emit_fatal(FailedWritingFile { path: &rlink_file, error })
139            });
140            return;
141        }
142
143        let _timer = sess.prof.verbose_generic_activity("link_crate");
144        let _timing = sess.timings.section_guard(sess.dcx(), TimingSection::Linking);
145        codegen_backend.link(
146            sess,
147            compiled_modules,
148            self.crate_info,
149            self.metadata,
150            &self.output_filenames,
151        )
152    }
153}