31
votes

What is the most productive and quickest way to debug shared objects that are loaded into R, in particular on OS X Mavericks? I'm primarily interested in debugging compiled Rcpp code.

I have read the R externals on debugging compiled code (http://cran.r-project.org/doc/manuals/R-exts.html#Debugging-compiled-code) which favours using gdb, but gdb isn't officially supported on Mavericks. However, it seems that lldb is a viable alternative? I found the most useful resource for working out how to debug compiled code in R from Dirk's response to this post (Thanks Dirk!) (Debugging (line by line) of Rcpp-generated DLL under Windows).

I can successfully debug compiled Rcpp code by following the steps which I outline below explicitly step by step, which other Rcpp novices may find this useful (apologies for the length, but I figure it's better to be clear than to omit and be vague). But this development process is a bit tedious and time consuming.

Questions:

  1. is there a faster and/or easier way to debug compiled Rcpp code, compared to what I do below?

  2. I'm a big fan of Rstudio, and would love to incorporate debugging shared objects created from that IDE, so if anyone knows how to do this, I would be interested to know? Rstudio seems to use attributes, and it appears that step 4 below needs modification, because there doesn't seem to be a .cpp file in the temporary directory after compiling (in my example below, there is no "file5156292c0b48.cpp" file)

The steps:

1) (One off) Go to the directory ~/.R (a hidden directory with the .). Create a new file called "Makevars" and in it add the line CXXFLAGS=-g -O0 -Wall.

2) In the terminal, type R -d lldb to launch R. lldb will now start.

3) Type run at the lldb command line. This will start R.

4) Compile the Rcpp code and find the location of the compiled objects. Dirk's response to the above mentioned post shows one way to do this. Here is an example I'll use here. Run the following commands in R:

library(inline)

fun <- cxxfunction(signature(), plugin="Rcpp", verbose=TRUE, body='
int theAnswer = 1;
int theAnswer2 = 2;
int theAnswer3 = 3;
double theAnswer4 = 4.5;
return wrap(theAnswer4);
')

This creates a compiled shared object and other files which can be found by running setwd(tempdir()) and list.files() in R. There will be a .cpp file, like "file5156292c0b48.cpp" and .so file like "file5156292c0b48.so"

5) Load the shared object into R by running dyn.load("file5156292c0b48.so") at the R command line

6) Now we want to debug the C++ code in this .so object. Go back to lldb by hitting ctrl + c. Now I want to set a break point at a specific line in the file5156292c0b48.cpp file. I find the correct line number by opening another terminal and looking at the line number of interest in file5156292c0b48.cpp. Say it's line 31, which corresponds to the line int theAnswer = 1; above in my example. I then type at the lldb command line: breakpoint set -f file5156292c0b48.cpp -l 31. The debugger prints back that a break point has been set and some other stuff...

7) Go back to R by running cont in lldb (the R prompt doesn't automatically appear for me until I hit enter) and call the function. Run fun() at the R command line. Now I am debugging the shared object (hit n to go to next line, p [object name] to print variables etc)....

2
Is this a followup to a question that appeared on R-SIG-Mac in the last day or two?IRTFM
@Clay I don't see how this is not a duplicate to what I wrote in the answer you link to -- beyond the obvious s/gdb/lldb/. Am I missing anything? [ No, RStudio does not include a C/C++-level debugger. ]Dirk Eddelbuettel
I wrote a blog post about how to step through and debug Rcpp using Xcode. It's mostly a rip-off of Brian Hall's article, Linking Xcode, C++ and R to create plots, but with more visual instructions.Ben
This youtube video right on this topic by Jim hester might be useful to some readers: youtube.com/watch?v=R3-IMGyNJY4FXQuantTrader
The Hester video looks extremely useful, but I get this error when I attempt to restart after R -d lldb - LaunchServices returned a bundle URL that does not match with the LoginItem's known association. I'm using Rstudio 1.4.1717, R version 4.1.0 on a MacBook pro with MacOS Big Sur version 11.6JerryN

2 Answers

11
votes

To debug simple Rcpp scripts like this, one thing you can do is create a .cpp application (with a main) that embeds R. This way you can debug it directly with Xcode which will give you a good debugging experience.

It gets more complicate when you start to want to debug packages.

4
votes

This is tough. I tried Xcode and Eclipse with a standalone C++ application, but it was so difficult to get all the headers and libraries working. Furthermore, the RcppExport code calls your real R function through a pointer which seemed to really confuse Xcode, and I couldn't step into my function.

I ended up with (gdb or lldb): In R: R -d lldb In debugger, set breakpoint: b functionName run In R: .Call(etc) # or just call your R code which invokes compiled C/C++ code Then back in debugger once break happens, you can step, examine frames, etc.

This lldb/gdb command quick reference helped a lot.

Forget about trying to do this in a GUI at this point. Hopefully Rstudio will get this going.