Use rustc version of dylib to choose which proc macro ABI to use
This commit is contained in:
parent
a8b0a91011
commit
39b8d10b93
@ -1,6 +1,8 @@
|
||||
//! Handles dynamic library loading for proc macro
|
||||
|
||||
use std::{
|
||||
convert::{TryFrom, TryInto},
|
||||
fmt,
|
||||
fs::File,
|
||||
io,
|
||||
path::{Path, PathBuf},
|
||||
@ -9,9 +11,16 @@
|
||||
use libloading::Library;
|
||||
use memmap2::Mmap;
|
||||
use object::Object;
|
||||
use proc_macro_api::ProcMacroKind;
|
||||
use proc_macro_api::{read_dylib_info, ProcMacroKind, RustCInfo};
|
||||
|
||||
use crate::{proc_macro::bridge, rustc_server::TokenStream};
|
||||
use crate::{
|
||||
proc_macro::bridge::{self as stable_bridge, client::ProcMacro as StableProcMacro},
|
||||
rustc_server::TokenStream as StableTokenStream,
|
||||
};
|
||||
use crate::{
|
||||
proc_macro_nightly::bridge::{self as nightly_bridge, client::ProcMacro as NightlyProcMacro},
|
||||
rustc_server_nightly::TokenStream as NightlyTokenStream,
|
||||
};
|
||||
|
||||
const NEW_REGISTRAR_SYMBOL: &str = "_rustc_proc_macro_decls_";
|
||||
|
||||
@ -74,26 +83,117 @@ fn load_library(file: &Path) -> Result<Library, libloading::Error> {
|
||||
unsafe { UnixLibrary::open(Some(file), RTLD_NOW | RTLD_DEEPBIND).map(|lib| lib.into()) }
|
||||
}
|
||||
|
||||
struct ProcMacroLibraryLibloading {
|
||||
// Hold the dylib to prevent it from unloading
|
||||
_lib: Library,
|
||||
exported_macros: Vec<bridge::client::ProcMacro>,
|
||||
enum ProcMacroABI {
|
||||
Stable,
|
||||
Nightly,
|
||||
}
|
||||
|
||||
impl TryFrom<RustCInfo> for ProcMacroABI {
|
||||
type Error = LoadProcMacroDylibError;
|
||||
|
||||
fn try_from(info: RustCInfo) -> Result<Self, Self::Error> {
|
||||
if info.version.0 < 1 {
|
||||
Err(LoadProcMacroDylibError::UnsupportedABI)
|
||||
} else if info.version.1 < 47 {
|
||||
Err(LoadProcMacroDylibError::UnsupportedABI)
|
||||
} else if info.version.1 < 54 {
|
||||
Ok(ProcMacroABI::Stable)
|
||||
} else {
|
||||
Ok(ProcMacroABI::Nightly)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum LoadProcMacroDylibError {
|
||||
Io(io::Error),
|
||||
UnsupportedABI,
|
||||
}
|
||||
|
||||
impl fmt::Display for LoadProcMacroDylibError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Io(e) => e.fmt(f),
|
||||
Self::UnsupportedABI => write!(f, "unsupported ABI version"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for LoadProcMacroDylibError {
|
||||
fn from(e: io::Error) -> Self {
|
||||
LoadProcMacroDylibError::Io(e)
|
||||
}
|
||||
}
|
||||
|
||||
enum ProcMacroLibraryLibloading {
|
||||
StableProcMacroLibrary {
|
||||
_lib: Library,
|
||||
exported_macros: Vec<crate::proc_macro::bridge::client::ProcMacro>,
|
||||
},
|
||||
NightlyProcMacroLibrary {
|
||||
_lib: Library,
|
||||
exported_macros: Vec<crate::proc_macro_nightly::bridge::client::ProcMacro>,
|
||||
},
|
||||
}
|
||||
|
||||
impl ProcMacroLibraryLibloading {
|
||||
fn open(file: &Path) -> io::Result<Self> {
|
||||
fn open(file: &Path) -> Result<Self, LoadProcMacroDylibError> {
|
||||
let symbol_name = find_registrar_symbol(file)?.ok_or_else(|| {
|
||||
invalid_data_err(format!("Cannot find registrar symbol in file {}", file.display()))
|
||||
})?;
|
||||
|
||||
let lib = load_library(file).map_err(invalid_data_err)?;
|
||||
let exported_macros = {
|
||||
let macros: libloading::Symbol<&&[bridge::client::ProcMacro]> =
|
||||
unsafe { lib.get(symbol_name.as_bytes()) }.map_err(invalid_data_err)?;
|
||||
macros.to_vec()
|
||||
};
|
||||
let version_info = read_dylib_info(file)?;
|
||||
let macro_abi: ProcMacroABI = version_info.try_into()?;
|
||||
|
||||
Ok(ProcMacroLibraryLibloading { _lib: lib, exported_macros })
|
||||
let lib = load_library(file).map_err(invalid_data_err)?;
|
||||
match macro_abi {
|
||||
ProcMacroABI::Stable => {
|
||||
let macros: libloading::Symbol<&&[crate::proc_macro::bridge::client::ProcMacro]> =
|
||||
unsafe { lib.get(symbol_name.as_bytes()) }.map_err(invalid_data_err)?;
|
||||
let macros_vec = macros.to_vec();
|
||||
Ok(ProcMacroLibraryLibloading::StableProcMacroLibrary {
|
||||
_lib: lib,
|
||||
exported_macros: macros_vec,
|
||||
})
|
||||
}
|
||||
ProcMacroABI::Nightly => {
|
||||
let macros: libloading::Symbol<
|
||||
&&[crate::proc_macro_nightly::bridge::client::ProcMacro],
|
||||
> = unsafe { lib.get(symbol_name.as_bytes()) }.map_err(invalid_data_err)?;
|
||||
let macros_vec = macros.to_vec();
|
||||
Ok(ProcMacroLibraryLibloading::NightlyProcMacroLibrary {
|
||||
_lib: lib,
|
||||
exported_macros: macros_vec,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PanicMessage {
|
||||
Stable(stable_bridge::PanicMessage),
|
||||
Nightly(nightly_bridge::PanicMessage),
|
||||
}
|
||||
|
||||
impl From<stable_bridge::PanicMessage> for PanicMessage {
|
||||
fn from(p: stable_bridge::PanicMessage) -> Self {
|
||||
PanicMessage::Stable(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<nightly_bridge::PanicMessage> for PanicMessage {
|
||||
fn from(p: nightly_bridge::PanicMessage) -> Self {
|
||||
PanicMessage::Nightly(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl PanicMessage {
|
||||
pub fn as_str(&self) -> Option<&str> {
|
||||
match self {
|
||||
Self::Stable(p) => p.as_str(),
|
||||
Self::Nightly(p) => p.as_str(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,7 +202,7 @@ pub struct Expander {
|
||||
}
|
||||
|
||||
impl Expander {
|
||||
pub fn new(lib: &Path) -> io::Result<Expander> {
|
||||
pub fn new(lib: &Path) -> Result<Expander, LoadProcMacroDylibError> {
|
||||
// Some libraries for dynamic loading require canonicalized path even when it is
|
||||
// already absolute
|
||||
let lib = lib.canonicalize()?;
|
||||
@ -119,69 +219,28 @@ pub fn expand(
|
||||
macro_name: &str,
|
||||
macro_body: &tt::Subtree,
|
||||
attributes: Option<&tt::Subtree>,
|
||||
) -> Result<tt::Subtree, bridge::PanicMessage> {
|
||||
let parsed_body = TokenStream::with_subtree(macro_body.clone());
|
||||
|
||||
let parsed_attributes = attributes
|
||||
.map_or(crate::rustc_server::TokenStream::new(), |attr| {
|
||||
TokenStream::with_subtree(attr.clone())
|
||||
});
|
||||
|
||||
for proc_macro in &self.inner.exported_macros {
|
||||
match proc_macro {
|
||||
bridge::client::ProcMacro::CustomDerive { trait_name, client, .. }
|
||||
if *trait_name == macro_name =>
|
||||
{
|
||||
let res = client.run(
|
||||
&crate::proc_macro::bridge::server::SameThread,
|
||||
crate::rustc_server::Rustc::default(),
|
||||
parsed_body,
|
||||
false,
|
||||
);
|
||||
return res.map(|it| it.into_subtree());
|
||||
}
|
||||
bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => {
|
||||
let res = client.run(
|
||||
&crate::proc_macro::bridge::server::SameThread,
|
||||
crate::rustc_server::Rustc::default(),
|
||||
parsed_body,
|
||||
false,
|
||||
);
|
||||
return res.map(|it| it.into_subtree());
|
||||
}
|
||||
bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => {
|
||||
let res = client.run(
|
||||
&crate::proc_macro::bridge::server::SameThread,
|
||||
crate::rustc_server::Rustc::default(),
|
||||
parsed_attributes,
|
||||
parsed_body,
|
||||
false,
|
||||
);
|
||||
return res.map(|it| it.into_subtree());
|
||||
}
|
||||
_ => continue,
|
||||
) -> Result<tt::Subtree, PanicMessage> {
|
||||
match &self.inner {
|
||||
ProcMacroLibraryLibloading::StableProcMacroLibrary { exported_macros, .. } => {
|
||||
expand_stable(macro_name, macro_body, attributes, &exported_macros[..])
|
||||
.map_err(PanicMessage::from)
|
||||
}
|
||||
ProcMacroLibraryLibloading::NightlyProcMacroLibrary { exported_macros, .. } => {
|
||||
expand_nightly(macro_name, macro_body, attributes, &exported_macros[..])
|
||||
.map_err(PanicMessage::from)
|
||||
}
|
||||
}
|
||||
|
||||
Err(bridge::PanicMessage::String("Nothing to expand".to_string()))
|
||||
}
|
||||
|
||||
pub fn list_macros(&self) -> Vec<(String, ProcMacroKind)> {
|
||||
self.inner
|
||||
.exported_macros
|
||||
.iter()
|
||||
.map(|proc_macro| match proc_macro {
|
||||
bridge::client::ProcMacro::CustomDerive { trait_name, .. } => {
|
||||
(trait_name.to_string(), ProcMacroKind::CustomDerive)
|
||||
}
|
||||
bridge::client::ProcMacro::Bang { name, .. } => {
|
||||
(name.to_string(), ProcMacroKind::FuncLike)
|
||||
}
|
||||
bridge::client::ProcMacro::Attr { name, .. } => {
|
||||
(name.to_string(), ProcMacroKind::Attr)
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
match &self.inner {
|
||||
ProcMacroLibraryLibloading::StableProcMacroLibrary { exported_macros, .. } => {
|
||||
list_macros_stable(&exported_macros[..])
|
||||
}
|
||||
ProcMacroLibraryLibloading::NightlyProcMacroLibrary { exported_macros, .. } => {
|
||||
list_macros_nightly(&exported_macros[..])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -217,3 +276,153 @@ fn ensure_file_with_lock_free_access(path: &Path) -> io::Result<PathBuf> {
|
||||
fn ensure_file_with_lock_free_access(path: &Path) -> io::Result<PathBuf> {
|
||||
Ok(path.to_path_buf())
|
||||
}
|
||||
|
||||
fn expand_nightly(
|
||||
macro_name: &str,
|
||||
macro_body: &tt::Subtree,
|
||||
attributes: Option<&tt::Subtree>,
|
||||
macros: &[NightlyProcMacro],
|
||||
) -> Result<tt::Subtree, crate::proc_macro_nightly::bridge::PanicMessage> {
|
||||
let parsed_body = NightlyTokenStream::with_subtree(macro_body.clone());
|
||||
|
||||
let parsed_attributes = attributes
|
||||
.map_or(crate::rustc_server_nightly::TokenStream::new(), |attr| {
|
||||
NightlyTokenStream::with_subtree(attr.clone())
|
||||
});
|
||||
|
||||
for proc_macro in macros {
|
||||
match proc_macro {
|
||||
crate::proc_macro_nightly::bridge::client::ProcMacro::CustomDerive {
|
||||
trait_name,
|
||||
client,
|
||||
..
|
||||
} if *trait_name == macro_name => {
|
||||
let res = client.run(
|
||||
&crate::proc_macro_nightly::bridge::server::SameThread,
|
||||
crate::rustc_server_nightly::Rustc::default(),
|
||||
parsed_body,
|
||||
false,
|
||||
);
|
||||
return res.map(|it| it.into_subtree());
|
||||
}
|
||||
crate::proc_macro_nightly::bridge::client::ProcMacro::Bang { name, client }
|
||||
if *name == macro_name =>
|
||||
{
|
||||
let res = client.run(
|
||||
&crate::proc_macro_nightly::bridge::server::SameThread,
|
||||
crate::rustc_server_nightly::Rustc::default(),
|
||||
parsed_body,
|
||||
false,
|
||||
);
|
||||
return res.map(|it| it.into_subtree());
|
||||
}
|
||||
crate::proc_macro_nightly::bridge::client::ProcMacro::Attr { name, client }
|
||||
if *name == macro_name =>
|
||||
{
|
||||
let res = client.run(
|
||||
&crate::proc_macro_nightly::bridge::server::SameThread,
|
||||
crate::rustc_server_nightly::Rustc::default(),
|
||||
parsed_attributes,
|
||||
parsed_body,
|
||||
false,
|
||||
);
|
||||
return res.map(|it| it.into_subtree());
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
|
||||
Err(crate::proc_macro_nightly::bridge::PanicMessage::String("Nothing to expand".to_string()))
|
||||
}
|
||||
|
||||
fn expand_stable(
|
||||
macro_name: &str,
|
||||
macro_body: &tt::Subtree,
|
||||
attributes: Option<&tt::Subtree>,
|
||||
macros: &[StableProcMacro],
|
||||
) -> Result<tt::Subtree, crate::proc_macro::bridge::PanicMessage> {
|
||||
let parsed_body = StableTokenStream::with_subtree(macro_body.clone());
|
||||
|
||||
let parsed_attributes = attributes.map_or(crate::rustc_server::TokenStream::new(), |attr| {
|
||||
StableTokenStream::with_subtree(attr.clone())
|
||||
});
|
||||
|
||||
for proc_macro in macros {
|
||||
match proc_macro {
|
||||
crate::proc_macro::bridge::client::ProcMacro::CustomDerive {
|
||||
trait_name,
|
||||
client,
|
||||
..
|
||||
} if *trait_name == macro_name => {
|
||||
let res = client.run(
|
||||
&crate::proc_macro::bridge::server::SameThread,
|
||||
crate::rustc_server::Rustc::default(),
|
||||
parsed_body,
|
||||
false,
|
||||
);
|
||||
return res.map(|it| it.into_subtree());
|
||||
}
|
||||
crate::proc_macro::bridge::client::ProcMacro::Bang { name, client }
|
||||
if *name == macro_name =>
|
||||
{
|
||||
let res = client.run(
|
||||
&crate::proc_macro::bridge::server::SameThread,
|
||||
crate::rustc_server::Rustc::default(),
|
||||
parsed_body,
|
||||
false,
|
||||
);
|
||||
return res.map(|it| it.into_subtree());
|
||||
}
|
||||
crate::proc_macro::bridge::client::ProcMacro::Attr { name, client }
|
||||
if *name == macro_name =>
|
||||
{
|
||||
let res = client.run(
|
||||
&crate::proc_macro::bridge::server::SameThread,
|
||||
crate::rustc_server::Rustc::default(),
|
||||
parsed_attributes,
|
||||
parsed_body,
|
||||
false,
|
||||
);
|
||||
return res.map(|it| it.into_subtree());
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
|
||||
Err(crate::proc_macro::bridge::PanicMessage::String("Nothing to expand".to_string()))
|
||||
}
|
||||
|
||||
pub fn list_macros_stable(macros: &[StableProcMacro]) -> Vec<(String, ProcMacroKind)> {
|
||||
macros
|
||||
.iter()
|
||||
.map(|proc_macro| match proc_macro {
|
||||
crate::proc_macro::bridge::client::ProcMacro::CustomDerive { trait_name, .. } => {
|
||||
(trait_name.to_string(), ProcMacroKind::CustomDerive)
|
||||
}
|
||||
crate::proc_macro::bridge::client::ProcMacro::Bang { name, .. } => {
|
||||
(name.to_string(), ProcMacroKind::FuncLike)
|
||||
}
|
||||
crate::proc_macro::bridge::client::ProcMacro::Attr { name, .. } => {
|
||||
(name.to_string(), ProcMacroKind::Attr)
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn list_macros_nightly(macros: &[NightlyProcMacro]) -> Vec<(String, ProcMacroKind)> {
|
||||
macros
|
||||
.iter()
|
||||
.map(|proc_macro| match proc_macro {
|
||||
crate::proc_macro_nightly::bridge::client::ProcMacro::CustomDerive {
|
||||
trait_name,
|
||||
..
|
||||
} => (trait_name.to_string(), ProcMacroKind::CustomDerive),
|
||||
crate::proc_macro_nightly::bridge::client::ProcMacro::Bang { name, .. } => {
|
||||
(name.to_string(), ProcMacroKind::FuncLike)
|
||||
}
|
||||
crate::proc_macro_nightly::bridge::client::ProcMacro::Attr { name, .. } => {
|
||||
(name.to_string(), ProcMacroKind::Attr)
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
@ -15,9 +15,16 @@
|
||||
#[doc(hidden)]
|
||||
mod proc_macro;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[doc(hidden)]
|
||||
mod proc_macro_nightly;
|
||||
|
||||
#[doc(hidden)]
|
||||
mod rustc_server;
|
||||
|
||||
#[doc(hidden)]
|
||||
mod rustc_server_nightly;
|
||||
|
||||
mod dylib;
|
||||
|
||||
use proc_macro::bridge::client::TokenStream;
|
||||
|
@ -91,7 +91,7 @@ pub(super) fn extend_from_slice(&mut self, xs: &[T]) {
|
||||
self.len += xs.len();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub(super) fn push(&mut self, v: T) {
|
||||
// The code here is taken from Vec::push, and we know that reserve()
|
||||
// will panic if we're exceeding isize::MAX bytes and so there's no need
|
||||
@ -145,7 +145,7 @@ fn to_vec<T: Copy>(b: Buffer<T>) -> Vec<T> {
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn reserve<T: Copy>(b: Buffer<T>, additional: usize) -> Buffer<T> {
|
||||
extern "C" fn reserve<T: Copy>(b: Buffer<T>, additional: usize) -> Buffer<T> {
|
||||
let mut v = to_vec(b);
|
||||
v.reserve(additional);
|
||||
Buffer::from(v)
|
||||
|
Loading…
Reference in New Issue
Block a user