Embedding Multiple Code Files in src/ with Headers

Separating compiled code into individual units using header files

programming
cpp
Author

James Balamuta

Published

March 10, 2015

This post is a version of the rcpp-headers-src README from the R&D Rcpp collection of compiled-code examples. The repository holds the full, runnable source.

This small example R package demonstrates how to split compiled C++ functions across several files in src/ and tie them together with header files, so each routine lives in its own translation unit while remaining callable from R. It is one of the R&D Rcpp prototype packages, a collection of minimal examples for integrating compiled code with R.

The SrcDir R package provides an example of using header files to split apart functions into separate code files while still being able to use each function.

In essence, this project shows how to go from:

src/
    |-> large-code-file.cpp

to:

src/
    |-> combined-routines.cpp
    |-> routineA.cpp
    |-> routineA.h
    |-> routineB.cpp
    |-> routineB.h

For further organization, see the SubdirSrc package for an example of compiling code found in src/ subdirectories (e.g. src/A, src/B).

Usage

To install the package, you must first have a compiler on your system that is compatible with R. For help on obtaining a compiler consult either macOS or Windows guides.

With a compiler in hand, one can then install the package from GitHub by:

# install.packages("remotes")
remotes::install_github("coatless-rd-rcpp/rcpp-headers-src")
library("SrcDir")

Implementation Details

Separating out code into different files requires the use of header files (.h). Headers provide a way to share function definitions and preprocessor macros between two or more C++ files (.cpp). Using the header inside of another file requires the use of the #include preprocessor directive, which effectively “copies” the contents of the header into the other file.

Take for instance the routineA.cpp file.

#include <Rcpp.h>
#include "routineA.h"

// [[Rcpp::export]]
Rcpp::NumericVector calc_A_routine(Rcpp::NumericVector x) {
  Rcpp::NumericVector a = x - 4;
  return a;
}

Note, there are two different kinds of #include used:

  • #include <header_system.h>
    • <> indicate a system header file found in system directories or supplied with -I.
    • Rcpp.h is a system library as it is located outside of the project space.
  • #include "header_local.h"
    • "" means the file resides in the working directory of the program.

For more details, please see Section 2.1 Include Syntax of the gcc documentation.

The accompanying header file would be routineA.h. The header would contain the function definition for calc_A_routine() as it is the only function declared within the file.

// Defines a header file containing function signatures for functions in src/

// Protect signatures using an inclusion guard.
#ifndef routineA_H
#define routineA_H

Rcpp::NumericVector calc_A_routine(Rcpp::NumericVector x);

#endif

As the header contents is “copied”, it is important to protect the function definitions to ensure they are only included once. To prevent this from happening, an inclusion guard is used. By checking for whether a variable is defined with #ifndef, the header file can be copied completely or skip the define portion. In short, the design pattern for this can be succiently stated as:

#ifndef myfilename_H
#define myfilename_H

// Contents here

#endif

From here, both routines A and B can be included inside a third file such as combined-routines.cpp. The inclusion statements would be:

#include <Rcpp.h>

// Load directory header files
#include "routineA.h"
#include "routineB.h"

// additional code

Source

The full package source is available on GitHub, and you can browse the rendered package site at rd-rcpp.thecoatlessprofessor.com/rcpp-headers-src.