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.

akenny430
  • 305
  • 3
  • 16
  • 7
    Please *please* *PLEASE* at least _glance_ at the fairly recent [Rcpp-introduction](https://cloud.r-project.org/web/packages/Rcpp/vignettes/Rcpp-introduction.pdf) vignette, and possibly also the [Rcpp Attributes](https://cloud.r-project.org/web/packages/Rcpp/vignettes/Rcpp-attributes.pdf) 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. – Dirk Eddelbuettel Dec 11 '19 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. – Dirk Eddelbuettel Dec 11 '19 at 15:20
  • 5
    In addition to what @DirkEddelbuettel has said, a look at Writing R Extensions would be a worthwhile investment. – Joseph Wood Dec 11 '19 at 15:53
  • 4
    Does this answer your question? [Renaming and Hiding an Exported Rcpp function in an R Package](https://stackoverflow.com/questions/46039132/renaming-and-hiding-an-exported-rcpp-function-in-an-r-package) – coatless Dec 12 '19 at 18:58

1 Answers1

11

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

Allan Cameron
  • 147,086
  • 7
  • 49
  • 87
  • 1
    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'. – Dirk Eddelbuettel Dec 12 '19 at 11:55