Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
mlysy opened this issue Jul 17, 2018 · 4 comments
Closed

Comments

@mlysy
Copy link
Contributor

mlysy commented Jul 17, 2018

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
@eddelbuettel
Copy link
Member

Well, Rcpp Modules being what it is this may not change any time soon as nobody is really working on it.

@mlysy
Copy link
Contributor Author

mlysy commented Jul 18, 2018

I see. I can try to dig deeper. Would you be willing to consider a possible PR?

@eddelbuettel
Copy link
Member

Absolutely. We are always open to quality work. Not saying hacking Modules is easy, but you are probably already deeper in it that us :)

@eddelbuettel
Copy link
Member

This can be closed too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants