@@ -13,16 +13,10 @@ use std::os::unix::ffi::OsStrExt;
1313#[ cfg( target_family = "windows" ) ]
1414use std:: os:: windows:: ffi:: OsStringExt ;
1515
16- //
17- // Environmental variables
18- //
19-
2016// The environmental variables that are usually set by R. These might be needed
2117// to set manually if we compile libR-sys outside of an R session.
2218//
2319// c.f., https://stat.ethz.ch/R-manual/R-devel/library/base/html/EnvVar.html
24- #[ cfg( feature = "use-bindgen" ) ]
25- const ENVVAR_R_INCLUDE_DIR : & str = "R_INCLUDE_DIR" ;
2620const ENVVAR_R_HOME : & str = "R_HOME" ;
2721
2822// An R version (e.g., "4.1.2" or "4.2.0-devel"). When this is set, the actual R
@@ -31,24 +25,11 @@ const ENVVAR_R_HOME: &str = "R_HOME";
3125const ENVVAR_R_VERSION : & str = "LIBRSYS_R_VERSION" ;
3226
3327// A path to a dir containing pre-computed bindings (default: "bindings").
34- #[ cfg( not( feature = "use-bindgen" ) ) ]
3528const ENVVAR_BINDINGS_PATH : & str = "LIBRSYS_BINDINGS_PATH" ;
3629
37- // A path to libclang toolchain. If this is set, the path is added to the
38- // compiler arguments on executing bindgen.
39- #[ cfg( feature = "use-bindgen" ) ]
40- const ENVVAR_LIBCLANG_INCLUDE_PATH : & str = "LIBRSYS_LIBCLANG_INCLUDE_PATH" ;
41-
42- // A path to an output dir of bindings in addition to the default "bindings"
43- // dir. If this is set, generated bindings are also put there.
44- #[ cfg( feature = "use-bindgen" ) ]
45- const ENVVAR_BINDINGS_OUTPUT_PATH : & str = "LIBRSYS_BINDINGS_OUTPUT_PATH" ;
46-
4730#[ derive( Debug ) ]
4831struct InstallationPaths {
4932 r_home : PathBuf ,
50- #[ cfg( feature = "use-bindgen" ) ]
51- include : PathBuf ,
5233 library : PathBuf ,
5334}
5435
@@ -209,47 +190,15 @@ fn get_r_library(r_home: &Path) -> PathBuf {
209190 }
210191}
211192
212- // Get the path to the R include directory either from an envvar or by executing the actual R binary.
213- #[ cfg( feature = "use-bindgen" ) ]
214- fn get_r_include ( r_home : & Path , library : & Path ) -> io:: Result < PathBuf > {
215- // If the environment variable R_INCLUDE_DIR is set we use it
216- if let Some ( include) = env:: var_os ( ENVVAR_R_INCLUDE_DIR ) {
217- return Ok ( PathBuf :: from ( include) ) ;
218- }
219-
220- // Otherwise, we try to execute `R` to find the include dir. Here,
221- // we're using the R home we found earlier, to make sure we're consistent.
222- let r_binary = InstallationPaths {
223- r_home : r_home. to_path_buf ( ) ,
224- #[ cfg( feature = "use-bindgen" ) ]
225- include : PathBuf :: new ( ) , // get_r_binary() doesn't use `include` so fill with an empty PathBuf.
226- library : library. to_path_buf ( ) ,
227- }
228- . get_r_binary ( ) ;
229-
230- let rout = r_command ( r_binary, r#"cat(normalizePath(R.home('include')))"# ) ?;
231- if !rout. is_empty ( ) {
232- Ok ( PathBuf :: from ( rout) )
233- } else {
234- Err ( Error :: new ( ErrorKind :: Other , "Cannot find R include." ) )
235- }
236- }
237-
238193fn probe_r_paths ( ) -> io:: Result < InstallationPaths > {
239194 // First we locate the R home
240195 let r_home = get_r_home ( ) ?;
241196
242197 // Now the library location. On Windows, it depends on the target architecture
243198 let library = get_r_library ( & r_home) ;
244199
245- // Finally the include location. It may or may not be located under R home
246- #[ cfg( feature = "use-bindgen" ) ]
247- let include = get_r_include ( & r_home, & library) ?;
248-
249200 Ok ( InstallationPaths {
250201 r_home,
251- #[ cfg( feature = "use-bindgen" ) ]
252- include,
253202 library,
254203 } )
255204}
@@ -377,192 +326,6 @@ fn set_r_version_vars(ver: &RVersionInfo) {
377326 println ! ( "cargo:r_version_devel={}" , ver. devel) ; // Becomes DEP_R_R_VERSION_DEVEL for clients
378327}
379328
380- #[ cfg( all( feature = "use-bindgen" , not( feature = "non-api" ) ) ) ]
381- fn get_non_api ( ) -> std:: collections:: HashSet < String > {
382- // Several non-APIs are required for extendr-engine, so we explicitly allow
383- // these here. If extendr-engine (or other crate) requires more non-APIs,
384- // add it here with caution.
385- const REQUIRED_NON_API : [ & str ; 6 ] = [
386- "R_CStackLimit" ,
387- "R_CleanTempDir" ,
388- "R_RunExitFinalizers" ,
389- "Rf_endEmbeddedR" ,
390- "Rf_initialize_R" ,
391- "setup_Rmainloop" ,
392- ] ;
393-
394- // nonAPI.txt is generated by
395- // Rscript -e 'cat(tools:::nonAPI, sep = "\n")' | tr -d '\r' | sort -u | tee ./nonAPI.txt
396- let non_api = include_str ! ( "./nonAPI.txt" )
397- . lines ( )
398- . filter ( |e| !REQUIRED_NON_API . contains ( e) )
399- . map ( |s| s. to_string ( ) ) ;
400-
401- std:: collections:: HashSet :: from_iter ( non_api)
402- }
403-
404- #[ cfg( feature = "use-bindgen" ) ]
405- /// Generate bindings by calling bindgen.
406- fn generate_bindings ( r_paths : & InstallationPaths , version_info : & RVersionInfo ) {
407- // The bindgen::Builder is the main entry point
408- // to bindgen, and lets you build up options for
409- // the resulting bindings.
410- let mut bindgen_builder = bindgen:: Builder :: default ( ) ;
411-
412- #[ cfg( all( feature = "use-bindgen" , not( feature = "non-api" ) ) ) ]
413- {
414- let blocklist = get_non_api ( ) . into_iter ( ) . collect :: < Vec < _ > > ( ) . join ( "|" ) ;
415- bindgen_builder = bindgen_builder. blocklist_item ( blocklist) ;
416- }
417-
418- bindgen_builder = bindgen_builder
419- . emit_diagnostics ( )
420- . translate_enum_integer_types ( true )
421- . merge_extern_blocks ( true )
422- // The input header we would like to generate
423- // bindings for.
424- . header ( "wrapper.h" )
425- // Tell cargo to invalidate the built crate whenever any of the
426- // included header files changed.
427- . parse_callbacks ( Box :: new ( bindgen:: CargoCallbacks :: new ( ) ) ) ;
428-
429- // Use enum-definition of `SEXPTYPE`, as it is available and compatible
430- bindgen_builder = bindgen_builder. clang_arg ( "-Denum_SEXPTYPE" ) ;
431-
432- // Collect C-enums into idiomatic Rust-style enums
433- bindgen_builder = bindgen_builder. default_enum_style ( bindgen:: EnumVariation :: Rust {
434- non_exhaustive : false ,
435- } ) ;
436-
437- if cfg ! ( feature = "layout_tests" ) {
438- bindgen_builder = bindgen_builder. layout_tests ( true ) ;
439- } else {
440- bindgen_builder = bindgen_builder. layout_tests ( false ) ;
441- }
442-
443- let target = env:: var ( "TARGET" ) . expect ( "Could not get the target triple" ) ;
444- let target_os = std:: env:: var ( "CARGO_CFG_TARGET_OS" ) . unwrap ( ) ;
445- let target_arch = env:: var ( "CARGO_CFG_TARGET_ARCH" ) . unwrap ( ) ;
446-
447- println ! (
448- "Generating bindings for target: {target}, os: {target_os}, architecture: {target_arch}"
449- ) ;
450-
451- let r_include_path = r_paths. include . display ( ) . to_string ( ) . replace ( r"\" , r"/" ) ;
452- let r_include_path_escaped = regex:: escape ( & r_include_path) ;
453- let r_include_path_escaped = format ! ( "{r_include_path_escaped}.*" ) ;
454-
455- // Point to the correct headers
456- bindgen_builder =
457- bindgen_builder. clang_args ( [ format ! ( "-I{r_include_path}" , ) , format ! ( "--target={target}" ) ] ) ;
458-
459- // this effectively ignores all non-R headers from sneaking in
460- bindgen_builder = bindgen_builder
461- . allowlist_file ( r_include_path_escaped)
462- . allowlist_file ( ".*wrapper\\ .h$" ) ;
463-
464- // stops warning about ignored attributes,
465- // e.g. ignores `__format__` attributes caused by `stdio.h`
466- bindgen_builder = bindgen_builder. clang_arg ( "-Wno-ignored-attributes" ) ;
467-
468- // allow injection of an alternative include path to libclang
469- if let Some ( alt_include) = env:: var_os ( ENVVAR_LIBCLANG_INCLUDE_PATH ) {
470- bindgen_builder =
471- bindgen_builder. clang_arg ( format ! ( "-I{}" , PathBuf :: from( alt_include) . display( ) ) ) ;
472- }
473-
474- // Remove constants defined by C-headers as
475- // there are rust equivalents for them.
476- let bindgen_builder = bindgen_builder
477- . blocklist_item ( "M_E" )
478- . blocklist_item ( "M_LOG2E" )
479- . blocklist_item ( "M_LOG10E" )
480- . blocklist_item ( "M_LN2" )
481- . blocklist_item ( "M_LN10" )
482- . blocklist_item ( "M_PI" )
483- . blocklist_item ( "M_PI_2" )
484- . blocklist_item ( "M_PI_4" )
485- . blocklist_item ( "M_1_PI" )
486- . blocklist_item ( "M_2_PI" )
487- . blocklist_item ( "M_2_SQRTPI" )
488- . blocklist_item ( "M_SQRT2" )
489- . blocklist_item ( "M_SQRT1_2" )
490- . blocklist_item ( "M_2PI" )
491- . blocklist_item ( "M_LOG10_2" ) ;
492-
493- // `VECTOR_PTR` is deprecated, use `DATAPTR` and friends instead
494- let bindgen_builder = bindgen_builder. blocklist_item ( "VECTOR_PTR" ) ;
495-
496- // Remove all Fortran items, these are items with underscore _ postfix
497- let bindgen_builder = bindgen_builder. blocklist_item ( "[A-Za-z_][A-Za-z0-9_]*[^_]_$" ) ;
498-
499- // Ensure that `SEXPREC` is opaque to Rust
500- let bindgen_builder = bindgen_builder. blocklist_item ( "SEXPREC" ) ;
501-
502- // Replace `TYPEOF` definition with one that gives same type as `SEXPTYPE`.
503- let bindgen_builder = bindgen_builder. blocklist_item ( "TYPEOF" ) ;
504-
505- // Replace this with a function that handles enum-version of SEXPTYPE correctly
506- let bindgen_builder = bindgen_builder. blocklist_item ( "Rf_isS4" ) ;
507-
508- // Replace second arg with SEXPTYPE, see lib.rs
509- let bindgen_builder = bindgen_builder. blocklist_type ( "R_altrep_Coerce_method_t" ) ;
510-
511- // Extra, and unnecessary item being generated by bindgen
512- let bindgen_builder = bindgen_builder. blocklist_item ( "Rcomplex__bindgen_ty_1" ) ;
513-
514- // Finish the builder and generate the bindings.
515- let bindings = bindgen_builder
516- . raw_line ( format ! (
517- "/* libR-sys version: {} */" ,
518- env!( "CARGO_PKG_VERSION" )
519- ) )
520- . raw_line ( format ! (
521- "/* bindgen clang version: {} */" ,
522- bindgen:: clang_version( ) . full
523- ) )
524- . raw_line ( format ! ( "/* r version: {} */" , version_info. full) )
525- . generate_comments ( true )
526- . parse_callbacks ( Box :: new ( TrimCommentsCallbacks ) )
527- . clang_arg ( "-fparse-all-comments" )
528- . generate ( )
529- // Unwrap the Result and panic on failure.
530- . expect ( "Unable to generate bindings" ) ;
531-
532- // Write the bindings to the $OUT_DIR/bindings.rs file.
533- let out_path = PathBuf :: from ( env:: var_os ( "OUT_DIR" ) . unwrap ( ) ) ;
534-
535- bindings
536- . write_to_file ( out_path. join ( "bindings.rs" ) )
537- . expect ( "Couldn't write bindings to default output path!" ) ;
538-
539- // Also write the bindings to a folder specified by `LIBRSYS_BINDINGS_OUTPUT_PATH`, if defined
540- if let Some ( alt_target) = env:: var_os ( ENVVAR_BINDINGS_OUTPUT_PATH ) {
541- let out_path = PathBuf :: from ( alt_target) ;
542- // if folder doesn't exist, try to create it
543- if !out_path. exists ( ) {
544- fs:: create_dir ( & out_path) . unwrap_or_else ( |_| {
545- panic ! (
546- "Couldn't create output directory for bindings: {}" ,
547- out_path. display( )
548- )
549- } ) ;
550- }
551-
552- let bindings_file_full = version_info. get_r_bindings_filename ( & target_os, & target_arch) ;
553- let out_file = out_path. join ( bindings_file_full) ;
554-
555- bindings
556- . write_to_file ( & out_file)
557- . unwrap_or_else ( |_| panic ! ( "Couldn't write bindings: {}" , out_file. display( ) ) ) ;
558- } else {
559- println ! (
560- "cargo:warning=Couldn't write the bindings since `LIBRSYS_BINDINGS_OUTPUT_PATH` is not set."
561- ) ;
562- }
563- }
564-
565- #[ cfg( not( feature = "use-bindgen" ) ) ]
566329/// Retrieve bindings from cache, if available. Errors out otherwise.
567330fn retrieve_prebuild_bindings ( version_info : & RVersionInfo ) {
568331 let target_os = std:: env:: var ( "CARGO_CFG_TARGET_OS" ) . unwrap ( ) ;
@@ -599,25 +362,6 @@ fn retrieve_prebuild_bindings(version_info: &RVersionInfo) {
599362 println ! ( "cargo:rerun-if-changed={}" , from. display( ) ) ;
600363}
601364
602- /// Provide extra cleaning of the processed elements in the headers.
603- #[ cfg( feature = "use-bindgen" ) ]
604- #[ derive( Debug ) ]
605- struct TrimCommentsCallbacks ;
606-
607- #[ cfg( feature = "use-bindgen" ) ]
608- impl bindgen:: callbacks:: ParseCallbacks for TrimCommentsCallbacks {
609- fn process_comment ( & self , comment : & str ) -> Option < String > {
610- // trim comments
611- let comment = comment. trim ( ) ;
612-
613- // replace bare brackets in comments
614- let comment = comment. replace ( '[' , r"\[" ) ;
615- let comment = comment. replace ( ']' , r"\]" ) ;
616-
617- Some ( comment)
618- }
619- }
620-
621365fn main ( ) {
622366 let r_paths = probe_r_paths ( ) ;
623367
@@ -652,8 +396,5 @@ fn main() {
652396 get_r_version ( ENVVAR_R_VERSION , & r_paths) . expect ( "Could not obtain R version" ) ;
653397 set_r_version_vars ( & version_info) ;
654398
655- #[ cfg( feature = "use-bindgen" ) ]
656- generate_bindings ( & r_paths, & version_info) ;
657- #[ cfg( not( feature = "use-bindgen" ) ) ]
658399 retrieve_prebuild_bindings ( & version_info) ;
659400}
0 commit comments