2021-03-09 04:28:37 +01:00
use std ::{ collections ::HashSet , env , path ::PathBuf , process ::Command } ;
2021-03-09 00:40:12 +01:00
use bindgen ::callbacks ::{ MacroParsingBehavior , ParseCallbacks } ;
2021-03-11 00:34:47 +01:00
use regex ::{ Captures , Regex } ;
2021-03-09 00:40:12 +01:00
extern crate bindgen ;
// https://github.com/rust-lang/rust-bindgen/issues/687#issuecomment-450750547
#[ derive(Debug) ]
struct IgnoreMacros ( HashSet < String > ) ;
impl ParseCallbacks for IgnoreMacros {
fn will_parse_macro ( & self , name : & str ) -> MacroParsingBehavior {
if self . 0. contains ( name ) {
MacroParsingBehavior ::Ignore
} else {
MacroParsingBehavior ::Default
}
}
}
2021-03-11 00:34:47 +01:00
const MIN_PHP_API_VER : u32 = 20200930 ;
const MAX_PHP_API_VER : u32 = 20200930 ;
2021-03-09 00:40:12 +01:00
fn main ( ) {
// rerun if wrapper header is changed
println! ( " cargo:rerun-if-changed=wrapper.h " ) ;
// use php-config to fetch includes
let includes_cmd = Command ::new ( " php-config " )
. arg ( " --includes " )
. output ( )
. expect ( " Unable to run `php-config`. Please ensure it is visible in your PATH. " ) ;
if ! includes_cmd . status . success ( ) {
let stderr = String ::from_utf8 ( includes_cmd . stderr )
. unwrap_or_else ( | _ | String ::from ( " Unable to read stderr " ) ) ;
panic! ( " Error running `php-config`: {} " , stderr ) ;
}
2021-03-11 00:34:47 +01:00
// Ensure the PHP API version is supported.
// We could easily use grep and sed here but eventually we want to support Windows,
// so it's easier to just use regex.
let php_i_cmd = Command ::new ( " php " )
. arg ( " -i " )
. output ( )
. expect ( " Unable to run `php -i`. Please ensure it is visible in your PATH. " ) ;
if ! php_i_cmd . status . success ( ) {
let stderr = String ::from_utf8 ( includes_cmd . stderr )
. unwrap_or_else ( | _ | String ::from ( " Unable to read stderr " ) ) ;
panic! ( " Error running `php -i`: {} " , stderr ) ;
}
let php_i = String ::from_utf8 ( php_i_cmd . stdout ) . expect ( " unabel to parse `php -i` stdout " ) ;
let php_api_regex = Regex ::new ( r "PHP API => ([0-9]+)" ) . unwrap ( ) ;
let api_ver : Vec < Captures > = php_api_regex . captures_iter ( php_i . as_ref ( ) ) . collect ( ) ;
match api_ver . first ( ) {
Some ( api_ver ) = > match api_ver . get ( 1 ) {
Some ( api_ver ) = > {
let api_ver : u32 = api_ver . as_str ( ) . parse ( ) . unwrap ( ) ;
if api_ver < MIN_PHP_API_VER | | api_ver > MAX_PHP_API_VER {
panic! ( " The current version of PHP is not supported. Current PHP API version: {} , requires a version between {} and {} " , api_ver , MIN_PHP_API_VER , MAX_PHP_API_VER ) ;
}
} ,
None = > panic! ( " Unable to retrieve PHP API version from `php -i`. Please check the installation and ensure it is callable. " )
} ,
None = > panic! ( " Unable to retrieve PHP API version from `php -i`. Please check the installation and ensure it is callable. " )
} ;
2021-03-09 08:47:20 +01:00
let includes =
String ::from_utf8 ( includes_cmd . stdout ) . expect ( " unable to parse `php-config` stdout " ) ;
2021-03-09 00:40:12 +01:00
2021-03-09 08:47:20 +01:00
let ignore_math_h_macros = IgnoreMacros (
vec! [
// math.h:914 - enum which uses #define for values
" FP_NAN " . into ( ) ,
" FP_INFINITE " . into ( ) ,
" FP_ZERO " . into ( ) ,
" FP_SUBNORMAL " . into ( ) ,
" FP_NORMAL " . into ( ) ,
// math.h:237 - enum which uses #define for values
" FP_INT_UPWARD " . into ( ) ,
" FP_INT_DOWNWARD " . into ( ) ,
" FP_INT_TOWARDZERO " . into ( ) ,
" FP_INT_TONEARESTFROMZERO " . into ( ) ,
" FP_INT_TONEAREST " . into ( ) ,
]
. into_iter ( )
. collect ( ) ,
) ;
2021-03-09 00:40:12 +01:00
let out_path = PathBuf ::from ( env ::var ( " OUT_DIR " ) . unwrap ( ) ) ;
bindgen ::Builder ::default ( )
. header ( " wrapper.h " )
. clang_args ( includes . split ( " " ) )
. parse_callbacks ( Box ::new ( bindgen ::CargoCallbacks ) )
. parse_callbacks ( Box ::new ( ignore_math_h_macros ) )
. rustfmt_bindings ( true )
. generate ( )
. expect ( " Unable to generate bindings for PHP " )
. write_to_file ( out_path . join ( " bindings.rs " ) )
. expect ( " Unable to write bindings file. " ) ;
}