tags:

views:

207

answers:

3

I am creating an R package that I intend to submit to CRAN that has a function calling a routine written in C. How do I load the compiled C routine in the R function in platform-independent way? I am able to make my package work on my intel-based Mac with:

function(mydata)
{
dyn.load(file.path(.Library,"mypkg/libs/i386",paste("mypkg", .Platform$dynlib.ext, sep=""))) 
try(
 output <- .C("myfunc_cversion",
              in_data    = as.double(mydata),
           res_data   = as.double(res),
     PACKAGE    = "mypkg")
 )
 result <- as.matrix(output$res_data)
 return(result)
}

The problem is the call to dyn.load where I cannot figure out how to specify the full path to the shared library for my installed package in a portable way.

Is there another variable in R besides .Library that I should use, or is there a better function than dyn.load for this case?

A: 

You need to look at the manual page for library.dynam(). It should allow you to do what you want, eg.

function(mydata)
{
library.dynam("mysharedobject",package=c("mypkg")) 
try(
        output <- .C("myfunc_cversion",
                     in_data    = as.double(mydata),
                     res_data   = as.double(res),
                     PACKAGE    = "mypkg")
        )
        result <- as.matrix(output$res_data)
        return(result)
}

where mysharedobject is the name of the shared object file without .dll/.so etc on the end.

The man page also recommends that you only use it in the .onLoad() or .First.lib() functions.

HTH


http://sekhon.berkeley.edu/base/html/library.dynam.html

David Lawrence Miller
+2  A: 

I think you are making it too complicated. You could always consult some of the existing 1800+ packages on CRAN. As a general rule, most packages load the object code on startup via .onLoad (and that can even be automated via the NAMESPACE file) --- see the R Extensions manual.

As a simple example, you could look at my digest package, it use the following from a file R/zzz.R (which is the standard approach suggested in the manual)

.onLoad <- function(lib, pkg) {
   library.dynam("digest", pkg, lib )
}

So after package load all functions from the dynamic library are available to all R functions for calling. That is more general than adding a library.dynam() to each function (and on top you only need library.dynam() once per R session anyway).

R itself deals with extensions (.dll, .so, .dylib, ...) and all other per-platform nitty gritty. I see no reason to divert from that approach. So see the manual, and the (literally) hundreds of published packages that do this.


Dirk Eddelbuettel
+1  A: 

I discovered that if I use a name space in my package then I can also solve this problem by using the useDynLib directive inside the NAMESPACE file for the package (as described in section 1.6.3 of the manual "Writing R Extensions" version 2.9.1 at www.r-project.org).

My NAMESPACE file now looks like:

useDynLib(mypkg, myfunc_cversion)
export(myfunc)

I then modify the R function definition to:

myfunc <- function(mydata)
{ 
try(
    output <- .C(myfunc_cversion,
                 in_data  = as.double(mydata),
                 res_data = as.double(res) )
    )
    result <- as.matrix(output$res_data)
    return(result)
}

That is, with no quotes around the C function name and without the PACKAGE argument in the .C call.

Michael Schneider