0

I have a C package which builds a executable with several argument flags. One compiles the code with a Makefile (I know, this needs to change for the R package) and an executable is created to be run via

$ ./codeName -f path/inputfile -o path/outputfile -p ## -s "type"

My goal is to integrate several of the functions used in this C package to be used with an R library. I take a look at some examples on github.com/cran of R packages using C. In Writing R Extensions, it explains how I could use .Call() and Makevars to call the C functions from R. I would like to avoid that like the plague. However, it looks like this would require significant re-writing with SEXP object--so I turn to Rcpp (yeah!)

I create the package Rcpp.package.skeleton("packageName")

Great. Within R, I do the following:

$ R
> library(devtools)
> build()  # works!
> install() # works!
> library(packageName)
> rcpp_hello_world()
## expected output

Everything works. Then I add my C package into /src. I then execute Rcpp::compileAttributes() in the package root directory via R--nothing happens and nothing is output, which is expected, as I haven't changed the C code at all yet.

I try installing with the commands above: devtools::build() and devtools::install(). Via the Makefile, it looks like the C code compiles perfectly! But then there's this issue:

** R
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded
Error in library.dynam(lib, package, package.lib) : 
  shared object ‘packageName.so’ not found
Error: loading failed
Execution halted'
ERROR: loading failed

Well, that's somewhat confusing, and I don't know why that has occurred, but the snag is the useDynLib("packageName") in the NAMESPACE. If I remove this, the C code appears to compile and the package installs via the build/install commands above. rcpp_hello_world() still works.

(1) Why does this error ‘packageName.so’ not found appear now, and can I get around it?

(This question has nothing to do with Rcpp.)

Then, I go to a .c file. I add

#include <Rcpp.h>
using namespace Rcpp;

to a *.c file and //[[Rcpp::export]] before a function I would like to import. (I'm not sure that's going to work in *.c, or in a C header file.)

Next, I go to the package root directory, open R and try this:

$ R
> library(Rcpp)
> compileAttributes()

That runs without error. However, no RcppExports.R and RcppExports.cpp were generated. Compiling the C code also results in the error that it cannot find #include <Rcpp.h>.

(2) Why would compileAttributes() not function in this environment? I must be incorrectly using Rcpp and //[[Rcpp::export]] in order to wrap these C functions into R-usable format.

ShanZhengYang
  • 16,511
  • 49
  • 132
  • 234
  • You could start from the other side with a working package as created by `Rcpp.package.skeleton()` or the equivalent function in RStudio and then compare. "Something" must be different here. – Dirk Eddelbuettel Nov 27 '17 at 18:29
  • 1
    Also, a very obvious one: Rcpp and `compileAttributes()` expect C++ code. Not C code. So files ending in `.c` are ignored _by design_. Just rename your files ... – Dirk Eddelbuettel Nov 27 '17 at 18:30
  • @DirkEddelbuettel Thanks for the input. Changing the extension to `.cpp` results in some compilation errors...In order to keep the C code unchanged, I may have to resort to writing `SEXP`... – ShanZhengYang Nov 27 '17 at 18:50
  • _Either_ you want C++ and Rcpp and can get converters written for you (ie no, you don't have to use `SEXP`) _or_ you want plain C in which case your quest for `compileAttributes()` is wrong. – Dirk Eddelbuettel Nov 27 '17 at 18:56
  • @DirkEddelbuettel In this case then, unless I could pass through the C code through `cFunction()`, there's no way integrating vanilla C code would be made easier with Rcpp (unless I could translate the C code into C++)? – ShanZhengYang Nov 27 '17 at 21:17

1 Answers1

2

What would you call this function? C code?

int fib(int n) { 
   if (n < 2) return n;
   return fib(n-1) + fib(n-2);
}

It passes as both C and C++ code. So let's call it C code.

You can clearly interface this from R via Rcpp with the following caller:

// [[Rcpp::export]]
int callFib(int n) {
   return fib(n);
}

Stick them all together into a C++ file so that Rcpp can operate on them (see comments) and you are all set.

R> library(Rcpp)
R> sourceCpp("/tmp/ex.cpp")

R> callFib(10)
[1] 55
R> 

The complete file is below.

#include <Rcpp.h>

int fib(int n) { 
  if (n < 2) return n;
  return fib(n-1) + fib(n-2);
}


// [[Rcpp::export]]
int callFib(int n) {
  return fib(n);
}

/*** R
callFib(10)
*/
Dirk Eddelbuettel
  • 360,940
  • 56
  • 644
  • 725