├── .Rbuildignore ├── .github ├── .gitignore └── workflows │ └── R-CMD-check.yaml ├── .gitignore ├── DESCRIPTION ├── LICENSE ├── NAMESPACE ├── NEWS ├── R └── hello.R ├── README.md ├── cleanup ├── cleanup.win ├── configure ├── configure.ucrt ├── hellorust.Rproj ├── man └── hellorust.Rd ├── src ├── Makevars ├── Makevars.win ├── myrustlib │ ├── .gitignore │ ├── Cargo.toml │ ├── api.h │ ├── src │ │ ├── hello.rs │ │ ├── lib.rs │ │ ├── mythreads.rs │ │ └── random.rs │ ├── vendor-authors.R │ ├── vendor-config.toml │ └── vendor-update.sh └── wrapper.c └── tools └── rustarch.R /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^src/myrustlib/target 4 | ^src/myrustlib/vendor/ 5 | \.lock$ 6 | \.rs\.bk$ 7 | ^README.md$ 8 | ^.travis.yml$ 9 | ^appveyor.yml$ 10 | ^\.github$ 11 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | pull_request: 6 | 7 | name: R-CMD-check 8 | 9 | jobs: 10 | R-CMD-check: 11 | runs-on: ${{ matrix.config.os }} 12 | 13 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 14 | 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | config: 19 | - { os: macos-latest, r: 'release' } 20 | - { os: macos-15, r: 'next' } 21 | - { os: windows-latest, r: 'release' } 22 | - { os: windows-latest, r: 'devel' } 23 | - { os: ubuntu-latest, r: 'devel', http-user-agent: 'release' } 24 | - { os: ubuntu-latest, r: 'release' } 25 | - { os: ubuntu-latest, r: 'oldrel-1' } 26 | - { os: ubuntu-24.04-arm, r: 'release' } 27 | 28 | env: 29 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 30 | R_KEEP_PKG_SOURCE: yes 31 | 32 | steps: 33 | - name: Add more rust targets 34 | if: runner.os == 'windows' 35 | run: rustup target add x86_64-pc-windows-gnu 36 | 37 | - uses: actions/checkout@v3 38 | 39 | - uses: r-lib/actions/setup-pandoc@v2 40 | 41 | - uses: r-lib/actions/setup-r@v2 42 | with: 43 | r-version: ${{ matrix.config.r }} 44 | http-user-agent: ${{ matrix.config.http-user-agent }} 45 | use-public-rspm: true 46 | 47 | - uses: r-lib/actions/setup-r-dependencies@v2 48 | with: 49 | extra-packages: any::rcmdcheck 50 | needs: check 51 | 52 | - uses: r-lib/actions/check-r-package@v2 53 | with: 54 | upload-snapshots: true 55 | env: 56 | MAKEFLAGS: -j4 57 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | src/*.o 5 | src/*.so 6 | src/*.dll 7 | src/*.a 8 | src/myrustlib/target/* 9 | src/myrustlib/vendor.tar.xz 10 | src/myrustlib/vendor/* 11 | inst/AUTHORS 12 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: hellorust 2 | Type: Package 3 | Title: Minimal Examples of Using Rust Code in R 4 | Version: 1.2.3 5 | Authors@R: c(person("Jeroen", "Ooms", role = c("aut", "cre"), email = "jeroenooms@gmail.com", 6 | comment = c(ORCID = "0000-0002-4035-0289")), 7 | person("Authors of the dependency Rust crates", role = "aut", comment = "see AUTHORS file")) 8 | Description: Template R package with minimal setup to use Rust code in R without 9 | hacks or frameworks. Includes basic examples of importing cargo dependencies, 10 | spawning threads and passing numbers or strings from Rust to R. Cargo crates 11 | are automatically 'vendored' in the R source package to support offline 12 | installation. The GitHub repository for this package has more details and also 13 | explains how to set up CI. This project was first presented at 'Erum2018' to 14 | showcase R-Rust integration ; for a real 15 | world use-case, see the 'gifski' package on 'CRAN'. 16 | License: MIT + file LICENSE 17 | URL: https://github.com/r-rust/hellorust 18 | BugReports: https://github.com/r-rust/hellorust/issues 19 | SystemRequirements: Cargo (Rust's package manager), rustc 20 | Encoding: UTF-8 21 | RoxygenNote: 7.2.1 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2022 2 | COPYRIGHT HOLDER: Jeroen Ooms 3 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(hello) 4 | export(random) 5 | export(runthreads) 6 | useDynLib(hellorust,hello_wrapper) 7 | useDynLib(hellorust,random_wrapper) 8 | useDynLib(hellorust,threads_wapper) 9 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | 1.2.3 2 | - Fix parallel make; more cleanup after build 3 | 4 | 1.2.2 5 | - Fix commented out CARGO_HOME in Makevars 6 | 7 | 1.2.1 8 | - Print rustc --version in configure as per CRAN request 9 | - Update maintainer email address 10 | 11 | 1.2.0 12 | - Windows: support aarch64-pc-windows-gnullvm 13 | 14 | 1.1.1 15 | - CRAN request: use role="aut" for rust dependencies 16 | - CRAN request: use -j2 instead of CARGO_BUILD_JOBS=2 17 | 18 | 1.1.0 19 | - Vendor cargo sources to comply with new CRAN guidlines 20 | 21 | 1.0.2 22 | - Windows: add -lntdll to PKG_LIBS as needed by Rust 1.70 and up 23 | -------------------------------------------------------------------------------- /R/hello.R: -------------------------------------------------------------------------------- 1 | #' Hello Rust! 2 | #' 3 | #' Minimal examples of calling rust functions in R via C. 4 | #' 5 | #' These functions call out to rust functions defined in the `myrustlib` cargo 6 | #' crate which is embedded in this package. They return values generated in Rust, 7 | #' such as a UTF-8 string or random number. In addition, `runthreads` is an 8 | #' example of a multi-threaded rust function. 9 | #' 10 | #' @export 11 | #' @rdname hellorust 12 | #' @examples hello() 13 | #' @return a value generated in Rust (a string, random number, and NULL respectively). 14 | #' @useDynLib hellorust hello_wrapper 15 | hello <- function() { 16 | .Call(hello_wrapper) 17 | } 18 | 19 | #' @export 20 | #' @rdname hellorust 21 | #' @examples random() 22 | #' @useDynLib hellorust random_wrapper 23 | random <- function(){ 24 | .Call(random_wrapper) 25 | } 26 | 27 | #' @export 28 | #' @rdname hellorust 29 | #' @examples runthreads() 30 | #' @useDynLib hellorust threads_wapper 31 | runthreads <- function(){ 32 | .Call(threads_wapper) 33 | invisible() 34 | } 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hello Rust 2 | 3 | [![R build status](https://github.com/r-rust/hellorust/workflows/R-CMD-check/badge.svg)](https://github.com/r-rust/hellorust/actions?workflow=R-CMD-check) 4 | 5 | > Minimal Examples of Using Rust Code in R 6 | 7 | Rust is a modern alternative to C and compiled rust code is ABI compatible with C. Many Rust libraries include C API headers so that the compiled rust code can be called from R/C/C++ as if it were C code. This package shows how to do this. The [r-rust](https://github.com/r-rust) organization contains several more simple R packages interfacing with cargo crates. 8 | 9 | To learn more about using Rust code in R packages, also have a look at the [r-rust FAQ](https://github.com/r-rust/faq) and the [slides](https://jeroen.github.io/erum2018/) about this project presented at eRum2018! 10 | 11 | ## Package Structure 12 | 13 | Bundle your rust code in a the embedded cargo package (see the `Cargo.toml` file) and then the [src/Makevars](src/Makevars) file is written such that R will automatically build the rust modules when the R package is installed. 14 | 15 | ``` 16 | hellorust 17 | ├─ configure ← checks if 'cargo' is installed 18 | ├─ src 19 | │ ├─ myrustlib ← bundled cargo package with your code 20 | │ | ├─ Cargo.toml ← cargo dependencies and metadata 21 | │ | ├─ src ← rust source code 22 | │ | └─ api.h ← C headers for exported rust API 23 | | | 24 | │ ├─ Makevars ← Ties everything together 25 | │ └─ wrapper.c ← C code for R package 26 | ├─ DESCRIPTION 27 | └─ R ← Standard R+C stuff 28 | ``` 29 | 30 | ## Vendoring 31 | 32 | As per the new [2023 cran guidelines](https://cran.r-project.org/web/packages/using_rust.html) we now vendor the cargo crates in the R source packages in order to support offline installation. This is done in a two step process: 33 | 34 | 1. (by package author) The [vendor-update.sh](src/myrustlib/vendor-update.sh) script creates the `vendor.tar.xz` bundle that contains all the cargo sources. In addition, the [vendor-authors.R](src/myrustlib/vendor-authors.R) script generates an `inst/AUTHORS` file that lists the authors of the dependencies, as required by CRAN. Both of these scripts are called in the package [cleanup](cleanup) file and therefore run automatically during `R CMD build` when the source package is created. 35 | 2. (by the user) At install time, the [Makevars](src/Makevars) extracts the `vendor.tar.xz` bundle (when available) and generates a `.cargo/config.toml` file to instruct `cargo build` to use the vendored (offline) sources. 36 | 37 | If you run `R CMD INSTALL` directly from a checkout (without building a source package), then no `vendor.tar.xz` is created and cargo falls back to downloading crates on-the-fly. 38 | 39 | You can test or force the use of vendored sources by passing `--offline` to `cargo build`. 40 | 41 | ## Installing this package 42 | 43 | If Rust is available, clone this repository and run the regular `R CMD INSTALL` command: 44 | 45 | ``` 46 | R CMD INSTALL hellorust 47 | ``` 48 | 49 | Alternatively, to download and install from within R itself: 50 | 51 | ```r 52 | # install.packages("remotes") 53 | remotes::install_github("r-rust/hellorust") 54 | ``` 55 | 56 | ## What is Cargo 57 | 58 | The standard rust toolchain includes a great package manager `cargo` with a corresponding registry [crates.io](https://crates.io/). Cargo makes it very easy to build a rust package including all dependencies into a static library that can easily be linked into an R package. 59 | 60 | This is perfect for R because we can compile and link all rust code at build-time without any system dependencies. Rust itself has no substantial runtime so the resulting R package is entirely self contained. Indeed, rust has been designed specifically to serve well as an embedded language. 61 | 62 | ## Installing Rust on Linux / MacOS 63 | 64 | Note that `cargo` is only needed at __build-time__. Rust has __no runtime dependencies__. The easiest way to install the latest version of Rust (including cargo) is from: https://www.rust-lang.org/tools/install 65 | 66 | Alternatively, you may install cargo from your OS package manager: 67 | 68 | - Debian/Ubuntu: `sudo apt-get install cargo` 69 | - Fedora/CentOS*: `sudo yum install cargo` 70 | - MacOS: `brew install rustc` 71 | 72 | *Note that on CentOS you first need to enable EPEL via `sudo yum install epel-release`. 73 | 74 | ## Installing Rust for R on Windows 75 | 76 | In order for rust to work with R you need to install the toolchain using `rustup` and then add the `x86_64-pc-windows-gnu` target. First download [rustup-init.exe](https://win.rustup.rs/) and then install the default toolchain: 77 | 78 | ``` 79 | rustup-init.exe -y --default-host x86_64-pc-windows-gnu 80 | ``` 81 | 82 | Or if rust is already installed (for example on GitHub actions), you can simply add the target: 83 | 84 | ``` 85 | rustup target add x86_64-pc-windows-gnu 86 | ``` 87 | 88 | To compile 32bit packages also add the `i686-pc-windows-gnu` target, but 32-bit is no longer supported as of R 4.2. 89 | 90 | ## GitHub Actions 91 | 92 | __Update 2023:__ This step is no longer needed because GitHub action runners now have the required Rust targets preinstalled by default. 93 | 94 | To use GitHub actions, you can use the [standard r workflow](https://github.com/r-lib/actions/blob/HEAD/.github/workflows/check-standard.yaml) script in combination with this extra step: 95 | 96 | ``` 97 | - name: Add Rtools targets to Rust 98 | if: runner.os == 'Windows' 99 | run: | 100 | rustup target add i686-pc-windows-gnu 101 | rustup target add x86_64-pc-windows-gnu 102 | ``` 103 | 104 | ## In the real world 105 | 106 | The [gifski](https://cran.r-project.org/web/packages/gifski/index.html) package has been on CRAN since 2018, and uses this same structure. 107 | 108 | ## More Resources 109 | - [r-rust FAQ](https://github.com/r-rust/faq) 110 | - Erum2018 [slides](https://jeroen.github.io/erum2018/) about this project presented by Jeroen 111 | - [Rust Inside Other Languages](https://doc.rust-lang.org/1.6.0/book/rust-inside-other-languages.html) chapter from official rust documentation 112 | - [extendr](https://github.com/extendr): a more advanced R extension interface using Rust 113 | - Duncan's proof of concept: [RCallRust](https://github.com/duncantl/RCallRust) 114 | -------------------------------------------------------------------------------- /cleanup: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | export PATH="$HOME/.cargo/bin:$PATH" 3 | cd src/myrustlib 4 | ./vendor-update.sh 5 | 6 | # Update ../inst/AUTHORS 7 | ${R_HOME}/bin/Rscript vendor-authors.R 8 | -------------------------------------------------------------------------------- /cleanup.win: -------------------------------------------------------------------------------- 1 | cleanup -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | export PATH="$PATH:$HOME/.cargo/bin" 3 | if [ $(command -v cargo) ]; then 4 | cargo --version 5 | rustc --version || true 6 | else 7 | echo "----------------------- [RUST NOT FOUND]---------------------------" 8 | echo "The 'cargo' command was not found on the PATH. Please install rustc" 9 | echo "from: https://www.rust-lang.org/tools/install" 10 | echo "" 11 | echo "Alternatively, you may install cargo from your OS package manager:" 12 | echo " - Debian/Ubuntu: sudo apt-get install cargo" 13 | echo " - Fedora/CentOS: sudo yum install cargo" 14 | echo " - MacOS: brew install rustc" 15 | echo "-------------------------------------------------------------------" 16 | echo "" 17 | exit 1 18 | fi 19 | exit 0 20 | -------------------------------------------------------------------------------- /configure.ucrt: -------------------------------------------------------------------------------- 1 | configure -------------------------------------------------------------------------------- /hellorust.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | ProjectId: 96528bc3-6344-4293-93e2-82a0487b38a2 3 | 4 | RestoreWorkspace: Default 5 | SaveWorkspace: Default 6 | AlwaysSaveHistory: Default 7 | 8 | EnableCodeIndexing: Yes 9 | UseSpacesForTab: Yes 10 | NumSpacesForTab: 2 11 | Encoding: UTF-8 12 | 13 | RnwWeave: Sweave 14 | LaTeX: pdfLaTeX 15 | 16 | AutoAppendNewline: Yes 17 | StripTrailingWhitespace: Yes 18 | 19 | BuildType: Package 20 | PackageUseDevtools: Yes 21 | PackageInstallArgs: --no-multiarch --with-keep.source 22 | -------------------------------------------------------------------------------- /man/hellorust.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/hello.R 3 | \name{hello} 4 | \alias{hello} 5 | \alias{random} 6 | \alias{runthreads} 7 | \title{Hello Rust!} 8 | \usage{ 9 | hello() 10 | 11 | random() 12 | 13 | runthreads() 14 | } 15 | \value{ 16 | a value generated in Rust (a string, random number, and NULL respectively). 17 | } 18 | \description{ 19 | Minimal examples of calling rust functions in R via C. 20 | } 21 | \details{ 22 | These functions call out to rust functions defined in the `myrustlib` cargo 23 | crate which is embedded in this package. They return values generated in Rust, 24 | such as a UTF-8 string or random number. In addition, `runthreads` is an 25 | example of a multi-threaded rust function. 26 | } 27 | \examples{ 28 | hello() 29 | random() 30 | runthreads() 31 | } 32 | -------------------------------------------------------------------------------- /src/Makevars: -------------------------------------------------------------------------------- 1 | LIBDIR = myrustlib/target/release 2 | STATLIB = $(LIBDIR)/libmyrustlib.a 3 | PKG_CFLAGS = -pthread 4 | PKG_CPPFLAGS = -DSTRICT_R_HEADERS -DR_NO_REMAP 5 | PKG_LIBS = -L$(LIBDIR) -lmyrustlib -lresolv -pthread 6 | 7 | all: cleanup 8 | 9 | $(SHLIB): $(STATLIB) 10 | 11 | # CRAN policy forbids using $HOME so we build in the current working dir and 12 | # never use local cache. Also CRAN does not allow using more than 2 CPUs. 13 | # This makes things really slow because we have to reinstall all dependencies. 14 | # You can comment these things out if you do not submit to CRAN. 15 | CRANFLAGS=-j 2 16 | CARGOTMP=$(PWD)/.cargo 17 | export CARGO_HOME=$(CARGOTMP) 18 | 19 | $(STATLIB): 20 | if [ -f myrustlib/vendor.tar.xz ]; then tar xf myrustlib/vendor.tar.xz && mkdir -p $(CARGOTMP) && cp myrustlib/vendor-config.toml $(CARGOTMP)/config.toml; fi 21 | PATH="${PATH}:${HOME}/.cargo/bin" cargo build ${CRANFLAGS} --release --manifest-path=myrustlib/Cargo.toml 22 | @$(STRIP_STATIC_LIB) $(STATLIB) || true 23 | @rm -Rf $(CARGOTMP) vendor || true # CRAN wants us to remove "detritus" 24 | @rm -Rf $(LIBDIR)/build || true 25 | 26 | cleanup: $(SHLIB) 27 | @rm -Rf $(STATLIB) myrustlib/target 28 | -------------------------------------------------------------------------------- /src/Makevars.win: -------------------------------------------------------------------------------- 1 | TARGET = $(shell "$(R_HOME)/bin$(R_ARCH_BIN)/Rscript.exe" "../tools/rustarch.R") 2 | LIBDIR = myrustlib/target/$(TARGET)/release 3 | STATLIB = $(LIBDIR)/libmyrustlib.a 4 | PKG_CPPFLAGS = -DSTRICT_R_HEADERS -DR_NO_REMAP 5 | PKG_LIBS = -L$(LIBDIR) -lmyrustlib -lws2_32 -ladvapi32 -lgdi32 -lbcrypt -lcrypt32 -luserenv -lntdll 6 | 7 | all: cleanup 8 | 9 | $(SHLIB): $(STATLIB) 10 | 11 | $(STATLIB): 12 | if [ -f myrustlib/vendor.tar.xz ]; then tar xf myrustlib/vendor.tar.xz && mkdir -p .cargo && cp myrustlib/vendor-config.toml .cargo/config.toml; fi 13 | PATH="$(USERPROFILE)\.cargo\bin:$(PATH)" cargo build --target=$(TARGET) --release --manifest-path=myrustlib/Cargo.toml 14 | 15 | cleanup: $(SHLIB) 16 | @rm -Rf $(STATLIB) myrustlib/target 17 | -------------------------------------------------------------------------------- /src/myrustlib/.gitignore: -------------------------------------------------------------------------------- 1 | x 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /src/myrustlib/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "myrustlib" 3 | version = "0.1.0" 4 | authors = ["Jeroen "] 5 | 6 | [lib] 7 | crate-type = ["staticlib"] 8 | 9 | [dependencies] 10 | rand = "0.4.1" 11 | libc = "*" 12 | -------------------------------------------------------------------------------- /src/myrustlib/api.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | char * string_from_rust(void); 8 | void free_string_from_rust(char*); 9 | int32_t random_number(void); 10 | void run_threads(void); 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif 15 | -------------------------------------------------------------------------------- /src/myrustlib/src/hello.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::CString; 2 | use std::os::raw::c_char; 3 | 4 | #[no_mangle] 5 | pub extern "C" fn string_from_rust() -> *const c_char { 6 | let s = CString::new("Hello ピカチュウ !").unwrap(); 7 | s.into_raw() 8 | } 9 | 10 | #[no_mangle] 11 | pub extern "C" fn free_string_from_rust(ptr: *mut c_char) { 12 | let _ = unsafe { CString::from_raw(ptr) }; 13 | } 14 | -------------------------------------------------------------------------------- /src/myrustlib/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Import dependencies 2 | extern crate libc; 3 | extern crate rand; 4 | 5 | // Modules are other .rs source files 6 | mod hello; 7 | mod random; 8 | mod mythreads; 9 | 10 | // Export functions called by R 11 | pub use hello::string_from_rust; 12 | pub use random::random_number; 13 | pub use mythreads::run_threads; 14 | -------------------------------------------------------------------------------- /src/myrustlib/src/mythreads.rs: -------------------------------------------------------------------------------- 1 | use std::thread; 2 | use std::time::Duration; 3 | 4 | #[no_mangle] 5 | pub extern fn run_threads() { 6 | thread::spawn(|| { 7 | for i in 1..10 { 8 | println!("hi number {} from the spawned thread!", i); 9 | thread::sleep(Duration::from_millis(1)); 10 | } 11 | }); 12 | 13 | for i in 1..5 { 14 | println!("hi number {} from the main thread!", i); 15 | thread::sleep(Duration::from_millis(1)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/myrustlib/src/random.rs: -------------------------------------------------------------------------------- 1 | use rand::random; 2 | 3 | #[no_mangle] 4 | pub extern fn random_number() -> i32 { 5 | let tuple = random::(); 6 | tuple 7 | } 8 | -------------------------------------------------------------------------------- /src/myrustlib/vendor-authors.R: -------------------------------------------------------------------------------- 1 | if(!require('jsonlite')) install.packages('jsonlite', repos = 'https://cloud.r-project.org') 2 | metadata <- jsonlite::fromJSON(pipe("cargo metadata --format-version 1")) 3 | packages <- metadata$packages 4 | stopifnot(is.data.frame(packages)) 5 | packages <- subset(packages, sapply(packages$authors, length) > 0 & name != 'myrustlib') 6 | authors <- vapply(packages$authors, function(x) paste(sub(" <.*>", "", x), collapse = ', '), character(1)) 7 | lines <- sprintf(" - %s %s: %s", packages$name, packages$version, authors) 8 | dir.create('../../inst', showWarnings = FALSE) 9 | footer <- sprintf("\n(This file was auto-generated from 'cargo metadata' on %s)", Sys.Date()) 10 | writeLines(c('Authors of vendored cargo crates', lines, footer), '../../inst/AUTHORS') 11 | -------------------------------------------------------------------------------- /src/myrustlib/vendor-config.toml: -------------------------------------------------------------------------------- 1 | [source.crates-io] 2 | replace-with = "vendored-sources" 3 | 4 | [source.vendored-sources] 5 | directory = "vendor" 6 | 7 | -------------------------------------------------------------------------------- /src/myrustlib/vendor-update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | rm -Rf vendor vendor.tar.xz 3 | cargo vendor 4 | tar -cJ --no-xattrs -f vendor.tar.xz vendor 5 | rm -Rf vendor 6 | 7 | -------------------------------------------------------------------------------- /src/wrapper.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Import C headers for rust API 4 | #include "myrustlib/api.h" 5 | 6 | // Actual Wrappers 7 | SEXP hello_wrapper(void){ 8 | char* hello_rust = string_from_rust(); 9 | SEXP hello_world_string = PROTECT(Rf_mkCharCE(hello_rust, CE_UTF8)); 10 | free_string_from_rust(hello_rust); 11 | UNPROTECT(1); 12 | return Rf_ScalarString(hello_world_string); 13 | } 14 | 15 | SEXP random_wrapper(void){ 16 | return Rf_ScalarInteger(random_number()); 17 | } 18 | 19 | SEXP threads_wapper(void){ 20 | run_threads(); 21 | return R_NilValue; 22 | } 23 | 24 | // Standard R package stuff 25 | static const R_CallMethodDef CallEntries[] = { 26 | {"hello_wrapper", (DL_FUNC) &hello_wrapper, 0}, 27 | {"random_wrapper", (DL_FUNC) &random_wrapper, 0}, 28 | {"threads_wapper", (DL_FUNC) &threads_wapper, 0}, 29 | {NULL, NULL, 0} 30 | }; 31 | 32 | void R_init_hellorust(DllInfo *dll) { 33 | R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); 34 | R_useDynamicSymbols(dll, FALSE); 35 | } 36 | -------------------------------------------------------------------------------- /tools/rustarch.R: -------------------------------------------------------------------------------- 1 | # See notes in FAQ about ARM64 support: 2 | # https://github.com/r-rust/faq#does-rust-support-windows-on-arm64-aarch64 3 | arch <- if(grepl("aarch", R.version$platform)){ 4 | "aarch64-pc-windows-gnullvm" 5 | } else if(grepl("clang", Sys.getenv('R_COMPILED_BY'))){ 6 | "x86_64-pc-windows-gnullvm" 7 | } else if(grepl("i386", R.version$platform)){ 8 | "i686-pc-windows-gnu" 9 | } else { 10 | "x86_64-pc-windows-gnu" 11 | } 12 | 13 | cat(arch) 14 | --------------------------------------------------------------------------------