从C评估R命令不起作用

  • 本文关键字:命令 不起作用 评估 r
  • 更新时间 :
  • 英文 :


我正在尝试制作一个简单的R命令计算器。

我有以下代码:

评估员.h

void evaluate(const std::string &command);
extern "C" SEXP run_eval() {
  evaluate("grDevices:::png("snapshot.png")");
  return R_NilValue;
}

评估员.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设备。你能告诉我出了什么问题吗?

您看过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设备。)

我找到了解决方案。只需更换

SEXP result = Rf_eval(exprSexp, R_GlobalEnv);

带有

SEXP result = Rf_eval(VECTOR_ELT(exprSexp, 0), R_GlobalEnv);

最新更新