mirror of
https://git.proxmox.com/git/perlmod
synced 2025-10-05 01:58:51 +00:00
macro: implement bootstrap function in rust
with this, the generated .pm files don't contain any exports anymore when implementing a `perlmod-bindgen` utility to generate .pm files, we can now also deprecate the `lib =` module attribute on the `package` proc macro Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
ebe0ba6487
commit
83f19b9599
@ -53,12 +53,7 @@ pub fn handle_module(attr: AttributeArgs, mut module: syn::ItemMod) -> Result<To
|
|||||||
)?;
|
)?;
|
||||||
*item = syn::Item::Verbatim(func.tokens);
|
*item = syn::Item::Verbatim(func.tokens);
|
||||||
|
|
||||||
package.export_named(
|
package.export_named(func.rust_name, func.perl_name, func.xs_name);
|
||||||
func.rust_name,
|
|
||||||
func.perl_name,
|
|
||||||
func.xs_name,
|
|
||||||
"src/FIXME.rs".to_string(),
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
*item = syn::Item::Fn(func);
|
*item = syn::Item::Fn(func);
|
||||||
}
|
}
|
||||||
@ -66,6 +61,8 @@ pub fn handle_module(attr: AttributeArgs, mut module: syn::ItemMod) -> Result<To
|
|||||||
other => *item = other,
|
other => *item = other,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
items.push(syn::Item::Verbatim(package.bootstrap_function()));
|
||||||
}
|
}
|
||||||
|
|
||||||
package.write()?;
|
package.write()?;
|
||||||
|
@ -1,62 +1,52 @@
|
|||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use proc_macro2::{Ident, Span};
|
use proc_macro2::{Ident, Span, TokenStream};
|
||||||
|
|
||||||
use syn::Error;
|
use quote::quote;
|
||||||
use syn::AttributeArgs;
|
use syn::AttributeArgs;
|
||||||
|
use syn::Error;
|
||||||
|
|
||||||
use crate::attribs::ModuleAttrs;
|
use crate::attribs::ModuleAttrs;
|
||||||
|
|
||||||
const MODULE_HEAD: &str = r#"
|
const MODULE_HEAD: &str = r#"
|
||||||
use strict;
|
require DynaLoader;
|
||||||
use warnings;
|
|
||||||
use DynaLoader ();
|
|
||||||
|
|
||||||
my $LIB;
|
|
||||||
|
|
||||||
BEGIN {
|
|
||||||
my sub newXS {
|
|
||||||
my ($perl_func_name, $full_symbol_name, $filename) = @_;
|
|
||||||
|
|
||||||
my $sym = DynaLoader::dl_find_symbol($LIB, $full_symbol_name);
|
|
||||||
die "failed to locate '$full_symbol_name'\n" if !defined $sym;
|
|
||||||
DynaLoader::dl_install_xsub($perl_func_name, $sym, $filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
my sub __load_shared_lib {
|
|
||||||
return if $LIB;
|
|
||||||
|
|
||||||
|
sub bootstrap {
|
||||||
my ($pkg) = @_;
|
my ($pkg) = @_;
|
||||||
|
|
||||||
my ($mod_name) = {{LIB_NAME}};
|
my ($mod_name) = {{LIB_NAME}};
|
||||||
|
my $bootstrap_name = 'xs_bootstrap_' . ($pkg =~ s/::/__/gr);
|
||||||
|
|
||||||
my @dirs = (map "-L$_/auto", @INC);
|
my @dirs = (map "-L$_/auto", @INC);
|
||||||
my (@mod_files) = DynaLoader::dl_findfile(@dirs"#;
|
my $mod_file = DynaLoader::dl_findfile("#;
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
const MODULE_HEAD_DEBUG: &str = r#", '-L./target/debug'"#;
|
const MODULE_HEAD_DEBUG: &str = r#"'-L./target/debug', "#;
|
||||||
|
|
||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
const MODULE_HEAD_DEBUG: &str = "";
|
const MODULE_HEAD_DEBUG: &str = "";
|
||||||
|
|
||||||
const MODULE_HEAD_2: &str = r#", $mod_name);
|
const MODULE_HEAD_2: &str = r#"@dirs, $mod_name);
|
||||||
die "failed to locate shared library for '$pkg' (lib${mod_name}.so)\n" if !@mod_files;
|
die "failed to locate shared library for '$pkg' (lib${mod_name}.so)\n" if !$mod_file;
|
||||||
|
|
||||||
$LIB = DynaLoader::dl_load_file($mod_files[0])
|
my $lib = DynaLoader::dl_load_file($mod_file)
|
||||||
or die "failed to load library '$mod_files[0]'\n";
|
or die "failed to load library '$mod_file'\n";
|
||||||
|
|
||||||
|
my $sym = DynaLoader::dl_find_symbol($lib, $bootstrap_name);
|
||||||
|
die "failed to locate '$bootstrap_name'\n" if !defined $sym;
|
||||||
|
my $boot = DynaLoader::dl_install_xsub($bootstrap_name, $sym, "src/FIXME.rs");
|
||||||
|
$boot->();
|
||||||
}
|
}
|
||||||
|
|
||||||
__load_shared_lib(__PACKAGE__);
|
__PACKAGE__->bootstrap;
|
||||||
"#;
|
|
||||||
|
|
||||||
const MODULE_TAIL: &str = "}\n";
|
1;
|
||||||
|
"#;
|
||||||
|
|
||||||
struct Export {
|
struct Export {
|
||||||
rust_name: Ident,
|
rust_name: Ident,
|
||||||
perl_name: Option<Ident>,
|
perl_name: Option<Ident>,
|
||||||
xs_name: Ident,
|
xs_name: Ident,
|
||||||
file_name: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Package {
|
pub struct Package {
|
||||||
@ -72,39 +62,61 @@ impl Package {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn export_named(
|
pub fn export_named(&mut self, rust_name: Ident, perl_name: Option<Ident>, xs_name: Ident) {
|
||||||
&mut self,
|
|
||||||
rust_name: Ident,
|
|
||||||
perl_name: Option<Ident>,
|
|
||||||
xs_name: Ident,
|
|
||||||
file_name: String,
|
|
||||||
) {
|
|
||||||
self.exported.push(Export {
|
self.exported.push(Export {
|
||||||
rust_name,
|
rust_name,
|
||||||
perl_name,
|
perl_name,
|
||||||
xs_name,
|
xs_name,
|
||||||
file_name,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn bootstrap_function(&self) -> TokenStream {
|
||||||
|
let mut newxs = TokenStream::new();
|
||||||
|
for export in &self.exported {
|
||||||
|
let perl_name = export.perl_name.as_ref().unwrap_or(&export.rust_name);
|
||||||
|
let sub_name = format!("{}::{}\0", self.attrs.package_name, perl_name);
|
||||||
|
let sub_lit = syn::LitByteStr::new(sub_name.as_bytes(), perl_name.span());
|
||||||
|
|
||||||
|
let xs_name = &export.xs_name;
|
||||||
|
|
||||||
|
newxs.extend(quote! {
|
||||||
|
RSPL_newXS_flags(
|
||||||
|
#sub_lit.as_ptr() as *const i8,
|
||||||
|
#xs_name as _,
|
||||||
|
concat!(::std::file!(), "\0").as_bytes().as_ptr() as *const i8,
|
||||||
|
::std::ptr::null(), // TODO: perl-style prototype string goes here
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let bootstrap_name =
|
||||||
|
format!("xs_bootstrap_{}", self.attrs.package_name).replace("::", "__");
|
||||||
|
let bootstrap_ident = Ident::new(&bootstrap_name, Span::call_site());
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn #bootstrap_ident(
|
||||||
|
_cv: &::perlmod::ffi::CV,
|
||||||
|
) {
|
||||||
|
unsafe {
|
||||||
|
use ::perlmod::ffi::RSPL_newXS_flags;
|
||||||
|
|
||||||
|
let argmark = ::perlmod::ffi::pop_arg_mark();
|
||||||
|
argmark.set_stack();
|
||||||
|
|
||||||
|
#newxs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn write(&self) -> Result<(), Error> {
|
pub fn write(&self) -> Result<(), Error> {
|
||||||
let mut source = format!(
|
let mut source = format!(
|
||||||
"package {};\n{}{}{}",
|
"package {};\n{}{}{}",
|
||||||
self.attrs.package_name, MODULE_HEAD, MODULE_HEAD_DEBUG, MODULE_HEAD_2
|
self.attrs.package_name, MODULE_HEAD, MODULE_HEAD_DEBUG, MODULE_HEAD_2
|
||||||
);
|
);
|
||||||
|
|
||||||
for export in &self.exported {
|
|
||||||
source = format!(
|
|
||||||
"{} newXS('{}', '{}', \"{}\");\n",
|
|
||||||
source,
|
|
||||||
export.perl_name.as_ref().unwrap_or(&export.rust_name),
|
|
||||||
export.xs_name,
|
|
||||||
export.file_name.replace('"', "\\\""),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
source.push_str(MODULE_TAIL);
|
|
||||||
|
|
||||||
if let Some(lib) = &self.attrs.lib_name {
|
if let Some(lib) = &self.attrs.lib_name {
|
||||||
source = source.replace("{{LIB_NAME}}", &format!("('{}')", lib));
|
source = source.replace("{{LIB_NAME}}", &format!("('{}')", lib));
|
||||||
} else {
|
} else {
|
||||||
|
@ -41,6 +41,15 @@ extern "C" {
|
|||||||
pub fn RSPL_stack_get(offset: usize) -> *mut SV;
|
pub fn RSPL_stack_get(offset: usize) -> *mut SV;
|
||||||
|
|
||||||
pub fn RSPL_croak_sv(sv: *mut SV) -> !;
|
pub fn RSPL_croak_sv(sv: *mut SV) -> !;
|
||||||
|
|
||||||
|
pub fn RSPL_newXS_flags(
|
||||||
|
name: *const i8,
|
||||||
|
subaddr: *const i8,
|
||||||
|
filename: *const i8,
|
||||||
|
proto: *const i8,
|
||||||
|
flags: u32,
|
||||||
|
);
|
||||||
|
|
||||||
pub fn RSPL_SvNV(sv: *mut SV) -> f64;
|
pub fn RSPL_SvNV(sv: *mut SV) -> f64;
|
||||||
pub fn RSPL_SvIV(sv: *mut SV) -> isize;
|
pub fn RSPL_SvIV(sv: *mut SV) -> isize;
|
||||||
pub fn RSPL_SvPVutf8(sv: *mut SV, len: *mut libc::size_t) -> *const libc::c_char;
|
pub fn RSPL_SvPVutf8(sv: *mut SV, len: *mut libc::size_t) -> *const libc::c_char;
|
||||||
|
@ -33,6 +33,16 @@ extern void RSPL_croak_sv(SV *sv) {
|
|||||||
croak_sv(sv);
|
croak_sv(sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern void RSPL_newXS_flags(
|
||||||
|
const char *name,
|
||||||
|
void *subaddr,
|
||||||
|
const char *const filename,
|
||||||
|
const char *const proto,
|
||||||
|
uint32_t flags
|
||||||
|
) {
|
||||||
|
newXS_flags(name, subaddr, filename, proto, flags);
|
||||||
|
}
|
||||||
|
|
||||||
extern double RSPL_SvNV(SV *sv) {
|
extern double RSPL_SvNV(SV *sv) {
|
||||||
return SvNV(sv);
|
return SvNV(sv);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user