Linking Error of R Package with Rcpp: "undefined symbol: LAPACKE_dgels

Linking Error of R Package with Rcpp: “undefined symbol: LAPACKE_dgels”

In this article, we will explore the linking error that occurs when using an R package with Rcpp. The problem arises when trying to link a C++ function to a Lapack library. We will delve into the possible solutions and provide code examples to illustrate each approach.

Problem Statement

We have created an R package called “lapacker” which provides a C interface for internal LAPACK library provided and used by R. The source code is available on GitHub: https://github.com/ypan1988/lapacker. However, when we try to compile a separate C++ file using Rcpp attributes, we encounter a linking error.

The error message indicates that the symbol “LAPACKE_dgels” cannot be found. This suggests that the Lapack library is not being properly linked to the C++ code.

Possible Solutions

There are four possible solutions to this problem:

  1. Convert lapacke into a header-only library and install it in inst/include

    By making this change, we can avoid the need for dynamic linking. This approach is similar to what RcppArmadillo uses.

  2. Link with a system installation of lapacke

    In this scenario, we would compile the Lapack library from source and link against it when compiling the C++ code.

  3. Register all functions with R and use the methods provided by R to link to them

    This approach involves using the WRE (Wrap R) and nloptr packages to wrap the LAPACKE functions and provide a callable interface to them.

  4. Compile a library meant for linking and install it with the R package

    In this case, we would compile the C++ code into a shared library that can be linked against when installing the package.

Solving Using Method 1

To convert lapacke into a header-only library and install it in inst/include, we need to make the following changes:

  • Modify the Makefile to include the Lapack header files instead of the dynamic library.
  • Update the PKG_LIBS variable in src/Makevars to only include the Lapack headers.

Here’s an example of how you can modify the Makefile:

# src/Makevars

PKG_LIBS = $(LAPACK_HEADERS) $(BLAS_LIBS) $(FLIBS)

And here’s an example of how you can update PKG_LIBS in src/Makevars:

# src/Makevars

PKG_LIBS = -I../inst/include/lapacke.h -llapacke -L/usr/lib/R/lib -lR -llapack

Now, we need to modify the inlineCxxPlugin function to include the Lapack header files and libraries:

# inlineCxxPlugin

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 -I/usr/share/R/include"
    settings
}

Solving Using Method 2

To link with a system installation of lapacke, we can compile the Lapack library from source and install it with the R package.

However, this approach requires significant modifications to our build process and may not be feasible for all projects.

Solving Using Method 3

To register all functions with R and use the methods provided by R to link to them, we need to use the WRE (Wrap R) and nloptr packages.

Here’s an example of how you can modify the inlineCxxPlugin function to wrap the LAPACKE functions:

# inlineCxxPlugin

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

And here’s an example of how you can wrap the LAPACKE functions using WRE:

# WRAP.lapacke.R

library(WRAP)

lapacke_dgels <- function(a, lda, b, ldb) {
    # Call the LAPACKE function
    info = lapacke_dgels(LAPACK_ROW_MAJOR,'N',m,n,nrhs,*a,lda,*b,ldb)
    
    # Return the result
    return(info)
}

Solving Using Method 4

To compile a library meant for linking and install it with the R package, we need to use the PKG_LIBS variable in src/Makevars.

Here’s an example of how you can modify the Makefile:

# src/Makevars

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

And here’s an example of how you can compile the C++ code into a shared library that can be linked against when installing the package:

# src/Makefile

LIBS = -o demo3.o $(LAPACK_LIBS)

build: build.so
    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++ $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) demo3.o -o build.so

clean:
    rm -f demo3.o build.so

By using one of these methods, we can resolve the linking error and compile our C++ code successfully.


Last modified on 2023-12-09