2012-07-05 12 views
17

के तहत आरसीपीपी जेनरेट डीएलएल के डीबगिंग (लाइन द्वारा लाइन) हाल ही में मैं डीएलएल उत्पन्न करने के लिए आरसीपीपी (इनलाइन) के साथ प्रयोग कर रहा हूं जो आपूर्ति किए गए आर इनपुट पर विभिन्न कार्यों को निष्पादित करता है। मैं आर इनपुट के एक विशिष्ट सेट के बाद, इन डीएलएल लाइन में कोड को डीबग करने में सक्षम होना चाहता हूं। (मैं 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() 

टाइपिंग आर सत्र में DLLs की एक सूची को लाता है। सूचीबद्ध उपरोक्त प्रक्रिया के द्वारा बनाई गई DLL होना चाहिए कि पिछले एक - यह एक यादृच्छिक अस्थायी नाम है, जो मेरे मामले में

file7e61645c 

"फ़ाइल नाम" कॉलम पता चलता है कि cxxfunction स्थान tempdir() में इस DLL डाल दिया है मेरे लिए जो वर्तमान में

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,0.7,77)) 

$out1 
[1] -14.0 1.4 154.0 

तो मैं बिंदु जहां मैं एक स्टैंडअलोन DLL सीधे फोन कर रहा हूँ आर इनपुट (यहाँ, वेक्टर c(-7,0.7,77)) के साथ पहुँच गए हैं, और यह वापसी होने सही ढंग से आर

का जवाब क्या मैं सच में की जरूरत है, हालांकि, पंक्ति-दर-पंक्ति डिबगिंग के लिए एक सुविधा (gdb का उपयोग कर, मुझे लगता है) कि मुझे myvar का मूल्य निरीक्षण करने के लिए 19 के लिए स्थापित किया जा रहा की अनुमति देगा, है 27, 28, 2 9, 30, और आखिरकार 101 कोड के रूप में प्रगति करता है। ऊपर दिया गया उदाहरण जानबूझकर स्थापित किया गया है ताकि डीएलएल को बुलाकर हमें माईवर के बारे में कुछ भी नहीं बताया जा सके।

स्पष्टीकरण के लिए, यहां "जीत स्थिति" कोड के शरीर में कुछ और जोड़ने के बिना myvar बदलने (मान myvar = 19 पहला कदम होगा!) को देखने में सक्षम है। स्पष्ट रूप से कोड को संकलित करने के तरीके में परिवर्तन की आवश्यकता हो सकती है (क्या डीबगिंग मोड सेटिंग्स चालू हैं?), या जिस तरह से आर कहा जाता है - लेकिन मुझे नहीं पता कि कहां से शुरू करना है। जैसा कि ऊपर बताया गया है, यह सब विंडोज आधारित है।

अंतिम नोट: मेरे प्रयोगों में, मैंने वास्तव में cxxfunction की एक प्रति में कुछ मामूली संशोधन किए ताकि आउटपुट डीएलएल - और उसके भीतर कोड - उपयोगकर्ता द्वारा परिभाषित नाम प्राप्त हो और उपयोगकर्ता द्वारा परिभाषित निर्देशिका में बैठे, बल्कि एक अस्थायी नाम और स्थान से। लेकिन यह सवाल के सार को प्रभावित नहीं करता है।मैं इस बात पर जोर देता हूं कि अगर कोई मुझे नजदीक देता है तो संकलन सेटिंग्स को बदलने के लिए काफी आसान होना चाहिए :)

पूर्णता के लिए, उपरोक्त मूल cxxfunction कॉल में verbose = TRUE को सेट करने से संकलन तर्क को दिखाया गया है निम्न प्रपत्र: सिवाय इसके कि स्ट्रिंग "file7e61645c" (उदाहरण के लिए "testdll") और संबंधित फाइलों पर कॉपी नाम के उपयोगकर्ता की पसंद से हर जगह बदल दिया जाता है

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 

मेरे रूपांतरित संस्करण, एक संकलन तर्क से ऊपर के समान है एक और स्थायी स्थान पर। आपकी मदद के लोगों के लिए अग्रिम में

धन्यवाद :)

+0

मैं सीधे मदद नहीं कर सकता, लेकिन मुझे पता है कि Dirk आदि हमेशा सहायक होते हैं। हालांकि वे आम तौर पर [आरसीपीपी ईमेल सूची] पर व्यवसाय करते हैं (http://lists.r-forge.r-project.org/mailman/listinfo/rcpp-devel) –

+0

इस पर कुछ हल्की प्रगति की है, इसलिए एक संक्षिप्त अपडेट । इनलाइन ::: संकलन कोड के साथ खेलना, जिसे cxxfunction के भीतर बुलाया जाता है, मैंने पाया कि 'आर सीएमडी एसएचआईएलबी' के अंत में '--debug' जोड़ने से मुझे डीडीएल के अंदर क्या चल रहा है यह जांचने की अनुमति दी गई है कि जीडीबी और आर। हाउवर , यह एक पूर्ण समाधान नहीं है क्योंकि कुछ चर पहुंच योग्य नहीं थे (जैसे 'i',' i' पर लूप के दौरान); संदेश आया कि उन्हें "अनुकूलित" किया गया था। मुझे लगता है कि इसलिए मुझे संकलन तर्क में "-O2" के साथ "-O2" को प्रतिस्थापित करने की आवश्यकता है ... लेकिन मुझे यह नहीं पता कि यह कैसे किया जाए ... –

+0

मैंने सबूत इकट्ठा किए हैं मुझे बस इतना करना है कि आरएमडी SHLIB कंपाइलर झंडे -ओ 2 से कुछ -g -O0 ... जैसे https://stat.ethz.ch/pipermail/r-devel/2008-November/051390.html पर पोस्ट देखें - लेकिन मुझे निर्दिष्ट करने की आवश्यकता के बारे में एक सटीक बयान की कमी है और कैसे। कुछ ऑनलाइन स्रोतों में '/.R/Makevars.win' पर एक फ़ाइल बनाने का उल्लेख है, लेकिन वे फ़ाइल का वर्णन नहीं करते हैं, और यह पत्र आर से पहले बिंदु के कारण विंडोज में मान्य स्थान नहीं है ... –

उत्तर

18

मैं एक छोटे से जुनून कुछ Rcpp उपयोगकर्ताओं inline पैकेज और उसके cxxfunction() साथ देखकर स्तब्ध हूं। हां, यह वास्तव में बहुत उपयोगी है और इसने निश्चित रूप से Rcpp को गोद लेने के लिए प्रेरित किया है क्योंकि यह त्वरित प्रयोग इतना आसान बनाता है। हां, इसने हमें स्रोतों में 700+ यूनिट परीक्षणों का उपयोग करने की अनुमति दी। हां, मैं यहां उदाहरणों का प्रदर्शन करने के लिए हर समय इसका उपयोग करता हूं, rcpp-devel list पर या यहां तक ​​कि presentations में भी रहते हैं।

लेकिन क्या इसका मतलब है कि हमें इसे प्रत्येक कार्य के लिए उपयोग करना चाहिए? क्या इसका मतलब यह है कि इसमें "लागत" नहीं है जैसे अस्थायी निर्देशिका आदि में यादृच्छिक फ़ाइल नाम जैसे पीपी? रोमैन और मैंने अन्यथा हमारे दस्तावेज़ीकरण में तर्क दिया।

आखिरकार, की गतिशील रूप से लोड आर मॉड्यूल डिबगिंग मुश्किल है क्योंकि यह खड़ा है। वहाँ (अनिवार्य) Writing R Extensions इसके बारे में एक पूरा खंड है, और डौग बेट्स एक या दो बार कैसे के माध्यम से ESS और Emacs यह करने के लिए के बारे में एक ट्यूटोरियल पोस्ट (हालांकि मैं हमेशा भूल जाते हैं, जहां वह इसे पोस्ट, एक बार rcpp-devel list पर IIRC) था।

संपादित करें 2012 Jul-07:

यहाँ कदम से अपने कदम है:

  • (प्रस्तावना: मैं कई वर्षों के लिए जीसीसी और जी ++ का उपयोग किया है, और यहां तक ​​कि जब मैं जोड़ने जी मैं हमेशा -O0 में -O2 बारी नहीं मैं सच में यकीन है कि आपको लगता है कि आवश्यकता है, लेकिन नहीं कर रहा हूँ के रूप में आप इसके लिए पूछना ...)

  • अपने वातावरण चर CXXFLAGS करने के लिए "जी -O0 सेट करें। - दीवार"। ऐसा करने के कई तरीके हैं, कुछ मंच-निर्भर हैं (जैसे विंडोज नियंत्रण कक्ष) और इसलिए कम सार्वभौमिक और दिलचस्प। मैं विंडोज और यूनिक्स पर ~/.R/Makevars का उपयोग करता हूं। आप इस्तेमाल कर सकते हैं कि, या आप आर के पूरे सिस्टम में $ RHOME/etc/Makeconf रद्द कर सकते थे या आप Makeconf.site या इस्तेमाल कर सकते हैं ... पूरी डॉक्स देखें --- लेकिन जैसा कि मैंने कहा, ~/.R/Makevars मेरी पसंदीदा तरीका के रूप में यह करता है आर

  • के बाहर संकलन में हस्तक्षेप न करें अब प्रत्येक संकलन आर आर सीएमडी एसएचआईएलबी, आर सीएमडी कम्पनी, आर सीएमडी इंस्टाल, के माध्यम से करता है ... का उपयोग करेगा। तो यह अब आप इनलाइन या स्थानीय पैकेज का उपयोग करने के लिए महत्वपूर्ण नहीं है। इनलाइन साथ सतत ...

  • बाकी के लिए, हम ज्यादातर का पालन करें 'धारा 4.4.1 गतिशील लोड कोड में प्रवेश बिंदुओं ढूँढना' "लेखन आर एक्सटेंशन" का:

  • प्रारंभ आर के साथ एक और आर सत्र - डी जीडीबी

  • अपने कोड संकलित करें।

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 
  • आह्वान जैसे tempdir() अस्थायी निर्देशिका, इस अस्थायी ऊपर और dyn.load() फ़ाइल का उपयोग किया निर्देशिका के लिए सीडी से ऊपर बनाया देखने के लिए:
dyn.load("file11673f928501.so") 
  • अब (Emacs, एक ड्रॉप-डाउन से एक सरल विकल्प में) एक ब्रेक संकेत भेजकर आर रोक देते हैं।

  • जीडीबी में, ब्रेकपॉइंट सेट करें।

    मज़ा()

  • : एकल काम ऊपर इतना

break file11673f928501.cpp 32 
cont 
  • आर में वापस, मेरे लिए लाइन 32 हो गया, फ़ंक्शन को कॉल करें

  • प्रेस्टो, डीबग में तोड़ बिंदु पर जर हम चाहते थे:

R> fun() 

Breakpoint 1, file11673f928501() at file11673f928501.cpp:32 
32  int theAnswer = 42; 
(gdb) 
  • अब यह "बस" आप पर निर्भर gdb अपना जादू

को अब काम करने के लिए किया जाता है, जैसा कि मैंने कहा मेरे पहले प्रयास में, यह सब एक आसान पैकेज के माध्यम से आसान होगा (मेरी आंखों में) Rcpp.package.skeleton() आपके लिए लिख सकता है क्योंकि आपको यादृच्छिक निर्देशिकाओं और फ़ाइल नामों से निपटने की ज़रूरत नहीं है। लेकिन प्रत्येक के लिए ...

+0

यदि कोई अंदर आरसीपीपी के साथ एक पैकेज का उपयोग कर रहा था, तो यह केवल CXXFLAGS को बदलने की बात है, R -d gdb के साथ आर शुरू करना, ब्रेकिंग आर, सीडीपी फ़ाइल में gdb के साथ ब्रेकपॉइंट सेट करना और फिर से शुरू करना? क्या आर को तोड़ने के बिना आर प्रक्रिया को संलग्न करना और ब्रेक सेट करना संभव नहीं है? आरसीपीपी के साथ डीबगिंग पैकेज पर कोई गाइड? आरसीपीपी बीटीडब्ल्यू के लिए बहुत सारे धन्यवाद! – Juancentro

+1

रिसाइड के साथ, आप सी ++ प्रोग्राम आपके लिए आर शुरू करते हैं। आप जीडीबी से आर प्रक्रिया को जोड़ने का प्रयास कर सकते हैं - या बस अपने बाहरी सी ++ प्रोग्राम पर जीडीबी का उपयोग करें। –

+0

क्षमा करें अगर मैं स्पष्ट नहीं था, तो मैं RInside के बारे में बात नहीं कर रहा हूं। मैं एक आर पैकेज के बारे में बात कर रहा हूं जो आरसीपीपी पर निर्भर करता है क्योंकि इसमें सी ++ कोड है। – Juancentro