@@ -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+
0 commit comments