When working on macOS and Windows, users will often download and install package binaries, rather than sources, as provided by CRAN. However, CRAN only provides binaries for the latest-available version of a package, and so binaries for older versions of a package will become inaccessible as that package is updated.
MRAN is a service provided by Microsoft that mirrors CRAN every day, and allows users to use particular snapshots of CRAN as their active repositories within their R session.
Starting with renv 0.10.0
, renv
can also
make use of MRAN binary packages when restoring packages on Windows and
macOS. When invoking renv::install()
or
renv::restore()
, renv
will attempt to install
the package from the latest-available MRAN snapshot that still had this
package available.
As an example, the stringi
package was updated from
version 1.4.5
to version 1.4.6
on 2020-02-17,
and binaries for that version of stringi
were made
available for macOS on 2020-02-20. Because of this, the last date on
which stringi 1.4.5
macOS binaries were available on CRAN
was 2020-02-19
.
Fortunately, because MRAN snapshotted CRAN on this date, we can retrieve that binary. For example, on macOS with R 3.6:
> renv::install("stringi@1.4.5")
'https://mran.microsoft.com/snapshot/2020-02-19/bin/macosx/el-capitan/contrib/3.6/stringi_1.4.5.tgz' ...
Retrieving
OK [file is up to date]1.4.5] ...
Installing stringi [ OK [installed binary]
When binaries are available from MRAN, renv
should
transparently download and use them when possible. When binaries are not
available, renv
will fall back to the old behavior, and
attempt to install packages from sources.
If you prefer not to make use of MRAN (e.g. because you are using
renv
in an environment without external internet access),
you can disable it with:
options(renv.config.mran.enabled = FALSE)
See also the ?renv::equip
function, which can assist you
in preparing your environment for compilation of packages.
While being able to install binary packages from arbitrary MRAN snapshots can be useful, one must be aware of potential incompatibility issues. In particular, we need to consider:
ABI compatibility issues can arise if different packages were built against different versions of a shared dependency. For example, one package may have been built against Rcpp 1.0.6, and another package might have been built against Rcpp 1.0.7. However, because only one version of the Rcpp package can be loaded at a time within an R session, mixing of these two packages might cause issues either on load or at runtime depending on the version of Rcpp available.
It’s worth emphasizing that this is not Rcpp’s fault; a package built
against Rcpp 1.0.7 would reasonably expect newer APIs made available by
that version of the package would be available at runtime, and that
contract would be violated if an older version of Rcpp were installed in
the project library. The challenge for renv
is that this
build-time dependency is not clearly communicated to renv
;
in general, it is not possible to know what packages (and their
versions) a particular package was built against.
R packages might occasionally (and unintentionally) take a build-time dependency on another R package – for example, a package with the code:
`%>%` <- magrittr::`%>%`
would take the version of %>%
that was available from
the version of magrittr that was available at build time, not
the one available at run time. This could be problematic if,
for example, an update to the magrittr
package changed in a
way that made old definitions of %>%
incompatible with
newer internal functions.
In general, it is a mistake for packages to take a build-time
dependency on exported objects from another package; rather, such
objects should be imported at runtime (using
e.g. importFrom()
in the package NAMESPACE
file).