c - 在 R 包中共享已编译的 C 代码并从另一个包运行它的首选方法是什么?

标签 c r package

假设我在 R 中有两个包,第一个名为 foo,第二个名为 bar。我想在 foo 中包含一个 C 函数,并以一种独立于平台且符合 CRAN 策略的方式与 bar 共享该功能。

执行此操作的首选方法是什么?我应该如何使用函数注册和动态库?

我的问题的目的是,尽管我通读了我能找到的所有文档,但我没有想到什么是显而易见的事情,而且我不确定最可持续的行动方案是什么。

示例:

假设在一个包 foo 中,我定义了一个 C 函数 addinc,它将两个数字相加。

#include <R.h>
#include <Rinternals.h>

SEXP addinc(SEXP x_, SEXP y_) {
  double x = asReal(x_);
  double y = asReal(y_);

  double sum = x + y;

  return ScalarReal(sum);
}

在同一个包中,我可以尝试通过 .Call 接口(interface)在名为 addinr 的 R 函数中调用 addinc

addinr <- function(x,y){
  .Call("addinc", x, y, PACKAGE="foo")
}

但是,在构建、检查和安装包时,运行 addinr 会返回以下错误,大概是因为该函数尚未在 R 中注册。

library(foo)
addinr(1,2)

Error in .Call("addinc", x, y, PACKAGE = "foo") :
"addinc" not available for .Call() for package "foo"

在我看来,解决这个问题的最简单方法是通过将 useDynLib(foo) 添加到 foo 的 NAMESPACE 文件来为编译后的代码构建一个动态库. 这似乎可以解决问题,因为我现在可以毫无问题地调用 addinr()。此外,我可以直接从 R 中运行 .Call("addinc", ..., PACKAGE="foo")

然而,我的真正的问题出现在第二个包,比如bar,应该使用fooaddinc。例如,假设 bar 定义了一个函数 multiplyinr,如下所示。

multiplyinr <- function(x,y){
  ans <- 0
  for(i in 1:y) ans <- .Call("addinc", ans, x, PACKAGE="foo")
  ans
}

事实上,这完全可以正常工作,我可以在 R 中调用 multiplyinr。但是,在构建和检查 bar 时,我收到一条提示这个事实的注释bar 正在调用来自不同包的外语函数。

Foreign function call to a different package:
.Call("addinc", ..., PACKAGE = "foo")
See chapter ‘System and foreign language interfaces’ in the ‘Writing R Extensions’ manual.

根据 this question ,包 bar 不适合提交给 CRAN,因为以这种方式使用 .Call() 不被视为“可移植”,如 Writing R Extensions manual 中所述。 .

总而言之,让 foo 在其 NAMESPACE 文件中包含一个 useDynLib(foo) 的简单解决方案似乎并不能完全解决问题。因此我的问题是:与其他包共享 C 函数的首选方法是什么?

此外:

使用 useDynLib() 真的很危险或不符合 CRAN 政策吗?在 NAMESPACE 文件中声明 useDynLib() 以替代手动注册和构建共享库的目的是什么?

手动注册 C 函数并构建共享库是否会改变任何东西(即,使用 R_RegisterCCallable()R_registerRoutines())?

最佳答案

一般的想法是通过使用例如创建的“本地符号信息”对象。 useDynLib(<pkg>, <symbol>)不是包的公共(public) API 的一部分,因此客户端包不应该直接调用它们(假设它们可以在包的 future 修订中更改)。

有两种方法可以“导出”已编译的例程以供客户端包使用:

  1. 只需在 foo 中导出一个 R 包装函数直接调用 native 例程,或者
  2. 使用R_RegisterCCallable()/R_GetCCallable()一对函数以获得指向所需函数的指针。 (包 foo 将调用 R_RegisterCCallable() 使某些函数可用;客户端包 bar 将调用 R_GetCCallable() 以获取指向该函数的指针)

换句话说,如果包作者“注册”了他们的 C 函数,他们就在声明这是他们包的公共(public) C API 的一部分,并允许客户端包通过此接口(interface)使用/调用它。

关于c - 在 R 包中共享已编译的 C 代码并从另一个包运行它的首选方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35103804/

相关文章:

r - 识别 GPS 数据中的 24 小时周期

r - Data.table:使用 Shiny 的变量动态选择组

r - 软件包安装错误 : compilation failed

java - 如何修复MAVEN中的 "Either artifact or artifactItems is required"错误

c - 加速器未显示在 GtkCheckMenuItem 中

c - 这段c代码的作用是什么?

r - 如何使用多行文本在分组条形图的条形上添加值?

Meteor 1.4版本安装包错误

C编程-如何将输出图片文件设置为.pgm格式?

c - 函数指针等于函数内的另一个指针,为什么需要加*