What is the preferred way to share compiled C code in package R and run it from another?

Suppose I have two packages in R, the first with the name foo , the second with the name bar . I want to enable the C function in foo and share this functionality with bar so that it is platform independent and complies with CRAN policies.

What is the preferred method for doing this and how can I use the function registration function and dynamic libraries?

The purpose of my question is that, although I read all the documentation I could find, nothing happened to me as obvious, and I'm not sure what the most sustainable course of action is.

Example:

Suppose in one package foo I define a C addinc function that adds two numbers.

 #include <Rh> #include <Rinternals.h> SEXP addinc(SEXP x_, SEXP y_) { double x = asReal(x_); double y = asReal(y_); double sum = x + y; return ScalarReal(sum); } 

In the same package, I can try calling addinc in an R function called addinr via the .Call interface.

 addinr <- function(x,y){ .Call("addinc", x, y, PACKAGE="foo") } 

However, when creating, checking, and installing the package, running addinr returns the error below, presumably because the function is not yet registered in R.

 library(foo) addinr(1,2) 

Error in .Call ("addinc", x, y, PACKAGE = "foo"):
"addinc" is not available for .Call () for package "foo"

It seems to me that the easiest way to solve this problem is to create a dynamic library for compiled code by adding the file useDynLib(foo) to foo NAMESPACE. This seems to solve the problem, because now I can call addinr() without any problems. Moreover, I can run .Call("addinc", ..., PACKAGE="foo") directly from R.

My real question, however, arises when it is assumed that the second package, say bar , uses foo addinc . For example, suppose bar defines the multiplyinr function as follows.

 multiplyinr <- function(x,y){ ans <- 0 for(i in 1:y) ans <- .Call("addinc", ans, x, PACKAGE="foo") ans } 

This, in fact, works perfectly fine, and I can call multiplyinr inside R. However, when I create and check the bar I get a note complaining that bar calls foreign language functions from another package.

Calling an external function for another package:
.Call ("addinc", ..., PACKAGE = "foo")
See the chapter "System and foreign language interfaces in the manual" Writing R-Extensions ".

According to this question, the package bar not suitable for sending to CRAN, since the use of .Call() thus not considered "portable", as explained in the Guide to Writing R Extensions .

In conclusion, the simple solution that foo includes useDynLib(foo) in its NAMESPACE file does not seem to cut it. So my question is: what is the preferred method for sharing the C function with other packages?

Wherein:

Does useDynLib() truly dangerous or incompatible CRAN policy? What is the purpose of declaring useDynLib() in a NAMESPACE file as an alternative to registering and creating a shared library manually?

Would you manually register the C function and expand the shared library to change anything (i.e. using R_RegisterCCallable() or R_registerRoutines() )?

+7
c r package
source share
1 answer

The general idea is that the 'native symbol info' objects created using, for example, useDynLib(<pkg>, <symbol>) are not part of the public API package, so client packages should not call them directly (they are supposed to be may be changed in future versions of the package).

There are two ways to β€œexport” a compiled routine for use by client packages:

  • Just export the wrapper function R to foo , which will directly call your own procedure, or
  • Use the pair of functions R_RegisterCCallable() / R_GetCCallable() to get a pointer to the desired function. (The foo package will call R_RegisterCCallable() to make some function available, the client package bar will call R_GetCCallable() to get a pointer to this function)

In other words, if the package author "registers" their C functions, they announce that they are part of the public C API of their package and allow client packages to use / call it through this interface.

+5
source share

All Articles