-
Notifications
You must be signed in to change notification settings - Fork 26
how to reuse a simple nimbleFunction outside of nimble
The NIMBLE compiler can produce code that can be used outside of nimble. In the future we hope to automate this process. For now, here is a guide on how to do it manually.
This how-to covers only a nimbleFunction with no setup code. For a nimbleFunctionwith setup code, the process would not be trivial, because nimble populates member data of the resulting C++ classes from calls from R based on the corresponding uncompiled nimbleFunction.
Let's say you've run
library(nimble)
plus1 <- nimbleFunction(
run = function(x = double(1)) {
return(x + 1)
returnType(double(1))
})
cplus1 <- compileNimble(plus1, dirName = '.')Then you will find two files of C++ source code:
- C++ function definitions:
P_1_plus1.cpp, and - C++ function declarations:
P_1_plus1.h.
in your local directory. The "1" may be a different number if you've been compiling other nimbleFunctions first.
You will also find a file like
- Compiled C++library:
P_1_plus1_05_18_13_54_45.so
where the last 5 numeric entries encode the date and time, so they will be different every time. On a different operating system (e.g. Windows), the file name may have a different suffix (e.g. .dll).
Finally, you will find a file called Makevars.
In your R session, you can look at the code for cplus1 constructed by compileNimble:
cplus1which for our example looks like this:
function (x)
{
if (is.null(CnativeSymbolInfo_)) {
warning("Trying to call compiled nimbleFunction that does not exist (may have been cleared).")
return(NULL)
}
ans <- .Call(CnativeSymbolInfo_, x)
ans <- ans[[2]]
ans
}Two ways to re-use cplus1 are:
- directly re-use the compiled C++ library. This would make sense if you just want to reload
cplus1in a new R session. - recompile the C++ source code and use the resulting library. This would make sense if you want to place nimble-generated C++ code into an R package src directory, so that the
R CMD installsystem will compile it when building the package. This how-to will not cover the R package aspects of this process. Instead it will show you how to recompile the C++ source from R, with the hope that it is straightforward to see how this would be useful within a package. Note also that the nimble package needs to be installed for the re-compilation to work, so one cannot yet include nimble-generated code in a package on CRAN since I don't think CRAN's package building system allows this kind of dependency at build time.
For either method, you will need to modify the R code for cplus1 to replace CnativeSymbolInfo_ with either a name or the result of getNativeSymbolInfo. I'll use a name for simplicity. Based on inspection of the C++ source files, this should be CALL_plus1. You can also remove the error-checking code at the top. Therefore you would use the following:
Assuming you are now in a new R session:
cplus1 <- function (x) ## copied and modified from above
{
ans <- .Call("CALL_plus1", x)
ans <- ans[[2]]
ans
}Now you are ready to either load the previously compiled shared library or to recompile it again from the C++ source files.
dyn.load("P_1_plus1_05_18_13_54_45.so")Then it should work:
cplus1(1:4) ## should return [1] 2 3 4 5The only file you need for this to work is the P_1_plus1_05_18_13_54_45.so.
To do this, you will need the two C++ source files and the Makevars file. You will also need the nimble package installed, since the C++ source files will expect to find nimble's C++ .h and .cpp files in the installed package directory, as listed in the Makevars file.
You will need to do:
system("R CMD SHLIB P_1_plus1.cpp")This should create "P_1_plus1.so" (or ".dll" on Windows). Now you can load this similarly to in the step above but with the different file name. Specifically:
dyn.load("P_1_plus1.so")Again, if you define cplus1 as above, this should work:
cplus1(1:4) ## should return [1] 2 3 4 5