Skip to content

Rcpp::exposeClass doesn't work with different class and CppClass arguments #879

@mlysy

Description

@mlysy

Here is a minimal example. First consider a simple C++ class defined in foo.h:

#ifndef foo_h
#define foo_h 1

// class to set/get a scalar double
class foo {
 private:
  double x;
 public:
  double get_x() {return x;}
  void set_x(double _x) {x = _x; return;}
  foo(double _x) {set_x(_x);}
};

#endif

Now let's create an R package exporting the class as an Rcpp module:

options(useFancyQuotes = FALSE) # Rcpp::exposeClass uses dQuote
pkg_path <- getwd() # where to create package
pkg_name <- "ModuleLoadTest" # name of package
pkg_dir <- file.path(pkg_path, pkg_name) # package root directory
# create package set up to export Rcpp modules
Rcpp::Rcpp.package.skeleton(name = pkg_name,
                            path = pkg_path,
                            force = TRUE,
                            example_code = FALSE, module = TRUE)
# remove module sample code
file.remove(list.files(file.path(pkg_dir, c("src", "R")),
                       full.names = TRUE))
# add foo header file to package (assuming foo.h is in current directory)
file.copy(from = "foo.h", to = file.path(pkg_dir, "src", "foo.h"))

Finally to wrap the class into a module. First with the R and C++ classes both named foo, which works as expected:

Rcpp::exposeClass(class = "foo",
                  constructors = list("double"),
                  fields = character(),
                  methods = c("get_x", "set_x"),
                  header = '#include "foo.h"',
                  CppClass = "foo",
                  file = file.path(pkg_dir, "src", "fooModule.cpp"),
                  Rfile = file.path(pkg_dir, "R", "fooClass.R"))
devtools::install(pkg_dir) # install package
# simple unit test for getter/setter
bar <- ModuleLoadTest::foo(0) # create object
replicate(n = 10, {
  x <- rnorm(1)
  bar$set_x(x)
  bar$get_x() - x
}) # should return an array of zeros

However, when I change class = "foo" to class = "fooR" in the above, and rerun devtools:install (also checked with R CMD install and with CRAN and GitHub versions of Rcpp), I get the following output/error message:

Installing ModuleLoadTest
'/Library/Frameworks/R.framework/Resources/bin/R' --no-site-file --no-environ  \
  --no-save --no-restore --quiet CMD INSTALL  \
  '/Users/mlysy/Documents/R/test/class/ModuleLoadTest'  \
  --library='/Users/mlysy/Documents/data/R/library' --install-tests 

* installing *source* packageModuleLoadTest...
** libs
/usr/local/opt/llvm/bin/clang++ -arch x86_64 -ftemplate-depth-256 -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG  -I"/Users/mlysy/Documents/data/R/library/Rcpp/include" -I/usr/local/include   -fPIC  -I/usr/local/opt/llvm/include -O3 -ffast-math -mtune=native -march=native -Wno-unused-variable -Wno-unused-function -Wno-pragmas -c fooModule.cpp -o fooModule.o
/usr/local/opt/llvm/bin/clang++ -arch x86_64 -ftemplate-depth-256 -dynamiclib -Wl,-headerpad_max_install_names -undefined dynamic_lookup -single_module -multiply_defined suppress -L/Library/Frameworks/R.framework/Resources/lib -L/usr/local/opt/llvm/lib -o ModuleLoadTest.so fooModule.o -F/Library/Frameworks/R.framework/.. -framework R -Wl,-framework -Wl,CoreFoundation
installing to /Users/mlysy/Documents/data/R/library/ModuleLoadTest/libs
** R
** byte-compile and prepare package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded
Error: package or namespace load failed forModuleLoadTestin .doLoadActions(where, attach):
 error in load action .__A__.1 for package ModuleLoadTest: Rcpp::loadRcppClass(Class = "fooR", CppClass = "foo", where = NS): No object "foo" in module "class_fooR"
Error: loading failed
Execution halted
ERROR: loading failed
* removing/Users/mlysy/Documents/data/R/library/ModuleLoadTest* restoring previous/Users/mlysy/Documents/data/R/library/ModuleLoadTestError: Command failed (1)

It seems that the problem is entirely with R/fooClass.R. That is, if I set Rfile = FALSE in the above and construct the object with bar <- new("fooR", x), install and test both work fine.

Moreover, a small adjustment to R/fooClass.R seems to overcome the issue (at least, for this particular example). Here is the original content of fooClass.R:

fooR <- setRcppClass("fooR", "foo")

If I switch the second argument from foo to fooR, then devtools::install runs without errors and so does the unit test above (via original bar <- ModuleLoadTest::fooR(0)).

Here is the R sessionInfo() after the first call to devtools::install:

R version 3.5.0 (2018-04-23)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS High Sierra 10.13.3

Matrix products: default
BLAS: /Library/Frameworks/R.framework/Versions/3.5/Resources/lib/libRblas.0.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.5/Resources/lib/libRlapack.dylib

locale:
[1] en_CA.UTF-8/en_CA.UTF-8/en_CA.UTF-8/C/en_CA.UTF-8/en_CA.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

loaded via a namespace (and not attached):
[1] compiler_3.5.0  tools_3.5.0     withr_2.1.2     memoise_1.1.0  
[5] Rcpp_0.12.17    pkgKitten_0.1.4 git2r_0.21.0    digest_0.6.15  
[9] devtools_1.13.5

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions