It is possible to write R extensions in Nim. Here is a rather useless example:
type sexptype = cuint
const realsxp = 14
type sexp {.importc: "SEXP", header: "<Rinternals.h>".} = object
proc protect(s: sexp): sexp
{.importc: "PROTECT", header: "<Rinternals.h>".}
proc unprotect(s: cint)
{.importc: "UNPROTECT", header: "<Rinternals.h>".}
proc allocVector(t: sexptype, n: cint): sexp
{.importc: "allocVector", header: "<Rinternals.h>".}
proc asReal(a: sexp): cdouble
{.importc: "asReal", header: "<Rinternals.h>".}
proc real(a: sexp): ptr cdouble
{.importc: "REAL", header: "<Rinternals.h>".}
proc add(a, b: sexp): sexp {.exportc, dynlib.} =
result = protect(allocVector(realsxp, 1))
real(result)[] = asReal(a)+asReal(b)
unprotect(1)
On my Windows machine (with 64 bit R, 64 bit Nim 0.16.0 and whatever gcc comes with RBuildTools) I compile it like this:
nim c -t:-m64 -l:-m64 -t:-I"C:/PROGRA~1/R/R-32~1.0/include" -t:-DNDEBUG -t:-I"d:/RCompile/r-compiling/local/local320/include" -t:-mtune=core2 -l:-Ld:/RCompile/r-compiling/local/local320/lib/x64 -l:-Ld:/RCompile/r-compiling/local/local320/lib -l:-LC:/PROGRA~1/R/R-32~1.0/bin/x64 -l:-lR --app:lib usewithR2.nim
Then it can be used from R like this:
dyn.load("usewithR2.dll")
print(.Call("add", 1.5, 3.2))
And it prints [1] 4.7. So far so good. However, it can't be distributed easily. CRAN probably wouldn't accept a package that requires a working Nim compiler to be installed. Is it possible to generate a platform-independent (as in "Windows, Linux and OS X", not as in "every possible AVR microcontroller") C file that does not require anything related to Nim and can be compiled with R CMD SHLIB? I had no success with options like --os:standalone, but maybe I didn't use it correctly. I would appreciate your help.
Just guessing, never tried anything like it, but you could try pre generating the sources for the platforms you want with something like cross compiling and then detect the one to compile with R?
It would be similar to how Nim does bootstrapping with csources.