[英]R package with both .c and .cpp files with Rcpp
I'm trying to build an R package which contains both C (in the form of .c files) and C++ code (in the form of .cpp files) using the Rcpp package as a dependency. 我正在尝试使用Rcpp包作为依赖项来构建一个包含C(以.c文件的形式)和C ++代码(以.cpp文件的形式)的R包。
I have a couple of questions. 我有一些问题。
To help with this, I have set up a little example which is available on my GitHub page ( https://github.com/tpbilton/testrcpp ). 为了解决这个问题,我建立了一个小例子,可以在我的GitHub页面( https://github.com/tpbilton/testrcpp )上找到。 I have used Rcpp.package.skeleton("testrcpp")
to initialize the package and added some functions (from this tutorial https://cran.r-project.org/web/packages/Rcpp/vignettes/Rcpp-introduction.pdf ) and then ran Rcpp::compileAttributes()
. 我已经使用Rcpp.package.skeleton("testrcpp")
来初始化程序包并添加了一些功能(来自本教程https://cran.r-project.org/web/packages/Rcpp/vignettes/Rcpp-introduction.pdf ),然后运行Rcpp::compileAttributes()
。 I installed the package and the c++ function convolve_cpp
works fine but the convolve_c
is not registered and I have no idea how to do this properly and my attempts at trying to register both functions have gone nowhere. 我安装了该软件包,并且c ++函数convolve_cpp
可以正常运行,但是convolve_c
没有注册,我也不知道如何正确执行此操作,尝试注册这两个函数的尝试也没有成功。
It helps to step back and review. 它有助于退后一步并进行审查。 Consider two packages: 考虑两个软件包:
convolve_c
which you write by hand as a C only package in 'long-form' and do everything manually, including handcrafting the initialization and registration 您将convolve_c
编写为“长格式”的仅C包,并手动完成所有操作,包括手工进行初始化和注册 convolve_cpp
which you write using Rcpp -- and compileAttributes()
and other tools do everything for you. convolve_cpp
您编写使用RCPP -和compileAttributes()
和其他工具为你做的一切。 In essence, you question amount to also having the C part done for you by Rcpp and it just doesn't work that way. 从本质上讲,您质疑Rcpp是否也为您完成了C部分 ,但是那样行不通。 Rcpp does not 'see' your src/convolvec.c
so it won't add it. Rcpp不会“看到”您的src/convolvec.c
convolvec.c,因此不会添加它。
But if you look at how these function registrations work -- thousand of CRAN packages to look at, and a manual to peruse -- then you can fill it by hand. 但是,如果您查看这些功能注册的工作原理(要查看的数千个CRAN软件包和要阅读的手册),那么您可以手工填写。
Or you could punt. 或者您可以平底锅。 Just add a third function, in C++, which calls your C function. 只需在C ++中添加第三个函数即可调用您的C函数。 Rcpp will take care of everything, and you're done. Rcpp会处理所有事情,您已完成。 Your choice: easy, or elaborate. 您的选择:简单或详尽。
Edit: To be more explicit, option 3 consists of adding 编辑:更明确地说,选项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);
}
Then run compileAttributes()
and all is good. 然后运行compileAttributes()
,一切都很好。 The mixing and matching will work too for the usual reason but is more work -- see "Writing R Extensions" for all the details. 由于通常的原因,混合和匹配也可以使用,但是需要更多工作-有关所有详细信息,请参见“编写R扩展”。
Illustration of it working: 工作原理图:
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>
First, is it actually possible to do this? 首先,实际上有可能这样做吗? Can one call C scripts and C++ scripts that are in the same R package? 可以调用同一R包中的C脚本和C ++脚本吗?
Yes. 是。 Rcpp very famously is taking advantage of R 's C API. Rcpp非常著名地利用了R的C API。 (cf Section 1.6.4 Portable C and C++ code of Writing R Extensions . (请参阅第1.6.4节 “ 编写R扩展的 可移植C和C ++代码 ”。
If the previous is possible, how then does one properly register the functions in the C and C++ scripts. 如果可能的话,那么如何在C和C ++脚本中正确注册功能。
Ideally, only surface aspects from the C++ script. 理想情况下,仅表面上使用C ++脚本编写。 Otherwise, you're stuck writing the glue. 否则,您将无法书写胶水。
I've taken this approach. 我采用了这种方法。 The post goes on to detail the slight changes. 该帖子继续详细介绍了细微的变化。 A working example can be found off-site at: 一个工作示例可以在以下位置找到:
https://github.com/r-pkg-examples/rcpp-and-c https://github.com/r-pkg-examples/rcpp-and-c
In short, we'll create a header file for the function definitions and include it with the C code. 简而言之,我们将为函数定义创建头文件,并将其包含在C代码中。 From there, we'll create a third file that is in C++ and export that function into R using _Rcpp. 从那里,我们将创建第三个C ++文件,并使用_Rcpp将函数导出到R中。
Here we use an inclusion guard via #ifndef
and #define
to ensure the function definitions are not repeated if we reuse the header file multiple times. 在这里,我们通过#ifndef
和#define
使用包含保护,以确保如果多次重复使用头文件,则函数定义不会重复。
#ifndef CONVOLVE_C_H
#define CONVOLVE_C_H
SEXP convolve_c(SEXP a, SEXP b);
#endif /* CONVOLVE_C_H */
Now, let's modify the file to allow for our custom header. 现在,让我们修改文件以允许我们的自定义标头。
#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;
}
Finally, we incorporate the C code using extern
within our C++ file to have the function name in C++ align with the C linkage. 最后,我们使用纳入C代码extern
我们的C ++内部文件在C函数名++与C链接对齐。 In addition, we manipulate the data type from SEXP
to NumericVector
. 另外,我们处理从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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.