代码之家  ›  专栏  ›  技术社区  ›  MichaelE

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

  •  4
  • MichaelE  · 技术社区  · 6 年前

    我正在调试 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文件中->新建文件->C++文件(使用timesTwo函数创建示例文件。)

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

    我在保存时检查了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].
    

    <= x.size() 因此,结果是运行时错误。

    问题是,如何获得有关此错误的调试输出,合理地告诉我发生了什么? 至少我想知道代码中触发异常的那一行以及使用哪些参数。

    我可以安装任何额外的程序或应用任何其他设置,只要我能找到如何做到这一点的确切细节。现在我从零开始只是为了让它工作。非常感谢。

    更新: 我发现这个网站: Debugging Rcpp c++ code using gdb 我安装了最新的 gcc 8.1带 gdb

    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/
    

    看起来它正在加载新的 它正在使用 DEBUG ,但它似乎仍然无法编译。有人知道为什么会出错吗?

    Rgui 它开始于许多线程显示在 窗口,但Rstudio中的所有内容都像以前一样运行,没有来自Rstudio或 .

    更新2: Rgui 没有用于编译的Rtools,因此我从提供链接安装了Rtools。它安装在C:\r工具中,而Rstudio安装在C:\r构建工具中。所以我现在有3个编译器,Rtools,RbuildTools和 通用条款 具有 . 它现在可以编译了,但仍然会出现与我在Rstudio中相同的错误。我希望至少得到更好的错误输出,比如传递的行和值。 说明书上说 Rgui 应该有一个断点,但我找不到这样的选择。

    我终于能够安装并运行Linux(Ubuntu 16.04.05)。 首先是我的 CXX标志

    $ 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

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

    然后,我在断点处执行拉尔夫发布的命令:

    > 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中使用它。仍在进行更多测试。

    1 回复  |  直到 4 年前
        1
  •  7
  •   R Yoda    5 年前

    通常的方法 R -d gdb 我在下面的原始答案中也建议,它在Windows上不起作用:


    -d名称

    仅限UNIX

    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() gdb -p <pid> . 你将不得不使用 continue 而不是 .


    我现在没有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
    

    接下来我们可以从R开始 gdb 作为调试器(c.f。 编写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)
    

    此时,您可以使用 下一个 (或者只是 n )和输出变量使用 打印 (或者只是 p ). 一个有用的命令也是 陈列 :

    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 .

        2
  •  3
  •   James Hirschorn    4 年前

    这可以用Visual Studio代码完成,因为它可以处理这两个方面 R C++ . 这允许您逐步完成 Rcpp 在GUI环境中一次编写一行代码。

    看到这个了吗 demo