Skip to content

Commit

Permalink
Auto merge of #32828 - vadimcn:symlinks, r=alexcrichton
Browse files Browse the repository at this point in the history
Do not rely on file extensions after path canonicalization.

Rustc does not recognize libraries which are symlinked to files having extension other than .rlib. The problem is that find_library_crate calls fs::canonicalize on found library paths, but then the resulting path is passed to get_metadata_section, which assumes it will end in ".rlib" if it's an rlib (from https://internals.rust-lang.org/t/is-library-path-canonicalization-worth-it/3206).

cc #29433
  • Loading branch information
bors committed Apr 13, 2016
2 parents 6136a86 + cc3b6f2 commit 525aa61
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 11 deletions.
40 changes: 29 additions & 11 deletions src/librustc_metadata/loader.rs
Expand Up @@ -231,6 +231,7 @@ use rustc_back::target::Target;

use std::cmp;
use std::collections::HashMap;
use std::fmt;
use std::fs;
use std::io::prelude::*;
use std::io;
Expand Down Expand Up @@ -283,6 +284,21 @@ pub struct CratePaths {

pub const METADATA_FILENAME: &'static str = "rust.metadata.bin";

#[derive(Copy, Clone, PartialEq)]
enum CrateFlavor {
Rlib,
Dylib
}

impl fmt::Display for CrateFlavor {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match *self {
CrateFlavor::Rlib => "rlib",
CrateFlavor::Dylib => "dylib"
})
}
}

impl CratePaths {
fn paths(&self) -> Vec<PathBuf> {
match (&self.dylib, &self.rlib) {
Expand Down Expand Up @@ -457,8 +473,8 @@ impl<'a> Context<'a> {
let mut libraries = Vec::new();
for (_hash, (rlibs, dylibs)) in candidates {
let mut metadata = None;
let rlib = self.extract_one(rlibs, "rlib", &mut metadata);
let dylib = self.extract_one(dylibs, "dylib", &mut metadata);
let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut metadata);
let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut metadata);
match metadata {
Some(metadata) => {
libraries.push(Library {
Expand Down Expand Up @@ -515,7 +531,7 @@ impl<'a> Context<'a> {
// read the metadata from it if `*slot` is `None`. If the metadata couldn't
// be read, it is assumed that the file isn't a valid rust library (no
// errors are emitted).
fn extract_one(&mut self, m: HashMap<PathBuf, PathKind>, flavor: &str,
fn extract_one(&mut self, m: HashMap<PathBuf, PathKind>, flavor: CrateFlavor,
slot: &mut Option<MetadataBlob>) -> Option<(PathBuf, PathKind)> {
let mut ret = None::<(PathBuf, PathKind)>;
let mut error = 0;
Expand All @@ -535,7 +551,7 @@ impl<'a> Context<'a> {
let mut err: Option<DiagnosticBuilder> = None;
for (lib, kind) in m {
info!("{} reading metadata from: {}", flavor, lib.display());
let metadata = match get_metadata_section(self.target, &lib) {
let metadata = match get_metadata_section(self.target, flavor, &lib) {
Ok(blob) => {
if self.crate_matches(blob.as_slice(), &lib) {
blob
Expand Down Expand Up @@ -702,8 +718,8 @@ impl<'a> Context<'a> {

// Extract the rlib/dylib pair.
let mut metadata = None;
let rlib = self.extract_one(rlibs, "rlib", &mut metadata);
let dylib = self.extract_one(dylibs, "dylib", &mut metadata);
let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut metadata);
let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut metadata);

if rlib.is_none() && dylib.is_none() { return None }
match metadata {
Expand Down Expand Up @@ -746,21 +762,21 @@ impl ArchiveMetadata {
}

// Just a small wrapper to time how long reading metadata takes.
fn get_metadata_section(target: &Target, filename: &Path)
fn get_metadata_section(target: &Target, flavor: CrateFlavor, filename: &Path)
-> Result<MetadataBlob, String> {
let start = Instant::now();
let ret = get_metadata_section_imp(target, filename);
let ret = get_metadata_section_imp(target, flavor, filename);
info!("reading {:?} => {:?}", filename.file_name().unwrap(),
start.elapsed());
return ret
}

fn get_metadata_section_imp(target: &Target, filename: &Path)
fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Path)
-> Result<MetadataBlob, String> {
if !filename.exists() {
return Err(format!("no such file: '{}'", filename.display()));
}
if filename.file_name().unwrap().to_str().unwrap().ends_with(".rlib") {
if flavor == CrateFlavor::Rlib {
// Use ArchiveRO for speed here, it's backed by LLVM and uses mmap
// internally to read the file. We also avoid even using a memcpy by
// just keeping the archive along while the metadata is in use.
Expand Down Expand Up @@ -864,7 +880,9 @@ pub fn read_meta_section_name(target: &Target) -> &'static str {
// A diagnostic function for dumping crate metadata to an output stream
pub fn list_file_metadata(target: &Target, path: &Path,
out: &mut io::Write) -> io::Result<()> {
match get_metadata_section(target, path) {
let filename = path.file_name().unwrap().to_str().unwrap();
let flavor = if filename.ends_with(".rlib") { CrateFlavor::Rlib } else { CrateFlavor::Dylib };
match get_metadata_section(target, flavor, path) {
Ok(bytes) => decoder::list_crate_metadata(bytes.as_slice(), out),
Err(msg) => {
write!(out, "{}\n", msg)
Expand Down
14 changes: 14 additions & 0 deletions src/test/run-make/symlinked-rlib/Makefile
@@ -0,0 +1,14 @@
-include ../tools.mk

# ignore windows: `ln` is actually `cp` on msys.
ifndef IS_WINDOWS

all:
$(RUSTC) foo.rs --crate-type=rlib -o $(TMPDIR)/foo.xxx
ln -nsf $(TMPDIR)/foo.xxx $(TMPDIR)/libfoo.rlib
$(RUSTC) bar.rs -L $(TMPDIR)

else
all:

endif
15 changes: 15 additions & 0 deletions src/test/run-make/symlinked-rlib/bar.rs
@@ -0,0 +1,15 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate foo;

fn main() {
foo::bar();
}
11 changes: 11 additions & 0 deletions src/test/run-make/symlinked-rlib/foo.rs
@@ -0,0 +1,11 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

pub fn bar() {}

0 comments on commit 525aa61

Please sign in to comment.