3. A minimal Rcpp package#

R provides a mechanism for grouping together related files containing, amongst other things, R code, c++ code, documentation, data files, vignettes, and so on. This mechanism also supports the management of package dependencies, version control, package citations and so on.

Although the R packaging mechanism is distinct from Rcpp, it can be used in conjunction with it. After all, Rcpp is an R package itself. One of the advantages of doing this (from the Rcpp perspective) is that the R package mechanism enables Rcpp to work with multiple *c++ source files.

Ultimately, an R package is just a collection of appropriately named files in a prescribed directory structure. There are many tools to help you construct an R package, but the minimal Rcpp enabled package is quite simple to create. The figure below shows the basic directory structure and files needed to create a minimal Rcpp package.

Here, praxi is the name of the package being created.

3.1. Exercise#

Create the above directory structure.

3.2. The DESCRIPTION file#

The DESCRIPTION file contains a basic description of the package (named praxi in this case) and other information such as the package maintainer details and other R packages that praxi is dependent on. Notice that that the Imports: and LinkingTo: fields in the DESCRIPTION file list the Rcpp package.

Package: praxi
Type: Package
Title: What the Package Does in One 'Title Case' Line
Version: 1.0
Date: 2024-02-29
Author: Your Name
Maintainer: Your Name <your@email.com>
Description: One paragraph description of what the package does as one
        or more full sentences.
License: GPL (>= 2)
Imports: Rcpp (>= 1.0.12)
LinkingTo: Rcpp

3.3. Exercise#

Create the DESCRIPTION file and place it into the praxi package directory structure. Note, you can set the name of the package using the

Package: 

field of the DESCRIPTION file.

3.4. The NAMESPACE file#

The NAMESPACE file also lists the dependencies of the package. It also registers the library when it is installed and exports the methods in the package for a user to access when the package is loaded using the library function within an R session or script. Notice that the package name appears in the useDynLib directive.

useDynLib(praxi, .registration=TRUE)
import(methods, Rcpp)
exportPattern("^[[:alpha:]]+")

3.5. Exercise#

Create the NAMESPACE file and place it into the praxi package directory structure.

3.6. The load_Rcpp_module.R file¶#

This file is used to load Rcpp modules into an R session.

loadModule("marshalling", TRUE)

Note, that the file does not have to be called load_Rcpp_module.R, but this is a good descriptive choice. It can also contain multiple loadModule directives (if you have more than one module to load. Of course, the module names correspond to those you use in your augmented c++ code.

3.7. Exercise#

Create the load_Rcpp_module.R file and place it into the praxi package directory structure.

3.8. The Makevars file#

The Makevars file is optional. It can be used to configure the way in which the R package gets constructed. Importantly, it can contain information about which version of c++ compiler to use when creating the package.

CXX_STD=CXX17

In this case, a c++ 17 compiler is specified.

3.9. Exercise#

Create the Makevars file and place it into the praxi package directory structure.

3.10. The c++ source and header files#

To add c++ code to the package, place your source code (.cpp) and header (.h) files in the src directory. This source code should include any Rcpp specific code, such as the module definitions. For example

#include "Rcpp.h"
using namespace Rcpp;


#include <string>
#include <iostream>


std::string marshall_string(const std::string& X)
{
    Rcout << X << std::endl;
    std::string Y {" blady blah ..."};
    return X + Y;
}

RCPP_MODULE(marshalling) 
{
function("rcpp_marshall_string", &marshall_string);
}

Note that you can separate your source code from the module definitions by using header files. Each *.cpp file in the src directory will be compiled and made available for use by other c++ functions in your package. However, only those functions added to the module will be available to users of your package.

3.11. Installing an R package using devtools#

R packages can be installed in various different ways. For example, directly from CRAN using the install.packages function from within an R session. Packages can also be installed from compressed tar files, from local file systems, and from github. A useful package for managing the installation of R packages is devtools. This package has a wide variety of facilities to help with building, hosting, debugging, and maintaining R packages. the devtools package can be installed directly from CRAN.

Note - devtools is a large package with many dependencies, so it may take some time to download and install.

install.packages("devtools")
Installing package into ‘/home/grosedj1/STOR-601-env/R-packages’
(as ‘lib’ is unspecified)

Once devtools has been installed it is an easy process to install the minimal Rcpp package from the local file system.

library(devtools)
install_local("praxi",force=TRUE)
── R CMD build ─────────────────────────────────────────────────────────────────
  checking for file ‘/tmp/RtmpcXf6Zd/file293b8b6eed24/praxi/DESCRIPTION’
─  preparing ‘praxi’:
  checking DESCRIPTION meta-information
─  cleaning src
─  checking for LF line-endings in source and make files and shell scripts
─  checking for empty or unneeded directories
─  building ‘praxi_1.0.tar.gz’
   
Installing package into ‘/home/grosedj1/STOR-601-env/R-packages’
(as ‘lib’ is unspecified)

The package has now available for use in R.

library(praxi)
rcpp_marshall_string("hello")
hello
'hello blady blah ...'

3.12. Hosting a package on github#

The easiest way to organise an R package on github is to create a new repository with same name as the package. The files and directories within the R package are then added to the repository (i.e. the top level package directory is not included. For example, in the case of the praxi package the repository should look like.

The package can now be installed directly from github, again usng devtools.

devtools::install_github("grosed/praxi",force=TRUE)
Downloading GitHub repo grosed/praxi@HEAD
── R CMD build ─────────────────────────────────────────────────────────────────
  checking for file ‘/tmp/RtmpXfyIQM/remotes2973288e5d5a/grosed-praxi-d51fbfb/DESCRIPTION’
─  preparing ‘praxi’:
  checking DESCRIPTION meta-information
─  cleaning src
─  checking for LF line-endings in source and make files and shell scripts
─  checking for empty or unneeded directories
─  building ‘praxi_1.0.tar.gz’
   
Installing package into ‘/home/grosedj1/STOR-601-env/R-packages’
(as ‘lib’ is unspecified)
library(praxi)
rcpp_marshall_string("hello")
hello
'hello blady blah ...'