Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rcpp: how to keep files generated by sourceCpp?

Tags:

r

rcpp

I use sourceCpp() from the Rcpp package to build a C++ file and call it from R. It seems to generate a temporary directory where it writes the source it compiles, but it removes that directory after building the code. I want to get access to the exact file it is compiling, so that I can see it in my debugger. How can I prevent sourceCpp() from deleting the file it compiles?

like image 316
John Zwinck Avatar asked May 22 '26 09:05

John Zwinck


2 Answers

I also love the flexibility of sourceCpp when doing academic researches. In many situations, writing a package is too much for our purposes. I have been using the following wrapper of sourceCpp which keeps the shared library.

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)
}

To use the code:

importCpp("foo.cpp")

If the file has not beed complied, the shared library and a R file foo.cpp.R will be copied to a folder lib under the current folder. However, if lib\foo.cpp.R is found, it would source the R file.

Also, if foo.cpp is modified, importCpp will recompile the cpp file if necessary.

like image 75
Randy Lai Avatar answered May 25 '26 01:05

Randy Lai


Reactivating this question since it was not answered and it is still my googles first hit.

I have a C version of an R function saved in the file f1.cpp. What I (and the op) want is the result of sourceCpp("f1.cpp"), namely the file f1.so which is hidden in the temporary folder defined via the argument cacheDir of the function sourceCpp.

If, however, I set cacheDir=/my/path to a director of my choice, still, temporary directories are created and the result is not saved as /my/path/f1.so but as /my/path/sourceCpp-x86_64-pc-linux-gnu-1.0.1/sourcecpp_2db138ae3a0c/sourceCpp_2.so.

This is very cumbersome since now I have to

  1. find and mv /my/path/asd/asd/sourceCpp_2.so /my/path/f1.so
  2. add the rather complicated line to the R script where the C version of the function finally shall be used:
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. Finally, I can add the well defined /my/path and all its content to the project I am working on (e.g. git*).

I dont see how "make a package" is an answer to this question.

like image 38
Chris Avatar answered May 24 '26 23:05

Chris