[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