Rcpp:如何保存sourceCpp生成的文件?

时间:2014-09-26 02:59:14

标签: r rcpp

我使用sourceCpp()包中的Rcpp来构建一个C ++文件并从R调用它。它似乎生成一个临时目录,它写入它编译的源代码,但它删除后的目录构建代码。我想访问它正在编译的确切文件,以便我可以在调试器中看到它。如何阻止sourceCpp()删除它编译的文件?

4 个答案:

答案 0 :(得分:3)

正如Dirk所说 - 认真,只需使用包。您在sourceCpp之上开发的任何其他工作流程都可能不够/令人烦恼。

也就是说,Rcpp不会自动删除生成源文件的目录。查看sourceCpp(..., verbose = TRUE)的输出:

> sourceCpp("~/scratch/save-source-cpp.cpp", verbose = TRUE)

Generated extern "C" functions 
--------------------------------------------------------


#include <Rcpp.h>

RcppExport SEXP sourceCpp_2047_timesTwo(SEXP xSEXP) {
BEGIN_RCPP
    SEXP __sexp_result;
    {
        Rcpp::RNGScope __rngScope;
        Rcpp::traits::input_parameter< int >::type x(xSEXP );
        int __result = timesTwo(x);
        PROTECT(__sexp_result = Rcpp::wrap(__result));
    }
    UNPROTECT(1);
    return __sexp_result;
END_RCPP
}

Generated R functions 
-------------------------------------------------------

`.sourceCpp_2047_DLLInfo` <- dyn.load('/var/folders/tm/5dt8p5s50x58br1k6wpqnwx00000gn/T//RtmppARq3j/sourcecpp_1b612a59c474/sourceCpp_85891.so')

timesTwo <- Rcpp:::sourceCppFunction(function(x) {}, FALSE, `.sourceCpp_2047_DLLInfo`, 'sourceCpp_2047_timesTwo')

rm(`.sourceCpp_2047_DLLInfo`)

Building shared library
--------------------------------------------------------

DIR: /var/folders/tm/5dt8p5s50x58br1k6wpqnwx00000gn/T//RtmppARq3j/sourcecpp_1b612a59c474

/Library/Frameworks/R.framework/Resources/bin/R CMD SHLIB -o 'sourceCpp_85891.so' 'save-source-cpp.cpp' 
clang++ -I/Library/Frameworks/R.framework/Resources/include -DNDEBUG  -I/usr/local/include -I/usr/local/include/freetype2 -I/opt/X11/include  -I"/Users/kevin/Library/R/3.1/library/Rcpp/include"    -fPIC  -g -O3 -Wall -pedantic -c save-source-cpp.cpp -o save-source-cpp.o
clang++ -dynamiclib -Wl,-headerpad_max_install_names -undefined dynamic_lookup -single_module -multiply_defined suppress -L/usr/local/lib -o sourceCpp_85891.so save-source-cpp.o -F/Library/Frameworks/R.framework/.. -framework R -Wl,-framework -Wl,CoreFoundation

请注意DIR:行。如果我查看其中的内容,我会看到:

> list.files("/var/folders/tm/5dt8p5s50x58br1k6wpqnwx00000gn/T//RtmppARq3j/sourcecpp_1b612a59c474")
[1] "save-source-cpp.cpp"   "save-source-cpp.cpp.R" "save-source-cpp.o"     "sourceCpp_29322.so" 

如果我读了(修改过的)cpp文件,我看到:

> cat(readLines("/var/folders/tm/5dt8p5s50x58br1k6wpqnwx00000gn/T//RtmppARq3j/sourcecpp_1b612a59c474/save-source-cpp.cpp"), sep = "\n")
#include <Rcpp.h>
using namespace Rcpp;

// Below is a simple example of exporting a C++ function to R. You can
// source this function into an R session using the Rcpp::sourceCpp
// function (or via the Source button on the editor toolbar)

// For more on using Rcpp click the Help button on the editor toolbar

// [[Rcpp::export]]
int timesTwo(int x) {
   return x * 2;
}


#include <Rcpp.h>

RcppExport SEXP sourceCpp_2047_timesTwo(SEXP xSEXP) {
BEGIN_RCPP
    SEXP __sexp_result;
    {
        Rcpp::RNGScope __rngScope;
        Rcpp::traits::input_parameter< int >::type x(xSEXP );
        int __result = timesTwo(x);
        PROTECT(__sexp_result = Rcpp::wrap(__result));
    }
    UNPROTECT(1);
    return __sexp_result;
END_RCPP
}

所以我们所做的就是使用可以理解常规函数接口的.Call接口生成包装函数。

如果要在某处保存该文件,可以使用capture.output(sourceCpp(..., verbose = TRUE))然后解析DIR:输出并从那里开始。

但严重的是,只需制作一个包裹。

答案 1 :(得分:2)

由于未回答此问题,因此仍然是我的Google的第一个热门内容,因此请重新激活它。

我在文件f1.cpp中保存了R函数的C版本。我(和操作员)想要的是sourceCpp("f1.cpp")的结果,即文件f1.so隐藏在通过函数cacheDir的参数sourceCpp定义的临时文件夹中。

但是,如果我将cacheDir=/my/path设置为自己选择的导演,则仍然会创建临时目录,并且结果不会保存为/my/path/f1.so,而是保存为/my/path/sourceCpp-x86_64-pc-linux-gnu-1.0.1/sourcecpp_2db138ae3a0c/sourceCpp_2.so

这很麻烦,因为我现在必须

  1. 找到并mv /my/path/asd/asd/sourceCpp_2.so /my/path/f1.so
  2. 在R脚本中添加相当复杂的行,在该脚本中应最终使用C版本的函数:
f1 <- Rcpp:::sourceCppFunction(function(arg1, arg2) {},
                               isVoid=F, dll=dyn.load("my/path/f1.so"),
                               symbol='sourceCpp_1_f1') # from the generated file f1.cpp.R
res <- f1(arg1, arg2)
  1. 最后,我可以将定义明确的/my/path及其所有内容添加到我正在从事的项目中(例如git *)。

我看不出“包装”是如何解决这个问题的。

答案 2 :(得分:1)

在进行学术研究时,我也喜欢sourceCpp的灵活性。在许多情况下,编写程序包对我们来说太多了。我一直在使用以下保存共享库的sourceCpp包装器。

importCpp <- function(infile, output_dir="lib", rebuild=FALSE){
    output_dir = ifelse(is.null(output_dir), ".", output_dir)
    dir.create(output_dir, recursive=T, showWarnings=FALSE)
    outfile = file.path(output_dir, paste0(infile, ".R"))

    if (!file.exists(outfile) || file.info(infile)$mtime > file.info(outfile)$mtime || rebuild){
        Rcpp::sourceCpp(infile, rebuild=rebuild)
        context = .Call("sourceCppContext", PACKAGE = "Rcpp",
            normalizePath(infile, winslash = "/"), code=NULL, 0L, .Platform)
        scriptfile = file.path(context$buildDirectory, context$rSourceFilename)
        content = readLines(scriptfile)
        ext = .Platform$dynlib.ext
        m = regexpr(paste0("(?<=dyn.load\\(').*", ext), content[1], perl=TRUE)
        shlibfile = file.path(output_dir, paste0(infile, ext))
        shlibfile0 = regmatches(content[1], m)
        content[1] = sub(shlibfile0, shlibfile, content[1])

        f = file(outfile, "w+")
        writeLines(content, f)
        close(f)
        file.copy(shlibfile0, shlibfile, overwrite=TRUE)
    }else{
        source(outfile)
    }
    invisible(outfile)
}

使用代码:

importCpp("foo.cpp")

如果文件未编译,则共享库和R文件foo.cpp.R将复制到当前文件夹下的文件夹lib。但是,如果找到lib\foo.cpp.R,它将获取R文件。

此外,如果foo.cpp被修改,importCpp将在必要时重新编译cpp文件。

答案 3 :(得分:0)

请参阅Rcpp属性小插图,了解如何从一次性文件转换为实验和探索(通过sourceCpp()编译到组织文件 - 使用相同的技术 - 以R喜欢的方式:作为包裹。

这并不难,Rcpp Attributes会帮助你,你会在适当的时候看到优势。您可以从Rcpp.package.skeleton()开始(请参阅其帮助页面)或从现有软件包中复制。

(另外,sourceCpp()使用的临时目录与您拨打sourceCpp()时所使用的R会话所使用的临时目录相同。我们不会进一步混淆。)