]> git.lizzy.rs Git - rust.git/blob - src/librustc_codegen_utils/codegen_backend.rs
Separate codepaths for fat and thin LTO in write.rs
[rust.git] / src / librustc_codegen_utils / codegen_backend.rs
1 // Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! The Rust compiler.
12 //!
13 //! # Note
14 //!
15 //! This API is completely unstable and subject to change.
16
17 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
18       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
19       html_root_url = "https://doc.rust-lang.org/nightly/")]
20 #![deny(warnings)]
21
22 #![feature(box_syntax)]
23
24 use std::any::Any;
25 use std::io::{self, Write};
26 use std::fs::File;
27 use std::path::Path;
28 use std::sync::{mpsc, Arc};
29
30 use rustc_data_structures::owning_ref::OwningRef;
31 use flate2::Compression;
32 use flate2::write::DeflateEncoder;
33
34 use syntax::symbol::Symbol;
35 use rustc::hir::def_id::LOCAL_CRATE;
36 use rustc::session::{Session, CompileIncomplete};
37 use rustc::session::config::{CrateType, OutputFilenames, PrintRequest};
38 use rustc::ty::TyCtxt;
39 use rustc::ty::query::Providers;
40 use rustc::middle::cstore::EncodedMetadata;
41 use rustc::middle::cstore::MetadataLoader;
42 use rustc::dep_graph::DepGraph;
43 use rustc_target::spec::Target;
44 use rustc_mir::monomorphize::collector;
45 use link::out_filename;
46
47 pub use rustc_data_structures::sync::MetadataRef;
48
49 pub trait CodegenBackend {
50     fn init(&self, _sess: &Session) {}
51     fn print(&self, _req: PrintRequest, _sess: &Session) {}
52     fn target_features(&self, _sess: &Session) -> Vec<Symbol> { vec![] }
53     fn print_passes(&self) {}
54     fn print_version(&self) {}
55     fn diagnostics(&self) -> &[(&'static str, &'static str)] { &[] }
56
57     fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync>;
58     fn provide(&self, _providers: &mut Providers);
59     fn provide_extern(&self, _providers: &mut Providers);
60     fn codegen_crate<'a, 'tcx>(
61         &self,
62         tcx: TyCtxt<'a, 'tcx, 'tcx>,
63         rx: mpsc::Receiver<Box<dyn Any + Send>>
64     ) -> Box<dyn Any>;
65
66     /// This is called on the returned `Box<dyn Any>` from `codegen_backend`
67     ///
68     /// # Panics
69     ///
70     /// Panics when the passed `Box<dyn Any>` was not returned by `codegen_backend`.
71     fn join_codegen_and_link(
72         &self,
73         ongoing_codegen: Box<dyn Any>,
74         sess: &Session,
75         dep_graph: &DepGraph,
76         outputs: &OutputFilenames,
77     ) -> Result<(), CompileIncomplete>;
78 }
79
80 pub struct NoLlvmMetadataLoader;
81
82 impl MetadataLoader for NoLlvmMetadataLoader {
83     fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<MetadataRef, String> {
84         let mut file = File::open(filename)
85             .map_err(|e| format!("metadata file open err: {:?}", e))?;
86
87         let mut buf = Vec::new();
88         io::copy(&mut file, &mut buf).unwrap();
89         let buf: OwningRef<Vec<u8>, [u8]> = OwningRef::new(buf).into();
90         return Ok(rustc_erase_owner!(buf.map_owner_box()));
91     }
92
93     fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String> {
94         self.get_rlib_metadata(target, filename)
95     }
96 }
97
98 pub struct MetadataOnlyCodegenBackend(());
99 pub struct OngoingCodegen {
100     metadata: EncodedMetadata,
101     metadata_version: Vec<u8>,
102     crate_name: Symbol,
103 }
104
105 impl MetadataOnlyCodegenBackend {
106     pub fn new() -> Box<dyn CodegenBackend> {
107         box MetadataOnlyCodegenBackend(())
108     }
109 }
110
111 impl CodegenBackend for MetadataOnlyCodegenBackend {
112     fn init(&self, sess: &Session) {
113         for cty in sess.opts.crate_types.iter() {
114             match *cty {
115                 CrateType::Rlib | CrateType::Dylib | CrateType::Executable => {},
116                 _ => {
117                     sess.diagnostic().warn(
118                         &format!("LLVM unsupported, so output type {} is not supported", cty)
119                     );
120                 },
121             }
122         }
123     }
124
125     fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
126         box NoLlvmMetadataLoader
127     }
128
129     fn provide(&self, providers: &mut Providers) {
130         ::symbol_names::provide(providers);
131
132         providers.target_features_whitelist = |_tcx, _cnum| {
133             Default::default() // Just a dummy
134         };
135         providers.is_reachable_non_generic = |_tcx, _defid| true;
136         providers.exported_symbols = |_tcx, _crate| Arc::new(Vec::new());
137     }
138     fn provide_extern(&self, providers: &mut Providers) {
139         providers.is_reachable_non_generic = |_tcx, _defid| true;
140     }
141
142     fn codegen_crate<'a, 'tcx>(
143         &self,
144         tcx: TyCtxt<'a, 'tcx, 'tcx>,
145         _rx: mpsc::Receiver<Box<dyn Any + Send>>
146     ) -> Box<dyn Any> {
147         use rustc_mir::monomorphize::item::MonoItem;
148
149         ::check_for_rustc_errors_attr(tcx);
150         ::symbol_names_test::report_symbol_names(tcx);
151         ::rustc_incremental::assert_dep_graph(tcx);
152         ::rustc_incremental::assert_module_sources::assert_module_sources(tcx);
153         ::rustc_mir::monomorphize::assert_symbols_are_distinct(tcx,
154             collector::collect_crate_mono_items(
155                 tcx,
156                 collector::MonoItemCollectionMode::Eager
157             ).0.iter()
158         );
159         // FIXME: Fix this
160         // ::rustc::middle::dependency_format::calculate(tcx);
161         let _ = tcx.link_args(LOCAL_CRATE);
162         let _ = tcx.native_libraries(LOCAL_CRATE);
163         for mono_item in
164             collector::collect_crate_mono_items(
165                 tcx,
166                 collector::MonoItemCollectionMode::Eager
167             ).0 {
168             match mono_item {
169                 MonoItem::Fn(inst) => {
170                     let def_id = inst.def_id();
171                     if def_id.is_local()  {
172                         let _ = inst.def.is_inline(tcx);
173                         let _ = tcx.codegen_fn_attrs(def_id);
174                     }
175                 }
176                 _ => {}
177             }
178         }
179         tcx.sess.abort_if_errors();
180
181         let metadata = tcx.encode_metadata();
182
183         box OngoingCodegen {
184             metadata: metadata,
185             metadata_version: tcx.metadata_encoding_version().to_vec(),
186             crate_name: tcx.crate_name(LOCAL_CRATE),
187         }
188     }
189
190     fn join_codegen_and_link(
191         &self,
192         ongoing_codegen: Box<dyn Any>,
193         sess: &Session,
194         _dep_graph: &DepGraph,
195         outputs: &OutputFilenames,
196     ) -> Result<(), CompileIncomplete> {
197         let ongoing_codegen = ongoing_codegen.downcast::<OngoingCodegen>()
198             .expect("Expected MetadataOnlyCodegenBackend's OngoingCodegen, found Box<dyn Any>");
199         for &crate_type in sess.opts.crate_types.iter() {
200             if crate_type != CrateType::Rlib &&
201                crate_type != CrateType::Dylib {
202                 continue;
203             }
204             let output_name =
205                 out_filename(sess, crate_type, &outputs, &ongoing_codegen.crate_name.as_str());
206             let mut compressed = ongoing_codegen.metadata_version.clone();
207             let metadata = if crate_type == CrateType::Dylib {
208                 DeflateEncoder::new(&mut compressed, Compression::fast())
209                     .write_all(&ongoing_codegen.metadata.raw_data)
210                     .unwrap();
211                 &compressed
212             } else {
213                 &ongoing_codegen.metadata.raw_data
214             };
215             let mut file = File::create(&output_name).unwrap();
216             file.write_all(metadata).unwrap();
217         }
218
219         sess.abort_if_errors();
220         if !sess.opts.crate_types.contains(&CrateType::Rlib)
221             && !sess.opts.crate_types.contains(&CrateType::Dylib)
222         {
223             sess.fatal("Executables are not supported by the metadata-only backend.");
224         }
225         Ok(())
226     }
227 }