4

I am trying to create a shared object I can load into R that calls Rust functions by way of R's C API. To call Rust from C, I am following this blog post. My problem arises when I try to create the shared library and link to the Rust library. The linker complains that it can't find my Rust function. I am quite new to compiled languages and have given this a couple days' worth of effort before turning to SO. In that time I have learned a lot about compiler flags and yet come no closer to a solution. I think it may be something obvious.

My C++ code:

#include "Rinternals.h"
#include "R.h"
#include "treble.h"

// test.cpp
extern "C" {

SEXP triple(SEXP val) {

    int32_t ival = *INTEGER(val);
    Rprintf("9 tripled is %d\n", treble(ival));
    return R_NilValue;
}

}

treble.h:

#include <stdint.h>

int32_t treble(int32_t value);

My Rust code:

#![crate_type = "dylib"]

#[no_mangle]
pub extern fn treble(value: i32) -> i32 {
  value * 3
}

This is what I'm doing on the command line:

$ rustc glue.rs
$ g++ -shared test.cpp -o test.so -I/Library/Frameworks/R.framework/Headers -L/Library/Frameworks/R.framework/Libraries -L. -lR -lglue
Undefined symbols for architecture x86_64:
  "treble(int)", referenced from:
      _triple in test-dac64b.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Inspecting the object file that rust creates:

$ nm -gU libglue.dylib
...
0000000000001750 T _treble
Zelazny7
  • 39,946
  • 18
  • 70
  • 84
  • Try making a [MCVE](/help/mcve). For example, do you need to link against the R libraries to reproduce the error? I'd guess not. – Shepmaster Jun 18 '15 at 01:11
  • If you want C code, why are you compiling as C++? Both gcc and Clang can compile as C, in which case there is no mangling without having to specify `extern`. – Matthieu M. Jun 18 '15 at 06:09
  • Mostly for my own learning. There is no reason for me to use C++, but that is how I started the project and I got to this point by making small edits. And now I am aware of name mangling! – Zelazny7 Jun 18 '15 at 12:18

1 Answers1

4

In the C++ code, you need to declare the Rust function (which is available via the C ABI) as extern "C".

treble.h

#include <stdint.h>

extern "C" {
  int32_t treble(int32_t value);
}

The error you are getting is because the C++ compiler is name mangling the method treble before attempting to link against it. extern "C" disables the mangling.

Additionally, your Rust FFI code should always use the types from the libc crate; in your case you want libc::int32_t.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • This indeed allowed me to compile successfully. I suspected it might have something to with mangling when the gcc version (stripped of the extern "C") worked. I am still having troubling loading the dynamic library in R, but I'll save that for another question. – Zelazny7 Jun 18 '15 at 02:35