假设我在R中有两个包,第一个名为foo
,第二个名为bar
。我想包含一个C函数,foo
并bar
以一种独立于平台且与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)
到foo
NAMESPACE文件为编译后的代码构建动态库。这似乎可以解决问题,因为我现在可以addinr()
没有问题地打电话。而且,我可以.Call("addinc", ..., PACKAGE="foo")
直接在R中运行。
但是,当第二个程序包应该使用s时,就会发生我的真正问题。例如,假设按如下方式定义一个函数。bar
foo
addinc
bar
multiplyinr
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()
)?
通常的想法是,使用例如useDynLib(<pkg>, <symbol>)
方法创建的“本机符号信息”对象不是包的公共API的一部分,因此客户端包不应直接调用它们(假定它们可以在包的未来版本中进行更改)。
有两种方法可以“导出”已编译的例程以供客户端软件包使用:
foo
即可直接调用本机例程,或者R_RegisterCCallable()
/R_GetCCallable()
对函数可获取指向所需函数的指针。(包foo
将调用R_RegisterCCallable()
以使某些功能可用;客户端包bar
将调用R_GetCCallable()
以获取指向该功能的指针)换句话说,如果程序包作者“注册”了他们的C函数,则他们声明它是其程序包的公共C API的一部分,并允许客户端程序包通过此接口使用/调用它。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句