Intro

With the arrival of R 3.4, a new era of CRAN checks regarding C++ registration was ushered in. In particular, CRAN checks now issue the following “NOTE”:

  • checking compiled code … NOTE

    File ‘packagename/libs/packagename.so’:

    Found no calls to: ‘R_registerRoutines’, ‘R_useDynamicSymbols’

The motivation behind the addition of this check can be found in Writing R Extensions: Section 5.4 Registering native routines and on R-devel: [Rd] Registration of native routines. More aptly, the motivation can be surmised by:

Registering routines has two main advantages: it provides a faster way to find the address of the entry point via tables stored in the DLL at compilation time, and it provides a run-time check that the entry point is called with the right number of arguments and, optionally, the right argument types.

However, the cost of these benefits is apparent to users of Rcpp as a minor inconvenience in the current build cycle. Presently, those that use Rcpp to generate the glue between R and C++ must manually trigger the creation of the package registration. The upside of this generation is it is as painless as merrying R with C++ using Rcpp thanks to R core – more so Kurt Hornik and Prof. Brian Ripley – releasing a tool to automatically create the necessary file. The remainder of this post talks specifically about how to use that tool.

Native routine registration helper

Prerequisites

The following assumes:

  • R 3.4
  • Package contains compiled code.

Package Registration Steps

To register routines for mypackage, perform the following steps:

  • Set the working directory to the package top-level. e.g.
setwd("/path/to/mypackage")
/mypackage (<--- this level)
  |- R/
     |- RcppExports.R
     |- ...
  |- src/
     |- RcppExports.cpp
     |- hello_world.cpp
     |- ...
  |- DESCRIPTION
  |- NAMESPACE
  |- ...
  • Automatically generate for 90% of the case the required package generation details using a function in R 3.4’s tools package that is relatively long…
tools::package_native_routine_registration_skeleton(".", "src/init.c")

Within the function call above, we direct the output immediately into the src/init.c file to avoid having to copy and paste from the terminal output. Furthermore, we also use the fact that the working directory is the correct top-level directory within the first argument (e.g. ".").

The src/init.c file for one of my R packages called [sitmo] (with some trunctions) looks like:

#include <R.h>
#include <Rinternals.h>
#include <stdlib.h> // for NULL
#include <R_ext/Rdynload.h>

/* FIXME: 
Check these declarations against the C/Fortran source code.
*/

/* .Call calls */
extern SEXP sitmo_runif_r(SEXP, SEXP, SEXP);
extern SEXP sitmo_sitmo_two_seeds(SEXP, SEXP);

static const R_CallMethodDef CallEntries[] = {
  {"sitmo_runif_r",            (DL_FUNC) &sitmo_runif_r,            3},
  {"sitmo_sitmo_two_seeds",    (DL_FUNC) &sitmo_sitmo_two_seeds,    2},
  {NULL, NULL, 0}
};

void R_init_sitmo(DllInfo *dll)
{
  R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);
  R_useDynamicSymbols(dll, FALSE);
}

Note: The above has been automatically generated similar to the autogeneration magic of RcppExports.R and RcppExports.cpp.

  • Update NAMESPACE by adding the following line:
useDynLib(mypackage, .registration = TRUE)

or if you are using roxygen2 use this roxygen tag:

#' @useDynLib mypackage, .registration = TRUE

As this tag relates to a package level descriptor, I group it with the roxygen2 "_PACKAGE" content block. For example, we have:

#' @useDynLib mypackage, .registration = TRUE
#' @details
#' Juicy package implementation specifics
#' @seealso \code{\link{func}}
"_PACKAGE"
  • (Optional) Update function export preferences in the NAMESPACE file

Furthermore, while in the NAMESPACE file make sure to remove any trace of exportPattern() that is automatically placed there when using package.skeleton(). Commonly, the line looks like:

exportPattern("^[[:alpha:]]+") 

If there is an exportPattern() within the package’s NAMESPACE, this captures a large range of functions. Inadvertently, this now captures RcppExport named functions in C++, e.g. mypackage_function_name. Thus, each function that you are interested in exporting must be explicitly stated in the NAMESPACE file. For example:

export(sample_func)
export(hello_world)

For those using roxygen2, they can use the @export roxygen tag within their code block. Thus, we would have:

#' Some function
#' 
#' Description
#' @param x A \code{integer}.
#' @return Many values
#' Add this export tag below!!!
#' @export
#' @details
#' Sample Function using the roxygen export tag
#' @examples
#' hello_world(1)
hello_world <- function(x) {
  for(i in seq_len(x)) {
    print("Hello World!")
  }
}

Fin

Having said the above piece, the package should now be ready to ship to CRAN in this brave new R 3.4 world. Before shipping, please make sure to test whether your functions still are accessible. If yet to make these tests formal, consider using unit tests via RUnit or testthat.