Skip to content

Commit 948551c

Browse files
committed
use tools::package_native_routine_registration_skeleton when available to discover and register additional non-Rcpp exported native routines
1 parent 30110e3 commit 948551c

File tree

2 files changed

+76
-11
lines changed

2 files changed

+76
-11
lines changed

R/Attributes.R

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,3 +1154,43 @@ sourceCppFunction <- function(func, isVoid, dll, symbol) {
11541154
as.character(token)
11551155
}
11561156

1157+
.extraRoutineRegistrations <- function(routines) {
1158+
1159+
declarations = character()
1160+
call_entries = character()
1161+
1162+
# if we are running R 3.4 or higher we can use an internal utility function
1163+
# to automatically discover additional native routines that require registration
1164+
if (getRversion() >= "3.4") {
1165+
1166+
# get the generated code from R
1167+
con <- textConnection(object = NULL, open = "w")
1168+
on.exit(close(con), add = TRUE)
1169+
tools::package_native_routine_registration_skeleton(
1170+
dir = ".",
1171+
con = con,
1172+
character_only = FALSE
1173+
)
1174+
code <- textConnectionValue(con)
1175+
1176+
# look for lines containing call entries
1177+
matches <- regexec('^\\s+\\{"([^"]+)",.*$', code)
1178+
matches <- regmatches(code, matches)
1179+
matches <- Filter(x = matches, function(x) {
1180+
length(x) > 0
1181+
})
1182+
for (match in matches) {
1183+
routine <- match[[2]]
1184+
if (!routine %in% routines) {
1185+
declaration <- grep(sprintf("^extern .* %s\\(.*$", routine), code,
1186+
value = TRUE)
1187+
declarations <- c(declarations, sub("^extern", "RcppExport", declaration))
1188+
call_entries <- c(call_entries, match[[1]])
1189+
}
1190+
}
1191+
}
1192+
1193+
# return extra declaratiosn and call entries
1194+
list(declarations = declarations,
1195+
call_entries = call_entries)
1196+
}

src/attributes.cpp

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1956,26 +1956,51 @@ namespace attributes {
19561956

19571957
// write native routines
19581958
if (!hasPackageInit && !nativeRoutines_.empty()) {
1959+
1960+
// build list of routines we will register
1961+
std::vector<std::string> routineNames;
1962+
std::vector<std::size_t> routineArgs;
1963+
for (std::size_t i=0;i<nativeRoutines_.size(); i++) {
1964+
const Attribute& attr = nativeRoutines_[i];
1965+
routineNames.push_back(package() + "_" + attr.exportedName());
1966+
routineArgs.push_back(attr.function().arguments().size());
1967+
}
1968+
if (hasCppInterface()) {
1969+
routineNames.push_back(registerCCallableExportedName());
1970+
routineArgs.push_back(0);
1971+
}
1972+
1973+
// see if there are additional registrations to perform
1974+
Rcpp::Function extraRoutinesFunc = Environment::namespace_env("Rcpp")[".extraRoutineRegistrations"];
1975+
List extraRoutines = extraRoutinesFunc(routineNames);
1976+
std::vector<std::string> declarations = extraRoutines["declarations"];
1977+
std::vector<std::string> callEntries = extraRoutines["call_entries"];
1978+
1979+
// generate declarations
1980+
if (declarations.size() > 0) {
1981+
ostr() << std::endl;
1982+
for (int i = 0; i<declarations.size(); i++)
1983+
ostr() << declarations[i] << std::endl;
1984+
}
1985+
1986+
// generate registration code
19591987
ostr() << std::endl;
19601988
ostr() << "static const R_CallMethodDef CallEntries[] = {" << std::endl;
1961-
if (hasCppInterface()) {
1962-
ostr() << " {\"" << registerCCallableExportedName() << "\", " <<
1963-
"(DL_FUNC) &" << registerCCallableExportedName() << ", " <<
1964-
0 << "}," << std::endl;
1989+
for (std::size_t i=0;i<routineNames.size(); i++) {
1990+
ostr() << " {\"" << routineNames[i] << "\", " <<
1991+
"(DL_FUNC) &" << routineNames[i] << ", " <<
1992+
routineArgs[i] << "}," << std::endl;
19651993
}
1966-
for (std::size_t i=0;i<nativeRoutines_.size(); i++) {
1967-
const Attribute& attr = nativeRoutines_[i];
1968-
std::string routine = package() + "_" + attr.exportedName();
1969-
ostr() << " {\"" << routine << "\", " <<
1970-
"(DL_FUNC) &" << routine << ", " <<
1971-
attr.function().arguments().size() << "}," << std::endl;
1994+
if (callEntries.size() > 0) {
1995+
for (int i = 0; i<callEntries.size(); i++)
1996+
ostr() << callEntries[i] << std::endl;
19721997
}
19731998
ostr() << " {NULL, NULL, 0}" << std::endl;
19741999
ostr() << "};" << std::endl;
19752000

19762001
ostr() << std::endl;
19772002

1978-
ostr() << "extern \"C\" void R_init_" << package() << "(DllInfo *dll) {" << std::endl;
2003+
ostr() << "RcppExport void R_init_" << package() << "(DllInfo *dll) {" << std::endl;
19792004
ostr() << " R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);" << std::endl;
19802005
ostr() << " R_useDynamicSymbols(dll, FALSE);" << std::endl;
19812006
ostr() << "}" << std::endl;

0 commit comments

Comments
 (0)