@@ -73,10 +73,33 @@ namespace Rcpp{
7373 } ;
7474
7575 namespace internal {
76+
77+ // the class_<Class> this shared library registered in a module, if
78+ // any. Unrelated classes of the same name in other libraries share
79+ // the typeid name, so make_new_object() passes this on for R to pick
80+ // the right module class; hidden visibility keeps one per library,
81+ // where the dynamic linker would otherwise share it between them
82+ template <typename Class>
83+ inline attribute_hidden void *& module_class_pointer (){
84+ static void * pointer = 0 ;
85+ return pointer ;
86+ }
87+
7688 template <typename Class>
7789 SEXP make_new_object ( Class* ptr ){
7890 Rcpp::XPtr<Class> xp ( ptr, true ) ;
79- Function maker = Environment::Rcpp_namespace ()[ " cpp_object_maker" ] ;
91+ Environment rcpp = Environment::Rcpp_namespace () ;
92+
93+ // older versions of Rcpp only have cpp_object_maker()
94+ void * class_pointer = module_class_pointer<Class>() ;
95+ SEXP maker_by_class = rcpp.get ( " cpp_object_maker_by_class" ) ;
96+ if ( class_pointer != 0 && maker_by_class != R_NilValue ){
97+ Shield<SEXP > class_xp ( R_MakeExternalPtr ( class_pointer, R_NilValue, R_NilValue ) ) ;
98+ Function maker ( maker_by_class ) ;
99+ return maker ( typeid (Class).name (), xp, class_xp ) ;
100+ }
101+
102+ Function maker = rcpp[ " cpp_object_maker" ] ;
80103 return maker ( typeid (Class).name () , xp ) ;
81104 }
82105 }
@@ -637,17 +660,29 @@ namespace Rcpp {
637660#define RCPP_MODULE_BOOT (name ) _rcpp_module_boot_##name
638661
639662// the boot function is called from R via .Call(), so exceptions thrown by
640- // the module body must be turned into R errors
641- #define RCPP_MODULE (name ) \
642- void _rcpp_module_##name##_init() ; \
643- static Rcpp::Module _rcpp_module_##name( # name ) ; \
644- extern " C" SEXP _rcpp_module_boot_##name(){ \
645- BEGIN_RCPP \
646- Rcpp::internal::ModuleScope _rcpp_module_scope ( & _rcpp_module_##name ) ; \
647- _rcpp_module_##name##_init ( ) ; \
648- return Rcpp::XPtr<Rcpp::Module>( & _rcpp_module_##name , false ) ; \
649- END_RCPP \
650- } \
663+ // the module body must be turned into R errors; it runs every time the
664+ // module is loaded, but the body adds to the static module, so it may only
665+ // run once, and a body that throws part-way leaves nothing behind so that
666+ // the next load does not append to what it registered
667+ #define RCPP_MODULE (name ) \
668+ void _rcpp_module_##name##_init() ; \
669+ static Rcpp::Module _rcpp_module_##name( # name ) ; \
670+ static bool _rcpp_module_##name##_initialized = false ; \
671+ extern " C" SEXP _rcpp_module_boot_##name(){ \
672+ BEGIN_RCPP \
673+ if ( ! _rcpp_module_##name##_initialized ){ \
674+ Rcpp::internal::ModuleScope _rcpp_module_scope ( & _rcpp_module_##name ) ; \
675+ try { \
676+ _rcpp_module_##name##_init ( ) ; \
677+ } catch ( ... ) { \
678+ _rcpp_module_##name.clear () ; \
679+ throw ; \
680+ } \
681+ _rcpp_module_##name##_initialized = true ; \
682+ } \
683+ return Rcpp::XPtr<Rcpp::Module>( & _rcpp_module_##name , false ) ; \
684+ END_RCPP \
685+ } \
651686 void _rcpp_module_##name##_init()
652687
653688// silly little dance to suppress a 'defined but not used variable' warning
0 commit comments