README.md

Separating Compiled Code into Individual Units with Headers

R-CMD-check

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:

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

License

GPL (>= 2)



coatless/header_cpp_code documentation built on March 13, 2024, 6:01 a.m.