Search code examples
rcpprcpp11

Register C++ version of Rcpp function and use it within the other Rcpp function in a new package


I have a package hpa that has some functions written in Rcpp. I want to use some of these functions within my new R-package. It is necesseraly to use this functions in "Rcpp form" in order to avoid perfomance penalty so I can't to export them in a usual way.

I have found a similar questions. Following the answer of Dirk Eddelbuettel I have investigated this file and written the following code (within init.c file that has been placed in the src folder) in hope to make polynomialIndex function (from hpa package) become available (in Rcpp i.e. C++ form) for Rcpp functions of other pacakges (including my new one):

#include <Rconfig.h>
#include <Rinternals.h>
#include <R_ext/Rdynload.h>
#include "polynomialIndex.h"

/* definition of functions provided for .Call()             */
static const R_CallMethodDef callMethods[] = {
    { "polynomialIndex", (DL_FUNC) &polynomialIndex, 1 },
    { NULL, NULL, 0 }
};

/* functions being called when package is loaded -- used to register    */
/* the functions we are exporting here                  */
void R_init_RApiSerialize(DllInfo *info) {

    /* used by external packages linking to internal serialization code from C */
    R_RegisterCCallable("hpa", "polynomialIndex", 
                        (DL_FUNC) &polynomialIndex);

    R_registerRoutines(info,
                       NULL,        /* slot for .C */
                       callMethods,     /* slot for .Call */
                       NULL,            /* slot for .Fortran */
                       NULL);       /* slot for .External */

    R_useDynamicSymbols(info, TRUE);    /* controls visibility */ 
}

Unfortenatelly when I am trying to build hpa package the following error message arise:

/mingw64/bin/gcc  -I"C:/R/R-41~1.0/include" -DNDEBUG  -I'C:/R/R-4.1.0/library/Rcpp/include' -I'C:/R/R-4.1.0/library/RcppArmadillo/include' -I'C:/R/R-4.1.0/library/RcppParallel/include'        -O2 -Wall  -std=gnu99 -mfpmath=sse -msse2 -mstackrealign  -c init.c -o init.o
In file included from C:/R/R-4.1.0/library/Rcpp/include/Rcpp/r/headers.h:66,
                 from C:/R/R-4.1.0/library/Rcpp/include/RcppCommon.h:30,
                 from C:/R/R-4.1.0/library/RcppArmadillo/include/RcppArmadilloForward.h:26,
                 from C:/R/R-4.1.0/library/RcppArmadillo/include/RcppArmadillo.h:31,
                 from polynomialIndex.h:4,
                 from init.c:4:
C:/R/R-4.1.0/library/Rcpp/include/Rcpp/platform/compiler.h:100:10: fatal error: cmath: No such file or directory
 #include <cmath>
          ^~~~~~~
compilation terminated.
make: *** [C:/R/R-41~1.0/etc/x64/Makeconf:238: init.o] Error 1

It seems to be associated with the fact that polynomialIndex.h file includes <RcppArmadillo.h>. The file itself looks as follows:

#ifndef hpa_polynomialIndex_H
#define hpa_polynomialIndex_H

#include <RcppArmadillo.h>
using namespace Rcpp;
using namespace RcppArmadillo;

NumericMatrix polynomialIndex(NumericVector pol_degrees,
                              bool is_validation);

String printPolynomial(NumericVector pol_degrees, 
                       NumericVector pol_coefficients,
                       bool is_validation);

#endif

Then I have tried to remove polynomialIndex.h from init.c and to declare polynomialIndex directly inside init.c file. Unfortunatelly it results into the other error message:

/mingw64/bin/gcc  -I"C:/R/R-41~1.0/include" -DNDEBUG  -I'C:/R/R-4.1.0/library/Rcpp/include' -I'C:/R/R-4.1.0/library/RcppArmadillo/include' -I'C:/R/R-4.1.0/library/RcppParallel/include'        -O2 -Wall  -std=gnu99 -mfpmath=sse -msse2 -mstackrealign  -c init.c -o init.o
** using staged installation
** libs
/mingw64/bin/g++ -std=gnu++11 -shared -s -static-libgcc -o hpa.dll tmp.def ParallelFunctions.o RcppExports.o hpaBinary.o hpaML.o hpaMain.o hpaSelection.o hpaValidation.o init.o normalMoments.o polynomialIndex.o spline.o -LC:/R/R-41~1.0/bin/x64 -lRlapack -LC:/R/R-41~1.0/bin/x64 -lRblas -lgfortran -lm -lquadmath -LC:/R/R-41~1.0/bin/x64 -lR
C:/rtools40/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: init.o:init.c:(.text+0x8): undefined reference to `polynomialIndex'
C:/rtools40/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: init.o:init.c:(.rdata+0x28): undefined reference to `polynomialIndex'
C:/rtools40/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: init.o:init.c:(.rdata$.refptr.polynomialIndex[.refptr.polynomialIndex]+0x0): undefined reference to `polynomialIndex'

Please help me to figure out these problems. In the end I want to be able to use polynomialIndex function within my new package. According to the information I have found it should look something like this (simplifed expample):

// [[Rcpp::depends(hpa)]]
#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector newFunc(NumericVector pol_degrees,
                      bool is_validation) {
  
  static SEXP(*polynomialIndex)(Rcpp::NumericVector, bool) = NULL;
  polynomialIndex = (SEXP(*)(Rcpp::NumericVector, bool)) R_GetCCallable("hpa", "polynomialIndex");
  
  NumericVector result = polynomialIndex(pol_degrees, is_validation);
  
  return(result);
}

P.S. This question is also similar to this one but does not resolve my problem.


Solution

  • This has been discussed before, and I would urge you to study these other questions and experiment with their answers.

    Here you appear to have a cross-over from a C compilation (started by gcc) touching a file in which you crossed over to C++. Which, plainly stated, you cannot do for C compilation.

    R offers C interfaces only. Rcpp helps you by autogenerating complying interface files. If you want to extend/alter them you have to play by the rules.

    Wrapping C++ code in (simpler, more portable, cross-compiler, ...) C interfaces is a decades old trick. You likely find many resources for it.