Hello everyone, I have a C++ program that calls R using R_tryEval, very similarly to what package RInside does. It used to work with R.3.4.3 and R.3.4.4. However, since I updated it to R.3.5.1, R sends an error message: "*Error in < My command > : the base graphics system is not registered*" for any command related to the graphics package.
I made a ticket on stackoverflow about it: https://stackoverflow.com/ questions/51242993/difference-between-r-3-4-4-and-r-3-5-1-in-r-api-for-c But nobody could explain why so far. And after reducing my code further, I am now enclined to think this is actually a bug. The code provided in stackOverflow is already reduced, but not minimal yet. Since then, I reduced it further to really ensure that it was not an interference from anything around it. So I removed the GUI and the callbacks. Here is a really minimal example attached. In its current form, the program just sends the command : par("mar") to R, and then the command dev.off() . With R.3.4.4, this program print as output what is expected. No error occured during evaluation of the command : *No error occured during eval of "par(\"mar\")"EXAMPLE #1 Output: EXAMPLE #1 Output: Result is: "5.1"Result is: "5.1"Result is: "5.1"Result is: "5.1"No error occured during eval of "dev.off()"Result is: "1"* But the exact same program with R.3.5.1 gives: *An error occured during eval of "par(\"mar\")"No error occured during eval of "dev.off()"Result is: "1"* The error that occured is not displayed here, since I removed the callbacks to fetch it, but it was: *Error in par("mar") : the base graphics system is not registered* I compiled Microsoft Visual C++ Compiler 15.0 (amd64), and uses 64bits version of R. But previously I also observed the same behovior with 32bits. I also tried re-installing R from scratch, without effect. I am using Windows 10, 64bits Registry variables PATH and R_HOME are correctly set and points to the appropriate version of R, installed in the default directory. I'd be glad to hear any ideas about potential fixes or workaround. Cheers, Andéol Evain
#include <thread> #include <iostream> #include <chrono> #ifdef _WIN32 #include <windows.h> #include <tlhelp32.h> #include <QProcess> #include <cwchar> #endif #include <QDebug> #include <rmanager.h> int main(int argc, char *argv[]) { // R API connection (for minimal version) RManager *rconsole = new RManager(); rconsole->parseEval("par(\"mar\")") ; rconsole->parseEval("dev.off()"); // Calling par open a graphics window, so we just close it before exiting. return 0 ; }
#ifndef RMANAGER_H #define RMANAGER_H #include <QObject> class RManager : public QObject { Q_OBJECT public: explicit RManager(QObject *parent = 0); // R side methods/callbacks int parseEval(const QString & line); // R interface callbacks // Out for minimisation of the issue. }; #endif // RMANAGER_H
#include "rmanager.h" #include <QDebug> #include <locale.h> #include <Rinternals.h> #include <Rembedded.h> #ifndef _WIN32 #include <Rinterface.h> // For Linux. #endif #include <R_ext/RStartup.h> #include <R_ext/Parse.h> #include <R.h> RManager::RManager(QObject *parent) : QObject(parent) { const char *argv[] = {"RConsole"}; int argc = sizeof(argv) / sizeof(argv[0]); setlocale(LC_NUMERIC, "C"); // Required by Rembedded. #ifndef _WIN32 R_SignalHandlers = 0; // Don't let R set up its own signal handlers #endif Rf_initEmbeddedR(argc, (char**)argv); // Assign all callbacks. None in this reduced bug illustration. Rf_endEmbeddedR(0); } /** * @brief RManager::parseEval is the core of this console, sending commands to R. * @param line * @return */ int RManager::parseEval(const QString &line) { ParseStatus status; SEXP cmdSexp, cmdexpr, ret = R_NilValue; int i, errorOccurred, retVal=0; // Convert the command line to SEXP PROTECT(cmdSexp = Rf_allocVector(STRSXP, 1)); SET_STRING_ELT(cmdSexp, 0, Rf_mkChar(line.toLocal8Bit().data())); cmdexpr = PROTECT(R_ParseVector(cmdSexp, -1, &status, R_NilValue)); switch (status){ case PARSE_OK: // In this toy program, that's the only case that occurs. // Loop is needed here as EXPSEXP might be of length > 1 for(i = 0; ((i < Rf_length(cmdexpr)) && (retVal==0)); i++){ PROTECT(ret = R_tryEval(VECTOR_ELT(cmdexpr, i), R_GlobalEnv, &errorOccurred)); if (errorOccurred) { qDebug() << "An error occured during eval of" << line ; retVal = -1; } else { qDebug() << "No error occured during eval of" << line ; printf("EXAMPLE #1 Output: "); for (i=0; i<length(ret); i++){ QString resultAsString ; switch( TYPEOF(ret) ) { case REALSXP: resultAsString = QString::number(REAL(ret)[0]) ; break; case INTSXP: resultAsString = QString::number(INTEGER(ret)[0]) ; break; case STRSXP: resultAsString = QString(CHAR(STRING_ELT(ret, 0))) ; break; default: resultAsString = QString("Can't recognize this data") ; } qDebug() << "Result is: " << resultAsString ; } printf("\n"); UNPROTECT(1); // Clear 'ret' } } break; case PARSE_INCOMPLETE: // need to read another line retVal = 1; break; case PARSE_NULL: Rf_warning(tr("%s: Etat d'analyse de commande : NULL (%d)\n").toStdString().data(), "RPPConsole", status); retVal = -2; break; case PARSE_ERROR: Rf_warning(tr("Erreur d'analyse de la commande : \"%s\"\n").toStdString().data(), line.toStdString().c_str()); retVal = -2; break; case PARSE_EOF: Rf_warning(tr("%s: Etat d'analyse de commande : EOF (%d)\n").toStdString().data(), "RPPConsole", status); break; default: Rf_warning(tr("%s: Etat d'analyse de commande non documenté %d\n").toStdString().data(), "RPPConsole", status); retVal = -2; break; } UNPROTECT(2); return retVal; }
______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel