Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to link to already compiled external shared libraries in RCPP using Makevars?

Tags:

c++

rcpp

I have looked at multiple places but failed to find a simple example for my problem.

What I need is to be able to use multiple .so files which I have (together with .h files).

A simple example would be:

I have the following files: a.h, a.cpp the function jeden - this is my R library, accessor.cpp which exposes to R the function dwa from external library libdwa.so. I have the header file dwa.h and this library libdwa.so.

I can manage building binary package (and everything works fine) only and only then when I put the library file libdwa.so into the directory '/usr/lib' (I use Debian). But it is not partable solution.

Where I should put the library "dwa" files (dwa.h and libdwa.so) and what flags add in the Makevars file to get portable solution?

SUMMARY ADDED

I summarize my results here. I believe some extremaly simple examples are useful at start.

  1. 2 external libraries put inside inst:

    /inst/include/dwa.h
    /inst/include/trzy.h
    /inst/jeden/libdwa.so
    /inst/jeden/libtrzy.so
    
  2. configure file /configure has the form (test6 is a name of the package):

    #!/bin/bash
    rpath=$(${R_HOME}/bin/Rscript -e 'cat(file.path(.libPaths()[1], "test6", "jeden"))') #'
    sed -e"s|@rpath@|"${rpath}"|" src/Makevars.in > src/Makevars
    
    exit 0
    
  3. The file /src/Makevars.in has the form:

    CXX_STD = CXX11
    
    PKG_CPPFLAGS = -I../inst/include/ -I.
    PKG_LIBS     = -ldwa -ltrzy -L../inst/jeden -Wl,-rpath,@rpath@
    
  4. The /src/accessor.cpp expose the libraries function to R:

    #include <Rcpp.h>
    #include "../inst/include/dwa.h"
    #include "../inst/include/trzy.h"
    
    // [[Rcpp::export]]
    Rcpp::String r_dwa() {
      Rcpp::String res = dwa();.
      return res;
    }
    
    // [[Rcpp::export]]
    Rcpp::String r_trzy() {
      Rcpp::String res = trzy();.
      return res;
    }
    
  5. Pure R library _/src/hello_world.cpp_ also exists:

    #include <Rcpp.h>
    using namespace Rcpp;
    
    // [[Rcpp::export]]
    String hello_world() {
      String hw = "Hello World";
      return hw ;
    }
    
  6. Finaly /NAMESPACE file:

    useDynLib("test6", .registration=TRUE)
    
    import("Rcpp")
    importFrom("utils", "object.size", "packageVersion")
    exportPattern("^[[:alpha:]]+")
    

Building source and binary packages was successful but only source one is usefull as the binary has path to the libraries written rigidly.

like image 954
francisco Avatar asked Dec 22 '25 00:12

francisco


1 Answers

Let's assume you have a directory structure like

/opt/dwa/include/dwa.h
/opt/dwa/lib/libdwa.so

In that case you could use is src/Makevars:

PKG_CPPFLAGS = -I/opt/dwa/include
PKG_LIBS = -L/opt/dwa/lib -ldwa -Wl,-rpath,/opt/dwa/lib

Of course, this is still not portable, since the path to the library and header files is hard coded. To circumvent this, one uses a template file, e.g. src/Makevars.in

PKG_CPPFLAGS = @DWA_INC@
PKG_LIBS = @DWA_LIB@

and writes a configure script that inspects the environment and creates src/Makevars based on the findings. There are different strategies for writing configure scripts. I typically use autoconf, e.g. in RcppArrayFire or dqmagic.

like image 54
Ralf Stubner Avatar answered Dec 24 '25 17:12

Ralf Stubner



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!