我正在尝试Rcpp在运行时调试已编译的代码。很长一段时间以来,我一直试图让它无法成功地工作。这里问了一个非常相似的问题: Debugging (line by line) of Rcpp-generated DLL under Windows这提出了同样的问题,但问题和答案都远远超出了我的理解。
这是我所拥有的:
Windows 7 Pro SP1
R 3.5
Rstudio 1.1.463 with Rcpp.
Rbuild Tools from Rstudio. (c++ compiler)
Run Code Online (Sandbox Code Playgroud)
过程:在 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;
}
return x;
}
Run Code Online (Sandbox Code Playgroud)
我在 Save 上检查了 Source 并将文件保存为 RcppTest.cpp ,它成功地获取或编译了文件。
在 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].
Run Code Online (Sandbox Code Playgroud)
错误是因为在 for 循环中<= x.size()所以结果是运行时错误。
问题是如何获得有关此错误的调试输出,合理地告诉我发生了什么?至少我想知道触发异常的代码行以及使用哪些参数。此外,我真的很想在异常之前逐行执行代码,以便我可以准确地监视正在发生的事情。
我可以安装任何其他程序或应用任何其他设置,只要我能找到有关如何操作的准确详细信息。现在我从头开始只是为了让它工作。谢谢你。
更新:
我找到了这个站点:Debugging Rcpp c++ code using gdb
我安装了最新的gcc8.1gdb
我在CXXFLAGS位于的makeconf文件中找到了C:\Program Files\R\R-3.5.1\etc\x64
然后我Rgui按照建议开始了,但是当我尝试时Rcpp:::sourceCpp出现错误:
> 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/
Run Code Online (Sandbox Code Playgroud)
看起来它正在加载新的CXXFLAGS并且正在使用DEBUG,但它似乎仍然无法编译。有人知道错误的原因吗?
我尝试以相同的方式运行 Rstudio Rgui,它开始时gdb窗口中显示了许多线程,但是 Rstudio 中的所有内容都像以前一样运行,没有来自 Rstudio 或gdb.
更新 2:
由于上面的错误指出Rgui没有用于编译的 Rtools,所以我从提供链接安装了 Rtools。它安装在 C:\Rtools 中,而 Rstudio 安装在 C:\RBuildTools 中。所以,我现在有3个编译器,Rtools,RbuildTools并gcc用gdb。它现在可以编译,但仍然出现与我在 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
Run Code Online (Sandbox Code Playgroud)
我不得不创建一个.R在我的主目录文件夹和一个Makevar在它只有一行的文件
CXXFLAGS = -g -O0 -Wall -pedantic -fstack-protector-strong -D_FORTIFY_SOURCE=2
仅此一项就花费了数小时,因为它实际上并没有说制作文件夹和文件。
然后我在断点处执行了 Ralf 发布的命令:
> 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)
Run Code Online (Sandbox Code Playgroud)
最后在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)
Run Code Online (Sandbox Code Playgroud)
这绝对是我调试最远的地方,但这是一个非常基本的功能,调试输出甚至错误输出都不是很有用。它给了我它正在执行的行,它可以显示 ii,但我无法显示数组值或整个数组。是否可以创建一个更具体的断点,使其仅在 时中断ii == 10?理想情况下,我希望在 Rstudio 或其他一些可以显示整个矢量的 GUI 中使用它。还在做更多的测试。
R -d gdb我也在下面的原始答案中建议的通常方法不适用于 Windows:
--debugger=name
-d 名称(仅限 UNIX)通过调试器名称运行 R。对于大多数调试器(例外是 valgrind 和最新版本的 gdb),更多的命令行选项被忽略,而应该在从调试器内部启动 R 可执行文件时给出。
https://cran.r-project.org/doc/manuals/r-release/R-intro.html#Invoking-R-from-the-command-line
选择:
gdb.exe Rgui.exebreak TimesTwo2runRcpp::sourceCpp("debug.cpp")next,print,display单步执行代码。步骤 1. 的替代方法是启动 R,使用 获取 PID Sys.getpid(),使用 附加调试器gdb -p <pid>。你将不得不使用continue而不是run.
我现在没有 Windows 机器,所以以下是在 Linux 上完成的。不过,我希望它是可以转让的。让我们从一个debug.cpp包含您的代码的简单 cpp 文件(在我的例子中)开始:
#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)
*/
Run Code Online (Sandbox Code Playgroud)
我可以通过在命令行上调用 R 来重现错误:
$ 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
Run Code Online (Sandbox Code Playgroud)
接下来我们可以使用gdb调试器启动 R (参见Dirk 所说的编写 R 扩展):
$ 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)
Run Code Online (Sandbox Code Playgroud)
在这一点上,你可以单步执行程序使用单next(或刚刚n),并使用输出变量print(或只是p)。一个有用的命令也是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]
Run Code Online (Sandbox Code Playgroud)
顺便说一句,我使用了以下编译标志:
$ R CMD config CXXFLAGS
-g -O2 -Wall -pedantic -fstack-protector-strong -D_FORTIFY_SOURCE=2
Run Code Online (Sandbox Code Playgroud)
您可能想要切换到-O0.