Search code examples
reigenrcpp

Building custom R package leads to undefined symbol


I'm currently working on a R package that depends on Eigen, EigenRand, and GSL. I was able to successfully build the package when it just depended on Eigen and GSL. Now, when I build, the compile is successful, but R is not able to link the .so file.

this is my Makevars file:

PKG_LIBS = $(R_HOME)/bin/Rscript -e "Rcpp:::LdFlags()"` `gsl-config --libs`
PKG_CPPFLAGS = -I '/path/to/include/eigen-3.4.0' -I '/path/to/include/EigenRand'

this is the error message:

Error: package or namespace load failed for ‘pkgname’ in dyn.load(file, DLLpath = DLLpath, ...):
 unable to load shared object '/tmp/RtmpwgpGqO/Rinst855c41160545/00LOCK-pkgname/00new/pkgname/libs/pkgname.so':
  /tmp/RtmpwgpGqO/Rinst855c41160545/00LOCK-pkgname/00new/pkgname/libs/pkgname.so: undefined symbol: _ZN4Rcpp9RcppEigen10eigen_wrapIN5Eigen5ArrayIiLin1ELin1ELi0ELin1ELin1EEEEEP7SEXPRECRKT_
Error: loading failed
Execution halted
ERROR: loading failed

I’ve changed the actual name to “pkgname” where it fits.

I was able to successfully compile and link to a package when the code just involved Eigen and GSL so I don’t think it’s a problem with these two libraries, and installing RcppEigen led to error with unknown includes, so I didn’t switch to RcppEigen.

Edit: I think I can reproduce the problem with this setup. I guess I couldn't build with Eigen, but because I didn't return the array created with Eigen, the compiler optimised it away for me. I would still be interested in knowing what went wrong though because even if I were to use the RcppEigen library, I still need to import EigenRand, which does not have a R package yet.

src/pkgexports.cpp:

#include <Rcpp.h>
using namespace Rcpp;

List pkgfn();
RcppExport SEXP pkgfn_pkgfn() {
BEGIN_RCPP
    Rcpp::RObject __result;
    Rcpp::traits::input_parameter< int >::type seed(seedSEXP);

    __result = Rcpp::wrap(pkgfn());
    return __result;
END_RCPP
} 

src/pkgfn.cpp:

#include <R.h>
#include <Rmath.h>
#include <Rcpp.h>
#include <Eigen/Dense>

using Rcpp::List;
using Rcpp::_;
using namespace Eigen;

List pkgfn(){
    ArrayXd r_beta = ArrayXd::Random(4);
    return List::create(_["r_beta"] = r_beta);
}

Makevars:

PKG_CPPFLAGS = -I '/usr/local/include/eigen3'  

Edit2: I've installed all other libraries using Mamba/Conda in another enviroment, but because Eigen & EigenRand doesn't seem to have channels for that I have installed them from source and added them to /usr/local/include


Solution

  • This seems to solve the problem. There was nothing wrong with including the libraries.

    src/pkgfn.cpp:

    #include <R.h>
    #include <Rmath.h>
    #include <Rcpp.h>
    #include <Eigen/Dense>
    
    using Rcpp::List;
    using Rcpp::_;
    using namespace Eigen;
    
    List pkgfn(){
        ArrayXd r_beta = ArrayXd::Random(4);
        auto r_beta_vec = vector<double>(r_beta.data(), r_beta.data()+4);
        return List::create(_["r_beta"] = r_beta_vec);
    }