使用带有Rcpp的第三方头文件

时间:2012-12-21 18:23:02

标签: c++ r rcpp

我有一个名为coolStuff.h的头文件,其中包含我想在cpp源文件中使用的函数awesomeSauce(arg1)

目录结构:

  • RworkingDirectory
    • sourceCpp
      • theCppFile.cpp
    • cppHeaders
      • coolStuff.h

守则:

#include <Rcpp.h>
#include <cppHeaders/coolStuff.h>
using namespace Rcpp;

// [[Rcpp::export]]
double someFunctionCpp(double someInput){

 double someOutput = awesomeSauce(someInput);

return someOutput;
}

我收到错误:

 theCppFile.cpp:2:31: error: cppHeaders/coolStuff.h: No such file or directory

我已经移动了整个地方的文件和目录,似乎无法让它工作。我看到使用第三方标题的例子就是这样说的:

#include <boost/array.hpp>

(来自Hadley / devtools)

https://github.com/hadley/devtools/wiki/Rcpp

那是什么给出的?我整个上午一直在寻找,并且找不到像我这样简单事情的答案。

更新01.11.12

好了,现在我已经想出如何在Rstudio中构建使用Rcpp的软件包,让我重新解释一下这个问题。我有一个独立的头文件coolStuff.h,它包含我想在我的cpp代码中使用的函数。

1)我应该在包目录结构中放置coolStuff.h,以便它包含的函数可以由theCppFile.cpp使用吗?

2)如何在cpp文件中调用coolStuff.h?再次感谢你的帮助。我从上次谈话中学到了很多东西。

注意:我读了小插图&#34;编写一个使用Rcpp&#34;它没有解释如何做到这一点。

答案:

好的,让我总结一下我的问题的答案,因为它分散在这个页面上。如果我得到一个错误的细节,请随时编辑或告诉我,我将对其进行编辑:

因此,您找到了一个.h.cpp文件,其中包含您要编写的.cpp文件中要使用的函数或其他一些代码,以便与{{1}一起使用}}。

让我们继续调用此找到的代码Rcpp并调用您要使用的函数coolStuff.h。让我们调用您正在编写的文件awesomeSauce()

(我应该注意,.h文件和.cpp文件中的代码都是C ++代码,它们之间的区别在于C ++程序员以正确的方式保持组织。我将讨论差异在这里,但在SO上的简单搜索会引导你讨论差异。对于你需要使用你发现的代码的R程序员,没有真正的区别。)

简称:您可以使用theCppFile.cpp这样的文件,前提是它不会调用其他库,只需剪切并粘贴到coolStuff.h,或者创建一个包可以将文件放在带有theCppFile.cpp文件的\src目录中,并使用您正在编写的文件顶部的theCppFile.cpp。后者更灵活,允许您在其他#include "coolStuff.h"文件中使用coolStuff.h中的函数。

详情:

1).cpp不得调用其他库。这意味着它不能在顶部包含任何include语句。如果是这样,我在下面详述的内容可能无法正常工作,并且使用调用其他库的已找到代码超出了此答案的范围。

2)如果您想使用coolStuff.h编译文件,则需要将sourceCpp()剪切并粘贴到coolStuff.h。我被告知存在异常,但theCppFile.cpp旨在编译一个sourceCpp()文件,因此这是最佳路径。

(注意:我不保证简单的剪切和粘贴可以开箱即用。您可能必须重命名变量,或者更有可能切换所使用的数据类型与您在{{{ 1}}。但到目前为止,使用6种不同的简单.cpp文件,剪切和粘贴对我来说很简单。

3)如果您只需要使用theCppFile.cpp.h的代码而不是其他地方的代码,那么您应该将其剪切并粘贴到coolStuff.h

(我再也不保证看到上面关于剪切和粘贴的说明)

4)如果要使用theCppFile.cpp和其他theCppFile.cpp文件中coolStuff.h中包含的代码,则需要研究构建包。这并不难,但可能有点棘手,因为有关使用Rcpp构建软件包的信息范围从您想要的任何R软件包的详尽彻底的文档(但是作为新手高于您的头脑),以及新手敏感介绍(可能会遗漏一些正好需要的)。

以下是我的建议:

A)首先获取theCppFile.cpp的版本,其中.cpp代码剪切并粘贴到theCppFile.cpp,并使用coolStuff.h进行编译,并按预期工作。这不是必须的,但是如果您不熟悉Rcpp OR软件包,那么在转移到下面更复杂的情况之前,确保您的代码在这种简单的情况下工作是很好的。

B)现在使用theCppFile.cpp构建您的包或使用RStudio中的Build功能(强烈推荐)。您可以在hadley/devtoolsRcpp Attributes Vignette中找到有关使用sourceCpp()的详细信息。使用Rcpp编写软件包的完整文档在Writing a package that uses Rcpp中,但是这个假设您已经很好地了解了C ++,并且没有使用新的&#34;属性&#34;做Rcpp的方式。

别忘了&#34; Build&amp;刷新&#34;如果您不在RStudio中使用RStudio或Rcpp.package.skeleton()

C)现在您应该在\ R目录中看到一个名为Rcpp.package.skeleton()的文件。打开它并检查出来。在compileAttributes()中,您应该看到RcppExports.R目录中所有.cpp文件的R包装函数。很甜蜜。

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

E)建立您的软件包后,您可以\srctheCppFile.cpp移动到coolStuff.h文件夹中。

F)现在你可以从srctheCppFile.cpp的顶部(以及你想使用coolStuff.h中的代码的任何其他.cpp文件)中删除剪切和粘贴代码。在theCppFile.cpp之后theCppFile.cpp。请注意,ranker.h周围没有括号,而是有#34;&#34;。当包含用户提供的本地文件而不是像Rcpp或STL等库文件时,这是一个C ++约定...

G)现在你必须重建包。在RStudio,这只是&#34; Build&amp;刷新&#34;在“生成”菜单中。如果您不使用RStudio,则应运行#include "coolStuff.h"

H)现在再次尝试R功能,就像在步骤D)中那样,希望它能正常工作。

7 个答案:

答案 0 :(得分:20)

问题是sourceCpp明确设计为仅构建一个独立的源文件。如果您希望sourceCpp具有依赖关系,那么它们必须是:

  1. 在系统包含目录(即/usr/local/lib/usr/lib);或

  2. 在您在Rcpp::depends属性

  3. 中列出的R包中

    正如Dirk所说,如果你想构建多个源文件,那么你应该考虑使用R包而不是sourceCpp

    请注意,如果您正在处理包并在包的src目录中的文件上执行sourceCpp,它将构建它就像它在包中一样(即,您可以包含来自src目录或inst / include目录)。

答案 1 :(得分:7)

通过在调用sourceCpp之前设置两个环境变量,我能够链接任何库(在本例中为MPFR):

Sys.setenv("PKG_CXXFLAGS"="-I/usr/include")
Sys.setenv("PKG_LIBS"="-L/usr/lib/x86_64-linux-gnu/ -lm -lmpc -lgmp -lmpfr")

第一个变量包含库头的路径。第二个包括库二进制文件的路径及其文件名。在这种情况下,还需要其他依赖库。有关更多详细信息,请检查g ++编译并链接flags。通常可以使用pkg-config:

获取此信息
pkg-config --cflags --libs mylib

为了更好地理解,我建议使用带有详细输出的sourceCpp来打印g ++编译和链接命令:

sourceCpp("mysource.cpp", verbose=TRUE, rebuild=TRUE)

答案 2 :(得分:4)

在调用sourceCpp

之前,我能够使用R中的以下全局命令链接一个boost库
Sys.setenv("PKG_CXXFLAGS"="-I \path-to-boost\")

基本上镜像这篇文章,但使用不同的编译器选项:http://gallery.rcpp.org/articles/first-steps-with-C++11/

答案 3 :(得分:2)

一些事情:

  1. 在您的主题中使用“第三方标题库”毫无意义。

  2. 第三方标题可以通过模板化代码工作,其中只需要标题,即只有一个包含步骤,编译器会解决问题。

  3. 一旦你需要库和目标代码的实际链接,除非你通过插件(或env.vars)给它提供元信息,否则你可能无法使用强大且有用的sourceCpp

  4. 因此,在这种情况下,请写一个包。

  5. 简单而简单的事情就是使用Rcpp和新属性,或旧的内联和cxxfunction。更多用于复杂用途---外部库 更复杂,您需要查阅文档。为此我们为Rcpp添加了几个小插曲。

答案 4 :(得分:1)

尖括号&lt;&gt;用于系统包括,例如标准库。

对于您自己项目的本地文件,请使用引号:&#34;&#34;。

此外,如果您将标题放在不同的目录中,则应在包含它的源文件的本地指定标题路径。

因此,对于您的示例,这应该有效:

#include "../cppHeaders/coolStuff.h"

您可以配置搜索路径,以便可以在不执行此操作的情况下找到该文件,但对于您希望包含在多个项目中的内容,或者其他人希望有人能够这样做,通常只会这样做。 ;安装&#39;

答案 5 :(得分:1)

我们可以通过将路径写入PKG_CXXFLAGS文件的.R/Makevars变量中的标头来添加它,如下所示。以下是在macOS中添加与Anaconda一起安装的xtensor头文件的示例。

⋊> ~ cat ~/.R/Makevars                                                                                                                              
CC=/usr/local/bin/gcc-7
CXX=/usr/local/bin/g++-7
CPLUS_INCLUDE_PATH=/opt/local/include:$CPLUS_INCLUDE_PATH
PKG_CXXFLAGS=-I/Users/kuroyanagi/.pyenv/versions/miniconda3-4.3.30/include
LD_LIBRARY_PATH=/opt/local/lib:$LD_LIBRARY_PATH
CXXFLAGS= -g0 -O3 -Wall
MAKE=make -j4

答案 6 :(得分:0)

这在Windows中对我有用:

Sys.setenv("PKG_CXXFLAGS"='-I"C:/boost/boost_1_66_0"')

编辑:实际上,如果您使用Boost Headers(感谢Ralf Stubner),则不需要:

// [[Rcpp::depends(BH)]]