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?

______________________________________________
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel

Reply via email to