-
Notifications
You must be signed in to change notification settings - Fork 2
/
README.Rmd
104 lines (61 loc) · 3.91 KB
/
README.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
---
output: github_document
editor_options:
chunk_output_type: console
---
<!-- README.md is generated from README.Rmd. Please edit that file -->
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%"
)
```
# cexport
This README holds an example of:
- Creating a C function that you can call from R.
- "Registering" that C callable to be called from _another package's_ C code.
- "Getting" the registered C callable and providing an easy header file for other packages to use.
- Actually calling that function from another package's C code.
This package implements, registers, and exports the function that will be called in other packages.
The other package that goes along with this one and actually calls the C function from it's own C code is [cexportuser](https://github.com/DavisVaughan/cexportuser).
You can install this package with:
```{r, eval=FALSE}
devtools::install_github("DavisVaughan/cexport")
```
You can install the companion package that uses this C code (which should "just work" and also install cexport if needed) with:
```{r, eval = FALSE}
devtools::install_github("DavisVaughan/cexportuser")
```
# Details
Here are the steps to do this yourself:
- Create your C function (`src/arith.c` - `cexport_plus_one()`)
- Optionally export it to R with the standard `R_registerRoutines()` (`src/init.c`) and `#' @useDynLib cexport, .registration = TRUE` (`cexport-package.R`).
- "Register" the C callable with `R_RegisterCCallable()` so other packages can find it with `R_GetCCallable()` (`src/init.c`).
- At this point, you can either let users call `R_GetCCallable()` themselves in their own package, or you can be nice and generate a header file that they can just `#include` to get access to your API.
- Let's be nice. In `inst/include/cexport.h` we create an API function with essentially the same signature as our original function, look up the C callable once, and call the function.
- We also make the function `static` so that users can call it from multiple of their C files without throwing any "duplicate symbol" errors.
- And we `R_INLINE` the function to reduce the overhead of the C function call. Essentially, once we have called the function once to get the C callable from `cexport`, repeated calls to the function will be just as fast as calling it natively.
- Now install the package.
The next section will be from the perspective of a package that is going to be calling `cexport_plus_one()` from their own C code. That package is [cexportuser](https://github.com/DavisVaughan/cexportuser).
- In the package that is going to be calling `cexport_plus_one()`, add `LinkingTo: cexport`.
- Now also add `Imports: cexport`. This is _required_ as you have to fully load `cexport` to be able to use its C callables.
- You must also `@importFrom` _something_ from `cexport` so it gets loaded. I imported the `plus_one()` function (`cexportuser-package.R`).
- Create your C function that is going to call `cexport_plus_one()`. At the top of the file put `#include <cexport.h>`. RStudio should recognize this for you. You can now call `cexport_plus_one()`. (`src/arith.h` - `cexportuser_plus_two()`).
- Export the C function to R if you want (`src/init.c`, exported as `plus_two()` in `arith.R`).
If all goes well you should be able to do something like:
```{r}
library(cexportuser)
plus_two(2L)
```
# References
A few packages do this, with `cleancall` probably being the easiest to read:
- [cleancall](https://github.com/r-lib/cleancall/)
- [bdsmatrix](https://github.com/cran/bdsmatrix)
- [xts](https://github.com/joshuaulrich/xts)
Also R Extensions has some advice:
- https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Linking-to-native-routines-in-other-packages
And there is some information in R Packages:
- [Exporting C Code](https://r-pkgs.org/src.html#c-export)
- [Importing C Code](https://r-pkgs.org/src.html#c-import)