Rcpp: Install package with static libraries for pl

2019-08-13 16:21发布

问题:

I want to use the libDAI C++ library within an R-package and want the package:

  1. to be usable on Linux and Windows
  2. save disc space (the external library has ~60 Mb)
  3. the end user does not need to install boost and gmp for compilation

My current setup is:

  • precompile libDAI
    • copy libdai.a to lib/
    • copy all libDAI header files to inst/include
  • add Makevar to src/

Modify Makevar file:

# include libraries
PKG_CPPFLAGS =-I../inst/include/
PKG_LIBS = -Llib -l../lib/libdai.a

My script for accessing the libDAI library is (test.cpp in src/):

#include <dai/factorgraph.h>
#include <Rcpp.h>
#include <cmath>

using namespace Rcpp;
using namespace std;
using namespace dai;

//'
//' Creates libDAI factor graph object
//'
//' @param factor_graph character definition of the factor graph
//' @export
// [[Rcpp::export]]
void initialize_factor_graph(const char* factor_graph) {

  // read the factor graph from the string
  std::istringstream fgStream(factor_graph);
  FactorGraph net;
  net.ReadFromString( fgStream );

  // Output some information about the factorgraph
  cout << "Factor graph has " << net.nrVars() << " variables" << endl;
  cout << "Factor graph has " << net.nrFactors() << " factors" << endl;

}

running Rscript -e "Rcpp::compileAttributes('libdai')", followed by R CMD INSTALL libdai returns the error:

Error: package or namespace load failed for 'libdai' in dyn.load(file, DLLpath = DLLpath, ...):
 unable to load shared object 
'/home/jk/libs/R/libdai/libs/libdai.so':
  /home/jk/libs/R/libdai/libs/libdai.so: undefined symbol: _ZTVN3dai11FactorGraphE
Error: loading failed

So my questions are:

  • What is wrong with my setup?
  • what is the best procedure to share my final package on CRAN?
  • What is the nicest setup for sharing the package?

My question is closely related to this and this question and several other post related to referencing static libraries, however I was not able to solve my problem with these links.

回答1:

How to link with a static library

You can either use -L<directory> -l<name> or <path>, i.e. in your case

PKG_LIBS = -L../lib -ldai

or

PKG_LIBS = ../lib/libdai.a

Header placement

The headers for libDAI are only used internally. One cannot link to the functions declared in these headers. I would therefore not use inst/include for these headers.

Dependencies on CRAN

The gmp library seems to be available on the CRAN builders, c.f. https://github.com/cran/gmp and https://cran.r-project.org/package=gmp. It seems that libDAI requires linking to boost (program options), c.f. https://bitbucket.org/jorism/libdai/src/83bd24a4c5bf17b0592a7b5b21e26bf052881833/Makefile.LINUX?at=master&fileviewer=file-view-default#Makefile.LINUX-49. However, looking at the actual Makefile it seems this is only used for tests and utility programs. So you might get away with the boost headers provided by the BH package.

Pre-building static libraries

This is a common approach on Windows (c.f. https://github.com/rwinlib), but I find it unusual for Linux. The more common approach would be one of:

  • include the sources in the package and compile during configure or package installation
  • download the sources and compile during configure
  • link with a system library (I haven't seen any for libDAI, though).

For all three approaches there are numerous examples on CRAN and GitHub. It is difficult to make a recommendation, though. I probably would go for "include the sources in the package" and use the Makefile provided by upstream as a starting point for building the library.