This commit is contained in:
Robin Appelman 2019-04-01 22:21:07 +02:00
commit aa1e5d7dca
14 changed files with 86 additions and 85 deletions

View file

@ -15,7 +15,7 @@ fn hello_other(other: String) {
#[ivory_export]
fn hello_world() {
printf("Hello world, Rust2!");
printf("Hello world, Rust!");
}
ivory_module!({

View file

@ -5,7 +5,6 @@ authors = ["Robin Appelman <robin@icewind.nl>"]
edition = "2018"
[dependencies]
libc = "0.2.50"
ivory = { path = "../../ivory", version = "0.1.0" }
[lib]

View file

@ -5,5 +5,5 @@
- build with `cargo build`
- run php with the module and call the defined method
```bash
php -d extension=target/debug/libhelloworld.so -r 'helloworld();'`
php -d extension=../../target/debug/libhelloworld.so -r 'helloworld();'`
```

View file

@ -8,7 +8,7 @@ fn hello_other(other: String) {
#[ivory_export]
fn hello_world() {
printf("Hello world, Rust2!");
printf("Hello world, Rust!");
}
ivory_module!({

View file

@ -9,7 +9,6 @@ repository = "https://github.com/rethinkphp/php-rs"
edition = "2018"
[dependencies]
libc = "0.2.50"
ivory-macro = { version = "0.1", path = "macro" }
ivory-sys = { version = "7.3", path = "sys" }

View file

@ -4,22 +4,26 @@ extern crate proc_macro;
use proc_macro2::{Span, TokenStream, TokenTree};
use quote::quote;
use syn::{AttributeArgs, Expr, FieldValue, FnArg, Ident, Item, ItemFn, LitStr, parse2, parse_macro_input, Pat, Type};
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::{
parse2, parse_macro_input, AttributeArgs, Expr, FieldValue, FnArg, Ident, Item, ItemFn, LitStr,
Pat, Type,
};
/// See the [crate documentation](index.html) for details
#[proc_macro_attribute]
pub fn ivory_export(attr: proc_macro::TokenStream, input: proc_macro::TokenStream) -> proc_macro::TokenStream {
pub fn ivory_export(
attr: proc_macro::TokenStream,
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let input: TokenStream = input.into();
let item = syn::parse2::<Item>(input).unwrap();
let _attr = parse_macro_input!(attr as AttributeArgs);
let output = match item {
Item::Fn(item_fn) => {
export_fn(item_fn).into()
}
_ => unimplemented!()
Item::Fn(item_fn) => export_fn(item_fn).into(),
_ => unimplemented!(),
};
// panic!("{}", output);
@ -38,9 +42,7 @@ fn export_fn(item: ItemFn) -> TokenStream {
unimplemented!("generics are not supported for exported functions");
}
let args: Vec<(String, Type, bool, Span)> = decl.inputs.into_iter()
.map(get_arg_info)
.collect();
let args: Vec<(String, Type, bool, Span)> = decl.inputs.into_iter().map(get_arg_info).collect();
let arg_count = args.len() as u32;
let arg_defs = args.iter().map(|(name, _type, is_ref, _)| {
@ -77,7 +79,7 @@ fn export_fn(item: ItemFn) -> TokenStream {
}
const #meta_name: ::ivory::zend::FunctionMeta = ::ivory::zend::FunctionMeta{
name: {concat!(#name_str, "\0").as_ptr() as *const ::libc::c_char},
name: {concat!(#name_str, "\0").as_ptr() as *const ::std::os::raw::c_char},
func: #name,
args: &[ #(#arg_defs),*]
};
@ -89,14 +91,17 @@ fn get_arg_info(arg: FnArg) -> (String, Type, bool, Span) {
FnArg::Captured(cap) => {
let arg_type = cap.ty;
match cap.pat {
Pat::Ident(ident_pat) => {
(ident_pat.ident.to_string(), arg_type, ident_pat.by_ref.is_some(), ident_pat.span())
},
Pat::Ident(ident_pat) => (
ident_pat.ident.to_string(),
arg_type,
ident_pat.by_ref.is_some(),
ident_pat.span(),
),
Pat::Ref(_ref_pat) => unimplemented!(),
_ => panic!()
_ => panic!(),
}
},
_ => panic!("only normal function arguments are supported")
}
_ => panic!("only normal function arguments are supported"),
}
}
@ -109,10 +114,8 @@ pub fn ivory_module(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let mut tokens = input.into_iter();
let token = tokens.next().unwrap();
let group = match token {
TokenTree::Group(group) => {
group
}
_ => panic!("macro input must be a group")
TokenTree::Group(group) => group,
_ => panic!("macro input must be a group"),
};
let fields = group.stream();
@ -161,8 +164,9 @@ pub fn ivory_module(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
}
fn into_c_str(input: TokenStream) -> TokenStream {
let tokens: Vec<TokenTree> = input.into_iter().map(|token| {
match token.clone() {
let tokens: Vec<TokenTree> = input
.into_iter()
.map(|token| match token.clone() {
TokenTree::Literal(_lit) => {
let mut tokens = TokenStream::new();
tokens.extend(vec![token.clone()]);
@ -170,7 +174,7 @@ fn into_c_str(input: TokenStream) -> TokenStream {
Ok(lit_str) => {
let val = lit_str.value();
let tokens = quote! {
{ concat!(#val, "\0").as_ptr() as *const ::libc::c_char }
{ concat!(#val, "\0").as_ptr() as *const ::std::os::raw::c_char }
};
if let Some(tree) = tokens.into_iter().next() {
tree
@ -178,12 +182,12 @@ fn into_c_str(input: TokenStream) -> TokenStream {
panic!();
}
}
Err(_) => token
Err(_) => token,
}
}
_ => token
}
}).collect();
_ => token,
})
.collect();
let mut output = TokenStream::new();
output.extend(tokens.into_iter());
output
@ -193,31 +197,29 @@ fn get_function_names(struct_def: TokenStream) -> Vec<String> {
let expr: Expr = parse2(struct_def).unwrap();
let expr = get_field_expr(expr, "functions").unwrap();
match expr {
Expr::Reference(ref_expr) => {
match *ref_expr.expr {
Expr::Array(arr) => {
arr.elems.into_iter().map(|element: Expr| {
Expr::Reference(ref_expr) => match *ref_expr.expr {
Expr::Array(arr) => arr
.elems
.into_iter()
.map(|element: Expr| {
let tokens: TokenStream = quote!(#element);
let tree = tokens.into_iter().next().unwrap();
match tree {
TokenTree::Ident(ident) => {
ident.to_string()
TokenTree::Ident(ident) => ident.to_string(),
_ => panic!(),
}
_ => panic!()
}
}).collect()
}
_ => panic!()
}
}
_ => panic!()
})
.collect(),
_ => panic!(),
},
_ => panic!(),
}
}
fn get_field_expr(expr: Expr, field_name: &str) -> Option<Expr> {
let fields: Punctuated<FieldValue, syn::token::Comma> = match expr {
Expr::Struct(expr) => expr.fields,
_ => panic!("invalid struct")
_ => panic!("invalid struct"),
};
for field in fields {
if let syn::Member::Named(ident) = &field.member {

View file

@ -1,17 +1,13 @@
use std::ffi::CString;
use std::intrinsics::transmute;
use libc::*;
use ivory_sys::zend_error;
extern "C" {
pub fn php_printf(format: *const c_char, ...) -> size_t;
}
use ivory_sys::{php_printf, zend_error};
pub fn printf<T: Into<Vec<u8>>>(string: T) {
let cstr = CString::new(string).unwrap();
unsafe { php_printf(cstr.as_ptr()); }
unsafe {
php_printf(cstr.as_ptr());
}
}
#[repr(i32)]
@ -41,5 +37,7 @@ impl From<ErrorLevel> for i32 {
pub fn error<T: Into<Vec<u8>>>(level: ErrorLevel, message: T) {
let cstr = CString::new(message).unwrap();
unsafe { zend_error(level.into(), cstr.as_ptr()); }
unsafe {
zend_error(level.into(), cstr.as_ptr());
}
}

View file

@ -1,5 +1,5 @@
use libc::*;
use std::ffi::CString;
use std::os::raw::{c_int, c_void};
extern "C" {
pub fn php_info_print_table_start();

View file

@ -1,6 +1,6 @@
#[macro_export]
macro_rules! c_str {
($s:expr) => {{
concat!($s, "\0").as_ptr() as *const ::libc::c_char
concat!($s, "\0").as_ptr() as *const ::std::os::raw::c_char
}};
}

View file

@ -1,6 +1,5 @@
use std;
use libc::*;
use std::os::raw::{c_char, c_uchar};
use crate::zend::HandlerFunc;
@ -33,7 +32,6 @@ impl ArgInfo {
}
}
#[derive(Clone)]
#[repr(C)]
pub struct Function {
fname: *const c_char,

View file

@ -1,9 +1,8 @@
use std;
use std::mem;
use std::os::raw::{c_char, c_int, c_uchar, c_uint, c_ushort, c_void};
use libc::*;
use crate::zend::function::{Function, ArgInfo};
use crate::zend::function::{ArgInfo, Function};
use crate::zend::{ExecuteData, ZVal};
pub(crate) type StartupFunc = extern "C" fn(type_: c_int, module_number: c_int) -> c_int;
@ -34,7 +33,7 @@ pub struct ModuleInternal {
request_shutdown_func: Option<ShutdownFunc>,
info_func: Option<InfoFunc>,
version: *const c_char,
globals_size: size_t,
globals_size: usize,
globals_ptr: *const c_void,
globals_ctor: Option<GlobalsCtorFunc>,
globals_dtor: Option<GlobalsDtorFunc>,
@ -97,7 +96,7 @@ impl ModuleInternal {
pub struct FunctionMeta {
pub name: *const c_char,
pub func: HandlerFunc,
pub args: &'static [ArgInfo]
pub args: &'static [ArgInfo],
}
impl FunctionMeta {
@ -114,5 +113,5 @@ pub struct PhpModule {
pub name: *const c_char,
pub version: *const c_char,
pub functions: &'static [HandlerFunc],
pub info: &'static [(&'static str, &'static str)]
pub info: &'static [(&'static str, &'static str)],
}

View file

@ -1,3 +1,12 @@
# ivory-sys
Bindings to php.
## PHP version
While building, it will grab the source for the php version specified in `Cargo.toml`.
Thus changing the version number of the crate also changes the version of php which it's compiled against
## Credits
This crate is taken almost entirely from [php-sys](https://github.com/hjr3/php-rpm/tree/master/php-sys), all credit goes to it's authors

View file

@ -26,7 +26,11 @@ fn run_command_or_fail(dir: String, cmd: &str, args: &[&str]) {
args.join(" "),
dir
);
let ret = Command::new(cmd).current_dir(dir).args(args).env("CC", "clang").status();
let ret = Command::new(cmd)
.current_dir(dir)
.args(args)
.env("CC", "clang")
.status();
match ret.map(|status| (status.success(), status.code())) {
Ok((true, _)) => return,
Ok((false, Some(c))) => panic!("Command failed with error code {}", c),
@ -69,14 +73,7 @@ fn main() {
if !exists("php-src/LICENSE") {
println_stderr!("Setting up PHP {}", php_version);
run_command_or_fail(
"/".to_string(),
"mkdir",
&[
"-p",
&target("")
],
);
run_command_or_fail("/".to_string(), "mkdir", &["-p", &target("")]);
run_command_or_fail(
target(""),
"git",
@ -159,6 +156,7 @@ fn main() {
.whitelist_function("php_printf")
.whitelist_type("zval")
.whitelist_type("zend_execute_data")
.whitelist_type("zend_module_entry")
.derive_default(false)
.header("wrapper.h")
.generate()

View file

@ -2,6 +2,5 @@
#define PHP_RS_WRAPPER_H
#include <Zend/zend.h>
#include <Zend/zend_compile.h>
//#include <main/php.h>
//#include <sapi/embed/php_embed.h>
#include <main/php.h>
#endif