[Rcpp-devel] namespace problems in adding C++ to an R project that already uses R

Daniel Kelley Dan.Kelley at Dal.Ca
Sat Mar 3 21:42:17 CET 2018


Thanks very much, Dirk.  I've got things working now, thanks to your help.  Part of my problem was slurring together @export and [[Rcpp::export]].

I really appreciate the help.

Dan.



> On Mar 3, 2018, at 12:25 PM, Dirk Eddelbuettel <edd at debian.org> wrote:
> 
> 
> On 3 March 2018 at 15:57, Daniel Kelley wrote:
> | Short version: are there any docs on namespace difficulties that might be
> | encountered whilst adding C++ to an R project that already uses C?
> 
> In short, yes.
> 
> It has to do with the symbol autogeneration _and registration_ we support
> since last year when R changed in that space and made it (essentially)
> mandatory to the registration.
> 
> But now you can now run into issues.  The easiest way is (personal view here)
> to just be explicit: if and when I would now have two symbols like your
> trap(), I preemptively declare the C(++) version trap_impl(), keep the '//
> [[Rcpp::export]]' so that it is callable but generally do not export it via
> NAMESPACE (and hence do document it in Rd). The last two are optional -- you
> could just export to R as well and alias in the help page but then users may
> get confused. And I then call the trap_impl() function in another R function
> trap() which I document.  [ That scheme is sometimes easiest for argument
> checks etc which are easier in R than in C++, and generally not time
> critical. ]
> | 
> | Long version (and I really do apologize for the length).
> | 
> | I am trying to convert some of the C in my biggish package ("oce", 70 kloc R
> | and 7 kloc C) from C to C++, because I think that will be easier for users to
> | work with, if they run into trouble and cannot contact me quickly.
> | 
> | The package is pretty old, and although I use roxygen for manpages, I wrote
> | NAMESPACE manually; it has
> 
> That's DESCRIPTION, actually.
> 
> | ```
> | LinkingTo: Rcpp
> | Imports: Rcpp
> | ```
> | 
> | as I think is required, for using Rcpp.
> | 
> | So far, I'm working with just a single function, named "trap" (for trapeziodal
> | integration), and it starts as below.
> | 
> | ```
> | #include <Rcpp.h>
> | using namespace Rcpp;
> | 
> | //' trapezoidal integration
> | //'
> | //' This is an interface to C++ code.
> | //' @param x vector of x values
> | //' @param y vector of y values
> | //' @param type number indicating type, 0, 1 or 2
> | //' @export
> | // [[Rcpp::export]]
> | NumericVector trap(NumericVector x, NumericVector y, NumericVector type)
> | {
> | ```
> | 
> | Building in Rstudio causes src/RcppExports.cpp to be created as below.  *NOTE:
> | there is no created code relating to CallEntries or R_init_oce, both of which I
> | see (the latter analogously) being defined when I make an Rcpp skeleton
> | project, and I think this may be close to the heart of the problem.*
> | 
> | ```
> | // Generated by using Rcpp::compileAttributes() -> do not edit by hand
> | // Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
> | 
> | #include <Rcpp.h>
> | 
> | using namespace Rcpp;
> | 
> | // trap
> | NumericVector trap(NumericVector x, NumericVector y, NumericVector type);
> | RcppExport SEXP _oce_trap(SEXP xSEXP, SEXP ySEXP, SEXP typeSEXP) {
> | BEGIN_RCPP
> |     Rcpp::RObject rcpp_result_gen;
> |     Rcpp::RNGScope rcpp_rngScope_gen;
> |     Rcpp::traits::input_parameter< NumericVector >::type x(xSEXP);
> |     Rcpp::traits::input_parameter< NumericVector >::type y(ySEXP);
> |     Rcpp::traits::input_parameter< NumericVector >::type type(typeSEXP);
> |     rcpp_result_gen = Rcpp::wrap(trap(x, y, type));
> |     return rcpp_result_gen;
> | END_RCPP
> | }
> | ```
> | 
> | With things established as the above, the package builds without error, and I can do
> | 
> | ```
> | .Call("_oce_trap", x, y, type)
> | ```
> | 
> | which works fine.
> 
> You would normally not need this as you would get a caller trap()
> autogenerated.  That may not happen here as you already had one.
> 
> | ```
> | .Call(`_oce_trap`, x, y, type)
> | ```
> | (as in the auto-generaged code in R/RcppExports.R) fails with
> | 
> | ```
> | Error: object '_oce_trap' not found
> | ```
> | 
> | Of course, the R code that gets written automatically also fails, because it
> | uses `oce_trap`.
> | 
> | The thing is, I am happy to use .Call() and the above would not be a problem, but there
> | is an autogenerated trap() function in R, and it uses the backtick form and therefore
> | devtools::check() gives a NOTE on the package, which I certainly do not want.
> 
> That is what the Rcpp::exports tag does for you. The alternative is to do as
> you do, _manually_ generate the wrapper as you did and to forgo the
> autogeneration.  I don't usually work this way, and I am not sure if this
> does or does not generate the init stib for you.
> 
> In what I describe above, I let R create an trap_impl() R wrapper for me, but
> don't export or document that one.
> 
> | Since I noticed that the autogenerated src/RcppExports.cpp
> | lacked anything about CallEntries or R_init_oce, I edited my existing
> | src/registerDynamicSymbol.c file, in which I had registered symbols for my
> | C code.  That file now looks like the following. Here, the CallEntries definition is new,
> 
> There is a safety aspect. If you had a manual one, it will not create a new
> one/ automatically which could overwrite yours.
> 
> Often you are better off deleting you old one and letting it autogenerated.
> Maybe try that in another branch.
> 
> | as is the extern and also the third argument to R_registerRoutines(), which was 
> | NULL when I was just using C.
> | 
> | ```
> | #include <R.h>
> | #include <Rinternals.h>
> | #include <R_ext/Rdynload.h>
> | 
> | extern SEXP _oce_trap(SEXP, SEXP, SEXP);
> | 
> | static const R_CallMethodDef CallEntries[] = {
> |     {"_oce_trap", (DL_FUNC) &_oce_trap, 3},
> |     {NULL, NULL, 0}
> | };
> | 
> | void R_init_oce(DllInfo* info) {
> |     R_registerRoutines(info, NULL, CallEntries, NULL, NULL);
> |     R_useDynamicSymbols(info, TRUE);
> | }
> | ```
> | 
> | Well, the above is a sketch of what I think are salient details. I am not
> | entirely sure, but it seems to me that `_oce_trap` ought to accessible with
> | .Call(). But it's not, and since this backtick notation is used in
> | autogenerated R code, I am stuck with devtools::check() NOTEs that worry
> | me.
> 
> I don't use devtools. What matters is what R CMD check says.  Which may be
> the same, I don't know.
> 
> | My guess is that a lot of my setup will be similar to that of projects using C that are more
> | than perhaps 5 years old. I realize that my setup is a bit of a hodge-podge, docs created
> | by roxygen2 but NAMESPACE hand-rolled, so that might make this different from
> | the setup in other packages.
> | 
> | I wonder if anyone else has got into similar difficulties in trying to add C++
> | to an R project that already uses C. If so, any hints would be greatly
> | appreciated!
> | 
> | Again, I'm sorry for the length of this. I hope to have been complete enough to
> | describe the problem, though.
> 
> No worries That was an exceptionally clear (if long) email, you really did
> get to the bottom of most if these things, and yes, some of us had similar
> transition woes when the registration scheme changed last year.  You are very
> close.  Hopefully my sketches above will get you closer.
> 
> Cheers, Dirk
> 
> -- 
> http://dirk.eddelbuettel.com | @eddelbuettel | edd at debian.org



More information about the Rcpp-devel mailing list