I want to build an Rcpp package with C++ and R code. With the C++ code only (R code removed), everything compiles and works nicely and after building and loading the exported functions are callable as expected as
<packageName>::<functionName>()
However, when including the R code with the call to the C++ code, I get an object not found error when building the package:
R CMD build <packageName>
[...]
** R
** byte-compile and prepare package for lazy loading
Error in <functionName>() :
object '_<packageName>_<functionName>' not found
Error: unable to load R code in package '<packageName>'
The error happens after the C++ code is successfully compiled.
<functionName>()
is mapped to
_<packageName>_<functionName>
in R/RcppExports.R
as usual, but it does not appear that it can be loaded by the R code at build time.
The structure of the package is as usual:
<packageName>
├── DESCRIPTION
├── man
│ ├── <functionName>.rd
│ └── <packageName>-package.rd
├── NAMESPACE
├── R
│ ├── <RCodeFileName>.R
│ └── RcppExports.R
├── README.md
└── src
├── <C++CodeFileName>.cpp
├── <C++CodeFileName>.o
├── <packageName>.so
├── RCppExports.cpp
├── RCppExports.o
└── symbols.rds
where the .o
and .so
files are produced when compiling the package.
The R file calls the function from the C++ file directly:
[other stuff]
[...]
<functionName>()
NAMESPACE
file is also as usual:
useDynLib(<packageName>, .registration=TRUE)
importFrom(Rcpp, evalCpp)
exportPattern("^[[:alpha:]]+")
This seems like a very simple and straight forward problem (calling C++ code from R code in an Rcpp package). Nevertheless, I seem to be unable to find any indication of how this should be done.
Edit (Apr 8 2020): build
vs. INSTALL
The problem will occur in every case for
R CMD INSTALL <packageName>_<version>.tar.gz
If the included help file
man/<packageName>-package.Rd
is built so that it forces installing the package to process help pages
the error will already occur in
R CMD build <packageName>
as described above.
Edit (Apr 8 2020): Steps to reproduce with Rcpp.package.skeleton()
(on Unix-like systems anyway)
Rscript -e 'Rcpp::Rcpp.package.skeleton("demo20200408")'
echo 'rcpp_hello_world()' > errorDemo/R/example.R
R CMD INSTALL errorDemo
You may want to slow dowm. The Rcpp package itself comes with a demo package generator via the Rcpp.package.skeleton()
function. Run it!
The compare piece by piece to what you have.
A second generator is e.g. built into RStudio and available under the File -> New Project -> New directory -> Package with Rcpp menu options.
Otherwise, hard to tell. Did you do anything funky to you function name? Because these are mapped to R and C++ you have restrictions from both. I.e. you cannot use a dot (as that would be a class method notation in C++).
Lastly, even when unexported the C++ function should be available from the installed and loaded package via three colons, i.e. mypkg:::myFun()
.
Lastly, quick demo:
Create itedd@rob:/tmp$ Rscript -e 'Rcpp::Rcpp.package.skeleton("demo20200408")'
Creating directories ...
Creating DESCRIPTION ...
Creating NAMESPACE ...
Creating Read-and-delete-me ...
Saving functions and data ...
Making help files ...
Done.
Further steps are described in './demo20200408/Read-and-delete-me'.
Adding Rcpp settings
>> added Imports: Rcpp
>> added LinkingTo: Rcpp
>> added useDynLib directive to NAMESPACE
>> added importFrom(Rcpp, evalCpp) directive to NAMESPACE
>> added example src file using Rcpp attributes
>> added Rd file for rcpp_hello_world
>> compiled Rcpp attributes
edd@rob:/tmp$
Install it
edd@rob:/tmp$ R CMD INSTALL demo20200408
* installing to library ‘/usr/local/lib/R/site-library’
* installing *source* package ‘demo20200408’ ...
** using staged installation
** libs
ccache g++ -I"/usr/share/R/include" -DNDEBUG -I"/usr/local/lib/R/site-library/Rcpp/include" -fpic -g -O3 -Wall -pipe -pedantic -c RcppExports.cpp -o RcppExports.o
ccache g++ -I"/usr/share/R/include" -DNDEBUG -I"/usr/local/lib/R/site-library/Rcpp/include" -fpic -g -O3 -Wall -pipe -pedantic -c rcpp_hello_world.cpp -o rcpp_hello_world.o
ccache g++ -Wl,-S -shared -L/usr/lib/R/lib -Wl,-Bsymbolic-functions -Wl,-z,relro -o demo20200408.so RcppExports.o rcpp_hello_world.o -L/usr/lib/R/lib -lR
installing to /usr/local/lib/R/site-library/00LOCK-demo20200408/00new/demo20200408/libs
** R
** byte-compile and prepare package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded from temporary location
** checking absolute paths in shared objects and dynamic libraries
** testing if installed package can be loaded from final location
** testing if installed package keeps a record of temporary installation path
* DONE (demo20200408)
edd@rob:/tmp$
Run it
edd@rob:/tmp$ Rscript -e 'library(demo20200408); rcpp_hello_world()'
[[1]]
[1] "foo" "bar"
[[2]]
[1] 0 1
edd@rob:/tmp$
And add an R function and call it too
edd@rob:/tmp$ echo 'r_hello_world <- function() cat("hi there\n")' > demo20200408/R/foo.R
edd@rob:/tmp$ R CMD INSTALL demo20200408
* installing to library ‘/usr/local/lib/R/site-library’
* installing *source* package ‘demo20200408’ ...
** using staged installation
** libs
make: Nothing to be done for 'all'.
installing to /usr/local/lib/R/site-library/00LOCK-demo20200408/00new/demo20200408/libs
** R
** byte-compile and prepare package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded from temporary location
** checking absolute paths in shared objects and dynamic libraries
** testing if installed package can be loaded from final location
** testing if installed package keeps a record of temporary installation path
* DONE (demo20200408)
edd@rob:/tmp$ Rscript -e 'library(demo20200408); r_hello_world()'
hi there
edd@rob:/tmp$
Still no issue despite OP's claims
In the most recent comment below it is claimed that the generated function cannot be called. That is false.
edd@rob:/tmp$ editor demo20200408/R/foo.R # subst. fave editor here
edd@rob:/tmp$ cat demo20200408/R/foo.R
r_hello_world <- function() {
cat("hi there\n")
ignored <- rcpp_hello_world()
NULL
}
edd@rob:/tmp$ R CMD INSTALL demo20200408
* installing to library ‘/usr/local/lib/R/site-library’
* installing *source* package ‘demo20200408’ ...
** using staged installation
** libs
make: Nothing to be done for 'all'.
installing to /usr/local/lib/R/site-library/00LOCK-demo20200408/00new/demo20200408/libs
** R
** byte-compile and prepare package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded from temporary location
** checking absolute paths in shared objects and dynamic libraries
** testing if installed package can be loaded from final location
** testing if installed package keeps a record of temporary installation path
* DONE (demo20200408)
edd@rob:/tmp$ Rscript -e 'library(demo20200408); r_hello_world()'
hi there
NULL
edd@rob:/tmp$