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, WorkProductMap};
11use rustc_middle::ty::TyCtxt;
12use rustc_session::Session;
13use rustc_session::config::{self, OutputFilenames, OutputType};
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(self, sess: &Session, codegen_backend: &dyn CodegenBackend) {
50        let (compiled_modules, mut work_products) = sess.time("finish_ongoing_codegen", || {
51            match self.ongoing_codegen.downcast::<CompiledModules>() {
52                // This was a check only build
53                Ok(compiled_modules) => (*compiled_modules, WorkProductMap::default()),
54
55                Err(ongoing_codegen) => codegen_backend.join_codegen(
56                    ongoing_codegen,
57                    sess,
58                    &self.output_filenames,
59                    &self.crate_info,
60                ),
61            }
62        });
63
64        if sess.codegen_units().as_usize() == 1 && sess.opts.unstable_opts.time_llvm_passes {
65            codegen_backend.print_pass_timings()
66        }
67
68        if sess.print_llvm_stats() {
69            codegen_backend.print_statistics()
70        }
71
72        if let Some(out_path) = sess.print_llvm_stats_json() {
73            let llvm_stats_json = codegen_backend.print_statistics_json();
74
75            if !llvm_stats_json.is_empty() {
76                if let Err(e) = std::fs::write(&out_path, llvm_stats_json) {
77                    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));
78                }
79            } else {
80                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!(
81                    "requested to print LLVM statistics to JSON file {}, but the codegen backend \
82                    did not provide any statistics",
83                    out_path,
84                ));
85            }
86        }
87
88        sess.timings.end_section(sess.dcx(), TimingSection::Codegen);
89
90        if sess.opts.incremental.is_some()
91            && let Some(path) = self.metadata.path()
92        {
93            let (id, product) = rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
94                sess,
95                "metadata",
96                &[("rmeta", path)],
97                &[],
98            );
99            work_products.insert(id, product);
100        }
101
102        sess.dcx().abort_if_errors();
103
104        let _timer = sess.timer("link");
105
106        sess.time("serialize_work_products", || {
107            rustc_incremental::save_work_product_index(sess, &self.dep_graph, work_products)
108        });
109
110        let prof = sess.prof.clone();
111        prof.generic_activity("drop_dep_graph").run(move || drop(self.dep_graph));
112
113        // Now that we won't touch anything in the incremental compilation directory
114        // any more, we can finalize it (which involves renaming it)
115        rustc_incremental::finalize_session_directory(sess, self.crate_hash);
116
117        if !sess
118            .opts
119            .output_types
120            .keys()
121            .any(|&i| i == OutputType::Exe || i == OutputType::Metadata)
122        {
123            return;
124        }
125
126        if sess.opts.unstable_opts.no_link {
127            let rlink_file = self.output_filenames.with_extension(config::RLINK_EXT);
128            CompiledModules::serialize_rlink(
129                sess,
130                &rlink_file,
131                &compiled_modules,
132                &self.crate_info,
133                &self.metadata,
134                &self.output_filenames,
135            )
136            .unwrap_or_else(|error| {
137                sess.dcx().emit_fatal(FailedWritingFile { path: &rlink_file, error })
138            });
139            return;
140        }
141
142        let _timer = sess.prof.verbose_generic_activity("link_crate");
143        let _timing = sess.timings.section_guard(sess.dcx(), TimingSection::Linking);
144        codegen_backend.link(
145            sess,
146            compiled_modules,
147            self.crate_info,
148            self.metadata,
149            &self.output_filenames,
150        )
151    }
152}