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

Reply via email to