diff --git a/ChangeLog b/ChangeLog index 016ffba17..ebc7d183b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2018-09-18 JJ Allaire + + * src/attributes.cpp: Add support [[Rcpp::init]] attribute + * vignettes/Rcpp-attributes.Rmd: Documentation for [[Rcpp::init]] attribute + 2018-09-17 Dirk Eddelbuettel * inst/include/Rcpp/r/headers.h: Define STRICT_R_HEADERS, but until diff --git a/inst/NEWS.Rd b/inst/NEWS.Rd index 6efcd28e8..225132f61 100644 --- a/inst/NEWS.Rd +++ b/inst/NEWS.Rd @@ -11,6 +11,11 @@ now; until then we protect it via \code{RCPP_NO_STRICT_HEADERS} which can then be used to avoid the definition; downstream maintainers are encouraged to update their packages as needed + } + \item Changes in Rcpp Attributes: + \itemize{ + \item Added \code{[[Rcpp::init]]} attribute for registering C++ functions to + run during package initialization. } \item Changes in Rcpp Modules: \itemize{ diff --git a/src/attributes.cpp b/src/attributes.cpp index ce4eeefba..94a23424e 100644 --- a/src/attributes.cpp +++ b/src/attributes.cpp @@ -153,6 +153,7 @@ namespace attributes { const char * const kExportAttribute = "export"; const char * const kExportName = "name"; const char * const kExportRng = "rng"; + const char * const kInitAttribute = "init"; const char * const kDependsAttribute = "depends"; const char * const kPluginsAttribute = "plugins"; const char * const kInterfacesAttribute = "interfaces"; @@ -673,6 +674,9 @@ namespace attributes { const std::string& name) const; private: + // for generating calls to init functions + std::vector initFunctions_; + // for generating C++ interfaces std::vector cppExports_; @@ -1323,8 +1327,8 @@ namespace attributes { // and it doesn't appear at the end of the file Function function; - // special handling for export - if (name == kExportAttribute) { + // special handling for export and init + if (name == kExportAttribute || name == kInitAttribute) { // parse the function (unless we are at the end of the file in // which case we print a warning) @@ -1673,6 +1677,7 @@ namespace attributes { bool SourceFileAttributesParser::isKnownAttribute(const std::string& name) const { return name == kExportAttribute || + name == kInitAttribute || name == kDependsAttribute || name == kPluginsAttribute || name == kInterfacesAttribute; @@ -1894,6 +1899,8 @@ namespace attributes { // add it to the native routines list nativeRoutines_.push_back(*it); + } else if (it->name() == kInitAttribute) { + initFunctions_.push_back(*it); } } // #nocov end @@ -1967,7 +1974,7 @@ namespace attributes { } // write native routines - if (!hasPackageInit && (!nativeRoutines_.empty() || !modules_.empty())) { + if (!hasPackageInit && (!nativeRoutines_.empty() || !modules_.empty() || !initFunctions_.empty())) { // build list of routines we will register std::vector routineNames; @@ -2022,11 +2029,29 @@ namespace attributes { ostr() << std::endl; + // write prototypes for init functions + for (std::size_t i = 0; i. + +You may however want to add additional C++ code to the package initialization sequence. To do this, you can add the `[[Rcpp::init]]` attribute to functions within your package. For example: + +```{cpp, eval = FALSE} +// [[Rcpp::init]] +void my_package_init(DllInfo *dll) { + // initialization code here +} +``` + +In this case, a call to `my_package_init()` will be added to the end of the automatically generated R_init function within RcppExports.cpp. For example: + +```{cpp, eval = FALSE} +void my_package_init(DllInfo *dll); +RcppExport void R_init_pkgname(DllInfo *dll) { + R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); + R_useDynamicSymbols(dll, FALSE); + my_package_init(dll); +} +``` + ## Types in Generated Code In some cases the signatures of the C++ functions that are generated within