Recientemente he estado experimentando con Rcpp (en línea) para generar archivos DLL que realizan varias tareas en las entradas R suministradas. Me gustaría poder depurar el código en estas DLL línea por línea, dado un conjunto específico de entradas R. (estoy trabajando en Windows.)Depuración (línea por línea) de DLL generada por Rcpp en Windows
Para ilustrar, vamos a considerar un ejemplo específico que cualquier persona debería ser capaz de ejecutar ...
El código siguiente es un cxxfunction muy simple, que simplemente se duplica el vector de entrada . Sin embargo, tenga en cuenta que hay una variable adicional myvar
que cambia el valor varias veces pero que no afecta la salida; esto se ha agregado para que podamos ver cuándo el proceso de depuración se está ejecutando correctamente.
library(inline)
library(Rcpp)
f0 <- cxxfunction(signature(a="numeric"), plugin="Rcpp", body='
Rcpp::NumericVector xa(a);
int myvar = 19;
int na = xa.size();
myvar = 27;
Rcpp::NumericVector out1(na);
for(int i=0; i < na; i++) {
out1[i] = 2*xa[i];
myvar++;
}
myvar = 101;
return(Rcpp::List::create(_["out1"] = out1));
')
Después corremos el anterior, escribiendo el comando
getLoadedDLLs()
resultado será una lista de archivos DLL en la sesión R. El último de la lista debe ser el DLL creado por el proceso anterior - tiene un nombre temporal al azar, que en mi caso es
file7e61645c
la columna "Nombre" muestra que cxxfunction ha puesto este DLL en la ubicación tempdir()
, que para mí es actualmente
C:/Users/TimP/AppData/Local/Temp/RtmpXuxtpa/file7e61645c.dll
Ahora, la manera obvia de llamar a la DLL es a través de f0
, de la siguiente manera
> f0(c(-7,0.7,77))
$out1
[1] -14.0 1.4 154.0
Pero podemos, por supuesto, También llamar a la DLL directamente por su nombre usando el comando .Call
:
> .Call("file7e61645c",c(-7,0.7,77))
$out1
[1] -14.0 1.4 154.0
Así que he llegado al punto en el que estoy llamando a una DLL independiente directamente con la entrada R (en este caso, el vector c(-7,0.7,77)
), y hacer que el retorno la respuesta correcta a R.
lo que realmente necesito, sin embargo, es una instalación para la línea por línea depuración (usando gDB, creo) que me permitirá observar el valor de myvar
se establece en 19, 27, 28, 29, 30 y finalmente 101 a medida que el código progresa. El ejemplo anterior se ha configurado deliberadamente para que llamar al DLL no nos diga nada sobre myvar.
Para aclarar, la "condición de victoria" aquí es poder observar el cambio de myvar (ver el valor myvar = 19 sería el primer paso) sin agregar nada más al cuerpo del código. Obviamente, esto puede requerir cambios en la forma en que se compila el código (¿hay alguna configuración de modo de depuración para encender?), O la forma en que se llama R, pero no sé por dónde empezar. Como se señaló anteriormente, todo esto está basado en Windows.
Nota final: en realidad, realicé algunas modificaciones menores en una copia de cxxfunction para que la DLL de salida (y el código que contiene) reciba un nombre definido por el usuario y se encuentre en un directorio definido por el usuario, que un nombre temporal y una ubicación. Pero esto no afecta la esencia de la pregunta.Menciono esto solo para enfatizar que debería ser bastante fácil alterar la configuración de compilación si alguien me da un codazo :)
Para completar, el ajuste verbose = TRUE en la llamada cxxfunction original anterior muestra el argumento de compilación para ser del siguiente forma:
C:/R/R-2.13.2/bin/i386/R CMD SHLIB file7e61645c.cpp 2> file7e61645c.cpp.err.txt
g++ -I"C:/R/R-213~1.2/include" -I"C:/R/R-2.13.2/library/Rcpp/include" -O2 -Wall -c file7e61645c.cpp -o file7e61645c.o
g++ -shared -s -static-libgcc -o file7e61645c.dll tmp.def file7e61645c.o C:/R/R-2.13.2/library/Rcpp/lib/i386/libRcpp.a -LC:/R/R-213~1.2/bin/i386 -lR
Mi versión adaptada tiene un argumento compilación idéntica a la anterior, excepto que la cadena "file7e61645c" se sustituye por todas partes por la elección del usuario del nombre (por ejemplo, "testdll") los archivos y la pertinentes copian a una ubicación más permanente.
Gracias de antemano por su ayuda chicos :)
No puedo ayudarlo directamente, pero sé que Dirk, etc. siempre me ayuda. Sin embargo, generalmente hacen negocios en la [lista de correo electrónico de Rcpp] (http://lists.r-forge.r-project.org/mailman/listinfo/rcpp-devel) –
Han hecho un progreso leve en esto, por lo que una breve actualización . Jugando con inline ::: compileCode, que se llama dentro de la función cxx, encontré que agregar '--debug' al final de' R CMD SHLIB' me permitió examinar lo que está pasando dentro de la DLL mediante la combinación de gdb y R. SIN EMBARGO , esta no es una solución completa ya que algunas variables eran inaccesibles (como 'i', durante el ciclo sobre' i'); surgió el mensaje de que habían sido "optimizados". Creo que, por lo tanto, necesito reemplazar el "-O2" con "-O0" en el argumento de compilación ... pero no tengo idea de cómo hacer que esto suceda ... –
He reunido una buena cantidad de evidencia de que todo lo que tengo que hacer es cambiar los indicadores del compilador R CMD SHLIB de -O2 a algo así como -g -O0 ... por ejemplo ver la publicación en https://stat.ethz.ch/pipermail/r-devel/2008-November/051390.html - pero me falta una declaración precisa de lo que debe especificarse y cómo. Algunas fuentes en línea mencionan la creación de un archivo en '/.R/Makevars.win' pero no describen el archivo, y esta no es una ubicación válida en Windows debido al punto antes de la letra R ... –