[Rd] How to call directly "dotTcl" C-function of the tcltk-package from the C-code of an external package?
Reijo Sund
re|jo@@und @end|ng |rom ue|@||
Wed May 29 00:25:54 CEST 2024
I have a use case with tcltk-package where I need to repeatedly call Tcl/Tk functions
very quickly. For such purpose, the standard R-interface turned out to be too slow, and
better option has been to call package's C-function dotTcl directly from my own C-code.
Before R 4.4.0 it was possible to use getNativeSymbolInfo("dotTcl","tcltk")$address (or
R_FindSymbol("dotTcl","tcltk",NULL) in C) to get the function-pointer and then call the
function directly, even though it has not been registered as C-callable for other
packages.
With R 4.4.0 these methods are unable to find the symbol anymore (tested in Linux).
I was not able to find what change has caused this new behaviour.
Taking a look at tcltk source code, it can be seen that the dotTcl is called using
.External within tcltk-package and there is a registration done for it with
R_registerRoutines. An object of class NativeSymbolInfo has also been created in the
tcltk namespace, and that can be accessed using tcltk:::.C_dotTcl.
However, the tcltk:::.C_dotTcl$address is an external pointer of a class
RegisteredNativeSymbol and not directly the function pointer to the actual routine. The
problem is that there appears not to be any R-level function that would extract the actual
function-pointer and that the C-interface for R_RegisteredNativeSymbol has been defined
in the internal Rdynpriv.h header that is not included in the public API headers.
The only way I was able to access the function directly was using the following C-level
approach in which essential parts of the headers are copied from the Rdynpriv.h:
#include <R.h>
#include <Rinternals.h>
#include <R_ext/Rdynload.h>
typedef struct {
char *name;
DL_FUNC fun;
int numArgs;
R_NativePrimitiveArgType *types;
} Rf_DotCSymbol;
typedef Rf_DotCSymbol Rf_DotFortranSymbol;
typedef struct {
char *name;
DL_FUNC fun;
int numArgs;
} Rf_DotCallSymbol;
typedef Rf_DotCallSymbol Rf_DotExternalSymbol;
struct Rf_RegisteredNativeSymbol {
NativeSymbolType type;
union {
Rf_DotCSymbol *c;
Rf_DotCallSymbol *call;
Rf_DotFortranSymbol *fortran;
Rf_DotExternalSymbol *external;
} symbol;
};
SEXP(*direct_dotTcl)(SEXP) = NULL;
SEXP FindRegFunc(SEXP symbol) {
R_RegisteredNativeSymbol *tmp = NULL;
tmp = (R_RegisteredNativeSymbol *) R_ExternalPtrAddr(symbol);
if (tmp==NULL) return R_NilValue;
direct_dotTcl = (SEXP(*)(SEXP)) tmp->symbol.external->fun;
return R_NilValue;
}
Although that works for me, I'm aware that this kind of approach is certainly not
recommmended for publicly available external packages. However, I couldn't find any
other more legitimate way to access dotTcl function directly from my C-code in R 4.4.0.
I have two questions:
Would it be possible to get dotTcl C-function (in tcltk.c) of the tcltk-package
registered as C-callable from other packages?
Was it an intentional change that caused the hiding of the earlier visible (registered)
symbols from other packages?
More information about the R-devel
mailing list