注册 C++ 版本的 Rcpp 函数并在新包中的其他 Rcpp 函数中使用它

Register C++ version of Rcpp function and use it within the other Rcpp function in a new package

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

我找到了一个 . Following the answer of Dirk Eddelbuettel I have investigated this file 并编写了以下代码(在 init.c 文件中,该文件已放置在 src 文件夹)希望使 polynomialIndex 函数(来自 hpa 包)对其他包(包括我的新包)的 Rcpp 函数可用(以 Rcpp 即 C++ 形式):

#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 文件包含 这一事实有关。文件本身如下所示:

#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 并声明 polynomialIndex 直接在 init.c 文件中。不幸的是,它会导致其他 错误消息 :

/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);
}

P.S。 This question 也与此类似,但没有解决我的问题。

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

这里你似乎从 C 编译(由 gcc 开始)接触了一个文件,其中 you 过渡到 C++。明确地说,您不能为 C 编译执行此操作。

R 仅提供 C 接口。 Rcpp 通过自动生成兼容的接口文件来帮助您。如果你想extend/alter他们,你必须遵守规则。

将 C++ 代码包装在(更简单、更可移植、交叉编译器...)C 接口中是几十年的老把戏了。您可能会找到很多相关资源。

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

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

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

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

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

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

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

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);
}

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