-
-
Notifications
You must be signed in to change notification settings - Fork 208
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
Register native routines automatically within compileAttributes #694
Conversation
Codecov Report
@@ Coverage Diff @@
## master #694 +/- ##
==========================================
- Coverage 89.72% 89.52% -0.21%
==========================================
Files 66 66
Lines 3523 3588 +65
==========================================
+ Hits 3161 3212 +51
- Misses 362 376 +14
Continue to review full report at Codecov.
|
LGTM! If I understand correctly, this means users can implicitly opt-out of Rcpp native routine registration just by making sure they provide their own call to |
Yes, that's right. If they have their own init function then we don't
generate any of the registration code.
However, even in that case if they do `useDynLib(pkgname, .registration =
TRUE)` then we will generate the R wrappers using symbol names rather than
character vectors. This should mean that users who prefer or who have
become accustomed to using the R 3.4 helper function will now get generated
R wrapper functions that correctly bind to the registered routines (i.e.
users that had previously been diligently registering all their routines to
pass CRAN checks were not actually *using* those routines because our
generated code in RcppExports.R was still referring to functions via
character vector rather than symbol.
…On Tue, May 16, 2017 at 12:37 PM, Kevin Ushey ***@***.***> wrote:
LGTM!
If I understand correctly, this means users can implicitly opt-out of Rcpp
native routine registration just by making sure they provide their own call
to R_init_<pkg> somewhere; is that right?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#694 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAGXx9-yxBZ0ZbnARsCCP4uRhC7F2mGlks5r6dDdgaJpZM4NcvyM>
.
|
That sounds like the right behavior to me as well. FWIW from what I understand, the
I think in theory the 'old' way we constructed Rcpp exports would still work fine -- it's only when users fail to provide the |
Yes, that is my understanding as well.
…On Tue, May 16, 2017 at 12:50 PM, Kevin Ushey ***@***.***> wrote:
That sounds like the right behavior to me as well. FWIW from what I
understand, the R_useDynamicSymbols(dllInfo, FALSE) bit implies the
following:
.Call("routine", PACKAGE = "package") # okay
.Call(routine) # okay given R native routine object called 'routine'
.Call("routine") # fail: won't discover routine
I think in theory the 'old' way we constructed Rcpp exports would still
work fine -- it's only when users fail to provide the PACKAGE = argument
will lookup fail. (Of course it's better for us to use the routine wrapper
objects directly)
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#694 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAGXx9YwME1PzBfrt57g_ijMAATobyaRks5r6dO7gaJpZM4NcvyM>
.
|
I am not entirely sure I agree with all of this. For months now, I have been doing two things:
but nothing else. In particular, I did not bother to alter all the "quoted" .Call() uses. I also never overwrote the default I on the boolean in I have the suspicion I am still missing something here. |
Yes, that's all correct. You were setting the table properly to use native symbols however compileAttributes wasn't generating code that actually used the symbols. e.g. in my reticulate example as a result of registering the symbols the following was sitting in the reticulate namespace: reticulate:::reticulate_py_is_none However, when calling "py_is_none" the string based version of lookup rather than the symbol based lookup was being used. Net: all of that registration was really just meeting the requirements of CRAN checks but not actually put into use by the package. The |
I think it is not quite as dire. On one package (anytime, use Rcpp, has FALSE) I hit a "unpleasant many-legged creature" when altering a function signature, running (older) But I think I agree: nicer calls, with the symbol rather than string, are the real goal. Getting there. This is a huge help. Running an RcppArmadillo test now; wonder how to best test this. Probably need to rebuild a few packages with / without the existing |
Yes, R was definitely checking but when it came time to call the function
it was doing string based lookup.
I believe Doug Bates actually suggested this feature like a week after we
came out with Rcpp attributes and we said "good idea, we'll do that later"
(as it turned out much, much later!). His argument was actually about the
performance benefit of just having the pointer in hand vs. having to look
it up with each call, which I think for a frequently called function would
indeed add up.
…On Tue, May 16, 2017 at 1:27 PM, Dirk Eddelbuettel ***@***.*** > wrote:
Net: all of that registration was really just meeting the requirements of
CRAN checks but not actually put into use by the package.
I think it is not quite as dire. On one package (anytime, use Rcpp, has
FALSE) I hit a "unpleasant many-legged creature" when altering a function
signature, running (older) compileAtttributes() and still couldn't -- as
init.c needed an update for the change number of arguments. So *some*
checking was done by R.
But I think I agree: nicer calls, with the *symbol* rather than string,
are the real goal. Getting there.
This is a huge help. Running an RcppArmadillo test now; wonder how to best
test this. Probably need to rebuild a few packages with / without the
existing init.c.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#694 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAGXx9mUnFF0vwnl62qQmYURAcZu-Ee6ks5r6dyQgaJpZM4NcvyM>
.
|
The performance aspect is nice but the delta seems a little marginal from my reading of WRE. Now, I will admit that I got totally confused a few weeks ago over one aspect I couldn't quite remember the details: we added And should we not now push harder for |
And/or do you know a package using |
I don't know of anyone using Rcpp::interfaces and couldn't find any on
GitHub!
I think the idea was if someone was e.g. creating a bunch of lower level
functions that would be useful for other C/C++ codebases they could do
that. In practice though it doesn't seem like people are doing this.
…On Tue, May 16, 2017 at 1:51 PM, Dirk Eddelbuettel ***@***.*** > wrote:
And/or do you know a package using Rcpp::interface() to provide C(++)
code for another package?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#694 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAGXx1JKUdwAJQLHy88MmaQmzy-QZ_fqks5r6eI5gaJpZM4NcvyM>
.
|
Yeah. I have it in RQuantLib, and "more code got generated" (that I sort-of had forgotten about) but I also do not know of a user package ... (And we now have header-only subset of QuantLib in Quantuccia so it is even more moot.) |
First real test: "boom". In g++ -Wl,-S -shared -L/usr/lib/R/lib -Wl,-Bsymbolic-functions -Wl,-z,relro -o anytime.so RcppExports.o anytime.o init.o -L/usr/lib/R/lib -lR
init.o: In function `R_init_anytime':
/home/edd/git/anytime/src/init.c:36: multiple definition of `R_init_anytime'
RcppExports.o:/home/edd/git/anytime/src/RcppExports.cpp:136: first defined here
collect2: error: ld returned 1 exit status
/usr/share/R/share/make/shlib.mk:6: recipe for target 'anytime.so' failed
make: *** [anytime.so] Error 1
ERROR: compilation failed for package ‘anytime’
* removing ‘/usr/local/lib/R/site-library/anytime’
* restoring previous ‘/usr/local/lib/R/site-library/anytime’
edd@max:~/git/anytime(feature/numeric_input_change)$ Quick guess: Maybe because patch currently does not scan C files? |
Necessary to discover R_init_pkgname functions defined within .c files (e.g. init.c)
Good one and yes that was the problem. Just pushed a fix.
…On Wed, May 17, 2017 at 6:46 AM, Dirk Eddelbuettel ***@***.*** > wrote:
First real test: "boom". In anytime, I have src/init.c but Rcpp created
registration in src/RcppExports.cpp too:
g++ -Wl,-S -shared -L/usr/lib/R/lib -Wl,-Bsymbolic-functions -Wl,-z,relro -o anytime.so RcppExports.o anytime.o init.o -L/usr/lib/R/lib -lR
init.o: In function `R_init_anytime':
/home/edd/git/anytime/src/init.c:36: multiple definition of `R_init_anytime'RcppExports.o:/home/edd/git/anytime/src/RcppExports.cpp:136: first defined herecollect2: error: ld returned 1 exit status/usr/share/R/share/make/shlib.mk:6: recipe for target 'anytime.so' failedmake: *** [anytime.so] Error 1ERROR: compilation failed for package ‘anytime’* removing ‘/usr/local/lib/R/site-library/anytime’* restoring previous ***@***.***:~/git/anytime(feature/numeric_input_change)$
Quick guess: Maybe because patch currently does not scan C files?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#694 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAGXx7_VmARhhu2FwM8duSTwhUviiZhuks5r6s_9gaJpZM4NcvyM>
.
|
@jjallaire Actual bug. Using my small-ish / recent-ish RcppQuantuccia package, I removed ~/git/rcppquantuccia(master)$ R CMD INSTALL .
* installing to library ‘/usr/local/lib/R/site-library’
* installing *source* package ‘RcppQuantuccia’ ...
** libs
g++ -std=gnu++11 -I/usr/share/R/include -DNDEBUG -I../inst/include/ -I. -I"/usr/local/lib/R/site-library/Rcpp/include" -I"/usr/local/lib/R/site-library/BH/include" -fpic -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -c RcppExports.cpp -o RcppExports.o
g++ -std=gnu++11 -I/usr/share/R/include -DNDEBUG -I../inst/include/ -I. -I"/usr/local/lib/R/site-library/Rcpp/include" -I"/usr/local/lib/R/site-library/BH/include" -fpic -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -c dates.cpp -o dates.o
g++ -std=gnu++11 -I/usr/share/R/include -DNDEBUG -I../inst/include/ -I. -I"/usr/local/lib/R/site-library/Rcpp/include" -I"/usr/local/lib/R/site-library/BH/include" -fpic -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -c utils.cpp -o utils.o
g++ -std=gnu++11 -shared -L/usr/lib/R/lib -Wl,-Bsymbolic-functions -Wl,-z,relro -o RcppQuantuccia.so RcppExports.o dates.o utils.o -L/usr/lib/R/lib -lR
installing to /usr/local/lib/R/site-library/RcppQuantuccia/libs
** R
** inst
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded
Error: package or namespace load failed for ‘RcppQuantuccia’ in .doLoadActions(where, attach):
error in load action .__A__.1 for package RcppQuantuccia: .Call("RcppQuantuccia_RcppExport_registerCCallable", PACKAGE = "RcppQuantuccia"): "RcppQuantuccia_RcppExport_registerCCallable" not available for .Call() for package "RcppQuantuccia"
Error: loading failed
Execution halted
ERROR: loading failed
* removing ‘/usr/local/lib/R/site-library/RcppQuantuccia’
* restoring previous ‘/usr/local/lib/R/site-library/RcppQuantuccia’
~/git/rcppquantuccia(master)$ Edit 1: The # Register entry points for exported C++ functions
methods::setLoadAction(function(ns) {
.Call('RcppQuantuccia_RcppExport_registerCCallable', PACKAGE = 'RcppQuantuccia')
}) If I comment that out, all is good. Edit 2: And it is caused by the |
Indeed! I think that this mechanism has broken the aforementioned
Rcpp::interfaces(cpp) which you must be using in this package. I'll fix
this tomorrow AM.
…On Wed, May 17, 2017 at 4:21 PM, Dirk Eddelbuettel ***@***.*** > wrote:
@jjallaire <https://github.com/jjallaire> Actual bug. Using my small-ish
/ recent-ish RcppQuantuccia package, I removed src/init.c and called
compileAttribute(). The RcppExports where updated, but:
~/git/rcppquantuccia(master)$ R CMD INSTALL .* installing to library ‘/usr/local/lib/R/site-library’* installing *source* package ‘RcppQuantuccia’ ...** libs
g++ -std=gnu++11 -I/usr/share/R/include -DNDEBUG -I../inst/include/ -I. -I"/usr/local/lib/R/site-library/Rcpp/include" -I"/usr/local/lib/R/site-library/BH/include" -fpic -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -c RcppExports.cpp -o RcppExports.o
g++ -std=gnu++11 -I/usr/share/R/include -DNDEBUG -I../inst/include/ -I. -I"/usr/local/lib/R/site-library/Rcpp/include" -I"/usr/local/lib/R/site-library/BH/include" -fpic -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -c dates.cpp -o dates.o
g++ -std=gnu++11 -I/usr/share/R/include -DNDEBUG -I../inst/include/ -I. -I"/usr/local/lib/R/site-library/Rcpp/include" -I"/usr/local/lib/R/site-library/BH/include" -fpic -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -c utils.cpp -o utils.o
g++ -std=gnu++11 -shared -L/usr/lib/R/lib -Wl,-Bsymbolic-functions -Wl,-z,relro -o RcppQuantuccia.so RcppExports.o dates.o utils.o -L/usr/lib/R/lib -lR
installing to /usr/local/lib/R/site-library/RcppQuantuccia/libs** R** inst** preparing package for lazy loading** help*** installing help indices** building package indices** testing if installed package can be loaded
Error: package or namespace load failed for ‘RcppQuantuccia’ in .doLoadActions(where, attach):
error in load action .__A__.1 for package RcppQuantuccia: .Call("RcppQuantuccia_RcppExport_registerCCallable", PACKAGE = "RcppQuantuccia"): "RcppQuantuccia_RcppExport_registerCCallable" not available for .Call() for package "RcppQuantuccia"
Error: loading failed
Execution halted
ERROR: loading failed* removing ‘/usr/local/lib/R/site-library/RcppQuantuccia’* restoring previous ‘/usr/local/lib/R/site-library/RcppQuantuccia’~/git/rcppquantuccia(master)$
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#694 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAGXx5wK6fBL3vhgzKPjIyhb_MeWC2n6ks5r61bOgaJpZM4NcvyM>
.
|
Just pushed a fix (and tested it with RcppQuantuccia). There's one more lingering issue: if users of attributes are combining that with exporting C/C++ functions without attributes then our current code generation won't pick that up. I don't know if that scenario exists as a practical matter but it seems like somewhere in the wild it must. We have a couple different options here:
I think option (1) vs. option (2+3) are about the same amount of work. I probably favor (1). |
Thanks for the fix, will test. I like 1) and was surprised you didn't go calling it directly. Shall we enable that more generally, or 'just' in the case of exported functions? |
…e to discover and register additional non-Rcpp exported native routines
I implemented (1) so this case should now be covered. The reason I didn't have R do all of the code generation is that it generates different code (assumes it's in a .c rather than .cpp file) and we may need to eventually inject additional code into the init function (e.g. imagine a package author wants our generated registration but also wants to run some code on init, we could scan for the definition of Rcpp_init_pkgname and then call it from R_init_pkgname if it exists). Calling R from this spot within code generation also won't find the definitions in RcppExports.R since they haven't yet been written (i.e. we'd need to always inject them into the generated R code, so easier to just generate our own code in the first place). |
Ahh. I see now. This should be good to merge then. |
Re Rcpp::interfaces: I'm actually using it for plogr (logging) and bindrcpp (creating/populating environments with bindings that call a C++ functiion). |
There are two main components here:
Use the metadata that we already have within
compileAttributes
to automatically emit a package init function that registers all exported C++ functions with R viaR_registerRoutines
.Note that users have been doing this manually for several months and some packages may already have an init function for other reasons. Consequently, we only do automatic registration if no existing package init function is found.
Registering native functions and calling
useDynLib(foo, .registration = TRUE)
is actually not sufficient to have R wrappers bind to the registered routines. To do that we actually need to generate this code:Rather than this code:
Note that we only want to generate the former code when the user has included
.registration = TRUE
(otherwise the routines won't be present in the package namespace). As a result, we scan theNAMESPACE
file foruseDynLib(pkgname, .registration = TRUE)
and only generate R wrappers of that form if it's found.Relevant documentation from Writing R Extensions is here: https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Registering-native-routines
Of particular interest is the bit about
R_useDynamicSymbols(info, FALSE)
. My reading of this is that by calling this you are saying that it still okay to to use this syntax:However, only if the symbol has been registered. This is important for us because we are now going to always pass
FALSE
toR_useDynamicSymbols
, and we don't want that to break packages that in turn neglect to pass.registration = TRUE
touseDynLib
. Since we register all the Rcpp exported functions they will work using either the character based or symbol based.Call
lookup.This branch of the reticulate package demonstrates the change in code generation that occurs:
https://github.com/rstudio/reticulate/compare/feature/register-native-routines
Note that we've changed our
@useDynLib
roxygen to:And that we've removed entirely the
init.cpp
file previously provided as a stub to pass CRAN tests.