我正在尝试制作简单的R命令评估程序。
我有以下代码:
Evaluator.h
void evaluate(const std::string &command);
extern "C" SEXP run_eval() {
evaluate("grDevices:::png(\"snapshot.png\")");
return R_NilValue;
}
Evaluator.cpp
SEXP createSexp(const std::string &str, ScopeProtector *protector) {
SEXP result = Rf_allocVector(STRSXP, 1);
protector->add(result);
SET_STRING_ELT(result, 0, Rf_mkChar(str.c_str()));
return result;
}
SEXP createExpressionSexp(SEXP strSexp, ScopeProtector *protector) {
ParseStatus status;
SEXP result = R_ParseVector(strSexp, 1, &status, R_NilValue);
protector->add(result);
return result;
}
SEXP createExpressionSexp(const std::string &str, ScopeProtector *protector) {
return createExpressionSexp(createSexp(str, protector), protector);
}
SEXP evaluateExpression(SEXP exprSexp, ScopeProtector *protector) {
SEXP result = Rf_eval(exprSexp, R_GlobalEnv);
protector->add(result);
return result;
}
void evaluate(const std::string &command) {
ScopeProtector protector;
evaluateExpression(createExpressionSexp(command, &protector), &protector);
}
ScopeProtector.h
class ScopeProtector: boost::noncopyable {
public:
ScopeProtector();
virtual ~ScopeProtector();
void add(SEXP sexp);
private:
class Impl;
const std::unique_ptr<Impl> pImpl;
};
ScopeProtector.cpp
class ScopeProtector::Impl {
public:
Impl() : count(0) {
}
virtual ~Impl() {
if (count > 0) {
UNPROTECT(count);
}
}
void add(SEXP sexp) {
PROTECT(sexp);
count++;
}
private:
int count;
};
ScopeProtector::ScopeProtector() : pImpl(new Impl) {
}
ScopeProtector::~ScopeProtector() = default;
void ScopeProtector::add(SEXP sexp) {
pImpl->add(sexp);
}
的CMakeLists.txt
cmake_minimum_required(VERSION 3.3)
project(REvaluator)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Werror")
include_directories("/usr/share/R/include")
set(
SOURCE_FILES
Evaluator.cpp Evaluator.h
ScopeProtector.cpp ScopeProtector.h
)
add_library(revaluator SHARED ${SOURCE_FILES})
我正在尝试通过执行以下命令来检查我的评估者:
> dyn.load("librevaluator.so")
> .Call("run_eval")
NULL
> dev.list()
NULL
正如您所看到的,没有任何png设备。你能告诉我这是什么问题吗?
答案 0 :(得分:0)
您是否查看了Rcpp及其Rcpp::Function()
?
R> library(Rcpp)
R> dev.list()
NULL
R> cppFunction('void newDev(std::string filename) {
Rcpp::Function dn = Rcpp::Function("png");
dn(filename); }')
R> newDev("/tmp/foo.png")
R> dev.list()
png
2
R>
我们通常不建议从“C ++中的低位”调用大量R函数,但对于像创建图形设备这样的偶然设置问题,它是完全没问题的。
(请注意,我缩进了代码以适应此处的显示。cppFunction()
是一行;它创建了一个共享库,其中包含在参数中定义的函数并分配它 - 以便新的R调用者我们刚刚创建的newDev
可用于创建png设备。)
答案 1 :(得分:0)
我找到了解决方案。只需替换
SEXP result = Rf_eval(exprSexp, R_GlobalEnv);
与
SEXP result = Rf_eval(VECTOR_ELT(exprSexp, 0), R_GlobalEnv);