Si supponga di avere due pacchetti in R, il primo denominato foo
, il secondo denominato bar
. Voglio includere una funzione C in foo
e condividere tale funzionalità con bar
in modo indipendente dalla piattaforma e coerente con le politiche CRAN.Qual è il metodo preferito per condividere il codice C compilato in un pacchetto R e eseguirlo da un altro?
Qual è il metodo preferito per eseguire questa operazione e come dovrei utilizzare la registrazione delle funzioni e le librerie dinamiche?
Lo scopo della mia domanda è che, anche se ho letto tutta la documentazione che ho trovato, non c'è nulla che mi sia accaduto come la cosa ovvia da fare, e non sono sicuro di quale sia la linea di condotta più sostenibile .
Esempio:
supponga che in un pacchetto foo
, definisco una funzione C addinc
che aggiunge due numeri.
#include <R.h>
#include <Rinternals.h>
SEXP addinc(SEXP x_, SEXP y_) {
double x = asReal(x_);
double y = asReal(y_);
double sum = x + y;
return ScalarReal(sum);
}
Nello stesso pacchetto, posso provare a chiamare addinc
in una funzione denominata R addinr
tramite l'interfaccia .Call
.
addinr <- function(x,y){
.Call("addinc", x, y, PACKAGE="foo")
}
Tuttavia, quando si costruisce, il controllo e l'installazione del pacchetto, in esecuzione addinr
restituisce l'errore di seguito, presumibilmente perché la funzione non è ancora registrato entro R.
library(foo)
addinr(1,2)
Error in .Call ("addinc", x, y, pACCHETTO = "foo"):
"addinc" non disponibile per .Call() per il pacchetto "foo"
Come sembra a me, il modo più semplice per risolvere questo problema è creare una libreria dinamica per il codice compilato aggiungendo il file NAMESPACE al file s. Questo sembra risolvere il problema perché ora posso chiamare addinr()
senza problemi. Inoltre, posso correre .Call("addinc", ..., PACKAGE="foo")
direttamente da R.
mio vera questione, tuttavia, si verifica quando un secondo pacchetto, diciamo bar
, si suppone di utilizzare foo
s addinc
. Ad esempio, supponiamo che bar
definisca una funzione multiplyinr
come segue.
multiplyinr <- function(x,y){
ans <- 0
for(i in 1:y) ans <- .Call("addinc", ans, x, PACKAGE="foo")
ans
}
Questo, infatti, funziona completamente bene, e posso chiamare multiplyinr
entro R. Tuttavia, quando la costruzione e la verifica bar
, ricevo una nota lamentano il fatto che bar
sta chiamando le funzioni di lingua straniera da un diverso pacchetto.
funzione degli Esteri chiamata a un pacchetto diverso:
.Call ("addinc", ..., PACCHETTO = "foo")
vedere il capitolo 'di sistema e di lingua straniera interfacce' in la 'scrittura R Estensioni ' Manuale.
Secondo this question, il pacchetto bar
non sarebbe adatto per la presentazione di CRAN perché usando .Call()
in questo modo non è considerato "portatile" come spiegato nella Writing R Extensions manual.
In conclusione, la semplice soluzione di avere foo
include un useDynLib(foo)
nel suo file NAMESPACE non sembra proprio tagliarlo. Quindi la mia domanda: qual è il metodo preferito per condividere una funzione C con altri pacchetti?
Inoltre:
Sta usando useDynLib()
veramente pericoloso o in contrasto con le politiche CRAN? Qual è lo scopo di dichiarare useDynLib()
nel file NAMESPACE come alternativa alla registrazione e alla creazione manuale della libreria condivisa?
Registrando manualmente la funzione C e modificando la libreria condivisa, è possibile modificare qualsiasi cosa (ad esempio utilizzando R_RegisterCCallable()
o R_registerRoutines()
)?
Hai visto questa sezione di R-ext? https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Linking-to-native-routines-in-other-packages –
Come ho capito, usando 'R_RegisterCCallable' è principalmente inteso per il collegamento a livello C. Tuttavia, voglio solo accedere al codice C a livello R (usando '.Call'). Questo è anche il motivo per cui ho chiesto se la registrazione delle funzioni in questo modo avrebbe offerto alcun miglioramento. – SimonG