我正在尝试使用Rcpp包作为依赖项来构建一个包含C(以.c文件的形式)和C ++代码(以.cpp文件的形式)的R包。
我有几个问题。
为此,我建立了一个小示例,该示例在我的GitHub页面(https://github.com/tpbilton/testrcpp)上可用。我已经使用Rcpp.package.skeleton("testrcpp")
来初始化程序包并添加了一些功能(来自本教程https://cran.r-project.org/web/packages/Rcpp/vignettes/Rcpp-introduction.pdf),然后运行了Rcpp::compileAttributes()
。我安装了该软件包,并且c ++函数convolve_cpp
可以正常运行,但是convolve_c
未注册,我也不知道如何正确执行此操作,尝试注册这两个函数的尝试也没有成功。>
答案 0 :(得分:4)
它有助于退后一步并进行查看。考虑两个软件包:
convolve_c
,您以“长格式”将其作为纯C包手工编写,并手动完成所有操作,包括手工进行初始化和注册convolve_cpp
–和compileAttributes()
和其他工具可以为您完成一切。从本质上讲,您质疑的是是否还有Rcpp为您完成的C部分,但那样行不通。 Rcpp不会“看到”您的src/convolvec.c
,因此不会添加它。
但是,如果您查看这些功能注册的工作方式-可以查看成千上万的CRAN软件包,以及要仔细阅读的手册-则可以 手动填写。
或者您可以平底锅。只需在C ++中添加第三个函数即可调用您的C函数。 Rcpp会处理所有事情,您已完成。您的选择:简单或详尽。
编辑:为了更加明确,选项3包括添加
#include <Rcpp.h>
extern "C" SEXP convolve_c(SEXP a, SEXP b);
// [[Rcpp::export]]
SEXP callCconvolve(SEXP a, SEXP b) {
return convolve_c(a, b);
}
然后运行compileAttributes()
,一切都很好。出于通常的原因,混合和匹配也可以使用,但是需要更多工作-有关所有详细信息,请参见“编写R扩展”。
它起作用的例证:
R> library(testrcpp)
R> a <- as.double(1:10)
R> b <- as.double(10:1)
R> identical(convolve_cpp(a, b), callCconvolve(a, b))
[1] TRUE
R>
答案 1 :(得分:2)
首先,实际上有可能这样做吗?可以调用同一R包中的C脚本和C ++脚本吗?
是的。 Rcpp 非常著名,它利用了 R 的 C API。 (参见Section 1.6.4 Portable C and C++ code中的Writing R Extensions 。
如果可能的话,那么如何在C和C ++脚本中正确注册功能。
理想情况下,仅是 C ++ 脚本的表面特征。否则,您将无法书写胶水。
我采用了这种方法。该帖子继续详细介绍了细微的变化。一个工作示例可以在以下位置找到:
https://github.com/r-pkg-examples/rcpp-and-c
简而言之,我们将为函数定义创建头文件,并将其包含在 C 代码中。从那里,我们将创建第三个文件,该文件位于 C ++ 中,并使用_Rcpp将函数导出到 R 中。
这里,我们通过#ifndef
和#define
使用了包含保护,以确保如果多次重复使用头文件,则不会重复使用函数定义。
#ifndef CONVOLVE_C_H
#define CONVOLVE_C_H
SEXP convolve_c(SEXP a, SEXP b);
#endif /* CONVOLVE_C_H */
现在,让我们修改文件以允许使用自定义标头。
#include <R.h>
#include <Rinternals.h>
// Incorporate our header
#include "convolve_in_c.h"
SEXP convolve_c(SEXP a, SEXP b) {
int na, nb, nab;
double *xa, *xb, *xab;
SEXP ab;
a = PROTECT(coerceVector(a, REALSXP));
b = PROTECT(coerceVector(b, REALSXP));
na = length(a); nb = length(b);
nab = na + nb - 1;
ab = PROTECT(allocVector(REALSXP, nab));
xa = REAL(a); xb = REAL(b); xab = REAL(ab);
for(int i = 0; i < nab; i++)
xab[i] = 0.0;
for(int i = 0; i < na; i++)
for(int j = 0; j < nb; j++)
xab[i + j] += xa[i] * xb[j];
UNPROTECT(3);
return ab;
}
最后,我们在{em> C ++ 文件中使用extern
合并 C 代码,以使 C ++ 中的函数名称与 C 链接。另外,我们将数据类型从SEXP
更改为NumericVector
。
#include "Rcpp.h"
// Define the method signature
#ifdef __cplusplus
extern "C" {
#endif
#include "convolve_in_c.h"
#ifdef __cplusplus
}
#endif
//' Call C function from Rcpp
//'
//' Uses the convolve_c function inside of a C++ routine by Rcpp.
//'
//' @param a,b A `numeric` vector.
//'
//' @return
//' A `numeric` vector of length \eqn{N_a + N_b}.
//'
//' @examples
//'
//' convolve_from_c(1:5, 5:1)
//'
//' @export
// [[Rcpp::export]]
Rcpp::NumericVector convolve_from_c(const Rcpp::NumericVector& a,
const Rcpp::NumericVector& b) {
// Compute the result in _C_ from _C++_.
SEXP ab = convolve_c(a, b);
// Cast as an _Rcpp_ NumericVector
Rcpp::NumericVector result( ab );
// Alternatively:
// Rcpp::NumericVector result( convolve_c(a, b) );
// Return result
return result;
}