2

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.

happ
  • 100
  • 10
  • What should a user of `libdai` be able to do? Use some R functions that are backed by C++ code from libDAI? Write new C++ code that uses libDAI? – Ralf Stubner Dec 05 '18 at 12:59
  • In very short, this is a _hard_ and open question. When @coatless and I are both retired we will come back to this and write the paper about the (maybe five) different ways this can be tackled. In short: it's not east, especially with an external library. But a few CRAN packages do it: bundle the source, build a static library (which is an architecture-and-OS-dependent task) and then use it. – Dirk Eddelbuettel Dec 05 '18 at 13:22
  • @RalfStubner I want to write C++ functions that use the inference and em algorithms provided by the C++ libDAI library. The end user will only use my R functions. – happ Dec 05 '18 at 13:26
  • @DirkEddelbuettel thank you for your answer. However I should be able to somehow make use of libDAI? So it is not possible to pre-compile it, does this mean a user must set up gmb and boost and directly compile libDAI while compiling the R-package? – happ Dec 05 '18 at 13:33
  • 2
    Assume eg CRAN has nothing (it may have libgmp though). You can get Boost _headers_ from BH. If you need Boost linking it is much harder. Forgetting these two, you will have to shop libDAI sources _and create build instructions_ for the three architectures so that your package can use it. As I said: _hard_. – Dirk Eddelbuettel Dec 05 '18 at 13:36
  • 2
    So as a first proxy, maybe delegate out to the libDAI website, assume someone has it built (on Linux or macOS, say) and write a simpler 'RcppDAI' package interfacing that. You can share that via GitHub etc while you work out if/how to include libDAI. – Dirk Eddelbuettel Dec 05 '18 at 13:37

2 Answers2

5

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.

Ralf Stubner
  • 26,263
  • 3
  • 40
  • 75
  • 1
    Pretty good answer. I would stress that 'Pre-building static libraries' is mostly about macOS and Windows. Some packages actually build their own static libraries: both `nloptr` and `RcppRedis` either use an installed library _or_ build from source on demand if needed (respectively: `libnlopt` and `libhiredis`). A few other packages just build the static library on demand. That is probably the only route to take as `libDAI` is a wee bit obscure. – Dirk Eddelbuettel Dec 05 '18 at 20:18
  • Thank you very much for your detailed answer it helped me a lot. I have a question related to your suggestion for the library dependencies. Does this mean, that the user should be able to compile my package without the need to compile `gmp` and `boost` on his system (Windows and Linux)? – happ Dec 12 '18 at 14:14
  • @J.Kr For compilation the `gmp` library and header files will be necessary. Since these are available on CTAN, though, Windows and Mac Users will be able to get *pre-build* packages from there. For `boost` I expect that the headers provided by `BH` are sufficient for compiling the package. – Ralf Stubner Dec 12 '18 at 15:49
  • @RalfStubner Thanks a lot for your help, I got the compilation running on Linux. However, the library requires gmpxx, It seems like this is not part of gmp. Additionally, I had a few other issues. I added an _Edit_ to my initial question. – happ Jan 10 '19 at 13:50
  • @J.Kr At least on Debian et al. `gmpxx.h` is part of `libgmp-dev`. As for your other questions: It would be better to ask a new question for this, but be sure to (re)read the "extending Rcpp" vignette before hand. You can extend Rcpp without modifying third parts headers. – Ralf Stubner Jan 10 '19 at 15:39
  • Thanks for bringing this up. A colleague of my also would like to used libdai as part of an R package. Is your package available somewhere? It would be very useful to us to see it in oder to get some inspiration. Thanks! – DrYak Oct 30 '20 at 19:06
  • @DrYak Which package are you referring to? – Ralf Stubner Oct 31 '20 at 13:28
0

Another approach: If you aim is to do inference in Bayesian networks, there is an R package that directly does that for you: https://github.com/cbg-ethz/SGS.

Fritz
  • 31
  • 2