2

I tried to call c++ function from another .cpp file. I used .h header. See below what I did.

I have a f.h file:

#ifndef PACKAGENAME_ADD_H
#define PACKAGENAME_ADD_H

#include <Rcpp.h>
Rcpp::NumericVector f(Rcpp::NumericVector x) ;

#endif

f.cpp file:

#include <Rcpp.h>
using namespace Rcpp;

NumericVector f(NumericVector x) {
  return x * 2;
}

g.cpp file:

#include <Rcpp.h>
#include <f.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector g(NumericVector x) {
  return f(x);
}

The three files are in the same folder I got this error when I run g.cpp:

Rcpp::sourceCpp('~/g.cpp')

Error in dyn.load("/tmp/Rtmpdu4AWp/sourceCpp-x86_64-pc-linux-gnu-0.12.17/sourcecpp_260f5e1a9ebc/sourceCpp_9.so") : unable to load shared object '/tmp/Rtmpdu4AWp/sourceCpp-x86_64-pc-linux-gnu-0.12.17/sourcecpp_260f5e1a9ebc/sourceCpp_9.so': /tmp/Rtmpdu4AWp/sourceCpp-x86_64-pc-linux-gnu-0.12.17/sourcecpp_260f5e1a9ebc/sourceCpp_9.so: undefined symbol: _Z1fN4Rcpp6VectorILi14ENS_15PreserveStorageEEE

Can someone help me? I work on ubuntu 18.04 and I have R 3.4.4 version.

feedMe
  • 3,431
  • 2
  • 36
  • 61
Ari.stat
  • 463
  • 4
  • 13
  • 5
    Including a header just gives you the declaration of functions - enough for the compiler, *not* enough for the linker. To actually create an executable you also need to link with the implementation (the object file or library defining the function). The source files being in the same folder is irrelevant. – Jesper Juhl Sep 10 '18 at 19:38
  • Thanks @JesperJuhl for your reply. Please i am a beginner. Can you explain more? – Ari.stat Sep 10 '18 at 19:45
  • Duplicated? I do not understand – Ari.stat Sep 10 '18 at 19:49
  • I honestly don't know what more to add. Include what you use, link with what you use.. learn your toolchain... The duplicate actually explains it well (read *all* of it). Also, link order *matters* on most platforms. – Jesper Juhl Sep 10 '18 at 19:49
  • @JesperJuhl Ok. How can I link with what I use? excuse me but I do not understand. Can you give an example? – Ari.stat Sep 10 '18 at 19:52
  • I am voting to reopen this question. On a pure C++ level this might be a duplicate, but in the context of Rcpp, compilation and linking is to some extend automated. In this particular case, the OP should have used `#include "f.h"` instead of `#include ` to get correct compilation and linking automatically. – Ralf Stubner Sep 10 '18 at 19:56
  • 4
    @Ari.stat I would follow the advice often given by Dirk (the creator of `Rcpp`) and **create a package**. `sourceCpp()` wasn't meant for a multiple files. Making R packages that call C++ via Rcpp is simple; look at `help("Rcpp::Rcpp.package.skeleton")` or [the Rcpp package vignette](https://cran.r-project.org/web/packages/Rcpp/vignettes/Rcpp-package.pdf) or [this answer](https://stackoverflow.com/questions/31396802/integrate-fortran-c-with-r/52136973#52136973) (disclaimer: mine) with an example of making a package from scratch with C++ & Fortran code – duckmayr Sep 10 '18 at 19:57
  • Ok. An example. You have a header file defining a function `void f()`. To be able to let your compiler know that function exists you `#include `. Ok, now we know it exists and we can do stuff with it. To be able to *actually call it* the linker (not the compiler) needs to find an actual implementation of `f`. You need to tell ot where to find that. It's probably in `f.o`, it might be in `f.a` or `f.so`, but in any case you need to say *where*. – Jesper Juhl Sep 10 '18 at 19:58
  • @RalfStubner I'm joining you. Precisely why I offered my comment (in case it doesn't get reopened, OP can have some starting point for the reasons you point out) – duckmayr Sep 10 '18 at 19:58
  • @duckmayr I am all for packaging stuff. However, it is not strictly necessary in this case as Rcpp attributes is able to handle certain use-cases with multiple files, c.f. "1.10.2. Shared Code in C++ Files" in `vignette("Rcpp-attributes", "Rcpp")`. – Ralf Stubner Sep 10 '18 at 20:02
  • When you build a C++ program, several things happen. First your code passes through the C pre-processor (cpp) which does some text replacement (including pasting your includes into source files). Then the compiler runs and figures out if you wrote a syntactically valid program (and more). Then the linker runs in order to bring together all those functions/objects you previously referred to - now it needs *concrete* implementations. Then, at the end you have an executable. It's a multi-layer process and it's *not* simple. – Jesper Juhl Sep 10 '18 at 20:03
  • 2
    @JesperJuhl All of that is true, but offers little help to those in OP's situation who are compiling C++ code for the purpose of calling it from R, all with the help of the `Rcpp` R package. As Ralf Stubner mentioned, "in the context of Rcpp, compilation and linking is to some extend automated." Someone calling `sourceCpp()` from R is coming at this from an entirely different context than you're familiar with. At a certain point, the question marked as dupe and the things you mention could be helpful, but not without understanding how this mixes with R/Rcpp specific issues. – duckmayr Sep 10 '18 at 20:10
  • @RalfStubner Good point/good catch on the Rcpp Attributes vignette. I'd never gone that route before. – duckmayr Sep 10 '18 at 20:11
  • I agree. When you are starting to point `sourceCpp()` at _multiple source files_ you have a linking error as @JesperJuhl said right from the start and _you want a package for that_ as it generally resolves this. Hence my vote keep this closed as dupe. – Dirk Eddelbuettel Sep 10 '18 at 21:34

1 Answers1

3

The way I am most familiar with dealing with this issue in the context of Rcpp is by creating a package. In the case you present in the original post, as pointed out by Ralf Stubner it isn't really necessary; after changing the brackets(<>) around f.h in g.cpp to quotes (""), your code compiled fine for me with sourceCpp():

Rcpp::sourceCpp("g.cpp")
g(1:10)
# [1]  2  4  6  8 10 12 14 16 18 20

(for details see section 1.10 of the Rcpp Attributes vignette).

However, if you are eventually needing multiple .cpp files to compile (i.e., not just one that relies on an implementation in another), the way to go is creating a package. This might sound involved or intimidating, but with the tools provided by Rcpp, it's really quite simple. Here are the steps I took to turn your code into a package:

  1. From R, run Rcpp::Rcpp.package.skeleton("SOanswer", example_code = FALSE)
  2. Delete the file Read-and-delte-me.
  3. Add the C++ files from your original post into the src/ folder (with only one minor edit -- changing the brackets(<>) around f.h in g.cpp to quotes ("")).
  4. From R, run Rcpp::compileAttributes("SOanswer/") and devtools::install("SOanswer/")

Then it should compile nicely and you can run g() from R:

SOanswer::g(1:10)
# [1]  2  4  6  8 10 12 14 16 18 20

I will say that I would add there a step 0: Read the vignettes at https://cran.r-project.org/package=Rcpp, in particular the Rcpp Introduction and Rcpp Package vignettes. You can also check out this lovely example of a package with headers in src/ provided by coatless in the comments.

duckmayr
  • 16,303
  • 3
  • 35
  • 53
  • 1
    To piggyback on @duckmayr's answer, check out https://github.com/r-pkg-examples/rcpp-headers-src for a package implementation w/ headers in `src/` – coatless Sep 11 '18 at 10:20
  • great! when I changed the brackets (<>) around f.h in g.cpp to quotes ("") it works very well. Thanks for your help. Endeed, I want to create a package further but I need the function now for some cheikings. I have somes questions for the package. Shoud I create a sub-folder inst/include/ in my package main folder for .h files or can I put them in scr/ folder ? – Ari.stat Sep 11 '18 at 10:40
  • @coatless Good resource! I've added it to the answer. – duckmayr Sep 11 '18 at 10:40
  • 1
    @Ari.stat Either will work, but you'll need to go the `inst/include` route if you want other R packages to be able to link to your header files. If you want to see examples of R packages that do that, check out these two packages I'm developing on my GitHub: [RcppDist](https://github.com/duckmayr/RcppDist) (to provide C++ headers for more probability distributions for Rcpp users) and [bggum](https://github.com/duckmayr/bggum) (there I'm not really looking for other packages to link to my header, I just did it that way out of habit) – duckmayr Sep 11 '18 at 10:43
  • 1
    @Ari.stat Header files for internal functions should go into `src`. Into `inst/include` I would only put header files for functions that are meant for consumption by other packages. These have to be header only functions or properly registered with R. Rcpp can do this registration automatically with the `Rcpp::interfaces` attribute. See for example my [dqrng](https://github.com/daqana/dqrng/) package. – Ralf Stubner Sep 11 '18 at 12:43