Skip to content

Commit 84fe537

Browse files
authored
Merge pull request #694 from RcppCore/feature/register-native-routines
Register native routines automatically within compileAttributes
2 parents 4e0f79c + 948551c commit 84fe537

File tree

6 files changed

+230
-42
lines changed

6 files changed

+230
-42
lines changed

ChangeLog

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
2017-05-16 JJ Allaire <[email protected]>
2+
3+
* R/Attributes.R: Automatically generate native routine registrations.
4+
* src/attributes.cpp: Automatically generate native routine registrations.
5+
* R/Rcpp.package.skeleton.R: Don't generate native routines when creating
6+
a package using attributes.
7+
18
2017-05-09 Dirk Eddelbuettel <[email protected]>
29

310
* R/Rcpp.package.skeleton.R (Rcpp.package.skeleton): Under R 3.4.0, run

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: Rcpp
22
Title: Seamless R and C++ Integration
3-
Version: 0.12.10.4
3+
Version: 0.12.10.5
44
Date: 2017-05-07
55
Author: Dirk Eddelbuettel, Romain Francois, JJ Allaire, Kevin Ushey, Qiang Kou,
66
Nathan Russell, Douglas Bates and John Chambers

R/Attributes.R

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,13 @@ compileAttributes <- function(pkgdir = ".", verbose = getOption("verbose")) {
404404
depends <- unique(.splitDepends(depends))
405405
depends <- depends[depends != "R"]
406406

407+
# check the NAMESPACE file to see if dynamic registration is enabled
408+
namespaceFile <- file.path(pkgdir, "NAMESPACE")
409+
if (!file.exists(namespaceFile))
410+
stop("pkgdir must refer to the directory containing an R package")
411+
pkgNamespace <- readLines(namespaceFile, warn = FALSE)
412+
registration <- any(grepl("^\\s*useDynLib.*\\.registration\\s*=\\s*TRUE.*$", pkgNamespace))
413+
407414
# determine source directory
408415
srcDir <- file.path(pkgdir, "src")
409416
if (!file.exists(srcDir))
@@ -415,7 +422,7 @@ compileAttributes <- function(pkgdir = ".", verbose = getOption("verbose")) {
415422
dir.create(rDir)
416423

417424
# get a list of all source files
418-
cppFiles <- list.files(srcDir, pattern = "\\.((c(c|pp))|(h(pp)?))$")
425+
cppFiles <- list.files(srcDir, pattern = "\\.((c(c|pp)?)|(h(pp)?))$")
419426

420427
# derive base names (will be used for modules)
421428
cppFileBasenames <- tools::file_path_sans_ext(cppFiles)
@@ -449,7 +456,7 @@ compileAttributes <- function(pkgdir = ".", verbose = getOption("verbose")) {
449456

450457
# generate exports
451458
invisible(.Call("compileAttributes", PACKAGE="Rcpp",
452-
pkgdir, pkgname, depends, cppFiles, cppFileBasenames,
459+
pkgdir, pkgname, depends, registration, cppFiles, cppFileBasenames,
453460
includes, verbose, .Platform))
454461
}
455462

@@ -1147,3 +1154,43 @@ sourceCppFunction <- function(func, isVoid, dll, symbol) {
11471154
as.character(token)
11481155
}
11491156

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+
}

R/Rcpp.package.skeleton.R

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -185,13 +185,17 @@ Rcpp.package.skeleton <- function(name = "anRpackage", list = character(),
185185
message(" >> copied the example module file ")
186186
}
187187

188-
if (getRversion() >= "3.4.0") {
189-
con <- file(file.path(src, "init.c"), "wt")
190-
tools::package_native_routine_registration_skeleton(root, con=con)
191-
close(con)
192-
message(" >> created init.c for package registration")
193-
} else {
194-
message(" >> R version older than 3.4.0 detected, so NO file init.c created.")
188+
# generate native routines if we aren't using attributes (which already generate
189+
# them automatically) and we have at least R 3.4
190+
if (!attributes) {
191+
if (getRversion() >= "3.4.0") {
192+
con <- file(file.path(src, "init.c"), "wt")
193+
tools::package_native_routine_registration_skeleton(root, con=con)
194+
close(con)
195+
message(" >> created init.c for package registration")
196+
} else {
197+
message(" >> R version older than 3.4.0 detected, so NO file init.c created.")
198+
}
195199
}
196200

197201
lines <- readLines(package.doc <- file.path( root, "man", sprintf("%s-package.Rd", name)))

inst/NEWS.Rd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
}
4141
\item Changes in Rcpp Attributes:
4242
\itemize{
43+
\item Automatically generate native routine registrations.
4344
\item The plugins for C++11, C++14, C++17 now set the values R 3.4.0 or
4445
later expects; a plugin for C++98 was added (Dirk in \ghpr{684} addressing
4546
\ghit{683}).

0 commit comments

Comments
 (0)