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
).
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")
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
GPL (>= 2)