0

我有一个包hpa有一些用Rcpp编写的功能。我想在我的新R 包中使用其中一些功能。为了避免性能损失,必须以“Rcpp 形式”使用此功能,因此我无法以通常的方式导出它们。

我发现了一个类似的问题。按照 Dirk Eddelbuettel 的回答,我调查了这个文件并编写了以下代码(在已放置在src文件夹中的init.c文件中),希望使polynomialIndex函数(来自 hpa 包)变得可用(以 Rcpp 即 C++ 形式) 用于其他包的 Rcpp 功能(包括我的新包):

#include <Rconfig.h>
#include <Rinternals.h>
#include <R_ext/Rdynload.h>
#include "polynomialIndex.h"

/* definition of functions provided for .Call()             */
static const R_CallMethodDef callMethods[] = {
    { "polynomialIndex", (DL_FUNC) &polynomialIndex, 1 },
    { NULL, NULL, 0 }
};

/* functions being called when package is loaded -- used to register    */
/* the functions we are exporting here                  */
void R_init_RApiSerialize(DllInfo *info) {

    /* used by external packages linking to internal serialization code from C */
    R_RegisterCCallable("hpa", "polynomialIndex", 
                        (DL_FUNC) &polynomialIndex);

    R_registerRoutines(info,
                       NULL,        /* slot for .C */
                       callMethods,     /* slot for .Call */
                       NULL,            /* slot for .Fortran */
                       NULL);       /* slot for .External */

    R_useDynamicSymbols(info, TRUE);    /* controls visibility */ 
}

不幸的是,当我尝试构建hpa包时,会出现以下错误消息

/mingw64/bin/gcc  -I"C:/R/R-41~1.0/include" -DNDEBUG  -I'C:/R/R-4.1.0/library/Rcpp/include' -I'C:/R/R-4.1.0/library/RcppArmadillo/include' -I'C:/R/R-4.1.0/library/RcppParallel/include'        -O2 -Wall  -std=gnu99 -mfpmath=sse -msse2 -mstackrealign  -c init.c -o init.o
In file included from C:/R/R-4.1.0/library/Rcpp/include/Rcpp/r/headers.h:66,
                 from C:/R/R-4.1.0/library/Rcpp/include/RcppCommon.h:30,
                 from C:/R/R-4.1.0/library/RcppArmadillo/include/RcppArmadilloForward.h:26,
                 from C:/R/R-4.1.0/library/RcppArmadillo/include/RcppArmadillo.h:31,
                 from polynomialIndex.h:4,
                 from init.c:4:
C:/R/R-4.1.0/library/Rcpp/include/Rcpp/platform/compiler.h:100:10: fatal error: cmath: No such file or directory
 #include <cmath>
          ^~~~~~~
compilation terminated.
make: *** [C:/R/R-41~1.0/etc/x64/Makeconf:238: init.o] Error 1

这似乎与polynomialIndex.h文件包含 <RcppArmadillo.h> 的事实有关。该文件本身如下所示:

#ifndef hpa_polynomialIndex_H
#define hpa_polynomialIndex_H

#include <RcppArmadillo.h>
using namespace Rcpp;
using namespace RcppArmadillo;

NumericMatrix polynomialIndex(NumericVector pol_degrees,
                              bool is_validation);

String printPolynomial(NumericVector pol_degrees, 
                       NumericVector pol_coefficients,
                       bool is_validation);

#endif

然后我尝试从init.c中删除polynomialIndex.h并直接在init.c文件中声明polynomialIndex 。不幸的是,它会导致另一个错误消息

/mingw64/bin/gcc  -I"C:/R/R-41~1.0/include" -DNDEBUG  -I'C:/R/R-4.1.0/library/Rcpp/include' -I'C:/R/R-4.1.0/library/RcppArmadillo/include' -I'C:/R/R-4.1.0/library/RcppParallel/include'        -O2 -Wall  -std=gnu99 -mfpmath=sse -msse2 -mstackrealign  -c init.c -o init.o
** using staged installation
** libs
/mingw64/bin/g++ -std=gnu++11 -shared -s -static-libgcc -o hpa.dll tmp.def ParallelFunctions.o RcppExports.o hpaBinary.o hpaML.o hpaMain.o hpaSelection.o hpaValidation.o init.o normalMoments.o polynomialIndex.o spline.o -LC:/R/R-41~1.0/bin/x64 -lRlapack -LC:/R/R-41~1.0/bin/x64 -lRblas -lgfortran -lm -lquadmath -LC:/R/R-41~1.0/bin/x64 -lR
C:/rtools40/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: init.o:init.c:(.text+0x8): undefined reference to `polynomialIndex'
C:/rtools40/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: init.o:init.c:(.rdata+0x28): undefined reference to `polynomialIndex'
C:/rtools40/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: init.o:init.c:(.rdata$.refptr.polynomialIndex[.refptr.polynomialIndex]+0x0): undefined reference to `polynomialIndex'

请帮我解决这些问题。最后,我希望能够在我的新包中使用 polynomialIndex 函数。根据我发现的信息,它应该看起来像这样(简化示例):

// [[Rcpp::depends(hpa)]]
#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector newFunc(NumericVector pol_degrees,
                      bool is_validation) {
  
  static SEXP(*polynomialIndex)(Rcpp::NumericVector, bool) = NULL;
  polynomialIndex = (SEXP(*)(Rcpp::NumericVector, bool)) R_GetCCallable("hpa", "polynomialIndex");
  
  NumericVector result = polynomialIndex(pol_degrees, is_validation);
  
  return(result);
}

PS这个问题也和这个类似,但不能解决我的问题。

4

2 回答 2

1

之前已经讨论过这个问题,我敦促您研究这些其他问题并尝试他们的答案。

在这里,您似乎从C编译(由 开始gcc)进行了交叉,触及了在其中交叉到C++的文件。简而言之,C 编译不能做到这一点。

R 仅提供 C 接口。Rcpp 通过自动生成符合要求的接口文件来帮助您。如果你想扩展/改变它们,你必须遵守规则。

将 C++ 代码包装在(更简单、更便携、交叉编译器……)C 接口中是一个几十年前的技巧。你可能会找到很多资源。

于 2021-07-08T13:28:38.830 回答
0

按照 Dirk Eddelbuettel 的建议,我对这个问题进行了额外的搜索。不幸的是,我找到了一个非常简单的解决方案。

首先,我删除了 init.c文件。

其次,我在hpa包的所有.cpp文件中添加了以下代码行。

// [[Rcpp::interfaces(r, cpp)]]

第三,我已将以下代码添加到我的新包的描述文件中,以便将其链接到hpa包(我在找到解决方案之前已经完成了它,但为了提供完整的收据,添加此信息似乎是合理的) .

Imports: Rcpp (>= 1.0.6), hpa (>= 1.2.1)
Depends: hpa (>= 1.2.1)
LinkingTo: Rcpp, RcppArmadillo, hpa

第四,出于同样的原因,我在命名空间文件中添加了以下代码行:

import(hpa)

第五,我编译了hpa包(像往常一样)并找到了一个名为inst的新文件夹。在这个文件夹里面有一个文件夹include。在这个文件夹中,我找到了一个新文件hpa.h。所以我只是简单地将这个文件包含在代码中,并将对函数的调用简化为hpa::polynomialIndex(...)。所以结果(成功工作!)代码如下:

// [[Rcpp::depends(hpa)]]
#include <RcppArmadillo.h>
#include <hpa.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector newFunc(NumericVector pol_degrees,
                      bool is_validation) {
  
  NumericVector result = hpa::polynomialIndex(pol_degrees, is_validation);
  
  return(result);
}

PS 调查文件hpa\inst\include\hpa_RcppExports.h以了解[[Rcpp::interfaces(r, cpp)]]是如何解决问题的。

于 2021-07-08T17:23:40.517 回答