Allow linking to a proc macro on the target in metadata and still use a host proc macro to execute them
This commit is contained in:
parent
97431a4090
commit
c3c1c8d4e0
4 changed files with 122 additions and 56 deletions
|
@ -1232,6 +1232,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
|||
Use with RUST_REGION_GRAPH=help for more info"),
|
||||
parse_only: bool = (false, parse_bool, [UNTRACKED],
|
||||
"parse only; do not compile, assemble, or link"),
|
||||
dual_proc_macros: bool = (false, parse_bool, [TRACKED],
|
||||
"load proc macros for both target and host, but only link to the target"),
|
||||
no_codegen: bool = (false, parse_bool, [TRACKED],
|
||||
"run all passes except codegen; no output"),
|
||||
treat_err_as_bug: bool = (false, parse_bool, [TRACKED],
|
||||
|
|
|
@ -18,6 +18,7 @@ pub enum FileMatch {
|
|||
|
||||
// A module for searching for libraries
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FileSearch<'a> {
|
||||
sysroot: &'a Path,
|
||||
triple: &'a str,
|
||||
|
|
|
@ -188,13 +188,15 @@ impl<'a> CrateLoader<'a> {
|
|||
});
|
||||
}
|
||||
|
||||
fn register_crate(&mut self,
|
||||
root: &Option<CratePaths>,
|
||||
ident: Symbol,
|
||||
span: Span,
|
||||
lib: Library,
|
||||
dep_kind: DepKind)
|
||||
-> (CrateNum, Lrc<cstore::CrateMetadata>) {
|
||||
fn register_crate(
|
||||
&mut self,
|
||||
host_lib: Option<Library>,
|
||||
root: &Option<CratePaths>,
|
||||
ident: Symbol,
|
||||
span: Span,
|
||||
lib: Library,
|
||||
dep_kind: DepKind
|
||||
) -> (CrateNum, Lrc<cstore::CrateMetadata>) {
|
||||
let crate_root = lib.metadata.get_root();
|
||||
info!("register crate `extern crate {} as {}`", crate_root.name, ident);
|
||||
self.verify_no_symbol_conflicts(span, &crate_root);
|
||||
|
@ -222,7 +224,16 @@ impl<'a> CrateLoader<'a> {
|
|||
let dependencies: Vec<CrateNum> = cnum_map.iter().cloned().collect();
|
||||
|
||||
let proc_macros = crate_root.proc_macro_decls_static.map(|_| {
|
||||
self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span)
|
||||
if self.sess.opts.debugging_opts.dual_proc_macros {
|
||||
let host_lib = host_lib.unwrap();
|
||||
self.load_derive_macros(
|
||||
&host_lib.metadata.get_root(),
|
||||
host_lib.dylib.clone().map(|p| p.0),
|
||||
span
|
||||
)
|
||||
} else {
|
||||
self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span)
|
||||
}
|
||||
});
|
||||
|
||||
let def_path_table = record_time(&self.sess.perf_stats.decode_def_path_tables_time, || {
|
||||
|
@ -269,6 +280,61 @@ impl<'a> CrateLoader<'a> {
|
|||
(cnum, cmeta)
|
||||
}
|
||||
|
||||
fn load_proc_macro<'b> (
|
||||
&mut self,
|
||||
locate_ctxt: &mut locator::Context<'b>,
|
||||
path_kind: PathKind,
|
||||
) -> Option<(LoadResult, Option<Library>)>
|
||||
where
|
||||
'a: 'b
|
||||
{
|
||||
// Use a new locator Context so trying to load a proc macro doesn't affect the error
|
||||
// message we emit
|
||||
let mut proc_macro_locator = locate_ctxt.clone();
|
||||
|
||||
// Try to load a proc macro
|
||||
proc_macro_locator.is_proc_macro = Some(true);
|
||||
|
||||
// Load the proc macro crate for the target
|
||||
let (locator, target_result) = if self.sess.opts.debugging_opts.dual_proc_macros {
|
||||
proc_macro_locator.reset();
|
||||
let result = match self.load(&mut proc_macro_locator)? {
|
||||
LoadResult::Previous(cnum) => return Some((LoadResult::Previous(cnum), None)),
|
||||
LoadResult::Loaded(library) => Some(LoadResult::Loaded(library))
|
||||
};
|
||||
// Don't look for a matching hash when looking for the host crate.
|
||||
// It won't be the same as the target crate hash
|
||||
locate_ctxt.hash = None;
|
||||
// Use the locate_ctxt when looking for the host proc macro crate, as that is required
|
||||
// so we want it to affect the error message
|
||||
(locate_ctxt, result)
|
||||
} else {
|
||||
(&mut proc_macro_locator, None)
|
||||
};
|
||||
|
||||
// Load the proc macro crate for the host
|
||||
|
||||
locator.reset();
|
||||
locator.is_proc_macro = Some(true);
|
||||
locator.target = &self.sess.host;
|
||||
locator.triple = TargetTriple::from_triple(config::host_triple());
|
||||
locator.filesearch = self.sess.host_filesearch(path_kind);
|
||||
|
||||
let host_result = self.load(locator)?;
|
||||
|
||||
Some(if self.sess.opts.debugging_opts.dual_proc_macros {
|
||||
let host_result = match host_result {
|
||||
LoadResult::Previous(..) => {
|
||||
panic!("host and target proc macros must be loaded in lock-step")
|
||||
}
|
||||
LoadResult::Loaded(library) => library
|
||||
};
|
||||
(target_result.unwrap(), Some(host_result))
|
||||
} else {
|
||||
(host_result, None)
|
||||
})
|
||||
}
|
||||
|
||||
fn resolve_crate<'b>(
|
||||
&'b mut self,
|
||||
root: &'b Option<CratePaths>,
|
||||
|
@ -281,53 +347,39 @@ impl<'a> CrateLoader<'a> {
|
|||
mut dep_kind: DepKind,
|
||||
) -> Result<(CrateNum, Lrc<cstore::CrateMetadata>), LoadError<'b>> {
|
||||
info!("resolving crate `extern crate {} as {}`", name, ident);
|
||||
let mut locate_ctxt = locator::Context {
|
||||
sess: self.sess,
|
||||
span,
|
||||
ident,
|
||||
crate_name: name,
|
||||
hash: hash.map(|a| &*a),
|
||||
extra_filename: extra_filename,
|
||||
filesearch: self.sess.target_filesearch(path_kind),
|
||||
target: &self.sess.target.target,
|
||||
triple: self.sess.opts.target_triple.clone(),
|
||||
root,
|
||||
rejected_via_hash: vec![],
|
||||
rejected_via_triple: vec![],
|
||||
rejected_via_kind: vec![],
|
||||
rejected_via_version: vec![],
|
||||
rejected_via_filename: vec![],
|
||||
should_match_name: true,
|
||||
is_proc_macro: Some(false),
|
||||
metadata_loader: &*self.cstore.metadata_loader,
|
||||
};
|
||||
|
||||
let result = if let Some(cnum) = self.existing_match(name, hash, path_kind) {
|
||||
LoadResult::Previous(cnum)
|
||||
(LoadResult::Previous(cnum), None)
|
||||
} else {
|
||||
info!("falling back to a load");
|
||||
let mut locate_ctxt = locator::Context {
|
||||
sess: self.sess,
|
||||
span,
|
||||
ident,
|
||||
crate_name: name,
|
||||
hash: hash.map(|a| &*a),
|
||||
extra_filename: extra_filename,
|
||||
filesearch: self.sess.target_filesearch(path_kind),
|
||||
target: &self.sess.target.target,
|
||||
triple: &self.sess.opts.target_triple,
|
||||
root,
|
||||
rejected_via_hash: vec![],
|
||||
rejected_via_triple: vec![],
|
||||
rejected_via_kind: vec![],
|
||||
rejected_via_version: vec![],
|
||||
rejected_via_filename: vec![],
|
||||
should_match_name: true,
|
||||
is_proc_macro: Some(false),
|
||||
metadata_loader: &*self.cstore.metadata_loader,
|
||||
};
|
||||
|
||||
self.load(&mut locate_ctxt).or_else(|| {
|
||||
self.load(&mut locate_ctxt).map(|r| (r, None)).or_else(|| {
|
||||
dep_kind = DepKind::UnexportedMacrosOnly;
|
||||
|
||||
let mut proc_macro_locator = locator::Context {
|
||||
target: &self.sess.host,
|
||||
triple: &TargetTriple::from_triple(config::host_triple()),
|
||||
filesearch: self.sess.host_filesearch(path_kind),
|
||||
rejected_via_hash: vec![],
|
||||
rejected_via_triple: vec![],
|
||||
rejected_via_kind: vec![],
|
||||
rejected_via_version: vec![],
|
||||
rejected_via_filename: vec![],
|
||||
is_proc_macro: Some(true),
|
||||
..locate_ctxt
|
||||
};
|
||||
|
||||
self.load(&mut proc_macro_locator)
|
||||
self.load_proc_macro(&mut locate_ctxt, path_kind)
|
||||
}).ok_or_else(move || LoadError::LocatorError(locate_ctxt))?
|
||||
};
|
||||
|
||||
match result {
|
||||
LoadResult::Previous(cnum) => {
|
||||
(LoadResult::Previous(cnum), None) => {
|
||||
let data = self.cstore.get_crate_data(cnum);
|
||||
if data.root.proc_macro_decls_static.is_some() {
|
||||
dep_kind = DepKind::UnexportedMacrosOnly;
|
||||
|
@ -337,9 +389,10 @@ impl<'a> CrateLoader<'a> {
|
|||
});
|
||||
Ok((cnum, data))
|
||||
}
|
||||
LoadResult::Loaded(library) => {
|
||||
Ok(self.register_crate(root, ident, span, library, dep_kind))
|
||||
(LoadResult::Loaded(library), host_library) => {
|
||||
Ok(self.register_crate(host_library, root, ident, span, library, dep_kind))
|
||||
}
|
||||
_ => panic!()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -355,7 +408,7 @@ impl<'a> CrateLoader<'a> {
|
|||
// don't want to match a host crate against an equivalent target one
|
||||
// already loaded.
|
||||
let root = library.metadata.get_root();
|
||||
if locate_ctxt.triple == &self.sess.opts.target_triple {
|
||||
if locate_ctxt.triple == self.sess.opts.target_triple {
|
||||
let mut result = LoadResult::Loaded(library);
|
||||
self.cstore.iter_crate_data(|cnum, data| {
|
||||
if data.root.name == root.name && root.hash == data.root.hash {
|
||||
|
@ -451,9 +504,9 @@ impl<'a> CrateLoader<'a> {
|
|||
fn read_extension_crate(&mut self, span: Span, orig_name: Symbol, rename: Symbol)
|
||||
-> ExtensionCrate {
|
||||
info!("read extension crate `extern crate {} as {}`", orig_name, rename);
|
||||
let target_triple = &self.sess.opts.target_triple;
|
||||
let target_triple = self.sess.opts.target_triple.clone();
|
||||
let host_triple = TargetTriple::from_triple(config::host_triple());
|
||||
let is_cross = target_triple != &host_triple;
|
||||
let is_cross = target_triple != host_triple;
|
||||
let mut target_only = false;
|
||||
let mut locate_ctxt = locator::Context {
|
||||
sess: self.sess,
|
||||
|
@ -464,7 +517,7 @@ impl<'a> CrateLoader<'a> {
|
|||
extra_filename: None,
|
||||
filesearch: self.sess.host_filesearch(PathKind::Crate),
|
||||
target: &self.sess.host,
|
||||
triple: &host_triple,
|
||||
triple: host_triple,
|
||||
root: &None,
|
||||
rejected_via_hash: vec![],
|
||||
rejected_via_triple: vec![],
|
||||
|
|
|
@ -244,11 +244,13 @@ use rustc_data_structures::owning_ref::OwningRef;
|
|||
|
||||
use log::{debug, info, warn};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CrateMismatch {
|
||||
path: PathBuf,
|
||||
got: String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Context<'a> {
|
||||
pub sess: &'a Session,
|
||||
pub span: Span,
|
||||
|
@ -258,7 +260,7 @@ pub struct Context<'a> {
|
|||
pub extra_filename: Option<&'a str>,
|
||||
// points to either self.sess.target.target or self.sess.host, must match triple
|
||||
pub target: &'a Target,
|
||||
pub triple: &'a TargetTriple,
|
||||
pub triple: TargetTriple,
|
||||
pub filesearch: FileSearch<'a>,
|
||||
pub root: &'a Option<CratePaths>,
|
||||
pub rejected_via_hash: Vec<CrateMismatch>,
|
||||
|
@ -302,6 +304,14 @@ impl CratePaths {
|
|||
}
|
||||
|
||||
impl<'a> Context<'a> {
|
||||
pub fn reset(&mut self) {
|
||||
self.rejected_via_hash.clear();
|
||||
self.rejected_via_triple.clear();
|
||||
self.rejected_via_kind.clear();
|
||||
self.rejected_via_version.clear();
|
||||
self.rejected_via_filename.clear();
|
||||
}
|
||||
|
||||
pub fn maybe_load_library_crate(&mut self) -> Option<Library> {
|
||||
let mut seen_paths = FxHashSet::default();
|
||||
match self.extra_filename {
|
||||
|
@ -399,7 +409,7 @@ impl<'a> Context<'a> {
|
|||
add);
|
||||
|
||||
if (self.ident == "std" || self.ident == "core")
|
||||
&& self.triple != &TargetTriple::from_triple(config::host_triple()) {
|
||||
&& self.triple != TargetTriple::from_triple(config::host_triple()) {
|
||||
err.note(&format!("the `{}` target may not be installed", self.triple));
|
||||
}
|
||||
err.span_label(self.span, "can't find crate");
|
||||
|
@ -718,7 +728,7 @@ impl<'a> Context<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
if &root.triple != self.triple {
|
||||
if root.triple != self.triple {
|
||||
info!("Rejecting via crate triple: expected {} got {}",
|
||||
self.triple,
|
||||
root.triple);
|
||||
|
|
Loading…
Reference in a new issue