Неопределенная ссылка при сборке пакета R с использованием Rcpp с внешней библиотекой C ++ - PullRequest
0 голосов
/ 13 марта 2019

Я пытаюсь создать пакет R для собственного использования, который использует Rcpp и чей код C ++ включает библиотеку Levmar . Я работаю на Windows.

Код C ++ работает нормально, когда я собираю его, например, с помощью CMake и запускаю его с Visual Studio. Но когда я помещаю этот код в свой пакет R и пытаюсь его собрать, я получаю следующую ошибку:

levmar_example_r.o: levmar_example_r.cpp :(. Text + 0x281): неопределенная ссылка на `dlevmar_der '

(dlevmar_der объявлен в levmar.h, который входит в мой пакет R, см. Ниже)

Я уже прочитал довольно много SO-сообщений о том, как создать пакет 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 / include и все файлы .c в папку src / levmar и, следовательно, удалить

PKG_LIBS = -L../bin -llevmar

в Makevars / Makevars.win и добавьте

-I src/levmar

на PKG_CPPFLAGS, но это тоже не сработало.

Ты хоть представляешь, что мне делать?

Не стесняйтесь спрашивать о точности, если я не достаточно ясно

1 Ответ

2 голосов
/ 14 марта 2019

СОДД одолела меня.Я создал очень грубый пакет, который компилирует код 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 включают только LAPACK двойной точности и BLAS.Я отключил сборку с одинарной точностью.

  • Библиотека levmar на самом деле чистая C. Поэтому я подозреваю, что ваши проблемы, вызванные различными C ++ ABI между VC и gcc, вероятно, не верны.Скорее всего, существует некоторая другая несовместимость между VC и gcc относительно компоновки статических библиотек.

На данный момент единственной доступной функцией является ваша test_levmar().Протестировано на Linux и Windows (через Appveyor и rhub).

...