diff --git a/bindings/r/.cargo/config.toml b/bindings/r/.cargo/config.toml new file mode 100644 index 0000000..ad4fe65 --- /dev/null +++ b/bindings/r/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +rustflags = ["-C", "link-args=-undefined dynamic_lookup"] \ No newline at end of file diff --git a/bindings/r/Cargo.toml b/bindings/r/Cargo.toml new file mode 100644 index 0000000..90cc117 --- /dev/null +++ b/bindings/r/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "codelist" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["staticlib"] +name = "codelist" +path = "src/lib.rs" +# Build as a dynamic library + +[dependencies] +extendr-api = "0.7.1" diff --git a/bindings/r/DESCRIPTION b/bindings/r/DESCRIPTION new file mode 100644 index 0000000..2eab0a5 --- /dev/null +++ b/bindings/r/DESCRIPTION @@ -0,0 +1,13 @@ +Package: codelist +Title: R Wrapper for Rust Functions +Version: 0.1.0 +Authors@R: + person("Your Name", "Your Last Name", email = "your.email@example.com", role = c("aut", "cre")) +Description: Provides R bindings for Rust functions using extendr. +License: MIT + file LICENSE +Encoding: UTF-8 +Roxygen: list(markdown = TRUE) +RoxygenNote: 7.3.2 +Imports: + rextendr +Config/rextendr/version: 0.3.1 diff --git a/bindings/r/NAMESPACE b/bindings/r/NAMESPACE new file mode 100644 index 0000000..0a80ddb --- /dev/null +++ b/bindings/r/NAMESPACE @@ -0,0 +1,2 @@ +useDynLib(codelist, .registration = TRUE) +export(hello) \ No newline at end of file diff --git a/bindings/r/R/extendr-wrappers.R b/bindings/r/R/extendr-wrappers.R new file mode 100644 index 0000000..53199cf --- /dev/null +++ b/bindings/r/R/extendr-wrappers.R @@ -0,0 +1,16 @@ +# Generated by extendr: Do not edit by hand + +# nolint start + +# +# This file was created with the following call: +# .Call("wrap__make_codelist_wrappers", use_symbols = TRUE, package_name = "codelist") + +#' @usage NULL +#' @useDynLib codelist, .registration = TRUE +NULL + +hello <- function() .Call(wrap__hello) + + +# nolint end diff --git a/bindings/r/README.md b/bindings/r/README.md new file mode 100644 index 0000000..39fc4b1 --- /dev/null +++ b/bindings/r/README.md @@ -0,0 +1,75 @@ +# R Bindings + +This package demonstrates how to call Rust functions from R using extendr. +I (@CarolineMorton) have not yet implemented this with our Codelist library +but rather with a simple "hello world" function. + +## Prerequisites + +- Install R (version 4.0 or higher recommended) + - macOS: `brew install r` + +#### Notes +- My R installation took a long time to complete, so be patient here. It seems like it was broken +because for some reason installing R also means it installs the latest version of Python, Pytorch and +a bunch of other things. I'm not super familiar with R or why it does this but 🤷‍♀️ it might just be a +me problem. +- I think you need to have Xcode installed on macOS to get the C bridge to work. +- I had to add R to my path before I could get into the R console via the terminal: +```bash +R +``` +- An alternative is to use RStudio, which is a popular IDE for R. +- You can exit the R console with `q()`. You then get this: +```bash +Save workspace image? [y/n/c]: +``` +which i said no to. + +## Building and Installing + +1. First build the Rust library: +```bash +cd r +cargo build --release +``` + +This will create a shared library in `target/release/libcodelist.dylib` (macOS) or `target/release/libcodelist.so` (Linux). + +2. Open R with the terminal command `R` +and install required packages. If you get an error message when running this, you may also need to install package dependencies for `devtools` first if not already installed: +```r +install.packages("devtools") +install.packages("rextendr") +``` + +I picked `64` as the mirror I wanted to use. + + +3. Build and load the package: +```r +rextendr::document() +devtools::document() +devtools::load_all() +``` + +4. Test that it works: +```r +hello() +``` + +## Installing Permanently + +To install the package permanently: + +```r +devtools::build() +devtools::install() +``` + +After installation, you can use it like any other R package: + +```r +library(codelist) +hello() +``` \ No newline at end of file diff --git a/bindings/r/src/Makevars b/bindings/r/src/Makevars new file mode 100644 index 0000000..6417f60 --- /dev/null +++ b/bindings/r/src/Makevars @@ -0,0 +1,13 @@ +LIBDIR = ../target/release +STATLIB = $(LIBDIR)/libcodelist.a +PKG_LIBS = -L$(LIBDIR) -lcodelist + +all: C_clean + +$(SHLIB): $(STATLIB) + +$(STATLIB): + cargo build --lib --release + +C_clean: + rm -Rf $(SHLIB) $(STATLIB) $(OBJECTS) \ No newline at end of file diff --git a/bindings/r/src/entrypoint.c b/bindings/r/src/entrypoint.c new file mode 100644 index 0000000..3c72e2a --- /dev/null +++ b/bindings/r/src/entrypoint.c @@ -0,0 +1,8 @@ +// We need to forward routine registration from C to Rust +// to avoid the linker removing the static library. + +void R_init_codelist_extendr(void *dll); + +void R_init_codelist(void *dll) { + R_init_codelist_extendr(dll); +} diff --git a/bindings/r/src/lib.rs b/bindings/r/src/lib.rs new file mode 100644 index 0000000..cc19cfa --- /dev/null +++ b/bindings/r/src/lib.rs @@ -0,0 +1,12 @@ +use extendr_api::prelude::*; + +#[extendr] +fn hello() -> &'static str { + println!("hello function called"); + "hello" +} + +extendr_module! { + mod codelist; + fn hello; +}