R de C — Helloworld más simple posible

6 minutos de lectura

avatar de usuario
jsight

¿Cuál es la función de C más simple posible para iniciar el intérprete de R, pasar una expresión pequeña (por ejemplo, 2+2) y obtener el resultado? Estoy tratando de compilar con MingW en Windows.

  • buen punto… aclarado.

    – jsight

    17 de marzo de 2010 a las 15:39

avatar de usuario
Shane

¿Quieres llamar a R desde C?

Mirar sección 8.1 en las Extensiones de Escritura R manual. También debe buscar en el directorio de “pruebas” (descargue el paquete fuente, extráigalo y tendrá el directorio de pruebas). Anteriormente se hizo una pregunta similar en R-Help y aquí estaba el ejemplo:

#include <Rinternals.h> 
#include <Rembedded.h> 

SEXP hello() { 
  return mkString("Hello, world!\n"); 
} 

int main(int argc, char **argv) { 
  SEXP x; 
  Rf_initEmbeddedR(argc, argv); 
  x = hello(); 
  return x == NULL;             /* i.e. 0 on success */ 
} 

El ejemplo simple del manual R es así:

 #include <Rembedded.h>

 int main(int ac, char **av)
 {
     /* do some setup */
     Rf_initEmbeddedR(argc, argv);
     /* do some more setup */

     /* submit some code to R, which is done interactively via
         run_Rmainloop();

         A possible substitute for a pseudo-console is

         R_ReplDLLinit();
         while(R_ReplDLLdo1() > 0) {
           add user actions here if desired
         }
      */
     Rf_endEmbeddedR(0);
     /* final tidying up after R is shutdown */
     return 0;
 }

Por cierto, es posible que desee considerar el uso de Rinde en cambio: Dirk proporciona un buen ejemplo de “hola mundo” en la página de inicio del proyecto.

Si está interesado en llamar a C desde R, aquí está mi respuesta original:

Esto no es exactamente “hola mundo”, pero aquí hay algunos buenos recursos:

  • Muchas gracias… Me faltaban las llamadas a la función R init… oops. Los ejemplos tuyos (y de otros) han sido de gran ayuda (lástima que no pueda dar respuestas aceptadas a algunos otros también… :)).

    – jsight

    17 de marzo de 2010 a las 21:20

Aqui tienes. Es la función principal, pero debería poder adaptarla a una función de propósito más general. Este ejemplo genera una expresión R a partir de llamadas C y también de una cadena C. Usted está solo para compilar en Windows, pero proporcioné pasos de compilación en Linux:

 /* simple.c */
 #include <Rinternals.h>
 #include <Rembedded.h>
 #include <R_ext/Parse.h>
 int
 main(int argc, char *argv[])
 {
    char *localArgs[] = {"R", "--no-save","--silent"};
    SEXP e, tmp, ret;
    ParseStatus status;
    int i;

    Rf_initEmbeddedR(3, localArgs);

    /* EXAMPLE #1 */

    /* Create the R expressions "rnorm(10)" with the R API.*/
    PROTECT(e = allocVector(LANGSXP, 2));
    tmp = findFun(install("rnorm"), R_GlobalEnv);
    SETCAR(e, tmp);
    SETCADR(e, ScalarInteger(10));

    /* Call it, and store the result in ret */
    PROTECT(ret = R_tryEval(e, R_GlobalEnv, NULL));

    /* Print out ret */
    printf("EXAMPLE #1 Output: ");
    for (i=0; i<length(ret); i++){
        printf("%f ",REAL(ret)[i]);
    }
    printf("\n");

    UNPROTECT(2);


    /* EXAMPLE 2*/

    /* Parse and eval the R expression "rnorm(10)" from a string */
    PROTECT(tmp = mkString("rnorm(10)"));
    PROTECT(e = R_ParseVector(tmp, -1, &status, R_NilValue));
    PROTECT(ret = R_tryEval(VECTOR_ELT(e,0), R_GlobalEnv, NULL));

    /* And print. */
    printf("EXAMPLE #2 Output: ");
    for (i=0; i<length(ret); i++){
        printf("%f ",REAL(ret)[i]);
    }
    printf("\n");

    UNPROTECT(3);
    Rf_endEmbeddedR(0);
    return(0);
 }

Compilar pasos:

$ gcc -I/usr/share/R/include/ -c -ggdb simple.c
$ gcc -o simple simple.o  -L/usr/lib/R/lib -lR
$ LD_LIBRARY_PATH=/usr/lib/R/lib R_HOME=/usr/lib/R ./simple
EXAMPLE #1 Output: 0.164351 -0.052308 -1.102335 -0.924609 -0.649887 0.605908 0.130604 0.243198 -2.489826 1.353731
EXAMPLE #2 Output: -1.532387 -1.126142 -0.330926 0.672688 -1.150783 -0.848974 1.617413 -0.086969 -1.334659 -0.313699

  • ¿Se puede compilar bajo VS2008 (MS Compiler)? ¿Cuáles son los argumentos?

    – sergey

    31 de mayo de 2012 a las 5:22

No creo que ninguno de los anteriores haya respondido la pregunta, que era evaluar 2 + 2;). Para usar una expresión de cadena sería algo como:

#include <Rinternals.h>
#include <R_ext/Parse.h>
#include <Rembedded.h>

int main(int argc, char **argv) {
    SEXP x;
    ParseStatus status;
    const char* expr = "2 + 2";

    Rf_initEmbeddedR(argc, argv);

    x = R_ParseVector(mkString(expr), 1, &status, R_NilValue);
    if (TYPEOF(x) == EXPRSXP) { /* parse returns an expr vector, you want the first */
        x = eval(VECTOR_ELT(x, 0), R_GlobalEnv);
        PrintValue(x);
    }

    Rf_endEmbeddedR(0);

    return 0;
}

Esto carece de comprobación de errores, obviamente, pero funciona:

Z:\>gcc -o e.exe e.c -IC:/PROGRA~1/R/R-213~1.0/include -LC:/PROGRA~1/R/R-213~1.0/bin/i386 -lR
Z:\>R CMD e.exe
[1] 4

(Para obtener los comandos adecuados para su uso R R CMD SHLIB e.c que le da las banderas relevantes del compilador)

También puede construir la expresión a mano si es lo suficientemente simple, por ejemplo, para rnorm(10) usarías

SEXP rnorm = install("rnorm");
SEXP x = eval(lang2(rnorm, ScalarInteger(10)), R_GlobalEnv);

  • ¿Se puede compilar bajo Visual Studio (compilador de MS)? ¿Cuáles son los parámetros?

    – sergey

    31 de mayo de 2012 a las 5:24

  • No, VC no es compatible oficialmente, el compilador nativo es MinGW. Puede haber formas de combinar el código VC con R (por ejemplo, a través de archivos DLL), pero no se garantiza que funcione.

    – Simón Urbanek

    5 de junio de 2012 a las 23:49

  • Compilé el código en Visual Studio (MS Compiler) :). Para hacerlo, la biblioteca R.lib debe crearse manualmente.

    – sergey

    28 de junio de 2012 a las 18:13

avatar de usuario
dirk eddelbuettel

Creo que no puedes hacerlo mucho mejor que el en línea paquete (que admite C, C++ y Fortran):

library(inline)
fun <- cfunction(signature(x="ANY"), 
                 body='printf("Hello, world\\n"); return R_NilValue;')
res <- fun(NULL)

que imprimirá ‘Hello, World’ para usted. Y ni siquiera sabe dónde/cómo/cuándo se invocan el compilador y el enlazador. [ The R_NilValue is R’s NULL version of a SEXP and the .Call() signature used here requires that you return a SEXP — see the ‘Writing R Extensions’ manual which you can’t really avoid here. ]

Luego tomará dicho código y lo envolverá en un paquete. Tuvimos un gran éxito con el uso
en línea Para el
Rcpp pruebas unitarias (más de 200 y contando ahora) y algunos de los ejemplos.

Ah, y esto en línea ejemplo funcionará en cualquier sistema operativo. Incluso Windoze siempre que tenga instalada la cadena de herramientas de creación de paquetes R, en PATH, etc.

Editar: Leí mal la pregunta. Lo que quieres es esencialmente lo que el más pequeño front-end hace (usando C puro) y lo que el RInterior Clases eliminadas para C++.

Jeff y yo nunca nos molestamos en portar más pequeño a Windoze, pero RInterior funcionó allí en la versión más reciente. Por lo tanto, debería poder hurgar en las recetas de compilación y crear una variante solo C de RInterior para que pueda alimentar la expresión a un proceso R incrustado. Sospecho que todavía quieres algo como Rcpp para la pista, ya que de lo contrario se vuelve tedioso.

Edición 2: Y como menciona Shane, de hecho hay algunos ejemplos en las fuentes de R en testing/Embedding/ junto con Makefile.win. Tal vez ese sea el comienzo más simple si está dispuesto a aprender sobre las funciones internas de R.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad