]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans_utils/trans_crate.rs
Allow runtime switching between trans backends
[rust.git] / src / librustc_trans_utils / trans_crate.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::prelude::*;
26 use std::io::{self, Cursor};
27 use std::fs::File;
28 use std::path::Path;
29 use std::sync::mpsc;
30
31 use rustc_data_structures::owning_ref::{ErasedBoxRef, OwningRef};
32 use ar::{Archive, Builder, Header};
33 use flate2::Compression;
34 use flate2::write::DeflateEncoder;
35
36 use syntax::symbol::Symbol;
37 use rustc::hir::def_id::LOCAL_CRATE;
38 use rustc::session::{Session, CompileIncomplete};
39 use rustc::session::config::{CrateType, OutputFilenames, PrintRequest};
40 use rustc::ty::TyCtxt;
41 use rustc::ty::maps::Providers;
42 use rustc::middle::cstore::EncodedMetadata;
43 use rustc::middle::cstore::MetadataLoader as MetadataLoader;
44 use rustc::dep_graph::DepGraph;
45 use rustc_back::target::Target;
46 use rustc_mir::monomorphize::collector;
47 use link::{build_link_meta, out_filename};
48
49 pub trait TransCrate {
50     fn print(&self, _req: PrintRequest, _sess: &Session) {}
51     fn target_features(&self, _sess: &Session) -> Vec<Symbol> { vec![] }
52
53     fn metadata_loader(&self) -> Box<MetadataLoader>;
54     fn provide(&self, _providers: &mut Providers);
55     fn provide_extern(&self, _providers: &mut Providers);
56     fn trans_crate<'a, 'tcx>(
57         &self,
58         tcx: TyCtxt<'a, 'tcx, 'tcx>,
59         rx: mpsc::Receiver<Box<Any + Send>>
60     ) -> Box<Any>;
61
62     /// This is called on the returned `Box<Any>` from `trans_crate`
63     ///
64     /// # Panics
65     ///
66     /// Panics when the passed `Box<Any>` was not returned by `trans_crate`.
67     fn join_trans_and_link(
68         &self,
69         trans: Box<Any>,
70         sess: &Session,
71         dep_graph: &DepGraph,
72         outputs: &OutputFilenames,
73     ) -> Result<(), CompileIncomplete>;
74 }
75
76 pub struct DummyTransCrate;
77
78 impl TransCrate for DummyTransCrate {
79     fn metadata_loader(&self) -> Box<MetadataLoader> {
80         box DummyMetadataLoader(())
81     }
82
83     fn provide(&self, _providers: &mut Providers) {
84         bug!("DummyTransCrate::provide");
85     }
86
87     fn provide_extern(&self, _providers: &mut Providers) {
88         bug!("DummyTransCrate::provide_extern");
89     }
90
91     fn trans_crate<'a, 'tcx>(
92         &self,
93         _tcx: TyCtxt<'a, 'tcx, 'tcx>,
94         _rx: mpsc::Receiver<Box<Any + Send>>
95     ) -> Box<Any> {
96         bug!("DummyTransCrate::trans_crate");
97     }
98
99     fn join_trans_and_link(
100         &self,
101         _trans: Box<Any>,
102         _sess: &Session,
103         _dep_graph: &DepGraph,
104         _outputs: &OutputFilenames,
105     ) -> Result<(), CompileIncomplete> {
106         bug!("DummyTransCrate::join_trans_and_link");
107     }
108 }
109
110 pub struct DummyMetadataLoader(());
111
112 impl MetadataLoader for DummyMetadataLoader {
113     fn get_rlib_metadata(
114         &self,
115         _target: &Target,
116         _filename: &Path
117     ) -> Result<ErasedBoxRef<[u8]>, String> {
118         bug!("DummyMetadataLoader::get_rlib_metadata");
119     }
120
121     fn get_dylib_metadata(
122         &self,
123         _target: &Target,
124         _filename: &Path
125     ) -> Result<ErasedBoxRef<[u8]>, String> {
126         bug!("DummyMetadataLoader::get_dylib_metadata");
127     }
128 }
129
130 pub struct NoLlvmMetadataLoader;
131
132 impl MetadataLoader for NoLlvmMetadataLoader {
133     fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<ErasedBoxRef<[u8]>, String> {
134         let file = File::open(filename)
135             .map_err(|e| format!("metadata file open err: {:?}", e))?;
136         let mut archive = Archive::new(file);
137
138         while let Some(entry_result) = archive.next_entry() {
139             let mut entry = entry_result
140                 .map_err(|e| format!("metadata section read err: {:?}", e))?;
141             if entry.header().identifier() == "rust.metadata.bin" {
142                 let mut buf = Vec::new();
143                 io::copy(&mut entry, &mut buf).unwrap();
144                 let buf: OwningRef<Vec<u8>, [u8]> = OwningRef::new(buf).into();
145                 return Ok(buf.map_owner_box().erase_owner());
146             }
147         }
148
149         Err("Couldnt find metadata section".to_string())
150     }
151
152     fn get_dylib_metadata(
153         &self,
154         _target: &Target,
155         _filename: &Path,
156     ) -> Result<ErasedBoxRef<[u8]>, String> {
157         // FIXME: Support reading dylibs from llvm enabled rustc
158         self.get_rlib_metadata(_target, _filename)
159     }
160 }
161
162 pub struct MetadataOnlyTransCrate(());
163 pub struct OngoingCrateTranslation {
164     metadata: EncodedMetadata,
165     metadata_version: Vec<u8>,
166     crate_name: Symbol,
167 }
168
169 impl MetadataOnlyTransCrate {
170     pub fn new(sess: &Session) -> Box<TransCrate> {
171         for cty in sess.opts.crate_types.iter() {
172             match *cty {
173                 CrateType::CrateTypeRlib | CrateType::CrateTypeDylib |
174                 CrateType::CrateTypeExecutable => {},
175                 _ => {
176                     sess.parse_sess.span_diagnostic.warn(
177                         &format!("LLVM unsupported, so output type {} is not supported", cty)
178                     );
179                 },
180             }
181         }
182
183         box MetadataOnlyTransCrate(())
184     }
185 }
186
187 impl TransCrate for MetadataOnlyTransCrate {
188     fn metadata_loader(&self) -> Box<MetadataLoader> {
189         box NoLlvmMetadataLoader
190     }
191
192     fn provide(&self, providers: &mut Providers) {
193         ::symbol_names::provide(providers);
194     }
195     fn provide_extern(&self, _providers: &mut Providers) {}
196
197     fn trans_crate<'a, 'tcx>(
198         &self,
199         tcx: TyCtxt<'a, 'tcx, 'tcx>,
200         _rx: mpsc::Receiver<Box<Any + Send>>
201     ) -> Box<Any> {
202         use rustc_mir::monomorphize::item::MonoItem;
203
204         ::check_for_rustc_errors_attr(tcx);
205         ::symbol_names_test::report_symbol_names(tcx);
206         ::rustc_incremental::assert_dep_graph(tcx);
207         ::rustc_incremental::assert_module_sources::assert_module_sources(tcx);
208         ::rustc_mir::monomorphize::assert_symbols_are_distinct(tcx,
209             collector::collect_crate_mono_items(
210                 tcx,
211                 collector::MonoItemCollectionMode::Eager
212             ).0.iter()
213         );
214         ::rustc::middle::dependency_format::calculate(tcx);
215         let _ = tcx.link_args(LOCAL_CRATE);
216         let _ = tcx.native_libraries(LOCAL_CRATE);
217         for trans_item in
218             collector::collect_crate_mono_items(
219                 tcx,
220                 collector::MonoItemCollectionMode::Eager
221             ).0 {
222             match trans_item {
223                 MonoItem::Fn(inst) => {
224                     let def_id = inst.def_id();
225                     if def_id.is_local()  {
226                         let _ = tcx.export_name(def_id);
227                         let _ = tcx.contains_extern_indicator(def_id);
228                         let _ = inst.def.is_inline(tcx);
229                         let attrs = inst.def.attrs(tcx);
230                         let _ =
231                             ::syntax::attr::find_inline_attr(Some(tcx.sess.diagnostic()), &attrs);
232                     }
233                 }
234                 _ => {}
235             }
236         }
237         tcx.sess.abort_if_errors();
238
239         let link_meta = build_link_meta(tcx.crate_hash(LOCAL_CRATE));
240         let exported_symbols = ::find_exported_symbols(tcx);
241         let metadata = tcx.encode_metadata(&link_meta, &exported_symbols);
242
243         box OngoingCrateTranslation {
244             metadata: metadata,
245             metadata_version: tcx.metadata_encoding_version().to_vec(),
246             crate_name: tcx.crate_name(LOCAL_CRATE),
247         }
248     }
249
250     fn join_trans_and_link(
251         &self,
252         trans: Box<Any>,
253         sess: &Session,
254         _dep_graph: &DepGraph,
255         outputs: &OutputFilenames,
256     ) -> Result<(), CompileIncomplete> {
257         let trans = trans.downcast::<OngoingCrateTranslation>()
258             .expect("Expected MetadataOnlyTransCrate's OngoingCrateTranslation, found Box<Any>");
259         for &crate_type in sess.opts.crate_types.iter() {
260             if crate_type != CrateType::CrateTypeRlib && crate_type != CrateType::CrateTypeDylib {
261                 continue;
262             }
263             let output_name =
264                 out_filename(sess, crate_type, &outputs, &trans.crate_name.as_str());
265             let mut compressed = trans.metadata_version.clone();
266             let metadata = if crate_type == CrateType::CrateTypeDylib {
267                 DeflateEncoder::new(&mut compressed, Compression::fast())
268                     .write_all(&trans.metadata.raw_data)
269                     .unwrap();
270                 &compressed
271             } else {
272                 &trans.metadata.raw_data
273             };
274             let mut builder = Builder::new(File::create(&output_name).unwrap());
275             let header = Header::new("rust.metadata.bin".to_string(), metadata.len() as u64);
276             builder.append(&header, Cursor::new(metadata)).unwrap();
277         }
278
279         sess.abort_if_errors();
280         if !sess.opts.crate_types.contains(&CrateType::CrateTypeRlib)
281             && !sess.opts.crate_types.contains(&CrateType::CrateTypeDylib)
282             // Don't error when running under compiletest
283             && ::std::env::var("RUSTC_COMPILETEST") != Ok("1".to_string())
284         {
285             sess.fatal("Executables are not supported by the metadata-only backend.");
286         }
287         Ok(())
288     }
289 }