Skip to content

Commit 7f7343d

Browse files
committed
Read and write dylib metadata
1 parent 1fc1fbe commit 7f7343d

File tree

5 files changed

+210
-15
lines changed

5 files changed

+210
-15
lines changed

Cargo.lock

+113
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ tempfile = "3.0.7"
2727
env_logger = "0.6"
2828
gimli = { git = "https://github.com/gimli-rs/gimli.git" }
2929
indexmap = "1.0.2"
30+
object = "0.11.0"
3031

3132
# Uncomment to use local checkout of cranelift
3233
#[patch."https://github.com/CraneStation/cranelift.git"]

src/lib.rs

+30-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![feature(rustc_private, never_type, decl_macro)]
22
#![allow(intra_doc_link_resolution_failure)]
33

4+
extern crate flate2;
45
extern crate log;
56
extern crate rustc;
67
extern crate rustc_allocator;
@@ -325,6 +326,34 @@ impl CodegenBackend for CraneliftCodegenBackend {
325326
rustc_incremental::save_dep_graph(tcx);
326327
rustc_incremental::finalize_session_directory(tcx.sess, tcx.crate_hash(LOCAL_CRATE));
327328

329+
let metadata_module = {
330+
use rustc::mir::mono::CodegenUnitNameBuilder;
331+
332+
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
333+
let metadata_cgu_name = cgu_name_builder
334+
.build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata"))
335+
.as_str()
336+
.to_string();
337+
338+
let mut metadata_artifact = faerie::Artifact::new(build_isa(tcx.sess).triple().clone(), metadata_cgu_name.clone());
339+
crate::metadata::write_metadata(tcx, &mut metadata_artifact);
340+
341+
let tmp_file = tcx
342+
.output_filenames(LOCAL_CRATE)
343+
.temp_path(OutputType::Metadata, Some(&metadata_cgu_name));
344+
345+
let obj = metadata_artifact.emit().unwrap();
346+
std::fs::write(&tmp_file, obj).unwrap();
347+
348+
CompiledModule {
349+
name: metadata_cgu_name,
350+
kind: ModuleKind::Metadata,
351+
object: Some(tmp_file),
352+
bytecode: None,
353+
bytecode_compressed: None,
354+
}
355+
};
356+
328357
return Box::new(CodegenResults {
329358
crate_name: tcx.crate_name(LOCAL_CRATE),
330359
modules: vec![emit_module(
@@ -343,13 +372,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
343372
} else {
344373
None
345374
},
346-
metadata_module: CompiledModule {
347-
name: "dummy_metadata".to_string(),
348-
kind: ModuleKind::Metadata,
349-
object: None,
350-
bytecode: None,
351-
bytecode_compressed: None,
352-
},
375+
metadata_module,
353376
crate_hash: tcx.crate_hash(LOCAL_CRATE),
354377
metadata,
355378
windows_subsystem: None, // Windows is not yet supported

src/metadata.rs

+65-7
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
1-
use rustc::middle::cstore::MetadataLoader;
2-
use rustc_data_structures::owning_ref::{self, OwningRef};
3-
use rustc_data_structures::rustc_erase_owner;
41
use std::fs::File;
52
use std::path::Path;
63

4+
use rustc::session::config;
5+
use rustc::ty::TyCtxt;
6+
use rustc::middle::cstore::{EncodedMetadata, MetadataLoader};
7+
use rustc_data_structures::owning_ref::{self, OwningRef};
8+
use rustc_data_structures::rustc_erase_owner;
9+
use rustc_target::spec::Target;
10+
711
pub const METADATA_FILENAME: &str = "rust.metadata.bin";
812

913
pub struct CraneliftMetadataLoader;
1014

1115
impl MetadataLoader for CraneliftMetadataLoader {
1216
fn get_rlib_metadata(
1317
&self,
14-
_target: &crate::rustc_target::spec::Target,
18+
_target: &Target,
1519
path: &Path,
1620
) -> Result<owning_ref::ErasedBoxRef<[u8]>, String> {
1721
let mut archive = ar::Archive::new(File::open(path).map_err(|e| format!("{:?}", e))?);
@@ -32,9 +36,63 @@ impl MetadataLoader for CraneliftMetadataLoader {
3236

3337
fn get_dylib_metadata(
3438
&self,
35-
_target: &crate::rustc_target::spec::Target,
36-
_path: &Path,
39+
_target: &Target,
40+
path: &Path,
3741
) -> Result<owning_ref::ErasedBoxRef<[u8]>, String> {
38-
Err("dylib metadata loading is not yet supported".to_string())
42+
println!("abc");
43+
use object::Object;
44+
let file = std::fs::read(path).map_err(|e| format!("read:{:?}", e))?;
45+
let file = object::File::parse(&file).map_err(|e| format!("parse: {:?}", e))?;
46+
let buf = file.section_data_by_name(".rustc").ok_or("no .rustc section")?.into_owned();
47+
let buf: OwningRef<Vec<u8>, [u8]> = OwningRef::new(buf).into();
48+
Ok(rustc_erase_owner!(buf.map_owner_box()))
3949
}
4050
}
51+
52+
// Adapted from https://github.com/rust-lang/rust/blob/da573206f87b5510de4b0ee1a9c044127e409bd3/src/librustc_codegen_llvm/base.rs#L47-L112
53+
pub fn write_metadata<'a, 'gcx>(
54+
tcx: TyCtxt<'a, 'gcx, 'gcx>,
55+
artifact: &mut faerie::Artifact
56+
) -> EncodedMetadata {
57+
use std::io::Write;
58+
use flate2::Compression;
59+
use flate2::write::DeflateEncoder;
60+
61+
#[derive(PartialEq, Eq, PartialOrd, Ord)]
62+
enum MetadataKind {
63+
None,
64+
Uncompressed,
65+
Compressed
66+
}
67+
68+
let kind = tcx.sess.crate_types.borrow().iter().map(|ty| {
69+
match *ty {
70+
config::CrateType::Executable |
71+
config::CrateType::Staticlib |
72+
config::CrateType::Cdylib => MetadataKind::None,
73+
74+
config::CrateType::Rlib => MetadataKind::Uncompressed,
75+
76+
config::CrateType::Dylib |
77+
config::CrateType::ProcMacro => MetadataKind::Compressed,
78+
}
79+
}).max().unwrap_or(MetadataKind::None);
80+
81+
if kind == MetadataKind::None {
82+
return EncodedMetadata::new();
83+
}
84+
85+
let metadata = tcx.encode_metadata();
86+
if kind == MetadataKind::Uncompressed {
87+
return metadata;
88+
}
89+
90+
assert!(kind == MetadataKind::Compressed);
91+
let mut compressed = tcx.metadata_encoding_version();
92+
DeflateEncoder::new(&mut compressed, Compression::fast())
93+
.write_all(&metadata.raw_data).unwrap();
94+
95+
artifact.declare_with(".rustc", faerie::Decl::debug_section(), compressed).unwrap();
96+
97+
metadata
98+
}

test.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ rm -r target/out || true
55
mkdir -p target/out/clif
66

77
echo "[BUILD] mini_core"
8-
$RUSTC example/mini_core.rs --crate-name mini_core --crate-type lib
8+
$RUSTC example/mini_core.rs --crate-name mini_core --crate-type dylib
99

1010
echo "[BUILD] example"
1111
$RUSTC example/example.rs --crate-type lib

0 commit comments

Comments
 (0)