Skip to content
Jean Thioulouse edited this page Jan 29, 2025 · 2 revisions

To use C++ functions with Rcpp in the ade4 package, one needs to:

  • Install the Rcpp package
  • Install the RcppArmadillo package (if needed)
  • Modify several files

Source files:

  • Files containing C++ code (.cpp) in the "src" folder
  • Files containing R code (.R) in the "R" folder
  • Files containing Rd code (.Rd) in the "man" folder
  • Add aliases for C++ functions in file "man/ade4-internals.Rd"

ade4-internals Rd

R System files:

  • DESCRIPTION file
  • NAMESPACE file

"DESCRIPTION" file: To be done only once (should be done already !)

  • In the "Imports:" field, add Rcpp (and RcppArmadillo, if needed)
  • Add the "LinkingTo:" field, and add Rcpp to it

"NAMESPACE" file: Export all the added functions (R and C++):

  • export("RV.randtest")
  • export("RVrandtestCpp")

NAMESPACE

Two files, RcppExports.cpp and RcppExports.R are created automatically by the Rcpp::compileAttributes() function.

  • In the "src" folder : File RcppExports.cpp contains the declaration of C++ functions
  • In the "R" folder : File RcppExports.R contains the declaration of R functions

Warning ! These two files are re-generated automatically each time the Rcpp::compileAttributes() is called.


File RcppExports.cpp : nothing to change. The header string "ade4" is added to the beginning of the name of each exported function.

// Generated by using Rcpp::compileAttributes() -> do not edit by hand
// Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393

#include <RcppArmadillo.h>
#include <Rcpp.h>

using namespace Rcpp;
#ifdef RCPP_USE_GLOBAL_ROSTREAM
Rcpp::Rostream<true>&  Rcpp::Rcout = Rcpp::Rcpp_cout_get();
Rcpp::Rostream<false>& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get();
#endif

// RVintrarandtestCpp
arma::vec RVintrarandtestCpp(const arma::mat& X, const arma::mat& Y, Rcpp::IntegerVector fac, const int nrepet);
RcppExport SEXP _ade4_RVintrarandtestCpp(SEXP XSEXP, SEXP YSEXP, SEXP facSEXP, SEXP nrepetSEXP) {
BEGIN_RCPP
    Rcpp::RObject rcpp_result_gen;
    Rcpp::RNGScope rcpp_rngScope_gen;
    Rcpp::traits::input_parameter< const arma::mat& >::type X(XSEXP);
    Rcpp::traits::input_parameter< const arma::mat& >::type Y(YSEXP);
    Rcpp::traits::input_parameter< Rcpp::IntegerVector >::type fac(facSEXP);
    Rcpp::traits::input_parameter< const int >::type nrepet(nrepetSEXP);
    rcpp_result_gen = Rcpp::wrap(RVintrarandtestCpp(X, Y, fac, nrepet));
    return rcpp_result_gen;
END_RCPP
}

File RcppExports.R (in the "R" folder), the header string "C_" must be added to the beginning of each function name in the call to the .Call function (see first line of NAMESPACE file).

# Generated by using Rcpp::compileAttributes() -> do not edit by hand
# Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393

RVintrarandtestCpp <- function(X, Y, fac, nrepet) {
    .Call(`C__ade4_RVintrarandtestCpp`, X, Y, fac, nrepet)
}

RVrandtestCpp <- function(X, Y, nrepet) {
    .Call(`C__ade4_RVrandtestCpp`, X, Y, nrepet)
}

procusterandtestCpp <- function(X, Y, nrepet) {
    .Call(`C__ade4_procusterandtestCpp`, X, Y, nrepet)
}

Another file must be edited manually: file "init.c" in the "src" folder. It contains the definitions of all the external functions (C and C++). The new C++ function must be added there, replacing all arguments by void * and adding the number of arguments.

  • C function definitions go to the static const R_CMethodDef CEntries[] = { parameter
  • C++ function definitions go to the static const R_CallMethodDef CallEntries[] = { parameter
  • Header string "C_" must NOT be added before each function names

Note that this file is NOT rebuilt automatically by function Rcpp::compileAttributes().

#include <R.h>
#include <Rinternals.h>
#include <stdlib.h> // for NULL
#include <R_ext/Rdynload.h>

/* .C calls */
extern void gearymoran(void *, void *, void *, void *, void *, void *, void *);
extern void MSTgraph(void *, void *, void *, void *);
etc...

/* .Call calls */
extern void _ade4_RVrandtestCpp(void *, void *, void *);
extern void _ade4_RVintrarandtestCpp(void *, void *, void *, void *);
etc...

static const R_CMethodDef CEntries[] = {
  {"gearymoran",                 (DL_FUNC) &gearymoran,                  7},
  {"MSTgraph",                   (DL_FUNC) &MSTgraph,                    4},
etc...

static const R_CallMethodDef CallEntries[] = {
    {"_ade4_procusterandtestCpp", (DL_FUNC) &_ade4_procusterandtestCpp, 3},
    {"_ade4_RVrandtestCpp", (DL_FUNC) &_ade4_RVrandtestCpp, 3},
etc...

void R_init_ade4(DllInfo *dll)
{
  R_registerRoutines(dll, CEntries, CallEntries, NULL, NULL);
  R_useDynamicSymbols(dll, FALSE);
}

Notes:

  • Once everything is set up, one can compile the ade4 package as usual with R CMD build/check/install.
  • During development stages, function Rcpp::sourceCpp() can be used to compile and execute C++ functions, without re-building the whole package.
  • Function Rcpp::compileAttributes() should be used to update the new C++ function definitions in files RcppExports.cpp and RcppExports.R, but the header string "C_" must be added manually each time before each function name in file RcppExports.R.
  • Warning ! When using Rstudio for the "check" step, function Rcpp::compileAttributes(), will change files RcppExports.cpp and RcppExports.R. So the header string "C_" will be missing before function names, and compilation will fail.

Using a library of C++ functions:

  • As in the case of C functions, C++ functions can be collected in a library.
  • For C functions, file src/tests.c contains the permutation tests functions (testinter, testdiscrimin, testertrace, etc.)
  • There is also the src/adesub.c file that contains "base" functions, (matrix computations, dynamic memory allocation, random permutations, etc.) The definitions of these functions are in the src/adesub.h file.

  • For C++ functions, file testsCpp.cpp contains permutation test functions re-written in C++ (for example, testinter becomes testinterCpp, etc.)
  • "Base" C++ functions (equivalent to the C functions in adesub.c) are grouped in file src/ade4libCpp.cpp and their definitions are in file inst/include/ade4libCpp.h.

Clone this wiki locally