-
Notifications
You must be signed in to change notification settings - Fork 154
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add infrastrucutre for optional compiled extensions
- Loading branch information
1 parent
071513b
commit fe5e558
Showing
14 changed files
with
303 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
|
||
renv_ext_init <- function() { | ||
tryCatch( | ||
renv_ext_init_impl(), | ||
error = function(cnd) print(cnd) | ||
) | ||
} | ||
|
||
renv_ext_init_impl <- function() { | ||
|
||
if (renv_metadata_embedded()) | ||
return() | ||
|
||
name <- Sys.getenv("R_PACKAGE_NAME", unset = NA) | ||
if (!is.na(name)) | ||
return() | ||
|
||
shlib <- renv_ext_compile() | ||
if (file.exists(shlib)) | ||
renv_ext_load(shlib) | ||
|
||
} | ||
|
||
renv_ext_compile <- function(force = FALSE) { | ||
|
||
# get paths | ||
pkgdir <- renv_paths_ext("renv") | ||
libsdir <- file.path(pkgdir, "libs") | ||
libname <- if (renv_platform_windows()) "renv.dll" else "renv.so" | ||
sopath <- file.path(libsdir, libname) | ||
srcfile <- system.file("ext/renv.c", package = "renv") | ||
tgtfile <- file.path(libsdir, "renv.c") | ||
hashpath <- file.path(libsdir, "md5sum") | ||
|
||
# initialize extension directory | ||
ensure_directory(libsdir) | ||
renv_scope_wd(libsdir) | ||
|
||
recompile <- force || | ||
!file.exists(sopath) || | ||
!file.exists(hashpath) || | ||
readLines(hashpath) != md5sum(srcfile) | ||
|
||
if (!recompile) | ||
return(sopath) | ||
|
||
# copy our DESCRIPTION file over, so we can convince R to load | ||
# this DLL as though it were part of our package | ||
renv_file_copy( | ||
source = system.file("DESCRIPTION", package = "renv"), | ||
target = file.path(pkgdir, "DESCRIPTION"), | ||
overwrite = TRUE | ||
) | ||
|
||
# copy the '.c' file over for compilation | ||
renv_file_copy( | ||
source = srcfile, | ||
target = tgtfile, | ||
overwrite = TRUE | ||
) | ||
|
||
# compile it | ||
renv_system_exec( | ||
command = R(), | ||
args = c("CMD", "SHLIB", "renv.c", "-o", libname) | ||
) | ||
|
||
# update the md5sum | ||
writeLines( | ||
md5sum(srcfile), | ||
con = hashpath | ||
) | ||
|
||
# return path to | ||
sopath | ||
|
||
} | ||
|
||
renv_ext_load <- function(shlib) { | ||
|
||
# load the shared library | ||
the$dll_info <- library.dynam( | ||
chname = "renv", | ||
package = "renv", | ||
lib.loc = renv_paths_ext() | ||
) | ||
|
||
# install the ffi equivalents | ||
envir <- renv_envir_self() | ||
enumerate(the$ffi, function(symbol, replacement) { | ||
renv_binding_replace( | ||
envir = envir, | ||
symbol = symbol, | ||
replacement = replacement | ||
) | ||
}) | ||
|
||
} | ||
|
||
renv_ext_unload <- function() { | ||
if (!is.null(the$dll_info)) { | ||
path <- the$dll_info[["path"]] | ||
the$dll_info <- NULL | ||
library.dynam.unload("renv", libpath = dirname(dirname(path))) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
|
||
the$ffi$renv_dependencies_recurse <- function(object, callback) { | ||
|
||
symbol <- as.symbol(names(formals(args(callback)))[[1L]]) | ||
envir <- new.env(parent = environment(callback)) | ||
expr <- body(callback) | ||
|
||
.Call( | ||
"renv_ffi_recurse", | ||
object, | ||
symbol, | ||
expr, | ||
envir, | ||
PACKAGE = .packageName | ||
) | ||
|
||
} | ||
|
||
the$ffi$renv_call_expect <- function(node, package, methods) { | ||
.Call( | ||
"renv_ffi_call_expect", | ||
node, | ||
as.character(package), | ||
as.character(methods), | ||
PACKAGE = .packageName | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
|
||
#include <stdlib.h> // for NULL | ||
|
||
#include <R.h> | ||
#include <Rinternals.h> | ||
#include <R_ext/Rdynload.h> | ||
|
||
// Helpers ---- | ||
|
||
// check for a call of the form 'package::foo(a, b, c)'; | ||
// if we match, then create a new call of the form 'foo(a, b, c)' | ||
static SEXP renv_call_expect_package(SEXP node, SEXP package) { | ||
|
||
if (TYPEOF(node) != LANGSXP) | ||
return node; | ||
|
||
SEXP call = CAR(node); | ||
if (TYPEOF(call) != LANGSXP) | ||
return node; | ||
|
||
SEXP symbol = CAR(call); | ||
if (TYPEOF(symbol) != SYMSXP) | ||
return node; | ||
|
||
const char* value = CHAR(PRINTNAME(symbol)); | ||
if (strcmp(value, "::") != 0 && strcmp(value, ":::") != 0) | ||
return node; | ||
|
||
SEXP name = CADR(call); | ||
if (TYPEOF(name) != SYMSXP) | ||
return node; | ||
|
||
int matches = strcmp(CHAR(PRINTNAME(name)), CHAR(STRING_ELT(package, 0))) == 0; | ||
if (!matches) | ||
return node; | ||
|
||
node = Rf_duplicate(node); | ||
SETCAR(node, CADDR(call)); | ||
return node; | ||
|
||
} | ||
|
||
|
||
// Methods ---- | ||
|
||
SEXP renv_ffi_recurse(SEXP object, | ||
SEXP symbol, | ||
SEXP expr, | ||
SEXP envir) | ||
{ | ||
switch (TYPEOF(object)) { | ||
|
||
case LISTSXP: | ||
case LANGSXP: | ||
|
||
Rf_defineVar(symbol, object, envir); | ||
SEXP result = Rf_eval(expr, envir); | ||
if (TYPEOF(result) == LANGSXP) { | ||
object = result; | ||
} | ||
|
||
PROTECT(object); | ||
while (object != R_NilValue) { | ||
renv_ffi_recurse(CAR(object), symbol, expr, envir); | ||
object = CDR(object); | ||
} | ||
UNPROTECT(1); | ||
|
||
break; | ||
|
||
case VECSXP: | ||
case EXPRSXP: | ||
|
||
for (int i = 0, n = Rf_xlength(object); i < n; i++) { | ||
renv_ffi_recurse(VECTOR_ELT(object, i), symbol, expr, envir); | ||
} | ||
|
||
break; | ||
|
||
} | ||
|
||
return object; | ||
|
||
} | ||
|
||
SEXP renv_ffi_call_expect(SEXP node, SEXP package, SEXP methods) { | ||
|
||
node = renv_call_expect_package(node, package); | ||
PROTECT(node); | ||
|
||
SEXP symbol = CAR(node); | ||
if (TYPEOF(symbol) != SYMSXP) { | ||
UNPROTECT(1); | ||
return R_NilValue; | ||
} | ||
|
||
const char* symname = CHAR(PRINTNAME(symbol)); | ||
for (int i = 0, n = Rf_xlength(methods); i < n; i++) { | ||
const char* method = CHAR(STRING_ELT(methods, i)); | ||
if (strcmp(method, symname) == 0) { | ||
UNPROTECT(1); | ||
return node; | ||
} | ||
} | ||
|
||
UNPROTECT(1); | ||
return R_NilValue; | ||
|
||
} | ||
|
||
|
||
// Init ---- | ||
|
||
static const R_CallMethodDef callEntries[] = { | ||
{ "renv_ffi_recurse", (DL_FUNC) &renv_ffi_recurse, 4 }, | ||
{ "renv_ffi_call_expect", (DL_FUNC) &renv_ffi_call_expect, 3}, | ||
{ NULL, NULL, 0 } | ||
}; | ||
|
||
void R_init_renv(DllInfo* dllInfo) | ||
{ | ||
R_registerRoutines(dllInfo, NULL, callEntries, NULL, NULL); | ||
R_useDynamicSymbols(dllInfo, FALSE); | ||
} |
Oops, something went wrong.