@@ -23,6 +23,7 @@ sourceCpp <- function(file = "",
23
23
env = globalenv(),
24
24
embeddedR = TRUE ,
25
25
rebuild = FALSE ,
26
+ cacheDir = tempdir(),
26
27
showOutput = verbose ,
27
28
verbose = getOption(" verbose" ),
28
29
dryRun = FALSE ) {
@@ -56,9 +57,16 @@ sourceCpp <- function(file = "",
56
57
}
57
58
}
58
59
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
+
59
67
# get the context (does code generation as necessary)
60
68
context <- .Call(" sourceCppContext" , PACKAGE = " Rcpp" ,
61
- file , code , rebuild , .Platform )
69
+ file , code , rebuild , cacheDir , .Platform )
62
70
63
71
# perform a build if necessary
64
72
if (context $ buildRequired || rebuild ) {
@@ -202,6 +210,7 @@ cppFunction <- function(code,
202
210
includes = character (),
203
211
env = parent.frame(),
204
212
rebuild = FALSE ,
213
+ cacheDir = tempdir(),
205
214
showOutput = verbose ,
206
215
verbose = getOption(" verbose" )) {
207
216
@@ -258,6 +267,7 @@ cppFunction <- function(code,
258
267
exported <- sourceCpp(code = code ,
259
268
env = env ,
260
269
rebuild = rebuild ,
270
+ cacheDir = cacheDir ,
261
271
showOutput = showOutput ,
262
272
verbose = verbose )
263
273
@@ -304,6 +314,7 @@ evalCpp <- function(code,
304
314
plugins = character (),
305
315
includes = character (),
306
316
rebuild = FALSE ,
317
+ cacheDir = tempdir(),
307
318
showOutput = verbose ,
308
319
verbose = getOption( " verbose" ) ){
309
320
@@ -312,7 +323,7 @@ evalCpp <- function(code,
312
323
env <- new.env()
313
324
cppFunction(code , depends = depends , plugins = plugins ,
314
325
includes = includes , env = env ,
315
- rebuild = rebuild , showOutput = showOutput , verbose = verbose )
326
+ rebuild = rebuild , cacheDir = cacheDir , showOutput = showOutput , verbose = verbose )
316
327
fun <- env [[" get_value" ]]
317
328
fun()
318
329
}
@@ -989,3 +1000,93 @@ sourceCppFunction <- function(func, isVoid, dll, symbol) {
989
1000
}
990
1001
.hasDevelTools
991
1002
}
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