Skip to content

Commit 9a58016

Browse files
committed
Put metadata in import library when building a dylib with MSVC
Remove metadata objects from rlib import libraries Fix tidy issues Don't try to remove metadata before linking Undo change to dylib linking
1 parent 8a1ce40 commit 9a58016

File tree

5 files changed

+79
-20
lines changed

5 files changed

+79
-20
lines changed

src/librustc_metadata/locator.rs

+23-15
Original file line numberDiff line numberDiff line change
@@ -862,33 +862,41 @@ fn get_metadata_section_imp(target: &Target,
862862
if !filename.exists() {
863863
return Err(format!("no such file: '{}'", filename.display()));
864864
}
865-
if flavor == CrateFlavor::Rlib {
865+
if flavor == CrateFlavor::Rmeta {
866+
let mut file = File::open(filename).map_err(|_|
867+
format!("could not open file: '{}'", filename.display()))?;
868+
let mut buf = vec![];
869+
file.read_to_end(&mut buf).map_err(|_|
870+
format!("failed to read rlib metadata: '{}'", filename.display()))?;
871+
let blob = MetadataBlob::Raw(buf);
872+
verify_decompressed_encoding_version(&blob, filename)?;
873+
return Ok(blob);
874+
} else if flavor == CrateFlavor::Rlib || target.options.is_like_msvc {
875+
// With MSVC, DLLs do not contain metadata. Instead, the import library
876+
// for the DLL is itself an Rlib.
877+
let rlib_filename = if flavor == CrateFlavor::Rlib {
878+
filename.to_owned()
879+
} else {
880+
filename.with_extension("dll.rlib")
881+
};
882+
866883
// Use ArchiveRO for speed here, it's backed by LLVM and uses mmap
867884
// internally to read the file. We also avoid even using a memcpy by
868885
// just keeping the archive along while the metadata is in use.
869-
let archive = match ArchiveRO::open(filename) {
886+
let archive = match ArchiveRO::open(&rlib_filename) {
870887
Some(ar) => ar,
871888
None => {
872-
debug!("llvm didn't like `{}`", filename.display());
873-
return Err(format!("failed to read rlib metadata: '{}'", filename.display()));
889+
debug!("llvm didn't like `{}`", rlib_filename.display());
890+
return Err(format!("failed to read rlib metadata: '{}'", rlib_filename.display()));
874891
}
875892
};
876893
return match ArchiveMetadata::new(archive).map(|ar| MetadataBlob::Archive(ar)) {
877-
None => Err(format!("failed to read rlib metadata: '{}'", filename.display())),
894+
None => Err(format!("failed to read rlib metadata: '{}'", rlib_filename.display())),
878895
Some(blob) => {
879-
verify_decompressed_encoding_version(&blob, filename)?;
896+
verify_decompressed_encoding_version(&blob, &rlib_filename)?;
880897
Ok(blob)
881898
}
882899
};
883-
} else if flavor == CrateFlavor::Rmeta {
884-
let mut file = File::open(filename).map_err(|_|
885-
format!("could not open file: '{}'", filename.display()))?;
886-
let mut buf = vec![];
887-
file.read_to_end(&mut buf).map_err(|_|
888-
format!("failed to read rlib metadata: '{}'", filename.display()))?;
889-
let blob = MetadataBlob::Raw(buf);
890-
verify_decompressed_encoding_version(&blob, filename)?;
891-
return Ok(blob);
892900
}
893901
unsafe {
894902
let buf = common::path2cstr(filename);

src/librustc_trans/back/link.rs

+48-1
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,29 @@ fn link_natively(sess: &Session,
777777
}
778778
info!("linker stderr:\n{}", escape_string(&prog.stderr[..]));
779779
info!("linker stdout:\n{}", escape_string(&prog.stdout[..]));
780+
781+
782+
// When linking a dynamic library with MSVC, we put the metadata
783+
// in the import library, so we add that here.
784+
if crate_type == config::CrateTypeDylib ||
785+
crate_type == config::CrateTypeProcMacro {
786+
if sess.target.target.options.is_like_msvc {
787+
// Find the import library and add the metadata to it
788+
let ref imp_lib_name = out_filename.with_extension("dll.lib");
789+
let ref imp_rlib_name = out_filename.with_extension("dll.rlib");
790+
791+
// Import library may not exist if there were no exports
792+
if fs::metadata(imp_lib_name).is_ok() {
793+
add_metadata_to_existing_lib(sess, trans, Some(imp_lib_name),
794+
imp_rlib_name, tmpdir);
795+
// Remove plain lib file
796+
remove(sess, imp_lib_name);
797+
} else {
798+
add_metadata_to_existing_lib(sess, trans, None, imp_rlib_name, tmpdir);
799+
}
800+
}
801+
}
802+
780803
},
781804
Err(e) => {
782805
sess.struct_err(&format!("could not exec the linker `{}`: {}", pname, e))
@@ -803,6 +826,22 @@ fn link_natively(sess: &Session,
803826
}
804827
}
805828

829+
fn add_metadata_to_existing_lib(sess: &Session,
830+
trans: &CrateTranslation,
831+
input_lib: Option<&Path>,
832+
output_rlib: &Path,
833+
tmpdir: &Path) {
834+
835+
info!("adding metadata to {:?} to build {:?}", input_lib, output_rlib);
836+
let mut ab = ArchiveBuilder::new(archive_config(sess, output_rlib, input_lib));
837+
ab.update_symbols();
838+
839+
let metadata = tmpdir.join(sess.cstore.metadata_filename());
840+
emit_metadata(sess, trans, &metadata);
841+
ab.add_file(&metadata);
842+
ab.build();
843+
}
844+
806845
fn link_args(cmd: &mut Linker,
807846
sess: &Session,
808847
crate_type: config::CrateType,
@@ -844,7 +883,11 @@ fn link_args(cmd: &mut Linker,
844883
// object file, so we link that in here.
845884
if crate_type == config::CrateTypeDylib ||
846885
crate_type == config::CrateTypeProcMacro {
847-
cmd.add_object(&outputs.with_extension(METADATA_OBJ_NAME));
886+
// We store the metadata in the import library instead of the DLL
887+
// when targetting MSVC.
888+
if !sess.target.target.options.is_like_msvc {
889+
cmd.add_object(&outputs.with_extension(METADATA_OBJ_NAME));
890+
}
848891
}
849892

850893
// Try to strip as much out of the generated object by removing unused
@@ -1157,6 +1200,9 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
11571200
lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib)
11581201
});
11591202

1203+
// If we're not doing LTO, don't need to remove metadata, and don't
1204+
// want to skip specific object files, then we can take the fast path,
1205+
// and pass the library directly to the linker without modification.
11601206
if !sess.lto() && crate_type != config::CrateTypeDylib && !skip_native {
11611207
cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath));
11621208
return
@@ -1240,6 +1286,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
12401286
if let Some(dir) = parent {
12411287
cmd.include_path(&fix_windows_verbatim_for_gcc(dir));
12421288
}
1289+
12431290
let filestem = cratepath.file_stem().unwrap().to_str().unwrap();
12441291
cmd.link_rust_dylib(&unlib(&sess.target, filestem),
12451292
parent.unwrap_or(Path::new("")));

src/librustc_trans/back/linker.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ impl<'a> Linker for MsvcLinker<'a> {
353353
// `foo.lib` file if the dll doesn't actually export any symbols, so we
354354
// check to see if the file is there and just omit linking to it if it's
355355
// not present.
356-
let name = format!("{}.dll.lib", lib);
356+
let name = format!("{}.dll.rlib", lib);
357357
if fs::metadata(&path.join(&name)).is_ok() {
358358
self.cmd.arg(name);
359359
}

src/librustc_trans/back/symbol_export.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,12 @@ impl ExportedSymbols {
7171
}
7272

7373
if scx.sess().crate_types.borrow().contains(&config::CrateTypeDylib) {
74-
local_crate.push((scx.metadata_symbol_name(),
75-
SymbolExportLevel::Rust));
74+
// When targetting MSVC, metadata is stored in import library
75+
// so don't add an exported symbol for it.
76+
if !scx.sess().target.target.options.is_like_msvc {
77+
local_crate.push((scx.metadata_symbol_name(),
78+
SymbolExportLevel::Rust));
79+
}
7680
}
7781

7882
let mut exports = FxHashMap();

0 commit comments

Comments
 (0)