草庐IT

r - 如何在 Windows 中调试(逐行)Rcpp 生成的代码?

coder 2024-02-20 原文

我正在尝试调试 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)

程序: 在 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;
}

我在保存时检查了源并将文件另存为 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].

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

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

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

更新: 我找到了这个网站:Debugging Rcpp c++ code using gdb 我安装了最新的 gcc 8.1 与 gdb

我找到了 CXXFLAGSmakeconf文件位于 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/

看起来它正在加载新的 CXXFLAGS它正在使用 DEBUG , 不过好像还是编译不了。有人知道错误的原因吗?

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

更新 2: 由于上面的错误指出 Rgui没有用于编译的 Rtools,所以我从提供的链接安装了 Rtools。它安装在 C:\Rtools 中,而 Rstudio 安装在 C:\RBuildTools 中。所以我现在有 3 个编译器,Rtools、RbuildTools 和 gccgdb . 它现在编译,但仍然给出与我在 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)

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) 

最后在 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) 

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

最佳答案

通常的做法R -d gdb ,我也在下面的原始答案中建议,在 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

备选方案:

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

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


我现在没有 Windows 机器,所以下面是在 Linux 上完成的。不过,我希望它是可转让的。让我们从一个包含您的代码的简单 cpp 文件(在我的例子中为 debug.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)
*/

我可以通过在命令行调用 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

接下来我们可以用gdb启动R作为调试器(参见 Dirk 所说的 Writing R Extensions):

$ 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)

此时您可以使用 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]

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

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

您可能想切换到 -O0 .

关于r - 如何在 Windows 中调试(逐行)Rcpp 生成的代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53622354/

有关r - 如何在 Windows 中调试(逐行)Rcpp 生成的代码?的更多相关文章

  1. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  2. ruby - 如何在 Ruby 中顺序创建 PI - 2

    出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

  3. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  4. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  5. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  6. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  7. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  8. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  9. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  10. ruby - 如何使用 Ruby aws/s3 Gem 生成安全 URL 以从 s3 下载文件 - 2

    我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A

随机推荐