user2667066
user2667066

Reputation: 2099

Alternative library functions (including C++ code) assigned during .onLoad in R package

I am building an R package using devtools which uses a single function (say f()) from another package (say pkg_X). But pkg_X is pretty heavyweight, and depends on all sorts of graphical libraries which aren't needed for the function I want. However, it's distributed under MIT, so I can pull out the functions needed and stick them into my package.

My reasoning is, however, that this isn't needed if the user has already installed pkg_X for some other reason. So what I want to do is to check for require("pkg_X") during the .onLoad() function of my package, and if it fails, define my own version of f().

An additional problem is that f() also depends on some C++ code which can be accessed using Rcpp::sourceCpp(). So at the moment in the .onLoad function I'm doing something like this (copied from https://community.rstudio.com/t/build-package-namespace-dynamically-during-onload/4101 )

## for NAMESPACE exporting
f <- NULL
cpp_func <- NULL

.onLoad <- function(lib, pkg, ...) {
  if (!suppressWarnings(require("pkg_X", character.only = TRUE))) {
    require(Rcpp)
    sourceCpp("alt_dir/mycppfile.cpp") #defines cpp_func()
    cpp_func <<- cpp_func #make globally accessible
    source("alt_dir/my_r_code.R") #defines f()
    f <<- f #make globally accessible
  }
}

Where mycppfile.cpp and my_r_code.R are present in an alt_dir directory in my package space.

I'm sure this is wrong - for example, when I do devtools::install("my_package") on my mac, it works for the time being, but doesn't install the mycppfile.cpp and my_r_code.R files into the right place, so that library(my_package) fails.

What is the right way to do this? I've not done any package development in R before, so I suspect I'm doing something silly.

Upvotes: 0

Views: 59

Answers (1)

Ralf Stubner
Ralf Stubner

Reputation: 26823

I suggest adding both my_r_code.R and mycppfile.cpp to your R package. Let them define functions my_f and my_cpp_func that are not exported.

Next I would add two wrapper functions wrap_f and wrap_cpp_func to the package that just do something like this:

wrap_f <- function(...) {
  if (require("pkg_X", quiet = TRUE)) {
    pkg_X::f(...)
  else {
    my_f(...)
  }
}

I find that easier to understand.

Upvotes: 2

Related Questions