Skip to contents

Overview

rdev supports my personal workflow, including creation of both traditional R packages and R Analysis Packages (vignette("analysis-package-layout")), enforcing consistency across packages, and providing Continuous Integration/Continuous Delivery (CI/CD) automation. I use the tools in rdev to improve code quality, speed up development of R code, and publish results of analyses in R and Quarto Notebooks as HTML to make them accessible to non-R users.

Installation

My current R development environment uses Homebrew, rig, RStudio, GitHub, a collection of R packages including rdev, Visual Studio Code, and Vim.

Homebrew

I use Homebrew Bundle to install all software on my systems; my basic macOS working environment is published on GitHub in macos-env.

Installing R

rig supports installation of multiple versions of official R binaries, which I use for reproducibility. To install R using rig, first install rig:

brew install --cask r-rig-app

Then install desired versions of R. The following installs R 4.1 through 4.6 on ARM based macs (as of 2026-07-26):

rig install oldrel/5 --without-pak
rig install oldrel/4 --without-pak
rig install oldrel/3 --without-pak
rig install oldrel/2 --without-pak
rig install oldrel --without-pak
rig install release --without-pak
rig default release

Note that:

  1. I don’t use pak, which rig installs by default, as it is not yet fully supported by renv.
  2. The oldest version of R I install is 4.1 (on ARM) or 4.3 (on Intel), which are the oldest versions of R that install into /opt instead of /usr/local (which causes issues for Homebrew)

Also note that RStudio requires R 3.6 or newer (as of version 2024.04.00). Since there was no ARM binary release for R 3.6 or R 4.0, running these versions requires installing the Intel binaries and running them with Rosetta 2.

Development Tools

Well, obviously, I use RStudio. RStudio is the leading IDE for R development and integrates with many R packages, although it sometimes falls short; I use GitHub and the command line for Git, and occasionally Visual Studio Code (which has better support for markdown) and Vim (which is faster for some types of edits).

Posit is developing a next-generation R and Python IDE based on Visual Studio Code, Positron. While I’ve tried using Positron, I’ve found that it has too many missing features to replace RStudio for my development, including:

  • Lack of a notebook-style interface for RMarkdown or Quarto documents
  • No support for lintr
  • No command History or package Build panes

Of these, the first two are showstoppers and the missing panes are nearly so.

RStudio, the GitHub desktop client, and Visual Studio Code are easily installed using Homebrew:

brew install --cask rstudio
brew install --cask github
brew install --cask visual-studio-code

It is recommended to change the default settings for .RData in RStudio (in Options > General > Basic > Workspace):

  • Uncheck “Restore .Data into workspace at startup”
  • Set “Save workspace to .Data on exit” to “Never”

Vim is installed by default on macOS and most Unix-like systems.

Packages

Managing packages and environments are a challenge for most modern languages. Thankfully R doesn’t have the same level of challenge as python, or even ruby, managing packages available within a project is a best practice. I use renv for this purpose, and use renv to install and manage all packages in all of my projects.

The setup-r script from rdev installs a base set of packages needed to run rdev in the R User Library. A streamlined version of that script is included below.

# fix rig permissions
sudo chown -R "$(whoami)":admin /Library/Frameworks/R.framework/Versions/*/Resources/library

RVERSION="$(Rscript -e 'cat(as.character(getRversion()[1,1:2]))')"
USERLIB="$HOME/Library/R/$(uname -m)/${RVERSION}/library"
DEVPKG='c("renv", "styler", "lintr", "miniUI", "languageserver", "rmarkdown", "stringr", "devtools", "available", "remotes")'
GITPKG='c("jabenninghoff/rdev")'

if [ ! -d "${USERLIB}" ]
then
    mkdir -p "${USERLIB}"
fi

echo "install.packages(${DEVPKG}, repos=\"https://cloud.r-project.org\", lib=\"${USERLIB}\")" | R --no-save
echo "remotes::install_github(${GITPKG}, lib=\"${USERLIB}\")" | R --no-save

The chown command is needed to allow updating the base packages using the RStudio Packages “Update” function. I generally update packages in RStudio with no projects open before starting development, then update packages in projects using renv::update().

If you’re installing (development) versions of packages from GitHub, it is recommended to set up a personal access token using usethis::create_github_token() and adding it to your Git credential store using gitcreds::gitcreds_set(). You can verify GitHub is set up following usethis recommendations with usethis::git_sitrep().

Makevars

When building from source, R uses ~/.R/Makevars to customize how C, C++, or Fortran code is compiled. I’ve developed a personalized Makevars file for macOS that detects Homebrew installed libraries, adds OpenMP support via libomp, and includes notes on officially supported versions of gfortran, along with instructions on how to use gfortran from Homebrew.

# macOS .R/Makevars
# adapted from https://github.com/Rdatatable/data.table/wiki/Installation
# https://firas.io/posts/data_table_openmp/
# and https://cran.r-project.org/doc/manuals/r-devel/R-exts.html#Using-Makevars

# CPPFLAGS is set in ${R_HOME}/etc/Makeconf and is set to "-I/opt/R/arm64/include" for ARM versions of R (>= 4.1)
# we use this to determine the (default) HOMEBREW_PREFIX for each architecture
ifeq "$(CPPFLAGS)" "-I/opt/R/arm64/include"
HOMEBREW_PREFIX=/opt/homebrew
else
HOMEBREW_PREFIX=/usr/local
endif

# include homebrew installed libraries
# https://stackoverflow.com/questions/79740057/libintl-h-not-found-when-installing-matrix-with-renv
LDFLAGS+=-L$(HOMEBREW_PREFIX)/lib
CPPFLAGS+=-I$(HOMEBREW_PREFIX)/include

# install libomp with `brew install libomp`
# libomp is keg only, set flags per libomp caveats
LDFLAGS+=-L$(HOMEBREW_PREFIX)/opt/libomp/lib
CPPFLAGS+=-I$(HOMEBREW_PREFIX)/opt/libomp/include

LDFLAGS+=-lomp

# Flags for OpenMP support that should allow packages that want to use
# OpenMP to do so (data.table), and other packages that bork with
# -fopenmp flag (stringi) to be left alone
# Support for C++98 was removed in R 4.1.0: https://cran.r-project.org/bin/windows/base/old/4.1.0/NEWS.R-4.1.0.html
# Supported C++ Standards in R 4.6.0: https://github.com/wch/r-source/tree/tags/R-4-6-0/tests/C%2B%2BStandards
SHLIB_OPENMP_CFLAGS=-Xclang -fopenmp
SHLIB_OPENMP_CXXFLAGS=-Xclang -fopenmp
SHLIB_OPENMP_CXX11FLAGS=-Xclang -fopenmp
SHLIB_OPENMP_CXX14FLAGS=-Xclang -fopenmp
SHLIB_OPENMP_CXX17FLAGS=-Xclang -fopenmp
SHLIB_OPENMP_CXX20FLAGS=-Xclang -fopenmp
SHLIB_OPENMP_CXX23FLAGS=-Xclang -fopenmp
SHLIB_OPENMP_CXX26FLAGS=-Xclang -fopenmp
SHLIB_OPENMP_FCFLAGS=-Xclang -fopenmp
SHLIB_OPENMP_FFLAGS=-Xclang -fopenmp

# gfortran is included with `brew install gcc`
# adapted from https://www.cynkra.com/blog/2021-03-16-gfortran-macos/
# with help from https://cran.r-project.org/doc/manuals/r-release/R-admin.html#macOS-packages
# and https://github.com/r-lib/rig/issues/207
# note: ignore linker duplicate libraries warning per https://github.com/orgs/Homebrew/discussions/4794
# -lemutls_w added here: https://github.com/wch/r-source/commit/22fab0d7a9f50afd4960e68d57bea137a004f03e
#
# CRAN uses specific gfortran binaries from https://mac.r-project.org/tools/:
#
# - gfortran 4.2.3 for R 3.6 (https://cran.r-project.org/bin/macosx/tools/)
# - gfortran 8.2 for intel R 4.0 through 4.2 (https://github.com/fxcoudert/gfortran-for-macOS)
# - gfortran 11.0.0 for arm64 R 4.1 (https://mac.r-project.org/libs-arm64/gfortran-f51f1da0-darwin20.0-arm64.tar.gz)
# - gfortran 12.0.1 for arm64 R 4.2 (https://github.com/R-macos/gcc-darwin-arm64)
# - gfortran-12.2-universal.pkg for R 4.3 and 4.4 (https://github.com/R-macos/gcc-12-branch)
# - gfortran-14.2-universal.pkg (r-gfortran) for R 4.5 and newer (https://github.com/R-macos/gcc-14-branch)
#
# uncomment the following lines when using homebrew gfortran
#FC=$(HOMEBREW_PREFIX)/bin/gfortran
#F77=$(HOMEBREW_PREFIX)/bin/gfortran
#FLIBS=-L$(HOMEBREW_PREFIX)/lib/gcc/current -lgfortran -lquadmath

The latest version of R gfortran 14.2 (for R 4.5 and newer) can be installed from jabenninghoff/homebrew-edge:

brew tap jabenninghoff/edge
brew trust --tap jabenninghoff/edge
brew install --cask r-gfortran

Further Reading

My workflow has been heavily influenced by the DevOps movement and the research of the DevOps Research and Assessment (DORA) team at Google started by Dr. Nicole Forsgren. Their research shows how technical and non-technical capabilities improve outcomes.

The functions included in rdev support many of the technical capabilities, including:

  • Code maintainability
  • Continuous delivery
  • Continuous integration
  • Deployment automation
  • Shifting left on security
  • Test automation
  • Trunk-based development
  • Version control

An outline of my SIRAcon 2022 talk, “Making R Work for You (With Automation)” is available on GitHub in siracon2022.