Linking error of R package with Rcpp: “undefined symbol: LAPACKE_dgels”

大憨熊 提交于 2019-12-13 14:52:42

问题


I am creating an R package 'lapacker' to provide the C interface for internal LAPACK library provided and used by R (with double precision and double complex only) using the R API header file "R_ext/Lapack.h". The source code: https://github.com/ypan1988/lapacker/

And the project structure:

/lapacker
  /inst
    /include
      /lapacke.h
      /someother header files
  /R
    /zzz.R
  /src
    /lapacke_dgetrf.c
    /lapacke_dgetrf_work.c
    /loads of other utility functions provided by LAPACKE 
    /rcpp_hello.cpp
  DESCRIPTION
  NAMESPACE

Inside the project, I tried a test function in rcpp_hello.cpp file (Note this example is coming from https://www.netlib.org/lapack/lapacke.html#_calling_code_dgels_code):

//'@export
// [[Rcpp::export]]
void example_lapacke_dgels()
{
  double a[5][3] = {{1,1,1},{2,3,4},{3,5,2},{4,2,5},{5,4,3}};
  double b[5][2] = {{-10,-3},{12,14},{14,12},{16,16},{18,16}};
  lapack_int info,m,n,lda,ldb,nrhs;
  int i,j;

  m = 5;
  n = 3;
  nrhs = 2;
  lda = 3;
  ldb = 2;

  info = LAPACKE_dgels(LAPACK_ROW_MAJOR,'N',m,n,nrhs,*a,lda,*b,ldb);

  for(i=0;i<n;i++)
  {
    for(j=0;j<nrhs;j++)
    {
      printf("%lf ",b[i][j]);
    }
    printf("\n");
  }
}

The whole package can compile properly with no errors, and in R it gives the right answer(indicating symbol LAPACKE_dgels can be found):

> example_lapacke_dgels()
2.000000 1.000000 
1.000000 1.000000 
1.000000 2.000000 

However, when I create a separate C++ file, say demo3.cpp with exactly the same function,

#include <Rcpp.h>

#include <lapacke.h>
// [[Rcpp::depends(lapacker)]]

// [[Rcpp::export]]
void lapacke_dgels_test()
{
  double a[5][3] = {{1,1,1},{2,3,4},{3,5,2},{4,2,5},{5,4,3}};
  double b[5][2] = {{-10,-3},{12,14},{14,12},{16,16},{18,16}};
  lapack_int info,m,n,lda,ldb,nrhs;
  int i,j;

  m = 5;
  n = 3;
  nrhs = 2;
  lda = 3;
  ldb = 2;

  info = LAPACKE_dgels(LAPACK_ROW_MAJOR,'N',m,n,nrhs,*a,lda,*b,ldb);

  for(i=0;i<n;i++)
  {
    for(j=0;j<nrhs;j++)
    {
      printf("%lf ",b[i][j]);
    }
    printf("\n");
  }
}

it no longer compiles properly (actually I tried under both macOS and ubuntu, same linking problem), and gives linking error messages (Cannot find symbol LAPACKE_dgels):

> Rcpp::sourceCpp("~/Desktop/demo3.cpp", showOutput = TRUE)
/usr/lib/R/bin/R CMD SHLIB -o 'sourceCpp_6.so'  'demo3.cpp'  
g++  -I/usr/share/R/include -DNDEBUG   -I"/home/yipan/R/x86_64-pc-linux-gnu-library/3.4/Rcpp/include" -I"/home/yipan/R/x86_64-pc-linux-gnu-library/3.4/lapacker/include" -I"/home/yipan/Desktop"    -fpic  -g -O2 -fdebug-prefix-map=/build/r-base-AitvI6/r-base-3.4.4=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g  -c demo3.cpp -o demo3.o
g++ -shared -L/usr/lib/R/lib -Wl,-Bsymbolic-functions -Wl,-z,relro -o sourceCpp_6.so demo3.o -L/usr/lib/R/lib -lR
Error in dyn.load("/tmp/RtmpUsASwK/sourceCpp-x86_64-pc-linux-gnu-1.0.0/sourcecpp_159e6145591d/sourceCpp_6.so") : 
  unable to load shared object '/tmp/RtmpUsASwK/sourceCpp-x86_64-pc-linux-gnu-1.0.0/sourcecpp_159e6145591d/sourceCpp_6.so':
  /tmp/RtmpUsASwK/sourceCpp-x86_64-pc-linux-gnu-1.0.0/sourcecpp_159e6145591d/sourceCpp_6.so: undefined symbol: LAPACKE_dgels

I have also checked the lapacker.so under /R/x86_64-pc-linux-gnu-library/3.4/lapacker/libs and found:

000000000000c6b0 g    DF .text  00000000000001bf  Base        LAPACKE_dgels

Do I miss something to get the demo3.cpp compile correctly? Thanks very much for your patience and time!


回答1:


You are facing a difficult problem here. The Symbol you are trying to resolve LAPACKE_dgels is part of lapacker.so, build during package installation. Problem is, that the libraries for R packages are not meant for linking. Instead, they are loaded by R dynamically at run-time. Basically, I see four possibilities:

  1. Convert lapacke into a header only library and install that in inst/include (c.f. RcppArmadillo).
  2. Link with a system installation of lapacke (easy on Linux ...)
  3. Register all functions with R and use the methods provided by R to link to them (c.f. WRE and nloptr).
  4. Compile a library meant for linking and install it with the R package. You will still need a plugin for that to work, since you have to add -L<path/to/lib> -l<libname> .... to PKG_LIBS.

I am sure there are examples on CRAN that use method 4, but none comes to mind right now. However, as a "code kata" I have converted a recent test package of mine to use this structure, c.f. https://github.com/rstub/levmaR/tree/static.


(Original incomplete answer.)

In src/Makevars you have

PKG_LIBS = $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)

You need an analogue setting when compiling a cpp file via Rcpp attributes. The best way achieve this is by using an Rcpp plugin, c.f. RcppArmadillo's solution (adjustments are untested!):

inlineCxxPlugin <- function(...) {
    plugin <-
        Rcpp::Rcpp.plugin.maker(
                  include.before = "#include <lapacke.h>",
                  libs           = "$(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)",
                  package        = "lapacker"
              )
    settings <- plugin()
    settings$env$PKG_CPPFLAGS <- "-I../inst/include"
    settings
}

BTW, why do you want to interface with LAPACK directly, when RcppArmadillo does so already?



来源:https://stackoverflow.com/questions/55187066/linking-error-of-r-package-with-rcpp-undefined-symbol-lapacke-dgels

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!