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

西蒙·G

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

首选的方法是什么?如何使用函数注册和动态库?

我的问题的目的是,即使我通读了所有可以找到的文档,对于我来说显然也没有发生任何事情,而且我不确定最可持续的行动是什么。

例:

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

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

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

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

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

library(foo)
addinr(1,2)

.Call(“ addinc”,x,y,PACKAGE =“ foo”)中的错误:
包“ foo”的.Call()无法使用“ addinc”

在我看来,解决此问题的最简单方法是通过添加useDynLib(foo)fooNAMESPACE文件为编译后的代码构建动态库这似乎可以解决问题,因为我现在可以addinr()没有问题地打电话而且,我可以.Call("addinc", ..., PACKAGE="foo")直接在R中运行

但是,当第二个程序包应该使用s时,就会发生我的真正问题例如,假设按如下方式定义一个函数barfooaddincbarmultiplyinr

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

实际上,这完全可以正常工作,并且我可以multiplyinr在R中调用。但是,在构建和检查时bar,我收到一条注释,抱怨bar从另一个包中调用外语函数。

外部函数调用到另一个程序包:
.Call(“ addinc”,...,PACKAGE =“ foo”)
请参见“编写R扩展”手册中的“系统和外语接口”一章。

根据这个问题,该软件包bar将不适合提交给CRAN,因为.Call()按照《编写R扩展》手册中的说明,不认为以这种方式使用该软件包是“便携式的”

总之,在其NAMESPACE文件中foo包含A的简单解决方案useDynLib(foo)似乎并没有削减它。因此,我的问题是:与其他软件包共享C函数的首选方法是什么?

此外:

使用useDynLib()确实是危险的还是与CRAN政策不一致?useDynLib()在NAMESPACE文件中声明的目的是替代手动注册和构建共享库的目的?

手动注册C函数并建立共享库是否会更改任何内容(即使用R_RegisterCCallable()R_registerRoutines())?

凯文·乌谢(Kevin Ushey)

通常的想法是,使用例如useDynLib(<pkg>, <symbol>)方法创建的“本机符号信息”对象不是包的公共API的一部分,因此客户端包不应直接调用它们(假定它们可以在包的未来版本中进行更改)。

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

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

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

无法加载程序包:它包含的单元也包含在另一个程序包中

根据本地代码从另一个pip安装的程序包运行py.test测试

SSIS主程序包执行另一个项目中的程序包

如何从我的程序包中的另一个程序包加载数据

从另一个程序包调用受保护的方法吗?

如何使已经存在的Nix程序包中的二进制文件能够在另一个程序包中运行Shell脚本?

突出版本并从一个分支发布程序包,但将标记保留在另一个分支

为什么从当前程序包将结构传递给具有文字struct参数的函数与从另一个程序包传递的函数不同?

nix:从另一个引用一个本地perl程序包

如何从另一个程序包的依赖项列表中删除特定程序包?

使用Hibernate程序包从另一个程序包访问数据库

安装程序包尝试下载另一个非相关程序包的文件

如何创建Java程序包以及如何在另一个程序包中导入它们?

为Meteor编写程序包时如何依赖另一个程序包

通过平滑代码导入从另一个项目构建的依赖项时,“对象不是程序包的成员”

在另一个实例化一个类的首选方法是什么?

在javafx中从另一个程序包加载FXML文件时出现错误?

从另一个程序包调用时,sublis不替代符号

将类移动到另一个程序包后出现MissingRequirementError

从另一个程序包读取属性文件时出现空指针错误

如何显示从一个程序包到另一个程序包的依赖关系链?

如何在Atom编辑器中给一个程序包优先于另一个程序包?

将场景从一个程序包切换到另一个程序包javafx

如何在另一个C ++程序中运行一个C ++程序?

CodeCompiler - 从另一个Java程序编译和运行Java程序

如何在另一个Java程序中编译和运行Java程序?

从共享全局变量的另一个python文件运行推荐序列的最佳方法是什么?

如何在另一个Eclipse工作区中创建的项目中使用另一个程序包中一个程序包的类

dpkg-shlibdeps:错误:在打包依赖于另一个程序包的程序包时找不到.so所需的库