从sourceCpp迁移到包含Rcpp的包

时间:2013-01-11 23:21:38

标签: c++ r rcpp

我目前有一个.cpp文件,我可以使用sourceCpp()编译。正如预期的那样,创建了相应的R函数,代码按预期工作。

这是:

#include <Rcpp.h> 
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector exampleOne(NumericVector vectorOne, NumericVector vectorTwo){

    NumericVector outputVector = vectorOne + vectorTwo; 

    return outputVector;
}

我现在正在使用Rcpp将项目转换为包。所以我用rStudio创建了骨架,并开始研究如何将事物转换过来。

在Hadley的excellent primer on Cpp中,他在第34节中说道;在一个包中使用Rcpp&#34;:

  

如果您的包使用Rcpp :: export属性,则需要在包构建过程中增加一个步骤。 compileAttributes函数扫描包中的源文件以获取Rcpp :: export属性,并生成将函数导出到R所需的代码。

     

每当添加,删除函数或更改其签名时,都应重新运行compileAttributes。请注意,如果使用RStudio或devtools构建程序包,则会自动执行此步骤。

因此看起来使用sourceCpp()编译的代码应该与包中的代码一样。

我创建了相应的R文件。

exampleOne <- function(vectorOne, vectorTwo){
    outToR <- .Call("exampleOne", vectorOne, vectorTwo, PACKAGE ="testPackage")
    outToR
}

然后我(重新)构建了包,我收到了这个错误:

Error in .Call("exampleOne", vectorOne, vectorTwo, PACKAGE = "voteR") : C symbol name "exampleOne" not in DLL for package "testPackage"

有没有人知道在使用sourceCpp()编译然后在包中使用它时需要做什么?

我应该注意到我已经读过:&#34;编写一个使用Rcpp&#34; http://cran.rstudio.com/web/packages/Rcpp/vignettes/Rcpp-package.pdf并了解那里提出的基本结构。但是,在查看RcppExamples源代码后,似乎晕影中的结构与示例包中使用的结构不完全相同。例如,没有使用.h文件。插图和源代码也不使用[[Rcpp :: export]]属性。这一切都很难准确追踪我的错误。

3 个答案:

答案 0 :(得分:8)

这是我如何从使用sourceCpp()到使用Rcpp的包的“演练”。如果有错误,请随时编辑或让我知道,我将编辑它。

[注意:我强烈建议在此过程中使用RStudio。]

因此,您需要对sourceCpp()事情进行调整,现在需要构建一个包。这并不难,但可能有点棘手,因为有关使用Rcpp构建软件包的信息范围从您想要的任何R软件包的详尽彻底的文档(但是作为新手高于您的头脑),以及新手敏感介绍(可能会遗漏你碰巧需要的细节)。

在这里,我使用oneCpp.cpptwoCpp.cpp作为您将在包中使用的两个.cpp文件的名称。

以下是我的建议:

一个。首先,我假设您有一个theCppFile.cpp版本,可以使用sourceCpp()进行编译,并按预期工作。这不是必须的,但是如果您不熟悉Rcpp OR软件包,那么在转移到下面更复杂的情况之前,确保您的代码在这种简单的情况下工作是很好的。

B中。现在使用Rcpp.package.skeleton()构建您的包,或者使用RStudio中的Project&gt; Create Project&gt; Package w / Rcpp向导(强烈推荐)。您可以在[hadley / devtools] [1]或[Rcpp Attributes Vignette] [2]中找到有关使用Rcpp.package.skeleton()的详细信息。使用Rcpp编写软件包的完整文档在[编写一个使用Rcpp的软件包] [3],但是这个假设您已经很好地了解了C ++,并且不使用新的“属性”方式来执行Rcpp。如果你转向制作更复杂的包装,那将是非常宝贵的。

您现在应该拥有包的目录结构,如下所示:

yourPackageName
- DESCRIPTION
- NAMESPACE
- \R\
    - RcppExports.R 
- Read-and-delete-me
- \man\
    - yourPackageName-package.Rd
- \src\
    - Makevars
    - Makevars.win
    - oneCpp.cpp 
    - twoCpp.cpp
    - RcppExports.cpp

设置好所有内容后,如果使用RStudio,请执行“Build&amp; Reload”;如果不在RStudio中,请执行compileAttributes()

℃。您现在应该在\ R目录中看到一个名为RcppExports.R的文件。打开它并检查出来。在RcppExports.R中,您应该看到.cpp目录中所有\src个文件的R包装函数。很甜蜜,嗯?。

D)尝试与您在theCppFile.cpp中编写的功能相对应的R功能。它有用吗?如果是这样的话继续前进。

E)您现在可以在创建.cpp目录时将新otherCpp.cpp文件添加到\src目录中。然后你只需要重建包,然后生成R包装并将其添加到RcppExports.R。在RStudio中,这只是Build菜单中的“Build&amp; Reload”。如果您不使用RStudio,则应运行compileAttributes()

答案 1 :(得分:4)

简而言之,诀窍是从包的根目录中调用compileAttributes()。例如,对于包foo

$ cd /path/to/foo
$ ls
DESCRIPTION  man  NAMESPACE  R  src
$ R
R> compileAttributes()

此命令将生成缺少的RcppExports.cppRcppExports.R

答案 2 :(得分:2)

你错过了树林。

sourceCpp()是最近的功能;它是我们称之为“Rcpp属性”的一部分,它有自己的小插图(在包中,在我的网站上和CRAN上具有相同的标题),您可能想要阅读它。除其他外,详细说明了如何将使用sourceCpp()编译和运行的内容转换为包。这就是你想要的。

在文档之间随机跳转对您没有帮助,在包装作者的真正源文档的最后可能更好。或者对它进行不同的旋转:您使用的是新功能,但旧的文档却没有反映出来。尝试用Rcpp编写一个基本包,也就是从另一端来到它。

最后,有一个邮件列表......