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

Dirk Eddelbuettel edd at debian.org
Sat Mar 3 17:25:59 CET 2018


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