1

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.

4
  • 7
    Please please PLEASE at least glance at the fairly recent Rcpp-introduction vignette, and possibly also the Rcpp Attributes one. And/or consider starting from a 'create a package with Rcpp' helper such as the one in RStudio or of course our Rcpp.package.skeleton() function written for exactly this purpose. Commented Dec 11, 2019 at 14:56
  • 6
    "I do not want the lincoef function exported at all" is saying I do not want to call it from R. You can still control via NAMESPACE what your package exports. Commented Dec 11, 2019 at 15:20
  • 5
    In addition to what @DirkEddelbuettel has said, a look at Writing R Extensions would be a worthwhile investment. Commented Dec 11, 2019 at 15:53
  • 4
    Does this answer your question? Renaming and Hiding an Exported Rcpp function in an R Package Commented Dec 12, 2019 at 18:58

1 Answer 1

12

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

Sign up to request clarification or add additional context in comments.

1 Comment

Nice answer. One trick to add is that // [[Rcpp::export(.linCoef)]] would be exported from C++ to an R function following the 'if it starts with a dot it is "hidden" as an R function' convention which would appear to be the desire here. Then there is no need to change the regexp in NAMESPACE as dot-starting names to not match 'starts with alphanumerical character'.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.