How to wrap 3rd party DLL for use in R?

Viewed 293

I need to use an existing 3rd party API that comes with a *.h and a *.dll file to load data into R. The functions provided by the dll are not callable directly, so I need to wrap them to call them from R. In order to familiarize myself with this, I made little example dll (based on the HOWTO from the MINGW page here, I have put the source code of the files at the end of the post). There is just one function in it that doubles an integer input. I can compile the dll just fine and also use it in a exe file, so it is functional. This is on Windows 10.

I am not sure how to correctly use this in R. I have created a package (named testwithdll2 ), placed the header file and the dll in "src", together with the wrapper function. When I try to compile the package, I get the follwing error messages with the undefined reference:

C:/Rtools/mingw_64/bin/gcc  -I"C:/PROGRA~1/R/R-35~1.1/include" -DNDEBUG
-O2 -Wall  -std=gnu99 -mtune=generic -c mydouble_c.c -o mydouble_c.o
C:/Rtools/mingw_64/bin/gcc -shared -s -static-libgcc -o testwithdll2.dll
tmp.def mydouble_c.o -LC:/PROGRA~1/R/R-35~1.1/bin/x64 -lR
mydouble_c.o:mydouble_c.c:(.text+0xc): undefined reference to `__imp_timestwo'
collect2.exe: error: ld returned 1 exit status

Any pointers on what might have gone wrong are greatly appreciated.

example_dll.h:

#ifndef EXAMPLE_DLL_H
#define EXAMPLE_DLL_H

#ifdef __cplusplus
extern "C" {
#endif

#ifdef BUILDING_EXAMPLE_DLL
#define EXAMPLE_DLL __declspec(dllexport)
#else
#define EXAMPLE_DLL __declspec(dllimport)
#endif

int EXAMPLE_DLL timestwo(int x);

#ifdef __cplusplus
}
#endif


#endif  // EXAMPLE_DLL_H

example_dll.cpp:

#include <stdio.h>
#include "example_dll.h"

int timestwo(int x)
{
        return 2 * x;
}

mydouble.c (in the src folder of the r package):

#include "example_dll.h"
void mydouble(int* a){
  *a = timestwo(*a);
}

timestwo.R (wrapper function, in the R folder):

#' @useDynLib testwithdll2 mydouble
#' @export
timestwo <- function(n){
  .C("mydouble",n )
  n
}
1 Answers

I figured out what to do. It was necessary to use a makevars file with the following lines:

MAKEVARS:

PKG_CPPFLAGS= -I.
PKG_LIBS= -L. -lexample_dll

It was also necessary to add the useDynlib call to the example_dll.dll in the namespace before the call to the testwithdll2.dll. This also meant that the .C call needed the PACKAGE parameter to be specified, so I had to change the r wrapper to:

timestwo.R

#' @useDynLib example_dll
#' @useDynLib testwithdll2
#' @export
timestwo <- function(n){
  .C("mydouble",n, PACKAGE = "testwithdll2")[[1]]
}

Now everything works as expected.

Related