如何在 Windows 中调试(逐行)Rcpp 生成的代码? [英] How to debug (line-by-line) Rcpp generated code in Windows?

查看:39
本文介绍了如何在 Windows 中调试(逐行)Rcpp 生成的代码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在运行时调试 Rcpp 编译后的代码.很长一段时间以来,我一直试图让它无法成功地工作.这里问了一个非常相似的问题:调试(逐行line) of Rcpp-generated DLL under Windows 它提出了同样的问题,但问题和答案都远远超出了我的理解.

这是我所拥有的:

Windows 7 Pro SP13.5带有 Rcpp 的 Rstudio 1.1.463.Rstudio 的 Rbuild 工具.(c++ 编译器)

程序:在 Rstudio File->New File->C++ File(创建一个带有 timesTwo 函数的示例文件.)

我在这个文件中添加了一个新函数:

//[[Rcpp::export]]NumericVector timesTwo2(NumericVector x) {for(int ii = 0; ii <= x.size(); ii++){x.at(ii) = x.at(ii) * 2;}返回 x;}

我在保存时检查了源文件并将文件保存为 RcppTest.cpp,它成功地获取或编译了文件.

在 Rstudio 中运行代码:

data = c(1:10)数据[1] 1 2 3 4 5 6 7 8 9 10timesTwo2(数据)timesTwo2(data) 中的错误:索引越界:[index=10;范围=10].

错误是因为在 for 循环中是 <= x.size() 所以结果是一个运行时错误.

问题是如何获得有关此错误的调​​试输出,合理地告诉我发生了什么?至少我想知道触发异常的代码行以及使用哪些参数.此外,我真的很想在异常之前逐行执行代码,以便我可以准确地监控正在发生的事情.

我可以安装任何其他程序或应用任何其他设置,只要我能找到有关如何操作的准确详细信息.现在我从头开始只是为了让它工作.谢谢.

更新:我找到了这个网站:使用 gdb 调试 Rcpp c++​​ 代码我用 gdb

安装了最新的 gcc 8.1

我在位于 C:\Program Files\R\R-3.5.1\etc\x64makeconf 文件中找到了 CXXFLAGS>然后我按照建议启动了 Rgui,但是当我尝试 Rcpp::sourceCpp 时出现错误:

<代码>>图书馆(Rcpp)>Rcpp::sourceCpp('Rcpptest.cpp')C:/PROGRA~1/R/R-35~1.1/etc/x64/Makeconf:230: 警告:覆盖目标.m.o"的配方C:/PROGRA~1/R/R-35~1.1/etc/x64/Makeconf:223: 警告:忽略目标 '.m.o' 的旧配方c:/Rtools/mingw_64/bin/g++ -I"C:/PROGRA~1/R/R-35~1.1/include" -DNDEBUG -I"C:/Users/Michael/Documents/R/win-library/3.5/Rcpp/include" -I"C:/PROGRA~1/R/R-35~1.1/bin/x64" -ggdb -O0 -Wall -gdwarf-2 -mtune=generic -c Rcpptest.cpp -o Rcpptest.oprocess_begin: CreateProcess(NULL, c:/Rtools/mingw_64/bin/g++ -IC:/PROGRA~1/R/R-35~1.1/include -DNDEBUG -IC:/Users/Michael/Documents/R/win-library/3.5/Rcpp/include -IC:/PROGRA~1/R/R-35~1.1/bin/x64 -ggdb -O0 -Wall -gdwarf-2 -mtune=generic -c Rcpptest.cpp -o Rcpptest.o,...) 失败的.make (e=2):系统找不到指定的文件.make: *** [C:/PROGRA~1/R/R-35~1.1/etc/x64/Makeconf:215: Rcpptest.o] 错误 2Rcpp::sourceCpp("Rcpptest.cpp") 中的错误:构建共享库时发生错误 1.警告:未找到为 R 构建 C++ 代码所需的工具.请下载并安装相应版本的 Rtools:http://cran.r-project.org/bin/windows/Rtools/

看起来它正在加载新的CXXFLAGS并且它正在使用DEBUG,但它似乎仍然无法编译.有人知道错误的原因吗?

我尝试以与 Rgui 相同的方式运行 Rstudio,它开始时 gdb 窗口中显示了许多线程,但 Rstudio 中的所有内容都与以前完全一样运行,没有额外的调试来自 Rstudio 或 gdb 的信息.

更新 2:由于上面的错误指出 Rgui 没有用于编译的 Rtools,所以我从提供链接安装了 Rtools.它安装在 C:\Rtools 中,而 Rstudio 安装在 C:\RBuildTools 中.所以我现在有 3 个编译器,Rtools、RbuildTools 和带有 gdbgcc.它现在可以编译,但仍然出现与我在 Rstudio 中所做的相同的错误.我想至少获得更好的错误输出,例如传递的行和值.指令说 Rgui 应该有一个断点位置,但我找不到这样的选项.

更新 3我终于能够设置并运行 Linux 安装(Ubuntu 16.04.05).首先是我的CXXFLAGS:

$ R CMD config CXXFLAGS-g -O0 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g

我必须在我的主目录中创建一个 .R 文件夹,并在其中创建一个 Makevar 文件

CXXFLAGS = -g -O0 -Wall -pedantic -fstack-protector-strong -D_FORTIFY_SOURCE=2

仅此一项就花费了数小时,因为它实际上并没有说制作文件夹和文件.

然后我在断点处执行了 Ralf 发布的命令:

<代码>>timesTwo2(d1)线程 1 "R" 在 RcppTest.cpp:19 处击中断点 1, timesTwo2 (x=...)19 NumericVector timesTwo2(NumericVector x) {(gdb) n20 for (int ii = 0; ii <= x.size(); ii++)(gdb) n22 x.at(ii) = x.at(ii) * 2;(gdb) 显示 ii1: ii = 0(gdb) n20 for (int ii = 0; ii <= x.size(); ii++)1: ii = 0(gdb) n22 x.at(ii) = x.at(ii) * 2;1: ii = 1(gdb) n20 for (int ii = 0; ii <= x.size(); ii++)1: ii = 1(gdb) 显示 x.at(ii)2:x.at(ii) = <错误:尝试获取不在内存中的值的地址.>(gdb) n22 x.at(ii) = x.at(ii) * 2;1: ii = 22:x.at(ii) = <错误:尝试获取不在内存中的值的地址.>(gdb)

最后在 n = 10 处:

1: ii = 102:x.at(ii) = <错误:尝试获取不在内存中的值的地址.>(gdb) n来自/usr/lib/R/lib/libR.so 的 Rf_applyClosure () 中的 0x00007ffff792d762(gdb)

这绝对是我调试最远的地方,但这是一个非常基本的功能,调试输出甚至错误输出都不是很有用.它给了我它正在执行的行,它可以显示 ii,但我无法显示数组值或整个数组.是否可以创建一个更具体的断点,使其仅在 ii == 10 时中断?理想情况下,我希望在 Rstudio 或其他一些可以显示整个矢量的 GUI 中使用它.仍在进行更多测试.

解决方案

通常的方法 R -d gdb,我也在下面的原始答案中建议,不适用于 Windows:><块引用>

--调试器=名称
-d 名称

(仅限 UNIX)通过调试器名称运行 R.对于大多数调试器(valgrind 和最新版本的 gdb 除外),更多的命令行选项被忽略,而应该在从调试器内部启动 R 可执行文件时提供.

https://cran.r-project.org/doc/manuals/r-release/R-intro.html#Invoking-R-from-the-command-line

替代方案:

  1. 在调试器中启动 R:gdb.exe Rgui.exe
  2. 设置断点:break TimesTwo2
  3. 运行 R:run
  4. 源文件:Rcpp::sourceCpp("debug.cpp")
  5. 使用nextprintdisplay来单步执行代码.

第 1 步的替代方法是启动 R,使用 Sys.getpid() 获取 PID,使用 gdb -p 附加调试器.您将不得不使用 continue 而不是 run.

<小时>

我现在没有 Windows 机器,所以以下是在 Linux 上完成的.不过,我希望它是可以转让的.让我们从一个包含您的代码的简单 cpp 文件(在我的例子中为 debug.cpp)开始:

#include 使用 Rcpp::NumericVector;//[[Rcpp::export]]NumericVector timesTwo2(NumericVector x) {for(int ii = 0; ii <= x.size(); ii++){x.at(ii) = x.at(ii) * 2;}返回 x;}/*** R数据 = c(1:10)数据timesTwo2(数据)*/

我可以通过在命令行上调用 R 来重现错误:

$ R -e "Rcpp::sourceCpp('debug.cpp')"R version 3.5.1 (2018-07-02)——羽毛喷雾"[...]>Rcpp::sourceCpp('debug.cpp')>数据 = c(1:10)>数据[1] 1 2 3 4 5 6 7 8 9 10>timesTwo2(数据)timesTwo2(data) 中的错误:索引越界:[index=10;范围=10].电话:<匿名>... 来源 ->withVisible ->评估 ->评估 ->timesTwo2 ->.称呼执行停止

接下来我们可以使用 gdb 作为调试器来启动 R(参见 Dirk 所说的编写 R 扩展):

$ R -d gdb -e "Rcpp::sourceCpp('debug.cpp')"GNU gdb (Debian 8.2-1) 8.2[...](gdb) 休息时间Two2未定义函数timesTwo2".在未来的共享库加载时使断点挂起?(y 或 [n]) y断点 1 (timesTwo2) 待处理.(gdb) 运行[...]>Rcpp::sourceCpp('debug.cpp')[线程 0xb40d3b40 (LWP 31793) 退出][从子进程 31795 分叉后分离]>数据 = c(1:10)>数据[1] 1 2 3 4 5 6 7 8 9 10>timesTwo2(数据)线程 1 "R" 在 timesTwo2(Rcpp::Vector<14, Rcpp::PreserveStorage>)@plt () 中击中断点 1, 0xb34f3310来自/tmp/RtmphgrjLg/sourceCpp-i686-pc-linux-gnu-1.0.0/sourcecpp_7c2d7f56744b/sourceCpp_2.so(gdb)

此时,您可以使用 next(或仅使用 n)单步执行程序并使用 print(或仅使用 n)输出变量代码>p).一个有用的命令也是 display:

线程 1 "R" 在 debug.cpp:5 处击中断点 1, timesTwo2 (x=...)5 NumericVector timesTwo2(NumericVector x) {(gdb) n6 for(int ii = 0; ii <= x.size(); ii++)(gdb) n8 x.at(ii) = x.at(ii) * 2;(gdb) 显示 ii2: ii = 0(gdb) n8 x.at(ii) = x.at(ii) * 2;2: ii = 0[...]2: ii = 9(gdb)46 内联代理 ref(R_xlen_t i) { return start[i] ;}2: ii = 9(gdb)6 for(int ii = 0; ii <= x.size(); ii++)2: ii = 10(gdb)8 x.at(ii) = x.at(ii) * 2;2: ii = 10(gdb)timesTwo2(data) 中的错误:索引越界:[index=10;范围=10].电话:<匿名>... 来源 ->withVisible ->评估 ->评估 ->timesTwo2 ->.称呼执行停止[从子进程 32698 分叉后分离][劣质 1(进程 32654)以代码 01 退出]

顺便说一句,我使用了以下编译标志:

$ R CMD config CXXFLAGS-g -O2 -Wall -pedantic -fstack-protector-strong -D_FORTIFY_SOURCE=2

您可能想切换到 -O0.

I am trying to debug Rcpp compiled code at run-time. I have been trying to get this to work unsuccessfully, for a very long time. A very similar question was asked here: Debugging (line by line) of Rcpp-generated DLL under Windows which asks the same question, but both the question and the answer are far beyond my understanding.

Here is what I have:

Windows 7 Pro SP1
R 3.5
Rstudio 1.1.463 with Rcpp.
Rbuild Tools from Rstudio. (c++ compiler)

Procedure: In Rstudio File->New File->C++ File (creates a sample file with a timesTwo function.)

I added a new function in this file:

// [[Rcpp::export]]
NumericVector timesTwo2(NumericVector x) {
  for(int ii = 0; ii <= x.size(); ii++)
  {
    x.at(ii) = x.at(ii) * 2;
  }
  return x;
}

I checked Source on Save and saved the file as RcppTest.cpp which sources or complies the file successfully.

Run code in Rstudio:

data = c(1:10)
data
[1]  1  2  3  4  5  6  7  8  9 10
timesTwo2(data)
Error in timesTwo2(data) : Index out of bounds: [index=10; extent=10].

The error is because in the for loop is <= x.size() so the result is a run-time error.

The question is how can get a debug output about this error that reasonably tells me what happened? At the very least I would like to know the line in the code that triggered the exception and with which parameters. Furthermore, I would really like to execute the code line-by-line to just before the exception so I can monitor exactly what is happening.

I can install any additional programs or apply any other settings as long as I can find precise details on how to do it. For now I am starting from scratch just to get it working. Thank you.

Update: I found this site: Debugging Rcpp c++ code using gdb I installed the latest gcc 8.1 with gdb

I found the CXXFLAGS in the makeconf file located in C:\Program Files\R\R-3.5.1\etc\x64 Then I started the Rgui as suggested, but when I try Rcpp:::sourceCpp I get an error:

> library(Rcpp)
> Rcpp::sourceCpp('Rcpptest.cpp')
C:/PROGRA~1/R/R-35~1.1/etc/x64/Makeconf:230: warning: overriding recipe for target '.m.o'
C:/PROGRA~1/R/R-35~1.1/etc/x64/Makeconf:223: warning: ignoring old recipe for target '.m.o'
c:/Rtools/mingw_64/bin/g++  -I"C:/PROGRA~1/R/R-35~1.1/include" -DNDEBUG   -I"C:/Users/Michael/Documents/R/win-library/3.5/Rcpp/include" -I"C:/PROGRA~1/R/R-35~1.1/bin/x64"        -ggdb -O0 -Wall -gdwarf-2 -mtune=generic -c Rcpptest.cpp -o Rcpptest.o
process_begin: CreateProcess(NULL, c:/Rtools/mingw_64/bin/g++ -IC:/PROGRA~1/R/R-35~1.1/include -DNDEBUG -IC:/Users/Michael/Documents/R/win-library/3.5/Rcpp/include -IC:/PROGRA~1/R/R-35~1.1/bin/x64 -ggdb -O0 -Wall -gdwarf-2 -mtune=generic -c Rcpptest.cpp -o Rcpptest.o, ...) failed.
make (e=2): The system cannot find the file specified.

make: *** [C:/PROGRA~1/R/R-35~1.1/etc/x64/Makeconf:215: Rcpptest.o] Error 2
Error in Rcpp::sourceCpp("Rcpptest.cpp") : 
  Error 1 occurred building shared library.

WARNING: The tools required to build C++ code for R were not found.

Please download and install the appropriate version of Rtools:

http://cran.r-project.org/bin/windows/Rtools/

It looks like it is loading the new CXXFLAGS and it is using DEBUG, but it seems that it still cannot compile. Anybody know why from the error?

I tried running Rstudio the same way as Rgui and it started with many threads showing in the gdb window, but everything in Rstudio ran exactly as before with no additional debug information from Rstudio or gdb.

Update 2: As the error above states that Rgui did not have Rtools for compiling so I installed the Rtools from the provide link. It installed in C:\Rtools while Rstudio installed in C:\RBuildTools. So I now have 3 compilers, Rtools, RbuildTools and gcc with gdb. It compiles now, but still gives the same error as I did in Rstudio. I would like to at least get better error output, like the line and value passed. The instruction say Rgui should have a spot for a break-point, but I cannot find such an option.

Update 3 I was finally able to set up and run a Linux install (Ubuntu 16.04.05). First here are my CXXFLAGS:

$ R CMD config CXXFLAGS
-g -O0 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g

I had to create a .R folder in my home directory and a Makevar file in it with just the line

CXXFLAGS = -g -O0 -Wall -pedantic -fstack-protector-strong -D_FORTIFY_SOURCE=2

This alone took hours as nowhere did it actually say make the folder and file.

Then I executed the commands as Ralf posted, at the break point:

> timesTwo2(d1)

Thread 1 "R" hit Breakpoint 1, timesTwo2 (x=...) at RcppTest.cpp:19
19  NumericVector timesTwo2(NumericVector x) {
(gdb) n
20    for (int ii = 0; ii <= x.size(); ii++)
(gdb) n
22      x.at(ii) = x.at(ii) * 2;
(gdb) display ii
1: ii = 0
(gdb) n
20    for (int ii = 0; ii <= x.size(); ii++)
1: ii = 0
(gdb) n
22      x.at(ii) = x.at(ii) * 2;
1: ii = 1
(gdb) n
20    for (int ii = 0; ii <= x.size(); ii++)
1: ii = 1
(gdb) display x.at(ii)
2: x.at(ii) = <error: Attempt to take address of value not located in memory.>
(gdb) n
22      x.at(ii) = x.at(ii) * 2;
1: ii = 2
2: x.at(ii) = <error: Attempt to take address of value not located in memory.>
(gdb) 

And finally at n = 10:

1: ii = 10
2: x.at(ii) = <error: Attempt to take address of value not located in memory.>
(gdb) n
0x00007ffff792d762 in Rf_applyClosure () from /usr/lib/R/lib/libR.so
(gdb) 

This is definitely the furthest I have come to debugging, but this is a very basic function and the debug output and even the error output was not very useful. It gave me the line it was executing and it could display ii, but I could not display the array value or the entire array. Is it possible to create a more specific break point such that it only breaks when ii == 10? Ideally I would like this in Rstudio or some other GUI that can display the entire vector. Still doing more testing.

解决方案

The usual approach R -d gdb, which I also suggested in my original answer below, does not work on Windows:

--debugger=name
-d name

(UNIX only) Run R through debugger name. For most debuggers (the exceptions are valgrind and recent versions of gdb), further command line options are disregarded, and should instead be given when starting the R executable from inside the debugger.

https://cran.r-project.org/doc/manuals/r-release/R-intro.html#Invoking-R-from-the-command-line

Alternative:

  1. Start R in debugger: gdb.exe Rgui.exe
  2. Set break point: break TimesTwo2
  3. Run R: run
  4. Source file: Rcpp::sourceCpp("debug.cpp")
  5. Use next, print, display to step through the code.

An alternative to step 1. would be to start R, get the PID with Sys.getpid(), attach debugger with gdb -p <pid>. You will than have to use continue instead of run.


I don't have a Windows machine right now, so the following was done on Linux. I hope it is transferable, though. Let's start with a simple cpp file (debug.cpp in my case) that contains your code:

#include <Rcpp.h>
using Rcpp::NumericVector;

// [[Rcpp::export]]
NumericVector timesTwo2(NumericVector x) {
  for(int ii = 0; ii <= x.size(); ii++)
  {
    x.at(ii) = x.at(ii) * 2;
  }
  return x;
}

/*** R
data = c(1:10)
data
timesTwo2(data)
*/

I can reproduce the error by calling R on the command line:

$ R -e "Rcpp::sourceCpp('debug.cpp')"

R version 3.5.1 (2018-07-02) -- "Feather Spray"
[...]

> Rcpp::sourceCpp('debug.cpp')

> data = c(1:10)

> data
 [1]  1  2  3  4  5  6  7  8  9 10

> timesTwo2(data)
Error in timesTwo2(data) : Index out of bounds: [index=10; extent=10].
Calls: <Anonymous> ... source -> withVisible -> eval -> eval -> timesTwo2 -> .Call
Execution halted

Next we can start R with gdb as debugger (c.f. Writing R Extensions as Dirk said):

$ R -d gdb -e "Rcpp::sourceCpp('debug.cpp')"
GNU gdb (Debian 8.2-1) 8.2
[...]
(gdb) break timesTwo2
Function "timesTwo2" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (timesTwo2) pending.
(gdb) run
[...]
> Rcpp::sourceCpp('debug.cpp')
[Thread 0xb40d3b40 (LWP 31793) exited]
[Detaching after fork from child process 31795]

> data = c(1:10)

> data
 [1]  1  2  3  4  5  6  7  8  9 10

> timesTwo2(data)

Thread 1 "R" hit Breakpoint 1, 0xb34f3310 in timesTwo2(Rcpp::Vector<14, Rcpp::PreserveStorage>)@plt ()
   from /tmp/RtmphgrjLg/sourceCpp-i686-pc-linux-gnu-1.0.0/sourcecpp_7c2d7f56744b/sourceCpp_2.so
(gdb)

At this point you can single step through the program using next (or just n) and output variables using print (or just p). A useful command is also display:

Thread 1 "R" hit Breakpoint 1, timesTwo2 (x=...) at debug.cpp:5
5   NumericVector timesTwo2(NumericVector x) {
(gdb) n
6     for(int ii = 0; ii <= x.size(); ii++)
(gdb) n
8       x.at(ii) = x.at(ii) * 2;
(gdb) display ii
2: ii = 0
(gdb) n
8       x.at(ii) = x.at(ii) * 2;
2: ii = 0

[...]

2: ii = 9
(gdb) 
46          inline proxy ref(R_xlen_t i) { return start[i] ; }
2: ii = 9
(gdb) 
6     for(int ii = 0; ii <= x.size(); ii++)
2: ii = 10
(gdb) 
8       x.at(ii) = x.at(ii) * 2;
2: ii = 10
(gdb) 
Error in timesTwo2(data) : Index out of bounds: [index=10; extent=10].
Calls: <Anonymous> ... source -> withVisible -> eval -> eval -> timesTwo2 -> .Call
Execution halted
[Detaching after fork from child process 32698]
[Inferior 1 (process 32654) exited with code 01]

BTW, I used the following compile flags:

$ R CMD config CXXFLAGS
-g -O2 -Wall -pedantic -fstack-protector-strong -D_FORTIFY_SOURCE=2

You might want to switch to -O0.

这篇关于如何在 Windows 中调试(逐行)Rcpp 生成的代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆