16

I have some c code that utilizes the igraph library. I would like to put an R wrapper around it and send it off to CRAN as an R package.

igraph already has an R port on CRAN, so it would make sense for my R package 'foo' to depend on R's igraph. Since foo uses its own C code that depends on the C igraph, how can I link my C functions to the original igraph library? I've read that this is done in a file called Makevars, but linking to an external library is very hairy.

If this isn't possible, is it better to just copy the entire igraph source code and put the whole thing into my /src directory? The R igraph package already has a file called Makevars, but I don't understand how all the c files get built - normally in my Makefile I have something like gcc (some list of .c source files) -o, but Makevar only contains

PKG_CFLAGS=-DUSING_R -I. -Ics -Iglpk -Iglpk/amd -Iglpk/colamd \
-g -O2 -I/usr/include/libxml2 -g -O2 -I/usr/include/libxml2 -DNDEBUG \
-DPACKAGE_VERSION=\"0.6\" -DINTERNAL_ARPACK \
-DIGRAPH_THREAD_LOCAL=/**/
PKG_CXXFLAGS= -DUSING_R -DIGRAPH_THREAD_LOCAL=/**/ -DNDEBUG
PKG_LIBS=-lxml2 -lz -lpthread -licucore -lm -lgmp  $(FLIBS) $(LAPACK_LIBS) $(BLAS_LIBS)

all: $(SHLIB)

and there is no other Makefile. In summary, how do I go about putting C code into an R package that depends on another C library, and how do I write the corresponding Makevars (or Makefile) to incorporate the C functions?

An older question was posted here but only seems to link to help on writing your own C code that does not depend on anything.

Community
  • 1
  • 1
JCWong
  • 1,163
  • 1
  • 10
  • 29
  • 1
    I don't think this is currently possible in a clean and portable way. – Gabor Csardi Sep 08 '12 at 05:18
  • Just want to mention here that copying the entire igraph source code is not that easy, either, as it depends on some external libraries, e.g. libxml2, GMP. I am actually in the same situation as the original poster, with the GLPK library/package. igraph now contains a copy of GLPK. – Gabor Csardi Sep 09 '12 at 02:53

2 Answers2

6

There are several questions here:

  1. Can a package 'foo' reliably link to a package 'bar'? "Writing R Extensions", at the beginning of Section 5.8 on "Linking to Other Packages" says "no, not generally" as Gabor hinted too in his earlier comment.

  2. Can C source code put into a package to build a package that depends on another libary: Yes, of course, and lots of packages on CRAN do it. Pick eg an example of a package depending on the GSL, or the JPEG/TIFF graphics libraries, or XML, or ... You can study these sources. That is not trivial easier, but if you study these packages, the documentation in Writing R Extensions and the other answers to related questions here you should get there.

Dirk Eddelbuettel
  • 360,940
  • 56
  • 644
  • 725
5

I take a slightly different reading of "Writing R Extensions". Paragraph 1 of Section 5.8.1 (dealing with unix-like operating systems) says that it's possible but not portable or recommended to link to a shared library. Paragraph 2 says static libraries are ok (the 'This' at the head of the paragraph is confusing; what does it refer to?) because the static library provided by packA can be discovered by packB when packB is installed, and is then incorporated into the dynamic library. This requires that packA provides a static library, and hence that packA realized that it's role was to do this; many packages will instead think of their role as providing an R interface to a subset of the functionality of the library that they wrap, and provide a shared object that links to the shared library in its own package.

An example is the Rsamtools package in Bioconductor, which creates static versions of the samtools library and provides a (tricky-to-get-right) mechanism for packages wanting to access the static library (a vignette provides a dependent package view of things). It's important to provide the absolute path to the static library PKG_LIBS="-l$(PKGB_PATH)/libpackB.a" to avoid static linking to the same library provided by the system (with the headers provided by packA).

@DirkEddelbuettel has almost surely gone down this road himself, and will point out my errors. I agree with his comment below that using a static library is sub-optimal (primarily from the memory consumption perspective?) but make the choice to avoid the portability reasons alluded to in paragraph 5.8.1.

Martin Morgan
  • 45,935
  • 7
  • 84
  • 112
  • Not really. I don't like static libs (on Unix, where we can do better) and what Rcpp et al do is different: they build a classic library themselves that others links against -- as opposed to using the one built by R. In that sense I fear the manual is correct. But if you want to force things with a static library then what you describe is correct -- RInside does the same (on Windows at least). – Dirk Eddelbuettel Sep 08 '12 at 17:25
  • @DirkEddelbuettel can you elaborate on 'classic library'? The reservation in Writing R Extensions seems to be in finding the correct library at run time? – Martin Morgan Sep 08 '12 at 17:50
  • a) Writing R Extensions only talks about a R, understandably. A package foo gets a file libs/foo.so. You cannot link against that. R however can open it via dlopen etc. b) What I called a "classic" library is more often called libfoo.so, and you can link against that via -lfoo. – Dirk Eddelbuettel Sep 08 '12 at 17:54
  • @DirkEddelbuettel But I think the point of R-exts is that -lfoo requires that libfoo.so be discoverable at run time, it's not installed in a standard place, so is not discoverable (in general, of course, even though almost everyone will be using compilers that can be configured to record the location of libfoo.so at the time of linking)? – Martin Morgan Sep 08 '12 at 18:06
  • No R package provides libfoo, all they do is libs/foo.so --- a file foo.so in a directory libs. The non-discoverable is a secondary concern having to do with the dynamic linker at runtime _if you talk about normal executables_ It is all different for R loadable packages. But the main issue is: foo.so cannot be used by gcc et al. – Dirk Eddelbuettel Sep 08 '12 at 18:21
  • @DirkEddelbuettel yes, I was supposing that an R package had created libfoo.so via Makevars / Makefile and installed it somewhere in the R library hierarchy -- [igraph](http://igraph.sourceforge.net/index.html)-the-library rather than [igraph](http://cran.r-project.org/web/packages/igraph/index.html)-the-package. – Martin Morgan Sep 08 '12 at 18:51