加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Windows > 正文

在Windows下调试(一行一行)Rcpp生成的DLL

发布时间:2020-12-13 20:26:25 所属栏目:Windows 来源:网络整理
导读:最近我一直在尝试使用Rcpp(内联)来生成在提供的R输入上执行各种任务的DLL.我想要能够逐行调试这些DLL中的代码,给定一组特定的R输入. (我在Windows下工作.) 为了说明,让我们考虑一个具体的例子,任何人都应该能够运行… 下面的代码是一个非常简单的cxxfunction
最近我一直在尝试使用Rcpp(内联)来生成在提供的R输入上执行各种任务的DLL.我想要能够逐行调试这些DLL中的代码,给定一组特定的R输入. (我在Windows下工作.)

为了说明,让我们考虑一个具体的例子,任何人都应该能够运行…

下面的代码是一个非常简单的cxxfunction,只需将输入向量加倍.但是请注意,还有一个额外的变量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));
')

在我们运行上面之后,键入命令

getLoadedDLLs()

在R会话中列出DLL列表.列出的最后一个应该是由上述过程创建的DLL – 它有一个随机的临时名称,在我的例子中

file7e61645c

“文件名”列显示cxxfunction已将此DLL放在位置tempdir()中,这对我来说是当前的

C:/Users/TimP/AppData/Local/Temp/RtmpXuxtpa/file7e61645c.dll

现在,通过f0调用DLL的明显方法如下

> f0(c(-7,0.7,77))

$out1
[1] -14.0   1.4 154.0

但是我们当然也可以使用.Call命令直接通过名称来调用DLL:

> .Call("file7e61645c",c(-7,77))

$out1
[1] -14.0   1.4 154.0

所以我已经达到了直接用R输入(这里是向量c(-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

我的修改版本具有与上述相同的编译参数,除了字符串“file7e61645c”被用户选择的名称(例如“testdll”)替换,并将相关文件复制到更永久的位置.

提前感谢你的帮助:)

有一些 Rcpp用户对 inline包及其cxxfunction()的迷恋感到有点震惊.是的,这确实是非常有用的,它肯定已经推动了 Rcpp的进一步采用,因为它使快速的实验变得更加容易.是的,它允许我们在源中使用700个单元测试.是的,我一直使用它来演示这里的例子,在 rcpp-devel list,甚至生活在 presentations.

但这是否意味着我们应该使用它来进行每一项任务?这是否意味着它没有“成本”,如临时目录等中的随机文件名?罗曼和我在我们的文件中另有争议.

最后,动态加载的R模块的调试比较困难.在(强制性)Writing R Extensions中有一个关于它的整个部分,Doug Bates一两次发布了关于如何通过ESS和Emacs(尽管我总是忘记他发布的地方)的教程;曾经是07年3月的IIRC.

编辑2012年7月 – 7月:

这是你的一步一步:

(序言:我已经使用gcc和g了很多年了,甚至当我添加-g时,我并不总是把-O2变成-O0,我真的不确定你需要这个,但是你要的是. ..)
>将您的环境变量CXXFLAGS设置为“-g -O0 -Wall”.有许多方法可以做到这一点,一些是平台依赖的(例如Windows控制面板),因此不那么普遍和有趣.我在Windows和Unix上使用?/ .R / Makevars.您可以使用它,或者您可以覆盖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会话.
>编译你的代码对于

06000

我得到

[...]
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

>调用例如tempdir()来查看临时目录,cd到上面使用的这个临时目录和dyn.load()上面构建的文件:

06002

>现在通过发送中断信号暂停R(在Emacs中,从下拉菜单中选择一个简单的选项).
>在gdb中,设置一个断点.上面的单个作业成为我的第32行,所以

06003

>返回R,调用函数:

fun()

> Presto,在我们想要的断点处的调试器中:

06004

>现在,“只是”你的工作gdb的魔法

现在,正如我在第一次尝试中所说的那样,通过Rcpp.package.skeleton()可以为您编写的一个简单的包,所有这一切将更容易(在我看来),因为您不必处理随机的目录和文件名.但每一个到自己的…

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读