Reputation: 23
I'm trying to create a R package for my own use, that is using Rcpp and whose C++ code include the Levmar library. I'm working on Windows.
The C++ code works fine when I build it using CMake for example and run it with Visual Studio. But when I put this code in my R package and try to build it, I get the following error :
levmar_example_r.o:levmar_example_r.cpp:(.text+0x281): undefined reference to `dlevmar_der'
(dlevmar_der is declared in levmar.h which is included in my R package, see below)
I have already read quite a lot of SO posts on how to build a R package with external libraries like this or this but it didn't help me to solve my problem.
The structure of my package :
bin/
|- levmar.lib
inst/
|- include/
|- levmar.h
man/
R/
src/
|- Makevars
|- Makevars.win
|- levmar_example_r.cpp
|- RcppExports.cpp
src-i386/
DESCRIPTION
NAMESPACE
Content of Makevars/Makevars.win
PKG_LIBS = -L../bin -llevmar
PKG_CPPFLAGS = -I../inst/include
The C++ code (levmar_example_r.cpp)
#include <iostream>
#include <levmar.h>
#include <math.h>
#include <Rcpp.h>
void fun(double *p, double *x, int m, int n, void *data_){
double a = p[0];
double b = p[1];
double *data = (double *) data_;
for(int i = 0; i < n; i++){
x[i] = log(a*data[i]+b);
}
}
void jacFun(double *p, double *jac, int m, int n, void *data_){
double a = p[0];
double b = p[1];
double *data = (double *) data_;
int k, l;
for(l=k=0; l < n; l++){
jac[k++] = data[l]/(a*data[l]+b);
jac[k++] = 1/(a*data[l]+b);
}
}
// [[Rcpp::export]]
void test_levmar(){
int m = 2; // # of parameters
int n = 40; // # of observations
double a = 1.0;
double b = 2.0;
double data[] = {0.119047619047619, 0.238095238095238, 0.357142857142857, 0.476190476190476, 0.595238095238095, 0.714285714285714, 1.07142857142857, 1.42857142857143,
0.119047619047619 ,0.238095238095238, 0.357142857142857, 0.476190476190476, 0.595238095238095, 0.714285714285714 ,1.07142857142857, 1.42857142857143 ,
0.119047619047619, 0.238095238095238, 0.357142857142857, 0.476190476190476, 0.595238095238095, 0.714285714285714, 1.07142857142857, 1.42857142857143,
0.119047619047619, 0.238095238095238, 0.357142857142857, 0.476190476190476 ,0.595238095238095, 0.714285714285714, 1.07142857142857, 1.42857142857143,
0.119047619047619, 0.238095238095238 ,0.357142857142857, 0.476190476190476, 0.595238095238095, 0.714285714285714, 1.07142857142857, 1.42857142857143};
double popti[2];
popti[0] = a; popti[1] = b;
double x[40];
fun(popti, x, m, n, (void *) data);
// algorithm parameters
double opts[LM_OPTS_SZ], info[LM_INFO_SZ];
opts[0]=LM_INIT_MU;
// stopping thresholds for
opts[1]=1E-10; // ||J^T e||_inf
opts[2]=1E-10; // ||Dp||_2
opts[3]=1E-10; // ||e||_2
opts[4]= LM_DIFF_DELTA; // finite difference if used
double p[2];
p[0] = 3.0; p[1] = 1.0;
dlevmar_der(fun,jacFun,p,x,m,n,100,opts,info,NULL,NULL,(void *) data);
std::cout << "Optimum found:" << std::scientific << std::setprecision(8)<< "\t"<< p[0]<< "\t" << p[1]<< std::endl;
}
I have also tried to put all headers of the levmar library in the inst/include folder and all the .c files in a src/levmar folder and consequently remove
PKG_LIBS = -L../bin -llevmar
in Makevars/Makevars.win and add
-I src/levmar
to the PKG_CPPFLAGS but it didn't work out either.
Do you have any idea on what I should do ?
Don't hesitate to ask for precisions if I wasn't clear enough
Upvotes: 1
Views: 825
Reputation: 26833
SODD got the better of me. I have build a very rough package that compiles the levmar code and creates an initial R package from it: https://github.com/rstub/levmaR. Important points:
Source files in sub-directories of src
are not automatically compiled. One has to add them somehow, e.g.
CXX_STD = CXX11
PKG_LIBS=-L. -llevmar $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)
PKG_CPPFLAGS=-I./levmar/ -DSTRICT_R_HEADERS
all: $(SHLIB)
$(SHLIB): liblevmar.a
LIBOBJS = levmar/lm.o levmar/Axb.o levmar/misc.o levmar/lmlec.o levmar/lmbc.o \
levmar/lmblec.o levmar/lmbleic.o
liblevmar.a: $(LIBOBJS)
$(AR) rcs liblevmar.a $(LIBOBJS)
By default levmar tries to build single- and double-precision functions and tries to use LAPACK. Default builds of R only include double-precision LAPACK and BLAS. I disabled the single precision build.
The levmar library is actually pure C. So my suspicion that your problems where caused by the different C++ ABIs between VC and gcc is probably not correct. Most likely there is some other incompatibility between VC and gcc concerning the layout of static libraries.
Right now the only available function is your test_levmar()
. Tested on Linux and Windows (via Appveyor and rhub).
Upvotes: 3