1

I have used RStudio on Ubuntu 18.04 to create an hello world R package using Rcpp like described here in Rcpp Package Development:

My ~/.R/Makevars contain only the line

CXXFLAGS=-g -O0 -Wall

and during pkg build I can see that these flags are applied.

How can print the current value of an R vector (C++ classes CharacterVector or NumericVector in gdb after hitting a breakpoint?

(gdb) p R_PV(x) (as explained in Writing R Extensions) shows an error (perhaps because the SEXP is wrapped?):

enter image description here

(gdb) whatis x
type = Rcpp::CharacterVector

My debug session:

R -d gdb --vanilla
(gdb) run
library(RcppTestPkg)
# type Strg + X to break into gdb to set a breakpoint
(gdb) break rcpp_hello_world.cpp:8
(gdb) cont
rcpp_hello_world()
Breakpoint 1, rcpp_hello_world () at rcpp_hello_world.cpp:8
8       NumericVector y   = NumericVector::create( 0.0, 1.0 ) ;
(gdb) n
9       List z            = List::create( x, y ) ;
(gdb) n
11      return z ;
(gdb) info locals
x = {<Rcpp::PreserveStorage<Rcpp::Vector<16, Rcpp::PreserveStorage> >> = {
    data = 0x5555562c4360}, <Rcpp::SlotProxyPolicy<Rcpp::Vector<16, Rcpp::PreserveStorage> >> = {<No data fields>}, <Rcpp::AttributeProxyPolicy<Rcpp::Vector<16, Rcpp::PreserveStorage> >> = {<No data fields>}, <Rcpp::NamesProxyPolicy<Rcpp::Vector<16, Rcpp::PreserveStorage> >> = {<No data fields>}, <Rcpp::RObjectMethods<Rcpp::Vector<16, Rcpp::PreserveStorage> >> = {<No data fields>}, <Rcpp::VectorBase<16, true, Rcpp::Vector<16, Rcpp::PreserveStorage> >> = {<Rcpp::traits::expands_to_logical__impl<16>> = {<No data fields>}, <No data fields>}, cache = {
    p = 0x7fffffffba10}}
y = {<Rcpp::PreserveStorage<Rcpp::Vector<14, Rcpp::PreserveStorage> >> = {
    data = 0x5555562c43d0}, <Rcpp::SlotProxyPolicy<Rcpp::Vector<14, Rcpp::PreserveStorage> >> = {<No data fields>}, <Rcpp::AttributeProxyPolicy<Rcpp::Vector<14, Rcpp::PreserveStorage> >> = {<No data fields>}, <Rcpp::NamesProxyPolicy<Rcpp::Vector<14, Rcpp::PreserveStorage> >> = {<No data fields>}, <Rcpp::RObjectMethods<Rcpp::Vector<14, Rcpp::PreserveStorage> >> = {<No data fields>}, <Rcpp::VectorBase<14, true, Rcpp::Vector<14, Rcpp::PreserveStorage> >> = {<Rcpp::traits::expands_to_logical__impl<14>> = {<No data fields>}, <No data fields>}, cache = {
    start = 0x5555562c43f8}}
z = {<Rcpp::PreserveStorage<Rcpp::Vector<19, Rcpp::PreserveStorage> >> = {
    data = 0x5555562c4440}, <Rcpp::SlotProxyPolicy<Rcpp::Vector<19, Rcpp::PreserveStorage> >> = {<No data fields>}, <Rcpp::AttributeProxyPolicy<Rcpp::Vector<19, Rcpp::PreserveStorage> >> = {<No data fields>}, <Rcpp::NamesProxyPolicy<Rcpp::Vector<19, Rcpp::PreserveStorage> >> = {<No data fields>}, <Rcpp::RObjectMethods<Rcpp::Vector<19, Rcpp::PreserveStorage> >> = {<No data fields>}, <Rcpp::VectorBase<19, true, Rcpp::Vector<19, Rcpp::PreserveStorage> >> = {<Rcpp::traits::expands_to_logical__impl<19>> = {<No data fields>}, <No data fields>}, cache = {
    p = 0x7fffffffbab0}}
(gdb) p x
$3 = {<Rcpp::PreserveStorage<Rcpp::Vector<16, Rcpp::PreserveStorage> >> = {
    data = 0x5555562c4360}, <Rcpp::SlotProxyPolicy<Rcpp::Vector<16, Rcpp::PreserveStorage> >> = {<No data fields>}, <Rcpp::AttributeProxyPolicy<Rcpp::Vector<16, Rcpp::PreserveStorage> >> = {<No data fields>}, <Rcpp::NamesProxyPolicy<Rcpp::Vector<16, Rcpp::PreserveStorage> >> = {<No data fields>}, <Rcpp::RObjectMethods<Rcpp::Vector<16, Rcpp::PreserveStorage> >> = {<No data fields>}, <Rcpp::VectorBase<16, true, Rcpp::Vector<16, Rcpp::PreserveStorage> >> = {<Rcpp::traits::expands_to_logical__impl<16>> = {<No data fields>}, <No data fields>}, cache = {
    p = 0x7fffffffba10}}

(gdb) p R_PV(x)
'R_PV' has unknown return type; cast the call to its declared return type

(gdb) p x->data
$5 = (SEXP) 0x5555566d2308
(gdb) p R_PV(x->data)
'R_PV' has unknown return type; cast the call to its declared return type


Edit: Here`s the source code of the function:

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
List rcpp_hello_world() {

    CharacterVector x = CharacterVector::create( "foo", "bar" )  ;
    NumericVector y   = NumericVector::create( 0.0, 1.0 ) ;
    List z            = List::create( x, y ) ;

    return z ;
}
R Yoda
  • 8,358
  • 2
  • 50
  • 87
  • 1
    The R API is for C types defined by R. You are pointing it a C++ type. You have two options: a) convert the C++ type to a `SEXP` via `Rcpp::wrap()`. Or b) point _inside_ the C++ type accessing the `SEXP` it contains. PS Screenshots are mostly frowned-upon at StackOverflow. You could have copied and pasted what you are showing there... – Dirk Eddelbuettel Oct 31 '19 at 23:52
  • Yes, screen shots are bad (just a teaser ;-) The code is the original code as created by RStudio (linked in my first sentence of the question). – R Yoda Nov 01 '19 at 00:08
  • @DirkEddelbuettel `Rcpp::wrap` and `Rcpp::print` fail in `gdb` (not found, eg. when trying `call print(x->data)` or `call Rcpp::wrap(x)`) because the linker optimizes away all unused template instances (`wrap` may also be inlined). How could I use these functions in `gdb` if my code does not use it (is there a Rcpp best practice to debug in `gdb` using these functions)? – R Yoda Nov 08 '19 at 23:52
  • Yes. The debugger only know C code. So it allows you to peek into a SEXP, and/or use the tools you found work with SEXP types. Now use `as<>()` and especially `wrap()` to _create yourself a `SEXP`_. And yes. It may require recompiling, But as they say, "life's a b%tch and then you die". You'll be my hero if you come with better tools at the gdb level. – Dirk Eddelbuettel Nov 09 '19 at 00:09
  • BTW my current **workaround** (as you have mentioned as option b in your first comment): What always seems to work in `gdb` (without recompilation) is using the SEXP inside the C++ type, eg. `call Rf_PrintValue(x->data)`... – R Yoda Nov 09 '19 at 00:19
  • 1
    Precisely. There is a `SEXP` in there, and `Rf_PrintValue` knows how to handle. And now, I am afraid, there is no man left behind the curtain.... – Dirk Eddelbuettel Nov 09 '19 at 00:21
  • 1
    For anyone else who comes here and gets stuck with calling `Rf_PrintValue` in order to see the contents of a NumericVector in gdb (unknown return type) this might help: `call (double) Rf_PrintValue(y.data)` – FXQuantTrader Jan 24 '23 at 11:27
  • @FXQuantTrader I wrote a little helper package for myself to ease debugging: https://github.com/aryoda/R_CppDebugHelper – R Yoda Jan 24 '23 at 13:18

1 Answers1

1

(gdb) p R_PV(x)

In my R source, R_PV is a function returning void. Try this instead:

(gdb) call R_PV(x)

As Dirk Eddelbuettel noted, you still need to pass the right type to R_PV, so perhaps the correct command is:

(gdb) call R_PV(Rcpp::wrap(&x))
Employed Russian
  • 199,314
  • 34
  • 295
  • 362
  • THX, good starting point but I still get `a syntax error in expression...`. Learning the `gdb` syntax and pitfalls is not easy... – R Yoda Nov 01 '19 at 00:12
  • How can I call `wrap` if gdb says: `call Rcpp::wrap(x)` -> `No symbol "wrap" in namespace "Rcpp"`? I also tried using ... `&x`... – R Yoda Nov 01 '19 at 00:26
  • The template function `wrap` is optimized away since it is not used in my example code... See https://stackoverflow.com/a/24958777 – R Yoda Nov 09 '19 at 00:03