Skip to content

Commit f3d4961

Browse files
committed
initial work on cacheDir
1 parent 5d2d8ea commit f3d4961

File tree

8 files changed

+289
-108
lines changed

8 files changed

+289
-108
lines changed

ChangeLog

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
2016-07-11 J.J. Allaire <[email protected]>
2+
3+
* R/Attributes.R Add cacheDir argument to sourceCpp to enable caching of
4+
shared libraries across R sessions
5+
* src/attributes.cpp Add cacheDir argument to sourceCpp to enable caching of
6+
shared libraries across R sessions
7+
18
2016-07-03 Dirk Eddelbuettel <[email protected]>
29

310
* DESCRIPTION (Version): Rolling minor version

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.5.4
3+
Version: 0.12.5.5
44
Date: 2016-07-03
55
Author: Dirk Eddelbuettel, Romain Francois, JJ Allaire, Kevin Ushey,
66
Qiang Kou, Douglas Bates and John Chambers

R/Attributes.R

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ sourceCpp <- function(file = "",
2323
env = globalenv(),
2424
embeddedR = TRUE,
2525
rebuild = FALSE,
26+
cacheDir = tempdir(),
2627
showOutput = verbose,
2728
verbose = getOption("verbose"),
2829
dryRun = FALSE) {
@@ -56,9 +57,16 @@ sourceCpp <- function(file = "",
5657
}
5758
}
5859

60+
# use an architecture/version specific subdirectory of the cacheDir
61+
# (since cached dynlibs can now perist across sessions we need to be
62+
# sure to invalidate them when R or Rcpp versions change)
63+
cacheDir <- path.expand(cacheDir)
64+
cacheDir <- normalizePath(cacheDir, winslash = "/", mustWork = FALSE)
65+
cacheDir <- .sourceCppPlatformCacheDir(cacheDir)
66+
5967
# get the context (does code generation as necessary)
6068
context <- .Call("sourceCppContext", PACKAGE="Rcpp",
61-
file, code, rebuild, .Platform)
69+
file, code, rebuild, cacheDir, .Platform)
6270

6371
# perform a build if necessary
6472
if (context$buildRequired || rebuild) {
@@ -202,6 +210,7 @@ cppFunction <- function(code,
202210
includes = character(),
203211
env = parent.frame(),
204212
rebuild = FALSE,
213+
cacheDir = tempdir(),
205214
showOutput = verbose,
206215
verbose = getOption("verbose")) {
207216

@@ -258,6 +267,7 @@ cppFunction <- function(code,
258267
exported <- sourceCpp(code = code,
259268
env = env,
260269
rebuild = rebuild,
270+
cacheDir = cacheDir,
261271
showOutput = showOutput,
262272
verbose = verbose)
263273

@@ -304,6 +314,7 @@ evalCpp <- function(code,
304314
plugins = character(),
305315
includes = character(),
306316
rebuild = FALSE,
317+
cacheDir = tempdir(),
307318
showOutput = verbose,
308319
verbose = getOption( "verbose" ) ){
309320

@@ -312,7 +323,7 @@ evalCpp <- function(code,
312323
env <- new.env()
313324
cppFunction(code, depends = depends, plugins = plugins,
314325
includes = includes, env = env,
315-
rebuild = rebuild, showOutput = showOutput, verbose = verbose )
326+
rebuild = rebuild, cacheDir = cacheDir, showOutput = showOutput, verbose = verbose )
316327
fun <- env[["get_value"]]
317328
fun()
318329
}
@@ -989,3 +1000,93 @@ sourceCppFunction <- function(func, isVoid, dll, symbol) {
9891000
}
9901001
.hasDevelTools
9911002
}
1003+
1004+
1005+
# insert a dynlib entry into the cache
1006+
.sourceCppDynlibInsert <- function(cacheDir, file, code, dynlib) {
1007+
cache <- .sourceCppDynlibReadCache(cacheDir)
1008+
index <- .sourceCppFindCacheEntryIndex(cache, file, code)
1009+
if (is.null(index))
1010+
index <- length(cache) + 1
1011+
cache[[index]] <- list(file = file, code = code, dynlib = dynlib)
1012+
.sourceCppDynlibWriteCache(cacheDir, cache)
1013+
}
1014+
1015+
# attempt to lookup a dynlib entry from the cache
1016+
.sourceCppDynlibLookup <- function(cacheDir, file, code) {
1017+
cache <- .sourceCppDynlibReadCache(cacheDir)
1018+
index <- .sourceCppFindCacheEntryIndex(cache, file, code)
1019+
if (!is.null(index))
1020+
cache[[index]]$dynlib
1021+
else
1022+
list()
1023+
}
1024+
1025+
# write the cache to disk
1026+
.sourceCppDynlibWriteCache <- function(cacheDir, cache) {
1027+
index_file <- file.path(cacheDir, "cache.rds")
1028+
save(cache, file = index_file)
1029+
}
1030+
1031+
# read the cache from disk
1032+
.sourceCppDynlibReadCache <- function(cacheDir) {
1033+
index_file <- file.path(cacheDir, "cache.rds")
1034+
if (file.exists(index_file)) {
1035+
load(file = index_file)
1036+
cache
1037+
} else {
1038+
list()
1039+
}
1040+
}
1041+
1042+
# search the cache for an entry that matches the file or code argument
1043+
.sourceCppFindCacheEntryIndex <- function(cache, file, code) {
1044+
1045+
if (length(cache) > 0) {
1046+
for (i in 1:length(cache)) {
1047+
entry <- cache[[i]]
1048+
if ((!is.null(file) && identical(file, entry$file)) ||
1049+
(!is.null(code) && identical(code, entry$code))) {
1050+
return(i)
1051+
}
1052+
}
1053+
}
1054+
1055+
# none found
1056+
NULL
1057+
}
1058+
1059+
# generate an R version / Rcpp version specific cache dir for dynlibs
1060+
.sourceCppPlatformCacheDir <- function(cacheDir) {
1061+
1062+
dir <- file.path(cacheDir,
1063+
paste("sourceCpp",
1064+
utils::packageVersion("Rcpp"),
1065+
R.version$platform,
1066+
R.version$`svn rev`,
1067+
sep = "-"))
1068+
if (!dir.exists(dir))
1069+
dir.create(dir, recursive = TRUE)
1070+
1071+
dir
1072+
}
1073+
1074+
# generate a unique token for a cacheDir
1075+
.sourceCppDynlibUniqueToken <- function(cacheDir) {
1076+
# read existing token (or create a new one)
1077+
token_file <- file.path(cacheDir, "token.rds")
1078+
if (file.exists(token_file))
1079+
load(file = token_file)
1080+
else
1081+
token <- 0
1082+
1083+
# increment
1084+
token <- token + 1
1085+
1086+
# write it
1087+
save(token, file = token_file)
1088+
1089+
# return it as a string
1090+
as.character(token)
1091+
}
1092+

inst/NEWS.Rd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
}
3434
\item Changes in Rcpp Attributes:
3535
\itemize{
36+
\item Add \code{cacheDir} argument to \code{sourceCpp()} to enable caching of
37+
shared libraries across R sessions.
3638
\item Code generation now deals correctly which packages containing a dot
3739
in their name (Qiang in \ghpr{501} fixing \ghit{500})
3840
}

man/cppFunction.Rd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ cppFunction(code, depends = character(), plugins = character(),
3030
}
3131
\item{rebuild}{
3232
Force a rebuild of the shared library.
33+
}
34+
\item{cacheDir}{
35+
Directory to use for caching shared libraries. If the underlying code passed to \code{sourceCpp} has not changed since the last invocation then a cached version of the shared library is used. The default value of \code{tempdir()} results in the cache being valid only for the current R session. Pass an alternate directory to preserve the cache across R sessions.
3336
}
3437
\item{showOutput}{
3538
\code{TRUE} to print \code{R CMD SHLIB} output to the console.

man/evalCpp.Rd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ see \code{\link{cppFunction}}
3434
}
3535
\item{rebuild}{
3636
see \code{\link{cppFunction}}
37+
}
38+
\item{cacheDir}{
39+
Directory to use for caching shared libraries. If the underlying code passed to \code{sourceCpp} has not changed since the last invocation then a cached version of the shared library is used. The default value of \code{tempdir()} results in the cache being valid only for the current R session. Pass an alternate directory to preserve the cache across R sessions.
3740
}
3841
\item{showOutput}{
3942
see \code{\link{cppFunction}}

man/sourceCpp.Rd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ sourceCpp(file = "", code = NULL, env = globalenv(),
2828
}
2929
\item{rebuild}{
3030
Force a rebuild of the shared library.
31+
}
32+
\item{cacheDir}{
33+
Directory to use for caching shared libraries. If the underlying file or code passed to \code{sourceCpp} has not changed since the last invocation then a cached version of the shared library is used. The default value of \code{tempdir()} results in the cache being valid only for the current R session. Pass an alternate directory to preserve the cache across R sessions.
3134
}
3235
\item{showOutput}{
3336
\code{TRUE} to print \code{R CMD SHLIB} output to the console.

0 commit comments

Comments
 (0)