Skip to main content

Using packages built on jlbind

Source: vignettes/using-clients.qmd

jlbind lets R packages call Julia code compiled ahead of time into a shared library, without a Julia session. This vignette explains how that library works and how to use an R package built with jlbind. To add Julia functions to your own R package, see Get started with jlbind. For how jlbind compares with other ways of calling Julia from R, see Performance.

How it works

An R process can load only one compiled Julia library. Julia has one runtime per process, and that runtime uses a single compiled image. If two R packages loaded separate copies of the library, they could conflict and crash the R session.

To avoid this, jlbind builds one shared library for each user, combining the Julia code of all installed R packages that use jlbind (clients). When you run install_library(), jlbind finds the installed clients, compiles their binding packages into one library, and saves it under tools::R_user_dir("jlbind", "data"). Loading a client loads that library and connects the client to it.

A client can only be bound to a library built from the version of that client currently installed. If you update a package without rebuilding the library, its functions will report that the library needs to be rebuilt.

Using a package built on jlbind

You need Julia 1.13 or later to build the shared library.

After installing or updating an R package that uses jlbind, run:

jlbind::install_library()

The first build downloads and compiles the required Julia dependencies, so it may take a few minutes.

NoteRestart R after rebuilding a library that is already loaded

Julia cannot be restarted within an R session. If the old library has already been loaded, rebuilding it on disk does not replace the copy in memory. Restart R to use the new library.

If something doesn’t work correctly

If a package that uses jlbind doesn’t work, first check its status:

jlbind::check_bound("somepkg")

The most common causes are that the shared library hasn’t been built yet, or that the package was updated after the last build. For a full report, run:

jlbind::jlbind_sitrep()

It shows the Julia that install_library() would use (with its version, and whether it came from JULIA or the PATH), the library and what it was built from, each installed package that uses jlbind and whether the library is current for it, and the thread count. It works whether or not a library has loaded, and returns the same information invisibly as a list.

If the Julia installation used for the build has been removed or replaced, for example by a juliaup update, rebuild the library. install_library() rebuilds it when the Julia version differs from the one it was built with. If the version is the same, use force = TRUE:

jlbind::install_library(force = TRUE)

You can select the Julia installation to use by setting the JULIA environment variable or by passing julia = to install_library().

The library is compiled for the building machine’s CPU. To use it on other machines (e.g. cluster nodes), set JULIA_CPU_TARGET=generic and rebuild with force = TRUE.

Threads

Julia runs with one thread by default. To use multiple threads, set JULIA_NUM_THREADS before loading the first package that uses jlbind, for example in your .Renviron file:

JULIA_NUM_THREADS=auto # or a number, such as 4

The thread count is fixed when the library is loaded, so restart R after changing it.

Dependency versions

All clients share a single set of Julia dependencies. By default, the build starts from the versions in the Manifest.toml of the first client that has one, and keeps them for the other clients where their [compat] bounds allow. Pass versions = "compat" to ignore the manifests and let Julia’s resolver choose versions from the clients’ [compat] bounds alone.

If a client’s [compat] bounds conflict with those of the clients listed before it by jlbind_clients(), it is left out of the build; check_bound() says which clients it conflicts with.

You can control which clients are included by specifying them explicitly:

jlbind::install_library(packages = c("pkgA", "pkgC"))

If you need both clients but never need them in the same R session, build a separate library for each. Set JLBIND_LIBRARY before loading the client to select the library for that session.

For example, build the two libraries:

jlbind::build_library("pkgA", "~/jlbind/pkgA")
jlbind::build_library("pkgB", "~/jlbind/pkgB")

Then select one in an R session:

# jlbind.dll on Windows, jlbind.dylib on macOS
Sys.setenv(JLBIND_LIBRARY = "~/jlbind/pkgA/jlbind.so")
library(pkgA)