从 R 包中的 Rcpp 返回用户定义的结构



Rcpp功能强大,在大多数情况下都运行良好,但是我无法弄清楚如何将返回用户定义结构的C函数包装到R包中。

描述

Package: myPackage
Type: Package
Title: What the Package Does (Title Case)
Version: 0.1.0
Depends: R (>= 4.0.0)
License: GPL-3
Encoding: UTF-8
LazyData: true
RoxygenNote: 7.1.0
Imports:
Rcpp
Suggests: 
knitr,
rmarkdown,
testthat
VignetteBuilder: knitr
LinkingTo: 
Rcpp

命名空间

# Generated by roxygen2: do not edit by hand
importFrom(Rcpp,evalCpp)
export(read_header)
useDynLib(myPackage, .registration = TRUE)

头文件 ("inst/include/myPackage_types.h"(

#include <Rcpp.h>
namespace Rcpp {
typedef struct {
int my_data;
} MY_HEADER_INFO;
template <> SEXP wrap(const MY_HEADER_INFO& x) {
std::vector<std::string> names;
std::vector<SEXP> elements(1);
// do something with the elements and names
names.push_back("my_data");
elements[0] = Rcpp::wrap( x.my_data );
return 0;
};
}

C代码

/*
read_header.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <Rcpp.h>
#include "inst/include/myPackage_types.h"
namespace Rcpp {
// [[Rcpp::export]]
Rcpp::MY_HEADER_INFO read_header() {
Rcpp::MY_HEADER_INFO *header;

header = (Rcpp::MY_HEADER_INFO*)malloc(sizeof(Rcpp::MY_HEADER_INFO));
memset(header, 0, sizeof(Rcpp::MY_HEADER_INFO));

return *header;
}
}

当我获取(即编译(C代码时,我得到以下信息:

Error in dyn.load("/private/var/folders/gl/jvj9b0xn34lgq6_h9370p8q80000gn/T/RtmpYRaBGW/sourceCpp-x86_64-apple-darwin17.0-1.0.4.6/sourcecpp_25a13fe3d7da/sourceCpp_49.so") : 
unable to load shared object ...

当我尝试构建软件包(CMD + Shift + B(时,我得到:

clang++ -mmacosx-version-min=10.13 -std=gnu++11 -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG  -I'/Library/Frameworks/R.framework/Versions/4.0/Resources/library/Rcpp/include' -I/usr/local/include   -fPIC  -Wall -g -O2  -UNDEBUG -Wall -pedantic -g -O0 -fdiagnostics-color=always -c RcppExports.cpp -o RcppExports.o
RcppExports.cpp:9:7: error: no type named 'MY_HEADER_INFO' in namespace 'Rcpp'
Rcpp::MY_HEADER_INFO read_header();
~~~~~~^

这看起来很简单,但我找不到类似的渐晕器或示例,而且我尝试过的任何变体似乎都不起作用。SourceCpp动态加载错误的原因是什么?为什么编译器在头文件中找不到代码?

谢谢!

我得到了这个工作,并将我的解决方案发布到GitHub:git@github.com:markrbower/myPackage.git

关键部分是: inst/include/myPackage_types.h

#include <RcppCommon.h>
namespace Rcpp {
typedef struct {
int my_data;
} MY_HEADER_INFO;
template <> SEXP wrap(const MY_HEADER_INFO& x);

template<> MY_HEADER_INFO* as(SEXP x);
} 

read_header.cpp

/*
read_header.c
*/
#include <stdio.h>
#include <stdlib.h>
#include "../inst/include/myPackage_types.h"
#include <RcppCommon.h>

namespace Rcpp {
template <> SEXP wrap(const MY_HEADER_INFO& x);
}
#include <Rcpp.h>
namespace Rcpp {
template <> SEXP wrap(const MY_HEADER_INFO& x) {
std::vector<std::string> names;
std::vector<SEXP> elements(1);
// do something with the elements and names
names.push_back("my_data");
elements[0] = wrap( x.my_data );

Rcpp::List result(elements.size());
for (size_t i = 0; i < elements.size(); ++i) {
result[i] = elements[i];
}
result.attr("names") = Rcpp::wrap(names);
// result can be return to R as a list   
return( result );
};
}
//' @importFrom Rcpp evalCpp
//' @useDynLib myPackage
//' @export
// [[Rcpp::export]]
Rcpp::MY_HEADER_INFO read_header() {
Rcpp::MY_HEADER_INFO *header = NULL;

printf( "%ldn", sizeof(Rcpp::MY_HEADER_INFO) );

header = (Rcpp::MY_HEADER_INFO*)malloc(sizeof(Rcpp::MY_HEADER_INFO));
memset(header, 0, sizeof(Rcpp::MY_HEADER_INFO));

header->my_data = 10;

return *header;
}

有两个问题。首先,我在错误的 Rcpp 标头下有模板定义(将初始调用放在 RcppCommon.h 之后,将详细调用放在 Rcpp.h 之后(。教程和示例警告我不要这样做,但我还是这样做了。其次,我发现如果你"源"代码,然后"加载"库,源代码将模糊库代码,你会得到一个"空指针"错误。运行"devtools::check(("向我展示了这一点,并指出修复程序是"rm"源函数。

我还要补充一点,我需要将两个 Roxygen 注释添加到我的 .cpp 文件中,以使适当的命令出现在我的 NAMESPACE 文件中: ' @importFrom Rcpp evalCpp ' @useDynLib我的包裹

我找到了一个旧帖子,Dirk建议使用Rcpp.package.skeleton函数来构建一个"baby"项目,然后慢慢添加东西,直到你可以做你想做的事。这比我一直使用的方法要好得多:从一个复杂的C程序开始,并尝试将我的代码硬塞到Rcpp中。

最新更新