R Package Integration with Modern Reusable C++ Code Using Rcpp - Part 4

by Daniel Hanson

Daniel Hanson is a full-time lecturer in the Computational Finance & Risk Management program within the Department of Applied Mathematics at the University of Washington.

In the previous post in this series, we looked at how to write interface files using Rcpp to call functions and instantiate classes in standard and reusable C++, with a code interface and reusable code examples shown in the discussion. My original plan for this week was to show how to import that code into an RStudio Rcpp project and build it into an R package, but as there are a number of steps in the setup and build process, we’ll first look at a very simple example to demonstrate these, and then we’ll turn our attention to importing the reusable C++ code next time.

The following discussion will be a step by step guide in the project configuration and build process with a single example .cpp file that is included by default when creating an Rcpp project in the RStudio IDE.

Creating an Rcpp Package Project in the RStudio IDE

Open the RStudio IDE, and select New Project... from the File menu at the top, and select New Directory as shown here:

New Project Wizard

Next, you will see the following selections, from which you should choose R Package using Rcpp. Be sure to make this selection, and not R package alone as shown above:

Select R Package using Rcpp

Next, enter the desired directory path and new subdirectory name, and create the project; the subdirectory will be the name of your R package, e.g. RcppProject:

Type in your package name

When finished, your RStudio session should look something like this:

RStudio Rcpp project

There is one more step to complete in order to ensure your interface functions will be exposed as R functions to your package users. In the Files pane at lower right, you should see a file called NAMESPACE:

The NAMESPACE file inside the package file structure

Double click on this file to open it in RStudio; you will see the following:

Original NAMESPACE file

Now, delete line 2, and then append a new line 3, as shown below. This will allow your tagged C++ interface files to be exportable to R. Leave line 4 blank, just as it is in the original. Then, save the file:

Updated NAMESPACE file

Remark: There are more advanced ways to configure the NAMESPACE file when building an R package, which would require in-depth explanation, distracting us from the main task of getting up and running with Rcpp. As such, we’ll just use this simple fix for our discussion.

Building an R Package

Returning to the Files pane in the RStudio IDE (see Figure 5 above), note the following sudirectories:

  • man: For documentation files (we will return to this in a later installment).
  • R: For R code to be included in a package; for now, we will only be concerned with C++ code.
  • src: This is where C++ code is located in the package:

    • Both header (.h) and implementation (.cpp) files
    • Both interface and reusable C++ code files

By clicking on the src subdirectory, you will see that there are two C++ files that are present by default in a blank RStudio Rcpp project:

Default C++ files

  • rcpp_hello_world.cpp: Simple interface function included as an example, by default.
  • RcppExports.cpp: This is a C++ file that is generated each time the Rcpp project is built in the RStudio environment. You need not be concerned about its contents, but it is crucial that you never modify this file on your own.

The rcpp_hello_world.cpp file

Let’s look at this simple example first. It should look somewhat similar to the C++ interface files presented last time. The main difference is it does not call any functions in an external file; it simply returns an R List object to the function user in R. Note the // [[Rcpp::export]] tag; this will export the rcpp_hello_world() function to R:

#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
List rcpp_hello_world() {
    CharacterVector x = CharacterVector::create( "foo", "bar" )  ;
    NumericVector y   = NumericVector::create( 0.0, 1.0 ) ;
    List z            = List::create( x, y ) ;
    return z ;
}

Your First R Package with C++ Code

Now, let’s build the package with this single C++ function. To do this, from the Build menu at the top of the RStudio IDE, and select Clean and Rebuild. In the upper right hand pane in the IDE, you will then see the C++ being compiled, and the package being built.

Select 'Clean and Rebuild' to build the R package

When the build is complete, your R session will restart, and your package will be loaded into your current R session, as shown in the console at the bottom of the R Studio IDE:

R restarts and loads the package after the build is complete

Now, type in rcpp_hello_world() at the console prompt, and check your results. You should see the following:

Run 'rcpp_hello_world()' in R

Congratulations! You have just built your first R package with integrated C++, and you called the exported function from an R session. You can also check that the package contents have been placed in the usual .../R-4.0.x/library directory, in a subdirectory with the package name, just like any other R package you load from CRAN.

Distribute the Package as a Binary

You can also export the package in binary form to a .zip file on Windows, or a tar.gz file on the Mac or on Linux. To do this, again from the Build menu, select Build Binary Package.

Build the package binary for distribution

You will again see the compile and build process in the upper right hand corner of the RStudio IDE. When complete, you can find your distributable file, e.g. RcppProject.zip, in the directory one level up from your project directory. To deploy it, either copy it to another machine with the same OS and R setup, or delete the package subdirectory, e.g. .../R-4.0.x/library/RcppProject. Then, open an new RStudio session, and install the package just as you would any other package locally:
\newpage

Install package locally

Next, load the package in your session, e.g. library(RcppProject), and then call the exported function again to verify it works.

Summary

We have now covered the process of building an R package containing C++ code in RStudio IDE, by integrating the code into an Rcpp project. The C++ code in this case consisted of a single .cpp file, with a single interface function tagged for export to R, to keep the discussion focused more on the process itself. Next time, we will revisit the C++ code file examples in the previous post, and show how to integrate them into an R package. The process is essentially the same as above, but with multiple source code files and multiple interface files, it will involve some additional management and other details.

Share Comments · · · · · ·

You may leave a comment below or discuss the post in the forum community.rstudio.com.