带有 Rcpp 的 .c 和 .cpp 文件的 R 包 [英] R package with both .c and .cpp files with Rcpp

查看:48
本文介绍了带有 Rcpp 的 .c 和 .cpp 文件的 R 包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 Rcpp 包作为依赖项构建一个包含 C(以 .c 文件的形式)和 C++ 代码(以 .cpp 文件的形式)的 R 包.

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.

我有几个问题.

  1. 首先,真的可以这样做吗?可以调用同一 R 包中的 C 脚本和 C++ 脚本吗?
  2. 如果前一种可行,那么如何在 C 和 C++ 脚本中正确注册函数.

为了帮助解决这个问题,我在我的 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 未注册,我不知道如何正确执行此操作以及我尝试注册这两个函数的尝试无处可去.

To help with this, I have set up a little example which is available on my GitHub page (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(). 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.

推荐答案

首先,这真的可能吗?可以调用同一个R包中的C脚本和C++脚本吗?

First, is it actually possible to do this? Can one call C scripts and C++ scripts that are in the same R package?

是的.Rcpp 以利用 RC API 而闻名.(参见 部分1.6.4 的可移植 C 和 C++ 代码编写 R 扩展.

Yes. Rcpp very famously is taking advantage of R's C API. (c.f. Section 1.6.4 Portable C and C++ code of Writing R Extensions .

如果前一个可行,那么如何在 C 和 C++ 脚本中正确注册函数.

If the previous is possible, how then does one properly register the functions in the C and C++ scripts.

理想情况下,只有 C++ 脚本的表面方面.否则,你会被困在写胶水里.

Ideally, only surface aspects from the C++ script. 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-和-c

简而言之,我们将为函数定义创建一个头文件,并将其包含在 C 代码中.从那里,我们将创建第三个 C++ 文件,并使用 _Rcpp 将该函数导出到 R.

In short, we'll create a header file for the function definitions and include it with the C code. From there, we'll create a third file that is in C++ and export that function into R using _Rcpp.

这里我们通过 #ifndef#define 使用包含保护来确保如果我们多次重用头文件,函数定义不会重复.

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 CONVOLVE_C_H
#define CONVOLVE_C_H

SEXP convolve_c(SEXP a, SEXP b);

#endif /* CONVOLVE_C_H */

convolve_in_c.c

现在,让我们修改文件以允许我们的自定义标题.

convolve_in_c.c

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

convolve_from_c_to_rcpp.cpp

最后,我们在 C++ 文件中使用 externC 代码合并到 C++ 文件中> 与 C 链接对齐.此外,我们将数据类型从 SEXP 操作为 NumericVector.

convolve_from_c_to_rcpp.cpp

Finally, we incorporate the C code using extern within our C++ file to have the function name in C++ align with the C linkage. In addition, we manipulate the data type from SEXP to 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;
}

这篇关于带有 Rcpp 的 .c 和 .cpp 文件的 R 包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆