Search code examples
rcpackagenamespaces

.C() function from spatstat.geom package not available in R, although it is exported by useDynLib


The CRAN R-package spatstat.geom defines a bunch of .C functions, and exports them in the NAMESPACE file via

useDynLib(spatstat.geom, .registration=TRUE, .fixes="SG_")

Yet I cannot access these functions with the usual .C syntax. For instance, the nncross.ppp() function contains a call to

.C(SG_knnXinterface, ..., PACKAGE = "spatstat.geom"),

which obviously works inside the spatstat.geom, but not outside of it, unlike for other functions exporting their C-functions in apparently the same way. My questions are:

  1. How can I access these C-functions from the console?
  2. Is this related to the "nested" package structure of the spatstat.* packages?

I tried to call

.C(SG_knnXinterface, ..., PACKAGE = "spatstat.geom")

but it returned

Error in .C("SG_nnXinterface", PACKAGE = "spatstat.geom", 2) : "SG_nnXinterface" not available for .C() for package "spatstat.geom",

even though I would expect the C function to be accessible in this way.

Some minimal reproducible examples:

Works (or at least function is found)

.C("spline_value", PACKAGE = "cobs")

Does not work

.C("SG_nnXinterface", PACKAGE = "spatstat.geom")

My sessionInfo():

R version 4.3.2 (2023-10-31)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 22.04.3 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.10.0 
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.10.0

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=de_BE.UTF-8       
 [4] LC_COLLATE=en_US.UTF-8     LC_MONETARY=de_BE.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=de_BE.UTF-8       LC_NAME=C                  LC_ADDRESS=C              
[10] LC_TELEPHONE=C             LC_MEASUREMENT=de_BE.UTF-8 LC_IDENTIFICATION=C       

time zone: Europe/Amsterdam
tzcode source: system (glibc)

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] spatstat.geom_3.2-7.007 spatstat.data_3.0-4    

loaded via a namespace (and not attached):
[1] compiler_4.3.2       deldir_2.0-2         Matrix_1.6-5         spatstat.utils_3.0-4
[5] tools_4.3.2          grid_4.3.2           polyclip_1.10-6      lattice_0.22-5

Solution

  • This is about "native registration" of entry points, a relatively new feature of R. The spatstat packages use native registration, while package cobs apparently does not.

    The namespace declaration

    UseDynLib(spatstat.geom, registration=TRUE, fixes="SG_")
    

    tells the package loader to dynamically load the object file spatstat.geom.so, and (because registration=TRUE) to look for a C function called R_spatstat_geom_init which the author of spatstat.geom must have written. The loader executes this function, which effectively declares all the available C or C++ functions to the R system, associating their string names with their actual entry points in the compiled object code, and declaring the number and type of arguments. Then for each declared C or C++ function, the loader will create a "symbol" in the R language associated with it. Because a prefix "SG_" was specified, the function nnXinterface defined in the C code will be associated with a symbol SG_nnXinterface. There are no quotes around the symbol. The symbol is added to the namespace of the package.

    If you wanted to use the R command .C to execute the function nnXinterface, you need to get access to the symbol SG_nnXinterface. The symbols are not exported from the package, but they are there in ghe namespace, e.g.

    spatstat.geom:::SG_nnXinterface
    

    will return some information. I'm not sure how to access these symbols in a way that will be acceptable to the R package checker. It will certainly require that spatstat.geom is already loaded.

    If you want to call the C function nnXinterface from some other C code, then you could either (a) just copy the source code for nnXinterface into your own package, or (b) figure out how to access the source code from another package, which again may run into issues with the package checker.