Gần đây tôi đã thử nghiệm với Rcpp (inline) để tạo các tệp DLL thực hiện các tác vụ khác nhau trên các đầu vào R được cung cấp. Tôi muốn có thể gỡ lỗi mã trong các dòng DLL này theo dòng, được đưa ra một bộ đầu vào R cụ thể. (Tôi đang làm việc trong môi trường Windows.)Gỡ lỗi (từng dòng) của DLL do Rcpp tạo dưới Windows
Để minh họa, chúng ta hãy xem xét một ví dụ cụ thể mà ai cũng sẽ có thể chạy ...
Đoạn code dưới đây là một cxxfunction thực sự đơn giản mà chỉ đơn giản tăng gấp đôi vector đầu vào . Tuy nhiên, lưu ý rằng có một biến bổ sung myvar
thay đổi giá trị một vài lần nhưng không ảnh hưởng đến đầu ra - điều này đã được thêm vào để chúng tôi có thể thấy khi nào quá trình gỡ lỗi đang chạy chính xác.
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));
')
Sau khi chúng tôi chạy trên, gõ lệnh
getLoadedDLLs()
sẽ trả về một danh sách các file DLL trong phiên R. Người cuối cùng được liệt kê nên là DLL tạo ra bởi quá trình trên - nó có một cái tên tạm thời ngẫu nhiên, mà trong trường hợp của tôi là
file7e61645c
Các "Tên tệp" cột cho thấy cxxfunction đã đưa DLL này ở vị trí tempdir()
, mà đối với tôi hiện đang
C:/Users/TimP/AppData/Local/Temp/RtmpXuxtpa/file7e61645c.dll
Bây giờ, một cách rõ ràng để gọi DLL là thông qua f0
, như sau
> f0(c(-7,0.7,77))
$out1
[1] -14.0 1.4 154.0
Nhưng chúng ta có thể đương nhiên cũng gọi DLL trực tiếp bằng tên sử dụng .Call
lệnh:
> .Call("file7e61645c",c(-7,0.7,77))
$out1
[1] -14.0 1.4 154.0
Vì vậy, tôi đã đạt đến điểm mà tôi gọi một DLL độc lập trực tiếp với đầu vào R (ở đây, vector c(-7,0.7,77)
), và có nó trở lại Câu trả lời đúng cho R.
Điều tôi thực sự cần là cơ sở để gỡ lỗi từng dòng (sử dụng gdb, tôi đoán) sẽ cho phép tôi quan sát giá trị myvar
được đặt thành 19, 27, 28, 29, 30 và cuối cùng là 101 khi mã tiến triển. Ví dụ trên được thiết lập một cách có chủ ý để gọi DLL cho chúng ta biết gì về myvar.
Để làm rõ, "điều kiện giành chiến thắng" ở đây là có thể quan sát myvar thay đổi (xem giá trị myvar = 19 sẽ là bước đầu tiên!) Mà không thêm bất kỳ thứ gì khác vào phần thân của mã. Điều này rõ ràng có thể yêu cầu thay đổi cách thức mã được biên dịch (có cài đặt chế độ gỡ lỗi để bật không?) Hoặc cách R được gọi - nhưng tôi không biết bắt đầu từ đâu. Như đã nói ở trên, tất cả điều này là dựa trên Windows.
Lưu ý cuối cùng: Trong thử nghiệm của mình, tôi đã thực hiện một số sửa đổi nhỏ cho bản sao của hàm cxxfunction để DLL đầu ra - và mã bên trong - nhận tên do người dùng xác định và nằm trong thư mục do người dùng xác định. hơn tên và vị trí tạm thời. Nhưng điều này không ảnh hưởng đến bản chất của câu hỏi.Tôi đề cập đến điều này chỉ để nhấn mạnh rằng nó sẽ khá dễ dàng để thay đổi các thiết lập biên dịch nếu ai đó đưa cho tôi một cú huých :)
Để hoàn thành, thiết lập verbose = TRUE trong lệnh cxxfunction gốc ở trên cho thấy đối số biên dịch là của hình thức sau đây:
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
phiên bản chuyển thể của tôi có một cuộc tranh luận tổng hợp giống với ở trên, ngoại trừ chuỗi "file7e61645c" được thay thế ở khắp mọi nơi bởi sự lựa chọn của người sử dụng tên (ví dụ: "testdll") và có liên quan file sao chép trên đến một vị trí cố định hơn.
Cảm ơn trước cho kẻ giúp đỡ của bạn :)
Tôi không thể giúp trực tiếp, nhưng tôi biết Dirk vv luôn hữu ích. Tuy nhiên, họ thường kinh doanh trên [danh sách email Rcpp] (http://lists.r-forge.r-project.org/mailman/listinfo/rcpp-devel) –
Đã thực hiện một số tiến bộ nhẹ về vấn đề này, vì vậy hãy cập nhật ngắn gọn . Chơi xung quanh với inline ::: compileCode, được gọi trong cxxfunction, tôi thấy rằng việc thêm '--debug' vào cuối' R CMD SHLIB' cho phép tôi kiểm tra những gì đang xảy ra bên trong DLL thông qua việc kết hợp gdb và R. HOWEVER , đây không phải là giải pháp đầy đủ vì một số biến không truy cập được (chẳng hạn như 'i', trong vòng lặp trên' i'); thông điệp xuất hiện rằng họ đã được "tối ưu hóa". Do đó, tôi nghĩ rằng tôi cần phải thay thế "-O2" bằng "-O0" trong đối số biên dịch ... nhưng tôi không có khái niệm về cách thực hiện điều này ... –
Tôi đã thu thập được một số bằng chứng rõ ràng tất cả những gì tôi cần làm là thay đổi cờ trình biên dịch R CMD SHLIB từ -O2 thành một thứ như -g -O0 ... ví dụ xem bài đăng tại https://stat.ethz.ch/pipermail/r-devel/2008-November/051390.html - nhưng tôi thiếu một tuyên bố chính xác về những gì cần xác định và làm thế nào. Một số nguồn trực tuyến đề cập đến việc tạo một tệp tại '/.R/Makevars.win' nhưng chúng không mô tả tệp và đây không phải là vị trí hợp lệ trong Windows do dấu chấm trước chữ R ... –