Tim*_*m P 20 debugging dll gdb r rcpp
最近我一直在尝试使用Rcpp(内联)来生成DLL,这些DLL在提供的R输入上执行各种任务.在给定一组特定的R输入的情况下,我希望能够逐行调试这些DLL中的代码.(我在Windows下工作.)
为了说明,让我们考虑一个任何人都应该能够运行的具体例子......
下面的代码是一个非常简单的cxx函数,它只是输入向量的两倍.但请注意,有一个额外的变量myvar可以更改值几次,但不会影响输出 - 这已添加,以便我们能够看到调试过程何时正确运行.
library(inline)
library(Rcpp)
f0 <- cxxfunction(signature(a="numeric"), plugin="Rcpp", body='
Rcpp::NumericVector xa(a);
int myvar = 19;
int na = xa.size();
myvar = 27;
Rcpp::NumericVector out1(na);
for(int i=0; i < na; i++) {
out1[i] = 2*xa[i];
myvar++;
}
myvar = 101;
return(Rcpp::List::create( _["out1"] = out1));
')
Run Code Online (Sandbox Code Playgroud)
运行上面的命令之后,输入命令
getLoadedDLLs()
Run Code Online (Sandbox Code Playgroud)
在R会话中显示DLL列表.列出的最后一个应该是由上面的过程创建的DLL - 它有一个随机的临时名称,在我的情况下是
file7e61645c
Run Code Online (Sandbox Code Playgroud)
"Filename"列显示cxxfunction已将此DLL放在该位置tempdir(),这对我来说是当前的位置
C:/Users/TimP/AppData/Local/Temp/RtmpXuxtpa/file7e61645c.dll
Run Code Online (Sandbox Code Playgroud)
现在,调用DLL的明显方法是via f0,如下所示
> f0(c(-7,0.7,77))
$out1
[1] -14.0 1.4 154.0
Run Code Online (Sandbox Code Playgroud)
但我们当然也可以使用以下.Call命令直接通过名称调用DLL :
> .Call("file7e61645c",c(-7,0.7,77))
$out1
[1] -14.0 1.4 154.0
Run Code Online (Sandbox Code Playgroud)
所以我已经达到了我用R输入(这里是向量c(-7,0.7,77))直接调用一个独立的DLL ,然后让它正确地将答案返回给R.
但是,我真正需要的是逐行调试的工具(使用gdb,我推测),这将允许我观察myvar设置为19,27,28,29,30,最后101 的值为代码进展.上面的例子是故意设置的,这样调用DLL就不会告诉我们myvar.
为了澄清,这里的"胜利条件"能够观察myvar变化(看到值myvar = 19将是第一步!)而不向代码主体添加任何其他东西.这显然可能需要改变编译代码的方式(是否有调试模式设置打开?),或者调用R的方式 - 但我不知道从哪里开始.如上所述,所有这些都是基于Windows的.
最后说明:在我的实验中,我实际上对cxxfunction的副本进行了一些小的修改,以便输出DLL - 以及其中的代码 - 接收用户定义的名称并且位于用户定义的目录中,而不是临时名称和位置.但这并不影响问题的本质.我提到这只是为了强调如果有人给我一个轻推,改变编译设置应该相当容易:)
为完整起见,在上面的原始cxxfunction调用中设置verbose = TRUE会将编译参数显示为以下形式:
C:/R/R-2.13.2/bin/i386/R CMD SHLIB file7e61645c.cpp 2> file7e61645c.cpp.err.txt
g++ -I"C:/R/R-213~1.2/include" -I"C:/R/R-2.13.2/library/Rcpp/include" -O2 -Wall -c file7e61645c.cpp -o file7e61645c.o
g++ -shared -s -static-libgcc -o file7e61645c.dll tmp.def file7e61645c.o C:/R/R-2.13.2/library/Rcpp/lib/i386/libRcpp.a -LC:/R/R-213~1.2/bin/i386 -lR
Run Code Online (Sandbox Code Playgroud)
我的改编版本有一个与上面相同的编译参数,除了字符串"file7e61645c"被用户选择的名称(例如"testdll")和相关文件复制到更永久的位置.
在此先感谢您的帮助:)
Dir*_*tel 19
一些Rcpp用户对内联包及其内容的痴迷让我感到有些震惊cxxfunction().是的,它确实非常有用,它肯定会进一步推动Rcpp的采用,因为它使快速实验变得更加容易.是的,它允许我们在源中使用700多个单元测试.是的,我一直用它来演示这里的例子,在rcpp-devel列表上,甚至是现场演示.
但这是否意味着我们应该将它用于每项任务?这是否意味着它没有"成本",如临时目录中的随机文件名等?Romain和我在我们的文档中另有说法.
最后,动态加载的R模块的调试很难实现.关于它的(强制性)写R扩展中有一个完整的部分,Doug Bates一两次发布了一个关于如何通过ESS和Emacs 这样做的教程(虽然我总是忘记他发布的地方;曾经是rcpp上的IIRC - 级别列表).
编辑2012年7月7日:
这是你的一步一步:
(序言:我已经使用gcc和g ++很多年了,甚至当我添加-g时我并不总是将-O2转换成-O0.我真的不确定你需要它,但是当你要求它时...... .)
将环境变量CXXFLAGS设置为"-g -O0 -Wall".有很多方法可以做到这一点,有些是依赖于平台的(例如Windows控制面板),因此不那么通用和有趣.我~/.R/Makevars在Windows和Unix上使用.您可以使用它,或者您可以覆盖R的系统级$ RHOME/etc/Makeconf,或者您可以使用Makeconf.site或...查看完整的文档---但正如我所说,这~/.R/Makevars是我的首选方式,因为它不是干扰R之外的编译
现在每个编译R通过R CMD SHLIB,R CMD COMPILE,R CMD INSTALL,...将使用.因此,使用内联或本地包不再重要.继续内联......
其余的,我们主要遵循"编写R扩展"中的"第4.4.1节查找动态加载代码中的入口点":
使用R -d gdb启动另一个R会话.
编译你的代码.对于
Run Code Online (Sandbox Code Playgroud)fun <- cxxfunction(signature(), plugin="Rcpp", verbose=TRUE, body=' int theAnswer = 42; return wrap(theAnswer); ')
我明白了
[...]
Compilation argument:
/usr/lib/R/bin/R CMD SHLIB file11673f928501.cpp 2> file11673f928501.cpp.err.txt
ccache g++-4.6 -I/usr/share/R/include -DNDEBUG -I"/usr/local/lib/R/site- library/Rcpp/include" -fpic -g -O0 -Wall -c file11673f928501.cpp -o file11673f928501.o
g++-4.6 -shared -o file11673f928501.so file11673f928501.o -L/usr/local/lib/R/site-library/Rcpp/lib -lRcpp -Wl,-rpath,/usr/local/lib/R/site-library/Rcpp/lib -L/usr/lib/R/lib -lR
Run Code Online (Sandbox Code Playgroud)
tempdir()查看临时目录,cd到上面使用的这个临时目录和dyn.load()上面构建的文件: Run Code Online (Sandbox Code Playgroud)dyn.load("file11673f928501.so")
现在通过发送中断信号暂停R(在Emacs中,从下拉列表中选择一个简单的选项).
在gdb中,设置断点.上面的单个作业对我来说变成了第32行,所以
Run Code Online (Sandbox Code Playgroud)break file11673f928501.cpp 32 cont
回到R,调用函数:
有趣的()
Presto,在我们想要的断点处的调试器中:
Run Code Online (Sandbox Code Playgroud)R> fun() Breakpoint 1, file11673f928501 () at file11673f928501.cpp:32 32 int theAnswer = 42; (gdb)
现在,正如我在第一次尝试中所说的那样,通过一个简单的包可以更容易(在我看来)Rcpp.package.skeleton(),因为你不必处理随机目录和文件名.但每个人都自己......
| 归档时间: |
|
| 查看次数: |
3246 次 |
| 最近记录: |