从 R 包中的 Rcpp 返回用户定义的结构
Returning a user-defined structure from Rcpp in an R package
Rcpp 功能强大,在大多数情况下都运行良好,但我不知道如何将 returns 用户定义结构的 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();
~~~~~~^
这看起来很简单,但我找不到类似的小插图或示例,而且我尝试过的 none 变体似乎有效。 SourceCpp动态加载报错是什么原因?为什么编译器找不到头文件中的代码?
谢谢!
我让这个工作并post将我的解决方案修改为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( "%ld\n", 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 header 下有模板定义(将初始调用放在 RcppCommon.h 之后,将详细调用放在 Rcpp.h 之后)。教程和示例警告我不要那样做,但我还是照做了。其次,我发现如果您“获取”代码然后然后“加载”库,则获取的代码会掩盖库代码,您将得到一个“空指针”错误。 运行“devtools::check()”向我展示了这一点,同时指出修复是“rm”源函数。
我还要补充一点,我需要将两个 Roxygen 注释添加到我的 .cpp 文件中,以使适当的命令出现在我的 NAMESPACE 文件中:
//' @importFrom Rcpp evalCpp
//' @useDynLib myPackage
我找到了一个旧的 post,其中 Dirk 建议使用 Rcpp.package.skeleton 函数构建一个“婴儿”项目,然后慢慢添加东西,直到您可以做您想做的事。这 so 比我一直使用的方法要好得多:从一个复杂的 C 程序开始,然后尝试将我的代码硬塞进 Rcpp。
Rcpp 功能强大,在大多数情况下都运行良好,但我不知道如何将 returns 用户定义结构的 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();
~~~~~~^
这看起来很简单,但我找不到类似的小插图或示例,而且我尝试过的 none 变体似乎有效。 SourceCpp动态加载报错是什么原因?为什么编译器找不到头文件中的代码?
谢谢!
我让这个工作并post将我的解决方案修改为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( "%ld\n", 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 header 下有模板定义(将初始调用放在 RcppCommon.h 之后,将详细调用放在 Rcpp.h 之后)。教程和示例警告我不要那样做,但我还是照做了。其次,我发现如果您“获取”代码然后然后“加载”库,则获取的代码会掩盖库代码,您将得到一个“空指针”错误。 运行“devtools::check()”向我展示了这一点,同时指出修复是“rm”源函数。
我还要补充一点,我需要将两个 Roxygen 注释添加到我的 .cpp 文件中,以使适当的命令出现在我的 NAMESPACE 文件中: //' @importFrom Rcpp evalCpp //' @useDynLib myPackage
我找到了一个旧的 post,其中 Dirk 建议使用 Rcpp.package.skeleton 函数构建一个“婴儿”项目,然后慢慢添加东西,直到您可以做您想做的事。这 so 比我一直使用的方法要好得多:从一个复杂的 C 程序开始,然后尝试将我的代码硬塞进 Rcpp。