Reputation:
I am trying to make a package with Rcpp. I have all of my C++
functions in a single .cpp
file as follows:
double meanvec(NumericVector x) {
int n = x.size();
double tot = 0;
for (int i = 0; i < n; i++) {
tot += x[i];
}
tot /= n;
return tot;
}
double inprod(NumericVector u, NumericVector v) {
int m = u.size();
double val = 0;
for (int i = 0; i < m; i++) {
val += u[i] * v[i];
}
return val;
}
NumericVector lincoef(NumericVector x, NumericVector y) {
int n = x.size();
double xm = meanvec(x);
double ym = meanvec(y);
NumericVector xa(n);
for (int i = 0; i < n; i++) {
xa[i] = x[i] - xm;
}
NumericVector ya(n);
for (int i = 0; i < n; i++) {
ya[i] = y[i] - ym;
}
double b1 = inprod(xa, ya) / inprod(xa, xa);
double b0 = ym - (b1 * xm);
NumericVector beta = NumericVector::create(b0, b1);
return beta;
}
Basically, the last function takes two vectors as input and outputs a single vector. I would like to call this function into a separate .R
file where I am trying to write another function. Something like this:
#' Title
#'
#' @param x Numeric vector.
#' @param y Numeric vector.
#'
#' @return
#' @export
linfit338 = function(x, y){
beta = .Call(`_pkg338_lincoef`, x, y)
fmod = function(x){
beta[1] + beta[2]*x
}
flist = list(beta, fmod)
return(flist)
}
Here the output is a list, where the first element is a vector from the C++
function being called and the second element is the created function. When I try to install and restart, I get this error message:
RcppExports.o:RcppExports.cpp:(.rdata+0x790): undefined reference to `_pkg338_lincoef'
My guess is that is has something to do with exporting the function. When I add // [[Rcpp::export]]
above the lincoef
function in the C++
file, I don't get any error message, and my final R
function works. However, my whole goal is that I do not want the lincoef
function exported at all.
Any way to fix this? I would also be open to suggestions as to how I can improve organizing these files, as this is my first experience building a package with Rcpp
.
Upvotes: 1
Views: 1487
Reputation: 173783
I think you're probably mixing up the concept of exporting C++ code to be used in R (via // [[Rcpp::export]]
), which is entirely different to exporting R functions from your package, i.e. making those functions available to end-users of your package.
To make your Rcpp functions callable from within R at all, you need to // [[Rcpp::export]]
them. If you don't do this, none of your C++ code will be available from within your R package.
It sounds like what you would like to do is to use the Rcpp-exported functions within your package but to hide them from end-users. This is a common use case for Rcpp, as it allows you to have an R function that acts as an end-user interface to your C++ code, while leaving you free to alter the C++ implementation in future developments without the risk of breaking existing users' code.
Any function you have created within your package, be it an R function or an Rcpp-exported function, has to actively be exported from your package to make it available to end-users. This is a different concept from // [[Rcpp::export]]
, which is needed to access C++ functions from within your package's R code.
Any R functions will only be exported from your R package if you specify them in the NAMESPACE
file in your project's root directory. Thus to export myfunction()
you need to have a line that says export(myfunction)
in the NAMESPACE file. You are using roxygen2, which will generate this line automatically as long as you write @export
in the roxygen skeleton. An alternative to using roxygen's exporting system is to specify an exportPattern
in the NAMESPACE
file that uses regex to export only functions whose names match a certain pattern.
My usual workflow is to prefix any Rcpp-exported functions with a period by writing my C++ functions like this:
// [[Rcpp::export(.MyCppFunction)]]
int BoringFunction() { return 0; }
I can now call the C++ function from R like this:
MyRFunction <- function()
{
result <- .MyCppFunction()
return(result)
}
The first line in my NAMESPACE
file looks like this:
exportPattern("^[[:alpha:]]+")
Which means that any R function in my package starting with a letter will be exported. Since all the functions I Rcpp::export
start with a period, I can use them internally within the R package but they won't be exported to end-users.
In other words, end-users of the package can call MyRFunction()
but would get an error if they tried to call .MyCppFunction
Upvotes: 12