使用RCPP与外部C 库构建R软件包时未定义的参考



我正在尝试创建一个用于自己使用的R软件包,即使用RCPP,其C 代码包括Levmar库。我在Windows上工作。

当我使用CMAKE构建它时,C 代码正常工作,并使用Visual Studio运行它。但是,当我将此代码放在R包中并尝试构建它时,我会收到以下错误:

levmar_example_r.o:levmar_example_r.cpp :(。text 0x281):未定义的引用`dlevmar_der'

(dlevmar_der在我的r软件包中包含在levmar.h中,请参见下文)

我已经阅读了很多关于如何使用类似外部库或这样的外部库来构建R软件包的文章,但这并没有帮助我解决问题。

我的包装的结构:

bin/
  |- levmar.lib
inst/
  |- include/
      |- levmar.h
man/
R/
src/
  |- Makevars
  |- Makevars.win
  |- levmar_example_r.cpp
  |- RcppExports.cpp
src-i386/
DESCRIPTION
NAMESPACE

makevars/makevars.win

的内容
PKG_LIBS = -L../bin -llevmar
PKG_CPPFLAGS = -I../inst/include 

C 代码(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;
 }

我还试图将levmar库的所有标题放在Inst/Inlude文件夹中,以及SRC/Levmar文件夹中的所有.c文件,因此删除了

PKG_LIBS = -L../bin -llevmar

在makevars/makevars.win中添加

-I src/levmar

到pkg_cppflags,但也无法解决。

您对我该怎么办有任何想法吗?

如果我不够清楚

,请随时询问精确度

sodd使我变得更好。我已经构建了一个非常粗略的软件包,该软件包编译了Levmar代码并从中创建一个初始的R软件包:https://github.com/rstub/levmar。要点:

  • src的子目录中的源文件不是自动编译的。必须以某种方式添加它们,例如

    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)
    
  • 默认情况下,Levmar试图构建单精度和双重精确功能,并尝试使用Lapack。R的默认构建仅包括Double Eccision Lapack和Blas。我禁用了单个精度构建。

  • levmar库实际上是纯净的C。因此,我怀疑您的问题是由VC和GCC之间不同的C ABI引起的问题。对于静态库的布局,VC和GCC之间很可能还有其他不相容性。

现在唯一可用的功能是您的test_levmar()。在Linux和Windows上测试(通过Appveyor和Rhub)。

最新更新