# libR-sys
Low-level R library bindings
[](https://github.com/extendr/libR-sys/actions)
[](https://crates.io/crates/libR-sys)
[](https://docs.rs/libR-sys)
[](https://opensource.org/licenses/MIT)
## Installation
The recommended way to build this library is to use precompiled bindings, which are available for `Linux`, `macOS`, and `Windows`.
Alternatively, the library can be built from source, in which case it invokes `bindgen` crate, which has extra platform-specific dependencies (including `msys2` for `Windows`).
## Configuration
`libR-sys` recognizes the following environment variables:
- `LIBRSYS_R_VERSION` If set, it is used to determine the version of R, for which bindings should be generated. `LIBRSYS_R_VERSION` should be set to one of the supported values, e.g. `4.2.0` or `4.3.0-devel` (the pattern is `major.minor.patch[-devel]`). Malformed `LIBRSYS_R_VERSION` results in compilation error. If `LIBRSYS_R_VERSION` is unset, `R` is invoked and its `R.version` is used.
## Using precompiled bindings (recommended)
Two components are required to build the library:
1. [`R`](https://cran.r-project.org/): It needs to be installed and available in the search path.
2. [`Rust`](https://www.rust-lang.org/learn/get-started): It is recommended to install `Rust` using `rustup`; search path should include `Rust` binaries.
**Note: On Windows, R < 4.2 requires a more complex setup in order to support the 32-bit version. Please refer to [README-old-windows.md](./README-old-windows.md) for more details.**
Once `R` and `Rust` are configured, the library can be easily built:
```bash
# macOS & Linux
cargo build
# Windows
cargo build --target x86_64-pc-windows-gnu
```
To test the build, run `cargo test`.
```bash
# macOS & Linux
cargo test
# Windows
cargo test --target x86_64-pc-windows-gnu
```
## Building bindings from source (advanced)
**Note: On Windows, R < 4.2 requires a more complex setup in order to support the 32-bit version. Please refer to [README-old-windows.md](./README-old-windows.md) for more details.**
The bindings can be generated using [`bindgen`](https://github.com/rust-lang/rust-bindgen), special `Rust` crate.
`bindgen` usage is enabled via `use-bindgen` feature flag.
`bindgen` requires [`libclang`](https://clang.llvm.org/docs/Tooling.html), which should be installed first.
This library relies on `LIBCLANG_PATH` environment variable to determine path to the appropriate version of `libclang`.
The output folder for bindings can be configured using `LIBRSYS_BINDINGS_OUTPUT_PATH` environment variable, thus make sure it is set to e.g `bindings`.
- **Linux**
Set `LIBCLANG_PATH` to the `lib` directory of your `llvm` installation, e.g.,
`LIBCLANG_PATH=/usr/lib/llvm-3.9/lib`. Build & test using
```shell
cargo build --features use-bindgen
cargo test --features use-bindgen
```
- **macOS**
Install `llvm-config` via [homebrew](https://brew.sh/) with:
```bash
brew install llvm
```
Add it to your search path via:
```bash
echo 'export PATH="/usr/local/opt/llvm/bin:$PATH"' >> ~/.bash_profile
```
If you want to compile `libR-sys` from within RStudio, you may also have to add the following line to your `.Renviron` file:
```bash
PATH=/usr/local/opt/llvm/bin:$PATH
```
Build & test using
```shell
cargo build --features use-bindgen
cargo test --features use-bindgen
```
- **Windows**
Binding generation on Windows happens with the help of `MSYS2`.
Make sure the environment variable `MSYS_ROOT` points to `MSYS2` root, e.g., `C:\tools\msys64`.
<details>
<summary>Installing and configuring `MSYS2`</summary>
Install `MSYS2`. Here is an example using `chocolatey`:
```shell
choco install msys2 -y
```
Set up `MSYS_ROOT` environment variable.
Install `clang` and `mingw`-toolchains (assuming `PowerShell` syntax)
```pwsh
&"$env:MSYS_ROOT\usr\bin\bash" -l -c "pacman -S --noconfirm mingw-w64-x86_64-clang mingw-w64-x86_64-toolchain"
```
</details>
Add the following to the `PATH` (using `PowerShell` syntax).
```pwsh
# for R >= 4.3, this should be "C:\rtools43"
$rtools_home = "C:\rtools42"
$env:PATH = "${env:R_HOME}\bin\x64;${rtools_home}\usr\bin;${rtools_home}\x86_64-w64-mingw32.static.posix\bin;${env:MSYS_ROOT}\mingw64\bin;${env:PATH}"
```
then build & test with
```pwsh
cargo build --target x86_64-pc-windows-gnu --features use-bindgen
```
## Toolchain setup on Windows
The setup is tricky because the Rtools' toolchain is a bit different from the
assumption of Rust.
### Install the GNU target of Rust
Both the default MSVC toolchain and the GNU toolchain should work fine with
libR-sys, but we recommend the MSVC toolchain because we mainly use it.
With either toolchain, since the R itself is built with the GNU toolchain, the
target must be GNU. So, the GNU target needs to be installed.
```shell
rustup target add x86_64-pc-windows-gnu
```
### Install Rtools42 (or Rtools43)
Rtools42 can be downloaded from [here][rtools42_website]. For R >= 4.3, download
Rtools43 from [here][rtools43_website]. Alternatively, `Rtools` will eventually
be available on `chocolatey`.
[rtools42_website]: https://cran.r-project.org/bin/windows/Rtools/rtools42/rtools.html
[rtools43_website]: https://cran.r-project.org/bin/windows/Rtools/rtools43/rtools.html
```shell
## TODO: Rtools42 is not yet on chocolatey
# choco install rtools -y
```
### Setup `R_HOME` and `PATH` Environment Variables
First, ensure that `R_HOME` points to `R` home, e.g. `C:\Program Files\R\R-4.2.0`
(in an R session, this should be automatically set by R).
Second, ensure that `PATH` is properly configured that the following executables
are available:
- the `R` binary to build against
- the compiler toolchain that is used for compiling the R itself, i.e., `Rtools`
Typically, the following paths need to be added to the head of `PATH` (using
`PowerShell` syntax).
```pwsh
# for R >= 4.3, this should be "C:\rtools43"
$rtools_home = "C:\rtools42"
$env:PATH = "${env:R_HOME}\bin\x64;${rtools_home}\usr\bin;${rtools_home}\x86_64-w64-mingw32.static.posix\bin;${env:PATH}"
```
Note that the above prepends, rather than appends, because otherwise the wrong
toolchain might be accidentally chosen if the `PATH` already contains another
version of `R` or compiler toolchain.
### Tweak the toolchain
As noted above, since the Rtools' toolchain is a bit different from the
assumption of Rust, we need the following tweaks:
1. Change the linker name to `x86_64-w64-mingw32.static.posix-gcc.exe`.
2. Add empty `libgcc_s.a` and `libgcc_eh.a`, and add them to the compiler's
library search paths via `LIBRARY_PATH` environment variables.
The first tweak is needed because Rtools42 and Rtools43 don't contain
`x86_64-w64-mingw32-gcc`, which `rustc` uses as the default linker for the
`x86_64-pc-windows-gnu` target. This can be done by adding `.cargo/config.toml`
with the following lines on the root directory of the project:
``` toml
[target.x86_64-pc-windows-gnu]
linker = "x86_64-w64-mingw32.static.posix-gcc.exe"
```
Alternatively, you can inject this configuration via the corresponding
environmental variable, `CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER`. See [the
Cargo Book] about how this works.
[The Cargo Book]: https://doc.rust-lang.org/cargo/reference/config.html#environment-variables
The second tweak is also required. `rustc` adds `-lgcc_eh` and `-lgcc_s` flags
to the compiler, but Rtools' GCC doesn't have `libgcc_eh` or `libgcc_s` due to
the compilation settings. So, in order to please the compiler, we need to add
empty `libgcc_eh` or `libgcc_s` to the library search paths. For more details,
please refer to [r-windows/rtools-packages].
[r-windows/rtools-packages]: https://github.com/r-windows/rtools-packages/blob/2407b23f1e0925bbb20a4162c963600105236318/mingw-w64-gcc/PKGBUILD#L313-L316
First, create a directory that contains empty `libgcc_eh` or `libgcc_s`.
``` ps1
# create a directory in an arbitrary location (e.g. libgcc_mock)
New-Item -Path libgcc_mock -Type Directory
# create empty libgcc_eh.a and libgcc_s.a
New-Item -Path libgcc_mock\libgcc_eh.a -Type File
New-Item -Path libgcc_mock\libgcc_s.a -Type File
```
Then, add the directory to `LIBRARY_PATH` environment variables. For example, this can be done
by adding the following lines to `.cargo/config.toml`:
``` toml
[env]
LIBRARY_PATH = "path/to/libgcc_mock"
```
#### Editor settings
<details>
Rust-analyzer might need some settings. For example, if you are using VS Code, you probably need to add the following options to `.vscode/settings.json`.
``` json
{
// The target needs to be GNU
"rust-analyzer.cargo.target": "x86_64-pc-windows-gnu",
// Specify "use-bindgen" for developing R-devel.
"rust-analyzer.cargo.features": [],
"terminal.integrated.env.windows": {
"R_HOME": "C:/Program Files/R/R-4.2.2",
"PATH": "${env:R_HOME}/bin/x64;C:/rtools42/x86_64-w64-mingw32.static.posix/bin;C:/rtools42/usr/bin;${env:PATH}"
}
}
```
</details>